@ckeditor/ckeditor5-utils 34.2.0 → 35.1.0

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +324 -0
  2. package/LICENSE.md +1 -1
  3. package/package.json +19 -8
  4. package/src/areconnectedthroughproperties.js +54 -71
  5. package/src/ckeditorerror.js +92 -114
  6. package/src/collection.js +594 -762
  7. package/src/comparearrays.js +22 -28
  8. package/src/config.js +193 -223
  9. package/src/count.js +8 -12
  10. package/src/diff.js +85 -110
  11. package/src/difftochanges.js +47 -57
  12. package/src/dom/createelement.js +17 -25
  13. package/src/dom/emittermixin.js +202 -263
  14. package/src/dom/getancestors.js +9 -13
  15. package/src/dom/getborderwidths.js +10 -13
  16. package/src/dom/getcommonancestor.js +9 -15
  17. package/src/dom/getdatafromelement.js +5 -9
  18. package/src/dom/getpositionedancestor.js +9 -14
  19. package/src/dom/global.js +15 -4
  20. package/src/dom/indexof.js +7 -11
  21. package/src/dom/insertat.js +2 -4
  22. package/src/dom/iscomment.js +2 -5
  23. package/src/dom/isnode.js +10 -12
  24. package/src/dom/isrange.js +2 -4
  25. package/src/dom/istext.js +2 -4
  26. package/src/dom/isvisible.js +2 -4
  27. package/src/dom/iswindow.js +11 -16
  28. package/src/dom/position.js +220 -410
  29. package/src/dom/rect.js +335 -414
  30. package/src/dom/remove.js +5 -8
  31. package/src/dom/resizeobserver.js +109 -342
  32. package/src/dom/scroll.js +151 -183
  33. package/src/dom/setdatainelement.js +5 -9
  34. package/src/dom/tounit.js +10 -12
  35. package/src/elementreplacer.js +30 -44
  36. package/src/emittermixin.js +368 -634
  37. package/src/env.js +109 -116
  38. package/src/eventinfo.js +12 -65
  39. package/src/fastdiff.js +96 -128
  40. package/src/first.js +8 -12
  41. package/src/focustracker.js +77 -133
  42. package/src/index.js +0 -9
  43. package/src/inserttopriorityarray.js +9 -30
  44. package/src/isiterable.js +2 -4
  45. package/src/keyboard.js +117 -196
  46. package/src/keystrokehandler.js +72 -88
  47. package/src/language.js +9 -15
  48. package/src/locale.js +61 -158
  49. package/src/mapsequal.js +12 -17
  50. package/src/mix.js +17 -16
  51. package/src/nth.js +8 -11
  52. package/src/objecttomap.js +7 -11
  53. package/src/observablemixin.js +474 -778
  54. package/src/priorities.js +20 -32
  55. package/src/spy.js +3 -6
  56. package/src/toarray.js +2 -13
  57. package/src/tomap.js +8 -10
  58. package/src/translation-service.js +57 -93
  59. package/src/uid.js +34 -38
  60. package/src/unicode.js +28 -43
  61. package/src/version.js +134 -143
package/src/keyboard.js CHANGED
@@ -2,29 +2,19 @@
2
2
  * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
- /**
7
- * A set of utilities related to keyboard support.
8
- *
9
- * @module utils/keyboard
10
- */
11
-
12
5
  import CKEditorError from './ckeditorerror';
13
6
  import env from './env';
14
-
15
7
  const modifiersToGlyphsMac = {
16
- ctrl: '⌃',
17
- cmd: '⌘',
18
- alt: '⌥',
19
- shift: '⇧'
8
+ ctrl: '⌃',
9
+ cmd: '⌘',
10
+ alt: '⌥',
11
+ shift: '⇧'
20
12
  };
21
-
22
13
  const modifiersToGlyphsNonMac = {
23
- ctrl: 'Ctrl+',
24
- alt: 'Alt+',
25
- shift: 'Shift+'
14
+ ctrl: 'Ctrl+',
15
+ alt: 'Alt+',
16
+ shift: 'Shift+'
26
17
  };
