Commit b3e34a06 authored by JC Brand's avatar JC Brand

Turn the emoji picker into a web component

parent be20b8e1
...@@ -64,16 +64,18 @@ describe("Emojis", function () { ...@@ -64,16 +64,18 @@ describe("Emojis", function () {
expect(visible_emojis[2].getAttribute('data-emoji')).toBe(':grinning:'); expect(visible_emojis[2].getAttribute('data-emoji')).toBe(':grinning:');
// Test that TAB autocompletes the to first match // Test that TAB autocompletes the to first match
view.emoji_picker_view.onKeyDown(tab_event); input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', picker).length === 1);
visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker); visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
expect(visible_emojis.length).toBe(1);
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:');
// Check that ENTER now inserts the match // Check that ENTER now inserts the match
const enter_event = Object.assign({}, tab_event, {'keyCode': 13, 'key': 'Enter', 'target': input}); const enter_event = Object.assign({}, tab_event, {'keyCode': 13, 'key': 'Enter', 'target': input});
view.emoji_picker_view.onKeyDown(enter_event); input.dispatchEvent(new KeyboardEvent('keydown', enter_event));
expect(input.value).toBe('');
await u.waitUntil(() => input.value === '');
expect(textarea.value).toBe(':grimacing: '); expect(textarea.value).toBe(':grimacing: ');
// Test that username starting with : doesn't cause issues // Test that username starting with : doesn't cause issues
...@@ -124,8 +126,9 @@ describe("Emojis", function () { ...@@ -124,8 +126,9 @@ describe("Emojis", function () {
'preventDefault': function preventDefault () {}, 'preventDefault': function preventDefault () {},
'stopPropagation': function stopPropagation () {} 'stopPropagation': function stopPropagation () {}
}; };
view.emoji_picker_view.onKeyDown(event); input.dispatchEvent(new KeyboardEvent('keydown', event));
await u.waitUntil(() => view.emoji_picker_view.model.get('query') === 'smiley');
await u.waitUntil(() => view.emoji_picker_view.model.get('query') === 'smiley', 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.length).toBe(2);
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:'); expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
...@@ -133,26 +136,28 @@ describe("Emojis", function () { ...@@ -133,26 +136,28 @@ describe("Emojis", function () {
// Check that pressing enter without an unambiguous match does nothing // Check that pressing enter without an unambiguous match does nothing
const enter_event = Object.assign({}, event, {'keyCode': 13}); const enter_event = Object.assign({}, event, {'keyCode': 13});
view.emoji_picker_view.onKeyDown(enter_event); input.dispatchEvent(new KeyboardEvent('keydown', enter_event));
expect(input.value).toBe('smiley'); expect(input.value).toBe('smiley');
// Test that TAB autocompletes the to first match // Test that TAB autocompletes the to first match
const tab_event = Object.assign({}, event, {'keyCode': 9, 'key': 'Tab'}); const tab_event = Object.assign({}, event, {'keyCode': 9, 'key': 'Tab'});
view.emoji_picker_view.onKeyDown(tab_event); input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
expect(input.value).toBe(':smiley:');
await u.waitUntil(() => input.value === ':smiley:');
visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker); visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', picker);
expect(visible_emojis.length).toBe(1); expect(visible_emojis.length).toBe(1);
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
view.emoji_picker_view.onKeyDown(enter_event); input.dispatchEvent(new KeyboardEvent('keydown', enter_event));
expect(input.value).toBe(''); await u.waitUntil(() => input.value === '');
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: '); expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
done(); done();
})); }));
}); });
describe("A Chat Message", function () { describe("A Chat Message", function () {
it("will display larger if it's only emojis", it("will display larger if it's only emojis",
mock.initConverse( mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {'use_system_emojis': true}, ['rosterGroupsFetched', 'chatBoxesFetched'], {'use_system_emojis': true},
......
This diff is collapsed.
This diff is collapsed.
import { html } from "lit-html";
import { __ } from '@converse/headless/i18n'; import { __ } from '@converse/headless/i18n';
import { _converse, api } from "@converse/headless/converse-core";
import { html } from "lit-html";
const u = converse.env.utils;
const i18n_search = __('Search'); const i18n_search = __('Search');
const i18n_search_results = __('Search results'); const i18n_search_results = __('Search results');
...@@ -11,7 +13,7 @@ const emoji_category = (o) => { ...@@ -11,7 +13,7 @@ const emoji_category = (o) => {
return html` return html`
<li data-category="${o.category}" <li data-category="${o.category}"
class="emoji-category ${o.category} ${(o.current_category === o.category) ? 'picked' : ''}" class="emoji-category ${o.category} ${(o.current_category === o.category) ? 'picked' : ''}"
title="${__(o._converse.emoji_category_labels[o.category])}"> title="${__(_converse.emoji_category_labels[o.category])}">
<a class="pick-category" <a class="pick-category"
@click=${o.onCategoryPicked} @click=${o.onCategoryPicked}
...@@ -45,7 +47,7 @@ const search_results = (o) => html` ...@@ -45,7 +47,7 @@ const search_results = (o) => html`
`; `;
const emojis_for_category = (o) => html` const emojis_for_category = (o) => html`
<a id="emoji-picker-${o.category}" class="emoji-category__heading" data-category="${o.category}">${ __(o._converse.api.settings.get('emoji_category_labels')[o.category]) }</a> <a id="emoji-picker-${o.category}" class="emoji-category__heading" data-category="${o.category}">${ __(api.settings.get('emoji_category_labels')[o.category]) }</a>
<ul class="emoji-picker" data-category="${o.category}"> <ul class="emoji-picker" data-category="${o.category}">
${ Object.values(o.emojis_by_category[o.category]).map(emoji => emoji_item(Object.assign({emoji}, o))) } ${ Object.values(o.emojis_by_category[o.category]).map(emoji => emoji_item(Object.assign({emoji}, o))) }
</ul> </ul>
...@@ -68,21 +70,27 @@ const all_emojis = (o) => html` ...@@ -68,21 +70,27 @@ const all_emojis = (o) => html`
`; `;
export default (o) => html` export default (o) => {
<div class="emoji-picker__header"> o.emoji_categories = api.settings.get('emoji_categories');
<input class="form-control emoji-search" name="emoji-search" placeholder="${i18n_search}" o.emojis_by_category = _converse.emojis.json;
.value=${o.query || ''} o.transform = u.getEmojiRenderer();
@keydown=${o.onSearchInputKeyDown} o.toned_emojis = _converse.emojis.toned;
@blur=${o.onSearchInputBlurred}
@focus=${o.onSearchInputFocus}> return html`
${ o.query ? '' : emoji_picker_header(o) } <div class="emoji-picker__header">
</div> <input class="form-control emoji-search" name="emoji-search" placeholder="${i18n_search}"
<div class="emoji-picker__lists"> .value=${o.query || ''}
${search_results(o)} @keydown=${o.onSearchInputKeyDown}
${all_emojis(o)} @blur=${o.onSearchInputBlurred}
</div> @focus=${o.onSearchInputFocus}>
<div class="emoji-skintone-picker"> ${ o.query ? '' : emoji_picker_header(o) }
<label>Skin tone</label> </div>
<ul>${ skintones.map(skintone => skintone_emoji(Object.assign({skintone}, o))) }</ul> <div class="emoji-picker__lists">
</div> ${search_results(o)}
`; ${all_emojis(o)}
</div>
<div class="emoji-skintone-picker">
<label>Skin tone</label>
<ul>${ skintones.map(skintone => skintone_emoji(Object.assign({skintone}, o))) }</ul>
</div>`;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment