emoji-picker: Move picker content into another component
to avoid re-rendering them when non-relevant properties change
This commit is contained in:
parent
bec476b601
commit
22b2875b52
@ -54,11 +54,11 @@ describe("Emojis", function () {
|
|||||||
}
|
}
|
||||||
view.onKeyDown(tab_event);
|
view.onKeyDown(tab_event);
|
||||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||||
let picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
|
const picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
|
||||||
const input = picker.querySelector('.emoji-search');
|
const input = picker.querySelector('.emoji-search');
|
||||||
expect(input.value).toBe(':gri');
|
expect(input.value).toBe(':gri');
|
||||||
|
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', picker).length === 3, 1000);
|
||||||
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
||||||
expect(visible_emojis.length).toBe(3);
|
|
||||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':grimacing:');
|
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':grimacing:');
|
||||||
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':grin:');
|
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':grin:');
|
||||||
expect(visible_emojis[2].getAttribute('data-emoji')).toBe(':grinning:');
|
expect(visible_emojis[2].getAttribute('data-emoji')).toBe(':grinning:');
|
||||||
@ -66,8 +66,8 @@ describe("Emojis", function () {
|
|||||||
// Test that TAB autocompletes the to first match
|
// Test that TAB autocompletes the to first match
|
||||||
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
||||||
|
|
||||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', picker).length === 1);
|
await u.waitUntil(() => sizzle(".emojis-lists__container--search .insert-emoji:not('.hidden')", picker).length === 1, 1000);
|
||||||
visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
visible_emojis = sizzle(".emojis-lists__container--search .insert-emoji:not('.hidden')", picker);
|
||||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':grimacing:');
|
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':grimacing:');
|
||||||
expect(input.value).toBe(':grimacing:');
|
expect(input.value).toBe(':grimacing:');
|
||||||
|
|
||||||
@ -95,8 +95,7 @@ describe("Emojis", function () {
|
|||||||
textarea.value = ':use';
|
textarea.value = ':use';
|
||||||
view.onKeyDown(tab_event);
|
view.onKeyDown(tab_event);
|
||||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||||
picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
|
await u.waitUntil(() => input.value === ':use');
|
||||||
expect(input.value).toBe(':use');
|
|
||||||
visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
|
visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
|
||||||
expect(visible_emojis.length).toBe(0);
|
expect(visible_emojis.length).toBe(0);
|
||||||
done();
|
done();
|
||||||
@ -129,8 +128,8 @@ describe("Emojis", function () {
|
|||||||
input.dispatchEvent(new KeyboardEvent('keydown', event));
|
input.dispatchEvent(new KeyboardEvent('keydown', event));
|
||||||
|
|
||||||
await u.waitUntil(() => view.emoji_picker_view.model.get('query') === 'smiley', 1000);
|
await u.waitUntil(() => view.emoji_picker_view.model.get('query') === 'smiley', 1000);
|
||||||
|
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', picker).length === 2, 1000);
|
||||||
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
||||||
expect(visible_emojis.length).toBe(2);
|
|
||||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
||||||
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':smiley_cat:');
|
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':smiley_cat:');
|
||||||
|
|
||||||
@ -144,8 +143,8 @@ describe("Emojis", function () {
|
|||||||
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
||||||
|
|
||||||
await u.waitUntil(() => input.value === ':smiley:');
|
await u.waitUntil(() => input.value === ':smiley:');
|
||||||
visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
|
await u.waitUntil(() => sizzle(".emojis-lists__container--search .insert-emoji:not('.hidden')", picker).length === 1);
|
||||||
expect(visible_emojis.length).toBe(1);
|
visible_emojis = sizzle(".emojis-lists__container--search .insert-emoji:not('.hidden')", picker);
|
||||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
||||||
|
|
||||||
// Check that ENTER now inserts the match
|
// Check that ENTER now inserts the match
|
||||||
|
@ -1,13 +1,114 @@
|
|||||||
import DOMNavigator from "../dom-navigator";
|
import DOMNavigator from "../dom-navigator";
|
||||||
import sizzle from 'sizzle';
|
import sizzle from 'sizzle';
|
||||||
import tpl_emoji_picker from "../templates/emoji_picker.js";
|
|
||||||
import { CustomElement } from './element.js';
|
import { CustomElement } from './element.js';
|
||||||
import { _converse, converse } from "@converse/headless/converse-core";
|
import { _converse, converse } from "@converse/headless/converse-core";
|
||||||
import { debounce, find } from "lodash-es";
|
import { debounce, find } from "lodash-es";
|
||||||
|
import { html } from "lit-element";
|
||||||
|
import { tpl_all_emojis, tpl_emoji_picker, tpl_search_results } from "../templates/emoji_picker.js";
|
||||||
|
|
||||||
const u = converse.env.utils;
|
const u = converse.env.utils;
|
||||||
|
|
||||||
|
|
||||||
|
export class EmojiPickerContent extends CustomElement {
|
||||||
|
static get properties () {
|
||||||
|
return {
|
||||||
|
'chatview': { type: Object },
|
||||||
|
'search_results': { type: Array },
|
||||||
|
'current_skintone': { type: String },
|
||||||
|
'model': { type: Object },
|
||||||
|
'query': { type: String },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const props = {
|
||||||
|
'current_skintone': this.current_skintone,
|
||||||
|
'insertEmoji': ev => this.insertEmoji(ev),
|
||||||
|
'query': this.query,
|
||||||
|
'search_results': this.search_results,
|
||||||
|
'shouldBeHidden': shortname => this.shouldBeHidden(shortname),
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<div class="emoji-picker__lists">
|
||||||
|
${tpl_search_results(props)}
|
||||||
|
${tpl_all_emojis(props)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated () {
|
||||||
|
this.initIntersectionObserver();
|
||||||
|
}
|
||||||
|
|
||||||
|
initIntersectionObserver () {
|
||||||
|
if (!window.IntersectionObserver) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.observer) {
|
||||||
|
this.observer.disconnect();
|
||||||
|
} else {
|
||||||
|
const options = {
|
||||||
|
root: this.querySelector('.emoji-picker__lists'),
|
||||||
|
threshold: [0.1]
|
||||||
|
}
|
||||||
|
const handler = ev => this.setCategoryOnVisibilityChange(ev);
|
||||||
|
this.observer = new IntersectionObserver(handler, options);
|
||||||
|
}
|
||||||
|
sizzle('.emoji-picker', this).forEach(a => this.observer.observe(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
setCategoryOnVisibilityChange (ev) {
|
||||||
|
const selected = this.parentElement.navigator.selected;
|
||||||
|
const intersection_with_selected = ev.filter(i => i.target.contains(selected)).pop();
|
||||||
|
let current;
|
||||||
|
// Choose the intersection that contains the currently selected
|
||||||
|
// element, or otherwise the one with the largest ratio.
|
||||||
|
if (intersection_with_selected) {
|
||||||
|
current = intersection_with_selected;
|
||||||
|
} else {
|
||||||
|
current = ev.reduce((p, c) => c.intersectionRatio >= (p?.intersectionRatio || 0) ? c : p, null);
|
||||||
|
}
|
||||||
|
if (current && current.isIntersecting) {
|
||||||
|
const category = current.target.getAttribute('data-category');
|
||||||
|
if (category !== this.model.get('current_category')) {
|
||||||
|
this.parentElement.preserve_scroll = true;
|
||||||
|
this.model.save({'current_category': category});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insertEmoji (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
const target = ev.target.nodeName === 'IMG' ? ev.target.parentElement : ev.target;
|
||||||
|
const replace = this.model.get('autocompleting');
|
||||||
|
const position = this.model.get('position');
|
||||||
|
this.model.set({'autocompleting': null, 'position': null, 'query': ''});
|
||||||
|
this.chatview.insertIntoTextArea(target.getAttribute('data-emoji'), replace, false, position);
|
||||||
|
this.chatview.emoji_dropdown.toggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldBeHidden (shortname) {
|
||||||
|
// 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 (!this.current_skintone || !shortname.includes(this.current_skintone)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.current_skintone && _converse.emojis.toned.includes(shortname)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.query && !_converse.FILTER_CONTAINS(shortname, this.query)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class EmojiPicker extends CustomElement {
|
export class EmojiPicker extends CustomElement {
|
||||||
|
|
||||||
static get properties () {
|
static get properties () {
|
||||||
@ -22,9 +123,8 @@ export class EmojiPicker extends CustomElement {
|
|||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
super();
|
super();
|
||||||
this.debouncedFilter = debounce(input => this.model.set({'query': input.value}), 500);
|
this.search_results = [];
|
||||||
this.preserve_scroll = false;
|
this.debouncedFilter = debounce(input => this.model.set({'query': input.value}), 250);
|
||||||
this._search_results = [];
|
|
||||||
this.onGlobalKeyDown = ev => this._onGlobalKeyDown(ev);
|
this.onGlobalKeyDown = ev => this._onGlobalKeyDown(ev);
|
||||||
const body = document.querySelector('body');
|
const body = document.querySelector('body');
|
||||||
body.addEventListener('keydown', this.onGlobalKeyDown);
|
body.addEventListener('keydown', this.onGlobalKeyDown);
|
||||||
@ -32,47 +132,59 @@ export class EmojiPicker extends CustomElement {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
return tpl_emoji_picker({
|
return tpl_emoji_picker({
|
||||||
|
'chatview': this.chatview,
|
||||||
'current_category': this.current_category,
|
'current_category': this.current_category,
|
||||||
'current_skintone': this.current_skintone,
|
'current_skintone': this.current_skintone,
|
||||||
|
'model': this.model,
|
||||||
'onCategoryPicked': ev => this.chooseCategory(ev),
|
'onCategoryPicked': ev => this.chooseCategory(ev),
|
||||||
'onEmojiPicked': ev => this.insertEmoji(ev),
|
|
||||||
'onSearchInputBlurred': ev => this.chatview.emitFocused(ev),
|
'onSearchInputBlurred': ev => this.chatview.emitFocused(ev),
|
||||||
'onSearchInputFocus': ev => this.onSearchInputFocus(ev),
|
'onSearchInputFocus': ev => this.onSearchInputFocus(ev),
|
||||||
'onSearchInputKeyDown': ev => this.onKeyDown(ev),
|
'onSearchInputKeyDown': ev => this.onKeyDown(ev),
|
||||||
'onSkintonePicked': ev => this.chooseSkinTone(ev),
|
'onSkintonePicked': ev => this.chooseSkinTone(ev),
|
||||||
'query': this.query,
|
'query': this.query,
|
||||||
'search_results': this.search_results,
|
'search_results': this.search_results,
|
||||||
'shouldBeHidden': shortname => this.shouldBeHidden(shortname),
|
'sn2Emoji': shortname => u.shortnamesToEmojis(this.getTonedShortname(shortname))
|
||||||
'transformCategory': shortname => u.shortnamesToEmojis(this.getTonedShortname(shortname))
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated () {
|
firstUpdated () {
|
||||||
this.initArrowNavigation();
|
this.initArrowNavigation();
|
||||||
this.initIntersectionObserver();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updated (changed) {
|
updated (changed) {
|
||||||
if (changed.has('current_category') && !this.preserve_scroll) {
|
changed.has('query') && this.updateSearchResults();
|
||||||
this.setScrollPosition();
|
changed.has('current_category') && this.setScrollPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
setScrollPosition () {
|
||||||
|
if (this.preserve_scroll) {
|
||||||
|
this.preserve_scroll = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const el = this.querySelector('.emoji-lists__container--browse');
|
||||||
|
const heading = this.querySelector(`#emoji-picker-${this.current_category}`);
|
||||||
|
if (heading) {
|
||||||
|
// +4 due to 2px padding on list elements
|
||||||
|
el.scrollTop = heading.offsetTop - heading.offsetHeight*3 + 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get search_results () {
|
updateSearchResults () {
|
||||||
const contains = _converse.FILTER_CONTAINS;
|
const contains = _converse.FILTER_CONTAINS;
|
||||||
if (this.query) {
|
if (this.query) {
|
||||||
if (this.query === this.old_query) {
|
if (this.query === this.old_query) {
|
||||||
return this._search_results;
|
return this.search_results;
|
||||||
} else if (this.old_query && this.query.includes(this.old_query)) {
|
} else if (this.old_query && this.query.includes(this.old_query)) {
|
||||||
this._search_results = this._search_results.filter(e => contains(e.sn, this.query));
|
this.search_results = this.search_results.filter(e => contains(e.sn, this.query));
|
||||||
} else {
|
} else {
|
||||||
this._search_results = _converse.emojis_list.filter(e => contains(e.sn, this.query));
|
this.search_results = _converse.emojis_list.filter(e => contains(e.sn, this.query));
|
||||||
}
|
}
|
||||||
this.old_query = this.query;
|
this.old_query = this.query;
|
||||||
} else {
|
} else if (this.search_results.length) {
|
||||||
this._search_results = [];
|
// Avoid re-rendering by only setting to new empty array if it wasn't empty before
|
||||||
|
this.search_results = [];
|
||||||
}
|
}
|
||||||
return this._search_results;
|
return this.search_results;
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
@ -96,29 +208,14 @@ export class EmojiPicker extends CustomElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setCategoryForElement (el, preserve_scroll=false) {
|
setCategoryForElement (el) {
|
||||||
const old_category = this.current_category;
|
const old_category = this.current_category;
|
||||||
const category = el.getAttribute('data-category') || old_category;
|
const category = el.getAttribute('data-category') || old_category;
|
||||||
if (old_category !== category) {
|
if (old_category !== category) {
|
||||||
this.preserve_scroll = preserve_scroll;
|
|
||||||
this.model.save({'current_category': category});
|
this.model.save({'current_category': category});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setCategoryOnVisibilityChange (ev) {
|
|
||||||
const selected = this.navigator.selected;
|
|
||||||
const intersection_with_selected = ev.filter(i => i.target.contains(selected)).pop();
|
|
||||||
let current;
|
|
||||||
// Choose the intersection that contains the currently selected
|
|
||||||
// element, or otherwise the one with the largest ratio.
|
|
||||||
if (intersection_with_selected) {
|
|
||||||
current = intersection_with_selected;
|
|
||||||
} else {
|
|
||||||
current = ev.reduce((p, c) => c.intersectionRatio >= (p?.intersectionRatio || 0) ? c : p, null);
|
|
||||||
}
|
|
||||||
current && current.isIntersecting && this.setCategoryForElement(current.target, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
insertIntoTextArea (value) {
|
insertIntoTextArea (value) {
|
||||||
const replace = this.model.get('autocompleting');
|
const replace = this.model.get('autocompleting');
|
||||||
const position = this.model.get('position');
|
const position = this.model.get('position');
|
||||||
@ -152,18 +249,6 @@ export class EmojiPicker extends CustomElement {
|
|||||||
!this.navigator.enabled && this.navigator.enable();
|
!this.navigator.enabled && this.navigator.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
insertEmoji (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
const target = ev.target.nodeName === 'IMG' ? ev.target.parentElement : ev.target;
|
|
||||||
const replace = this.model.get('autocompleting');
|
|
||||||
const position = this.model.get('position');
|
|
||||||
this.model.set({'autocompleting': null, 'position': null});
|
|
||||||
this.chatview.insertIntoTextArea(target.getAttribute('data-emoji'), replace, false, position);
|
|
||||||
this.chatview.emoji_dropdown.toggle();
|
|
||||||
this.model.set({'query': ''});
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyDown (ev) {
|
onKeyDown (ev) {
|
||||||
if (ev.keyCode === converse.keycodes.TAB) {
|
if (ev.keyCode === converse.keycodes.TAB) {
|
||||||
if (ev.target.value) {
|
if (ev.target.value) {
|
||||||
@ -208,25 +293,6 @@ export class EmojiPicker extends CustomElement {
|
|||||||
this.disableArrowNavigation();
|
this.disableArrowNavigation();
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldBeHidden (shortname) {
|
|
||||||
// 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 (!this.current_skintone || !shortname.includes(this.current_skintone)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.current_skintone && _converse.emojis.toned.includes(shortname)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.query && !_converse.FILTER_CONTAINS(shortname, this.query)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTonedShortname (shortname) {
|
getTonedShortname (shortname) {
|
||||||
if (_converse.emojis.toned.includes(shortname) && this.current_skintone) {
|
if (_converse.emojis.toned.includes(shortname) && this.current_skintone) {
|
||||||
return `${shortname.slice(0, shortname.length-1)}_${this.current_skintone}:`
|
return `${shortname.slice(0, shortname.length-1)}_${this.current_skintone}:`
|
||||||
@ -234,23 +300,6 @@ export class EmojiPicker extends CustomElement {
|
|||||||
return shortname;
|
return shortname;
|
||||||
}
|
}
|
||||||
|
|
||||||
initIntersectionObserver () {
|
|
||||||
if (!window.IntersectionObserver) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.observer) {
|
|
||||||
this.observer.disconnect();
|
|
||||||
} else {
|
|
||||||
const options = {
|
|
||||||
root: this.querySelector('.emoji-picker__lists'),
|
|
||||||
threshold: [0.1]
|
|
||||||
}
|
|
||||||
const handler = ev => this.setCategoryOnVisibilityChange(ev);
|
|
||||||
this.observer = new IntersectionObserver(handler, options);
|
|
||||||
}
|
|
||||||
sizzle('.emoji-picker', this).forEach(a => this.observer.observe(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
initArrowNavigation () {
|
initArrowNavigation () {
|
||||||
if (!this.navigator) {
|
if (!this.navigator) {
|
||||||
const default_selector = 'li:not(.hidden):not(.emoji-skintone), .emoji-search';
|
const default_selector = 'li:not(.hidden):not(.emoji-skintone), .emoji-search';
|
||||||
@ -291,15 +340,8 @@ export class EmojiPicker extends CustomElement {
|
|||||||
this.navigator.enable();
|
this.navigator.enable();
|
||||||
this.navigator.handleKeydown(ev);
|
this.navigator.handleKeydown(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
setScrollPosition () {
|
|
||||||
const el = this.querySelector('.emoji-lists__container--browse');
|
|
||||||
const heading = this.querySelector(`#emoji-picker-${this.current_category}`);
|
|
||||||
if (heading) {
|
|
||||||
// +4 due to 2px padding on list elements
|
|
||||||
el.scrollTop = heading.offsetTop - heading.offsetHeight*3 + 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window.customElements.define('converse-emoji-picker', EmojiPicker);
|
window.customElements.define('converse-emoji-picker', EmojiPicker);
|
||||||
|
window.customElements.define('converse-emoji-picker-content', EmojiPickerContent);
|
||||||
|
@ -18,26 +18,26 @@ const emoji_category = (o) => {
|
|||||||
<a class="pick-category"
|
<a class="pick-category"
|
||||||
@click=${o.onCategoryPicked}
|
@click=${o.onCategoryPicked}
|
||||||
href="#emoji-picker-${o.category}"
|
href="#emoji-picker-${o.category}"
|
||||||
data-category="${o.category}">${o.transformCategory(o.emoji_categories[o.category])} </a>
|
data-category="${o.category}">${o.emoji} </a>
|
||||||
</li>
|
</li>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emoji_picker_header = (o) => html`
|
const emoji_picker_header = (o) => {
|
||||||
<ul>
|
const cats = api.settings.get('emoji_categories');
|
||||||
${ Object.keys(o.emoji_categories).map(category => (o.emoji_categories[category] ? emoji_category(Object.assign({category}, o)) : '')) }
|
const transform = c => cats[c] ? emoji_category(Object.assign({'category': c, 'emoji': o.sn2Emoji(cats[c])}, o)) : '';
|
||||||
</ul>
|
return html`<ul>${ Object.keys(cats).map(transform) }</ul>`;
|
||||||
`;
|
}
|
||||||
|
|
||||||
const emoji_item = (o) => {
|
const emoji_item = (o) => {
|
||||||
return html`
|
return html`
|
||||||
<li class="emoji insert-emoji ${o.shouldBeHidden(o.emoji.sn) ? 'hidden' : ''}" data-emoji="${o.emoji.sn}" title="${o.emoji.sn}">
|
<li class="emoji insert-emoji ${o.shouldBeHidden(o.emoji.sn) ? 'hidden' : ''}" data-emoji="${o.emoji.sn}" title="${o.emoji.sn}">
|
||||||
<a href="#" @click=${o.onEmojiPicked} data-emoji="${o.emoji.sn}">${u.shortnamesToEmojis(o.emoji.sn)}</a>
|
<a href="#" @click=${o.insertEmoji} data-emoji="${o.emoji.sn}">${u.shortnamesToEmojis(o.emoji.sn)}</a>
|
||||||
</li>
|
</li>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const search_results = (o) => html`
|
export const tpl_search_results = (o) => html`
|
||||||
<span ?hidden=${!o.query} class="emoji-lists__container emojis-lists__container--search">
|
<span ?hidden=${!o.query} class="emoji-lists__container emojis-lists__container--search">
|
||||||
<a id="emoji-picker-search-results" class="emoji-category__heading">${i18n_search_results}</a>
|
<a id="emoji-picker-search-results" class="emoji-category__heading">${i18n_search_results}</a>
|
||||||
<ul class="emoji-picker">
|
<ul class="emoji-picker">
|
||||||
@ -46,33 +46,33 @@ const search_results = (o) => html`
|
|||||||
</span>
|
</span>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const emojis_for_category = (o) => html`
|
const emojis_for_category = (o) => {
|
||||||
<a id="emoji-picker-${o.category}" class="emoji-category__heading" data-category="${o.category}">${ __(api.settings.get('emoji_category_labels')[o.category]) }</a>
|
const emojis_by_category = _converse.emojis.json;
|
||||||
<ul class="emoji-picker" data-category="${o.category}">
|
return html`
|
||||||
${ Object.values(o.emojis_by_category[o.category]).map(emoji => emoji_item(Object.assign({emoji}, o))) }
|
<a id="emoji-picker-${o.category}" class="emoji-category__heading" data-category="${o.category}">${ __(api.settings.get('emoji_category_labels')[o.category]) }</a>
|
||||||
</ul>
|
<ul class="emoji-picker" data-category="${o.category}">
|
||||||
`;
|
${ Object.values(emojis_by_category[o.category]).map(emoji => emoji_item(Object.assign({emoji}, o))) }
|
||||||
|
</ul>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const tpl_all_emojis = (o) => {
|
||||||
|
const cats = api.settings.get('emoji_categories');
|
||||||
|
return html`
|
||||||
|
<span ?hidden=${o.query} class="emoji-lists__container emoji-lists__container--browse">
|
||||||
|
${Object.keys(cats).map(c => (cats[c] ? emojis_for_category(Object.assign({'category': c}, o)) : ''))}
|
||||||
|
</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const skintone_emoji = (o) => {
|
const skintone_emoji = (o) => {
|
||||||
return html`
|
return html`
|
||||||
<li data-skintone="${o.skintone}" class="emoji-skintone ${(o.current_skintone === o.skintone) ? 'picked' : ''}">
|
<li data-skintone="${o.skintone}" class="emoji-skintone ${(o.current_skintone === o.skintone) ? 'picked' : ''}">
|
||||||
<a class="pick-skintone" href="#" data-skintone="${o.skintone}" @click=${o.onSkintonePicked}>${u.shortnamesToEmojis(':'+o.skintone+':')}</a>
|
<a class="pick-skintone" href="#" data-skintone="${o.skintone}" @click=${o.onSkintonePicked}>${u.shortnamesToEmojis(':'+o.skintone+':')}</a>
|
||||||
</li>
|
</li>`;
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const all_emojis = (o) => html`
|
|
||||||
<span ?hidden=${o.query} class="emoji-lists__container emoji-lists__container--browse">
|
|
||||||
${Object.keys(o.emoji_categories).map(category => (o.emoji_categories[category] ? emojis_for_category(Object.assign({category}, o)) : ''))}
|
|
||||||
</span>
|
|
||||||
`;
|
|
||||||
|
|
||||||
|
|
||||||
export default (o) => {
|
|
||||||
o.emoji_categories = api.settings.get('emoji_categories');
|
|
||||||
o.emojis_by_category = _converse.emojis.json;
|
|
||||||
o.toned_emojis = _converse.emojis.toned;
|
|
||||||
|
|
||||||
|
export const tpl_emoji_picker = (o) => {
|
||||||
return html`
|
return html`
|
||||||
<div class="emoji-picker__header">
|
<div class="emoji-picker__header">
|
||||||
<input class="form-control emoji-search" name="emoji-search" placeholder="${i18n_search}"
|
<input class="form-control emoji-search" name="emoji-search" placeholder="${i18n_search}"
|
||||||
@ -82,10 +82,14 @@ export default (o) => {
|
|||||||
@focus=${o.onSearchInputFocus}>
|
@focus=${o.onSearchInputFocus}>
|
||||||
${ o.query ? '' : emoji_picker_header(o) }
|
${ o.query ? '' : emoji_picker_header(o) }
|
||||||
</div>
|
</div>
|
||||||
<div class="emoji-picker__lists">
|
<converse-emoji-picker-content
|
||||||
${search_results(o)}
|
.chatview=${o.chatview}
|
||||||
${all_emojis(o)}
|
.model=${o.model}
|
||||||
</div>
|
.search_results="${o.search_results}"
|
||||||
|
current_skintone="${o.current_skintone}"
|
||||||
|
query="${o.query}"
|
||||||
|
></converse-emoji-picker-content>
|
||||||
|
|
||||||
<div class="emoji-skintone-picker">
|
<div class="emoji-skintone-picker">
|
||||||
<label>Skin tone</label>
|
<label>Skin tone</label>
|
||||||
<ul>${ skintones.map(skintone => skintone_emoji(Object.assign({skintone}, o))) }</ul>
|
<ul>${ skintones.map(skintone => skintone_emoji(Object.assign({skintone}, o))) }</ul>
|
||||||
|
Loading…
Reference in New Issue
Block a user