xmpp.chapril.org-conversejs/src/converse-emoji-views.js

216 lines
8.3 KiB
JavaScript
Raw Normal View History

// Converse.js
// https://conversejs.org
//
// Copyright (c) 2013-2019, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
/**
* @module converse-emoji-views
*/
import "@converse/headless/converse-emoji";
import BrowserStorage from "backbone.browserStorage";
import bootstrap from "bootstrap.native";
import tpl_emoji_button from "templates/emoji_button.html";
import tpl_emojis from "templates/emojis.html";
const { Backbone } = converse.env;
const u = converse.env.utils;
converse.plugins.add('converse-emoji-views', {
/* Plugin dependencies are other plugins which might be
* overridden or relied upon, and therefore need to be loaded before
* this plugin.
*
* If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found. By default it's
* false, which means these plugins are only loaded opportunistically.
*
* NB: These plugins need to have already been loaded via require.js.
*/
dependencies: ["converse-emoji", "converse-chatview"],
overrides: {
ChatBoxView: {
events: {
'click .toggle-smiley': 'toggleEmojiMenu',
},
onEnterPressed () {
if (this.emoji_dropdown && u.isVisible(this.emoji_dropdown.el.querySelector('.emoji-picker'))) {
this.emoji_dropdown.toggle();
}
this.__super__.onEnterPressed.apply(this, arguments);
}
},
ChatRoomView: {
events: {
'click .toggle-smiley': 'toggleEmojiMenu'
},
}
},
initialize () {
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const { _converse } = this;
const { __ } = _converse;
_converse.api.settings.update({
'use_system_emojis': true,
'visible_toolbar_buttons': {
'emoji': true
},
});
const emoji_aware_chat_view = {
createEmojiPicker () {
if (_converse.emojipicker === undefined) {
const storage = _converse.config.get('storage'),
id = `converse.emoji-${_converse.bare_jid}`;
_converse.emojipicker = new _converse.EmojiPicker({'id': id});
_converse.emojipicker.browserStorage = new BrowserStorage[storage](id);
_converse.emojipicker.fetch();
}
this.emoji_picker_view = new _converse.EmojiPickerView({'model': _converse.emojipicker});
this.emoji_picker_view.chatview = this;
},
async toggleEmojiMenu (ev) {
if (this.emoji_dropdown === undefined) {
ev.stopPropagation();
const dropdown_el = this.el.querySelector('.toggle-smiley.dropup');
this.emoji_dropdown = new bootstrap.Dropdown(dropdown_el, true);
this.emoji_dropdown.el = dropdown_el;
this.emoji_dropdown.toggle();
await _converse.api.waitUntil('emojisInitialized');
this.emoji_picker_view.render();
this.emoji_picker_view.setScrollPosition();
}
},
insertEmojiPicker () {
const picker_el = this.el.querySelector('.emoji-picker');
if (picker_el !== null) {
picker_el.innerHTML = '';
picker_el.appendChild(this.emoji_picker_view.el);
}
}
};
Object.assign(_converse.ChatBoxView.prototype, emoji_aware_chat_view);
function emojiShouldBeHidden (shortname, current_skintone, toned_emojis) {
// Helper method for the template which decides whether an
// emoji should be hidden, based on which skin tone is
// currently being applied.
if (shortname.includes('_tone')) {
if (!current_skintone || !shortname.includes(current_skintone)) {
return true;
}
} else {
if (current_skintone && toned_emojis.includes(shortname)) {
return true;
}
}
return false;
}
_converse.EmojiPickerView = Backbone.VDOMView.extend({
className: 'emoji-picker__container',
events: {
'click .emoji-category-picker li.emoji-category': 'chooseCategory',
'click .emoji-skintone-picker li.emoji-skintone': 'chooseSkinTone',
'click .toggle-smiley ul.emoji-picker li': 'insertEmoji'
},
initialize () {
this.model.on('change:current_skintone', this.render, this);
this.model.on('change:current_category', () => {
this.render();
this.setScrollPosition();
});
_converse.api.trigger('emojiPickerViewInitialized');
},
toHTML () {
const html = tpl_emojis(
Object.assign(
this.model.toJSON(), {
'_converse': _converse,
'emoji_categories': _converse.emoji_categories,
'emojis_by_category': u.getEmojisByCategory(),
'shouldBeHidden': emojiShouldBeHidden,
'skintones': ['tone1', 'tone2', 'tone3', 'tone4', 'tone5'],
'toned_emojis': _converse.emojis.toned,
'transform': u.getEmojiRenderer(),
'transformCategory': shortname => u.getEmojiRenderer()(this.getTonedShortname(shortname))
}
)
);
return html;
},
getTonedShortname (shortname) {
if (_converse.emojis.toned.includes(shortname) && this.model.get('current_skintone')) {
return `${shortname.slice(0, shortname.length-1)}_${this.model.get('current_skintone')}:`
}
return shortname;
},
chooseSkinTone (ev) {
ev.preventDefault();
ev.stopPropagation();
const target = ev.target.nodeName === 'IMG' ?
ev.target.parentElement : ev.target;
const skintone = target.getAttribute("data-skintone").trim();
if (this.model.get('current_skintone') === skintone) {
this.model.save({'current_skintone': ''});
} else {
this.model.save({'current_skintone': skintone});
}
},
chooseCategory (ev) {
ev.preventDefault();
ev.stopPropagation();
const target = ev.target.nodeName === 'IMG' ? ev.target.parentElement : ev.target;
const category = target.getAttribute("data-category").trim();
this.model.save({'current_category': category});
},
setScrollPosition () {
const category = this.model.get('current_category');
const el = this.el.querySelector('.emoji-picker__lists');
const heading = this.el.querySelector(`#emoji-picker-${category}`);
el.scrollTop = heading.offsetTop - heading.offsetHeight*2;
},
insertEmoji (ev) {
ev.preventDefault();
ev.stopPropagation();
const target = ev.target.nodeName === 'IMG' ? ev.target.parentElement : ev.target;
this.chatview.insertIntoTextArea(target.getAttribute('data-emoji'));
}
});
/************************ BEGIN Event Handlers ************************/
_converse.api.listen.on('renderToolbar', view => {
if (_converse.visible_toolbar_buttons.emoji) {
const html = tpl_emoji_button({'tooltip_insert_smiley': __('Insert emojis')});
view.el.querySelector('.chat-toolbar').insertAdjacentHTML('afterBegin', html);
view.createEmojiPicker();
view.insertEmojiPicker();
}
});
}
});