zulip/static/js/hotspots.js

227 lines
6.5 KiB
JavaScript
Raw Normal View History

var hotspots = (function () {
var exports = {};
// popover orientations
var TOP = 'top';
var LEFT = 'left';
var RIGHT = 'right';
var BOTTOM = 'bottom';
var VIEWPORT_CENTER = 'viewport_center';
// popover orientation can optionally be fixed here (property: popover),
// otherwise popovers.compute_placement is used to compute orientation
2017-07-14 03:21:30 +02:00
var HOTSPOT_LOCATIONS = {
click_to_reply: {
element: '.selected_message .messagebox-content',
offset_x: 0.5,
offset_y: 0.5,
2017-07-14 03:21:30 +02:00
},
new_topic_button: {
element: '#left_bar_compose_stream_button_big',
offset_x: 0,
offset_y: 0,
2017-07-14 03:21:30 +02:00
},
stream_settings: {
element: '#streams_inline_cog',
offset_x: 0.5,
offset_y: 0.5,
2017-07-14 03:21:30 +02:00
},
};
// popover illustration url(s)
var WHALE = '/static/images/hotspots/whale.svg';
2017-07-14 03:21:30 +02:00
exports.map_hotspots_to_DOM = function (hotspots, locations) {
hotspots.forEach(function (hotspot) {
hotspot.location = locations[hotspot.name];
});
};
2017-07-14 03:21:30 +02:00
exports.post_hotspot_as_read = function (hotspot_name) {
channel.post({
url: '/json/users/me/hotspots',
2017-07-14 03:21:30 +02:00
data: { hotspot: JSON.stringify(hotspot_name) },
error: function (err) {
blueslip.error(err.responseText);
},
});
2017-07-14 03:21:30 +02:00
};
function place_icon(hotspot) {
if ($(hotspot.location.element).length === 0) {
2017-07-14 03:21:30 +02:00
$('#hotspot_' + hotspot.name + '_icon').css('display', 'none');
return false;
2017-07-14 03:21:30 +02:00
}
var offset = {
top: $(hotspot.location.element).outerHeight() * hotspot.location.offset_y,
left: $(hotspot.location.element).outerWidth() * hotspot.location.offset_x,
};
2017-07-14 03:21:30 +02:00
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');
return false;
2017-07-14 03:21:30 +02:00
}
$('#hotspot_' + hotspot.name + '_icon').css('display', 'block');
$('#hotspot_' + hotspot.name + '_icon').css(placement);
return true;
}
2017-07-14 03:21:30 +02:00
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;
var orientation = hotspot.location.popover ||
popovers.compute_placement(
$(hotspot.location.element),
popover_height,
popover_width,
false
);
switch (orientation) {
case TOP:
2017-07-14 03:21:30 +02:00
popover_offset = {
top: -(popover_height + arrow_offset),
left: (el_width / 2) - (popover_width / 2),
};
arrow_placement = 'bottom';
break;
case LEFT:
2017-07-14 03:21:30 +02:00
popover_offset = {
top: (el_height / 2) - (popover_height / 2),
left: -(popover_width + arrow_offset),
};
arrow_placement = 'right';
break;
case BOTTOM:
2017-07-14 03:21:30 +02:00
popover_offset = {
top: el_height + arrow_offset,
left: (el_width / 2) - (popover_width / 2),
};
arrow_placement = 'top';
break;
case RIGHT:
2017-07-14 03:21:30 +02:00
popover_offset = {
top: (el_height / 2) - (popover_height / 2),
left: el_width + arrow_offset,
};
arrow_placement = 'left';
break;
case VIEWPORT_CENTER:
popover_offset = {
top: el_height / 2,
left: el_width / 2,
};
arrow_placement = '';
break;
2017-07-14 03:21:30 +02:00
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 popover_placement;
if (orientation === VIEWPORT_CENTER) {
popover_placement = {
top: '45%',
left: '50%',
transform: 'translate(-50%, -50%)',
};
} else {
var client_rect = $(hotspot.location.element).get(0).getBoundingClientRect();
popover_placement = {
top: client_rect.top + popover_offset.top,
left: client_rect.left + popover_offset.left,
transform: '',
};
}
2017-07-14 03:21:30 +02:00
$('#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,
img: WHALE,
});
2017-07-14 03:21:30 +02:00
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);
$('body').prepend(hotspot_overlay_HTML);
if (place_icon(hotspot)) {
place_popover(hotspot);
}
2017-07-14 03:21:30 +02:00
// reposition on any event that might update the UI
['resize', 'scroll', 'onkeydown', 'click']
.forEach(function (event_name) {
window.addEventListener(event_name, _.debounce(function () {
if (place_icon(hotspot)) {
place_popover(hotspot);
}
}, 10), true);
2017-07-14 03:21:30 +02:00
});
}, (hotspot.delay * 100));
}
exports.is_open = function () {
return $('.hotspot.overlay').hasClass('show');
};
2017-07-14 03:21:30 +02:00
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.load_new(page_params.hotspots);
};
return exports;
}());
if (typeof module !== 'undefined') {
module.exports = hotspots;
}