Преглед на файлове

Removed createRoot() and changed attachDomRoot() in ViewDocument.

Oskar Wróbel преди 8 години
родител
ревизия
cec344851b

+ 20 - 53
packages/ckeditor5-engine/src/view/document.js

@@ -10,7 +10,6 @@
 import Selection from './selection';
 import Renderer from './renderer';
 import DomConverter from './domconverter';
-import RootEditableElement from './rooteditableelement';
 import { injectQuirksHandling } from './filler';
 import { injectUiElementHandling } from './uielement';
 import log from '@ckeditor/ckeditor5-utils/src/log';
@@ -19,6 +18,7 @@ import SelectionObserver from './observer/selectionobserver';
 import FocusObserver from './observer/focusobserver';
 import KeyObserver from './observer/keyobserver';
 import FakeSelectionObserver from './observer/fakeselectionobserver';
+import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
 import { scrollViewportToShowTarget } from '@ckeditor/ckeditor5-utils/src/dom/scroll';
@@ -76,10 +76,15 @@ export default class Document {
 		/**
 		 * Roots of the view tree. Map of the {module:engine/view/element~Element view elements} with roots names as keys.
 		 *
+		 * View roots are created as a result of binding between {@link module:engine/view/document~Document#roots} and
+		 * {@link module:engine/model/document~Document#roots} and this is handled by
+		 * {@link modeule:engine/controller/editingcontroller~EditingController}, so to create view root we need to create
+		 * model root using {@link module:engine/model/document~Document#createRoot}.
+		 *
 		 * @readonly
 		 * @member {Map} module:engine/view/document~Document#roots
 		 */
-		this.roots = new Map();
+		this.roots = new Collection( { idProperty: 'rootName' } );
 
 		/**
 		 * Defines whether document is in read-only mode.
@@ -177,69 +182,31 @@ export default class Document {
 	}
 
 	/**
-	 * Creates a {@link module:engine/view/document~Document#roots view root element}.
-	 *
-	 * If the DOM element is passed as a first parameter it will be automatically
-	 * {@link module:engine/view/document~Document#attachDomRoot attached}:
-	 *
-	 *		document.createRoot( document.querySelector( 'div#editor' ) ); // Will call document.attachDomRoot.
-	 *
-	 * However, if the string is passed, then only the view element will be created and the DOM element have to be
-	 * attached separately:
-	 *
-	 *		document.createRoot( 'body' );
-	 *		document.attachDomRoot( document.querySelector( 'body#editor' ) );
-	 *
-	 * In both cases, {@link module:engine/view/rooteditableelement~RootEditableElement#rootName element name} is always
-	 * transformed to lower
-	 * case.
-	 *
-	 * @param {Element|String} domRoot DOM root element or the tag name of view root element if the DOM element will be
-	 * attached later.
-	 * @param {String} [name='main'] Name of the root.
-	 * @returns {module:engine/view/rooteditableelement~RootEditableElement} The created view root element.
-	 */
-	createRoot( domRoot, name = 'main' ) {
-		const rootTag = typeof domRoot == 'string' ? domRoot : domRoot.tagName;
-
-		const viewRoot = new RootEditableElement( rootTag.toLowerCase(), name );
-		viewRoot.document = this;
-
-		this.roots.set( name, viewRoot );
-
-		// Mark changed nodes in the renderer.
-		viewRoot.on( 'change:children', ( evt, node ) => this.renderer.markToSync( 'children', node ) );
-		viewRoot.on( 'change:attributes', ( evt, node ) => this.renderer.markToSync( 'attributes', node ) );
-		viewRoot.on( 'change:text', ( evt, node ) => this.renderer.markToSync( 'text', node ) );
-
-		if ( this.domConverter.isElement( domRoot ) ) {
-			this.attachDomRoot( domRoot, name );
-		}
-
-		return viewRoot;
-	}
-
-	/**
-	 * Attaches DOM root element to the view element and enable all observers on that element. This method also
-	 * {@link module:engine/view/renderer~Renderer#markToSync mark element} to be synchronized with the view what means that all child
-	 * nodes will be removed and replaced with content of the view root.
+	 * Attaches DOM root element to the view element and enable all observers on that element.
+	 * Also {@link module:engine/view/renderer~Renderer#markToSync mark element} to be synchronized with the view
+	 * what means that all child nodes will be removed and replaced with content of the view root.
 	 *
-	 * Note that {@link module:engine/view/document~Document#createRoot} will call this method automatically if the DOM element is
-	 * passed to it.
+	 * This method also will change view element name as the same as tag name of given dom root.
+	 * Name is always transformed to lower case.
 	 *
-	 * @param {Element|String} domRoot DOM root element.
+	 * @param {Element} domRoot DOM root element.
 	 * @param {String} [name='main'] Name of the root.
 	 */
 	attachDomRoot( domRoot, name = 'main' ) {
 		const viewRoot = this.getRoot( name );
 
-		this.domRoots.set( name, domRoot );
+		// Set view root name the same as DOM root tag name.
+		viewRoot._name = domRoot.tagName.toLowerCase();
 
+		this.domRoots.set( name, domRoot );
 		this.domConverter.bindElements( domRoot, viewRoot );
-
 		this.renderer.markToSync( 'children', viewRoot );
 		this.renderer.domDocuments.add( domRoot.ownerDocument );
 
+		viewRoot.on( 'change:children', ( evt, node ) => this.renderer.markToSync( 'children', node ) );
+		viewRoot.on( 'change:attributes', ( evt, node ) => this.renderer.markToSync( 'attributes', node ) );
+		viewRoot.on( 'change:text', ( evt, node ) => this.renderer.markToSync( 'text', node ) );
+
 		for ( const observer of this._observers.values() ) {
 			observer.observe( domRoot, name );
 		}

+ 46 - 100
packages/ckeditor5-engine/tests/view/document/document.js

@@ -5,6 +5,7 @@
 
 /* globals document */
 
+import RootEditableElement from '../../../src/view/rooteditableelement';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 import Document from '../../../src/view/document';
 import Observer from '../../../src/view/observer/observer';
@@ -88,29 +89,37 @@ describe( 'Document', () => {
 		} );
 	} );
 
