浏览代码

Added: Support for inserting `TextProxy` instances into `Element` and `DocumentFragment` (in model and view).

Szymon Cofalik 8 年之前
父节点
当前提交
656860a510

+ 17 - 8
packages/ckeditor5-engine/src/model/documentfragment.js

@@ -10,6 +10,7 @@
 import NodeList from './nodelist';
 import Element from './element';
 import Text from './text';
+import TextProxy from './textproxy';
 import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';
 
 /**
@@ -218,10 +219,10 @@ export default class DocumentFragment {
 	/**
 	 * {@link #insertChildren Inserts} one or more nodes at the end of this document fragment.
 	 *
-	 * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} nodes Nodes to be inserted.
+	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.
 	 */
-	appendChildren( nodes ) {
-		this.insertChildren( this.childCount, nodes );
+	appendChildren( items ) {
+		this.insertChildren( this.childCount, items );
 	}
 
 	/**
@@ -229,10 +230,10 @@ export default class DocumentFragment {
 	 * to this document fragment.
 	 *
 	 * @param {Number} index Index at which nodes should be inserted.
-	 * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} nodes Nodes to be inserted.
+	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.
 	 */
-	insertChildren( index, nodes ) {
-		nodes = normalize( nodes );
+	insertChildren( index, items ) {
+		const nodes = normalize( items );
 
 		for ( const node of nodes ) {
 			// If node that is being added to this element is already inside another element, first remove it from the old parent.
@@ -306,7 +307,7 @@ export default class DocumentFragment {
 
 // Converts strings to Text and non-iterables to arrays.
 //
-// @param {String|module:engine/model/node~Node|Iterable.<String|module:engine/model/node~Node>}
+// @param {String|module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>}
 // @return {Iterable.<module:engine/model/node~Node>}
 function normalize( nodes ) {
 	// Separate condition because string is iterable.
@@ -321,6 +322,14 @@ function normalize( nodes ) {
 	// Array.from to enable .map() on non-arrays.
 	return Array.from( nodes )
 		.map( node => {
-			return typeof node == 'string' ? new Text( node ) : node;
+			if ( typeof node == 'string' ) {
+				return new Text( node );
+			}
+
+			if ( node instanceof TextProxy ) {
+				return new Text( node.data, node.getAttributes() );
+			}
+
+			return node;
 		} );
 }

+ 15 - 6
packages/ckeditor5-engine/src/model/element.js

@@ -10,6 +10,7 @@
 import Node from './node';
 import NodeList from './nodelist';
 import Text from './text';
+import TextProxy from './textproxy';
 import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';
 
 /**
@@ -187,7 +188,7 @@ export default class Element extends Node {
 	/**
 	 * {@link module:engine/model/element~Element#insertChildren Inserts} one or more nodes at the end of this element.
 	 *
-	 * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} nodes Nodes to be inserted.
+	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} nodes Nodes to be inserted.
 	 */
 	appendChildren( nodes ) {
 		this.insertChildren( this.childCount, nodes );
@@ -198,10 +199,10 @@ export default class Element extends Node {
 	 * to this element.
 	 *
 	 * @param {Number} index Index at which nodes should be inserted.
-	 * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} nodes Nodes to be inserted.
+	 * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.
 	 */
-	insertChildren( index, nodes ) {
-		nodes = normalize( nodes );
+	insertChildren( index, items ) {
+		const nodes = normalize( items );
 
 		for ( const node of nodes ) {
 			// If node that is being added to this element is already inside another element, first remove it from the old parent.
@@ -305,7 +306,7 @@ export default class Element extends Node {
 
 // Converts strings to Text and non-iterables to arrays.
 //
-// @param {String|module:engine/model/node~Node|Iterable.<String|module:engine/model/node~Node>}
+// @param {String|module:engine/model/item~Item|Iterable.<String|module:engine/model/item~Item>}
 // @return {Iterable.<module:engine/model/node~Node>}
 function normalize( nodes ) {
 	// Separate condition because string is iterable.
@@ -320,6 +321,14 @@ function normalize( nodes ) {
 	// Array.from to enable .map() on non-arrays.
 	return Array.from( nodes )
 		.map( node => {
-			return typeof node == 'string' ? new Text( node ) : node;
+			if ( typeof node == 'string' ) {
+				return new Text( node );
+			}
+
+			if ( node instanceof TextProxy ) {
+				return new Text( node.data, node.getAttributes() );
+			}
+
+			return node;
 		} );
 }

+ 17 - 8
packages/ckeditor5-engine/src/view/documentfragment.js

@@ -8,6 +8,7 @@
  */
 
 import Text from './text';
+import TextProxy from './textproxy';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';
 import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
@@ -99,11 +100,11 @@ export default class DocumentFragment {
 	 * {@link module:engine/view/documentfragment~DocumentFragment#insertChildren Insert} a child node or a list of child nodes at the end
 	 * and sets the parent of these nodes to this fragment.
 	 *
-	 * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} nodes Node or the list of nodes to be inserted.
+	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
 	 * @returns {Number} Number of appended nodes.
 	 */
-	appendChildren( nodes ) {
-		return this.insertChildren( this.childCount, nodes );
+	appendChildren( items ) {
+		return this.insertChildren( this.childCount, items );
 	}
 
 	/**
@@ -140,14 +141,14 @@ export default class DocumentFragment {
 	 * this fragment.
 	 *
 	 * @param {Number} index Position where nodes should be inserted.
-	 * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} nodes Node or list of nodes to be inserted.
+	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
 	 * @returns {Number} Number of inserted nodes.
 	 */
-	insertChildren( index, nodes ) {
+	insertChildren( index, items ) {
 		this._fireChange( 'children', this );
 		let count = 0;
 
-		nodes = normalize( nodes );
+		const nodes = normalize( items );
 
 		for ( const node of nodes ) {
 			// If node that is being added to this element is already inside another element, first remove it from the old parent.
@@ -199,7 +200,7 @@ mix( DocumentFragment, EmitterMixin );
 
 // Converts strings to Text and non-iterables to arrays.
 //
-// @param {String|module:engine/view/node~Node|Iterable.<String|module:engine/view/node~Node>}
+// @param {String|module:engine/view/item~Item|Iterable.<String|module:engine/view/item~Item>}
 // @return {Iterable.<module:engine/view/node~Node>}
 function normalize( nodes ) {
 	// Separate condition because string is iterable.
@@ -214,6 +215,14 @@ function normalize( nodes ) {
 	// Array.from to enable .map() on non-arrays.
 	return Array.from( nodes )
 		.map( node => {
-			return typeof node == 'string' ? new Text( node ) : node;
+			if ( typeof node == 'string' ) {
+				return new Text( node );
+			}
+
+			if ( node instanceof TextProxy ) {
+				return new Text( node.data );
+			}
+
+			return node;
 		} );
 }

+ 17 - 8
packages/ckeditor5-engine/src/view/element.js

@@ -9,6 +9,7 @@
 
 import Node from './node';
 import Text from './text';
+import TextProxy from './textproxy';
 import objectToMap from '@ckeditor/ckeditor5-utils/src/objecttomap';
 import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';
 import isPlainObject from '@ckeditor/ckeditor5-utils/src/lib/lodash/isPlainObject';
@@ -193,11 +194,11 @@ export default class Element extends Node {
 	 * and sets the parent of these nodes to this element.
 	 *
 	 * @fires module:engine/view/node~Node#change
-	 * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} nodes Node or the list of nodes to be inserted.
+	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
 	 * @returns {Number} Number of appended nodes.
 	 */
-	appendChildren( nodes ) {
-		return this.insertChildren( this.childCount, nodes );
+	appendChildren( items ) {
+		return this.insertChildren( this.childCount, items );
 	}
 
 	/**
@@ -344,15 +345,15 @@ export default class Element extends Node {
 	 * this element.
 	 *
 	 * @param {Number} index Position where nodes should be inserted.
-	 * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} nodes Node or the list of nodes to be inserted.
+	 * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.
 	 * @fires module:engine/view/node~Node#change
 	 * @returns {Number} Number of inserted nodes.
 	 */
-	insertChildren( index, nodes ) {
+	insertChildren( index, items ) {
 		this._fireChange( 'children', this );
 		let count = 0;
 
-		nodes = normalize( nodes );
+		const nodes = normalize( items );
 
 		for ( const node of nodes ) {
 			// If node that is being added to this element is already inside another element, first remove it from the old parent.
@@ -809,7 +810,7 @@ function parseClasses( classesSet, classesString ) {
 
 // Converts strings to Text and non-iterables to arrays.
 //
-// @param {String|module:engine/view/node~Node|Iterable.<String|module:engine/view/node~Node>}
+// @param {String|module:engine/view/item~Item|Iterable.<String|module:engine/view/item~Item>}
 // @return {Iterable.<module:engine/view/node~Node>}
 function normalize( nodes ) {
 	// Separate condition because string is iterable.
@@ -824,6 +825,14 @@ function normalize( nodes ) {
 	// Array.from to enable .map() on non-arrays.
 	return Array.from( nodes )
 		.map( node => {
-			return typeof node == 'string' ? new Text( node ) : node;
+			if ( typeof node == 'string' ) {
+				return new Text( node );
+			}
+
+			if ( node instanceof TextProxy ) {
+				return new Text( node.data );
+			}
+
+			return node;
 		} );
 }

+ 15 - 0
packages/ckeditor5-engine/tests/model/documentfragment.js

@@ -5,6 +5,7 @@
 
 import Element from '../../src/model/element';
 import Text from '../../src/model/text';
+import TextProxy from '../../src/model/textproxy';
 import DocumentFragment from '../../src/model/documentfragment';
 import { jsonParseStringify } from '../../tests/model/_utils/utils';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
@@ -151,6 +152,20 @@ describe( 'DocumentFragment', () => {
 			expect( frag.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'p' );
 			expect( frag.getChild( 1 ) ).to.have.property( 'data' ).that.equals( 'abc' );
 		} );
+
+		it( 'should accept and correctly handle text proxies', () => {
+			const frag = new DocumentFragment();
+			const text = new Text( 'abcxyz', { bold: true } );
+			const textProxy = new TextProxy( text, 2, 3 );
+
+			frag.insertChildren( 0, textProxy );
+
+			expect( frag.childCount ).to.equal( 1 );
+			expect( frag.maxOffset ).to.equal( 3 );
+			expect( frag.getChild( 0 ) ).to.be.instanceof( Text );
+			expect( frag.getChild( 0 ).data ).to.equal( 'cxy' );
+			expect( frag.getChild( 0 ).getAttribute( 'bold' ) ).to.equal( true );
+		} );
 	} );
 
 	describe( 'appendChildren', () => {

+ 15 - 0
packages/ckeditor5-engine/tests/model/element.js

@@ -6,6 +6,7 @@
 import Node from '../../src/model/node';
 import Element from '../../src/model/element';
 import Text from '../../src/model/text';
+import TextProxy from '../../src/model/textproxy';
 import { jsonParseStringify } from '../../tests/model/_utils/utils';
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
@@ -126,6 +127,20 @@ describe( 'Element', () => {
 			expect( element.maxOffset ).to.equal( 3 );
 			expect( element.getChild( 0 ) ).to.have.property( 'data' ).that.equals( 'abc' );
 		} );
+
+		it( 'should accept and correctly handle text proxies', () => {
+			const element = new Element( 'div' );
+			const text = new Text( 'abcxyz', { bold: true } );
+			const textProxy = new TextProxy( text, 2, 3 );
+
+			element.insertChildren( 0, textProxy );
+
+			expect( element.childCount ).to.equal( 1 );
+			expect( element.maxOffset ).to.equal( 3 );
+			expect( element.getChild( 0 ) ).to.be.instanceof( Text );
+			expect( element.getChild( 0 ).data ).to.equal( 'cxy' );
+			expect( element.getChild( 0 ).getAttribute( 'bold' ) ).to.equal( true );
+		} );
 	} );
 
 	describe( 'appendChildren', () => {

+ 14 - 0
packages/ckeditor5-engine/tests/view/documentfragment.js

@@ -6,6 +6,8 @@
 import DocumentFragment from '../../src/view/documentfragment';
 import Element from '../../src/view/element';
 import Node from '../../src/view/node';
+import Text from '../../src/view/text';
+import TextProxy from '../../src/view/textproxy';
 
 describe( 'DocumentFragment', () => {
 	describe( 'constructor()', () => {
@@ -160,6 +162,18 @@ describe( 'DocumentFragment', () => {
 
 				fragment.appendChildren( el1 );
 			} );
+
+			it( 'should accept and correctly handle text proxies', () => {
+				const frag = new DocumentFragment();
+				const text = new Text( 'abcxyz' );
+				const textProxy = new TextProxy( text, 2, 3 );
+
+				frag.insertChildren( 0, textProxy );
+
+				expect( frag.childCount ).to.equal( 1 );
+				expect( frag.getChild( 0 ) ).to.be.instanceof( Text );
+				expect( frag.getChild( 0 ).data ).to.equal( 'cxy' );
+			} );
 		} );
 
 		describe( 'getChildIndex', () => {

+ 14 - 0
packages/ckeditor5-engine/tests/view/element.js

@@ -6,6 +6,8 @@
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import Node from '../../src/view/node';
 import Element from '../../src/view/element';
+import Text from '../../src/view/text';
+import TextProxy from '../../src/view/textproxy';
 
 import encodedImage from './_utils/encodedimage.txt';
 
@@ -332,6 +334,18 @@ describe( 'Element', () => {
 				expect( count2 ).to.equal( 1 );
 				expect( count3 ).to.equal( 1 );
 			} );
+
+			it( 'should accept and correctly handle text proxies', () => {
+				const element = new Element( 'div' );
+				const text = new Text( 'abcxyz' );
+				const textProxy = new TextProxy( text, 2, 3 );
+
+				element.insertChildren( 0, textProxy );
+
+				expect( element.childCount ).to.equal( 1 );
+				expect( element.getChild( 0 ) ).to.be.instanceof( Text );
+				expect( element.getChild( 0 ).data ).to.equal( 'cxy' );
+			} );
 		} );
 
 		describe( 'getChildIndex', () => {