@ckeditor/ckeditor5-utils 35.3.2 → 36.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/LICENSE.md +1 -1
- package/package.json +5 -5
- package/src/areconnectedthroughproperties.js +7 -9
- package/src/ckeditorerror.js +52 -71
- package/src/collection.js +108 -150
- package/src/comparearrays.js +11 -9
- package/src/config.js +30 -84
- package/src/count.js +6 -4
- package/src/diff.js +8 -6
- package/src/difftochanges.js +18 -15
- package/src/dom/createelement.js +12 -10
- package/src/dom/emittermixin.js +44 -85
- package/src/dom/findclosestscrollableancestor.js +30 -0
- package/src/dom/getancestors.js +3 -3
- package/src/dom/getborderwidths.js +3 -3
- package/src/dom/getcommonancestor.js +4 -4
- package/src/dom/getdatafromelement.js +3 -3
- package/src/dom/getpositionedancestor.js +2 -3
- package/src/dom/global.js +13 -15
- package/src/dom/indexof.js +3 -3
- package/src/dom/insertat.js +4 -4
- package/src/dom/iscomment.js +1 -4
- package/src/dom/isnode.js +1 -4
- package/src/dom/isrange.js +1 -4
- package/src/dom/istext.js +1 -4
- package/src/dom/isvisible.js +1 -4
- package/src/dom/iswindow.js +1 -4
- package/src/dom/position.js +111 -134
- package/src/dom/rect.js +43 -53
- package/src/dom/remove.js +2 -2
- package/src/dom/resizeobserver.js +11 -36
- package/src/dom/scroll.js +86 -92
- package/src/dom/setdatainelement.js +3 -3
- package/src/dom/tounit.js +2 -11
- package/src/elementreplacer.js +3 -3
- package/src/emittermixin.js +49 -49
- package/src/env.js +15 -76
- package/src/eventinfo.js +3 -3
- package/src/fastdiff.js +116 -97
- package/src/first.js +1 -4
- package/src/focustracker.js +12 -20
- package/src/index.js +19 -1
- package/src/inserttopriorityarray.js +3 -3
- package/src/isiterable.js +3 -3
- package/src/keyboard.js +21 -22
- package/src/keystrokehandler.js +27 -25
- package/src/language.js +2 -3
- package/src/locale.js +12 -15
- package/src/mapsequal.js +5 -5
- package/src/mix.js +16 -14
- package/src/nth.js +1 -5
- package/src/objecttomap.js +7 -5
- package/src/observablemixin.js +127 -151
- package/src/priorities.js +1 -10
- package/src/splicearray.js +13 -12
- package/src/spy.js +2 -2
- package/src/toarray.js +1 -1
- package/src/tomap.js +8 -6
- package/src/translation-service.js +71 -53
- package/src/uid.js +6 -4
- package/src/unicode.js +10 -16
- package/src/version.js +33 -27
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2023, 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
5
|
/**
|
|
@@ -9,13 +9,15 @@ import global from './global';
|
|
|
9
9
|
/**
|
|
10
10
|
* A helper class which instances allow performing custom actions when native DOM elements are resized.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const editableElement = editor.editing.view.getDomRoot();
|
|
13
14
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* const observer = new ResizeObserver( editableElement, entry => {
|
|
16
|
+
* console.log( 'The editable element has been resized in DOM.' );
|
|
17
|
+
* console.log( entry.target ); // -> editableElement
|
|
18
|
+
* console.log( entry.contentRect.width ); // -> e.g. '423px'
|
|
19
|
+
* } );
|
|
20
|
+
* ```
|
|
19
21
|
*
|
|
20
22
|
* It uses the [native DOM resize observer](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)
|
|
21
23
|
* under the hood.
|
|
@@ -24,9 +26,9 @@ export default class ResizeObserver {
|
|
|
24
26
|
/**
|
|
25
27
|
* Creates an instance of the `ResizeObserver` class.
|
|
26
28
|
*
|
|
27
|
-
* @param
|
|
29
|
+
* @param element A DOM element that is to be observed for resizing. Note that
|
|
28
30
|
* the element must be visible (i.e. not detached from DOM) for the observer to work.
|
|
29
|
-
* @param
|
|
31
|
+
* @param callback A function called when the observed element was resized. It passes
|
|
30
32
|
* the [`ResizeObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)
|
|
31
33
|
* object with information about the resize event.
|
|
32
34
|
*/
|
|
@@ -49,11 +51,6 @@ export default class ResizeObserver {
|
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
51
53
|
* Registers a new resize callback for the DOM element.
|
|
52
|
-
*
|
|
53
|
-
* @private
|
|
54
|
-
* @static
|
|
55
|
-
* @param {Element} element
|
|
56
|
-
* @param {Function} callback
|
|
57
54
|
*/
|
|
58
55
|
static _addElementCallback(element, callback) {
|
|
59
56
|
if (!ResizeObserver._elementCallbacks) {
|
|
@@ -69,11 +66,6 @@ export default class ResizeObserver {
|
|
|
69
66
|
/**
|
|
70
67
|
* Removes a resize callback from the DOM element. If no callbacks are left
|
|
71
68
|
* for the element, it removes the element from the native observer.
|
|
72
|
-
*
|
|
73
|
-
* @private
|
|
74
|
-
* @static
|
|
75
|
-
* @param {Element} element
|
|
76
|
-
* @param {Function} callback
|
|
77
69
|
*/
|
|
78
70
|
static _deleteElementCallback(element, callback) {
|
|
79
71
|
const callbacks = ResizeObserver._getElementCallbacks(element);
|
|
@@ -94,11 +86,6 @@ export default class ResizeObserver {
|
|
|
94
86
|
}
|
|
95
87
|
/**
|
|
96
88
|
* Returns are registered resize callbacks for the DOM element.
|
|
97
|
-
*
|
|
98
|
-
* @private
|
|
99
|
-
* @static
|
|
100
|
-
* @param {Element} element
|
|
101
|
-
* @returns {Set.<Function>|null|undefined}
|
|
102
89
|
*/
|
|
103
90
|
static _getElementCallbacks(element) {
|
|
104
91
|
if (!ResizeObserver._elementCallbacks) {
|
|
@@ -108,9 +95,6 @@ export default class ResizeObserver {
|
|
|
108
95
|
}
|
|
109
96
|
/**
|
|
110
97
|
* Creates the single native observer shared across all `ResizeObserver` instances.
|
|
111
|
-
*
|
|
112
|
-
* @private
|
|
113
|
-
* @static
|
|
114
98
|
*/
|
|
115
99
|
static _createObserver() {
|
|
116
100
|
ResizeObserver._observerInstance = new global.window.ResizeObserver(entries => {
|
|
@@ -127,19 +111,10 @@ export default class ResizeObserver {
|
|
|
127
111
|
}
|
|
128
112
|
/**
|
|
129
113
|
* The single native observer instance shared across all {@link module:utils/dom/resizeobserver~ResizeObserver} instances.
|
|
130
|
-
*
|
|
131
|
-
* @static
|
|
132
|
-
* @private
|
|
133
|
-
* @readonly
|
|
134
|
-
* @property {Object|null}
|
|
135
114
|
*/
|
|
136
115
|
ResizeObserver._observerInstance = null;
|
|
137
116
|
/**
|
|
138
117
|
* A mapping of native DOM elements and their callbacks shared across all
|
|
139
118
|
* {@link module:utils/dom/resizeobserver~ResizeObserver} instances.
|
|
140
|
-
*
|
|
141
|
-
* @static
|
|
142
|
-
* @private
|
|
143
|
-
* @property {Map.<Element,Set>|null}
|
|
144
119
|
*/
|
|
145
120
|
ResizeObserver._elementCallbacks = null;
|
package/src/dom/scroll.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2023, 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
5
|
/**
|
|
@@ -13,9 +13,9 @@ import isText from './istext';
|
|
|
13
13
|
* This helper will scroll all `target` ancestors and the web browser viewport to reveal the target to
|
|
14
14
|
* the user. If the `target` is already visible, nothing will happen.
|
|
15
15
|
*
|
|
16
|
-
* @param
|
|
17
|
-
* @param
|
|
18
|
-
* @param
|
|
16
|
+
* @param options
|
|
17
|
+
* @param options.target A target, which supposed to become visible to the user.
|
|
18
|
+
* @param options.viewportOffset An offset from the edge of the viewport (in pixels)
|
|
19
19
|
* the `target` will be moved by when the viewport is scrolled. It enhances the user experience
|
|
20
20
|
* by keeping the `target` some distance from the edge of the viewport and thus making it easier to
|
|
21
21
|
* read or edit by the user.
|
|
@@ -76,7 +76,7 @@ export function scrollViewportToShowTarget({ target, viewportOffset = 0 }) {
|
|
|
76
76
|
* Makes any page `HTMLElement` or `Range` (target) visible within its scrollable ancestors,
|
|
77
77
|
* e.g. if they have `overflow: scroll` CSS style.
|
|
78
78
|
*
|
|
79
|
-
* @param
|
|
79
|
+
* @param target A target, which supposed to become visible to the user.
|
|
80
80
|
*/
|
|
81
81
|
export function scrollAncestorsToShowTarget(target) {
|
|
82
82
|
const targetParent = getParentElement(target);
|
|
@@ -84,47 +84,56 @@ export function scrollAncestorsToShowTarget(target) {
|
|
|
84
84
|
return new Rect(target);
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Makes a given rect visible within its parent window.
|
|
89
|
+
*
|
|
90
|
+
* Note: Avoid the situation where the caret is still in the viewport, but totally
|
|
91
|
+
* at the edge of it. In such situation, if it moved beyond the viewport in the next
|
|
92
|
+
* action e.g. after paste, the scrolling would move it to the viewportOffset level
|
|
93
|
+
* and it all would look like the caret visually moved up/down:
|
|
94
|
+
*
|
|
95
|
+
* 1.
|
|
96
|
+
* ```
|
|
97
|
+
* | foo[]
|
|
98
|
+
* | <--- N px of space below the caret
|
|
99
|
+
* +---------------------------------...
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* 2. *paste*
|
|
103
|
+
* 3.
|
|
104
|
+
* ```
|
|
105
|
+
* |
|
|
106
|
+
* |
|
|
107
|
+
* +-foo-----------------------------...
|
|
108
|
+
* bar[] <--- caret below viewport, scrolling...
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* 4. *scrolling*
|
|
112
|
+
* 5.
|
|
113
|
+
* ```
|
|
114
|
+
* |
|
|
115
|
+
* | foo
|
|
116
|
+
* | bar[] <--- caret precisely at the edge
|
|
117
|
+
* +---------------------------------...
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* To prevent this, this method checks the rects moved by the viewportOffset to cover
|
|
121
|
+
* the upper/lower edge of the viewport. It makes sure if the action repeats, there's
|
|
122
|
+
* no twitching – it's a purely visual improvement:
|
|
123
|
+
*
|
|
124
|
+
* 5. (after fix)
|
|
125
|
+
* ```
|
|
126
|
+
* |
|
|
127
|
+
* | foo
|
|
128
|
+
* | bar[]
|
|
129
|
+
* | <--- N px of space below the caret
|
|
130
|
+
* +---------------------------------...
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @param window A window which is scrolled to reveal the rect.
|
|
134
|
+
* @param rect A rect which is to be revealed.
|
|
135
|
+
* @param viewportOffset See scrollViewportToShowTarget.
|
|
136
|
+
*/
|
|
128
137
|
function scrollWindowToShowRect(window, rect, viewportOffset) {
|
|
129
138
|
const targetShiftedDownRect = rect.clone().moveBy(0, viewportOffset);
|
|
130
139
|
const targetShiftedUpRect = rect.clone().moveBy(0, -viewportOffset);
|
|
@@ -149,11 +158,12 @@ function scrollWindowToShowRect(window, rect, viewportOffset) {
|
|
|
149
158
|
window.scrollTo(scrollX, scrollY);
|
|
150
159
|
}
|
|
151
160
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Recursively scrolls element ancestors to visually reveal a rect.
|
|
163
|
+
*
|
|
164
|
+
* @param parent A parent The first ancestors to start scrolling.
|
|
165
|
+
* @param getRect A function which returns the Rect, which is to be revealed.
|
|
166
|
+
*/
|
|
157
167
|
function scrollAncestorsToShowRect(parent, getRect) {
|
|
158
168
|
const parentWindow = getWindow(parent);
|
|
159
169
|
let parentRect, targetRect;
|
|
@@ -177,47 +187,33 @@ function scrollAncestorsToShowRect(parent, getRect) {
|
|
|
177
187
|
parent = parent.parentNode;
|
|
178
188
|
}
|
|
179
189
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// @param {module:utils/dom/rect~Rect} firstRect
|
|
184
|
-
// @param {module:utils/dom/rect~Rect} secondRect
|
|
185
|
-
// @returns {Boolean}
|
|
190
|
+
/**
|
|
191
|
+
* Determines if a given `Rect` extends beyond the bottom edge of the second `Rect`.
|
|
192
|
+
*/
|
|
186
193
|
function isBelow(firstRect, secondRect) {
|
|
187
194
|
return firstRect.bottom > secondRect.bottom;
|
|
188
195
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// @param {module:utils/dom/rect~Rect} firstRect
|
|
193
|
-
// @param {module:utils/dom/rect~Rect} secondRect
|
|
194
|
-
// @returns {Boolean}
|
|
196
|
+
/**
|
|
197
|
+
* Determines if a given `Rect` extends beyond the top edge of the second `Rect`.
|
|
198
|
+
*/
|
|
195
199
|
function isAbove(firstRect, secondRect) {
|
|
196
200
|
return firstRect.top < secondRect.top;
|
|
197
201
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// @param {module:utils/dom/rect~Rect} firstRect
|
|
202
|
-
// @param {module:utils/dom/rect~Rect} secondRect
|
|
203
|
-
// @returns {Boolean}
|
|
202
|
+
/**
|
|
203
|
+
* Determines if a given `Rect` extends beyond the left edge of the second `Rect`.
|
|
204
|
+
*/
|
|
204
205
|
function isLeftOf(firstRect, secondRect) {
|
|
205
206
|
return firstRect.left < secondRect.left;
|
|
206
207
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
// @param {module:utils/dom/rect~Rect} firstRect
|
|
211
|
-
// @param {module:utils/dom/rect~Rect} secondRect
|
|
212
|
-
// @returns {Boolean}
|
|
208
|
+
/**
|
|
209
|
+
* Determines if a given `Rect` extends beyond the right edge of the second `Rect`.
|
|
210
|
+
*/
|
|
213
211
|
function isRightOf(firstRect, secondRect) {
|
|
214
212
|
return firstRect.right > secondRect.right;
|
|
215
213
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// @param {HTMLElement|Range} elementOrRange
|
|
220
|
-
// @returns {Window}
|
|
214
|
+
/**
|
|
215
|
+
* Returns the closest window of an element or range.
|
|
216
|
+
*/
|
|
221
217
|
function getWindow(elementOrRange) {
|
|
222
218
|
if (isRange(elementOrRange)) {
|
|
223
219
|
return elementOrRange.startContainer.ownerDocument.defaultView;
|
|
@@ -226,11 +222,9 @@ function getWindow(elementOrRange) {
|
|
|
226
222
|
return elementOrRange.ownerDocument.defaultView;
|
|
227
223
|
}
|
|
228
224
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
// @param {HTMLElement|Range} elementOrRange
|
|
233
|
-
// @returns {HTMLelement}
|
|
225
|
+
/**
|
|
226
|
+
* Returns the closest parent of an element or DOM range.
|
|
227
|
+
*/
|
|
234
228
|
function getParentElement(elementOrRange) {
|
|
235
229
|
if (isRange(elementOrRange)) {
|
|
236
230
|
let parent = elementOrRange.commonAncestorContainer;
|
|
@@ -244,13 +238,13 @@ function getParentElement(elementOrRange) {
|
|
|
244
238
|
return elementOrRange.parentNode;
|
|
245
239
|
}
|
|
246
240
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Returns the rect of an element or range residing in an iframe.
|
|
243
|
+
* The result rect is relative to the geometry of the passed window instance.
|
|
244
|
+
*
|
|
245
|
+
* @param target Element or range which rect should be returned.
|
|
246
|
+
* @param relativeWindow A window the rect should be relative to.
|
|
247
|
+
*/
|
|
254
248
|
function getRectRelativeToWindow(target, relativeWindow) {
|
|
255
249
|
const targetWindow = getWindow(target);
|
|
256
250
|
const rect = new Rect(target);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2023, 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
5
|
/**
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
/**
|
|
10
10
|
* Sets data in a given element.
|
|
11
11
|
*
|
|
12
|
-
* @param
|
|
13
|
-
* @param
|
|
12
|
+
* @param el The element in which the data will be set.
|
|
13
|
+
* @param data The data string.
|
|
14
14
|
*/
|
|
15
15
|
export default function setDataInElement(el, data) {
|
|
16
16
|
if (el instanceof HTMLTextAreaElement) {
|
package/src/dom/tounit.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2023, 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
5
|
/**
|
|
@@ -9,17 +9,8 @@
|
|
|
9
9
|
* Returns a helper function, which adds a desired trailing
|
|
10
10
|
* `unit` to the passed value.
|
|
11
11
|
*
|
|
12
|
-
* @param
|
|
13
|
-
* @returns {module:utils/dom/tounit~helper}
|
|
12
|
+
* @param unit An unit like "px" or "em".
|
|
14
13
|
*/
|
|
15
14
|
export default function toUnit(unit) {
|
|
16
|
-
/**
|
|
17
|
-
* A function, which adds a pre–defined trailing `unit`
|
|
18
|
-
* to the passed `value`.
|
|
19
|
-
*
|
|
20
|
-
* @function helper
|
|
21
|
-
* @param {String|Number} value A value to be given the unit.
|
|
22
|
-
* @returns {String} A value with the trailing unit.
|
|
23
|
-
*/
|
|
24
15
|
return value => value + unit;
|
|
25
16
|
}
|
package/src/elementreplacer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2023, 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
5
|
/**
|
|
@@ -18,8 +18,8 @@ export default class ElementReplacer {
|
|
|
18
18
|
*
|
|
19
19
|
* The effect of this method can be reverted by {@link #restore}.
|
|
20
20
|
*
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
21
|
+
* @param element The element to replace.
|
|
22
|
+
* @param newElement The replacement element. If not passed, then the `element` will just be hidden.
|
|
23
23
|
*/
|
|
24
24
|
replace(element, newElement) {
|
|
25
25
|
this._replacedElements.push({ element, newElement });
|
package/src/emittermixin.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2023, 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
5
|
/**
|
|
6
6
|
* @module utils/emittermixin
|
|
7
7
|
*/
|
|
8
|
-
/* eslint-disable new-cap */
|
|
9
8
|
import EventInfo from './eventinfo';
|
|
10
9
|
import uid from './uid';
|
|
11
10
|
import priorities from './priorities';
|
|
@@ -16,18 +15,11 @@ import CKEditorError from './ckeditorerror';
|
|
|
16
15
|
const _listeningTo = Symbol('listeningTo');
|
|
17
16
|
const _emitterId = Symbol('emitterId');
|
|
18
17
|
const _delegations = Symbol('delegations');
|
|
19
|
-
|
|
20
|
-
* Mixin that injects the {@link ~Emitter events API} into its host.
|
|
21
|
-
*
|
|
22
|
-
* Read more about the concept of emitters in the:
|
|
23
|
-
* * {@glink framework/guides/architecture/core-editor-architecture#event-system-and-observables Event system and observables}
|
|
24
|
-
* section of the {@glink framework/guides/architecture/core-editor-architecture Core editor architecture} guide.
|
|
25
|
-
* * {@glink framework/guides/deep-dive/event-system Event system} deep dive guide.
|
|
26
|
-
*
|
|
27
|
-
* @mixin EmitterMixin
|
|
28
|
-
* @implements module:utils/emittermixin~Emitter
|
|
29
|
-
*/
|
|
18
|
+
const defaultEmitterClass = EmitterMixin(Object);
|
|
30
19
|
export default function EmitterMixin(base) {
|
|
20
|
+
if (!base) {
|
|
21
|
+
return defaultEmitterClass;
|
|
22
|
+
}
|
|
31
23
|
class Mixin extends base {
|
|
32
24
|
on(event, callback, options) {
|
|
33
25
|
this.listenTo(this, event, callback, options);
|
|
@@ -250,24 +242,21 @@ export default function EmitterMixin(base) {
|
|
|
250
242
|
}
|
|
251
243
|
return Mixin;
|
|
252
244
|
}
|
|
253
|
-
export const Emitter = EmitterMixin(Object);
|
|
254
245
|
// Backward compatibility with `mix`
|
|
255
246
|
([
|
|
256
247
|
'on', 'once', 'off', 'listenTo',
|
|
257
248
|
'stopListening', 'fire', 'delegate', 'stopDelegating',
|
|
258
249
|
'_addEventListener', '_removeEventListener'
|
|
259
250
|
]).forEach(key => {
|
|
260
|
-
EmitterMixin[key] =
|
|
251
|
+
EmitterMixin[key] = defaultEmitterClass.prototype[key];
|
|
261
252
|
});
|
|
262
253
|
/**
|
|
263
254
|
* Checks if `listeningEmitter` listens to an emitter with given `listenedToEmitterId` and if so, returns that emitter.
|
|
264
255
|
* If not, returns `null`.
|
|
265
256
|
*
|
|
266
257
|
* @internal
|
|
267
|
-
* @
|
|
268
|
-
* @param
|
|
269
|
-
* @param {String} listenedToEmitterId Unique emitter id of emitter listened to.
|
|
270
|
-
* @returns {module:utils/emittermixin~Emitter|null}
|
|
258
|
+
* @param listeningEmitter An emitter that listens.
|
|
259
|
+
* @param listenedToEmitterId Unique emitter id of emitter listened to.
|
|
271
260
|
*/
|
|
272
261
|
export function _getEmitterListenedTo(listeningEmitter, listenedToEmitterId) {
|
|
273
262
|
const listeningTo = listeningEmitter[_listeningTo];
|
|
@@ -282,9 +271,8 @@ export function _getEmitterListenedTo(listeningEmitter, listenedToEmitterId) {
|
|
|
282
271
|
* **Note:** `_emitterId` can be set only once.
|
|
283
272
|
*
|
|
284
273
|
* @internal
|
|
285
|
-
* @
|
|
286
|
-
* @param
|
|
287
|
-
* @param {String} [id] Unique id to set. If not passed, random unique id will be set.
|
|
274
|
+
* @param emitter An emitter for which id will be set.
|
|
275
|
+
* @param id Unique id to set. If not passed, random unique id will be set.
|
|
288
276
|
*/
|
|
289
277
|
export function _setEmitterId(emitter, id) {
|
|
290
278
|
if (!emitter[_emitterId]) {
|
|
@@ -295,16 +283,16 @@ export function _setEmitterId(emitter, id) {
|
|
|
295
283
|
* Returns emitter's unique id.
|
|
296
284
|
*
|
|
297
285
|
* @internal
|
|
298
|
-
* @
|
|
299
|
-
* @param {module:utils/emittermixin~Emitter} emitter An emitter which id will be returned.
|
|
300
|
-
* @returns {String|undefined}
|
|
286
|
+
* @param emitter An emitter which id will be returned.
|
|
301
287
|
*/
|
|
302
288
|
export function _getEmitterId(emitter) {
|
|
303
289
|
return emitter[_emitterId];
|
|
304
290
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
291
|
+
/**
|
|
292
|
+
* Gets the internal `_events` property of the given object.
|
|
293
|
+
* `_events` property store all lists with callbacks for registered event names.
|
|
294
|
+
* If there were no events registered on the object, empty `_events` object is created.
|
|
295
|
+
*/
|
|
308
296
|
function getEvents(source) {
|
|
309
297
|
if (!source._events) {
|
|
310
298
|
Object.defineProperty(source, '_events', {
|
|
@@ -313,18 +301,22 @@ function getEvents(source) {
|
|
|
313
301
|
}
|
|
314
302
|
return source._events;
|
|
315
303
|
}
|
|
316
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Creates event node for generic-specific events relation architecture.
|
|
306
|
+
*/
|
|
317
307
|
function makeEventNode() {
|
|
318
308
|
return {
|
|
319
309
|
callbacks: [],
|
|
320
310
|
childEvents: []
|
|
321
311
|
};
|
|
322
312
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
313
|
+
/**
|
|
314
|
+
* Creates an architecture for generic-specific events relation.
|
|
315
|
+
* If needed, creates all events for given eventName, i.e. if the first registered event
|
|
316
|
+
* is foo:bar:abc, it will create foo:bar:abc, foo:bar and foo event and tie them together.
|
|
317
|
+
* It also copies callbacks from more generic events to more specific events when
|
|
318
|
+
* specific events are created.
|
|
319
|
+
*/
|
|
328
320
|
function createEventNamespace(source, eventName) {
|
|
329
321
|
const events = getEvents(source);
|
|
330
322
|
// First, check if the event we want to add to the structure already exists.
|
|
@@ -375,9 +367,11 @@ function createEventNamespace(source, eventName) {
|
|
|
375
367
|
events[name].childEvents.push(childEventName);
|
|
376
368
|
}
|
|
377
369
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
370
|
+
/**
|
|
371
|
+
* Gets an array containing callbacks list for a given event and it's more specific events.
|
|
372
|
+
* I.e. if given event is foo:bar and there is also foo:bar:abc event registered, this will
|
|
373
|
+
* return callback list of foo:bar and foo:bar:abc (but not foo).
|
|
374
|
+
*/
|
|
381
375
|
function getCallbacksListsForNamespace(source, eventName) {
|
|
382
376
|
const eventNode = getEvents(source)[eventName];
|
|
383
377
|
if (!eventNode) {
|
|
@@ -390,9 +384,11 @@ function getCallbacksListsForNamespace(source, eventName) {
|
|
|
390
384
|
}
|
|
391
385
|
return callbacksLists;
|
|
392
386
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
387
|
+
/**
|
|
388
|
+
* Get the list of callbacks for a given event, but only if there any callbacks have been registered.
|
|
389
|
+
* If there are no callbacks registered for given event, it checks if this is a specific event and looks
|
|
390
|
+
* for callbacks for it's more generic version.
|
|
391
|
+
*/
|
|
396
392
|
function getCallbacksForEvent(source, eventName) {
|
|
397
393
|
let event;
|
|
398
394
|
if (!source._events || !(event = source._events[eventName]) || !event.callbacks.length) {
|
|
@@ -409,13 +405,13 @@ function getCallbacksForEvent(source, eventName) {
|
|
|
409
405
|
}
|
|
410
406
|
return event.callbacks;
|
|
411
407
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
408
|
+
/**
|
|
409
|
+
* Fires delegated events for given map of destinations.
|
|
410
|
+
*
|
|
411
|
+
* @param destinations A map containing `[ {@link module:utils/emittermixin~Emitter}, "event name" ]` pair destinations.
|
|
412
|
+
* @param eventInfo The original event info object.
|
|
413
|
+
* @param fireArgs Arguments the original event was fired with.
|
|
414
|
+
*/
|
|
419
415
|
function fireDelegatedEvents(destinations, eventInfo, fireArgs) {
|
|
420
416
|
for (let [emitter, name] of destinations) {
|
|
421
417
|
if (!name) {
|
|
@@ -429,7 +425,9 @@ function fireDelegatedEvents(destinations, eventInfo, fireArgs) {
|
|
|
429
425
|
emitter.fire(delegatedInfo, ...fireArgs);
|
|
430
426
|
}
|
|
431
427
|
}
|
|
432
|
-
|
|
428
|
+
/**
|
|
429
|
+
* Helper for registering event callback on the emitter.
|
|
430
|
+
*/
|
|
433
431
|
function addEventListener(listener, emitter, event, callback, options) {
|
|
434
432
|
if (emitter._addEventListener) {
|
|
435
433
|
emitter._addEventListener(event, callback, options);
|
|
@@ -440,7 +438,9 @@ function addEventListener(listener, emitter, event, callback, options) {
|
|
|
440
438
|
(listener._addEventListener).call(emitter, event, callback, options);
|
|
441
439
|
}
|
|
442
440
|
}
|
|
443
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Helper for removing event callback from the emitter.
|
|
443
|
+
*/
|
|
444
444
|
function removeEventListener(listener, emitter, event, callback) {
|
|
445
445
|
if (emitter._removeEventListener) {
|
|
446
446
|
emitter._removeEventListener(event, callback);
|