2017-01-24 01:48:35 +01:00
|
|
|
var hotspots = (function () {
|
|
|
|
|
|
|
|
var exports = {};
|
|
|
|
|
2017-07-14 03:21:30 +02:00
|
|
|
// 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';
|
|
|
|
|
2017-08-01 00:36:09 +02:00
|
|
|
// 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',
|
|
|
|
icon: CENTER,
|
|
|
|
},
|
|
|
|
new_topic_button: {
|
|
|
|
element: '#left_bar_compose_stream_button_big',
|
|
|
|
icon: TOP_LEFT,
|
|
|
|
},
|
|
|
|
stream_settings: {
|
|
|
|
element: '#streams_inline_cog',
|
|
|
|
icon: CENTER,
|
|
|
|
},
|
2017-01-24 01:48:35 +01:00
|
|
|
};
|
|
|
|
|
2017-08-02 02:25:52 +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-01-24 01:48:35 +01:00
|
|
|
};
|
|
|
|
|
2017-07-14 03:21:30 +02:00
|
|
|
exports.post_hotspot_as_read = function (hotspot_name) {
|
2017-01-24 01:48:35 +01:00
|
|
|
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-01-24 01:48:35 +01:00
|
|
|
});
|
2017-07-14 03:21:30 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2017-01-24 01:48:35 +01:00
|
|
|
}
|
|
|
|
|
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;
|
2017-08-01 00:36:09 +02:00
|
|
|
var orientation = hotspot.location.popover ||
|
|
|
|
popovers.compute_placement($(hotspot.location.element));
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2017-08-01 00:36:09 +02:00
|
|
|
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;
|
|
|
|
|
2017-08-01 00:36:09 +02:00
|
|
|
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;
|
|
|
|
|
2017-08-01 00:36:09 +02:00
|
|
|
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;
|
|
|
|
|
2017-08-01 00:36:09 +02:00
|
|
|
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
|
2017-08-01 00:36:09 +02:00
|
|
|
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,
|
2017-08-02 02:25:52 +02:00
|
|
|
img: WHALE,
|
2017-01-24 01:48:35 +01:00
|
|
|
});
|
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);
|
|
|
|
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) {
|
2017-08-02 03:01:17 +02:00
|
|
|
window.addEventListener(event_name, _.debounce(function () {
|
2017-07-14 03:21:30 +02:00
|
|
|
place_icon(hotspot);
|
|
|
|
place_popover(hotspot);
|
2017-08-02 03:01:17 +02:00
|
|
|
}, 10), true);
|
2017-07-14 03:21:30 +02:00
|
|
|
});
|
|
|
|
}, (hotspot.delay * 100));
|
|
|
|
}
|
|
|
|
|
2017-08-02 04:46:56 +02:00
|
|
|
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);
|
|
|
|
};
|
2017-01-24 01:48:35 +01:00
|
|
|
|
|
|
|
return exports;
|
|
|
|
}());
|
|
|
|
if (typeof module !== 'undefined') {
|
|
|
|
module.exports = hotspots;
|
|
|
|
}
|