Skip to content

Commit c870406

Browse files
committed
Add emoji autocompletion
Signed-off-by: John Molakvoæ (skjnldsv) <[email protected]>
1 parent f28decf commit c870406

File tree

5 files changed

+61
-6
lines changed

5 files changed

+61
-6
lines changed

.eslintrc.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module.exports = {
22
globals: {
3+
EMOJIS: true,
34
SCOPE_VERSION: true,
45
TRANSLATIONS: true,
56
oc_userconfig: true

package-lock.json

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"cypress": "^6.5.0",
8484
"cypress-visual-regression": "^1.5.0",
8585
"cypress-vue-unit-test": "^3.5.1",
86+
"emoji-datasource": "^6.0.0",
8687
"eslint": "^6.8.0",
8788
"eslint-config-standard": "^14.1.1",
8889
"eslint-loader": "^4.0.2",

src/components/RichContenteditable/RichContenteditable.vue

+28-6
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ export default {
193193
data() {
194194
return {
195195
tribute: null,
196-
options: {
196+
autocompleteOptions: {
197197
fillAttr: 'id',
198198
// Search against id and label (display name)
199199
lookup: result => `${result.id} ${result.label}`,
@@ -208,6 +208,21 @@ export default {
208208
// Autocompletion results
209209
values: this.debouncedAutoComplete,
210210
},
211+
emojiOptions: {
212+
trigger: ':',
213+
// Search against id and label (display name)
214+
lookup: result => result.short_names.join(' '),
215+
// Where to inject the menu popup
216+
menuContainer: this.menuContainer,
217+
// Popup mention autocompletion templates
218+
menuItemTemplate: item => item.original.value,
219+
// Hide if no results
220+
noMatchTemplate: () => '<span class="hidden"></span>',
221+
// Inner display of mentions, display raw emoji
222+
selectTemplate: item => item.original.value,
223+
// Autocompletion results
224+
values: EMOJIS,
225+
},
211226

212227
// Represent the raw untrimmed text of the contenteditable
213228
// serves no other purpose than to check whether the
@@ -276,8 +291,11 @@ export default {
276291
},
277292

278293
mounted() {
279-
this.tribute = new Tribute(this.options)
280-
this.tribute.attach(this.$el)
294+
this.autocompleteTribute = new Tribute(this.autocompleteOptions)
295+
this.autocompleteTribute.attach(this.$el)
296+
297+
this.emojiTribute = new Tribute(this.emojiOptions)
298+
this.emojiTribute.attach(this.$el)
281299

282300
// Update default value
283301
this.updateContent(this.value)
@@ -287,8 +305,11 @@ export default {
287305
this.$refs.contenteditable.contentEditable = this.contenteditable
288306
},
289307
beforeDestroy() {
290-
if (this.tribute) {
291-
this.tribute.detach(this.$el)
308+
if (this.autocompleteTribute) {
309+
this.autocompleteTribute.detach(this.$el)
310+
}
311+
if (this.emojiTribute) {
312+
this.emojiTribute.detach(this.$el)
292313
}
293314
},
294315

@@ -421,7 +442,8 @@ export default {
421442
onEnter(event) {
422443
// Prevent submitting if autocompletion menu
423444
// is opened or length is over maxlength
424-
if (this.multiline || this.isOverMaxlength || this.tribute.isActive) {
445+
if (this.multiline || this.isOverMaxlength
446+
|| this.autocompleteTribute.isActive || this.emojiTribute.isActive) {
425447
return
426448
}
427449

webpack.common.js

+25
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,30 @@ const IconfontPlugin = require('iconfont-plugin-webpack')
1111
const nodeExternals = require('webpack-node-externals')
1212
const StyleLintPlugin = require('stylelint-webpack-plugin')
1313

14+
const emojisData = require('emoji-datasource/emoji.json')
15+
const EMOJIS = emojisData
16+
.filter(emoji => emoji.short_name)
17+
.reduce((accumulator, current) => {
18+
// Add current emoji
19+
const emoji = Object.assign({}, current)
20+
emoji.value = String.fromCodePoint(...emoji.unified.split('-').map(hex => '0x' + hex))
21+
delete emoji.skin_variations
22+
accumulator.push(emoji)
23+
24+
// Handle variations, take the current emoji and replace with variations
25+
if (current.skin_variations) {
26+
Object.values(current.skin_variations).forEach((variation) => {
27+
const emojiVariation = Object.assign({}, current, variation)
28+
emojiVariation.value = String.fromCodePoint(...emojiVariation.unified.split('-').map(hex => '0x' + hex))
29+
delete emojiVariation.skin_variations
30+
accumulator.push(emojiVariation)
31+
})
32+
}
33+
return accumulator
34+
}, [])
35+
36+
console.info('Emojis count:', EMOJIS.length, typeof emojisData)
37+
1438
// scope variable
1539
// fallback for cypress testing
1640
const appVersion = JSON.stringify(process.env.npm_package_version || 'nextcloud-vue')
@@ -149,6 +173,7 @@ module.exports = {
149173
new DefinePlugin({
150174
SCOPE_VERSION,
151175
TRANSLATIONS: JSON.stringify(translations),
176+
EMOJIS: JSON.stringify(EMOJIS),
152177
}),
153178
],
154179
resolve: {

0 commit comments

Comments
 (0)