Files
discourse/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6

183 lines
4.9 KiB
JavaScript

import groups from 'discourse/lib/emoji/groups';
import KeyValueStore from "discourse/lib/key-value-store";
import { emojiList } from 'pretty-text/emoji';
import { emojiUrlFor } from 'discourse/lib/text';
const keyValueStore = new KeyValueStore("discourse_emojis_");
const EMOJI_USAGE = "emojiUsage";
let PER_ROW = 12;
const PER_PAGE = 60;
let ungroupedIcons, recentlyUsedIcons;
if (!keyValueStore.getObject(EMOJI_USAGE)) {
keyValueStore.setObject({key: EMOJI_USAGE, value: {}});
}
function closeSelector() {
$('.emoji-modal, .emoji-modal-wrapper').remove();
$('body, textarea').off('keydown.emoji');
}
function initializeUngroupedIcons() {
const groupedIcons = {};
groups.forEach(group => {
group.icons.forEach(icon => groupedIcons[icon] = true);
});
ungroupedIcons = [];
const emojis = emojiList();
emojis.forEach(emoji => {
if (groupedIcons[emoji] !== true) {
ungroupedIcons.push(emoji);
}
});
if (ungroupedIcons.length) {
groups.push({name: 'ungrouped', icons: ungroupedIcons});
}
}
function trackEmojiUsage(title) {
const recent = keyValueStore.getObject(EMOJI_USAGE) || {};
if (!recent[title]) { recent[title] = { title: title, usage: 0 }; }
recent[title]["usage"]++;
keyValueStore.setObject({key: EMOJI_USAGE, value: recent});
// clear the cache
recentlyUsedIcons = null;
}
function sortByUsage(a, b) {
if (a.usage > b.usage) { return -1; }
if (b.usage > a.usage) { return 1; }
return a.title.localeCompare(b.title);
}
function initializeRecentlyUsedIcons() {
recentlyUsedIcons = [];
const usage = _.map(keyValueStore.getObject(EMOJI_USAGE)).sort(sortByUsage);
const recent = usage.slice(0, PER_ROW);
if (recent.length > 0) {
recent.forEach(emoji => recentlyUsedIcons.push(emoji.title));
const recentGroup = groups.findBy('name', 'recent');
if (recentGroup) {
recentGroup.icons = recentlyUsedIcons;
} else {
groups.push({ name: 'recent', icons: recentlyUsedIcons });
}
}
}
function toolbar(selected) {
if (!ungroupedIcons) { initializeUngroupedIcons(); }
if (!recentlyUsedIcons) { initializeRecentlyUsedIcons(); }
return groups.map((g, i) => {
let icon = g.tabicon;
let title = g.fullname;
if (g.name === "recent") {
icon = "star";
title = "Recent";
} else if (g.name === "ungrouped") {
icon = g.icons[0];
title = "Custom";
}
return { src: emojiUrlFor(icon),
title,
groupId: i,
selected: i === selected };
});
}
function bindEvents(page, offset, options) {
$('.emoji-page a').click(e => {
const title = $(e.currentTarget).attr('title');
trackEmojiUsage(title);
options.onSelect(title);
closeSelector();
return false;
}).hover(e => {
const title = $(e.currentTarget).attr('title');
const html = "<img src='" + emojiUrlFor(title) + "' class='emoji'> <span>:" + title + ":<span>";
$('.emoji-modal .info').html(html);
}, () => $('.emoji-modal .info').html(""));
$('.emoji-modal .nav .next a').click(() => render(page, offset+PER_PAGE, options));
$('.emoji-modal .nav .prev a').click(() => render(page, offset-PER_PAGE, options));
$('.emoji-modal .toolbar a').click(function(){
const p = parseInt($(this).data('group-id'));
render(p, 0, options);
return false;
});
}
function render(page, offset, options) {
keyValueStore.set({key: "emojiPage", value: page});
keyValueStore.set({key: "emojiOffset", value: offset});
const toolbarItems = toolbar(page);
const rows = [];
let row = [];
const icons = groups[page].icons;
const max = offset + PER_PAGE;
for(let i=offset; i<max; i++){
if(!icons[i]){ break; }
if(row.length === (options.perRow || PER_ROW)){
rows.push(row);
row = [];
}
row.push({src: emojiUrlFor(icons[i]), title: icons[i]});
}
rows.push(row);
const model = {
toolbarItems: toolbarItems,
rows: rows,
prevDisabled: offset === 0,
nextDisabled: (max + 1) > icons.length,
modalClass: options.modalClass
};
$('.emoji-modal', options.appendTo).remove();
const template = options.container.lookup('template:emoji-toolbar.raw');
options.appendTo.append(template(model));
bindEvents(page, offset, options);
}
function showSelector(options) {
options = options || {};
options.appendTo = options.appendTo || $('body');
options.appendTo.append('<div class="emoji-modal-wrapper"></div>');
$('.emoji-modal-wrapper').click(() => closeSelector());
if (Discourse.Site.currentProp('mobileView')) { PER_ROW = 9; }
const page = options.page ? _.findIndex(groups, (g) => { return g.name === options.page; })
: keyValueStore.getInt("emojiPage", 0);
const offset = keyValueStore.getInt("emojiOffset", 0);
render(page, offset, options);
$('body, textarea').on('keydown.emoji', e => {
if (e.which === 27) {
closeSelector();
return false;
}
});
}
export { showSelector };