FEATURE: favorites emojis will also show in composer autocomplete (#8011)

This commit is contained in:
Joffrey JAFFEUX
2019-08-16 11:47:03 +02:00
committed by GitHub
parent 9a9e31f927
commit 936d4ce17a
5 changed files with 106 additions and 39 deletions

View File

@ -220,6 +220,7 @@ export default Ember.Component.extend({
_mouseTrap: null, _mouseTrap: null,
showLink: true, showLink: true,
emojiPickerIsActive: false, emojiPickerIsActive: false,
emojiStore: Ember.inject.service("emoji-store"),
@computed("placeholder") @computed("placeholder")
placeholderTranslated(placeholder) { placeholderTranslated(placeholder) {
@ -422,6 +423,7 @@ export default Ember.Component.extend({
transformComplete: v => { transformComplete: v => {
if (v.code) { if (v.code) {
this.emojiStore.track(v.code);
return `${v.code}:`; return `${v.code}:`;
} else { } else {
$editorInput.autocomplete({ cancel: true }); $editorInput.autocomplete({ cancel: true });
@ -458,7 +460,17 @@ export default Ember.Component.extend({
} }
if (term === "") { if (term === "") {
return resolve(["slight_smile", "smile", "wink", "sunny", "blush"]); if (this.emojiStore.favorites.length) {
return resolve(this.emojiStore.favorites.slice(0, 5));
} else {
return resolve([
"slight_smile",
"smile",
"wink",
"sunny",
"blush"
]);
}
} }
if (translations[full]) { if (translations[full]) {

View File

@ -1,7 +1,7 @@
import { on, observes } from "ember-addons/ember-computed-decorators"; import { on, observes } from "ember-addons/ember-computed-decorators";
import { findRawTemplate } from "discourse/lib/raw-templates"; import { findRawTemplate } from "discourse/lib/raw-templates";
import { emojiUrlFor } from "discourse/lib/text"; import { emojiUrlFor } from "discourse/lib/text";
import KeyValueStore from "discourse/lib/key-value-store";
import { import {
extendedEmojiList, extendedEmojiList,
isSkinTonableEmoji, isSkinTonableEmoji,
@ -10,21 +10,14 @@ import {
import { safariHacksDisabled } from "discourse/lib/utilities"; import { safariHacksDisabled } from "discourse/lib/utilities";
const { run } = Ember; const { run } = Ember;
const keyValueStore = new KeyValueStore("discourse_emojis_");
const EMOJI_USAGE = "emojiUsage";
const EMOJI_SELECTED_DIVERSITY = "emojiSelectedDiversity";
const PER_ROW = 11; const PER_ROW = 11;
const customEmojis = _.keys(extendedEmojiList()).map(code => { const customEmojis = _.keys(extendedEmojiList()).map(code => {
return { code, src: emojiUrlFor(code) }; return { code, src: emojiUrlFor(code) };
}); });
export function resetCache() {
keyValueStore.setObject({ key: EMOJI_USAGE, value: [] });
keyValueStore.setObject({ key: EMOJI_SELECTED_DIVERSITY, value: 1 });
}
export default Ember.Component.extend({ export default Ember.Component.extend({
automaticPositioning: true, automaticPositioning: true,
emojiStore: Ember.inject.service("emoji-store"),
close() { close() {
this._unbindEvents(); this._unbindEvents();
@ -46,11 +39,10 @@ export default Ember.Component.extend({
this.$results = this.$picker.find(".results"); this.$results = this.$picker.find(".results");
this.$list = this.$picker.find(".list"); this.$list = this.$picker.find(".list");
this.set( this.setProperties({
"selectedDiversity", selectedDiversity: this.emojiStore.diversity,
keyValueStore.getObject(EMOJI_SELECTED_DIVERSITY) || 1 recentEmojis: this.emojiStore.favorites
); });
this.set("recentEmojis", keyValueStore.getObject(EMOJI_USAGE) || []);
run.scheduleOnce("afterRender", this, function() { run.scheduleOnce("afterRender", this, function() {
this._bindEvents(); this._bindEvents();
@ -88,18 +80,7 @@ export default Ember.Component.extend({
_setup() { _setup() {
this.$picker = $(this.element.querySelector(".emoji-picker")); this.$picker = $(this.element.querySelector(".emoji-picker"));
this.$modal = $(this.element.querySelector(".emoji-picker-modal")); this.$modal = $(this.element.querySelector(".emoji-picker-modal"));
this.appEvents.on("emoji-picker:close", this, "_closeEmojiPicker"); this.appEvents.on("emoji-picker:close", this, "_closeEmojiPicker");
if (!keyValueStore.getObject(EMOJI_USAGE)) {
keyValueStore.setObject({ key: EMOJI_USAGE, value: [] });
} else if (_.isPlainObject(keyValueStore.getObject(EMOJI_USAGE))) {
// handle legacy format
keyValueStore.setObject({
key: EMOJI_USAGE,
value: _.keys(keyValueStore.getObject(EMOJI_USAGE))
});
}
}, },
@on("didUpdateAttrs") @on("didUpdateAttrs")
@ -116,10 +97,7 @@ export default Ember.Component.extend({
@observes("selectedDiversity") @observes("selectedDiversity")
selectedDiversityChanged() { selectedDiversityChanged() {
keyValueStore.setObject({ this.emojiStore.diversity = this.selectedDiversity;
key: EMOJI_SELECTED_DIVERSITY,
value: this.selectedDiversity
});
$.each( $.each(
this.$list.find(".emoji[data-loaded='1'].diversity"), this.$list.find(".emoji[data-loaded='1'].diversity"),
@ -326,7 +304,7 @@ export default Ember.Component.extend({
".section[data-section='recent'] .clear-recent" ".section[data-section='recent'] .clear-recent"
); );
$recent.on("click", () => { $recent.on("click", () => {
keyValueStore.setObject({ key: EMOJI_USAGE, value: [] }); this.emojiStore.favorites = [];
this.set("recentEmojis", []); this.set("recentEmojis", []);
this._scrollTo(0); this._scrollTo(0);
return false; return false;
@ -608,12 +586,8 @@ export default Ember.Component.extend({
}, },
_trackEmojiUsage(code) { _trackEmojiUsage(code) {
let recent = keyValueStore.getObject(EMOJI_USAGE) || []; this.emojiStore.track(code);
recent = recent.filter(r => r !== code); this.set("recentEmojis", this.emojiStore.favorites.slice(0, PER_ROW));
recent.unshift(code);
recent.length = Math.min(recent.length, PER_ROW);
keyValueStore.setObject({ key: EMOJI_USAGE, value: recent });
this.set("recentEmojis", recent);
}, },
_scrollTo(y) { _scrollTo(y) {

View File

@ -0,0 +1,48 @@
import KeyValueStore from "discourse/lib/key-value-store";
const EMOJI_USAGE = "emojiUsage";
const EMOJI_SELECTED_DIVERSITY = "emojiSelectedDiversity";
const TRACKED_EMOJIS = 15;
const STORE_NAMESPACE = "discourse_emojis_";
export default Ember.Service.extend({
init() {
this._super(...arguments);
this.store = new KeyValueStore(STORE_NAMESPACE);
if (!this.store.getObject(EMOJI_USAGE)) {
this.favorites = [];
}
},
get diversity() {
return this.store.getObject(EMOJI_SELECTED_DIVERSITY) || 1;
},
set diversity(value) {
this.store.setObject({ key: EMOJI_SELECTED_DIVERSITY, value: value || 1 });
},
get favorites() {
return this.store.getObject(EMOJI_USAGE) || [];
},
set favorites(value) {
this.store.setObject({ key: EMOJI_USAGE, value: value || [] });
},
track(code) {
const normalizedCode = code.replace(/(^:)|(:$)/g, "");
const recent = this.favorites.filter(r => r !== normalizedCode);
recent.unshift(normalizedCode);
recent.length = Math.min(recent.length, TRACKED_EMOJIS);
this.favorites = recent;
},
reset() {
const store = new KeyValueStore(STORE_NAMESPACE);
store.setObject({ key: EMOJI_USAGE, value: [] });
store.setObject({ key: EMOJI_SELECTED_DIVERSITY, value: 1 });
}
});

View File

@ -1,11 +1,11 @@
import { acceptance } from "helpers/qunit-helpers"; import { acceptance } from "helpers/qunit-helpers";
import { IMAGE_VERSION as v } from "pretty-text/emoji/version"; import { IMAGE_VERSION as v } from "pretty-text/emoji/version";
import { resetCache } from "discourse/components/emoji-picker";
acceptance("EmojiPicker", { acceptance("EmojiPicker", {
loggedIn: true, loggedIn: true,
beforeEach() { beforeEach() {
resetCache(); const store = Discourse.__container__.lookup("service:emojis-store");
store.reset();
} }
}); });

View File

@ -0,0 +1,33 @@
QUnit.module("lib:emoji-store", {
afterEach() {
const store = Discourse.__container__.lookup("service:emoji-store");
store.reset();
}
});
QUnit.test("defaults", assert => {
const store = Discourse.__container__.lookup("service:emoji-store");
assert.deepEqual(store.favorites, []);
assert.equal(store.diversity, 1);
});
QUnit.test("diversity", assert => {
const store = Discourse.__container__.lookup("service:emoji-store");
store.diversity = 2;
assert.equal(store.diversity, 2);
});
QUnit.test("favorites", assert => {
const store = Discourse.__container__.lookup("service:emoji-store");
store.favorites = ["smile"];
assert.deepEqual(store.favorites, ["smile"]);
});
QUnit.test("track", assert => {
const store = Discourse.__container__.lookup("service:emoji-store");
store.track("woman:t4");
assert.deepEqual(store.favorites, ["woman:t4"]);
store.track("otter");
store.track(":otter:");
assert.deepEqual(store.favorites, ["otter", "woman:t4"]);
});