@ckeditor/ckeditor5-engine 37.0.0-alpha.3 → 37.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/package.json +23 -23
- package/src/controller/datacontroller.d.ts +3 -0
- package/src/controller/datacontroller.js +16 -1
- package/src/index.d.ts +4 -2
- package/src/index.js +4 -0
- package/src/model/differ.d.ts +52 -8
- package/src/model/differ.js +104 -4
- package/src/model/document.d.ts +17 -7
- package/src/model/document.js +44 -5
- package/src/model/documentfragment.d.ts +4 -0
- package/src/model/documentfragment.js +6 -0
- package/src/model/node.d.ts +4 -4
- package/src/model/node.js +9 -5
- package/src/model/operation/attributeoperation.d.ts +1 -1
- package/src/model/operation/attributeoperation.js +1 -1
- package/src/model/operation/insertoperation.d.ts +1 -1
- package/src/model/operation/insertoperation.js +1 -1
- package/src/model/operation/mergeoperation.d.ts +1 -1
- package/src/model/operation/mergeoperation.js +1 -1
- package/src/model/operation/moveoperation.d.ts +1 -1
- package/src/model/operation/moveoperation.js +1 -1
- package/src/model/operation/operation.d.ts +1 -1
- package/src/model/operation/operation.js +1 -1
- package/src/model/operation/operationfactory.js +2 -0
- package/src/model/operation/rootattributeoperation.d.ts +7 -11
- package/src/model/operation/rootattributeoperation.js +6 -6
- package/src/model/operation/rootoperation.d.ts +75 -0
- package/src/model/operation/rootoperation.js +108 -0
- package/src/model/operation/splitoperation.d.ts +1 -1
- package/src/model/operation/splitoperation.js +1 -1
- package/src/model/operation/transform.js +8 -0
- package/src/model/rootelement.d.ts +15 -1
- package/src/model/rootelement.js +17 -1
- package/src/model/writer.d.ts +29 -1
- package/src/model/writer.js +74 -1
- package/src/view/matcher.d.ts +2 -2
- package/src/view/matcher.js +2 -2
- package/src/view/observer/arrowkeysobserver.d.ts +4 -0
- package/src/view/observer/arrowkeysobserver.js +4 -0
- package/src/view/observer/domeventobserver.d.ts +4 -0
- package/src/view/observer/domeventobserver.js +6 -0
- package/src/view/observer/fakeselectionobserver.d.ts +4 -0
- package/src/view/observer/fakeselectionobserver.js +4 -0
- package/src/view/observer/mutationobserver.d.ts +4 -0
- package/src/view/observer/mutationobserver.js +16 -2
- package/src/view/observer/observer.d.ts +7 -2
- package/src/view/observer/selectionobserver.d.ts +4 -0
- package/src/view/observer/selectionobserver.js +6 -0
- package/src/view/observer/tabobserver.d.ts +4 -0
- package/src/view/observer/tabobserver.js +4 -0
- package/src/view/placeholder.js +3 -3
- package/src/view/renderer.d.ts +4 -4
- package/src/view/renderer.js +17 -25
- package/src/view/view.js +3 -0
package/src/model/writer.js
CHANGED
|
@@ -13,6 +13,7 @@ import MergeOperation from './operation/mergeoperation';
|
|
|
13
13
|
import MoveOperation from './operation/moveoperation';
|
|
14
14
|
import RenameOperation from './operation/renameoperation';
|
|
15
15
|
import RootAttributeOperation from './operation/rootattributeoperation';
|
|
16
|
+
import RootOperation from './operation/rootoperation';
|
|
16
17
|
import SplitOperation from './operation/splitoperation';
|
|
17
18
|
import DocumentFragment from './documentfragment';
|
|
18
19
|
import DocumentSelection from './documentselection';
|
|
@@ -361,7 +362,7 @@ export default class Writer {
|
|
|
361
362
|
* writer.move( sourceRange, image, 'after' );
|
|
362
363
|
* ```
|
|
363
364
|
*
|
|
364
|
-
* These parameters
|
|
365
|
+
* These parameters work the same way as {@link #createPositionAt `writer.createPositionAt()`}.
|
|
365
366
|
*
|
|
366
367
|
* Note that items can be moved only within the same tree. It means that you can move items within the same root
|
|
367
368
|
* (element or document fragment) or between {@link module:engine/model/document~Document#roots documents roots},
|
|
@@ -917,6 +918,78 @@ export default class Writer {
|
|
|
917
918
|
const oldRange = marker.getRange();
|
|
918
919
|
applyMarkerOperation(this, name, oldRange, null, marker.affectsData);
|
|
919
920
|
}
|
|
921
|
+
/**
|
|
922
|
+
* Adds a new root to the document (or re-attaches a {@link #detachRoot detached root}).
|
|
923
|
+
*
|
|
924
|
+
* Throws an error, if trying to add a root that is already added and attached.
|
|
925
|
+
*
|
|
926
|
+
* @param rootName Name of the added root.
|
|
927
|
+
* @param elementName The element name. Defaults to `'$root'` which also has some basic schema defined
|
|
928
|
+
* (e.g. `$block` elements are allowed inside the `$root`). Make sure to define a proper schema if you use a different name.
|
|
929
|
+
* @returns The added root element.
|
|
930
|
+
*/
|
|
931
|
+
addRoot(rootName, elementName = '$root') {
|
|
932
|
+
this._assertWriterUsedCorrectly();
|
|
933
|
+
const root = this.model.document.getRoot(rootName);
|
|
934
|
+
if (root && root.isAttached()) {
|
|
935
|
+
/**
|
|
936
|
+
* Root with provided name already exists and is attached.
|
|
937
|
+
*
|
|
938
|
+
* @error writer-addroot-root-exists
|
|
939
|
+
*/
|
|
940
|
+
throw new CKEditorError('writer-addroot-root-exists', this);
|
|
941
|
+
}
|
|
942
|
+
const document = this.model.document;
|
|
943
|
+
const operation = new RootOperation(rootName, elementName, true, document, document.version);
|
|
944
|
+
this.batch.addOperation(operation);
|
|
945
|
+
this.model.applyOperation(operation);
|
|
946
|
+
return this.model.document.getRoot(rootName);
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Detaches the root from the document.
|
|
950
|
+
*
|
|
951
|
+
* All content and markers are removed from the root upon detaching. New content and new markers cannot be added to the root, as long
|
|
952
|
+
* as it is detached.
|
|
953
|
+
*
|
|
954
|
+
* A root cannot be fully removed from the document, it can be only detached. A root is permanently removed only after you
|
|
955
|
+
* re-initialize the editor and do not specify the root in the initial data.
|
|
956
|
+
*
|
|
957
|
+
* A detached root can be re-attached using {@link #addRoot}.
|
|
958
|
+
*
|
|
959
|
+
* Throws an error if the root does not exist or the root is already detached.
|
|
960
|
+
*
|
|
961
|
+
* @param rootOrName Name of the detached root.
|
|
962
|
+
*/
|
|
963
|
+
detachRoot(rootOrName) {
|
|
964
|
+
this._assertWriterUsedCorrectly();
|
|
965
|
+
const root = typeof rootOrName == 'string' ? this.model.document.getRoot(rootOrName) : rootOrName;
|
|
966
|
+
if (!root || !root.isAttached()) {
|
|
967
|
+
/**
|
|
968
|
+
* Root with provided name does not exist or is already detached.
|
|
969
|
+
*
|
|
970
|
+
* @error writer-detachroot-no-root
|
|
971
|
+
*/
|
|
972
|
+
throw new CKEditorError('writer-detachroot-no-root', this);
|
|
973
|
+
}
|
|
974
|
+
// First, remove all markers from the root. It is better to do it before removing stuff for undo purposes.
|
|
975
|
+
// However, looking through all the markers may not be the best performance wise. But there's no better solution for now.
|
|
976
|
+
for (const marker of this.model.markers) {
|
|
977
|
+
if (marker.getRange().root === root) {
|
|
978
|
+
this.removeMarker(marker);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
// Remove all attributes from the root.
|
|
982
|
+
for (const key of root.getAttributeKeys()) {
|
|
983
|
+
this.removeAttribute(key, root);
|
|
984
|
+
}
|
|
985
|
+
// Remove all contents of the root.
|
|
986
|
+
this.remove(this.createRangeIn(root));
|
|
987
|
+
// Finally, detach the root.
|
|
988
|
+
const document = this.model.document;
|
|
989
|
+
const operation = new RootOperation(root.rootName, root.name, false, document, document.version);
|
|
990
|
+
this.batch.addOperation(operation);
|
|
991
|
+
this.model.applyOperation(operation);
|
|
992
|
+
}
|
|
920
993
|
setSelection(...args) {
|
|
921
994
|
this._assertWriterUsedCorrectly();
|
|
922
995
|
this.model.document.selection._setTo(...args);
|
package/src/view/matcher.d.ts
CHANGED
|
@@ -447,7 +447,7 @@ export type ClassPatterns = PropertyPatterns<never>;
|
|
|
447
447
|
* }
|
|
448
448
|
* ```
|
|
449
449
|
*
|
|
450
|
-
* Refer to the {@glink updating/
|
|
450
|
+
* Refer to the {@glink updating/guides/update-to-29##update-to-ckeditor-5-v2910 Migration to v29.1.0} guide
|
|
451
451
|
* and {@link module:engine/view/matcher~MatcherPattern} documentation.
|
|
452
452
|
*
|
|
453
453
|
* @param pattern Pattern with missing properties.
|
|
@@ -478,7 +478,7 @@ export type ClassPatterns = PropertyPatterns<never>;
|
|
|
478
478
|
* }
|
|
479
479
|
* ```
|
|
480
480
|
*
|
|
481
|
-
* Refer to the {@glink updating/
|
|
481
|
+
* Refer to the {@glink updating/guides/update-to-29##update-to-ckeditor-5-v2910 Migration to v29.1.0} guide
|
|
482
482
|
* and the {@link module:engine/view/matcher~MatcherPattern} documentation.
|
|
483
483
|
*
|
|
484
484
|
* @param pattern Pattern with missing properties.
|
package/src/view/matcher.js
CHANGED
|
@@ -468,7 +468,7 @@ function matchStyles(patterns, element) {
|
|
|
468
468
|
* }
|
|
469
469
|
* ```
|
|
470
470
|
*
|
|
471
|
-
* Refer to the {@glink updating/
|
|
471
|
+
* Refer to the {@glink updating/guides/update-to-29##update-to-ckeditor-5-v2910 Migration to v29.1.0} guide
|
|
472
472
|
* and {@link module:engine/view/matcher~MatcherPattern} documentation.
|
|
473
473
|
*
|
|
474
474
|
* @param pattern Pattern with missing properties.
|
|
@@ -499,7 +499,7 @@ function matchStyles(patterns, element) {
|
|
|
499
499
|
* }
|
|
500
500
|
* ```
|
|
501
501
|
*
|
|
502
|
-
* Refer to the {@glink updating/
|
|
502
|
+
* Refer to the {@glink updating/guides/update-to-29##update-to-ckeditor-5-v2910 Migration to v29.1.0} guide
|
|
503
503
|
* and the {@link module:engine/view/matcher~MatcherPattern} documentation.
|
|
504
504
|
*
|
|
505
505
|
* @param pattern Pattern with missing properties.
|
|
@@ -56,6 +56,10 @@ export default abstract class DomEventObserver<EventType extends keyof HTMLEleme
|
|
|
56
56
|
* @inheritDoc
|
|
57
57
|
*/
|
|
58
58
|
observe(domElement: HTMLElement): void;
|
|
59
|
+
/**
|
|
60
|
+
* @inheritDoc
|
|
61
|
+
*/
|
|
62
|
+
stopObserving(domElement: HTMLElement): void;
|
|
59
63
|
/**
|
|
60
64
|
* Calls `Document#fire()` if observer {@link #isEnabled is enabled}.
|
|
61
65
|
*
|
|
@@ -56,6 +56,12 @@ export default class DomEventObserver extends Observer {
|
|
|
56
56
|
}, { useCapture: this.useCapture });
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* @inheritDoc
|
|
61
|
+
*/
|
|
62
|
+
stopObserving(domElement) {
|
|
63
|
+
this.stopListening(domElement);
|
|
64
|
+
}
|
|
59
65
|
/**
|
|
60
66
|
* Calls `Document#fire()` if observer {@link #isEnabled is enabled}.
|
|
61
67
|
*
|
|
@@ -33,7 +33,7 @@ export default class MutationObserver extends Observer {
|
|
|
33
33
|
};
|
|
34
34
|
this.domConverter = view.domConverter;
|
|
35
35
|
this.renderer = view._renderer;
|
|
36
|
-
this._domElements =
|
|
36
|
+
this._domElements = new Set();
|
|
37
37
|
this._mutationObserver = new window.MutationObserver(this._onMutations.bind(this));
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
@@ -46,11 +46,25 @@ export default class MutationObserver extends Observer {
|
|
|
46
46
|
* @inheritDoc
|
|
47
47
|
*/
|
|
48
48
|
observe(domElement) {
|
|
49
|
-
this._domElements.
|
|
49
|
+
this._domElements.add(domElement);
|
|
50
50
|
if (this.isEnabled) {
|
|
51
51
|
this._mutationObserver.observe(domElement, this._config);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* @inheritDoc
|
|
56
|
+
*/
|
|
57
|
+
stopObserving(domElement) {
|
|
58
|
+
this._domElements.delete(domElement);
|
|
59
|
+
if (this.isEnabled) {
|
|
60
|
+
// Unfortunately, it is not possible to stop observing particular DOM element.
|
|
61
|
+
// In order to stop observing one of multiple DOM elements, we need to re-connect the mutation observer.
|
|
62
|
+
this._mutationObserver.disconnect();
|
|
63
|
+
for (const domElement of this._domElements) {
|
|
64
|
+
this._mutationObserver.observe(domElement, this._config);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
54
68
|
/**
|
|
55
69
|
* @inheritDoc
|
|
56
70
|
*/
|
|
@@ -71,11 +71,16 @@ export default abstract class Observer extends Observer_base {
|
|
|
71
71
|
*/
|
|
72
72
|
checkShouldIgnoreEventFromTarget(domTarget: Node | null): boolean;
|
|
73
73
|
/**
|
|
74
|
-
* Starts observing
|
|
74
|
+
* Starts observing given DOM element.
|
|
75
75
|
*
|
|
76
|
-
* @param
|
|
76
|
+
* @param domElement DOM element to observe.
|
|
77
|
+
* @param name The name of the related root element.
|
|
77
78
|
*/
|
|
78
79
|
abstract observe(domElement: HTMLElement, name: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* Stops observing given DOM element.
|
|
82
|
+
*/
|
|
83
|
+
abstract stopObserving(domElement: HTMLElement): void;
|
|
79
84
|
}
|
|
80
85
|
/**
|
|
81
86
|
* The constructor of {@link ~Observer} subclass.
|
|
@@ -101,6 +101,12 @@ export default class SelectionObserver extends Observer {
|
|
|
101
101
|
});
|
|
102
102
|
this._documents.add(domDocument);
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* @inheritDoc
|
|
106
|
+
*/
|
|
107
|
+
stopObserving(domElement) {
|
|
108
|
+
this.stopListening(domElement);
|
|
109
|
+
}
|
|
104
110
|
/**
|
|
105
111
|
* @inheritDoc
|
|
106
112
|
*/
|
package/src/view/placeholder.js
CHANGED
|
@@ -56,10 +56,10 @@ export function enablePlaceholder({ view, element, text, isDirectHost = true, ke
|
|
|
56
56
|
*/
|
|
57
57
|
export function disablePlaceholder(view, element) {
|
|
58
58
|
const doc = element.document;
|
|
59
|
+
if (!documentPlaceholders.has(doc)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
59
62
|
view.change(writer => {
|
|
60
|
-
if (!documentPlaceholders.has(doc)) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
63
|
const placeholders = documentPlaceholders.get(doc);
|
|
64
64
|
const config = placeholders.get(element);
|
|
65
65
|
writer.removeAttribute('data-placeholder', config.hostElement);
|
package/src/view/renderer.d.ts
CHANGED
|
@@ -208,11 +208,11 @@ export default class Renderer extends Renderer_base {
|
|
|
208
208
|
* @param actions Actions array which is a result of the {@link module:utils/diff~diff} function.
|
|
209
209
|
* @param actualDom Actual DOM children
|
|
210
210
|
* @param expectedDom Expected DOM children.
|
|
211
|
-
* @param
|
|
212
|
-
*
|
|
213
|
-
* @returns Actions array modified with the `
|
|
211
|
+
* @param comparator A comparator function that should return `true` if the given node should be reused
|
|
212
|
+
* (either by the update of a text node data or an element children list for similar elements).
|
|
213
|
+
* @returns Actions array modified with the `update` actions.
|
|
214
214
|
*/
|
|
215
|
-
private
|
|
215
|
+
private _findUpdateActions;
|
|
216
216
|
/**
|
|
217
217
|
* Marks text nodes to be synchronized.
|
|
218
218
|
*
|
package/src/view/renderer.js
CHANGED
|
@@ -261,11 +261,11 @@ export default class Renderer extends ObservableMixin() {
|
|
|
261
261
|
const actualDomChildren = Array.from(this.domConverter.mapViewToDom(viewElement).childNodes);
|
|
262
262
|
const expectedDomChildren = Array.from(this.domConverter.viewChildrenToDom(viewElement, { withChildren: false }));
|
|
263
263
|
const diff = this._diffNodeLists(actualDomChildren, expectedDomChildren);
|
|
264
|
-
const actions = this.
|
|
265
|
-
if (actions.indexOf('
|
|
264
|
+
const actions = this._findUpdateActions(diff, actualDomChildren, expectedDomChildren, areSimilarElements);
|
|
265
|
+
if (actions.indexOf('update') !== -1) {
|
|
266
266
|
const counter = { equal: 0, insert: 0, delete: 0 };
|
|
267
267
|
for (const action of actions) {
|
|
268
|
-
if (action === '
|
|
268
|
+
if (action === 'update') {
|
|
269
269
|
const insertIndex = counter.equal + counter.insert;
|
|
270
270
|
const deleteIndex = counter.equal + counter.delete;
|
|
271
271
|
const viewChild = viewElement.getChild(insertIndex);
|
|
@@ -512,17 +512,9 @@ export default class Renderer extends ObservableMixin() {
|
|
|
512
512
|
addInlineFiller(domElement.ownerDocument, expectedDomChildren, inlineFillerPosition.offset);
|
|
513
513
|
}
|
|
514
514
|
const diff = this._diffNodeLists(actualDomChildren, expectedDomChildren);
|
|
515
|
-
//
|
|
516
|
-
//
|
|
517
|
-
|
|
518
|
-
// and we should not do it because the difference between view and DOM could lead to position mapping problems.
|
|
519
|
-
// Since the composition is fragile and often breaks if the composed text node is replaced while composing
|
|
520
|
-
// we need to make sure that we update the existing text node and not replace it with another one.
|
|
521
|
-
// We don't want to change the behavior on other browsers for safety, but maybe one day cause it seems to make sense.
|
|
522
|
-
// https://github.com/ckeditor/ckeditor5/issues/12455.
|
|
523
|
-
const actions = env.isAndroid ?
|
|
524
|
-
this._findReplaceActions(diff, actualDomChildren, expectedDomChildren, { replaceText: true }) :
|
|
525
|
-
diff;
|
|
515
|
+
// We need to make sure that we update the existing text node and not replace it with another one.
|
|
516
|
+
// The composition and different "language" browser extensions are fragile to text node being completely replaced.
|
|
517
|
+
const actions = this._findUpdateActions(diff, actualDomChildren, expectedDomChildren, areTextNodes);
|
|
526
518
|
let i = 0;
|
|
527
519
|
const nodesToUnbind = new Set();
|
|
528
520
|
// Handle deletions first.
|
|
@@ -541,7 +533,7 @@ export default class Renderer extends ObservableMixin() {
|
|
|
541
533
|
nodesToUnbind.add(actualDomChildren[i]);
|
|
542
534
|
remove(actualDomChildren[i]);
|
|
543
535
|
}
|
|
544
|
-
else if (action === 'equal' || action === '
|
|
536
|
+
else if (action === 'equal' || action === 'update') {
|
|
545
537
|
i++;
|
|
546
538
|
}
|
|
547
539
|
}
|
|
@@ -557,7 +549,7 @@ export default class Renderer extends ObservableMixin() {
|
|
|
557
549
|
i++;
|
|
558
550
|
}
|
|
559
551
|
// Update the existing text node data. Note that replace action is generated only for Android for now.
|
|
560
|
-
else if (action === '
|
|
552
|
+
else if (action === 'update') {
|
|
561
553
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
562
554
|
// @if CK_DEBUG_TYPING // console.group( '%c[Renderer]%c Update text node',
|
|
563
555
|
// @if CK_DEBUG_TYPING // 'color: green;font-weight: bold', ''
|
|
@@ -613,11 +605,11 @@ export default class Renderer extends ObservableMixin() {
|
|
|
613
605
|
* @param actions Actions array which is a result of the {@link module:utils/diff~diff} function.
|
|
614
606
|
* @param actualDom Actual DOM children
|
|
615
607
|
* @param expectedDom Expected DOM children.
|
|
616
|
-
* @param
|
|
617
|
-
*
|
|
618
|
-
* @returns Actions array modified with the `
|
|
608
|
+
* @param comparator A comparator function that should return `true` if the given node should be reused
|
|
609
|
+
* (either by the update of a text node data or an element children list for similar elements).
|
|
610
|
+
* @returns Actions array modified with the `update` actions.
|
|
619
611
|
*/
|
|
620
|
-
|
|
612
|
+
_findUpdateActions(actions, actualDom, expectedDom, comparator) {
|
|
621
613
|
// If there is no both 'insert' and 'delete' actions, no need to check for replaced elements.
|
|
622
614
|
if (actions.indexOf('insert') === -1 || actions.indexOf('delete') === -1) {
|
|
623
615
|
return actions;
|
|
@@ -634,8 +626,8 @@ export default class Renderer extends ObservableMixin() {
|
|
|
634
626
|
actualSlice.push(actualDom[counter.equal + counter.delete]);
|
|
635
627
|
}
|
|
636
628
|
else { // equal
|
|
637
|
-
newActions = newActions.concat(diff(actualSlice, expectedSlice,
|
|
638
|
-
.map(
|
|
629
|
+
newActions = newActions.concat(diff(actualSlice, expectedSlice, comparator)
|
|
630
|
+
.map(action => action === 'equal' ? 'update' : action));
|
|
639
631
|
newActions.push('equal');
|
|
640
632
|
// Reset stored elements on 'equal'.
|
|
641
633
|
actualSlice = [];
|
|
@@ -643,8 +635,8 @@ export default class Renderer extends ObservableMixin() {
|
|
|
643
635
|
}
|
|
644
636
|
counter[action]++;
|
|
645
637
|
}
|
|
646
|
-
return newActions.concat(diff(actualSlice, expectedSlice,
|
|
647
|
-
.map(
|
|
638
|
+
return newActions.concat(diff(actualSlice, expectedSlice, comparator)
|
|
639
|
+
.map(action => action === 'equal' ? 'update' : action));
|
|
648
640
|
}
|
|
649
641
|
/**
|
|
650
642
|
* Marks text nodes to be synchronized.
|
|
@@ -879,7 +871,7 @@ function addInlineFiller(domDocument, domParentOrArray, offset) {
|
|
|
879
871
|
* Whether two DOM nodes should be considered as similar.
|
|
880
872
|
* Nodes are considered similar if they have the same tag name.
|
|
881
873
|
*/
|
|
882
|
-
function
|
|
874
|
+
function areSimilarElements(node1, node2) {
|
|
883
875
|
return isNode(node1) && isNode(node2) &&
|
|
884
876
|
!isText(node1) && !isText(node2) &&
|
|
885
877
|
!isComment(node1) && !isComment(node2) &&
|
package/src/view/view.js
CHANGED
|
@@ -215,6 +215,9 @@ export default class View extends ObservableMixin() {
|
|
|
215
215
|
}
|
|
216
216
|
this.domRoots.delete(name);
|
|
217
217
|
this.domConverter.unbindDomElement(domRoot);
|
|
218
|
+
for (const observer of this._observers.values()) {
|
|
219
|
+
observer.stopObserving(domRoot);
|
|
220
|
+
}
|
|
218
221
|
}
|
|
219
222
|
/**
|
|
220
223
|
* Gets DOM root element.
|