FIX: clicking "more..." in emoji autocomplete (#26160)
Should open the emoji picker. But it wasn't 😅 The `handleOutsideClick` event was listening too early and would catch the click on the "more..." option in the autocomplete as a click outside the emoji picker and would immediately close it 🤦 The fix was to defer registering to this event.
This commit is contained in:
parent
139e21e37d
commit
44f6b24e34
|
@ -19,14 +19,10 @@ import discourseComputed, {
|
||||||
} from "discourse-common/utils/decorators";
|
} from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
function customEmojis() {
|
function customEmojis() {
|
||||||
const list = extendedEmojiList();
|
|
||||||
const groups = [];
|
const groups = [];
|
||||||
for (const [code, emoji] of list.entries()) {
|
for (const [code, emoji] of extendedEmojiList()) {
|
||||||
groups[emoji.group] = groups[emoji.group] || [];
|
groups[emoji.group] ||= [];
|
||||||
groups[emoji.group].push({
|
groups[emoji.group].push({ code, src: emojiUrlFor(code) });
|
||||||
code,
|
|
||||||
src: emojiUrlFor(code),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
@ -48,9 +44,7 @@ export default Component.extend({
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.set("customEmojis", customEmojis());
|
this.set("customEmojis", customEmojis());
|
||||||
|
|
||||||
if ("IntersectionObserver" in window) {
|
if ("IntersectionObserver" in window) {
|
||||||
this._sectionObserver = this._setupSectionObserver();
|
this._sectionObserver = this._setupSectionObserver();
|
||||||
}
|
}
|
||||||
|
@ -58,7 +52,6 @@ export default Component.extend({
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.appEvents.on("emoji-picker:close", this, "onClose");
|
this.appEvents.on("emoji-picker:close", this, "onClose");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -83,9 +76,7 @@ export default Component.extend({
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
this._sectionObserver?.disconnect();
|
||||||
this._sectionObserver && this._sectionObserver.disconnect();
|
|
||||||
|
|
||||||
this.appEvents.off("emoji-picker:close", this, "onClose");
|
this.appEvents.off("emoji-picker:close", this, "onClose");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -95,7 +86,6 @@ export default Component.extend({
|
||||||
|
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
this._applyFilter(this.initialFilter);
|
this._applyFilter(this.initialFilter);
|
||||||
document.addEventListener("click", this.handleOutsideClick);
|
|
||||||
|
|
||||||
const emojiPicker = document.querySelector(".emoji-picker");
|
const emojiPicker = document.querySelector(".emoji-picker");
|
||||||
if (!emojiPicker) {
|
if (!emojiPicker) {
|
||||||
|
@ -147,9 +137,10 @@ export default Component.extend({
|
||||||
// of blocking the rendering of the picker
|
// of blocking the rendering of the picker
|
||||||
discourseLater(() => {
|
discourseLater(() => {
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
|
document.addEventListener("click", this.handleOutsideClick);
|
||||||
|
|
||||||
if (!this.site.isMobileDevice || this.isEditorFocused) {
|
if (!this.site.isMobileDevice || this.isEditorFocused) {
|
||||||
const filter = emojiPicker.querySelector("input.filter");
|
emojiPicker.querySelector("input.filter")?.focus();
|
||||||
filter && filter.focus();
|
|
||||||
|
|
||||||
if (this._sectionObserver) {
|
if (this._sectionObserver) {
|
||||||
emojiPicker
|
emojiPicker
|
||||||
|
@ -170,7 +161,7 @@ export default Component.extend({
|
||||||
onClose(event) {
|
onClose(event) {
|
||||||
event?.stopPropagation();
|
event?.stopPropagation();
|
||||||
document.removeEventListener("click", this.handleOutsideClick);
|
document.removeEventListener("click", this.handleOutsideClick);
|
||||||
this.onEmojiPickerClose && this.onEmojiPickerClose(event);
|
this.onEmojiPickerClose?.(event);
|
||||||
},
|
},
|
||||||
|
|
||||||
diversityScales: computed("selectedDiversity", function () {
|
diversityScales: computed("selectedDiversity", function () {
|
||||||
|
@ -239,10 +230,11 @@ export default Component.extend({
|
||||||
@action
|
@action
|
||||||
onCategorySelection(sectionName, event) {
|
onCategorySelection(sectionName, event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
const section = document.querySelector(
|
document
|
||||||
|
.querySelector(
|
||||||
`.emoji-picker-emoji-area .section[data-section="${sectionName}"]`
|
`.emoji-picker-emoji-area .section[data-section="${sectionName}"]`
|
||||||
);
|
)
|
||||||
section && section.scrollIntoView();
|
?.scrollIntoView();
|
||||||
},
|
},
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -264,7 +256,7 @@ export default Component.extend({
|
||||||
|
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
this.onClose(event);
|
this.onClose(event);
|
||||||
const path = event.path || (event.composedPath && event.composedPath());
|
const path = event.path || event.composedPath?.();
|
||||||
|
|
||||||
const fromChatComposer = path.find((e) =>
|
const fromChatComposer = path.find((e) =>
|
||||||
e?.classList?.contains("chat-composer-container")
|
e?.classList?.contains("chat-composer-container")
|
||||||
|
@ -325,8 +317,10 @@ export default Component.extend({
|
||||||
const emojiBelow = [...emojis]
|
const emojiBelow = [...emojis]
|
||||||
.filter((c) => c.offsetTop > active.offsetTop)
|
.filter((c) => c.offsetTop > active.offsetTop)
|
||||||
.find((c) => c.offsetLeft === active.offsetLeft);
|
.find((c) => c.offsetLeft === active.offsetLeft);
|
||||||
|
if (emojiBelow) {
|
||||||
this._updateEmojiPreview(emojiBelow.title);
|
this._updateEmojiPreview(emojiBelow.title);
|
||||||
emojiBelow?.focus();
|
emojiBelow.focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === "ArrowUp") {
|
if (event.key === "ArrowUp") {
|
||||||
|
@ -420,11 +414,8 @@ export default Component.extend({
|
||||||
|
|
||||||
_applyDiversity(diversity) {
|
_applyDiversity(diversity) {
|
||||||
const emojiPickerArea = document.querySelector(".emoji-picker-emoji-area");
|
const emojiPickerArea = document.querySelector(".emoji-picker-emoji-area");
|
||||||
|
emojiPickerArea?.querySelectorAll(".emoji.diversity").forEach((img) => {
|
||||||
emojiPickerArea &&
|
img.src = emojiUrlFor(this._codeWithDiversity(img.title, diversity));
|
||||||
emojiPickerArea.querySelectorAll(".emoji.diversity").forEach((img) => {
|
|
||||||
const code = this._codeWithDiversity(img.title, diversity);
|
|
||||||
img.src = emojiUrlFor(code);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -442,14 +433,13 @@ export default Component.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const button = categoryButtons.querySelector(
|
|
||||||
`.category-button[data-section="${sectionName}"]`
|
|
||||||
);
|
|
||||||
|
|
||||||
categoryButtons
|
categoryButtons
|
||||||
.querySelectorAll(".category-button")
|
.querySelectorAll(".category-button")
|
||||||
.forEach((b) => b.classList.remove("current"));
|
.forEach((b) => b.classList.remove("current"));
|
||||||
button && button.classList.add("current");
|
|
||||||
|
categoryButtons
|
||||||
|
.querySelector(`.category-button[data-section="${sectionName}"]`)
|
||||||
|
?.classList?.add("current");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -475,8 +465,7 @@ export default Component.extend({
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
handleOutsideClick(event) {
|
handleOutsideClick(event) {
|
||||||
const emojiPicker = document.querySelector(".emoji-picker");
|
if (!document.querySelector(".emoji-picker")?.contains(event.target)) {
|
||||||
if (emojiPicker && !emojiPicker.contains(event.target)) {
|
|
||||||
this.onClose(event);
|
this.onClose(event);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { click, visit } from "@ember/test-helpers";
|
import { click, fillIn, visit } from "@ember/test-helpers";
|
||||||
import { IMAGE_VERSION as v } from "pretty-text/emoji/version";
|
import { IMAGE_VERSION as v } from "pretty-text/emoji/version";
|
||||||
import { test } from "qunit";
|
import { test } from "qunit";
|
||||||
import {
|
import {
|
||||||
|
@ -8,7 +8,6 @@ import {
|
||||||
query,
|
query,
|
||||||
simulateKey,
|
simulateKey,
|
||||||
simulateKeys,
|
simulateKeys,
|
||||||
visible,
|
|
||||||
} from "discourse/tests/helpers/qunit-helpers";
|
} from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
|
||||||
acceptance("Emoji", function (needs) {
|
acceptance("Emoji", function (needs) {
|
||||||
|
@ -20,7 +19,6 @@ acceptance("Emoji", function (needs) {
|
||||||
|
|
||||||
await simulateKeys(query(".d-editor-input"), "a :blonde_wo\t");
|
await simulateKeys(query(".d-editor-input"), "a :blonde_wo\t");
|
||||||
|
|
||||||
assert.ok(visible(".d-editor-preview"));
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
normalizeHtml(query(".d-editor-preview").innerHTML.trim()),
|
normalizeHtml(query(".d-editor-preview").innerHTML.trim()),
|
||||||
normalizeHtml(
|
normalizeHtml(
|
||||||
|
@ -29,13 +27,31 @@ acceptance("Emoji", function (needs) {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("emoji can be picked from the emoji-picker using the mouse", async function (assert) {
|
||||||
|
await visit("/t/internationalization-localization/280");
|
||||||
|
await click("#topic-footer-buttons .btn.create");
|
||||||
|
|
||||||
|
await simulateKeys(query(".d-editor-input"), "an :arrow");
|
||||||
|
// the 6th item in the list is the "more..."
|
||||||
|
await click(".autocomplete.ac-emoji ul li:nth-of-type(6)");
|
||||||
|
|
||||||
|
assert.dom(".emoji-picker.opened.has-filter").exists();
|
||||||
|
await click(".emoji-picker .results img:first-of-type");
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
normalizeHtml(query(".d-editor-preview").innerHTML.trim()),
|
||||||
|
normalizeHtml(
|
||||||
|
`<p>an <img src="/images/emoji/twitter/arrow_backward.png?v=${v}" title=":arrow_backward:" class="emoji" alt=":arrow_backward:" loading="lazy" width="20" height="20" style="aspect-ratio: 20 / 20;"></p>`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("skin toned emoji is cooked properly", async function (assert) {
|
test("skin toned emoji is cooked properly", async function (assert) {
|
||||||
await visit("/t/internationalization-localization/280");
|
await visit("/t/internationalization-localization/280");
|
||||||
await click("#topic-footer-buttons .btn.create");
|
await click("#topic-footer-buttons .btn.create");
|
||||||
|
|
||||||
await simulateKeys(query(".d-editor-input"), "a :blonde_woman:t5:");
|
await fillIn(query(".d-editor-input"), "a :blonde_woman:t5:");
|
||||||
|
|
||||||
assert.ok(visible(".d-editor-preview"));
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
normalizeHtml(query(".d-editor-preview").innerHTML.trim()),
|
normalizeHtml(query(".d-editor-preview").innerHTML.trim()),
|
||||||
normalizeHtml(
|
normalizeHtml(
|
||||||
|
@ -44,9 +60,7 @@ acceptance("Emoji", function (needs) {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
needs.settings({
|
needs.settings({ emoji_autocomplete_min_chars: 2 });
|
||||||
emoji_autocomplete_min_chars: 2,
|
|
||||||
});
|
|
||||||
|
|
||||||
test("siteSetting:emoji_autocomplete_min_chars", async function (assert) {
|
test("siteSetting:emoji_autocomplete_min_chars", async function (assert) {
|
||||||
await visit("/t/internationalization-localization/280");
|
await visit("/t/internationalization-localization/280");
|
||||||
|
|
Loading…
Reference in New Issue