@ckeditor/ckeditor5-utils 34.2.0 → 35.0.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 +0 -92
  5. package/src/ckeditorerror.js +0 -217
  6. package/src/collection.js +0 -785
  7. package/src/comparearrays.js +0 -51
  8. package/src/config.js +0 -246
  9. package/src/count.js +0 -26
  10. package/src/diff.js +0 -138
  11. package/src/difftochanges.js +0 -86
  12. package/src/dom/createelement.js +0 -49
  13. package/src/dom/emittermixin.js +0 -341
  14. package/src/dom/getancestors.js +0 -31
  15. package/src/dom/getborderwidths.js +0 -27
  16. package/src/dom/getcommonancestor.js +0 -31
  17. package/src/dom/getdatafromelement.js +0 -24
  18. package/src/dom/getpositionedancestor.js +0 -28
  19. package/src/dom/global.js +0 -26
  20. package/src/dom/indexof.js +0 -25
  21. package/src/dom/insertat.js +0 -19
  22. package/src/dom/iscomment.js +0 -20
  23. package/src/dom/isnode.js +0 -26
  24. package/src/dom/isrange.js +0 -18
  25. package/src/dom/istext.js +0 -18
  26. package/src/dom/isvisible.js +0 -25
  27. package/src/dom/iswindow.js +0 -30
  28. package/src/dom/position.js +0 -518
  29. package/src/dom/rect.js +0 -443
  30. package/src/dom/remove.js +0 -21
  31. package/src/dom/resizeobserver.js +0 -378
  32. package/src/dom/scroll.js +0 -302
  33. package/src/dom/setdatainelement.js +0 -24
  34. package/src/dom/tounit.js +0 -27
  35. package/src/elementreplacer.js +0 -57
  36. package/src/emittermixin.js +0 -719
  37. package/src/env.js +0 -190
  38. package/src/eventinfo.js +0 -79
  39. package/src/fastdiff.js +0 -261
  40. package/src/first.js +0 -24
  41. package/src/focustracker.js +0 -157
  42. package/src/index.js +0 -45
  43. package/src/inserttopriorityarray.js +0 -42
  44. package/src/isiterable.js +0 -18
  45. package/src/keyboard.js +0 -301
  46. package/src/keystrokehandler.js +0 -130
  47. package/src/language.js +0 -26
  48. package/src/locale.js +0 -176
  49. package/src/mapsequal.js +0 -32
  50. package/src/mix.js +0 -47
  51. package/src/nth.js +0 -31
  52. package/src/objecttomap.js +0 -29
  53. package/src/observablemixin.js +0 -908
  54. package/src/priorities.js +0 -44
  55. package/src/spy.js +0 -25
  56. package/src/toarray.js +0 -18
  57. package/src/tomap.js +0 -29
  58. package/src/translation-service.js +0 -216
  59. package/src/uid.js +0 -59
  60. package/src/unicode.js +0 -106
  61. package/src/version.js +0 -157
