@ckeditor/ckeditor5-utils 35.0.1 → 35.2.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 +1 -1
- package/package.json +5 -5
- package/src/collection.js +3 -5
- package/src/dom/emittermixin.js +75 -96
- package/src/dom/global.js +15 -1
- package/src/dom/rect.js +4 -5
- package/src/emittermixin.js +204 -222
- package/src/env.js +16 -1
- package/src/focustracker.js +4 -6
- package/src/keystrokehandler.js +1 -1
- package/src/mix.js +4 -0
- package/src/observablemixin.js +194 -195
- package/src/splicearray.js +39 -0
- package/src/translation-service.js +18 -18
- package/src/version.js +1 -1
package/src/emittermixin.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @module utils/emittermixin
|
|
7
7
|
*/
|
|
8
|
+
/* eslint-disable new-cap */
|
|
8
9
|
import EventInfo from './eventinfo';
|
|
9
10
|
import uid from './uid';
|
|
10
11
|
import priorities from './priorities';
|
|
@@ -26,257 +27,238 @@ const _delegations = Symbol('delegations');
|
|
|
26
27
|
* @mixin EmitterMixin
|
|
27
28
|
* @implements module:utils/emittermixin~Emitter
|
|
28
29
|
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
on(event, callback, options = {}) {
|
|
34
|
-
this.listenTo(this, event, callback, options);
|
|
35
|
-
},
|
|
36
|
-
/**
|
|
37
|
-
* @inheritDoc
|
|
38
|
-
*/
|
|
39
|
-
once(event, callback, options) {
|
|
40
|
-
let wasFired = false;
|
|
41
|
-
const onceCallback = (event, ...args) => {
|
|
42
|
-
// Ensure the callback is called only once even if the callback itself leads to re-firing the event
|
|
43
|
-
// (which would call the callback again).
|
|
44
|
-
if (!wasFired) {
|
|
45
|
-
wasFired = true;
|
|
46
|
-
// Go off() at the first call.
|
|
47
|
-
event.off();
|
|
48
|
-
// Go with the original callback.
|
|
49
|
-
callback.call(this, event, ...args);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
// Make a similar on() call, simply replacing the callback.
|
|
53
|
-
this.listenTo(this, event, onceCallback, options);
|
|
54
|
-
},
|
|
55
|
-
/**
|
|
56
|
-
* @inheritDoc
|
|
57
|
-
*/
|
|
58
|
-
off(event, callback) {
|
|
59
|
-
this.stopListening(this, event, callback);
|
|
60
|
-
},
|
|
61
|
-
/**
|
|
62
|
-
* @inheritDoc
|
|
63
|
-
*/
|
|
64
|
-
listenTo(emitter, event, callback, options = {}) {
|
|
65
|
-
let emitterInfo, eventCallbacks;
|
|
66
|
-
// _listeningTo contains a list of emitters that this object is listening to.
|
|
67
|
-
// This list has the following format:
|
|
68
|
-
//
|
|
69
|
-
// _listeningTo: {
|
|
70
|
-
// emitterId: {
|
|
71
|
-
// emitter: emitter,
|
|
72
|
-
// callbacks: {
|
|
73
|
-
// event1: [ callback1, callback2, ... ]
|
|
74
|
-
// ....
|
|
75
|
-
// }
|
|
76
|
-
// },
|
|
77
|
-
// ...
|
|
78
|
-
// }
|
|
79
|
-
if (!this[_listeningTo]) {
|
|
80
|
-
this[_listeningTo] = {};
|
|
81
|
-
}
|
|
82
|
-
const emitters = this[_listeningTo];
|
|
83
|
-
if (!_getEmitterId(emitter)) {
|
|
84
|
-
_setEmitterId(emitter);
|
|
30
|
+
export default function EmitterMixin(base) {
|
|
31
|
+
class Mixin extends base {
|
|
32
|
+
on(event, callback, options) {
|
|
33
|
+
this.listenTo(this, event, callback, options);
|
|
85
34
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
35
|
+
once(event, callback, options) {
|
|
36
|
+
let wasFired = false;
|
|
37
|
+
const onceCallback = (event, ...args) => {
|
|
38
|
+
// Ensure the callback is called only once even if the callback itself leads to re-firing the event
|
|
39
|
+
// (which would call the callback again).
|
|
40
|
+
if (!wasFired) {
|
|
41
|
+
wasFired = true;
|
|
42
|
+
// Go off() at the first call.
|
|
43
|
+
event.off();
|
|
44
|
+
// Go with the original callback.
|
|
45
|
+
callback.call(this, event, ...args);
|
|
46
|
+
}
|
|
91
47
|
};
|
|
48
|
+
// Make a similar on() call, simply replacing the callback.
|
|
49
|
+
this.listenTo(this, event, onceCallback, options);
|
|
92
50
|
}
|
|
93
|
-
|
|
94
|
-
|
|
51
|
+
off(event, callback) {
|
|
52
|
+
this.stopListening(this, event, callback);
|
|
95
53
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (callback) {
|
|
114
|
-
removeEventListener(this, emitter, event, callback);
|
|
115
|
-
// We must remove callbacks as well in order to prevent memory leaks.
|
|
116
|
-
// See https://github.com/ckeditor/ckeditor5/pull/8480
|
|
117
|
-
const index = eventCallbacks.indexOf(callback);
|
|
118
|
-
if (index !== -1) {
|
|
119
|
-
if (eventCallbacks.length === 1) {
|
|
120
|
-
delete emitterInfo.callbacks[event];
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
removeEventListener(this, emitter, event, callback);
|
|
124
|
-
}
|
|
54
|
+
listenTo(emitter, event, callback, options = {}) {
|
|
55
|
+
let emitterInfo, eventCallbacks;
|
|
56
|
+
// _listeningTo contains a list of emitters that this object is listening to.
|
|
57
|
+
// This list has the following format:
|
|
58
|
+
//
|
|
59
|
+
// _listeningTo: {
|
|
60
|
+
// emitterId: {
|
|
61
|
+
// emitter: emitter,
|
|
62
|
+
// callbacks: {
|
|
63
|
+
// event1: [ callback1, callback2, ... ]
|
|
64
|
+
// ....
|
|
65
|
+
// }
|
|
66
|
+
// },
|
|
67
|
+
// ...
|
|
68
|
+
// }
|
|
69
|
+
if (!this[_listeningTo]) {
|
|
70
|
+
this[_listeningTo] = {};
|
|
125
71
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
while ((callback = eventCallbacks.pop())) {
|
|
130
|
-
removeEventListener(this, emitter, event, callback);
|
|
72
|
+
const emitters = this[_listeningTo];
|
|
73
|
+
if (!_getEmitterId(emitter)) {
|
|
74
|
+
_setEmitterId(emitter);
|
|
131
75
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
76
|
+
const emitterId = _getEmitterId(emitter);
|
|
77
|
+
if (!(emitterInfo = emitters[emitterId])) {
|
|
78
|
+
emitterInfo = emitters[emitterId] = {
|
|
79
|
+
emitter,
|
|
80
|
+
callbacks: {}
|
|
81
|
+
};
|
|
138
82
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// No params provided. off() all emitters.
|
|
142
|
-
else {
|
|
143
|
-
for (emitterId in emitters) {
|
|
144
|
-
this.stopListening(emitters[emitterId].emitter);
|
|
83
|
+
if (!(eventCallbacks = emitterInfo.callbacks[event])) {
|
|
84
|
+
eventCallbacks = emitterInfo.callbacks[event] = [];
|
|
145
85
|
}
|
|
146
|
-
|
|
86
|
+
eventCallbacks.push(callback);
|
|
87
|
+
// Finally register the callback to the event.
|
|
88
|
+
addEventListener(this, emitter, event, callback, options);
|
|
147
89
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
//
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
// If this proves to be too inefficient, another method is to change `.on()` so callbacks are stored if same
|
|
167
|
-
// event is currently processed. Then, `.fire()` at the end, would have to add all stored events.
|
|
168
|
-
callbacks = Array.from(callbacks);
|
|
169
|
-
for (let i = 0; i < callbacks.length; i++) {
|
|
170
|
-
callbacks[i].callback.apply(this, callbackArgs);
|
|
171
|
-
// Remove the callback from future requests if off() has been called.
|
|
172
|
-
if (eventInfo.off.called) {
|
|
173
|
-
// Remove the called mark for the next calls.
|
|
174
|
-
delete eventInfo.off.called;
|
|
175
|
-
this._removeEventListener(event, callbacks[i].callback);
|
|
90
|
+
stopListening(emitter, event, callback) {
|
|
91
|
+
const emitters = this[_listeningTo];
|
|
92
|
+
let emitterId = emitter && _getEmitterId(emitter);
|
|
93
|
+
const emitterInfo = (emitters && emitterId) ? emitters[emitterId] : undefined;
|
|
94
|
+
const eventCallbacks = (emitterInfo && event) ? emitterInfo.callbacks[event] : undefined;
|
|
95
|
+
// Stop if nothing has been listened.
|
|
96
|
+
if (!emitters || (emitter && !emitterInfo) || (event && !eventCallbacks)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// All params provided. off() that single callback.
|
|
100
|
+
if (callback) {
|
|
101
|
+
removeEventListener(this, emitter, event, callback);
|
|
102
|
+
// We must remove callbacks as well in order to prevent memory leaks.
|
|
103
|
+
// See https://github.com/ckeditor/ckeditor5/pull/8480
|
|
104
|
+
const index = eventCallbacks.indexOf(callback);
|
|
105
|
+
if (index !== -1) {
|
|
106
|
+
if (eventCallbacks.length === 1) {
|
|
107
|
+
delete emitterInfo.callbacks[event];
|
|
176
108
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
break;
|
|
109
|
+
else {
|
|
110
|
+
removeEventListener(this, emitter, event, callback);
|
|
180
111
|
}
|
|
181
112
|
}
|
|
182
113
|
}
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const passAllDestinations = delegations.get('*');
|
|
188
|
-
if (destinations) {
|
|
189
|
-
fireDelegatedEvents(destinations, eventInfo, args);
|
|
114
|
+
// Only `emitter` and `event` provided. off() all callbacks for that event.
|
|
115
|
+
else if (eventCallbacks) {
|
|
116
|
+
while ((callback = eventCallbacks.pop())) {
|
|
117
|
+
removeEventListener(this, emitter, event, callback);
|
|
190
118
|
}
|
|
191
|
-
|
|
192
|
-
|
|
119
|
+
delete emitterInfo.callbacks[event];
|
|
120
|
+
}
|
|
121
|
+
// Only `emitter` provided. off() all events for that emitter.
|
|
122
|
+
else if (emitterInfo) {
|
|
123
|
+
for (event in emitterInfo.callbacks) {
|
|
124
|
+
this.stopListening(emitter, event);
|
|
193
125
|
}
|
|
126
|
+
delete emitters[emitterId];
|
|
127
|
+
}
|
|
128
|
+
// No params provided. off() all emitters.
|
|
129
|
+
else {
|
|
130
|
+
for (emitterId in emitters) {
|
|
131
|
+
this.stopListening(emitters[emitterId].emitter);
|
|
132
|
+
}
|
|
133
|
+
delete this[_listeningTo];
|
|
194
134
|
}
|
|
195
|
-
return eventInfo.return;
|
|
196
|
-
}
|
|
197
|
-
catch (err) {
|
|
198
|
-
// @if CK_DEBUG // throw err;
|
|
199
|
-
/* istanbul ignore next */
|
|
200
|
-
CKEditorError.rethrowUnexpectedError(err, this);
|
|
201
135
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
136
|
+
fire(eventOrInfo, ...args) {
|
|
137
|
+
try {
|
|
138
|
+
const eventInfo = eventOrInfo instanceof EventInfo ? eventOrInfo : new EventInfo(this, eventOrInfo);
|
|
139
|
+
const event = eventInfo.name;
|
|
140
|
+
let callbacks = getCallbacksForEvent(this, event);
|
|
141
|
+
// Record that the event passed this emitter on its path.
|
|
142
|
+
eventInfo.path.push(this);
|
|
143
|
+
// Handle event listener callbacks first.
|
|
144
|
+
if (callbacks) {
|
|
145
|
+
// Arguments passed to each callback.
|
|
146
|
+
const callbackArgs = [eventInfo, ...args];
|
|
147
|
+
// Copying callbacks array is the easiest and most secure way of preventing infinite loops, when event callbacks
|
|
148
|
+
// are added while processing other callbacks. Previous solution involved adding counters (unique ids) but
|
|
149
|
+
// failed if callbacks were added to the queue before currently processed callback.
|
|
150
|
+
// If this proves to be too inefficient, another method is to change `.on()` so callbacks are stored if same
|
|
151
|
+
// event is currently processed. Then, `.fire()` at the end, would have to add all stored events.
|
|
152
|
+
callbacks = Array.from(callbacks);
|
|
153
|
+
for (let i = 0; i < callbacks.length; i++) {
|
|
154
|
+
callbacks[i].callback.apply(this, callbackArgs);
|
|
155
|
+
// Remove the callback from future requests if off() has been called.
|
|
156
|
+
if (eventInfo.off.called) {
|
|
157
|
+
// Remove the called mark for the next calls.
|
|
158
|
+
delete eventInfo.off.called;
|
|
159
|
+
this._removeEventListener(event, callbacks[i].callback);
|
|
160
|
+
}
|
|
161
|
+
// Do not execute next callbacks if stop() was called.
|
|
162
|
+
if (eventInfo.stop.called) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
211
166
|
}
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const destinations =
|
|
216
|
-
|
|
217
|
-
|
|
167
|
+
// Delegate event to other emitters if needed.
|
|
168
|
+
const delegations = this[_delegations];
|
|
169
|
+
if (delegations) {
|
|
170
|
+
const destinations = delegations.get(event);
|
|
171
|
+
const passAllDestinations = delegations.get('*');
|
|
172
|
+
if (destinations) {
|
|
173
|
+
fireDelegatedEvents(destinations, eventInfo, args);
|
|
218
174
|
}
|
|
219
|
-
|
|
220
|
-
|
|
175
|
+
if (passAllDestinations) {
|
|
176
|
+
fireDelegatedEvents(passAllDestinations, eventInfo, args);
|
|
221
177
|
}
|
|
222
|
-
}
|
|
178
|
+
}
|
|
179
|
+
return eventInfo.return;
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
// @if CK_DEBUG // throw err;
|
|
183
|
+
/* istanbul ignore next */
|
|
184
|
+
CKEditorError.rethrowUnexpectedError(err, this);
|
|
223
185
|
}
|
|
224
|
-
};
|
|
225
|
-
},
|
|
226
|
-
/**
|
|
227
|
-
* @inheritDoc
|
|
228
|
-
*/
|
|
229
|
-
stopDelegating(event, emitter) {
|
|
230
|
-
if (!this[_delegations]) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
if (!event) {
|
|
234
|
-
this[_delegations].clear();
|
|
235
186
|
}
|
|
236
|
-
|
|
237
|
-
|
|
187
|
+
delegate(...events) {
|
|
188
|
+
return {
|
|
189
|
+
to: (emitter, nameOrFunction) => {
|
|
190
|
+
if (!this[_delegations]) {
|
|
191
|
+
this[_delegations] = new Map();
|
|
192
|
+
}
|
|
193
|
+
// Originally there was a for..of loop which unfortunately caused an error in Babel that didn't allow
|
|
194
|
+
// build an application. See: https://github.com/ckeditor/ckeditor5-react/issues/40.
|
|
195
|
+
events.forEach(eventName => {
|
|
196
|
+
const destinations = this[_delegations].get(eventName);
|
|
197
|
+
if (!destinations) {
|
|
198
|
+
this[_delegations].set(eventName, new Map([[emitter, nameOrFunction]]));
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
destinations.set(emitter, nameOrFunction);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
};
|
|
238
206
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
207
|
+
stopDelegating(event, emitter) {
|
|
208
|
+
if (!this[_delegations]) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (!event) {
|
|
212
|
+
this[_delegations].clear();
|
|
213
|
+
}
|
|
214
|
+
else if (!emitter) {
|
|
215
|
+
this[_delegations].delete(event);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const destinations = this[_delegations].get(event);
|
|
219
|
+
if (destinations) {
|
|
220
|
+
destinations.delete(emitter);
|
|
221
|
+
}
|
|
243
222
|
}
|
|
244
223
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
for (const callbacks of lists) {
|
|
259
|
-
// Add the callback to the list in the right priority position.
|
|
260
|
-
insertToPriorityArray(callbacks, callbackDefinition);
|
|
224
|
+
_addEventListener(event, callback, options) {
|
|
225
|
+
createEventNamespace(this, event);
|
|
226
|
+
const lists = getCallbacksListsForNamespace(this, event);
|
|
227
|
+
const priority = priorities.get(options.priority);
|
|
228
|
+
const callbackDefinition = {
|
|
229
|
+
callback,
|
|
230
|
+
priority
|
|
231
|
+
};
|
|
232
|
+
// Add the callback to all callbacks list.
|
|
233
|
+
for (const callbacks of lists) {
|
|
234
|
+
// Add the callback to the list in the right priority position.
|
|
235
|
+
insertToPriorityArray(callbacks, callbackDefinition);
|
|
236
|
+
}
|
|
261
237
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
// Remove the callback from the list (fixing the next index).
|
|
272
|
-
callbacks.splice(i, 1);
|
|
273
|
-
i--;
|
|
238
|
+
_removeEventListener(event, callback) {
|
|
239
|
+
const lists = getCallbacksListsForNamespace(this, event);
|
|
240
|
+
for (const callbacks of lists) {
|
|
241
|
+
for (let i = 0; i < callbacks.length; i++) {
|
|
242
|
+
if (callbacks[i].callback == callback) {
|
|
243
|
+
// Remove the callback from the list (fixing the next index).
|
|
244
|
+
callbacks.splice(i, 1);
|
|
245
|
+
i--;
|
|
246
|
+
}
|
|
274
247
|
}
|
|
275
248
|
}
|
|
276
249
|
}
|
|
277
250
|
}
|
|
278
|
-
|
|
279
|
-
|
|
251
|
+
return Mixin;
|
|
252
|
+
}
|
|
253
|
+
export const Emitter = EmitterMixin(Object);
|
|
254
|
+
// Backward compatibility with `mix`
|
|
255
|
+
([
|
|
256
|
+
'on', 'once', 'off', 'listenTo',
|
|
257
|
+
'stopListening', 'fire', 'delegate', 'stopDelegating',
|
|
258
|
+
'_addEventListener', '_removeEventListener'
|
|
259
|
+
]).forEach(key => {
|
|
260
|
+
EmitterMixin[key] = Emitter.prototype[key];
|
|
261
|
+
});
|
|
280
262
|
/**
|
|
281
263
|
* Checks if `listeningEmitter` listens to an emitter with given `listenedToEmitterId` and if so, returns that emitter.
|
|
282
264
|
* If not, returns `null`.
|
|
@@ -455,7 +437,7 @@ function addEventListener(listener, emitter, event, callback, options) {
|
|
|
455
437
|
else {
|
|
456
438
|
// Allow listening on objects that do not implement Emitter interface.
|
|
457
439
|
// This is needed in some tests that are using mocks instead of the real objects with EmitterMixin mixed.
|
|
458
|
-
listener._addEventListener.call(emitter, event, callback, options);
|
|
440
|
+
(listener._addEventListener).call(emitter, event, callback, options);
|
|
459
441
|
}
|
|
460
442
|
}
|
|
461
443
|
// Helper for removing event callback from the emitter.
|
package/src/env.js
CHANGED
|
@@ -6,7 +6,22 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* @module utils/env
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Safely returns `userAgent` from browser's navigator API in a lower case.
|
|
11
|
+
* If navigator API is not available it will return an empty string.
|
|
12
|
+
*
|
|
13
|
+
* @returns {String}
|
|
14
|
+
*/
|
|
15
|
+
export function getUserAgent() {
|
|
16
|
+
// In some environments navigator API might not be available.
|
|
17
|
+
try {
|
|
18
|
+
return navigator.userAgent.toLowerCase();
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const userAgent = getUserAgent();
|
|
10
25
|
/**
|
|
11
26
|
* A namespace containing environment and browser information.
|
|
12
27
|
*
|
package/src/focustracker.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
5
|
/* global setTimeout, clearTimeout */
|
|
6
|
+
/* eslint-disable new-cap */
|
|
6
7
|
/**
|
|
7
8
|
* @module utils/focustracker
|
|
8
9
|
*/
|
|
9
10
|
import DomEmitterMixin from './dom/emittermixin';
|
|
10
|
-
import
|
|
11
|
+
import { Observable } from './observablemixin';
|
|
11
12
|
import CKEditorError from './ckeditorerror';
|
|
12
|
-
import mix from './mix';
|
|
13
13
|
/**
|
|
14
14
|
* Allows observing a group of `Element`s whether at least one of them is focused.
|
|
15
15
|
*
|
|
@@ -25,8 +25,9 @@ import mix from './mix';
|
|
|
25
25
|
* @mixes module:utils/dom/emittermixin~EmitterMixin
|
|
26
26
|
* @mixes module:utils/observablemixin~ObservableMixin
|
|
27
27
|
*/
|
|
28
|
-
class FocusTracker {
|
|
28
|
+
export default class FocusTracker extends DomEmitterMixin(Observable) {
|
|
29
29
|
constructor() {
|
|
30
|
+
super();
|
|
30
31
|
this.set('isFocused', false);
|
|
31
32
|
this.set('focusedElement', null);
|
|
32
33
|
this._elements = new Set();
|
|
@@ -98,6 +99,3 @@ class FocusTracker {
|
|
|
98
99
|
}, 0);
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
|
-
mix(FocusTracker, DomEmitterMixin);
|
|
102
|
-
mix(FocusTracker, ObservableMixin);
|
|
103
|
-
export default FocusTracker;
|
package/src/keystrokehandler.js
CHANGED
|
@@ -71,7 +71,7 @@ export default class KeystrokeHandler {
|
|
|
71
71
|
* the {@link module:utils/keyboard~parseKeystroke} function.
|
|
72
72
|
* @param {Function} callback A function called with the
|
|
73
73
|
* {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and
|
|
74
|
-
* a helper
|
|
74
|
+
* a helper function to call both `preventDefault()` and `stopPropagation()` on the underlying event.
|
|
75
75
|
* @param {Object} [options={}] Additional options.
|
|
76
76
|
* @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of the keystroke
|
|
77
77
|
* callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority
|
package/src/mix.js
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
*
|
|
26
26
|
* Note: Properties which already exist in the base class will not be overriden.
|
|
27
27
|
*
|
|
28
|
+
* @depreciated Use mixin pattern, see: https://www.typescriptlang.org/docs/handbook/mixins.html.
|
|
28
29
|
* @param {Function} [baseClass] Class which prototype will be extended.
|
|
29
30
|
* @param {Object} [...mixins] Objects from which to get properties.
|
|
30
31
|
*/
|
|
@@ -36,6 +37,9 @@ export default function mix(baseClass, ...mixins) {
|
|
|
36
37
|
if (key in baseClass.prototype) {
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
40
|
+
if (typeof mixin == 'function' && (key == 'length' || key == 'name' || key == 'prototype')) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
39
43
|
const sourceDescriptor = Object.getOwnPropertyDescriptor(mixin, key);
|
|
40
44
|
sourceDescriptor.enumerable = false;
|
|
41
45
|
Object.defineProperty(baseClass.prototype, key, sourceDescriptor);
|