8
0
Просмотр исходного кода

viewToDom and domToView works now the same way.

Piotr Jasiun 10 лет назад
Родитель
Сommit
ec8b4864b9

+ 28 - 16
packages/ckeditor5-engine/src/treeview/converter.js

@@ -34,15 +34,12 @@ export default class Converter {
 		return false;
 	}
 
-	cloneDomAttrs( domElement, viewElement ) {
-		for ( let i = domElement.attributes.length - 1; i >= 0; i-- ) {
-			let attr = domElement.attributes[ i ];
-			viewElement.setAttr( attr.name, attr.value );
+	// bind: false, withChildren: true
+	viewToDom( viewNode, domDocument, options ) {
+		if ( !options ) {
+			options = {};
 		}
-	}
 
-	// viewToDom do bind elements
-	viewToDom( viewNode, domDocument ) {
 		if ( viewNode instanceof ViewText ) {
 			return domDocument.createTextNode( viewNode.getText() );
 		} else {
@@ -51,23 +48,31 @@ export default class Converter {
 			}
 
 			const domElement = domDocument.createElement( viewNode.name );
-			this.bindElements( domElement, viewNode );
+
+			if ( options.bind ) {
+				this.bindElements( domElement, viewNode );
+			}
 
 			for ( let key of viewNode.getAttrKeys() ) {
 				domElement.setAttribute( key, viewNode.getAttr( key ) );
 			}
 
-			for ( let childView of viewNode.getChildren() ) {
-				domElement.appendChild( this.viewToDom( childView, domDocument ) );
+			if ( options.withChildren || options.withChildren === undefined ) {
+				for ( let childView of viewNode.getChildren() ) {
+					domElement.appendChild( this.viewToDom( childView, domDocument, options ) );
+				}
 			}
 
 			return domElement;
 		}
 	}
 
-	// Note that created elements will not have coresponding DOM elements created it these did not exist before.
-	// domToView do not bind elements
-	domToView( domElement ) {
+	// bind: false, withChildren: true
+	domToView( domElement, options ) {
+		if ( !options ) {
+			options = {};
+		}
+
 		let viewElement = this.getCorespondingView( domElement );
 
 		if ( viewElement ) {
@@ -78,16 +83,23 @@ export default class Converter {
 			return new ViewText( domElement.data );
 		} else {
 			viewElement = new ViewElement( domElement.tagName.toLowerCase() );
+
+			if ( options.bind ) {
+				this.bindElements( domElement, viewElement );
+			}
+
 			const attrs = domElement.attributes;
 
 			for ( let i = attrs.length - 1; i >= 0; i-- ) {
 				viewElement.setAttr( attrs[ i ].name, attrs[ i ].value );
 			}
 
-			for ( let i = 0, len = domElement.childNodes.length; i < len; i++ ) {
-				let domChild = domElement.childNodes[ i ];
+			if ( options.withChildren || options.withChildren === undefined ) {
+				for ( let i = 0, len = domElement.childNodes.length; i < len; i++ ) {
+					let domChild = domElement.childNodes[ i ];
 
-				viewElement.appendChildren( this.domToView( domChild ) );
+					viewElement.appendChildren( this.domToView( domChild, options ) );
+				}
 			}
 
 			return viewElement;

+ 0 - 2
packages/ckeditor5-engine/src/treeview/element.js

@@ -29,8 +29,6 @@ export default class Element extends Node {
 		if ( children ) {
 			this.insertChildren( 0, children );
 		}
-
-		this._domElement = null;
 	}
 
 	appendChildren( nodes ) {

+ 11 - 3
packages/ckeditor5-engine/src/treeview/node.js

@@ -12,6 +12,8 @@ import objectUtils from '../lib/lodash/object.js';
 export default class Node {
 	constructor() {
 		this.parent = null;
+
+		this._treeView = null;
 	}
 
 	getIndex() {
@@ -47,13 +49,19 @@ export default class Node {
 	}
 
 	getTreeView() {
-		if ( !this.parent ) {
-			return null;
-		} else {
+		if ( this._treeView ) {
+			return this._treeView;
+		} else if ( this.parent ) {
 			return this.parent.getTreeView();
+		} else {
+			return null;
 		}
 	}
 
+	setTreeView( treeView ) {
+		this._treeView = treeView;
+	}
+
 	_fireChange( type, node ) {
 		this.fire( 'change', type, node );
 

+ 2 - 1
packages/ckeditor5-engine/src/treeview/renderer.js

@@ -101,7 +101,8 @@ export default class Renderer {
 
 			for ( let action of actions ) {
 				if ( action === 'INSERT' ) {
-					domElement.insertBefore( converter.viewToDom( viewChildren[ i ], domDocument ), domChildren[ i ] || null  );
+					let domChildToInsert = converter.viewToDom( viewChildren[ i ], domDocument, { bind: true } );
+					domElement.insertBefore( domChildToInsert, domChildren[ i ] || null  );
 					i++;
 				} else if ( action === 'DELETE' ) {
 					domElement.removeChild( domChildren[ i ] );

+ 0 - 25
packages/ckeditor5-engine/src/treeview/rootelement.js

@@ -1,25 +0,0 @@
-/**
- * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import Element from './element.js';
-
-/**
- * Class for nodes that are roots of trees in tree data view.
- *
- * @class treeView.RootElement
- */
-export default class RootElement extends Element {
-	constructor( name, treeView ) {
-		super( name );
-
-		this._treeView = treeView;
-	}
-
-	getTreeView() {
-		return this._treeView;
-	}
-}

+ 2 - 4
packages/ckeditor5-engine/src/treeview/treeview.js

@@ -6,7 +6,6 @@
 'use strict';
 
 import EmitterMixin from '../emittermixin.js';
-import RootElement from './rootelement.js';
 import Renderer from './renderer.js';
 import Converter from './converter.js';
 
@@ -26,9 +25,8 @@ export default class TreeView {
 		/**
 		 * Root of the view
 		 */
-		this.viewRoot = new RootElement( domRoot.tagName.toLowerCase(), this );
-		this.converter.cloneDomAttrs( domRoot, this.viewRoot );
-		this.converter.bindElements( domRoot, this.viewRoot );
+		this.viewRoot = this.converter.domToView( domRoot , { bind: true, withChildren: false } );
+		this.viewRoot.setTreeView( this );
 
 		this.renderer = new Renderer( this.converter );
 		this.renderer.markToSync( 'CHILDREN', this.viewRoot );

+ 105 - 17
packages/ckeditor5-engine/tests/treeview/converter.js

@@ -58,22 +58,6 @@ describe( 'converter', () => {
 		} );
 	} );
 
-	describe( 'cloneDomAttrs', () => {
-		it( 'should clone DOM attributes', () => {
-			const domElement = document.createElement( 'p' );
-			domElement.setAttribute( 'foo', '1' );
-			domElement.setAttribute( 'bar', '2' );
-
-			const viewElement = new ViewElement( 'p' );
-
-			converter.cloneDomAttrs( domElement, viewElement );
-
-			expect( viewElement.getAttr( 'foo' ) ).to.equal( '1' );
-			expect( viewElement.getAttr( 'bar' ) ).to.equal( '2' );
-			expect( getIteratorCount( viewElement.getAttrKeys() ) ).to.equal( 2 );
-		} );
-	} );
-
 	describe( 'domToView', () => {
 		it( 'should create tree of view elements from DOM elements', () => {
 			const domImg = document.createElement( 'img' );
@@ -104,6 +88,58 @@ describe( 'converter', () => {
 			expect( converter.getCorespondingDom( viewP ) ).to.not.equal( domP );
 			expect( converter.getCorespondingDom( viewP.getChild( 0 ) ) ).to.equal( domImg );
 		} );
+
+		it( 'should create tree of view elements from DOM elements and bind elements', () => {
+			const domImg = document.createElement( 'img' );
+			const domText = document.createTextNode( 'foo' );
+			const domP = document.createElement( 'p' );
+
+			domP.setAttribute( 'class', 'foo' );
+
+			domP.appendChild( domImg );
+			domP.appendChild( domText );
+
+			const viewP = converter.domToView( domP, { bind: true } );
+
+			expect( viewP ).to.be.an.instanceof( ViewElement );
+			expect( viewP.name ).to.equal( 'p' );
+
+			expect( viewP.getAttr( 'class' ) ).to.equal( 'foo' );
+			expect( getIteratorCount( viewP.getAttrKeys() ) ).to.equal( 1 );
+
+			expect( viewP.getChildCount() ).to.equal( 2 );
+			expect( viewP.getChild( 0 ).name ).to.equal( 'img' );
+			expect( viewP.getChild( 1 ).getText() ).to.equal( 'foo' );
+
+			expect( converter.getCorespondingDom( viewP ) ).to.equal( domP );
+			expect( converter.getCorespondingDom( viewP.getChild( 0 ) ) ).to.equal( domP.childNodes[ 0 ] );
+		} );
+
+		it( 'should create tree of view elements from DOM element without children', () => {
+			const domImg = document.createElement( 'img' );
+			const domText = document.createTextNode( 'foo' );
+			const domP = document.createElement( 'p' );
+
+			domP.setAttribute( 'class', 'foo' );
+
+			domP.appendChild( domImg );
+			domP.appendChild( domText );
+
+			const viewImg = new ViewElement( 'img' );
+
+			converter.bindElements( domImg, viewImg );
+
+			const viewP = converter.domToView( domP, { withChildren: false } );
+
+			expect( viewP ).to.be.an.instanceof( ViewElement );
+			expect( viewP.name ).to.equal( 'p' );
+
+			expect( viewP.getAttr( 'class' ) ).to.equal( 'foo' );
+			expect( getIteratorCount( viewP.getAttrKeys() ) ).to.equal( 1 );
+
+			expect( viewP.getChildCount() ).to.equal( 0 );
+			expect( converter.getCorespondingDom( viewP ) ).to.not.equal( domP );
+		} );
 	} );
 
 	describe( 'viewToDom', () => {
@@ -133,9 +169,61 @@ describe( 'converter', () => {
 			expect( domP.childNodes[ 0 ].tagName.toLowerCase() ).to.equal( 'img' );
 			expect( domP.childNodes[ 1 ].data ).to.equal( 'foo' );
 
-			expect( converter.getCorespondingView( domP ) ).to.equal( viewP );
+			expect( converter.getCorespondingView( domP ) ).not.to.equal( viewP );
 			expect( converter.getCorespondingView( domP.childNodes[ 0 ] ) ).to.equal( viewImg );
 		} );
+
+		it( 'should create tree of DOM elements from view elements and bind elements', () => {
+			const viewImg = new ViewElement( 'img' );
+			const viewText = new ViewText( 'foo' );
+			const viewP = new ViewElement( 'p' );
+
+			viewP.setAttr( 'class', 'foo' );
+
+			viewP.appendChildren( viewImg );
+			viewP.appendChildren( viewText );
+
+			const domP = converter.viewToDom( viewP, document, { bind: true } );
+
+			expect( domP ).to.be.an.instanceof( HTMLElement );
+			expect( domP.tagName.toLowerCase() ).to.equal( 'p' );
+
+			expect( domP.getAttribute( 'class' ) ).to.equal( 'foo' );
+			expect( domP.attributes.length ).to.equal( 1 );
+
+			expect( domP.childNodes.length ).to.equal( 2 );
+			expect( domP.childNodes[ 0 ].tagName.toLowerCase() ).to.equal( 'img' );
+			expect( domP.childNodes[ 1 ].data ).to.equal( 'foo' );
+
+			expect( converter.getCorespondingView( domP ) ).to.equal( viewP );
+			expect( converter.getCorespondingView( domP.childNodes[ 0 ] ) ).to.equal( viewP.getChild( 0 ) );
+		} );
+
+		it( 'should create tree of DOM elements from view element without children', () => {
+			const viewImg = new ViewElement( 'img' );
+			const viewText = new ViewText( 'foo' );
+			const viewP = new ViewElement( 'p' );
+
+			viewP.setAttr( 'class', 'foo' );
+
+			viewP.appendChildren( viewImg );
+			viewP.appendChildren( viewText );
+
+			const domImg = document.createElement( 'img' );
+
+			converter.bindElements( domImg, viewImg );
+
+			const domP = converter.viewToDom( viewP, document, { withChildren: false } );
+
+			expect( domP ).to.be.an.instanceof( HTMLElement );
+			expect( domP.tagName.toLowerCase() ).to.equal( 'p' );
+
+			expect( domP.getAttribute( 'class' ) ).to.equal( 'foo' );
+			expect( domP.attributes.length ).to.equal( 1 );
+
+			expect( domP.childNodes.length ).to.equal( 0 );
+			expect( converter.getCorespondingView( domP ) ).not.to.equal( viewP );
+		} );
 	} );
 
 	describe( 'getCorespondingView', () => {

+ 15 - 5
packages/ckeditor5-engine/tests/treeview/node.js

@@ -8,7 +8,6 @@
 'use strict';
 
 import Element from '/ckeditor5/core/treeview/element.js';
-import RootElement from '/ckeditor5/core/treeview/rootelement.js';
 import Text from '/ckeditor5/core/treeview/text.js';
 import CKEditorError from '/ckeditor5/core/ckeditorerror.js';
 
@@ -89,17 +88,28 @@ describe( 'Node', () => {
 	} );
 
 	describe( 'getTreeView', () => {
-		it( 'should return null if root is not a RootElement', () => {
+		it( 'should return null if any parent has not set treeview', () => {
 			expect( charA.getTreeView() ).to.be.null;
 		} );
 
-		it( 'should return TreeView attached to the RootElement', () => {
+		it( 'should return TreeView attached to the element', () => {
 			const tvMock = {};
-			const parent = new RootElement( 'div', tvMock );
+			const element = new Element( 'p' );
+
+			element.setTreeView( tvMock );
+
+			expect( element.getTreeView() ).to.equal( tvMock );
+		} );
+
+		it( 'should return TreeView attached to the parent element', () => {
+			const tvMock = {};
+			const parent = new Element( 'div' );
 			const child = new Element( 'p' );
 
 			child.parent = parent;
 
+			parent.setTreeView( tvMock );
+
 			expect( parent.getTreeView() ).to.equal( tvMock );
 			expect( child.getTreeView() ).to.equal( tvMock );
 		} );
@@ -118,7 +128,7 @@ describe( 'Node', () => {
 			img = new Element( 'img' );
 			img.setAttr( 'src', 'img.png' );
 
-			root = new RootElement( 'p', { renderer: { markToSync: rootChangeSpy } } );
+			root = new Element( 'p', { renderer: { markToSync: rootChangeSpy } } );
 			root.appendChildren( [ text, img ] );
 
 			root.on( 'change', ( evt, type, node ) => {