@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.
- package/CHANGELOG.md +324 -0
- package/LICENSE.md +1 -1
- package/package.json +19 -8
- package/src/areconnectedthroughproperties.js +0 -92
- package/src/ckeditorerror.js +0 -217
- package/src/collection.js +0 -785
- package/src/comparearrays.js +0 -51
- package/src/config.js +0 -246
- package/src/count.js +0 -26
- package/src/diff.js +0 -138
- package/src/difftochanges.js +0 -86
- package/src/dom/createelement.js +0 -49
- package/src/dom/emittermixin.js +0 -341
- package/src/dom/getancestors.js +0 -31
- package/src/dom/getborderwidths.js +0 -27
- package/src/dom/getcommonancestor.js +0 -31
- package/src/dom/getdatafromelement.js +0 -24
- package/src/dom/getpositionedancestor.js +0 -28
- package/src/dom/global.js +0 -26
- package/src/dom/indexof.js +0 -25
- package/src/dom/insertat.js +0 -19
- package/src/dom/iscomment.js +0 -20
- package/src/dom/isnode.js +0 -26
- package/src/dom/isrange.js +0 -18
- package/src/dom/istext.js +0 -18
- package/src/dom/isvisible.js +0 -25
- package/src/dom/iswindow.js +0 -30
- package/src/dom/position.js +0 -518
- package/src/dom/rect.js +0 -443
- package/src/dom/remove.js +0 -21
- package/src/dom/resizeobserver.js +0 -378
- package/src/dom/scroll.js +0 -302
- package/src/dom/setdatainelement.js +0 -24
- package/src/dom/tounit.js +0 -27
- package/src/elementreplacer.js +0 -57
- package/src/emittermixin.js +0 -719
- package/src/env.js +0 -190
- package/src/eventinfo.js +0 -79
- package/src/fastdiff.js +0 -261
- package/src/first.js +0 -24
- package/src/focustracker.js +0 -157
- package/src/index.js +0 -45
- package/src/inserttopriorityarray.js +0 -42
- package/src/isiterable.js +0 -18
- package/src/keyboard.js +0 -301
- package/src/keystrokehandler.js +0 -130
- package/src/language.js +0 -26
- package/src/locale.js +0 -176
- package/src/mapsequal.js +0 -32
- package/src/mix.js +0 -47
- package/src/nth.js +0 -31
- package/src/objecttomap.js +0 -29
- package/src/observablemixin.js +0 -908
- package/src/priorities.js +0 -44
- package/src/spy.js +0 -25
- package/src/toarray.js +0 -18
- package/src/tomap.js +0 -29
- package/src/translation-service.js +0 -216
- package/src/uid.js +0 -59
- package/src/unicode.js +0 -106
- package/src/version.js +0 -157
package/src/focustracker.js
DELETED
|
@@ -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
|
-
*/
|
package/src/keystrokehandler.js
DELETED
|
@@ -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
|
-
}
|