@ckeditor/ckeditor5-emoji 44.2.0-alpha.6 → 44.2.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -0
- package/build/emoji.js +1 -1
- package/ckeditor5-metadata.json +8 -2
- package/dist/index-editor.css +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.js +211 -91
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/augmentation.d.ts +2 -1
- package/src/emojimention.d.ts +3 -2
- package/src/emojimention.js +8 -8
- package/src/emojipicker.d.ts +3 -3
- package/src/emojipicker.js +14 -14
- package/src/emojirepository.d.ts +13 -14
- package/src/emojirepository.js +15 -81
- package/src/emojiutils.d.ts +58 -0
- package/src/emojiutils.js +141 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/utils/isemojisupported.d.ts +11 -0
- package/src/utils/isemojisupported.js +68 -0
- package/theme/emojigrid.css +1 -1
package/dist/index.js
CHANGED
|
@@ -9,10 +9,68 @@ import Fuse from 'fuse.js';
|
|
|
9
9
|
import { groupBy, escapeRegExp } from 'lodash-es';
|
|
10
10
|
import { View, addKeyboardHandlingForGrid, ButtonView, FocusCycler, SearchTextView, createLabeledInputText, createDropdown, ViewModel, addListToDropdown, SearchInfoView, ContextualBalloon, Dialog, MenuBarMenuListItemButtonView, clickOutsideHandler } from '@ckeditor/ckeditor5-ui/dist/index.js';
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
/**
|
|
13
|
+
* @license Copyright (c) 2023, Koala Interactive SAS
|
|
14
|
+
* For licensing, see https://github.com/koala-interactive/is-emoji-supported/blob/master/LICENSE.md
|
|
15
|
+
*/ /**
|
|
16
|
+
* @module emoji/utils/isemojisupported
|
|
17
|
+
*/ /**
|
|
18
|
+
* Checks if the two pixels parts are the same using canvas.
|
|
19
|
+
*/ function isEmojiSupported(unicode) {
|
|
20
|
+
const ctx = getCanvas();
|
|
21
|
+
/* istanbul ignore next -- @preserve */ if (!ctx) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const CANVAS_HEIGHT = 25;
|
|
25
|
+
const CANVAS_WIDTH = 20;
|
|
26
|
+
const textSize = Math.floor(CANVAS_HEIGHT / 2);
|
|
27
|
+
// Initialize canvas context.
|
|
28
|
+
ctx.font = textSize + 'px Arial, Sans-Serif';
|
|
29
|
+
ctx.textBaseline = 'top';
|
|
30
|
+
ctx.canvas.width = CANVAS_WIDTH * 2;
|
|
31
|
+
ctx.canvas.height = CANVAS_HEIGHT;
|
|
32
|
+
ctx.clearRect(0, 0, CANVAS_WIDTH * 2, CANVAS_HEIGHT);
|
|
33
|
+
// Draw in red on the left.
|
|
34
|
+
ctx.fillStyle = '#FF0000';
|
|
35
|
+
ctx.fillText(unicode, 0, 22);
|
|
36
|
+
// Draw in blue on right.
|
|
37
|
+
ctx.fillStyle = '#0000FF';
|
|
38
|
+
ctx.fillText(unicode, CANVAS_WIDTH, 22);
|
|
39
|
+
const a = ctx.getImageData(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT).data;
|
|
40
|
+
const count = a.length;
|
|
41
|
+
let i = 0;
|
|
42
|
+
// Search the first visible pixel.
|
|
43
|
+
for(; i < count && !a[i + 3]; i += 4);
|
|
44
|
+
// No visible pixel.
|
|
45
|
+
/* istanbul ignore next -- @preserve */ if (i >= count) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
// Emoji has immutable color, so we check the color of the emoji in two different colors.
|
|
49
|
+
// the result show be the same.
|
|
50
|
+
const x = CANVAS_WIDTH + i / 4 % CANVAS_WIDTH;
|
|
51
|
+
const y = Math.floor(i / 4 / CANVAS_WIDTH);
|
|
52
|
+
const b = ctx.getImageData(x, y, 1, 1).data;
|
|
53
|
+
if (a[i] !== b[0] || a[i + 2] !== b[2]) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
//Some emojis consist of different ones, so they will show multiple characters if they are not supported.
|
|
57
|
+
/* istanbul ignore next -- @preserve */ if (ctx.measureText(unicode).width >= CANVAS_WIDTH) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
// Supported.
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
function getCanvas() {
|
|
64
|
+
try {
|
|
65
|
+
return document.createElement('canvas').getContext('2d');
|
|
66
|
+
} catch {
|
|
67
|
+
/* istanbul ignore next -- @preserve */ return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @module emoji/emojiutils
|
|
73
|
+
*/ const SKIN_TONE_MAP = {
|
|
16
74
|
0: 'default',
|
|
17
75
|
1: 'light',
|
|
18
76
|
2: 'medium-light',
|
|
@@ -20,12 +78,127 @@ const SKIN_TONE_MAP = {
|
|
|
20
78
|
4: 'medium-dark',
|
|
21
79
|
5: 'dark'
|
|
22
80
|
};
|
|
81
|
+
/**
|
|
82
|
+
* A map representing an emoji and its release version.
|
|
83
|
+
* It's used to identify a user's minimal supported emoji level.
|
|
84
|
+
*/ const EMOJI_SUPPORT_LEVEL = {
|
|
85
|
+
'': 16,
|
|
86
|
+
'🫨': 15.1 // Shaking head. Although the version of emoji is 15, it is used to detect versions 15 and 15.1.
|
|
87
|
+
};
|
|
23
88
|
const BASELINE_EMOJI_WIDTH = 24;
|
|
89
|
+
/**
|
|
90
|
+
* The Emoji utilities plugin.
|
|
91
|
+
*/ class EmojiUtils extends Plugin {
|
|
92
|
+
/**
|
|
93
|
+
* @inheritDoc
|
|
94
|
+
*/ static get pluginName() {
|
|
95
|
+
return 'EmojiUtils';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* @inheritDoc
|
|
99
|
+
*/ static get isOfficialPlugin() {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Checks if the emoji is supported by verifying the emoji version supported by the system first.
|
|
104
|
+
* Then checks if emoji contains a zero width joiner (ZWJ), and if yes, then checks if it is supported by the system.
|
|
105
|
+
*/ isEmojiSupported(item, emojiSupportedVersionByOs, container) {
|
|
106
|
+
const isEmojiVersionSupported = item.version <= emojiSupportedVersionByOs;
|
|
107
|
+
if (!isEmojiVersionSupported) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
if (!this.hasZwj(item.emoji)) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return this.isEmojiZwjSupported(item, container);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Checks the supported emoji version by the OS, by sampling some representatives from different emoji releases.
|
|
117
|
+
*/ getEmojiSupportedVersionByOs() {
|
|
118
|
+
return Object.entries(EMOJI_SUPPORT_LEVEL).reduce((currentVersion, [emoji, newVersion])=>{
|
|
119
|
+
if (newVersion > currentVersion && EmojiUtils._isEmojiSupported(emoji)) {
|
|
120
|
+
return newVersion;
|
|
121
|
+
}
|
|
122
|
+
return currentVersion;
|
|
123
|
+
}, 0);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check for ZWJ (zero width joiner) character.
|
|
127
|
+
*/ hasZwj(emoji) {
|
|
128
|
+
return emoji.includes('\u200d');
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Checks whether the emoji is supported in the operating system.
|
|
132
|
+
*/ isEmojiZwjSupported(item, container) {
|
|
133
|
+
const emojiWidth = this.getNodeWidth(container, item.emoji);
|
|
134
|
+
// On Windows, some supported emoji are ~50% bigger than the baseline emoji, but what we really want to guard
|
|
135
|
+
// against are the ones that are 2x the size, because those are truly broken (person with red hair = person with
|
|
136
|
+
// floating red wig, black cat = cat with black square, polar bear = bear with snowflake, etc.)
|
|
137
|
+
// So here we set the threshold at 1.8 times the size of the baseline emoji.
|
|
138
|
+
return emojiWidth < BASELINE_EMOJI_WIDTH * 1.8;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Returns the width of the provided node.
|
|
142
|
+
*/ getNodeWidth(container, node) {
|
|
143
|
+
const span = document.createElement('span');
|
|
144
|
+
span.textContent = node;
|
|
145
|
+
container.appendChild(span);
|
|
146
|
+
const nodeWidth = span.offsetWidth;
|
|
147
|
+
container.removeChild(span);
|
|
148
|
+
return nodeWidth;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Creates a div for emoji width testing purposes.
|
|
152
|
+
*/ createEmojiWidthTestingContainer() {
|
|
153
|
+
const container = document.createElement('div');
|
|
154
|
+
container.setAttribute('aria-hidden', 'true');
|
|
155
|
+
container.style.position = 'absolute';
|
|
156
|
+
container.style.left = '-9999px';
|
|
157
|
+
container.style.whiteSpace = 'nowrap';
|
|
158
|
+
container.style.fontSize = BASELINE_EMOJI_WIDTH + 'px';
|
|
159
|
+
return container;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Adds default skin tone property to each emoji. If emoji defines other skin tones, they are added as well.
|
|
163
|
+
*/ normalizeEmojiSkinTone(item) {
|
|
164
|
+
const entry = {
|
|
165
|
+
...item,
|
|
166
|
+
skins: {
|
|
167
|
+
default: item.emoji
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
if (item.skins) {
|
|
171
|
+
item.skins.forEach((skin)=>{
|
|
172
|
+
const skinTone = SKIN_TONE_MAP[skin.tone];
|
|
173
|
+
entry.skins[skinTone] = skin.emoji;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return entry;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Checks whether the emoji belongs to a group that is allowed.
|
|
180
|
+
*/ isEmojiCategoryAllowed(item) {
|
|
181
|
+
// Category group=2 contains skin tones only, which we do not want to render.
|
|
182
|
+
return item.group !== 2;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* A function used to determine if emoji is supported by detecting pixels.
|
|
186
|
+
*
|
|
187
|
+
* Referenced for unit testing purposes. Kept in a separate file because of licensing.
|
|
188
|
+
*/ static _isEmojiSupported = isEmojiSupported;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// An endpoint from which the emoji database will be downloaded during plugin initialization.
|
|
192
|
+
// The `{version}` placeholder is replaced with the value from editor config.
|
|
193
|
+
const EMOJI_DATABASE_URL = 'https://cdn.ckeditor.com/ckeditor5/data/emoji/{version}/en.json';
|
|
24
194
|
/**
|
|
25
195
|
* The emoji repository plugin.
|
|
26
196
|
*
|
|
27
197
|
* Loads the emoji database from URL during plugin initialization and provides utility methods to search it.
|
|
28
198
|
*/ class EmojiRepository extends Plugin {
|
|
199
|
+
/**
|
|
200
|
+
* An instance of the [Fuse.js](https://www.fusejs.io/) library.
|
|
201
|
+
*/ _fuseSearch;
|
|
29
202
|
/**
|
|
30
203
|
* Emoji database.
|
|
31
204
|
*/ _database;
|
|
@@ -34,8 +207,12 @@ const BASELINE_EMOJI_WIDTH = 24;
|
|
|
34
207
|
* The promise resolves with `true` when the database is successfully downloaded or `false` otherwise.
|
|
35
208
|
*/ _databasePromise;
|
|
36
209
|
/**
|
|
37
|
-
*
|
|
38
|
-
*/
|
|
210
|
+
* @inheritDoc
|
|
211
|
+
*/ static get requires() {
|
|
212
|
+
return [
|
|
213
|
+
EmojiUtils
|
|
214
|
+
];
|
|
215
|
+
}
|
|
39
216
|
/**
|
|
40
217
|
* @inheritDoc
|
|
41
218
|
*/ static get pluginName() {
|
|
@@ -63,17 +240,20 @@ const BASELINE_EMOJI_WIDTH = 24;
|
|
|
63
240
|
/**
|
|
64
241
|
* @inheritDoc
|
|
65
242
|
*/ async init() {
|
|
243
|
+
const emojiUtils = this.editor.plugins.get('EmojiUtils');
|
|
66
244
|
const emojiVersion = this.editor.config.get('emoji.version');
|
|
67
245
|
const emojiDatabaseUrl = EMOJI_DATABASE_URL.replace('{version}', `${emojiVersion}`);
|
|
68
246
|
const emojiDatabase = await loadEmojiDatabase(emojiDatabaseUrl);
|
|
247
|
+
const emojiSupportedVersionByOs = emojiUtils.getEmojiSupportedVersionByOs();
|
|
69
248
|
// Skip the initialization if the emoji database download has failed.
|
|
70
249
|
// An empty database prevents the initialization of other dependent plugins, such as `EmojiMention` and `EmojiPicker`.
|
|
71
250
|
if (!emojiDatabase.length) {
|
|
72
251
|
return this._databasePromiseResolveCallback(false);
|
|
73
252
|
}
|
|
74
|
-
const container = createEmojiWidthTestingContainer();
|
|
253
|
+
const container = emojiUtils.createEmojiWidthTestingContainer();
|
|
254
|
+
document.body.appendChild(container);
|
|
75
255
|
// Store the emoji database after normalizing the raw data.
|
|
76
|
-
this._database = emojiDatabase.filter((item)=>isEmojiCategoryAllowed(item)).filter((item)=>
|
|
256
|
+
this._database = emojiDatabase.filter((item)=>emojiUtils.isEmojiCategoryAllowed(item)).filter((item)=>emojiUtils.isEmojiSupported(item, emojiSupportedVersionByOs, container)).map((item)=>emojiUtils.normalizeEmojiSkinTone(item));
|
|
77
257
|
container.remove();
|
|
78
258
|
// Create instance of the Fuse.js library with configured weighted search keys and disabled fuzzy search.
|
|
79
259
|
this._fuseSearch = new Fuse(this._database, {
|
|
@@ -239,11 +419,6 @@ const BASELINE_EMOJI_WIDTH = 24;
|
|
|
239
419
|
*/ isReady() {
|
|
240
420
|
return this._databasePromise;
|
|
241
421
|
}
|
|
242
|
-
/**
|
|
243
|
-
* A function used to check if the given emoji is supported in the operating system.
|
|
244
|
-
*
|
|
245
|
-
* Referenced for unit testing purposes.
|
|
246
|
-
*/ static _isEmojiSupported = isEmojiSupported;
|
|
247
422
|
}
|
|
248
423
|
/**
|
|
249
424
|
* Makes the HTTP request to download the emoji database.
|
|
@@ -269,61 +444,6 @@ const BASELINE_EMOJI_WIDTH = 24;
|
|
|
269
444
|
}
|
|
270
445
|
return result;
|
|
271
446
|
}
|
|
272
|
-
/**
|
|
273
|
-
* Creates a div for emoji width testing purposes.
|
|
274
|
-
*/ function createEmojiWidthTestingContainer() {
|
|
275
|
-
const container = document.createElement('div');
|
|
276
|
-
container.setAttribute('aria-hidden', 'true');
|
|
277
|
-
container.style.position = 'absolute';
|
|
278
|
-
container.style.left = '-9999px';
|
|
279
|
-
container.style.whiteSpace = 'nowrap';
|
|
280
|
-
container.style.fontSize = BASELINE_EMOJI_WIDTH + 'px';
|
|
281
|
-
document.body.appendChild(container);
|
|
282
|
-
return container;
|
|
283
|
-
}
|
|
284
|
-
/**
|
|
285
|
-
* Returns the width of the provided node.
|
|
286
|
-
*/ function getNodeWidth(container, node) {
|
|
287
|
-
const span = document.createElement('span');
|
|
288
|
-
span.textContent = node;
|
|
289
|
-
container.appendChild(span);
|
|
290
|
-
const nodeWidth = span.offsetWidth;
|
|
291
|
-
container.removeChild(span);
|
|
292
|
-
return nodeWidth;
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Checks whether the emoji is supported in the operating system.
|
|
296
|
-
*/ function isEmojiSupported(item, container) {
|
|
297
|
-
const emojiWidth = getNodeWidth(container, item.emoji);
|
|
298
|
-
// On Windows, some supported emoji are ~50% bigger than the baseline emoji, but what we really want to guard
|
|
299
|
-
// against are the ones that are 2x the size, because those are truly broken (person with red hair = person with
|
|
300
|
-
// floating red wig, black cat = cat with black square, polar bear = bear with snowflake, etc.)
|
|
301
|
-
// So here we set the threshold at 1.8 times the size of the baseline emoji.
|
|
302
|
-
return emojiWidth / 1.8 < BASELINE_EMOJI_WIDTH && emojiWidth >= BASELINE_EMOJI_WIDTH;
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Adds default skin tone property to each emoji. If emoji defines other skin tones, they are added as well.
|
|
306
|
-
*/ function normalizeEmojiSkinTone(item) {
|
|
307
|
-
const entry = {
|
|
308
|
-
...item,
|
|
309
|
-
skins: {
|
|
310
|
-
default: item.emoji
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
if (item.skins) {
|
|
314
|
-
item.skins.forEach((skin)=>{
|
|
315
|
-
const skinTone = SKIN_TONE_MAP[skin.tone];
|
|
316
|
-
entry.skins[skinTone] = skin.emoji;
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
return entry;
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* Checks whether the emoji belongs to a group that is allowed.
|
|
323
|
-
*/ function isEmojiCategoryAllowed(item) {
|
|
324
|
-
// Category group=2 contains skin tones only, which we do not want to render.
|
|
325
|
-
return item.group !== 2;
|
|
326
|
-
}
|
|
327
447
|
|
|
328
448
|
const EMOJI_MENTION_MARKER = ':';
|
|
329
449
|
const EMOJI_SHOW_ALL_OPTION_ID = ':__EMOJI_SHOW_ALL:';
|
|
@@ -411,9 +531,9 @@ const EMOJI_HINT_OPTION_ID = ':__EMOJI_HINT:';
|
|
|
411
531
|
* @inheritDoc
|
|
412
532
|
*/ async init() {
|
|
413
533
|
const editor = this.editor;
|
|
414
|
-
this.
|
|
415
|
-
this.
|
|
416
|
-
this._isEmojiRepositoryAvailable = await this.
|
|
534
|
+
this.emojiPickerPlugin = editor.plugins.has('EmojiPicker') ? editor.plugins.get('EmojiPicker') : null;
|
|
535
|
+
this.emojiRepositoryPlugin = editor.plugins.get('EmojiRepository');
|
|
536
|
+
this._isEmojiRepositoryAvailable = await this.emojiRepositoryPlugin.isReady();
|
|
417
537
|
// Override the `mention` command listener if the emoji repository is ready.
|
|
418
538
|
if (this._isEmojiRepositoryAvailable) {
|
|
419
539
|
editor.once('ready', this._overrideMentionExecuteListener.bind(this));
|
|
@@ -470,7 +590,7 @@ const EMOJI_HINT_OPTION_ID = ':__EMOJI_HINT:';
|
|
|
470
590
|
editor.model.change((writer)=>{
|
|
471
591
|
editor.model.deleteContent(writer.createSelection(eventData.range));
|
|
472
592
|
});
|
|
473
|
-
const emojiPickerPlugin = this.
|
|
593
|
+
const emojiPickerPlugin = this.emojiPickerPlugin;
|
|
474
594
|
emojiPickerPlugin.showUI(text.slice(1));
|
|
475
595
|
setTimeout(()=>{
|
|
476
596
|
emojiPickerPlugin.emojiPickerView.focus();
|
|
@@ -497,17 +617,17 @@ const EMOJI_HINT_OPTION_ID = ':__EMOJI_HINT:';
|
|
|
497
617
|
if (!this._isEmojiRepositoryAvailable) {
|
|
498
618
|
return [];
|
|
499
619
|
}
|
|
500
|
-
const emojis = this.
|
|
620
|
+
const emojis = this.emojiRepositoryPlugin.getEmojiByQuery(searchQuery).map((emoji)=>{
|
|
501
621
|
let text = emoji.skins[this._skinTone] || emoji.skins.default;
|
|
502
|
-
if (this.
|
|
503
|
-
text = emoji.skins[this.
|
|
622
|
+
if (this.emojiPickerPlugin) {
|
|
623
|
+
text = emoji.skins[this.emojiPickerPlugin.skinTone] || emoji.skins.default;
|
|
504
624
|
}
|
|
505
625
|
return {
|
|
506
626
|
id: `:${emoji.annotation}:`,
|
|
507
627
|
text
|
|
508
628
|
};
|
|
509
629
|
});
|
|
510
|
-
if (!this.
|
|
630
|
+
if (!this.emojiPickerPlugin) {
|
|
511
631
|
return emojis.slice(0, this._emojiDropdownLimit);
|
|
512
632
|
}
|
|
513
633
|
const actionItem = {
|
|
@@ -1245,10 +1365,10 @@ const VISUAL_SELECTION_MARKER_NAME = 'emoji-picker';
|
|
|
1245
1365
|
* @inheritDoc
|
|
1246
1366
|
*/ async init() {
|
|
1247
1367
|
const editor = this.editor;
|
|
1248
|
-
this.
|
|
1249
|
-
this.
|
|
1368
|
+
this.balloonPlugin = editor.plugins.get('ContextualBalloon');
|
|
1369
|
+
this.emojiRepositoryPlugin = editor.plugins.get('EmojiRepository');
|
|
1250
1370
|
// Skip registering a button in the toolbar and list item in the menu bar if the emoji repository is not ready.
|
|
1251
|
-
if (!await this.
|
|
1371
|
+
if (!await this.emojiRepositoryPlugin.isReady()) {
|
|
1252
1372
|
return;
|
|
1253
1373
|
}
|
|
1254
1374
|
const command = new EmojiCommand(editor);
|
|
@@ -1299,8 +1419,8 @@ const VISUAL_SELECTION_MARKER_NAME = 'emoji-picker';
|
|
|
1299
1419
|
this.emojiPickerView.searchView.setInputValue(searchValue);
|
|
1300
1420
|
}
|
|
1301
1421
|
this.emojiPickerView.searchView.search(searchValue);
|
|
1302
|
-
if (!this.
|
|
1303
|
-
this.
|
|
1422
|
+
if (!this.balloonPlugin.hasView(this.emojiPickerView)) {
|
|
1423
|
+
this.balloonPlugin.add({
|
|
1304
1424
|
view: this.emojiPickerView,
|
|
1305
1425
|
position: this._getBalloonPositionData()
|
|
1306
1426
|
});
|
|
@@ -1327,11 +1447,11 @@ const VISUAL_SELECTION_MARKER_NAME = 'emoji-picker';
|
|
|
1327
1447
|
* Creates an instance of the `EmojiPickerView` class that represents an emoji balloon.
|
|
1328
1448
|
*/ _createEmojiPickerView() {
|
|
1329
1449
|
const emojiPickerView = new EmojiPickerView(this.editor.locale, {
|
|
1330
|
-
emojiCategories: this.
|
|
1450
|
+
emojiCategories: this.emojiRepositoryPlugin.getEmojiCategories(),
|
|
1331
1451
|
skinTone: this.editor.config.get('emoji.skinTone'),
|
|
1332
|
-
skinTones: this.
|
|
1452
|
+
skinTones: this.emojiRepositoryPlugin.getSkinTones(),
|
|
1333
1453
|
getEmojiByQuery: (query)=>{
|
|
1334
|
-
return this.
|
|
1454
|
+
return this.emojiRepositoryPlugin.getEmojiByQuery(query);
|
|
1335
1455
|
}
|
|
1336
1456
|
});
|
|
1337
1457
|
// Insert an emoji on a tile click.
|
|
@@ -1345,8 +1465,8 @@ const VISUAL_SELECTION_MARKER_NAME = 'emoji-picker';
|
|
|
1345
1465
|
});
|
|
1346
1466
|
// Update the balloon position when layout is changed.
|
|
1347
1467
|
this.listenTo(emojiPickerView, 'update', ()=>{
|
|
1348
|
-
if (this.
|
|
1349
|
-
this.
|
|
1468
|
+
if (this.balloonPlugin.visibleView === emojiPickerView) {
|
|
1469
|
+
this.balloonPlugin.updatePosition();
|
|
1350
1470
|
}
|
|
1351
1471
|
});
|
|
1352
1472
|
// Close the panel on `Esc` key press when the **actions have focus**.
|
|
@@ -1358,17 +1478,17 @@ const VISUAL_SELECTION_MARKER_NAME = 'emoji-picker';
|
|
|
1358
1478
|
clickOutsideHandler({
|
|
1359
1479
|
emitter: emojiPickerView,
|
|
1360
1480
|
contextElements: [
|
|
1361
|
-
this.
|
|
1481
|
+
this.balloonPlugin.view.element
|
|
1362
1482
|
],
|
|
1363
1483
|
callback: ()=>this._hideUI(),
|
|
1364
|
-
activator: ()=>this.
|
|
1484
|
+
activator: ()=>this.balloonPlugin.visibleView === emojiPickerView
|
|
1365
1485
|
});
|
|
1366
1486
|
return emojiPickerView;
|
|
1367
1487
|
}
|
|
1368
1488
|
/**
|
|
1369
1489
|
* Hides the balloon with the emoji picker.
|
|
1370
1490
|
*/ _hideUI() {
|
|
1371
|
-
this.
|
|
1491
|
+
this.balloonPlugin.remove(this.emojiPickerView);
|
|
1372
1492
|
this.emojiPickerView.searchView.setInputValue('');
|
|
1373
1493
|
this.editor.editing.view.focus();
|
|
1374
1494
|
this._hideFakeVisualSelection();
|
|
@@ -1403,7 +1523,7 @@ const VISUAL_SELECTION_MARKER_NAME = 'emoji-picker';
|
|
|
1403
1523
|
});
|
|
1404
1524
|
}
|
|
1405
1525
|
/**
|
|
1406
|
-
* Returns positioning options for the {@link #
|
|
1526
|
+
* Returns positioning options for the {@link #balloonPlugin}. They control the way the balloon is attached
|
|
1407
1527
|
* to the target element or selection.
|
|
1408
1528
|
*/ _getBalloonPositionData() {
|
|
1409
1529
|
const view = this.editor.editing.view;
|
|
@@ -1486,5 +1606,5 @@ const VISUAL_SELECTION_MARKER_NAME = 'emoji-picker';
|
|
|
1486
1606
|
}
|
|
1487
1607
|
}
|
|
1488
1608
|
|
|
1489
|
-
export { Emoji, EmojiCommand, EmojiMention, EmojiPicker, EmojiRepository };
|
|
1609
|
+
export { Emoji, EmojiCommand, EmojiMention, EmojiPicker, EmojiRepository, EmojiUtils };
|
|
1490
1610
|
//# sourceMappingURL=index.js.map
|