Move Views associated to emojis into a new plugin
This commit is contained in:
parent
d7ce231c51
commit
1cf9a936a4
@ -283,6 +283,10 @@ body.converse-fullscreen {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
a, a:visited, a:not([href]):not([tabindex]) {
|
a, a:visited, a:not([href]):not([tabindex]) {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--link-color);
|
color: var(--link-color);
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
background-color: var(--chat-head-color);
|
background-color: var(--chat-head-color);
|
||||||
.emoji-picker__container {
|
.emoji-picker__container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
background: white;
|
background: white;
|
||||||
.emoji-picker__lists {
|
.emoji-picker__lists {
|
||||||
@ -29,13 +31,18 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.emoji-skintone-picker {
|
.emoji-skintone-picker {
|
||||||
padding: 0.25em 0;
|
display: flex;
|
||||||
|
label {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: var(--font-size);
|
||||||
|
color: var(--heading-color);
|
||||||
|
}
|
||||||
|
padding: 0.5em 0;
|
||||||
background-color: var(--chat-head-color);
|
background-color: var(--chat-head-color);
|
||||||
width: auto;
|
width: auto;
|
||||||
font-size: var(--font-size-huge);
|
font-size: var(--font-size-large);
|
||||||
&:hover {
|
|
||||||
background-color: var(--highlight-color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.emoji-picker {
|
.emoji-picker {
|
||||||
@ -114,9 +121,6 @@
|
|||||||
#conversejs.converse-overlayed {
|
#conversejs.converse-overlayed {
|
||||||
.emoji-picker__container {
|
.emoji-picker__container {
|
||||||
height: var(--embedded-emoji-picker-height);
|
height: var(--embedded-emoji-picker-height);
|
||||||
.emoji-picker__lists {
|
|
||||||
height: calc(var(--embedded-emoji-picker-height) - 4em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,9 +156,6 @@
|
|||||||
#conversejs.converse-fullscreen {
|
#conversejs.converse-fullscreen {
|
||||||
.emoji-picker__container {
|
.emoji-picker__container {
|
||||||
height: var(--fullpage-emoji-picker-height);
|
height: var(--fullpage-emoji-picker-height);
|
||||||
.emoji-picker__lists {
|
|
||||||
height: calc(var(--fullpage-emoji-picker-height) - 4em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.chatbox {
|
.chatbox {
|
||||||
.sendXMPPMessage {
|
.sendXMPPMessage {
|
||||||
|
@ -153,7 +153,7 @@ $mobile_portrait_length: 480px !default;
|
|||||||
--occupants-border-bottom: 1px solid lightgrey;
|
--occupants-border-bottom: 1px solid lightgrey;
|
||||||
--occupants-features-display: block;
|
--occupants-features-display: block;
|
||||||
|
|
||||||
--embedded-emoji-picker-height: 200px;
|
--embedded-emoji-picker-height: 300px;
|
||||||
|
|
||||||
--avatar-border-radius: 10%;
|
--avatar-border-radius: 10%;
|
||||||
--avatar-border: 1px solid lightgrey;
|
--avatar-border: 1px solid lightgrey;
|
||||||
@ -162,14 +162,14 @@ $mobile_portrait_length: 480px !default;
|
|||||||
--fullpage-chat-head-height: 62px;
|
--fullpage-chat-head-height: 62px;
|
||||||
--fullpage-chat-height: calc(var(--vh, 1vh) * 100);
|
--fullpage-chat-height: calc(var(--vh, 1vh) * 100);
|
||||||
--fullpage-chat-width: 100%;
|
--fullpage-chat-width: 100%;
|
||||||
--fullpage-emoji-picker-height: 200px;
|
--fullpage-emoji-picker-height: 300px;
|
||||||
--fullpage-max-chat-textarea-height: 15em;
|
--fullpage-max-chat-textarea-height: 15em;
|
||||||
|
|
||||||
--overlayed-chat-head-height: 55px;
|
--overlayed-chat-head-height: 55px;
|
||||||
--overlayed-chat-height: 450px;
|
--overlayed-chat-height: 450px;
|
||||||
--overlayed-chat-width: 250px;
|
--overlayed-chat-width: 250px;
|
||||||
--overlayed-chatbox-hover-height: 1em;
|
--overlayed-chatbox-hover-height: 1em;
|
||||||
--overlayed-emoji-picker-height: 100px;
|
--overlayed-emoji-picker-height: 150px;
|
||||||
--overlayed-max-chat-textarea-height: 200px;
|
--overlayed-max-chat-textarea-height: 200px;
|
||||||
--overlayed-badge-color: #818479; // $gray-color
|
--overlayed-badge-color: #818479; // $gray-color
|
||||||
|
|
||||||
|
@ -451,18 +451,15 @@
|
|||||||
const view = _converse.chatboxviews.get(contact_jid);
|
const view = _converse.chatboxviews.get(contact_jid);
|
||||||
const toolbar = view.el.querySelector('ul.chat-toolbar');
|
const toolbar = view.el.querySelector('ul.chat-toolbar');
|
||||||
expect(toolbar.querySelectorAll('li.toggle-smiley').length).toBe(1);
|
expect(toolbar.querySelectorAll('li.toggle-smiley').length).toBe(1);
|
||||||
// Register spies
|
|
||||||
spyOn(view, 'toggleEmojiMenu').and.callThrough();
|
spyOn(view, 'toggleEmojiMenu').and.callThrough();
|
||||||
spyOn(view, 'insertEmoji').and.callThrough();
|
|
||||||
|
|
||||||
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||||
toolbar.querySelector('li.toggle-smiley').click();
|
toolbar.querySelector('li.toggle-smiley').click();
|
||||||
|
|
||||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container')));
|
await u.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker__container')));
|
||||||
const picker = view.el.querySelector('.toggle-smiley .emoji-picker-container');
|
const picker = await u.waitUntil(() => view.el.querySelector('.toggle-smiley .emoji-picker__container'));
|
||||||
const items = picker.querySelectorAll('.emoji-picker li');
|
const item = await u.waitUntil(() => picker.querySelector('.emoji-picker li.insert-emoji'));
|
||||||
items[0].click()
|
item.click()
|
||||||
expect(view.insertEmoji).toHaveBeenCalled();
|
|
||||||
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':grinning: ');
|
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':grinning: ');
|
||||||
toolbar.querySelector('li.toggle-smiley').click(); // Close the panel again
|
toolbar.querySelector('li.toggle-smiley').click(); // Close the panel again
|
||||||
done();
|
done();
|
||||||
@ -485,10 +482,9 @@
|
|||||||
expect(counter.textContent).toBe('188');
|
expect(counter.textContent).toBe('188');
|
||||||
|
|
||||||
toolbar.querySelector('li.toggle-smiley').click();
|
toolbar.querySelector('li.toggle-smiley').click();
|
||||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container')));
|
const picker = await u.waitUntil(() => view.el.querySelector('.toggle-smiley .emoji-picker__container'));
|
||||||
var picker = view.el.querySelector('.toggle-smiley .emoji-picker-container');
|
const item = await u.waitUntil(() => picker.querySelector('.emoji-picker li.insert-emoji'));
|
||||||
var items = picker.querySelectorAll('.emoji-picker li');
|
item.click()
|
||||||
items[0].click()
|
|
||||||
expect(counter.textContent).toBe('177');
|
expect(counter.textContent).toBe('177');
|
||||||
|
|
||||||
const textarea = view.el.querySelector('.chat-textarea');
|
const textarea = view.el.querySelector('.chat-textarea');
|
||||||
|
@ -7,20 +7,16 @@
|
|||||||
/**
|
/**
|
||||||
* @module converse-chatview
|
* @module converse-chatview
|
||||||
*/
|
*/
|
||||||
import "@converse/headless/converse-emoji";
|
|
||||||
import "backbone.nativeview";
|
import "backbone.nativeview";
|
||||||
import "converse-chatboxviews";
|
import "converse-chatboxviews";
|
||||||
import "converse-message-view";
|
import "converse-message-view";
|
||||||
import "converse-modal";
|
import "converse-modal";
|
||||||
import * as twemoji from "twemoji";
|
|
||||||
import BrowserStorage from "backbone.browserStorage";
|
import BrowserStorage from "backbone.browserStorage";
|
||||||
import { Overview } from "backbone.overview";
|
import { Overview } from "backbone.overview";
|
||||||
import bootstrap from "bootstrap.native";
|
|
||||||
import converse from "@converse/headless/converse-core";
|
import converse from "@converse/headless/converse-core";
|
||||||
import tpl_chatbox from "templates/chatbox.html";
|
import tpl_chatbox from "templates/chatbox.html";
|
||||||
import tpl_chatbox_head from "templates/chatbox_head.html";
|
import tpl_chatbox_head from "templates/chatbox_head.html";
|
||||||
import tpl_chatbox_message_form from "templates/chatbox_message_form.html";
|
import tpl_chatbox_message_form from "templates/chatbox_message_form.html";
|
||||||
import tpl_emojis from "templates/emojis.html";
|
|
||||||
import tpl_error_message from "templates/error_message.html";
|
import tpl_error_message from "templates/error_message.html";
|
||||||
import tpl_help_message from "templates/help_message.html";
|
import tpl_help_message from "templates/help_message.html";
|
||||||
import tpl_info from "templates/info.html";
|
import tpl_info from "templates/info.html";
|
||||||
@ -49,7 +45,6 @@ converse.plugins.add('converse-chatview', {
|
|||||||
* NB: These plugins need to have already been loaded via require.js.
|
* NB: These plugins need to have already been loaded via require.js.
|
||||||
*/
|
*/
|
||||||
dependencies: [
|
dependencies: [
|
||||||
"converse-emoji",
|
|
||||||
"converse-chatboxviews",
|
"converse-chatboxviews",
|
||||||
"converse-disco",
|
"converse-disco",
|
||||||
"converse-message-view",
|
"converse-message-view",
|
||||||
@ -65,20 +60,16 @@ converse.plugins.add('converse-chatview', {
|
|||||||
|
|
||||||
_converse.api.settings.update({
|
_converse.api.settings.update({
|
||||||
'auto_focus': true,
|
'auto_focus': true,
|
||||||
'emoji_image_path': twemoji.default.base,
|
|
||||||
'message_limit': 0,
|
'message_limit': 0,
|
||||||
'show_send_button': false,
|
'show_send_button': false,
|
||||||
'show_toolbar': true,
|
'show_toolbar': true,
|
||||||
'time_format': 'HH:mm',
|
'time_format': 'HH:mm',
|
||||||
'use_system_emojis': true,
|
|
||||||
'visible_toolbar_buttons': {
|
'visible_toolbar_buttons': {
|
||||||
'call': false,
|
'call': false,
|
||||||
'clear': true,
|
'clear': true,
|
||||||
'emoji': true,
|
|
||||||
'spoiler': true
|
'spoiler': true
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
twemoji.default.base = _converse.emoji_image_path;
|
|
||||||
|
|
||||||
function onWindowStateChanged (data) {
|
function onWindowStateChanged (data) {
|
||||||
if (_converse.chatboxviews) {
|
if (_converse.chatboxviews) {
|
||||||
@ -92,87 +83,6 @@ converse.plugins.add('converse-chatview', {
|
|||||||
_converse.api.listen.on('windowStateChanged', onWindowStateChanged);
|
_converse.api.listen.on('windowStateChanged', onWindowStateChanged);
|
||||||
|
|
||||||
|
|
||||||
_converse.EmojiPicker = Backbone.Model.extend({
|
|
||||||
defaults: {
|
|
||||||
'current_category': 'people',
|
|
||||||
'current_skintone': '',
|
|
||||||
'scroll_position': 0
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
_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'
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize () {
|
|
||||||
this.model.on('change:current_skintone', this.render, this);
|
|
||||||
this.model.on('change:current_category', this.render, this);
|
|
||||||
_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': this.shouldBeHidden,
|
|
||||||
'skintones': ['tone1', 'tone2', 'tone3', 'tone4', 'tone5'],
|
|
||||||
'toned_emojis': _converse.emojis.toned,
|
|
||||||
'transform': u.getEmojiRenderer()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
|
|
||||||
shouldBeHidden (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 (_.includes(shortname, '_tone')) {
|
|
||||||
if (!current_skintone || !_.includes(shortname, current_skintone)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (current_skintone && _.includes(toned_emojis, shortname)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
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) {
|
|
||||||
const target = ev.target.nodeName === 'IMG' ? ev.target.parentElement : ev.target;
|
|
||||||
const category = target.getAttribute("data-category").trim();
|
|
||||||
this.model.save({
|
|
||||||
'current_category': category,
|
|
||||||
'scroll_position': 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
_converse.ChatBoxHeading = _converse.ViewWithAvatar.extend({
|
_converse.ChatBoxHeading = _converse.ViewWithAvatar.extend({
|
||||||
initialize () {
|
initialize () {
|
||||||
this.model.on('change:status', this.onStatusMessageChanged, this);
|
this.model.on('change:status', this.onStatusMessageChanged, this);
|
||||||
@ -336,8 +246,6 @@ converse.plugins.add('converse-chatview', {
|
|||||||
'click .toggle-call': 'toggleCall',
|
'click .toggle-call': 'toggleCall',
|
||||||
'click .toggle-clear': 'clearMessages',
|
'click .toggle-clear': 'clearMessages',
|
||||||
'click .toggle-compose-spoiler': 'toggleComposeSpoilerMessage',
|
'click .toggle-compose-spoiler': 'toggleComposeSpoilerMessage',
|
||||||
'click .toggle-smiley ul.emoji-picker li': 'insertEmoji',
|
|
||||||
'click .toggle-smiley': 'toggleEmojiMenu',
|
|
||||||
'click .upload-file': 'toggleFileUpload',
|
'click .upload-file': 'toggleFileUpload',
|
||||||
'input .chat-textarea': 'inputChanged',
|
'input .chat-textarea': 'inputChanged',
|
||||||
'keydown .chat-textarea': 'onKeyDown',
|
'keydown .chat-textarea': 'onKeyDown',
|
||||||
@ -361,9 +269,6 @@ converse.plugins.add('converse-chatview', {
|
|||||||
|
|
||||||
this.model.presence.on('change:show', this.onPresenceChanged, this);
|
this.model.presence.on('change:show', this.onPresenceChanged, this);
|
||||||
this.render();
|
this.render();
|
||||||
this.createEmojiPicker();
|
|
||||||
this.insertEmojiPicker();
|
|
||||||
await this.renderEmojiPicker();
|
|
||||||
await this.updateAfterMessagesFetched();
|
await this.updateAfterMessagesFetched();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -509,11 +414,7 @@ converse.plugins.add('converse-chatview', {
|
|||||||
const all_resources_support_spolers = results.reduce((acc, val) => (acc && val), true);
|
const all_resources_support_spolers = results.reduce((acc, val) => (acc && val), true);
|
||||||
if (all_resources_support_spolers) {
|
if (all_resources_support_spolers) {
|
||||||
const html = tpl_spoiler_button(this.model.toJSON());
|
const html = tpl_spoiler_button(this.model.toJSON());
|
||||||
if (_converse.visible_toolbar_buttons.emoji) {
|
this.el.querySelector('.chat-toolbar').insertAdjacentHTML('afterBegin', html);
|
||||||
this.el.querySelector('.toggle-smiley').insertAdjacentHTML('afterEnd', html);
|
|
||||||
} else {
|
|
||||||
this.el.querySelector('.chat-toolbar').insertAdjacentHTML('afterBegin', html);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -544,9 +445,7 @@ converse.plugins.add('converse-chatview', {
|
|||||||
'message_limit': _converse.message_limit,
|
'message_limit': _converse.message_limit,
|
||||||
'show_call_button': _converse.visible_toolbar_buttons.call,
|
'show_call_button': _converse.visible_toolbar_buttons.call,
|
||||||
'show_spoiler_button': _converse.visible_toolbar_buttons.spoiler,
|
'show_spoiler_button': _converse.visible_toolbar_buttons.spoiler,
|
||||||
'tooltip_insert_smiley': __('Insert emojis'),
|
|
||||||
'tooltip_start_call': __('Start a call'),
|
'tooltip_start_call': __('Start a call'),
|
||||||
'use_emoji': _converse.visible_toolbar_buttons.emoji,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -987,10 +886,7 @@ converse.plugins.add('converse-chatview', {
|
|||||||
} else if (ev.keyCode === _converse.keycodes.ESCAPE) {
|
} else if (ev.keyCode === _converse.keycodes.ESCAPE) {
|
||||||
return this.onEscapePressed(ev);
|
return this.onEscapePressed(ev);
|
||||||
} else if (ev.keyCode === _converse.keycodes.ENTER) {
|
} else if (ev.keyCode === _converse.keycodes.ENTER) {
|
||||||
if (this.emoji_dropdown && u.isVisible(this.emoji_dropdown.el.querySelector('.emoji-picker'))) {
|
return this.onEnterPressed(ev);
|
||||||
this.emoji_dropdown.toggle();
|
|
||||||
}
|
|
||||||
return this.onFormSubmitted(ev);
|
|
||||||
} else if (ev.keyCode === _converse.keycodes.UP_ARROW && !ev.target.selectionEnd) {
|
} else if (ev.keyCode === _converse.keycodes.UP_ARROW && !ev.target.selectionEnd) {
|
||||||
const textarea = this.el.querySelector('.chat-textarea');
|
const textarea = this.el.querySelector('.chat-textarea');
|
||||||
if (!textarea.value || u.hasClass('correcting', textarea)) {
|
if (!textarea.value || u.hasClass('correcting', textarea)) {
|
||||||
@ -1022,6 +918,10 @@ converse.plugins.add('converse-chatview', {
|
|||||||
return this.model.messages.filter({'sender': 'me'});
|
return this.model.messages.filter({'sender': 'me'});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onEnterPressed (ev) {
|
||||||
|
return this.onFormSubmitted(ev);
|
||||||
|
},
|
||||||
|
|
||||||
onEscapePressed (ev) {
|
onEscapePressed (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
const idx = this.model.messages.findLastIndex('correcting'),
|
const idx = this.model.messages.findLastIndex('correcting'),
|
||||||
@ -1143,35 +1043,6 @@ converse.plugins.add('converse-chatview', {
|
|||||||
u.placeCaretAtEnd(textarea);
|
u.placeCaretAtEnd(textarea);
|
||||||
},
|
},
|
||||||
|
|
||||||
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});
|
|
||||||
},
|
|
||||||
|
|
||||||
insertEmoji (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
const target = ev.target.nodeName === 'IMG' ? ev.target.parentElement : ev.target;
|
|
||||||
this.insertIntoTextArea(target.getAttribute('data-emoji'));
|
|
||||||
},
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleCall (ev) {
|
toggleCall (ev) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
/**
|
/**
|
||||||
@ -1269,19 +1140,6 @@ converse.plugins.add('converse-chatview', {
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
async renderEmojiPicker () {
|
|
||||||
await _converse.api.waitUntil('emojisInitialized');
|
|
||||||
this.emoji_picker_view.render();
|
|
||||||
},
|
|
||||||
|
|
||||||
insertEmojiPicker () {
|
|
||||||
const picker_el = this.el.querySelector('.emoji-picker');
|
|
||||||
if (picker_el !== null) {
|
|
||||||
picker_el.innerHTML = '';
|
|
||||||
picker_el.appendChild(this.emoji_picker_view.el);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
emitFocused () {
|
emitFocused () {
|
||||||
/**
|
/**
|
||||||
* Triggered when the focus has been moved to a particular chat.
|
* Triggered when the focus has been moved to a particular chat.
|
||||||
|
207
src/converse-emoji-views.js
Normal file
207
src/converse-emoji-views.js
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
// 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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return html;
|
||||||
|
},
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
@ -624,8 +624,6 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
'click .show-room-details-modal': 'showRoomDetailsModal',
|
'click .show-room-details-modal': 'showRoomDetailsModal',
|
||||||
'click .toggle-call': 'toggleCall',
|
'click .toggle-call': 'toggleCall',
|
||||||
'click .toggle-occupants': 'toggleOccupants',
|
'click .toggle-occupants': 'toggleOccupants',
|
||||||
'click .toggle-smiley ul.emoji-picker li': 'insertEmoji',
|
|
||||||
'click .toggle-smiley': 'toggleEmojiMenu',
|
|
||||||
'click .upload-file': 'toggleFileUpload',
|
'click .upload-file': 'toggleFileUpload',
|
||||||
'keydown .chat-textarea': 'onKeyDown',
|
'keydown .chat-textarea': 'onKeyDown',
|
||||||
'keyup .chat-textarea': 'onKeyUp',
|
'keyup .chat-textarea': 'onKeyUp',
|
||||||
@ -635,7 +633,7 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
'drop .chat-textarea': 'onDrop',
|
'drop .chat-textarea': 'onDrop',
|
||||||
},
|
},
|
||||||
|
|
||||||
async initialize () {
|
initialize () {
|
||||||
this.initDebounced();
|
this.initDebounced();
|
||||||
|
|
||||||
this.model.messages.on('add', this.onMessageAdded, this);
|
this.model.messages.on('add', this.onMessageAdded, this);
|
||||||
@ -662,9 +660,6 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
this.model.occupants.on('change:affiliation', this.onOccupantAffiliationChanged, this);
|
this.model.occupants.on('change:affiliation', this.onOccupantAffiliationChanged, this);
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
this.createEmojiPicker();
|
|
||||||
this.insertEmojiPicker();
|
|
||||||
await this.renderEmojiPicker();
|
|
||||||
this.updateAfterMessagesFetched();
|
this.updateAfterMessagesFetched();
|
||||||
this.createOccupantsView();
|
this.createOccupantsView();
|
||||||
this.onConnectionStatusChanged();
|
this.onConnectionStatusChanged();
|
||||||
|
@ -8,6 +8,7 @@ import "converse-bookmark-views"; // Views for XEP-0048 Bookmarks
|
|||||||
import "converse-chatview"; // Renders standalone chat boxes for single user chat
|
import "converse-chatview"; // Renders standalone chat boxes for single user chat
|
||||||
import "converse-controlbox"; // The control box
|
import "converse-controlbox"; // The control box
|
||||||
import "converse-dragresize"; // Allows chat boxes to be resized by dragging them
|
import "converse-dragresize"; // Allows chat boxes to be resized by dragging them
|
||||||
|
import "converse-emoji-views";
|
||||||
import "converse-fullscreen";
|
import "converse-fullscreen";
|
||||||
import "converse-headline"; // Support for headline messages
|
import "converse-headline"; // Support for headline messages
|
||||||
import "converse-mam-views";
|
import "converse-mam-views";
|
||||||
@ -15,8 +16,8 @@ import "converse-minimize"; // Allows chat boxes to be minimized
|
|||||||
import "converse-muc-views"; // Views related to MUC
|
import "converse-muc-views"; // Views related to MUC
|
||||||
import "converse-notification"; // HTML5 Notifications
|
import "converse-notification"; // HTML5 Notifications
|
||||||
import "converse-omemo";
|
import "converse-omemo";
|
||||||
import "converse-push"; // XEP-0357 Push Notifications
|
|
||||||
import "converse-profile";
|
import "converse-profile";
|
||||||
|
import "converse-push"; // XEP-0357 Push Notifications
|
||||||
import "converse-register"; // XEP-0077 In-band registration
|
import "converse-register"; // XEP-0077 In-band registration
|
||||||
import "converse-roomslist"; // Show currently open chat rooms
|
import "converse-roomslist"; // Show currently open chat rooms
|
||||||
import "converse-rosterview";
|
import "converse-rosterview";
|
||||||
@ -33,6 +34,7 @@ const WHITELISTED_PLUGINS = [
|
|||||||
'converse-chatview',
|
'converse-chatview',
|
||||||
'converse-controlbox',
|
'converse-controlbox',
|
||||||
'converse-dragresize',
|
'converse-dragresize',
|
||||||
|
'converse-emoji-views',
|
||||||
'converse-fullscreen',
|
'converse-fullscreen',
|
||||||
'converse-headline',
|
'converse-headline',
|
||||||
'converse-mam-views',
|
'converse-mam-views',
|
||||||
|
@ -10,7 +10,7 @@ import * as twemoji from "twemoji";
|
|||||||
import _ from "./lodash.noconflict";
|
import _ from "./lodash.noconflict";
|
||||||
import converse from "./converse-core";
|
import converse from "./converse-core";
|
||||||
|
|
||||||
const { Strophe } = converse.env;
|
const { Backbone, Strophe } = converse.env;
|
||||||
const u = converse.env.utils;
|
const u = converse.env.utils;
|
||||||
|
|
||||||
const ASCII_LIST = {
|
const ASCII_LIST = {
|
||||||
@ -198,6 +198,14 @@ converse.plugins.add('converse-emoji', {
|
|||||||
"flags": __("Flags")
|
"flags": __("Flags")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_converse.EmojiPicker = Backbone.Model.extend({
|
||||||
|
defaults: {
|
||||||
|
'current_category': 'people',
|
||||||
|
'current_skintone': '',
|
||||||
|
'scroll_position': 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
_converse.emojis = {};
|
_converse.emojis = {};
|
||||||
|
|
||||||
u.getEmojiRenderer = function () {
|
u.getEmojiRenderer = function () {
|
||||||
|
4
src/templates/emoji_button.html
Normal file
4
src/templates/emoji_button.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<li class="toggle-toolbar-menu toggle-smiley dropup">
|
||||||
|
<a class="toggle-smiley far fa-smile" title="{{{o.tooltip_insert_smiley}}}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></a>
|
||||||
|
<div class="emoji-picker dropdown-menu toolbar-menu"></div>
|
||||||
|
</li>
|
@ -10,9 +10,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="emoji-picker__lists">
|
<div class="emoji-picker__lists">
|
||||||
{[ Object.keys(o.emoji_categories).forEach(function (category) { ]}
|
{[ Object.keys(o.emoji_categories).forEach(function (category) { ]}
|
||||||
<a id="emoji-picker-{{{category}}}" class="emoji-category__heading">{{{o._converse.emoji_category_labels[category]}}}</a>
|
<a id="emoji-picker-{{{category}}}" class="emoji-category__heading">{{{o._converse.emoji_category_labels[category]}}}</a>
|
||||||
<ul class="emoji-picker emoji-picker-{{{category}}}">
|
<ul class="emoji-picker emoji-picker-{{{category}}}">
|
||||||
{[ o._.forEach(o.emojis_by_category[category], function (emoji) { ]}
|
{[ o.emojis_by_category[category].forEach(function (emoji) { ]}
|
||||||
<li class="emoji insert-emoji {[ if (o.shouldBeHidden(emoji.sn, o.current_skintone, o.toned_emojis)) { ]} hidden {[ }; ]}"
|
<li class="emoji insert-emoji {[ if (o.shouldBeHidden(emoji.sn, o.current_skintone, o.toned_emojis)) { ]} hidden {[ }; ]}"
|
||||||
data-emoji="{{{emoji.sn}}}" title="{{{emoji.sn}}}">
|
data-emoji="{{{emoji.sn}}}" title="{{{emoji.sn}}}">
|
||||||
<a href="#" data-emoji="{{{emoji.sn}}}"> {{ o.transform(emoji.sn) }} </a>
|
<a href="#" data-emoji="{{{emoji.sn}}}"> {{ o.transform(emoji.sn) }} </a>
|
||||||
@ -21,11 +21,14 @@
|
|||||||
</ul>
|
</ul>
|
||||||
{[ }); ]}
|
{[ }); ]}
|
||||||
</div>
|
</div>
|
||||||
<ul class="emoji-skintone-picker">
|
<div class="emoji-skintone-picker">
|
||||||
{[ o._.forEach(o.skintones, function (skintone) { ]}
|
<label>Skin tone:</label>
|
||||||
<li data-skintone="{{{skintone}}}" class="emoji-skintone {[ if (o.current_skintone === skintone) { ]} picked {[ } ]}">
|
<ul>
|
||||||
<a class="pick-skintone" href="#" data-skintone="{{{skintone}}}"> {{ o.transform(':'+skintone+':') }} </a>
|
{[ o.skintones.forEach(function (skintone) { ]}
|
||||||
</li>
|
<li data-skintone="{{{skintone}}}" class="emoji-skintone {[ if (o.current_skintone === skintone) { ]} picked {[ } ]}">
|
||||||
{[ }); ]}
|
<a class="pick-skintone" href="#" data-skintone="{{{skintone}}}"> {{ o.transform(':'+skintone+':') }} </a>
|
||||||
</ul>
|
</li>
|
||||||
|
{[ }); ]}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,3 @@
|
|||||||
{[ if (o.use_emoji) { ]}
|
|
||||||
<li class="toggle-toolbar-menu toggle-smiley dropup">
|
|
||||||
<a class="toggle-smiley far fa-smile" title="{{{o.tooltip_insert_smiley}}}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></a>
|
|
||||||
<div class="emoji-picker dropdown-menu toolbar-menu"></div>
|
|
||||||
</li>
|
|
||||||
{[ } ]}
|
|
||||||
{[ if (o.show_call_button) { ]}
|
{[ if (o.show_call_button) { ]}
|
||||||
<li class="toggle-call fa fa-phone" title="{{{o.label_start_call}}}"></li>
|
<li class="toggle-call fa fa-phone" title="{{{o.label_start_call}}}"></li>
|
||||||
{[ } ]}
|
{[ } ]}
|
||||||
|
Loading…
Reference in New Issue
Block a user