27
-
28
18
  /**
29
19
  * An object with `keyName => keyCode` pairs for a set of known keys.
30
20
  *
@@ -39,11 +29,7 @@ const modifiersToGlyphsNonMac = {
39
29
  * * `ctrl`, `cmd`, `shift`, `alt`.
40
30
  */
41
31
  export const keyCodes = generateKnownKeyCodes();
42
-
43
- const keyCodeNames = Object.fromEntries(
44
- Object.entries( keyCodes ).map( ( [ name, code ] ) => [ code, name.charAt( 0 ).toUpperCase() + name.slice( 1 ) ] )
45
- );
46
-
32
+ const keyCodeNames = Object.fromEntries(Object.entries(keyCodes).map(([name, code]) => [code, name.charAt(0).toUpperCase() + name.slice(1)]));
47
33
  /**
48
34
  * Converts a key name or {@link module:utils/keyboard~KeystrokeInfo keystroke info} into a key code.
49
35
  *
@@ -53,32 +39,29 @@ const keyCodeNames = Object.fromEntries(
53
39
  * or a keystroke data object.
54
40
  * @returns {Number} Key or keystroke code.
55
41
  */
56
- export function getCode( key ) {
57
- let keyCode;
58
-
59
- if ( typeof key == 'string' ) {
60
- keyCode = keyCodes[ key.toLowerCase() ];
61
-
62
- if ( !keyCode ) {
63
- /**
64
- * Unknown key name. Only key names included in the {@link module:utils/keyboard~keyCodes} can be used.
65
- *
66
- * @error keyboard-unknown-key
67
- * @param {String} key
68
- */
69
- throw new CKEditorError( 'keyboard-unknown-key', null, { key } );
70
- }
71
- } else {
72
- keyCode = key.keyCode +
73
- ( key.altKey ? keyCodes.alt : 0 ) +
74
- ( key.ctrlKey ? keyCodes.ctrl : 0 ) +
75
- ( key.shiftKey ? keyCodes.shift : 0 ) +
76
- ( key.metaKey ? keyCodes.cmd : 0 );
77
- }
78
-
79
- return keyCode;
42
+ export function getCode(key) {
43
+ let keyCode;
44
+ if (typeof key == 'string') {
45
+ keyCode = keyCodes[key.toLowerCase()];
46
+ if (!keyCode) {
47
+ /**
48
+ * Unknown key name. Only key names included in the {@link module:utils/keyboard~keyCodes} can be used.
49
+ *
50
+ * @error keyboard-unknown-key
51
+ * @param {String} key
52
+ */
53
+ throw new CKEditorError('keyboard-unknown-key', null, { key });
54
+ }
55
+ }
56
+ else {
57
+ keyCode = key.keyCode +
58
+ (key.altKey ? keyCodes.alt : 0) +
59
+ (key.ctrlKey ? keyCodes.ctrl : 0) +
60
+ (key.shiftKey ? keyCodes.shift : 0) +
61
+ (key.metaKey ? keyCodes.cmd : 0);
62
+ }
63
+ return keyCode;
80
64
  }
81
-
82
65
  /**
83
66
  * Parses the keystroke and returns a keystroke code that will match the code returned by
84
67
  * {@link module:utils/keyboard~getCode} for the corresponding {@link module:utils/keyboard~KeystrokeInfo keystroke info}.
@@ -101,16 +84,14 @@ export function getCode( key ) {
101
84
  * @param {String|Array.<Number|String>} keystroke The keystroke definition.
102
85
  * @returns {Number} Keystroke code.
103
86
  */
104
- export function parseKeystroke( keystroke ) {
105
- if ( typeof keystroke == 'string' ) {
106
- keystroke = splitKeystrokeText( keystroke );
107
- }
108
-
109
- return keystroke
110
- .map( key => ( typeof key == 'string' ) ? getEnvKeyCode( key ) : key )
111
- .reduce( ( key, sum ) => sum + key, 0 );
87
+ export function parseKeystroke(keystroke) {
88
+ if (typeof keystroke == 'string') {
89
+ keystroke = splitKeystrokeText(keystroke);
90
+ }
91
+ return keystroke
92
+ .map(key => (typeof key == 'string') ? getEnvKeyCode(key) : key)
93
+ .reduce((key, sum) => sum + key, 0);
112
94
  }
113
-
114
95
  /**
115
96
  * Translates any keystroke string text like `"Ctrl+A"` to an
116
97
  * environment–specific keystroke, i.e. `"⌘A"` on macOS.
@@ -118,37 +99,31 @@ export function parseKeystroke( keystroke ) {
118
99
  * @param {String} keystroke The keystroke text.
119
100
  * @returns {String} The keystroke text specific for the environment.
120
101
  */
121
- export function getEnvKeystrokeText( keystroke ) {
122
- let keystrokeCode = parseKeystroke( keystroke );
123
-
124
- const modifiersToGlyphs = Object.entries( env.isMac ? modifiersToGlyphsMac : modifiersToGlyphsNonMac );
125
-
126
- const modifiers = modifiersToGlyphs.reduce( ( modifiers, [ name, glyph ] ) => {
127
- // Modifier keys are stored as a bit mask so extract those from the keystroke code.
128
- if ( ( keystrokeCode & keyCodes[ name ] ) != 0 ) {
129
- keystrokeCode &= ~keyCodes[ name ];
130
- modifiers += glyph;
131
- }
132
-
133
- return modifiers;
134
- }, '' );
135
-
136
- return modifiers + ( keystrokeCode ? keyCodeNames[ keystrokeCode ] : '' );
102
+ export function getEnvKeystrokeText(keystroke) {
103
+ let keystrokeCode = parseKeystroke(keystroke);
104
+ const modifiersToGlyphs = Object.entries(env.isMac ? modifiersToGlyphsMac : modifiersToGlyphsNonMac);
105
+ const modifiers = modifiersToGlyphs.reduce((modifiers, [name, glyph]) => {
106
+ // Modifier keys are stored as a bit mask so extract those from the keystroke code.
107
+ if ((keystrokeCode & keyCodes[name]) != 0) {
108
+ keystrokeCode &= ~keyCodes[name];
109
+ modifiers += glyph;
110
+ }
111
+ return modifiers;
112
+ }, '');
113
+ return modifiers + (keystrokeCode ? keyCodeNames[keystrokeCode] : '');
137
114
  }
138
-
139
115
  /**
140
116
  * Returns `true` if the provided key code represents one of the arrow keys.
141
117
  *
142
118
  * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.
143
119
  * @returns {Boolean}
144
120
  */
145
- export function isArrowKeyCode( keyCode ) {
146
- return keyCode == keyCodes.arrowright ||
147
- keyCode == keyCodes.arrowleft ||
148
- keyCode == keyCodes.arrowup ||
149
- keyCode == keyCodes.arrowdown;
121
+ export function isArrowKeyCode(keyCode) {
122
+ return keyCode == keyCodes.arrowright ||
123
+ keyCode == keyCodes.arrowleft ||
124
+ keyCode == keyCodes.arrowup ||
125
+ keyCode == keyCodes.arrowdown;
150
126
  }
151
-
152
127
  /**
153
128
  * Returns the direction in which the {@link module:engine/model/documentselection~DocumentSelection selection}
154
129
  * will move when the provided arrow key code is pressed considering the language direction of the editor content.
@@ -157,45 +132,37 @@ export function isArrowKeyCode( keyCode ) {
157
132
  * in the model structure. Similarly, pressing the right arrow moves the selection left (backward).
158
133
  *
159
134
  * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.
160
- * @param {'ltr'|'rtl'} contentLanguageDirection The content language direction, corresponding to
135
+ * @param {module:utils/language~LanguageDirection} contentLanguageDirection The content language direction, corresponding to
161
136
  * {@link module:utils/locale~Locale#contentLanguageDirection}.
162
- * @returns {'left'|'up'|'right'|'down'} Localized arrow direction.
137
+ * @returns {module:utils/keyboard~ArrowKeyCodeDirection|undefined} Localized arrow direction or `undefined` for non-arrow key codes.
163
138
  */
164
- export function getLocalizedArrowKeyCodeDirection( keyCode, contentLanguageDirection ) {
165
- const isLtrContent = contentLanguageDirection === 'ltr';
166
-
167
- switch ( keyCode ) {
168
- case keyCodes.arrowleft:
169
- return isLtrContent ? 'left' : 'right';
170
-
171
- case keyCodes.arrowright:
172
- return isLtrContent ? 'right' : 'left';
173
-
174
- case keyCodes.arrowup:
175
- return 'up';
176
-
177
- case keyCodes.arrowdown:
178
- return 'down';
179
- }
139
+ export function getLocalizedArrowKeyCodeDirection(keyCode, contentLanguageDirection) {
140
+ const isLtrContent = contentLanguageDirection === 'ltr';
141
+ switch (keyCode) {
142
+ case keyCodes.arrowleft:
143
+ return isLtrContent ? 'left' : 'right';
144
+ case keyCodes.arrowright:
145
+ return isLtrContent ? 'right' : 'left';
146
+ case keyCodes.arrowup:
147
+ return 'up';
148
+ case keyCodes.arrowdown:
149
+ return 'down';
150
+ }
180
151
  }
181
-
182
152
  // Converts a key name to the key code with mapping based on the env.
183
153
  //
184
154
  // See: {@link module:utils/keyboard~getCode}.
185
155
  //
186
156
  // @param {String} key The key name (see {@link module:utils/keyboard~keyCodes}).
187
157
  // @returns {Number} Key code.
188
- function getEnvKeyCode( key ) {
189
- // Don't remap modifier key for forced modifiers.
190
- if ( key.endsWith( '!' ) ) {
191
- return getCode( key.slice( 0, -1 ) );
192
- }
193
-
194
- const code = getCode( key );
195
-
196
- return env.isMac && code == keyCodes.ctrl ? keyCodes.cmd : code;
158
+ function getEnvKeyCode(key) {
159
+ // Don't remap modifier key for forced modifiers.
160
+ if (key.endsWith('!')) {
161
+ return getCode(key.slice(0, -1));
162
+ }
163
+ const code = getCode(key);
164
+ return env.isMac && code == keyCodes.ctrl ? keyCodes.cmd : code;
197
165
  }
198
-
199
166
  /**
200
167
  * Determines if the provided key code moves the {@link module:engine/model/documentselection~DocumentSelection selection}
201
168
  * forward or backward considering the language direction of the editor content.
@@ -204,98 +171,52 @@ function getEnvKeyCode( key ) {
204
171
  * in the model structure. Similarly, pressing the right arrow moves the selection backward.
205
172
  *
206
173
  * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.
207
- * @param {'ltr'|'rtl'} contentLanguageDirection The content language direction, corresponding to
174
+ * @param {module:utils/language~LanguageDirection} contentLanguageDirection The content language direction, corresponding to
208
175
  * {@link module:utils/locale~Locale#contentLanguageDirection}.
209
176
  * @returns {Boolean}
210
177
  */
211
- export function isForwardArrowKeyCode( keyCode, contentLanguageDirection ) {
212
- const localizedKeyCodeDirection = getLocalizedArrowKeyCodeDirection( keyCode, contentLanguageDirection );
213
-
214
- return localizedKeyCodeDirection === 'down' || localizedKeyCodeDirection === 'right';
178
+ export function isForwardArrowKeyCode(keyCode, contentLanguageDirection) {
179
+ const localizedKeyCodeDirection = getLocalizedArrowKeyCodeDirection(keyCode, contentLanguageDirection);
180
+ return localizedKeyCodeDirection === 'down' || localizedKeyCodeDirection === 'right';
215
181
  }
216
-
217
182
  function generateKnownKeyCodes() {
218
- const keyCodes = {
219
- arrowleft: 37,
220
- arrowup: 38,
221
- arrowright: 39,
222
- arrowdown: 40,
223
- backspace: 8,
224
- delete: 46,
225
- enter: 13,
226
- space: 32,
227
- esc: 27,
228
- tab: 9,
229
-
230
- // The idea about these numbers is that they do not collide with any real key codes, so we can use them
231
- // like bit masks.
232
- ctrl: 0x110000,
233
- shift: 0x220000,
234
- alt: 0x440000,
235
- cmd: 0x880000
236
- };
237
-
238
- // a-z
239
- for ( let code = 65; code <= 90; code++ ) {
240
- const letter = String.fromCharCode( code );
241
-
242
- keyCodes[ letter.toLowerCase() ] = code;
243
- }
244
-
245
- // 0-9
246
- for ( let code = 48; code <= 57; code++ ) {
247
- keyCodes[ code - 48 ] = code;
248
- }
249
-
250
- // F1-F12
251
- for ( let code = 112; code <= 123; code++ ) {
252
- keyCodes[ 'f' + ( code - 111 ) ] = code;
253
- }
254
-
255
- // other characters
256
- for ( const char of '`-=[];\',./\\' ) {
257
- keyCodes[ char ] = char.charCodeAt( 0 );
258
- }
259
-
260
- return keyCodes;
183
+ const keyCodes = {
184
+ arrowleft: 37,
185
+ arrowup: 38,
186
+ arrowright: 39,
187
+ arrowdown: 40,
188
+ backspace: 8,
189
+ delete: 46,
190
+ enter: 13,
191
+ space: 32,
192
+ esc: 27,
193
+ tab: 9,
194
+ // The idea about these numbers is that they do not collide with any real key codes, so we can use them
195
+ // like bit masks.
196
+ ctrl: 0x110000,
197
+ shift: 0x220000,
198
+ alt: 0x440000,
199
+ cmd: 0x880000
200
+ };
201
+ // a-z
202
+ for (let code = 65; code <= 90; code++) {
203
+ const letter = String.fromCharCode(code);
204
+ keyCodes[letter.toLowerCase()] = code;
205
+ }
206
+ // 0-9
207
+ for (let code = 48; code <= 57; code++) {
208
+ keyCodes[code - 48] = code;
209
+ }
210
+ // F1-F12
211
+ for (let code = 112; code <= 123; code++) {
212
+ keyCodes['f' + (code - 111)] = code;
213
+ }
214
+ // other characters
215
+ for (const char of '`-=[];\',./\\') {
216
+ keyCodes[char] = char.charCodeAt(0);
217
+ }
218
+ return keyCodes;
261
219
  }
262
-
263
- function splitKeystrokeText( keystroke ) {
264
- return keystroke.split( '+' ).map( key => key.trim() );
220
+ function splitKeystrokeText(keystroke) {
221
+ return keystroke.split('+').map(key => key.trim());
265
222
  }
266
-
267
- /**
268
- * Information about the keystroke.
269
- *
270
- * @interface module:utils/keyboard~KeystrokeInfo
271
- */
272
-
273
- /**
274
- * The [key code](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode).
275
- *
276
- * @member {Number} module:utils/keyboard~KeystrokeInfo#keyCode
277
- */
278
-
279
- /**
280
- * Whether the <kbd>Alt</kbd> modifier was pressed.
281
- *
282
- * @member {Boolean} module:utils/keyboard~KeystrokeInfo#altKey
283
- */
284
-
285
- /**
286
- * Whether the <kbd>Ctrl</kbd> modifier was pressed.
287
- *
288
- * @member {Boolean} module:utils/keyboard~KeystrokeInfo#ctrlKey
289
- */
290
-
291
- /**
292
- * Whether the <kbd>Shift</kbd> modifier was pressed.
293
- *
294
- * @member {Boolean} module:utils/keyboard~KeystrokeInfo#shiftKey
295
- */
296
-
297
- /**
298
- * Whether the <kbd>Cmd</kbd> modifier was pressed.
299
- *
300
- * @member {Boolean} module:utils/keyboard~KeystrokeInfo#metaKey
301
- */
@@ -2,14 +2,11 @@
2
2
  * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module utils/keystrokehandler
8
7
  */
9
-
10
8
  import DomEmitterMixin from './dom/emittermixin';
11
9
  import { getCode, parseKeystroke } from './keyboard';
12
-
13
10
  /**
14
11
  * Keystroke handler allows registering callbacks for given keystrokes.
15
12
  *
@@ -42,89 +39,76 @@ import { getCode, parseKeystroke } from './keyboard';
42
39
  *
43
40
  */
44
41
  export default class KeystrokeHandler {
45
- /**
46
- * Creates an instance of the keystroke handler.
47
- */
48
- constructor() {
49
- /**
50
- * Listener used to listen to events for easier keystroke handler destruction.
51
- *
52
- * @protected
53
- * @member {module:utils/dom/emittermixin~Emitter}
54
- */
55
- this._listener = Object.create( DomEmitterMixin );
56
- }
57
-
58
- /**
59
- * Starts listening for `keydown` events from a given emitter.
60
- *
61
- * @param {module:utils/emittermixin~Emitter} emitter
62
- */
63
- listenTo( emitter ) {
64
- // The #_listener works here as a kind of dispatcher. It groups the events coming from the same
65
- // keystroke so the listeners can be attached to them with different priorities.
66
- //
67
- // E.g. all the keystrokes with the `keyCode` of 42 coming from the `emitter` are propagated
68
- // as a `_keydown:42` event by the `_listener`. If there's a callback created by the `set`
69
- // method for this 42 keystroke, it listens to the `_listener#_keydown:42` event only and interacts
70
- // only with other listeners of this particular event, thus making it possible to prioritize
71
- // the listeners and safely cancel execution, when needed. Instead of duplicating the Emitter logic,
72
- // the KeystrokeHandler re–uses it to do its job.
73
- this._listener.listenTo( emitter, 'keydown', ( evt, keyEvtData ) => {
74
- this._listener.fire( '_keydown:' + getCode( keyEvtData ), keyEvtData );
75
- } );
76
- }
77
-
78
- /**
79
- * Registers a handler for the specified keystroke.
80
- *
81
- * @param {String|Array.<String|Number>} keystroke Keystroke defined in a format accepted by
82
- * the {@link module:utils/keyboard~parseKeystroke} function.
83
- * @param {Function} callback A function called with the
84
- * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and
85
- * a helper funcion to call both `preventDefault()` and `stopPropagation()` on the underlying event.
86
- * @param {Object} [options={}] Additional options.
87
- * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of the keystroke
88
- * callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority
89
- * are called in the order they were added.
90
- */
91
- set( keystroke, callback, options = {} ) {
92
- const keyCode = parseKeystroke( keystroke );
93
- const priority = options.priority;
94
-
95
- // Execute the passed callback on KeystrokeHandler#_keydown.
96
- // TODO: https://github.com/ckeditor/ckeditor5-utils/issues/144
97
- this._listener.listenTo( this._listener, '_keydown:' + keyCode, ( evt, keyEvtData ) => {
98
- callback( keyEvtData, () => {
99
- // Stop the event in the DOM: no listener in the web page
100
- // will be triggered by this event.
101
- keyEvtData.preventDefault();
102
- keyEvtData.stopPropagation();
103
-
104
- // Stop the event in the KeystrokeHandler: no more callbacks
105
- // will be executed for this keystroke.
106
- evt.stop();
107
- } );
108
-
109
- // Mark this keystroke as handled by the callback. See: #press.
110
- evt.return = true;
111
- }, { priority } );
112
- }
113
-
114
- /**
115
- * Triggers a keystroke handler for a specified key combination, if such a keystroke was {@link #set defined}.
116
- *
117
- * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEvtData Key event data.
118
- * @returns {Boolean} Whether the keystroke was handled.
119
- */
120
- press( keyEvtData ) {
121
- return !!this._listener.fire( '_keydown:' + getCode( keyEvtData ), keyEvtData );
122
- }
123
-
124
- /**
125
- * Destroys the keystroke handler.
126
- */
127
- destroy() {
128
- this._listener.stopListening();
129
- }
42
+ /**
43
+ * Creates an instance of the keystroke handler.
44
+ */
45
+ constructor() {
46
+ this._listener = Object.create(DomEmitterMixin);
47
+ }
48
+ /**
49
+ * Starts listening for `keydown` events from a given emitter.
50
+ *
51
+ * @param {module:utils/emittermixin~Emitter|HTMLElement|Window} emitter
52
+ */
53
+ listenTo(emitter) {
54
+ // The #_listener works here as a kind of dispatcher. It groups the events coming from the same
55
+ // keystroke so the listeners can be attached to them with different priorities.
56
+ //
57
+ // E.g. all the keystrokes with the `keyCode` of 42 coming from the `emitter` are propagated
58
+ // as a `_keydown:42` event by the `_listener`. If there's a callback created by the `set`
59
+ // method for this 42 keystroke, it listens to the `_listener#_keydown:42` event only and interacts
60
+ // only with other listeners of this particular event, thus making it possible to prioritize
61
+ // the listeners and safely cancel execution, when needed. Instead of duplicating the Emitter logic,
62
+ // the KeystrokeHandler re–uses it to do its job.
63
+ this._listener.listenTo(emitter, 'keydown', (evt, keyEvtData) => {
64
+ this._listener.fire('_keydown:' + getCode(keyEvtData), keyEvtData);
65
+ });
66
+ }
67
+ /**
68
+ * Registers a handler for the specified keystroke.
69
+ *
70
+ * @param {String|Array.<String|Number>} keystroke Keystroke defined in a format accepted by
71
+ * the {@link module:utils/keyboard~parseKeystroke} function.
72
+ * @param {Function} callback A function called with the
73
+ * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and
74
+ * a helper funcion to call both `preventDefault()` and `stopPropagation()` on the underlying event.
75
+ * @param {Object} [options={}] Additional options.
76
+ * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of the keystroke
77
+ * callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority
78
+ * are called in the order they were added.
79
+ */
80
+ set(keystroke, callback, options = {}) {
81
+ const keyCode = parseKeystroke(keystroke);
82
+ const priority = options.priority;
83
+ // Execute the passed callback on KeystrokeHandler#_keydown.
84
+ // TODO: https://github.com/ckeditor/ckeditor5-utils/issues/144
85
+ this._listener.listenTo(this._listener, '_keydown:' + keyCode, (evt, keyEvtData) => {
86
+ callback(keyEvtData, () => {
87
+ // Stop the event in the DOM: no listener in the web page
88
+ // will be triggered by this event.
89
+ keyEvtData.preventDefault();
90
+ keyEvtData.stopPropagation();
91
+ // Stop the event in the KeystrokeHandler: no more callbacks
92
+ // will be executed for this keystroke.
93
+ evt.stop();
94
+ });
95
+ // Mark this keystroke as handled by the callback. See: #press.
96
+ evt.return = true;
97
+ }, { priority });
98
+ }
99
+ /**
100
+ * Triggers a keystroke handler for a specified key combination, if such a keystroke was {@link #set defined}.
101
+ *
102
+ * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEvtData Key event data.
103
+ * @returns {Boolean} Whether the keystroke was handled.
104
+ */
105
+ press(keyEvtData) {
106
+ return !!this._listener.fire('_keydown:' + getCode(keyEvtData), keyEvtData);
107
+ }
108
+ /**
109
+ * Destroys the keystroke handler.
110
+ */
111
+ destroy() {
112
+ this._listener.stopListening();
113
+ }
130
114
  }
package/src/language.js CHANGED
@@ -2,25 +2,19 @@
2
2
  * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
- /**
7
- * @module utils/language
8
- */
9
-
10
5
  const RTL_LANGUAGE_CODES = [
11
- 'ar', 'ara', // Arabic
12
- 'fa', 'per', 'fas', // Persian
13
- 'he', 'heb', // Hebrew
14
- 'ku', 'kur', // Kurdish
15
- 'ug', 'uig' // Uighur, Uyghur
6
+ 'ar', 'ara',
7
+ 'fa', 'per', 'fas',
8
+ 'he', 'heb',
9
+ 'ku', 'kur',
10
+ 'ug', 'uig' // Uighur, Uyghur
16
11
  ];
17
-
18
12
  /**
19
13
  * Helps determine whether a language text direction is LTR or RTL.
20
14
  *
21
- * @param {String} language The ISO 639-1 or ISO 639-2 language code.
22
- * @returns {'ltr'|'rtl'}
15
+ * @param {String} languageCode The ISO 639-1 or ISO 639-2 language code.
16
+ * @returns {module:utils/language~LanguageDirection}
23
17
  */
24
- export function getLanguageDirection( languageCode ) {
25
- return RTL_LANGUAGE_CODES.includes( languageCode ) ? 'rtl' : 'ltr';
18
+ export function getLanguageDirection(languageCode) {
19
+ return RTL_LANGUAGE_CODES.includes(languageCode) ? 'rtl' : 'ltr';
26
20
  }