-	describe( 'createRoot()', () => {
-		it( 'should create root', () => {
-			const domP = document.createElement( 'p' );
+	describe( 'attachDomRoot()', () => {
+		it( 'should attach DOM element to main view element', () => {
 			const domDiv = document.createElement( 'div' );
-			domDiv.appendChild( domP );
-
-			const ret = viewDocument.createRoot( domDiv );
+			const viewRoot = createRoot( 'div', 'main', viewDocument );
 
-			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
-			expect( count( viewDocument.roots ) ).to.equal( 1 );
+			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
 
-			const domRoot = viewDocument.getDomRoot();
-			const viewRoot = viewDocument.getRoot();
+			viewDocument.attachDomRoot( domDiv );
 
-			expect( ret ).to.equal( viewRoot );
+			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
 
-			expect( domRoot ).to.equal( domDiv );
+			expect( viewDocument.getDomRoot() ).to.equal( domDiv );
 			expect( viewDocument.domConverter.mapViewToDom( viewRoot ) ).to.equal( domDiv );
 
-			expect( viewRoot.name ).to.equal( 'div' );
 			expect( viewDocument.renderer.markedChildren.has( viewRoot ) ).to.be.true;
 		} );
 
+		it( 'should attach DOM element to custom view element', () => {
+			const domH1 = document.createElement( 'h1' );
+			const viewH1 = createRoot( 'h1', 'header', viewDocument );
+
+			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
+
+			viewDocument.attachDomRoot( domH1, 'header' );
+
+			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
+			expect( viewDocument.getDomRoot( 'header' ) ).to.equal( domH1 );
+			expect( viewDocument.domConverter.mapViewToDom( viewH1 ) ).to.equal( domH1 );
+			expect( viewDocument.renderer.markedChildren.has( viewH1 ) ).to.be.true;
+		} );
+
 		it( 'should call observe on each observer', () => {
 			// The variable will be overwritten.
 			viewDocument.destroy();
@@ -127,96 +136,17 @@ describe( 'Document', () => {
 			const observerMock = viewDocument.addObserver( ObserverMock );
 			const observerMockGlobalCount = viewDocument.addObserver( ObserverMockGlobalCount );
 
-			viewDocument.createRoot( document.createElement( 'div' ), 'root1' );
+			createRoot( 'div', 'root1', viewDocument );
+			viewDocument.attachDomRoot( document.createElement( 'div' ), 'root1' );
 
 			sinon.assert.calledOnce( observerMock.observe );
 			sinon.assert.calledOnce( observerMockGlobalCount.observe );
 		} );
-
-		it( 'should create "main" root by default', () => {
-			const domDiv = document.createElement( 'div' );
-			const ret = viewDocument.createRoot( domDiv );
-
-			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
-			expect( count( viewDocument.roots ) ).to.equal( 1 );
-
-			const domRoot = viewDocument.domRoots.get( 'main' );
-			const viewRoot = viewDocument.roots.get( 'main' );
-
-			expect( ret ).to.equal( viewRoot );
-
-			expect( domRoot ).to.equal( domDiv );
-		} );
-
-		it( 'should create root with given name', () => {
-			const domDiv = document.createElement( 'div' );
-			const ret = viewDocument.createRoot( domDiv, 'header' );
-
-			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
-			expect( count( viewDocument.roots ) ).to.equal( 1 );
-
-			const domRoot = viewDocument.domRoots.get( 'header' );
-			const viewRoot = viewDocument.roots.get( 'header' );
-
-			expect( ret ).to.equal( viewRoot );
-
-			expect( domRoot ).to.equal( domDiv );
-		} );
-
-		it( 'should create root without attaching DOM element', () => {
-			const ret = viewDocument.createRoot( 'div' );
-
-			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
-			expect( count( viewDocument.roots ) ).to.equal( 1 );
-			expect( ret ).to.equal( viewDocument.getRoot() );
-		} );
-	} );
-
-	describe( 'attachDomRoot()', () => {
-		it( 'should create root without attach DOM element to the view element', () => {
-			const domDiv = document.createElement( 'div' );
-			const viewRoot = viewDocument.createRoot( 'div' );
-
-			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
-			expect( count( viewDocument.roots ) ).to.equal( 1 );
-			expect( viewRoot ).to.equal( viewDocument.getRoot() );
-
-			viewDocument.attachDomRoot( domDiv );
-
-			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
-			expect( count( viewDocument.roots ) ).to.equal( 1 );
-
-			expect( viewDocument.getDomRoot() ).to.equal( domDiv );
-			expect( viewDocument.domConverter.mapViewToDom( viewRoot ) ).to.equal( domDiv );
-
-			expect( viewDocument.renderer.markedChildren.has( viewRoot ) ).to.be.true;
-		} );
-
-		it( 'should create root without attach DOM element to the view element with given name', () => {
-			const domH1 = document.createElement( 'h1' );
-			viewDocument.createRoot( 'DIV' );
-			const viewH1 = viewDocument.createRoot( 'h1', 'header' );
-
-			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
-			expect( count( viewDocument.roots ) ).to.equal( 2 );
-			expect( viewH1 ).to.equal( viewDocument.getRoot( 'header' ) );
-
-			viewDocument.attachDomRoot( domH1, 'header' );
-
-			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
-			expect( count( viewDocument.roots ) ).to.equal( 2 );
-
-			expect( viewDocument.getDomRoot( 'header' ) ).to.equal( domH1 );
-			expect( viewDocument.domConverter.mapViewToDom( viewH1 ) ).to.equal( domH1 );
-
-			expect( viewDocument.getRoot().name ).to.equal( 'div' );
-			expect( viewDocument.renderer.markedChildren.has( viewH1 ) ).to.be.true;
-		} );
 	} );
 
 	describe( 'getRoot()', () => {
 		it( 'should return "main" root', () => {
-			viewDocument.createRoot( document.createElement( 'div' ) );
+			createRoot( 'div', 'main', viewDocument );
 
 			expect( count( viewDocument.roots ) ).to.equal( 1 );
 
@@ -224,7 +154,7 @@ describe( 'Document', () => {
 		} );
 
 		it( 'should return named root', () => {
-			viewDocument.createRoot( document.createElement( 'h1' ), 'header' );
+			createRoot( 'h1', 'header', viewDocument );
 
 			expect( count( viewDocument.roots ) ).to.equal( 1 );
 
@@ -299,8 +229,11 @@ describe( 'Document', () => {
 		} );
 
 		it( 'should call observe on each root', () => {
-			viewDocument.createRoot( document.createElement( 'div' ), 'root1' );
-			viewDocument.createRoot( document.createElement( 'div' ), 'root2' );
+			createRoot( 'div', 'roo1', viewDocument );
+			createRoot( 'div', 'roo2', viewDocument );
+
+			viewDocument.attachDomRoot( document.createElement( 'div' ), 'roo1' );
+			viewDocument.attachDomRoot( document.createElement( 'div' ), 'roo2' );
 
 			const observerMock = viewDocument.addObserver( ObserverMock );
 
@@ -338,10 +271,12 @@ describe( 'Document', () => {
 		} );
 
 		it( 'scrolls to the first range in selection with an offset', () => {
+			const root = createRoot( 'div', 'main', viewDocument );
 			const stub = testUtils.sinon.stub( global.window, 'scrollTo' );
-			const root = viewDocument.createRoot( domRoot );
 			const range = ViewRange.createIn( root );
 
+			viewDocument.attachDomRoot( domRoot );
+
 			// Make sure the window will have to scroll to the domRoot.
 			Object.assign( domRoot.style, {
 				position: 'absolute',
@@ -405,7 +340,8 @@ describe( 'Document', () => {
 			domEditable = document.createElement( 'div' );
 			domEditable.setAttribute( 'contenteditable', 'true' );
 			document.body.appendChild( domEditable );
-			viewEditable = viewDocument.createRoot( domEditable );
+			viewEditable = createRoot( 'div', 'main', viewDocument );
+			viewDocument.attachDomRoot( domEditable );
 			viewDocument.selection.addRange( ViewRange.createFromParentsAndOffsets( viewEditable, 0, viewEditable, 0 ) );
 		} );
 
@@ -472,3 +408,13 @@ describe( 'Document', () => {
 		} );
 	} );
 } );
+
+function createRoot( name, rootName, viewDoc ) {
+	const viewRoot = new RootEditableElement( name );
+
+	viewRoot.rootName = rootName;
+	viewRoot.document = viewDoc;
+	viewDoc.roots.add( viewRoot );
+
+	return viewRoot;
+}

+ 19 - 3
packages/ckeditor5-engine/tests/view/document/integration.js

@@ -5,6 +5,7 @@
 
 /* globals document */
 
+import RootEditableElement from '../../../src/view/rooteditableelement';
 import Document from '../../../src/view/document';
 import ViewElement from '../../../src/view/element';
 import { isBlockFiller, BR_FILLER } from '../../../src/view/filler';
@@ -19,7 +20,9 @@ describe( 'Document integration', () => {
 		] );
 
 		const viewDocument = new Document();
-		viewDocument.createRoot( domDiv );
+
+		createRoot( 'div', 'main', viewDocument );
+		viewDocument.attachDomRoot( domDiv );
 		viewDocument.render();
 
 		expect( domDiv.childNodes.length ).to.equal( 1 );
@@ -32,7 +35,8 @@ describe( 'Document integration', () => {
 		const domDiv = document.createElement( 'div' );
 
 		const viewDocument = new Document();
-		viewDocument.createRoot( domDiv );
+		createRoot( 'div', 'main', viewDocument );
+		viewDocument.attachDomRoot( domDiv );
 
 		viewDocument.getRoot().appendChildren( new ViewElement( 'p' ) );
 		viewDocument.render();
@@ -47,7 +51,9 @@ describe( 'Document integration', () => {
 		const domRoot = document.createElement( 'div' );
 
 		const viewDocument = new Document();
-		const viewRoot = viewDocument.createRoot( domRoot );
+		const viewRoot = createRoot( 'div', 'main', viewDocument );
+
+		viewDocument.attachDomRoot( domRoot );
 
 		const viewP = new ViewElement( 'p', { class: 'foo' } );
 		viewRoot.appendChildren( viewP );
@@ -65,3 +71,13 @@ describe( 'Document integration', () => {
 		viewDocument.destroy();
 	} );
 } );
+
+function createRoot( name, rootName, viewDoc ) {
+	const viewRoot = new RootEditableElement( name );
+
+	viewRoot.rootName = rootName;
+	viewRoot.document = viewDoc;
+	viewDoc.roots.add( viewRoot );
+
+	return viewRoot;
+}

+ 13 - 1
packages/ckeditor5-engine/tests/view/document/jumpoverinlinefiller.js

@@ -5,6 +5,7 @@
 
 /* globals document */
 
+import RootEditableElement from '../../../src/view/rooteditableelement';
 import ViewRange from '../../../src/view/range';
 import ViewDocument from '../../../src/view/document';
 import { INLINE_FILLER_LENGTH, isInlineFiller, startsWithFiller } from '../../../src/view/filler';
@@ -24,7 +25,8 @@ describe( 'Document', () => {
 		document.body.appendChild( domRoot );
 
 		viewDocument = new ViewDocument();
-		viewDocument.createRoot( domRoot );
+		createRoot( 'div', 'main', viewDocument );
+		viewDocument.attachDomRoot( domRoot );
 
 		document.getSelection().removeAllRanges();
 
@@ -133,3 +135,13 @@ describe( 'Document', () => {
 		} );
 	} );
 } );
+
+function createRoot( name, rootName, viewDoc ) {
+	const viewRoot = new RootEditableElement( name );
+
+	viewRoot.rootName = rootName;
+	viewRoot.document = viewDoc;
+	viewDoc.roots.add( viewRoot );
+
+	return viewRoot;
+}

+ 13 - 1
packages/ckeditor5-engine/tests/view/document/jumpoveruielement.js

@@ -7,6 +7,7 @@
 
 import ViewDocument from '../../../src/view/document';
 import UIElement from '../../../src/view/uielement';
+import RootEditableElement from '../../../src/view/rooteditableelement';
 import ViewContainerElement from '../../../src/view/containerelement';
 import ViewAttribtueElement from '../../../src/view/attributeelement';
 import ViewText from '../../../src/view/text';
@@ -35,7 +36,8 @@ describe( 'Document', () => {
 		document.body.appendChild( domRoot );
 
 		viewDocument = new ViewDocument();
-		viewRoot = viewDocument.createRoot( domRoot );
+		viewRoot = createRoot( 'div', 'main', viewDocument );
+		viewDocument.attachDomRoot( domRoot );
 
 		domSelection = document.getSelection();
 		domSelection.removeAllRanges();
@@ -80,6 +82,16 @@ describe( 'Document', () => {
 		}
 	}
 
+	function createRoot( name, rootName, viewDoc ) {
+		const viewRoot = new RootEditableElement( name );
+
+		viewRoot.rootName = rootName;
+		viewRoot.document = viewDoc;
+		viewDoc.roots.add( viewRoot );
+
+		return viewRoot;
+	}
+
 	describe( 'jump over ui element handler', () => {
 		describe( 'collapsed selection', () => {
 			it( 'do nothing when another key is pressed', () => {