mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 14:03:30 +00:00
This commit moves the `emoji_collection` datasource in the emoji picker to emoji.js and renames it to `emojis_by_name`. It is a mapping from emoji name to object where each object describes an emoji. This is an effort in the direction of de-duplicating and unifying the datasets being used by various our widgets(like emoji picker and composebox typeahead) in the webapp. Migrating all the widgets to a single datasource will help us in removing the whole class of annoying bugs which causes some emojis to be missing from some widgets.
725 lines
25 KiB
JavaScript
725 lines
25 KiB
JavaScript
var emoji_picker = (function () {
|
|
|
|
var exports = {};
|
|
|
|
// Emoji picker is of fixed width and height. Update these
|
|
// whenever these values are changed in `reactions.css`.
|
|
var APPROX_HEIGHT = 375;
|
|
var APPROX_WIDTH = 255;
|
|
|
|
// The functionalities for reacting to a message with an emoji
|
|
// and composing a message with an emoji share a single widget,
|
|
// implemented as the emoji_popover.
|
|
exports.complete_emoji_catalog = [];
|
|
exports.frequently_used_emojis_list = [
|
|
'1f44d', // thumbs_up
|
|
'1f389', // party_popper
|
|
'1f642', // simple_smile
|
|
'2764', // heart
|
|
'1f6e0', // hammer_and_wrench
|
|
'1f419', // octopus
|
|
];
|
|
var current_message_emoji_popover_elem;
|
|
var emoji_catalog_last_coordinates = {
|
|
section: 0,
|
|
index: 0,
|
|
};
|
|
var current_section = 0;
|
|
var current_index = 0;
|
|
var search_is_active = false;
|
|
var search_results = [];
|
|
var section_head_offsets = [];
|
|
|
|
function get_all_emoji_categories() {
|
|
return [
|
|
{ name: "Popular", icon: "fa-thumbs-o-up" },
|
|
{ name: "Smileys & People", icon: "fa-smile-o" },
|
|
{ name: "Animals & Nature", icon: "fa-leaf" },
|
|
{ name: "Food & Drink", icon: "fa-cutlery" },
|
|
{ name: "Activities", icon: "fa-soccer-ball-o" },
|
|
{ name: "Travel & Places", icon: "fa-car" },
|
|
{ name: "Objects", icon: "fa-lightbulb-o" },
|
|
{ name: "Symbols", icon: "fa-hashtag" },
|
|
{ name: "Custom", icon: "fa-cog" },
|
|
];
|
|
}
|
|
|
|
function get_total_sections() {
|
|
if (search_is_active) {
|
|
return 1;
|
|
}
|
|
return exports.complete_emoji_catalog.length;
|
|
}
|
|
|
|
function get_max_index(section) {
|
|
if (search_is_active) {
|
|
return search_results.length;
|
|
} else if (section >= 0 && section < get_total_sections()) {
|
|
return exports.complete_emoji_catalog[section].emojis.length;
|
|
}
|
|
}
|
|
|
|
function get_emoji_id(section, index) {
|
|
var type = "emoji_picker_emoji";
|
|
if (search_is_active) {
|
|
type = "emoji_search_result";
|
|
}
|
|
var emoji_id = [type, section, index].join(",");
|
|
return emoji_id;
|
|
}
|
|
|
|
function get_emoji_coordinates(emoji_id) {
|
|
// Emoji id is of the following form:
|
|
// <emoji_type>_<section_number>_<index>.
|
|
// See `get_emoji_id()`.
|
|
var emoji_info = emoji_id.split(",");
|
|
return {
|
|
section: parseInt(emoji_info[1], 10),
|
|
index: parseInt(emoji_info[2], 10),
|
|
};
|
|
}
|
|
|
|
function show_search_results() {
|
|
$(".emoji-popover-emoji-map").hide();
|
|
$(".emoji-popover-category-tabs").hide();
|
|
$(".emoji-search-results-container").show();
|
|
emoji_catalog_last_coordinates = {
|
|
section: current_section,
|
|
index: current_index,
|
|
};
|
|
current_section = 0;
|
|
current_index = 0;
|
|
search_is_active = true;
|
|
}
|
|
|
|
function show_emoji_catalog() {
|
|
$(".emoji-popover-emoji-map").show();
|
|
$(".emoji-popover-category-tabs").show();
|
|
$(".emoji-search-results-container").hide();
|
|
current_section = emoji_catalog_last_coordinates.section;
|
|
current_index = emoji_catalog_last_coordinates.index;
|
|
search_is_active = false;
|
|
}
|
|
|
|
exports.generate_emoji_picker_data = function (realm_emojis) {
|
|
exports.complete_emoji_catalog = {};
|
|
exports.complete_emoji_catalog.Custom = [];
|
|
_.each(realm_emojis, function (realm_emoji, realm_emoji_name) {
|
|
exports.complete_emoji_catalog.Custom.push(emoji.emojis_by_name[realm_emoji_name]);
|
|
});
|
|
|
|
_.each(emoji_codes.emoji_catalog, function (codepoints, category) {
|
|
exports.complete_emoji_catalog[category] = [];
|
|
_.each(codepoints, function (codepoint) {
|
|
if (emoji_codes.codepoint_to_name.hasOwnProperty(codepoint)) {
|
|
var emoji_name = emoji_codes.codepoint_to_name[codepoint];
|
|
if (emoji.emojis_by_name.hasOwnProperty(emoji_name) &&
|
|
emoji.emojis_by_name[emoji_name].is_realm_emoji !== true) {
|
|
exports.complete_emoji_catalog[category].push(
|
|
emoji.emojis_by_name[emoji_name]
|
|
);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
exports.complete_emoji_catalog.Popular = [];
|
|
_.each(exports.frequently_used_emojis_list, function (codepoint) {
|
|
if (emoji_codes.codepoint_to_name.hasOwnProperty(codepoint)) {
|
|
var emoji_name = emoji_codes.codepoint_to_name[codepoint];
|
|
if (emoji.emojis_by_name.hasOwnProperty(emoji_name)) {
|
|
exports.complete_emoji_catalog.Popular.push(emoji.emojis_by_name[emoji_name]);
|
|
}
|
|
}
|
|
});
|
|
|
|
var categories = get_all_emoji_categories().filter(function (category) {
|
|
return !!exports.complete_emoji_catalog[category.name];
|
|
});
|
|
exports.complete_emoji_catalog = categories.map(function (category) {
|
|
return {
|
|
name: category.name,
|
|
icon: category.icon,
|
|
emojis: exports.complete_emoji_catalog[category.name],
|
|
};
|
|
});
|
|
};
|
|
|
|
var generate_emoji_picker_content = function (id) {
|
|
var emojis_used = [];
|
|
|
|
if (id !== undefined) {
|
|
emojis_used = reactions.get_emojis_used_by_user_for_message_id(id);
|
|
}
|
|
_.each(emoji.emojis_by_name, function (emoji_dict) {
|
|
emoji_dict.has_reacted = _.any(emoji_dict.aliases, function (alias) {
|
|
return _.contains(emojis_used, alias);
|
|
});
|
|
});
|
|
|
|
return templates.render('emoji_popover_content', {
|
|
message_id: id,
|
|
emoji_categories: exports.complete_emoji_catalog,
|
|
});
|
|
};
|
|
|
|
function refill_section_head_offsets(popover) {
|
|
section_head_offsets = [];
|
|
popover.find('.emoji-popover-subheading').each(function () {
|
|
section_head_offsets.push({
|
|
section: $(this).attr('data-section'),
|
|
position_y: $(this).position().top,
|
|
});
|
|
});
|
|
}
|
|
|
|
exports.reactions_popped = function () {
|
|
return current_message_emoji_popover_elem !== undefined;
|
|
};
|
|
|
|
exports.hide_emoji_popover = function () {
|
|
$('.has_popover').removeClass('has_popover has_emoji_popover');
|
|
if (exports.reactions_popped()) {
|
|
var orig_title = current_message_emoji_popover_elem.data("original-title");
|
|
ui.destroy_scrollbar($(".emoji-popover-emoji-map"));
|
|
ui.destroy_scrollbar($(".emoji-search-results-container"));
|
|
current_message_emoji_popover_elem.popover("destroy");
|
|
current_message_emoji_popover_elem.prop("title", orig_title);
|
|
current_message_emoji_popover_elem.removeClass("reaction_button_visible");
|
|
current_message_emoji_popover_elem = undefined;
|
|
}
|
|
};
|
|
|
|
function get_selected_emoji() {
|
|
return $(".emoji-popover-emoji").filter(":focus")[0];
|
|
}
|
|
|
|
function get_rendered_emoji(section, index) {
|
|
var emoji_id = get_emoji_id(section, index);
|
|
var emoji = $(".emoji-popover-emoji[data-emoji-id='" + emoji_id + "']");
|
|
if (emoji.length > 0) {
|
|
return emoji;
|
|
}
|
|
}
|
|
|
|
function filter_emojis() {
|
|
var elt = $(".emoji-popover-filter").expectOne();
|
|
var query = elt.val().trim().toLowerCase();
|
|
var message_id = $(".emoji-search-results-container").data("message-id");
|
|
var search_results_visible = $(".emoji-search-results-container").is(":visible");
|
|
if (query !== "") {
|
|
var categories = exports.complete_emoji_catalog;
|
|
var search_terms = query.split(" ");
|
|
search_results = [];
|
|
_.each(categories, function (category) {
|
|
if (category.name === "Popular") {
|
|
return;
|
|
}
|
|
var emojis = category.emojis;
|
|
_.each(emojis, function (emoji_dict) {
|
|
_.any(emoji_dict.aliases, function (alias) {
|
|
var match = _.every(search_terms, function (search_term) {
|
|
return alias.indexOf(search_term) >= 0;
|
|
});
|
|
if (match) {
|
|
search_results.push(_.extend({}, emoji_dict, {name: alias}));
|
|
return true;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
var rendered_search_results = templates.render('emoji_popover_search_results', {
|
|
search_results: search_results,
|
|
message_id: message_id,
|
|
});
|
|
$('.emoji-search-results').html(rendered_search_results);
|
|
ui.update_scrollbar($(".emoji-search-results-container"));
|
|
if (!search_results_visible) {
|
|
show_search_results();
|
|
}
|
|
} else {
|
|
show_emoji_catalog();
|
|
}
|
|
}
|
|
|
|
function get_alias_to_be_used(message_id, emoji_name) {
|
|
// If the user has reacted to this message, then this function
|
|
// returns the alias of this emoji he used, otherwise, returns
|
|
// the passed name as it is.
|
|
var message = message_store.get(message_id);
|
|
var aliases = [emoji_name];
|
|
if (!emoji.active_realm_emojis.hasOwnProperty(emoji_name)) {
|
|
if (emoji_codes.name_to_codepoint.hasOwnProperty(emoji_name)) {
|
|
var codepoint = emoji_codes.name_to_codepoint[emoji_name];
|
|
aliases = emoji.default_emoji_aliases[codepoint];
|
|
} else {
|
|
blueslip.error("Invalid emoji name.");
|
|
return;
|
|
}
|
|
}
|
|
var user_id = page_params.user_id;
|
|
var reaction = _.find(message.reactions, function (reaction) {
|
|
return reaction.user.id === user_id && _.contains(aliases, reaction.emoji_name);
|
|
});
|
|
if (reaction) {
|
|
return reaction.emoji_name;
|
|
}
|
|
return emoji_name;
|
|
}
|
|
|
|
function toggle_reaction(emoji_name) {
|
|
var message_id = current_msg_list.selected_id();
|
|
var message = message_store.get(message_id);
|
|
if (!message) {
|
|
blueslip.error('reactions: Bad message id: ' + message_id);
|
|
return;
|
|
}
|
|
|
|
var alias = get_alias_to_be_used(message_id, emoji_name);
|
|
reactions.toggle_emoji_reaction(message_id, alias);
|
|
}
|
|
|
|
function maybe_select_emoji(e) {
|
|
if (e.keyCode === 13) { // enter key
|
|
e.preventDefault();
|
|
var first_emoji = get_rendered_emoji(0, 0);
|
|
if (first_emoji) {
|
|
if (emoji_picker.is_composition(first_emoji)) {
|
|
first_emoji.click();
|
|
} else {
|
|
toggle_reaction(first_emoji.data("emoji-name"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.toggle_selected_emoji = function () {
|
|
// Toggle the currently selected emoji.
|
|
var selected_emoji = get_selected_emoji();
|
|
|
|
if (selected_emoji === undefined) {
|
|
return;
|
|
}
|
|
|
|
var emoji_name = $(selected_emoji).data("emoji-name");
|
|
|
|
toggle_reaction(emoji_name);
|
|
};
|
|
|
|
function round_off_to_previous_multiple(number_to_round, multiple) {
|
|
return number_to_round - number_to_round % multiple;
|
|
}
|
|
|
|
function reset_emoji_showcase() {
|
|
$(".emoji-showcase-container").html("");
|
|
}
|
|
|
|
function update_emoji_showcase($focused_emoji) {
|
|
// Don't use jQuery's data() function here. It has the side-effect
|
|
// of converting emoji names like :100:, :1234: etc to number.
|
|
var focused_emoji_name = $focused_emoji.attr("data-emoji-name");
|
|
var canonical_name = emoji.get_canonical_name(focused_emoji_name);
|
|
var focused_emoji_dict = emoji.emojis_by_name[canonical_name];
|
|
|
|
var emoji_dict = _.extend({}, focused_emoji_dict, {
|
|
name: focused_emoji_name.replace(/_/g, ' '),
|
|
});
|
|
var rendered_showcase = templates.render("emoji_showcase", {
|
|
emoji_dict: emoji_dict,
|
|
});
|
|
|
|
$(".emoji-showcase-container").html(rendered_showcase);
|
|
}
|
|
|
|
function may_be_change_focused_emoji(next_section, next_index, preserve_scroll) {
|
|
var next_emoji = get_rendered_emoji(next_section, next_index);
|
|
if (next_emoji) {
|
|
current_section = next_section;
|
|
current_index = next_index;
|
|
if (!preserve_scroll) {
|
|
next_emoji.focus();
|
|
} else {
|
|
var $emoji_map = $(".emoji-popover-emoji-map");
|
|
var start = $emoji_map.scrollTop();
|
|
next_emoji.focus();
|
|
if ($emoji_map.scrollTop() !== start) {
|
|
$emoji_map.scrollTop(start);
|
|
}
|
|
}
|
|
update_emoji_showcase(next_emoji);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function may_be_change_active_section(next_section) {
|
|
if (next_section >= 0 && next_section < get_total_sections()) {
|
|
current_section = next_section;
|
|
current_index = 0;
|
|
var offset = section_head_offsets[current_section];
|
|
if (offset) {
|
|
$(".emoji-popover-emoji-map").scrollTop(offset.position_y);
|
|
may_be_change_focused_emoji(current_section, current_index);
|
|
}
|
|
}
|
|
}
|
|
|
|
function get_next_emoji_coordinates(move_by) {
|
|
var next_section = current_section;
|
|
var next_index = current_index + move_by;
|
|
var max_len;
|
|
if (next_index < 0) {
|
|
next_section = next_section - 1;
|
|
if (next_section >= 0) {
|
|
next_index = get_max_index(next_section) - 1;
|
|
if (move_by === -6) {
|
|
max_len = get_max_index(next_section);
|
|
var prev_multiple = round_off_to_previous_multiple(max_len, 6);
|
|
next_index = prev_multiple + current_index;
|
|
next_index = next_index >= max_len
|
|
? prev_multiple + current_index - 6
|
|
: next_index;
|
|
}
|
|
}
|
|
} else if (next_index >= get_max_index(next_section)) {
|
|
next_section = next_section + 1;
|
|
if (next_section < get_total_sections()) {
|
|
next_index = 0;
|
|
if (move_by === 6) {
|
|
max_len = get_max_index(next_index);
|
|
next_index = current_index % 6;
|
|
next_index = next_index >= max_len ? max_len - 1 : next_index;
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
section: next_section,
|
|
index: next_index,
|
|
};
|
|
}
|
|
|
|
function change_focus_to_filter() {
|
|
$('.emoji-popover-filter').focus();
|
|
// If search is active reset current selected emoji to first emoji.
|
|
if (search_is_active) {
|
|
current_section = 0;
|
|
current_index = 0;
|
|
}
|
|
reset_emoji_showcase();
|
|
}
|
|
|
|
exports.navigate = function (event_name) {
|
|
if (event_name === 'toggle_reactions_popover' && exports.reactions_popped() &&
|
|
(search_is_active === false || search_results.length === 0)) {
|
|
exports.hide_emoji_popover();
|
|
return true;
|
|
}
|
|
|
|
// If search is active and results are empty then return immediately.
|
|
if (search_is_active === true && search_results.length === 0) {
|
|
return;
|
|
}
|
|
|
|
var selected_emoji = get_rendered_emoji(current_section, current_index);
|
|
var is_filter_focused = $('.emoji-popover-filter').is(':focus');
|
|
var next_section = 0;
|
|
// special cases
|
|
if (is_filter_focused) {
|
|
// Move down into emoji map.
|
|
var filter_text = $(".emoji-popover-filter").val();
|
|
var is_cursor_at_end = $(".emoji-popover-filter").caret() === filter_text.length;
|
|
if (event_name === "down_arrow" ||
|
|
is_cursor_at_end && event_name === "right_arrow") {
|
|
selected_emoji.focus();
|
|
if (current_section === 0 && current_index < 6) {
|
|
$(".emoji-popover-emoji-map").scrollTop(0);
|
|
}
|
|
update_emoji_showcase(selected_emoji);
|
|
return true;
|
|
}
|
|
if (event_name === "tab") {
|
|
selected_emoji.focus();
|
|
update_emoji_showcase(selected_emoji);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else if (current_section === 0 && current_index < 6 && event_name === 'up_arrow' ||
|
|
current_section === 0 && current_index === 0 && event_name === 'left_arrow') {
|
|
if (selected_emoji) {
|
|
// In this case, we're move up into the reaction
|
|
// filter. Here, we override the default browser
|
|
// behavior, which in Firefox is good (preserving
|
|
// the cursor position) and in Chrome is bad (cursor
|
|
// goes to beginning) with something reasonable and
|
|
// consistent (cursor goes to the end of the filter
|
|
// string).
|
|
$('.emoji-popover-filter').focus().caret(Infinity);
|
|
$(".emoji-popover-emoji-map").scrollTop(0);
|
|
$(".emoji-search-results-container").scrollTop(0);
|
|
current_section = 0;
|
|
current_index = 0;
|
|
reset_emoji_showcase();
|
|
return true;
|
|
}
|
|
} else if (event_name === 'tab') {
|
|
change_focus_to_filter();
|
|
return true;
|
|
} else if (event_name === 'shift_tab') {
|
|
if (!is_filter_focused) {
|
|
change_focus_to_filter();
|
|
}
|
|
return true;
|
|
} else if (event_name === 'page_up') {
|
|
next_section = current_section - 1;
|
|
may_be_change_active_section(next_section);
|
|
return true;
|
|
} else if (event_name === 'page_down') {
|
|
next_section = current_section + 1;
|
|
may_be_change_active_section(next_section);
|
|
return true;
|
|
} else if (!is_filter_focused) {
|
|
var next_coord = {};
|
|
switch (event_name) {
|
|
case 'down_arrow':
|
|
next_coord = get_next_emoji_coordinates(6);
|
|
break;
|
|
case 'up_arrow':
|
|
next_coord = get_next_emoji_coordinates(-6);
|
|
break;
|
|
case 'left_arrow':
|
|
next_coord = get_next_emoji_coordinates(-1);
|
|
break;
|
|
case 'right_arrow':
|
|
next_coord = get_next_emoji_coordinates(1);
|
|
break;
|
|
}
|
|
return may_be_change_focused_emoji(next_coord.section, next_coord.index);
|
|
}
|
|
return false;
|
|
};
|
|
|
|
function process_keypress(e) {
|
|
var is_filter_focused = $('.emoji-popover-filter').is(':focus');
|
|
var pressed_key = e.which;
|
|
if (!is_filter_focused && pressed_key !== 58) {
|
|
// ':' => 58, is a hotkey for toggling reactions popover.
|
|
if (pressed_key >= 32 && pressed_key <= 126 || pressed_key === 8) {
|
|
// Handle only printable characters or backspace.
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
var emoji_filter = $('.emoji-popover-filter');
|
|
var old_query = emoji_filter.val();
|
|
var new_query = "";
|
|
|
|
if (pressed_key === 8) { // Handles backspace.
|
|
new_query = old_query.slice(0, -1);
|
|
} else { // Handles any printable character.
|
|
var key_str = String.fromCharCode(e.which);
|
|
new_query = old_query + key_str;
|
|
}
|
|
|
|
emoji_filter.val(new_query);
|
|
change_focus_to_filter();
|
|
filter_emojis();
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.emoji_select_tab = function (elt) {
|
|
var scrolltop = elt.scrollTop();
|
|
var scrollheight = elt.prop('scrollHeight');
|
|
var elt_height = elt.height();
|
|
var currently_selected = "";
|
|
section_head_offsets.forEach(function (o) {
|
|
if (scrolltop + elt_height / 2 >= o.position_y) {
|
|
currently_selected = o.section;
|
|
}
|
|
});
|
|
// Handles the corner case of the last category being
|
|
// smaller than half of the emoji picker height.
|
|
if (elt_height + scrolltop === scrollheight) {
|
|
currently_selected = section_head_offsets[section_head_offsets.length - 1].section;
|
|
}
|
|
// Handles the corner case of the scrolling back to top.
|
|
if (scrolltop === 0) {
|
|
currently_selected = section_head_offsets[0].section;
|
|
}
|
|
if (currently_selected) {
|
|
$('.emoji-popover-tab-item.active').removeClass('active');
|
|
$('.emoji-popover-tab-item[data-tab-name="' + currently_selected + '"]').addClass('active');
|
|
}
|
|
};
|
|
|
|
function register_popover_events(popover) {
|
|
var $emoji_map = popover.find('.emoji-popover-emoji-map');
|
|
|
|
$emoji_map.on("scroll", function () {
|
|
emoji_picker.emoji_select_tab($emoji_map);
|
|
});
|
|
|
|
$('.emoji-popover-filter').on('input', filter_emojis);
|
|
$('.emoji-popover-filter').keydown(maybe_select_emoji);
|
|
$('.emoji-popover').keypress(process_keypress);
|
|
$('.emoji-popover').keydown(function (e) {
|
|
// Because of cross-browser issues we need to handle backspace
|
|
// key separately. Firefox fires `keypress` event for backspace
|
|
// key but chrome doesn't so we need to trigger the logic for
|
|
// handling backspace in `keydown` event which is fired by both.
|
|
if (e.which === 8) {
|
|
process_keypress(e);
|
|
}
|
|
});
|
|
}
|
|
|
|
exports.render_emoji_popover = function (elt, id) {
|
|
var template_args = {
|
|
class: "emoji-info-popover",
|
|
};
|
|
var placement = popovers.compute_placement(elt, APPROX_HEIGHT, APPROX_WIDTH, true);
|
|
|
|
var template = templates.render('emoji_popover', template_args);
|
|
|
|
// if the window is mobile sized, add the `.popover-flex` wrapper to the emoji
|
|
// popover so that it will be wrapped in flex and centered in the screen.
|
|
if (window.innerWidth <= 768) {
|
|
template = "<div class='popover-flex'>" + template + "</div>";
|
|
}
|
|
|
|
elt.popover({
|
|
// temporary patch for handling popover placement of `viewport_center`
|
|
placement: placement === 'viewport_center' ? 'left' : placement,
|
|
template: template,
|
|
title: "",
|
|
content: generate_emoji_picker_content(id),
|
|
trigger: "manual",
|
|
});
|
|
elt.popover("show");
|
|
elt.prop("title", i18n.t("Add emoji reaction (:)"));
|
|
$('.emoji-popover-filter').focus();
|
|
ui.set_up_scrollbar($(".emoji-popover-emoji-map"));
|
|
ui.set_up_scrollbar($(".emoji-search-results-container"));
|
|
current_message_emoji_popover_elem = elt;
|
|
|
|
emoji_catalog_last_coordinates = {
|
|
section: 0,
|
|
index: 0,
|
|
};
|
|
show_emoji_catalog();
|
|
|
|
var popover = elt.data('popover').$tip;
|
|
refill_section_head_offsets(popover);
|
|
register_popover_events(popover);
|
|
};
|
|
|
|
exports.toggle_emoji_popover = function (element, id) {
|
|
var last_popover_elem = current_message_emoji_popover_elem;
|
|
popovers.hide_all();
|
|
if (last_popover_elem !== undefined
|
|
&& last_popover_elem.get()[0] === element) {
|
|
// We want it to be the case that a user can dismiss a popover
|
|
// by clicking on the same element that caused the popover.
|
|
return;
|
|
}
|
|
|
|
$(element).closest('.message_row').toggleClass('has_popover has_emoji_popover');
|
|
var elt = $(element);
|
|
if (id !== undefined) {
|
|
current_msg_list.select_id(id);
|
|
}
|
|
|
|
if (elt.data('popover') === undefined) {
|
|
// Keep the element over which the popover is based off visible.
|
|
elt.addClass("reaction_button_visible");
|
|
emoji_picker.render_emoji_popover(elt, id);
|
|
}
|
|
reset_emoji_showcase();
|
|
};
|
|
|
|
exports.register_click_handlers = function () {
|
|
|
|
$(document).on('click', '.emoji-popover-emoji.reaction', function () {
|
|
// When an emoji is clicked in the popover,
|
|
// if the user has reacted to this message with this emoji
|
|
// the reaction is removed
|
|
// otherwise, the reaction is added
|
|
var emoji_name = $(this).data("emoji-name");
|
|
toggle_reaction(emoji_name);
|
|
});
|
|
|
|
$(document).on('click', '.emoji-popover-emoji.composition', function (e) {
|
|
var emoji_name = $(this).data("emoji-name");
|
|
var emoji_text = ':' + emoji_name + ':';
|
|
compose_ui.insert_syntax_and_focus(emoji_text);
|
|
e.stopPropagation();
|
|
emoji_picker.hide_emoji_popover();
|
|
});
|
|
|
|
$("#compose").on("click", "#emoji_map", function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
emoji_picker.toggle_emoji_popover(this);
|
|
});
|
|
|
|
$("#main_div").on("click", ".reaction_button", function (e) {
|
|
e.stopPropagation();
|
|
|
|
var message_id = rows.get_message_id(this);
|
|
emoji_picker.toggle_emoji_popover(this, message_id);
|
|
});
|
|
|
|
$("body").on("click", ".actions_popover .reaction_button", function (e) {
|
|
var msgid = $(e.currentTarget).data('message-id');
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
// HACK: Because we need the popover to be based off an
|
|
// element that definitely exists in the page even if the
|
|
// message wasn't sent by us and thus the .reaction_hover
|
|
// element is not present, we use the message's
|
|
// .icon-vector-chevron-down element as the base for the popover.
|
|
var elem = $(".selected_message .actions_hover")[0];
|
|
emoji_picker.toggle_emoji_popover(elem, msgid);
|
|
});
|
|
|
|
$("body").on("click", ".emoji-popover-tab-item", function (e) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
var offset = _.find(section_head_offsets, function (o) {
|
|
return o.section === $(this).attr("data-tab-name");
|
|
}.bind(this));
|
|
|
|
if (offset) {
|
|
$(".emoji-popover-emoji-map").scrollTop(offset.position_y);
|
|
}
|
|
});
|
|
|
|
$("body").on("click", ".emoji-popover-filter", function () {
|
|
reset_emoji_showcase();
|
|
});
|
|
|
|
$("body").on("mouseenter", ".emoji-popover-emoji", function () {
|
|
var emoji_id = $(this).data("emoji-id");
|
|
var emoji_coordinates = get_emoji_coordinates(emoji_id);
|
|
|
|
may_be_change_focused_emoji(emoji_coordinates.section, emoji_coordinates.index, true);
|
|
});
|
|
};
|
|
|
|
exports.is_composition = function (emoji) {
|
|
return $(emoji).hasClass('composition');
|
|
};
|
|
|
|
exports.initialize = function () {
|
|
exports.generate_emoji_picker_data(emoji.active_realm_emojis);
|
|
};
|
|
|
|
return exports;
|
|
|
|
}());
|
|
|
|
if (typeof module !== 'undefined') {
|
|
module.exports = emoji_picker;
|
|
}
|
|
window.emoji_picker = emoji_picker;
|