瀏覽代碼

Changed: Introduced `view.utils` and `view.utils.getTouchingTextNode`.

Szymon Cofalik 8 年之前
父節點
當前提交
13c3f03bf4
共有 2 個文件被更改,包括 99 次插入0 次删除
  1. 41 0
      packages/ckeditor5-engine/src/view/utils.js
  2. 58 0
      packages/ckeditor5-engine/tests/view/utils.js

+ 41 - 0
packages/ckeditor5-engine/src/view/utils.js

@@ -0,0 +1,41 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import ViewPosition from './position';
+import ViewTreeWalker from './treewalker';
+
+/**
+ * Contains utility functions for working on view.
+ *
+ * @module engine/view/utils
+ */
+
+/**
+ * For given {@link module:engine/view/text~Text view text node}, it finds previous or next sibling that is contained
+ * in the same container element. If there is no such sibling, `null` is returned.
+ *
+ * @param {module:engine/view/text~Text} node Reference node.
+ * @param {Boolean} getNext If `true` next touching sibling will be returned. If `false` previous touching sibling will be returned.
+ * @returns {module:engine/view/text~Text|null} Touching text node or `null` if there is no next or previous touching text node.
+ */
+export function getTouchingTextNode( node, getNext ) {
+	const treeWalker = new ViewTreeWalker( {
+		startPosition: getNext ? ViewPosition.createAfter( node ) : ViewPosition.createBefore( node ),
+		direction: getNext ? 'forward' : 'backward'
+	} );
+
+	for ( const value of treeWalker ) {
+		if ( value.item.is( 'containerElement' ) ) {
+			// ViewContainerElement is found on a way to next ViewText node, so given `node` was first/last
+			// text node in it's container element.
+			return null;
+		} else if ( value.item.is( 'text' ) ) {
+			// Found a text node in the same container element.
+			return value.item;
+		}
+	}
+
+	return null;
+}

+ 58 - 0
packages/ckeditor5-engine/tests/view/utils.js

@@ -0,0 +1,58 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import ViewAttributeElement from '../../src/view/attributeelement';
+import ViewContainerElement from '../../src/view/containerelement';
+import ViewText from '../../src/view/text';
+
+import { getTouchingTextNode } from '../../src/view/utils';
+
+describe( 'getTouchingTextNode()', () => {
+	let a, b, x, y;
+
+	beforeEach( () => {
+		a = new ViewText( 'a' );
+		b = new ViewText( 'b' );
+		x = new ViewText( 'x' );
+		y = new ViewText( 'y' );
+
+		// <div><p>ab</p><p><em><strong>x</strong></em>y</p></div>
+		/* eslint-disable no-new */
+		new ViewContainerElement( 'div', null, [
+			new ViewContainerElement( 'p', null, [ a, b ] ),
+
+			new ViewContainerElement( 'p', null, [
+				new ViewAttributeElement( 'em', null, new ViewAttributeElement( 'strong', null, x ) ),
+				y
+			] )
+		] );
+	} );
+
+	it( 'should return next touching view text node', () => {
+		expect( getTouchingTextNode( a, true ) ).to.equal( b );
+	} );
+
+	it( 'should return previous touching view text node', () => {
+		expect( getTouchingTextNode( b, false ) ).to.equal( a );
+	} );
+
+	it( 'should go outside of attribute element looking for text nodes', () => {
+		expect( getTouchingTextNode( x, true ) ).to.equal( y );
+	} );
+
+	it( 'should go inside attribute element looking for text nodes', () => {
+		expect( getTouchingTextNode( y, false ) ).to.equal( x );
+	} );
+
+	it( 'should return null if there is no next text node in given container element', () => {
+		expect( getTouchingTextNode( b, true ) ).to.be.null;
+		expect( getTouchingTextNode( y, true ) ).to.be.null;
+	} );
+
+	it( 'should return null if there is no previous text node in given container element', () => {
+		expect( getTouchingTextNode( a, false ) ).to.be.null;
+		expect( getTouchingTextNode( x, false ) ).to.be.null;
+	} );
+} );