@ckeditor/ckeditor5-engine 33.0.0 → 34.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/README.md +2 -1
- package/package.json +22 -22
- package/src/conversion/downcasthelpers.js +90 -19
- package/src/conversion/mapper.js +2 -2
- package/src/conversion/upcastdispatcher.js +31 -1
- package/src/index.js +6 -0
- package/src/model/differ.js +33 -15
- package/src/model/model.js +120 -3
- package/src/model/schema.js +79 -10
- package/src/model/treewalker.js +2 -3
- package/src/model/utils/deletecontent.js +15 -2
- package/src/model/utils/findoptimalinsertionrange.js +68 -0
- package/src/model/utils/insertobject.js +173 -0
- package/src/view/attributeelement.js +0 -10
- package/src/view/domconverter.js +16 -1
- package/src/view/downcastwriter.js +5 -49
- package/src/view/element.js +0 -27
- package/src/view/emptyelement.js +0 -3
- package/src/view/matcher.js +2 -2
- package/src/view/observer/clickobserver.js +0 -1
- package/src/view/observer/inputobserver.js +1 -1
- package/src/view/observer/tabobserver.js +68 -0
- package/src/view/placeholder.js +1 -1
- package/src/view/rawelement.js +0 -3
- package/src/view/uielement.js +0 -3
- package/src/view/view.js +4 -0
|
@@ -185,10 +185,6 @@ export default class DowncastWriter {
|
|
|
185
185
|
* // Set `id` of a marker element so it is not joined or merged with "normal" elements.
|
|
186
186
|
* writer.createAttributeElement( 'span', { class: 'my-marker' }, { id: 'marker:my' } );
|
|
187
187
|
*
|
|
188
|
-
* **Note:** By default an `AttributeElement` is split by a
|
|
189
|
-
* {@link module:engine/view/containerelement~ContainerElement `ContainerElement`} but this behavior can be modified
|
|
190
|
-
* with `isAllowedInsideAttributeElement` option set while {@link #createContainerElement creating the element}.
|
|
191
|
-
*
|
|
192
188
|
* @param {String} name Name of the element.
|
|
193
189
|
* @param {Object} [attributes] Element's attributes.
|
|
194
190
|
* @param {Object} [options] Element's options.
|
|
@@ -237,7 +233,7 @@ export default class DowncastWriter {
|
|
|
237
233
|
* ] );
|
|
238
234
|
*
|
|
239
235
|
* // Create element with specific options.
|
|
240
|
-
* writer.createContainerElement( 'span', { class: 'placeholder' }, {
|
|
236
|
+
* writer.createContainerElement( 'span', { class: 'placeholder' }, { renderUnsafeAttributes: [ 'foo' ] } );
|
|
241
237
|
*
|
|
242
238
|
* @param {String} name Name of the element.
|
|
243
239
|
* @param {Object} [attributes] Elements attributes.
|
|
@@ -245,9 +241,6 @@ export default class DowncastWriter {
|
|
|
245
241
|
* A node or a list of nodes to be inserted into the created element. If no children were specified, element's `options`
|
|
246
242
|
* can be passed in this argument.
|
|
247
243
|
* @param {Object} [options] Element's options.
|
|
248
|
-
* @param {Boolean} [options.isAllowedInsideAttributeElement=false] Whether an element is
|
|
249
|
-
* {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped
|
|
250
|
-
* with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.
|
|
251
244
|
* @param {Array.<String>} [options.renderUnsafeAttributes] A list of attribute names that should be rendered in the editing
|
|
252
245
|
* pipeline even though they would normally be filtered out by unsafe attribute detection mechanisms.
|
|
253
246
|
* @returns {module:engine/view/containerelement~ContainerElement} Created element.
|
|
@@ -263,10 +256,6 @@ export default class DowncastWriter {
|
|
|
263
256
|
|
|
264
257
|
const containerElement = new ContainerElement( this.document, name, attributes, children );
|
|
265
258
|
|
|
266
|
-
if ( options.isAllowedInsideAttributeElement !== undefined ) {
|
|
267
|
-
containerElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
259
|
if ( options.renderUnsafeAttributes ) {
|
|
271
260
|
containerElement._unsafeAttributesToRender.push( ...options.renderUnsafeAttributes );
|
|
272
261
|
}
|
|
@@ -310,9 +299,6 @@ export default class DowncastWriter {
|
|
|
310
299
|
* @param {String} name Name of the element.
|
|
311
300
|
* @param {Object} [attributes] Elements attributes.
|
|
312
301
|
* @param {Object} [options] Element's options.
|
|
313
|
-
* @param {Boolean} [options.isAllowedInsideAttributeElement=true] Whether an element is
|
|
314
|
-
* {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped
|
|
315
|
-
* with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.
|
|
316
302
|
* @param {Array.<String>} [options.renderUnsafeAttributes] A list of attribute names that should be rendered in the editing
|
|
317
303
|
* pipeline even though they would normally be filtered out by unsafe attribute detection mechanisms.
|
|
318
304
|
* @returns {module:engine/view/emptyelement~EmptyElement} Created element.
|
|
@@ -320,10 +306,6 @@ export default class DowncastWriter {
|
|
|
320
306
|
createEmptyElement( name, attributes, options = {} ) {
|
|
321
307
|
const emptyElement = new EmptyElement( this.document, name, attributes );
|
|
322
308
|
|
|
323
|
-
if ( options.isAllowedInsideAttributeElement !== undefined ) {
|
|
324
|
-
emptyElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
309
|
if ( options.renderUnsafeAttributes ) {
|
|
328
310
|
emptyElement._unsafeAttributesToRender.push( ...options.renderUnsafeAttributes );
|
|
329
311
|
}
|
|
@@ -354,23 +336,15 @@ export default class DowncastWriter {
|
|
|
354
336
|
* @param {String} name The name of the element.
|
|
355
337
|
* @param {Object} [attributes] Element attributes.
|
|
356
338
|
* @param {Function} [renderFunction] A custom render function.
|
|
357
|
-
* @param {Object} [options] Element's options.
|
|
358
|
-
* @param {Boolean} [options.isAllowedInsideAttributeElement=true] Whether an element is
|
|
359
|
-
* {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped
|
|
360
|
-
* with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.
|
|
361
339
|
* @returns {module:engine/view/uielement~UIElement} The created element.
|
|
362
340
|
*/
|
|
363
|
-
createUIElement( name, attributes, renderFunction
|
|
341
|
+
createUIElement( name, attributes, renderFunction ) {
|
|
364
342
|
const uiElement = new UIElement( this.document, name, attributes );
|
|
365
343
|
|
|
366
344
|
if ( renderFunction ) {
|
|
367
345
|
uiElement.render = renderFunction;
|
|
368
346
|
}
|
|
369
347
|
|
|
370
|
-
if ( options.isAllowedInsideAttributeElement !== undefined ) {
|
|
371
|
-
uiElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
348
|
return uiElement;
|
|
375
349
|
}
|
|
376
350
|
|
|
@@ -397,9 +371,6 @@ export default class DowncastWriter {
|
|
|
397
371
|
* @param {Object} [attributes] Element attributes.
|
|
398
372
|
* @param {Function} [renderFunction] A custom render function.
|
|
399
373
|
* @param {Object} [options] Element's options.
|
|
400
|
-
* @param {Boolean} [options.isAllowedInsideAttributeElement=true] Whether an element is
|
|
401
|
-
* {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped
|
|
402
|
-
* with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.
|
|
403
374
|
* @param {Array.<String>} [options.renderUnsafeAttributes] A list of attribute names that should be rendered in the editing
|
|
404
375
|
* pipeline even though they would normally be filtered out by unsafe attribute detection mechanisms.
|
|
405
376
|
* @returns {module:engine/view/rawelement~RawElement} The created element.
|
|
@@ -409,10 +380,6 @@ export default class DowncastWriter {
|
|
|
409
380
|
|
|
410
381
|
rawElement.render = renderFunction || ( () => {} );
|
|
411
382
|
|
|
412
|
-
if ( options.isAllowedInsideAttributeElement !== undefined ) {
|
|
413
|
-
rawElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
383
|
if ( options.renderUnsafeAttributes ) {
|
|
417
384
|
rawElement._unsafeAttributesToRender.push( ...options.renderUnsafeAttributes );
|
|
418
385
|
}
|
|
@@ -790,7 +757,7 @@ export default class DowncastWriter {
|
|
|
790
757
|
|
|
791
758
|
// Break attributes on nodes that do exist in the model tree so they can have attributes, other elements
|
|
792
759
|
// can't have an attribute in model and won't get wrapped with an AttributeElement while down-casted.
|
|
793
|
-
const breakAttributes = !
|
|
760
|
+
const breakAttributes = !node.is( 'uiElement' );
|
|
794
761
|
|
|
795
762
|
if ( !lastGroup || lastGroup.breakAttributes != breakAttributes ) {
|
|
796
763
|
groups.push( {
|
|
@@ -979,16 +946,6 @@ export default class DowncastWriter {
|
|
|
979
946
|
* Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-nonselection-collapsed-range` when passed range
|
|
980
947
|
* is collapsed and different than view selection.
|
|
981
948
|
*
|
|
982
|
-
* **Note:** Attribute elements by default can wrap {@link module:engine/view/text~Text},
|
|
983
|
-
* {@link module:engine/view/emptyelement~EmptyElement}, {@link module:engine/view/uielement~UIElement},
|
|
984
|
-
* {@link module:engine/view/rawelement~RawElement} and other attribute elements with higher priority. Other elements while placed
|
|
985
|
-
* inside an attribute element will split it (or nest it in case of an `AttributeElement`). This behavior can be modified by changing
|
|
986
|
-
* the `isAllowedInsideAttributeElement` option while using
|
|
987
|
-
* {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement},
|
|
988
|
-
* {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement},
|
|
989
|
-
* {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement} or
|
|
990
|
-
* {@link module:engine/view/downcastwriter~DowncastWriter#createRawElement}.
|
|
991
|
-
*
|
|
992
949
|
* @param {module:engine/view/range~Range} range Range to wrap.
|
|
993
950
|
* @param {module:engine/view/attributeelement~AttributeElement} attribute Attribute element to use as wrapper.
|
|
994
951
|
* @returns {module:engine/view/range~Range} range Range after wrapping, spanning over wrapping attribute element.
|
|
@@ -1399,7 +1356,6 @@ export default class DowncastWriter {
|
|
|
1399
1356
|
const child = parent.getChild( i );
|
|
1400
1357
|
const isText = child.is( '$text' );
|
|
1401
1358
|
const isAttribute = child.is( 'attributeElement' );
|
|
1402
|
-
const isAllowedInsideAttributeElement = child.isAllowedInsideAttributeElement;
|
|
1403
1359
|
|
|
1404
1360
|
//
|
|
1405
1361
|
// (In all examples, assume that `wrapElement` is `<span class="foo">` element.)
|
|
@@ -1418,7 +1374,7 @@ export default class DowncastWriter {
|
|
|
1418
1374
|
//
|
|
1419
1375
|
// <p>abc</p> --> <p><span class="foo">abc</span></p>
|
|
1420
1376
|
// <p><strong>abc</strong></p> --> <p><span class="foo"><strong>abc</strong></span></p>
|
|
1421
|
-
else if ( isText ||
|
|
1377
|
+
else if ( isText || !isAttribute || shouldABeOutsideB( wrapElement, child ) ) {
|
|
1422
1378
|
// Clone attribute.
|
|
1423
1379
|
const newAttribute = wrapElement._clone();
|
|
1424
1380
|
|
|
@@ -1436,7 +1392,7 @@ export default class DowncastWriter {
|
|
|
1436
1392
|
//
|
|
1437
1393
|
// <p><a href="foo.html">abc</a></p> --> <p><a href="foo.html"><span class="foo">abc</span></a></p>
|
|
1438
1394
|
//
|
|
1439
|
-
else if ( isAttribute ) {
|
|
1395
|
+
else /* if ( isAttribute ) */ {
|
|
1440
1396
|
this._wrapChildren( child, 0, child.childCount, wrapElement );
|
|
1441
1397
|
}
|
|
1442
1398
|
|
package/src/view/element.js
CHANGED
|
@@ -130,15 +130,6 @@ export default class Element extends Node {
|
|
|
130
130
|
*/
|
|
131
131
|
this._customProperties = new Map();
|
|
132
132
|
|
|
133
|
-
/**
|
|
134
|
-
* Whether an element is allowed inside an AttributeElement and can be wrapped with
|
|
135
|
-
* {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.
|
|
136
|
-
*
|
|
137
|
-
* @protected
|
|
138
|
-
* @member {Boolean}
|
|
139
|
-
*/
|
|
140
|
-
this._isAllowedInsideAttributeElement = false;
|
|
141
|
-
|
|
142
133
|
/**
|
|
143
134
|
* A list of attribute names that should be rendered in the editing pipeline even though filtering mechanisms
|
|
144
135
|
* implemented in the {@link module:engine/view/domconverter~DomConverter} (for instance,
|
|
@@ -175,17 +166,6 @@ export default class Element extends Node {
|
|
|
175
166
|
return this._children.length === 0;
|
|
176
167
|
}
|
|
177
168
|
|
|
178
|
-
/**
|
|
179
|
-
* Whether the element is allowed inside an AttributeElement and can be wrapped with
|
|
180
|
-
* {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.
|
|
181
|
-
*
|
|
182
|
-
* @readonly
|
|
183
|
-
* @type {Boolean}
|
|
184
|
-
*/
|
|
185
|
-
get isAllowedInsideAttributeElement() {
|
|
186
|
-
return this._isAllowedInsideAttributeElement;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
169
|
/**
|
|
190
170
|
* Checks whether this object is of the given.
|
|
191
171
|
*
|
|
@@ -350,11 +330,6 @@ export default class Element extends Node {
|
|
|
350
330
|
return false;
|
|
351
331
|
}
|
|
352
332
|
|
|
353
|
-
// Check isAllowedInsideAttributeElement property.
|
|
354
|
-
if ( this.isAllowedInsideAttributeElement != otherElement.isAllowedInsideAttributeElement ) {
|
|
355
|
-
return false;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
333
|
// Check number of attributes, classes and styles.
|
|
359
334
|
if ( this._attrs.size !== otherElement._attrs.size || this._classes.size !== otherElement._classes.size ||
|
|
360
335
|
this._styles.size !== otherElement._styles.size ) {
|
|
@@ -633,8 +608,6 @@ export default class Element extends Node {
|
|
|
633
608
|
// is changed by e.g. toWidget() function from ckeditor5-widget. Perhaps this should be one of custom props.
|
|
634
609
|
cloned.getFillerOffset = this.getFillerOffset;
|
|
635
610
|
|
|
636
|
-
cloned._isAllowedInsideAttributeElement = this.isAllowedInsideAttributeElement;
|
|
637
|
-
|
|
638
611
|
return cloned;
|
|
639
612
|
}
|
|
640
613
|
|
package/src/view/emptyelement.js
CHANGED
|
@@ -37,9 +37,6 @@ export default class EmptyElement extends Element {
|
|
|
37
37
|
constructor( document, name, attrs, children ) {
|
|
38
38
|
super( document, name, attrs, children );
|
|
39
39
|
|
|
40
|
-
// Override the default of the base class.
|
|
41
|
-
this._isAllowedInsideAttributeElement = true;
|
|
42
|
-
|
|
43
40
|
/**
|
|
44
41
|
* Returns `null` because filler is not needed for EmptyElements.
|
|
45
42
|
*
|
package/src/view/matcher.js
CHANGED
|
@@ -739,7 +739,7 @@ function matchStyles( patterns, element ) {
|
|
|
739
739
|
* styles: /^border.*$/
|
|
740
740
|
* }
|
|
741
741
|
*
|
|
742
|
-
* Refer to the {@glink
|
|
742
|
+
* Refer to the {@glink updating/migration-to-29##migration-to-ckeditor-5-v2910 Migration to v29.1.0} guide
|
|
743
743
|
* and {@link module:engine/view/matcher~MatcherPattern} documentation.
|
|
744
744
|
*
|
|
745
745
|
* @param {Object} pattern Pattern with missing properties.
|
|
@@ -769,7 +769,7 @@ function matchStyles( patterns, element ) {
|
|
|
769
769
|
* classes: 'foobar'
|
|
770
770
|
* }
|
|
771
771
|
*
|
|
772
|
-
* Refer to the {@glink
|
|
772
|
+
* Refer to the {@glink updating/migration-to-29##migration-to-ckeditor-5-v2910 Migration to v29.1.0} guide
|
|
773
773
|
* and the {@link module:engine/view/matcher~MatcherPattern} documentation.
|
|
774
774
|
*
|
|
775
775
|
* @param {Object} pattern Pattern with missing properties.
|
|
@@ -0,0 +1,68 @@
|
|
|
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 engine/view/observer/tabobserver
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import Observer from './observer';
|
|
11
|
+
import BubblingEventInfo from './bubblingeventinfo';
|
|
12
|
+
|
|
13
|
+
import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Tab observer introduces the {@link module:engine/view/document~Document#event:tab `Document#tab`} event.
|
|
17
|
+
*
|
|
18
|
+
* Note that because {@link module:engine/view/observer/tabobserver~TabObserver} is attached by the
|
|
19
|
+
* {@link module:engine/view/view~View} this event is available by default.
|
|
20
|
+
*
|
|
21
|
+
* @extends module:engine/view/observer/observer~Observer
|
|
22
|
+
*/
|
|
23
|
+
export default class TabObserver extends Observer {
|
|
24
|
+
/**
|
|
25
|
+
* @inheritDoc
|
|
26
|
+
*/
|
|
27
|
+
constructor( view ) {
|
|
28
|
+
super( view );
|
|
29
|
+
|
|
30
|
+
const doc = this.document;
|
|
31
|
+
|
|
32
|
+
doc.on( 'keydown', ( evt, data ) => {
|
|
33
|
+
if (
|
|
34
|
+
!this.isEnabled ||
|
|
35
|
+
data.keyCode != keyCodes.tab ||
|
|
36
|
+
data.ctrlKey
|
|
37
|
+
) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const event = new BubblingEventInfo( doc, 'tab', doc.selection.getFirstRange() );
|
|
42
|
+
|
|
43
|
+
doc.fire( event, data );
|
|
44
|
+
|
|
45
|
+
if ( event.stop.called ) {
|
|
46
|
+
evt.stop();
|
|
47
|
+
}
|
|
48
|
+
} );
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @inheritDoc
|
|
53
|
+
*/
|
|
54
|
+
observe() {}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Event fired when the user presses a tab key.
|
|
59
|
+
*
|
|
60
|
+
* Introduced by {@link module:engine/view/observer/tabobserver~TabObserver}.
|
|
61
|
+
*
|
|
62
|
+
* Note that because {@link module:engine/view/observer/tabobserver~TabObserver} is attached by the
|
|
63
|
+
* {@link module:engine/view/view~View} this event is available by default.
|
|
64
|
+
*
|
|
65
|
+
* @event module:engine/view/document~Document#event:tab
|
|
66
|
+
*
|
|
67
|
+
* @param {module:engine/view/observer/domeventdata~DomEventData} data
|
|
68
|
+
*/
|
package/src/view/placeholder.js
CHANGED
|
@@ -276,7 +276,7 @@ function getChildPlaceholderHostSubstitute( parent ) {
|
|
|
276
276
|
if ( parent.childCount ) {
|
|
277
277
|
const firstChild = parent.getChild( 0 );
|
|
278
278
|
|
|
279
|
-
if ( firstChild.is( 'element' ) && !firstChild.is( 'uiElement' ) ) {
|
|
279
|
+
if ( firstChild.is( 'element' ) && !firstChild.is( 'uiElement' ) && !firstChild.is( 'attributeElement' ) ) {
|
|
280
280
|
return firstChild;
|
|
281
281
|
}
|
|
282
282
|
}
|
package/src/view/rawelement.js
CHANGED
|
@@ -47,9 +47,6 @@ export default class RawElement extends Element {
|
|
|
47
47
|
constructor( document, name, attrs, children ) {
|
|
48
48
|
super( document, name, attrs, children );
|
|
49
49
|
|
|
50
|
-
// Override the default of the base class.
|
|
51
|
-
this._isAllowedInsideAttributeElement = true;
|
|
52
|
-
|
|
53
50
|
/**
|
|
54
51
|
* Returns `null` because filler is not needed for raw elements.
|
|
55
52
|
*
|
package/src/view/uielement.js
CHANGED
|
@@ -50,9 +50,6 @@ export default class UIElement extends Element {
|
|
|
50
50
|
constructor( document, name, attributes, children ) {
|
|
51
51
|
super( document, name, attributes, children );
|
|
52
52
|
|
|
53
|
-
// Override the default of the base class.
|
|
54
|
-
this._isAllowedInsideAttributeElement = true;
|
|
55
|
-
|
|
56
53
|
/**
|
|
57
54
|
* Returns `null` because filler is not needed for UIElements.
|
|
58
55
|
*
|
package/src/view/view.js
CHANGED
|
@@ -23,6 +23,7 @@ import FocusObserver from './observer/focusobserver';
|
|
|
23
23
|
import CompositionObserver from './observer/compositionobserver';
|
|
24
24
|
import InputObserver from './observer/inputobserver';
|
|
25
25
|
import ArrowKeysObserver from './observer/arrowkeysobserver';
|
|
26
|
+
import TabObserver from './observer/tabobserver';
|
|
26
27
|
|
|
27
28
|
import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
|
|
28
29
|
import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
@@ -54,6 +55,8 @@ import env from '@ckeditor/ckeditor5-utils/src/env';
|
|
|
54
55
|
* * {@link module:engine/view/observer/keyobserver~KeyObserver},
|
|
55
56
|
* * {@link module:engine/view/observer/fakeselectionobserver~FakeSelectionObserver}.
|
|
56
57
|
* * {@link module:engine/view/observer/compositionobserver~CompositionObserver}.
|
|
58
|
+
* * {@link module:engine/view/observer/arrowkeysobserver~ArrowKeysObserver}.
|
|
59
|
+
* * {@link module:engine/view/observer/tabobserver~TabObserver}.
|
|
57
60
|
*
|
|
58
61
|
* This class also {@link module:engine/view/view~View#attachDomRoot binds the DOM and the view elements}.
|
|
59
62
|
*
|
|
@@ -186,6 +189,7 @@ export default class View {
|
|
|
186
189
|
this.addObserver( FakeSelectionObserver );
|
|
187
190
|
this.addObserver( CompositionObserver );
|
|
188
191
|
this.addObserver( ArrowKeysObserver );
|
|
192
|
+
this.addObserver( TabObserver );
|
|
189
193
|
|
|
190
194
|
if ( env.isAndroid ) {
|
|
191
195
|
this.addObserver( InputObserver );
|