@@ -1,157 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
-
6
- /* global setTimeout, clearTimeout */
7
-
8
- /**
9
- * @module utils/focustracker
10
- */
11
-
12
- import DomEmitterMixin from './dom/emittermixin';
13
- import ObservableMixin from './observablemixin';
14
- import CKEditorError from './ckeditorerror';
15
- import mix from './mix';
16
-
17
- /**
18
- * Allows observing a group of `HTMLElement`s whether at least one of them is focused.
19
- *
20
- * Used by the {@link module:core/editor/editor~Editor} in order to track whether the focus is still within the application,
21
- * or were used outside of its UI.
22
- *
23
- * **Note** `focus` and `blur` listeners use event capturing, so it is only needed to register wrapper `HTMLElement`
24
- * which contain other `focusable` elements. But note that this wrapper element has to be focusable too
25
- * (have e.g. `tabindex="-1"`).
26
- *
27
- * Check out the {@glink framework/guides/deep-dive/ui/focus-tracking "Deep dive into focus tracking" guide} to learn more.
28
- *
29
- * @mixes module:utils/dom/emittermixin~EmitterMixin
30
- * @mixes module:utils/observablemixin~ObservableMixin
31
- */
32
- export default class FocusTracker {
33
- constructor() {
34
- /**
35
- * True when one of the registered elements is focused.
36
- *
37
- * @readonly
38
- * @observable
39
- * @member {Boolean} #isFocused
40
- */
41
- this.set( 'isFocused', false );
42
-
43
- /**
44
- * The currently focused element.
45
- *
46
- * While {@link #isFocused `isFocused`} remains `true`, the focus can
47
- * move between different UI elements. This property tracks those
48
- * elements and tells which one is currently focused.
49
- *
50
- * @readonly
51
- * @observable
52
- * @member {HTMLElement|null} #focusedElement
53
- */
54
- this.set( 'focusedElement', null );
55
-
56
- /**
57
- * List of registered elements.
58
- *
59
- * @private
60
- * @member {Set.<HTMLElement>}
61
- */
62
- this._elements = new Set();
63
-
64
- /**
65
- * Event loop timeout.
66
- *
67
- * @private
68
- * @member {Number}
69
- */
70
- this._nextEventLoopTimeout = null;
71
- }
72
-
73
- /**
74
- * Starts tracking the specified element.
75
- *
76
- * @param {HTMLElement} element
77
- */
78
- add( element ) {
79
- if ( this._elements.has( element ) ) {
80
- /**
81
- * This element is already tracked by {@link module:utils/focustracker~FocusTracker}.
82
- *
83
- * @error focustracker-add-element-already-exist
84
- */
85
- throw new CKEditorError( 'focustracker-add-element-already-exist', this );
86
- }
87
-
88
- this.listenTo( element, 'focus', () => this._focus( element ), { useCapture: true } );
89
- this.listenTo( element, 'blur', () => this._blur(), { useCapture: true } );
90
- this._elements.add( element );
91
- }
92
-
93
- /**
94
- * Stops tracking the specified element and stops listening on this element.
95
- *
96
- * @param {HTMLElement} element
97
- */
98
- remove( element ) {
99
- if ( element === this.focusedElement ) {
100
- this._blur( element );
101
- }
102
-
103
- if ( this._elements.has( element ) ) {
104
- this.stopListening( element );
105
- this._elements.delete( element );
106
- }
107
- }
108
-
109
- /**
110
- * Destroys the focus tracker by:
111
- * - Disabling all event listeners attached to tracked elements.
112
- * - Removing all tracked elements that were previously added.
113
- */
114
- destroy() {
115
- this.stopListening();
116
- }
117
-
118
- /**
119
- * Stores currently focused element and set {#isFocused} as `true`.
120
- *
121
- * @private
122
- * @param {HTMLElement} element Element which has been focused.
123
- */
124
- _focus( element ) {
125
- clearTimeout( this._nextEventLoopTimeout );
126
-
127
- this.focusedElement = element;
128
- this.isFocused = true;
129
- }
130
-
131
- /**
132
- * Clears currently focused element and set {@link #isFocused} as `false`.
133
- * This method uses `setTimeout` to change order of fires `blur` and `focus` events.
134
- *
135
- * @private
136
- * @fires blur
137
- */
138
- _blur() {
139
- clearTimeout( this._nextEventLoopTimeout );
140
-
141
- this._nextEventLoopTimeout = setTimeout( () => {
142
- this.focusedElement = null;
143
- this.isFocused = false;
144
- }, 0 );
145
- }
146
-
147
- /**
148
- * @event focus
149
- */
150
-
151
- /**
152
- * @event blur
153
- */
154
- }
155
-
156
- mix( FocusTracker, DomEmitterMixin );
157
- mix( FocusTracker, ObservableMixin );
package/src/index.js DELETED
@@ -1,45 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
-
6
- /**
7
- * @module utils
8
- */
9
-
10
- export { default as env } from './env';
11
- export { default as diff } from './diff';
12
-
13
- export { default as mix } from './mix';
14
- export { default as EmitterMixin } from './emittermixin';
15
- export { default as ObservableMixin } from './observablemixin';
16
-
17
- export { default as CKEditorError, logError, logWarning } from './ckeditorerror';
18
-
19
- export { default as ElementReplacer } from './elementreplacer';
20
-
21
- export { default as createElement } from './dom/createelement';
22
- export { default as DomEmitterMixin } from './dom/emittermixin';
23
- export { default as global } from './dom/global';
24
- export { default as getDataFromElement } from './dom/getdatafromelement';
25
- export { default as Rect } from './dom/rect';
26
- export { default as ResizeObserver } from './dom/resizeobserver';
27
- export { default as setDataInElement } from './dom/setdatainelement';
28
- export { default as toUnit } from './dom/tounit';
29
- export { default as isVisible } from './dom/isvisible';
30
- export * from './dom/scroll';
31
-
32
- export * from './keyboard';
33
- export * from './language';
34
- export { default as Locale } from './locale';
35
- export { default as Collection } from './collection';
36
- export { default as first } from './first';
37
- export { default as FocusTracker } from './focustracker';
38
- export { default as KeystrokeHandler } from './keystrokehandler';
39
- export { default as toArray } from './toarray';
40
- export { default as toMap } from './tomap';
41
- export { default as priorities } from './priorities';
42
-
43
- export { default as uid } from './uid';
44
-
45
- export { default as version } from './version';
@@ -1,42 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
-
6
- import priorities from './priorities';
7
-
8
- /**
9
- * @module utils/inserttopriorityarray
10
- */
11
-
12
- /**
13
- * The priority object descriptor.
14
- *
15
- * const objectWithPriority = {
16
- * priority: 'high'
17
- * }
18
- *
19
- * @typedef {Object} module:utils/inserttopriorityarray~ObjectWithPriority
20
- *
21
- * @property {module:utils/priorities~PriorityString|Number} priority Priority of the object.
22
- */
23
-
24
- /**
25
- * Inserts any object with priority at correct index by priority so registered objects are always sorted from highest to lowest priority.
26
- *
27
- * @param {Array.<module:utils/inserttopriorityarray~ObjectWithPriority>} objects Array of objects with priority to insert object to.
28
- * @param {module:utils/inserttopriorityarray~ObjectWithPriority} objectToInsert Object with `priority` property.
29
- */
30
- export default function insertToPriorityArray( objects, objectToInsert ) {
31
- const priority = priorities.get( objectToInsert.priority );
32
-
33
- for ( let i = 0; i < objects.length; i++ ) {
34
- if ( priorities.get( objects[ i ].priority ) < priority ) {
35
- objects.splice( i, 0, objectToInsert );
36
-
37
- return;
38
- }
39
- }
40
-
41
- objects.push( objectToInsert );
42
- }
package/src/isiterable.js DELETED
@@ -1,18 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
-
6
- /**
7
- * @module utils/isiterable
8
- */
9
-
10
- /**
11
- * Checks if value implements iterator interface.
12
- *
13
- * @param {*} value The value to check.
14
- * @returns {Boolean} True if value implements iterator interface.
15
- */
16
- export default function isIterable( value ) {
17
- return !!( value && value[ Symbol.iterator ] );
18
- }
package/src/keyboard.js DELETED
@@ -1,301 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
-
6
- /**
7
- * A set of utilities related to keyboard support.
8
- *
9
- * @module utils/keyboard
10
- */
11
-
12
- import CKEditorError from './ckeditorerror';
13
- import env from './env';
14
-
15
- const modifiersToGlyphsMac = {
16
- ctrl: '⌃',
17
- cmd: '⌘',
18
- alt: '⌥',
19
- shift: '⇧'
20
- };
21
-
22
- const modifiersToGlyphsNonMac = {
23
- ctrl: 'Ctrl+',
24
- alt: 'Alt+',
25
- shift: 'Shift+'
26
- };
27
-
28
- /**
29
- * An object with `keyName => keyCode` pairs for a set of known keys.
30
- *
31
- * Contains:
32
- *
33
- * * `a-z`,
34
- * * `0-9`,
35
- * * `f1-f12`,
36
- * * `` ` ``, `-`, `=`, `[`, `]`, `;`, `'`, `,`, `.`, `/`, `\`,
37
- * * `arrow(left|up|right|bottom)`,
38
- * * `backspace`, `delete`, `enter`, `esc`, `tab`,
39
- * * `ctrl`, `cmd`, `shift`, `alt`.
40
- */
41
- 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
-
47
- /**
48
- * Converts a key name or {@link module:utils/keyboard~KeystrokeInfo keystroke info} into a key code.
49
- *
50
- * Note: Key names are matched with {@link module:utils/keyboard~keyCodes} in a case-insensitive way.
51
- *
52
- * @param {String|module:utils/keyboard~KeystrokeInfo} A key name (see {@link module:utils/keyboard~keyCodes})
53
- * or a keystroke data object.
54
- * @returns {Number} Key or keystroke code.
55
- */
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;
80
- }
81
-
82
- /**
83
- * Parses the keystroke and returns a keystroke code that will match the code returned by
84
- * {@link module:utils/keyboard~getCode} for the corresponding {@link module:utils/keyboard~KeystrokeInfo keystroke info}.
85
- *
86
- * The keystroke can be passed in two formats:
87
- *
88
- * * as a single string – e.g. `ctrl + A`,
89
- * * as an array of {@link module:utils/keyboard~keyCodes known key names} and key codes – e.g.:
90
- * * `[ 'ctrl', 32 ]` (ctrl + space),
91
- * * `[ 'ctrl', 'a' ]` (ctrl + A).
92
- *
93
- * Note: Key names are matched with {@link module:utils/keyboard~keyCodes} in a case-insensitive way.
94
- *
95
- * Note: Only keystrokes with a single non-modifier key are supported (e.g. `ctrl+A` is OK, but `ctrl+A+B` is not).
96
- *
97
- * Note: On macOS, keystroke handling is translating the `Ctrl` key to the `Cmd` key and handling only that keystroke.
98
- * For example, a registered keystroke `Ctrl+A` will be translated to `Cmd+A` on macOS. To disable the translation of some keystroke,
99
- * use the forced modifier: `Ctrl!+A` (note the exclamation mark).
100
- *
101
- * @param {String|Array.<Number|String>} keystroke The keystroke definition.
102
- * @returns {Number} Keystroke code.
103
- */
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 );
112
- }
113
-
114
- /**
115
- * Translates any keystroke string text like `"Ctrl+A"` to an
116
- * environment–specific keystroke, i.e. `"⌘A"` on macOS.
117
- *
118
- * @param {String} keystroke The keystroke text.
119
- * @returns {String} The keystroke text specific for the environment.
120
- */
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 ] : '' );
137
- }
138
-
139
- /**
140
- * Returns `true` if the provided key code represents one of the arrow keys.
141
- *
142
- * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.
143
- * @returns {Boolean}
144
- */
145
- export function isArrowKeyCode( keyCode ) {
146
- return keyCode == keyCodes.arrowright ||
147
- keyCode == keyCodes.arrowleft ||
148
- keyCode == keyCodes.arrowup ||
149
- keyCode == keyCodes.arrowdown;
150
- }
151
-
152
- /**
153
- * Returns the direction in which the {@link module:engine/model/documentselection~DocumentSelection selection}
154
- * will move when the provided arrow key code is pressed considering the language direction of the editor content.
155
- *
156
- * For instance, in right–to–left (RTL) content languages, pressing the left arrow means moving the selection right (forward)
157
- * in the model structure. Similarly, pressing the right arrow moves the selection left (backward).
158
- *
159
- * @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
161
- * {@link module:utils/locale~Locale#contentLanguageDirection}.
162
- * @returns {'left'|'up'|'right'|'down'} Localized arrow direction.
163
- */
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
- }
180
- }
181
-
182
- // Converts a key name to the key code with mapping based on the env.
183
- //
184
- // See: {@link module:utils/keyboard~getCode}.
185
- //
186
- // @param {String} key The key name (see {@link module:utils/keyboard~keyCodes}).
187
- // @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;
197
- }
198
-
199
- /**
200
- * Determines if the provided key code moves the {@link module:engine/model/documentselection~DocumentSelection selection}
201
- * forward or backward considering the language direction of the editor content.
202
- *
203
- * For instance, in right–to–left (RTL) languages, pressing the left arrow means moving forward
204
- * in the model structure. Similarly, pressing the right arrow moves the selection backward.
205
- *
206
- * @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
208
- * {@link module:utils/locale~Locale#contentLanguageDirection}.
209
- * @returns {Boolean}
210
- */
211
- export function isForwardArrowKeyCode( keyCode, contentLanguageDirection ) {
212
- const localizedKeyCodeDirection = getLocalizedArrowKeyCodeDirection( keyCode, contentLanguageDirection );
213
-
214
- return localizedKeyCodeDirection === 'down' || localizedKeyCodeDirection === 'right';
215
- }
216
-
217
- 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;
261
- }
262
-
263
- function splitKeystrokeText( keystroke ) {
264
- return keystroke.split( '+' ).map( key => key.trim() );
265
- }
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
- */
@@ -1,130 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
-
6
- /**
7
- * @module utils/keystrokehandler
8
- */
9
-
10
- import DomEmitterMixin from './dom/emittermixin';
11
- import { getCode, parseKeystroke } from './keyboard';
12
-
13
- /**
14
- * Keystroke handler allows registering callbacks for given keystrokes.
15
- *
16
- * The most frequent use of this class is through the {@link module:core/editor/editor~Editor#keystrokes `editor.keystrokes`}
17
- * property. It allows listening to keystrokes executed in the editing view:
18
- *
19
- * editor.keystrokes.set( 'Ctrl+A', ( keyEvtData, cancel ) => {
20
- * console.log( 'Ctrl+A has been pressed' );
21
- * cancel();
22
- * } );
23
- *
24
- * However, this utility class can be used in various part of the UI. For instance, a certain {@link module:ui/view~View}
25
- * can use it like this:
26
- *
27
- * class MyView extends View {
28
- * constructor() {
29
- * this.keystrokes = new KeystrokeHandler();
30
- *
31
- * this.keystrokes.set( 'tab', handleTabKey );
32
- * }
33
- *
34
- * render() {
35
- * super.render();
36
- *
37
- * this.keystrokes.listenTo( this.element );
38
- * }
39
- * }
40
- *
41
- * That keystroke handler will listen to `keydown` events fired in this view's main element.
42
- *
43
- */
44
- 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
- }
130
- }