mirror of https://github.com/zulip/zulip.git
hotspots: Implement hotspots frontend.
This commit is contained in:
parent
d951375d6c
commit
5a8b1e6253
|
@ -467,7 +467,7 @@ with_overrides(function (override) {
|
|||
with_overrides(function (override) {
|
||||
// hotspots
|
||||
var event = event_fixtures.hotspots;
|
||||
override('hotspots.show', noop);
|
||||
override('hotspots.load_new', noop);
|
||||
dispatch(event);
|
||||
assert_same(page_params.hotspots, event.hotspots);
|
||||
});
|
||||
|
|
|
@ -583,6 +583,66 @@ $(function () {
|
|||
});
|
||||
}());
|
||||
|
||||
|
||||
// HOTSPOTS
|
||||
|
||||
// open
|
||||
$('body').on('click', '.hotspot-icon', function (e) {
|
||||
// hide icon
|
||||
$(this).animate({ opacity: 0 }, {
|
||||
duration: 300,
|
||||
done: function () {
|
||||
$(this).css({ display: 'none' });
|
||||
}.bind(this),
|
||||
});
|
||||
|
||||
// show popover
|
||||
var hotspot_name = $(e.target).closest('.hotspot-icon')
|
||||
.attr('id')
|
||||
.replace('hotspot_', '')
|
||||
.replace('_icon', '');
|
||||
var overlay_name = 'hotspot_' + hotspot_name + '_overlay';
|
||||
|
||||
overlays.open_overlay({
|
||||
name: overlay_name,
|
||||
overlay: $('#' + overlay_name),
|
||||
on_close: function () {
|
||||
// close popover
|
||||
$(this).css({ display: 'block' });
|
||||
$(this).animate({ opacity: 1 }, {
|
||||
duration: 300,
|
||||
});
|
||||
}.bind(this),
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// confirm
|
||||
$('body').on('click', '.hotspot.overlay .hotspot-confirm', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var overlay_name = $(this).closest('.hotspot.overlay').attr('id');
|
||||
|
||||
var hotspot_name = overlay_name
|
||||
.replace('hotspot_', '')
|
||||
.replace('_overlay', '');
|
||||
|
||||
// Comment below to disable marking hotspots as read in production
|
||||
hotspots.post_hotspot_as_read(hotspot_name);
|
||||
|
||||
overlays.close_overlay(overlay_name);
|
||||
$('#hotspot_' + hotspot_name + '_icon').remove();
|
||||
});
|
||||
|
||||
// stop propagation
|
||||
$('body').on('click', '.hotspot.overlay .hotspot-popover', function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
|
||||
// MAIN CLICK HANDLER
|
||||
|
||||
$(document).on('click', function (e) {
|
||||
|
|
|
@ -2,42 +2,226 @@ var hotspots = (function () {
|
|||
|
||||
var exports = {};
|
||||
|
||||
exports.show = function (hotspot_list) {
|
||||
$('.hotspot').hide();
|
||||
for (var i = 0; i < hotspot_list.length; i += 1) {
|
||||
$("#hotspot_".concat(hotspot_list[i].name)).show();
|
||||
// icon placements (relative to element):
|
||||
var TOP_LEFT = 'TOP_LEFT';
|
||||
var TOP_RIGHT = 'TOP_RIGHT';
|
||||
var BOTTOM_RIGHT = 'BOTTOM_RIGHT';
|
||||
var BOTTOM_LEFT = 'BOTTOM_LEFT';
|
||||
var CENTER = 'CENTER';
|
||||
|
||||
var HOTSPOT_LOCATIONS = {
|
||||
click_to_reply: {
|
||||
element: '.selected_message .messagebox-content',
|
||||
icon: CENTER,
|
||||
},
|
||||
new_topic_button: {
|
||||
element: '#left_bar_compose_stream_button_big',
|
||||
icon: TOP_LEFT,
|
||||
},
|
||||
stream_settings: {
|
||||
element: '#streams_inline_cog',
|
||||
icon: CENTER,
|
||||
},
|
||||
};
|
||||
|
||||
exports.map_hotspots_to_DOM = function (hotspots, locations) {
|
||||
hotspots.forEach(function (hotspot) {
|
||||
hotspot.location = locations[hotspot.name];
|
||||
});
|
||||
};
|
||||
|
||||
exports.post_hotspot_as_read = function (hotspot_name) {
|
||||
channel.post({
|
||||
url: '/json/users/me/hotspots',
|
||||
data: { hotspot: JSON.stringify(hotspot_name) },
|
||||
error: function (err) {
|
||||
blueslip.error(err.responseText);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
function place_icon(hotspot) {
|
||||
if (!$(hotspot.location.element).length === 0) {
|
||||
$('#hotspot_' + hotspot.name + '_icon').css('display', 'none');
|
||||
return;
|
||||
}
|
||||
|
||||
var el_width = $(hotspot.location.element).outerWidth();
|
||||
var el_height = $(hotspot.location.element).outerHeight();
|
||||
|
||||
var offset;
|
||||
switch (hotspot.location.icon) {
|
||||
case TOP_LEFT:
|
||||
offset = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
};
|
||||
break;
|
||||
|
||||
case TOP_RIGHT:
|
||||
offset = {
|
||||
top: 0,
|
||||
left: el_width,
|
||||
};
|
||||
break;
|
||||
|
||||
case BOTTOM_RIGHT:
|
||||
offset = {
|
||||
top: el_height,
|
||||
left: el_width,
|
||||
};
|
||||
break;
|
||||
|
||||
case BOTTOM_LEFT:
|
||||
offset = {
|
||||
top: el_height,
|
||||
left: 0,
|
||||
};
|
||||
break;
|
||||
|
||||
case CENTER:
|
||||
offset = {
|
||||
top: (el_height / 2),
|
||||
left: (el_width / 2),
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
blueslip.error(
|
||||
'Invalid icon placement value for hotspot \'' +
|
||||
hotspot.name + '\''
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
var client_rect = $(hotspot.location.element).get(0).getBoundingClientRect();
|
||||
var placement = {
|
||||
top: client_rect.top + offset.top,
|
||||
left: client_rect.left + offset.left,
|
||||
};
|
||||
|
||||
if ($(hotspot.location.element).css('display') === 'none' ||
|
||||
!$(hotspot.location.element).is(':visible') ||
|
||||
$(hotspot.location.element).is(':hidden')) {
|
||||
$('#hotspot_' + hotspot.name + '_icon').css('display', 'none');
|
||||
} else {
|
||||
$('#hotspot_' + hotspot.name + '_icon').css('display', 'block');
|
||||
$('#hotspot_' + hotspot.name + '_icon').css(placement);
|
||||
}
|
||||
}
|
||||
|
||||
function place_popover(hotspot) {
|
||||
if (!hotspot.location.element) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var popover_width = $('#hotspot_' + hotspot.name + '_overlay .hotspot-popover').outerWidth();
|
||||
var popover_height = $('#hotspot_' + hotspot.name + '_overlay .hotspot-popover').outerHeight();
|
||||
var el_width = $(hotspot.location.element).outerWidth();
|
||||
var el_height = $(hotspot.location.element).outerHeight();
|
||||
var arrow_offset = 20;
|
||||
|
||||
var popover_offset;
|
||||
var arrow_placement;
|
||||
switch (popovers.compute_placement($(hotspot.location.element))) {
|
||||
case 'top':
|
||||
popover_offset = {
|
||||
top: -(popover_height + arrow_offset),
|
||||
left: (el_width / 2) - (popover_width / 2),
|
||||
};
|
||||
arrow_placement = 'bottom';
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
popover_offset = {
|
||||
top: (el_height / 2) - (popover_height / 2),
|
||||
left: -(popover_width + arrow_offset),
|
||||
};
|
||||
arrow_placement = 'right';
|
||||
break;
|
||||
|
||||
case 'bottom':
|
||||
popover_offset = {
|
||||
top: el_height + arrow_offset,
|
||||
left: (el_width / 2) - (popover_width / 2),
|
||||
};
|
||||
arrow_placement = 'top';
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
popover_offset = {
|
||||
top: (el_height / 2) - (popover_height / 2),
|
||||
left: el_width + arrow_offset,
|
||||
};
|
||||
arrow_placement = 'left';
|
||||
break;
|
||||
|
||||
default:
|
||||
blueslip.error(
|
||||
'Invalid popover placement value for hotspot \'' +
|
||||
hotspot.name + '\''
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// position arrow
|
||||
arrow_placement = 'arrow-' + arrow_placement;
|
||||
$('#hotspot_' + hotspot.name + '_overlay .hotspot-popover')
|
||||
.removeClass('arrow-top arrow-left arrow-bottom arrow-right')
|
||||
.addClass(arrow_placement);
|
||||
|
||||
// position popover
|
||||
var client_rect = $(hotspot.location.element).get(0).getBoundingClientRect();
|
||||
var popover_placement = {
|
||||
top: client_rect.top + popover_offset.top,
|
||||
left: client_rect.left + popover_offset.left,
|
||||
};
|
||||
|
||||
$('#hotspot_' + hotspot.name + '_overlay .hotspot-popover')
|
||||
.css(popover_placement);
|
||||
}
|
||||
|
||||
function insert_hotspot_into_DOM(hotspot) {
|
||||
var hotspot_overlay_HTML = templates.render('hotspot_overlay', {
|
||||
name: hotspot.name,
|
||||
title: hotspot.title,
|
||||
description: hotspot.description,
|
||||
});
|
||||
|
||||
var hotspot_icon_HTML =
|
||||
'<div class="hotspot-icon" id="hotspot_' + hotspot.name + '_icon">' +
|
||||
'<span class="dot"></span>' +
|
||||
'<span class="pulse"></span>' +
|
||||
'</div>';
|
||||
|
||||
setTimeout(function () {
|
||||
$('body').prepend(hotspot_icon_HTML);
|
||||
place_icon(hotspot);
|
||||
|
||||
$('body').prepend(hotspot_overlay_HTML);
|
||||
place_popover(hotspot);
|
||||
|
||||
// reposition on any event that might update the UI
|
||||
['resize', 'scroll', 'onkeydown', 'click']
|
||||
.forEach(function (event_name) {
|
||||
window.addEventListener(event_name, function () {
|
||||
place_icon(hotspot);
|
||||
place_popover(hotspot);
|
||||
}, true);
|
||||
});
|
||||
}, (hotspot.delay * 100));
|
||||
}
|
||||
|
||||
exports.load_new = function (new_hotspots) {
|
||||
exports.map_hotspots_to_DOM(new_hotspots, HOTSPOT_LOCATIONS);
|
||||
new_hotspots.forEach(insert_hotspot_into_DOM);
|
||||
};
|
||||
|
||||
exports.initialize = function () {
|
||||
exports.show(page_params.hotspots);
|
||||
exports.load_new(page_params.hotspots);
|
||||
};
|
||||
|
||||
function mark_hotspot_as_read(hotspot) {
|
||||
channel.post({
|
||||
url: '/json/users/me/hotspots',
|
||||
data: {hotspot: JSON.stringify(hotspot)},
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$("#hotspot_click_to_reply").on('click', function (e) {
|
||||
mark_hotspot_as_read("click_to_reply");
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
$("#hotspot_new_topic_button").on('click', function (e) {
|
||||
mark_hotspot_as_read("new_topic_button");
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
$("#hotspot_stream_settings").on('click', function (e) {
|
||||
mark_hotspot_as_read("stream_settings");
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
});
|
||||
|
||||
return exports;
|
||||
}());
|
||||
if (typeof module !== 'undefined') {
|
||||
|
|
|
@ -16,8 +16,10 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
|
|||
break;
|
||||
|
||||
case 'hotspots':
|
||||
hotspots.show(event.hotspots);
|
||||
page_params.hotspots = event.hotspots;
|
||||
hotspots.load_new(event.hotspots);
|
||||
page_params.hotspots = page_params.hotspots ?
|
||||
page_params.hotspots.concat(event.hotspots) :
|
||||
event.hotspots;
|
||||
break;
|
||||
|
||||
case 'muted_topics':
|
||||
|
|
|
@ -263,7 +263,6 @@ $(function () {
|
|||
unread_ui.initialize();
|
||||
activity.initialize();
|
||||
emoji.initialize();
|
||||
hotspots.initialize();
|
||||
compose_fade.initialize();
|
||||
pm_list.initialize();
|
||||
stream_list.initialize();
|
||||
|
|
|
@ -85,6 +85,8 @@ def find(fns):
|
|||
if not html_classes:
|
||||
if 'bar-success' in line:
|
||||
html_classes = ['bar-success', 'bar-danger']
|
||||
elif fn == 'hotspots.js' and 'arrow_placement' in line:
|
||||
html_classes = ['arrow-top', 'arrow-left', 'arrow-bottom', 'arrow-right']
|
||||
elif 'color_class' in line:
|
||||
continue
|
||||
elif 'stream_dark' in line:
|
||||
|
|
Loading…
Reference in New Issue