ソースを参照

Move filler logic to the separate file.

Piotr Jasiun 9 年 前
コミット
cf4b9c66a7

+ 16 - 54
packages/ckeditor5-engine/src/treeview/domconverter.js

@@ -11,26 +11,10 @@ import ViewPosition from './position.js';
 import ViewRange from './range.js';
 import ViewSelection from './selection.js';
 import ViewDocumentFragment from './documentfragment.js';
+import { BR_FILLER, INLINE_FILLER_LENGTH, isBlockFiller, isInlineFiller, startsWithFiller, getDataWithoutFiller } from './filler.js';
 
 import indexOf from '../../utils/dom/indexof.js';
 
-export const BR_FILLER = ( domDocument ) => {
-	const fillerBr = domDocument.createElement( 'br' );
-	fillerBr.dataset.filler = true;
-
-	return fillerBr;
-};
-
-export const NBSP_FILLER = ( domDocument ) => domDocument.createTextNode( ' ' );
-
-export const INLINE_FILLER_SIZE = 7;
-
-export let INLINE_FILLER = '';
-
-for ( let i = 0; i < INLINE_FILLER_SIZE; i++ ) {
-	INLINE_FILLER += '\u200b';
-}
-
 /**
  * DomConverter is a set of tools to do transformations between DOM nodes and view nodes. It also handles
  * {@link engine.treeView.DomConverter#bindElements binding} these nodes.
@@ -72,9 +56,7 @@ export default class DomConverter {
 		 */
 		this._viewToDomMapping = new WeakMap();
 
-		this.blockFillerCreator = options.blockFiller || BR_FILLER;
-
-		this._templateBlockFiller = this.blockFillerCreator( window.document );
+		this.blockFiller = options.blockFiller || BR_FILLER;
 	}
 
 	/**
@@ -161,7 +143,7 @@ export default class DomConverter {
 
 		for ( let childView of viewElement.getChildren() ) {
 			if ( fillerPositionOffset === offset ) {
-				yield this.blockFillerCreator( domDocument );
+				yield this.blockFiller( domDocument );
 			}
 
 			yield this.viewToDom( childView, domDocument, options );
@@ -170,7 +152,7 @@ export default class DomConverter {
 		}
 
 		if ( fillerPositionOffset === offset ) {
-			yield this.blockFillerCreator( domDocument );
+			yield this.blockFiller( domDocument );
 		}
 	}
 
@@ -192,8 +174,8 @@ export default class DomConverter {
 			const domParent = this.getCorrespondingDomText( viewParent );
 			let offset = viewPosition.offset;
 
-			if ( this.startsWithFiller( domParent ) ) {
-				offset += INLINE_FILLER_SIZE;
+			if ( startsWithFiller( domParent ) ) {
+				offset += INLINE_FILLER_LENGTH;
 			}
 
 			return { parent: domParent, offset: offset };
@@ -209,8 +191,8 @@ export default class DomConverter {
 				domAfter = domBefore.nextSibling;
 			}
 
-			if ( domAfter instanceof Text && this.startsWithFiller( domAfter ) ) {
-				return { parent: domAfter, offset: INLINE_FILLER_SIZE };
+			if ( domAfter instanceof Text && startsWithFiller( domAfter ) ) {
+				return { parent: domAfter, offset: INLINE_FILLER_LENGTH };
 			}
 
 			const offset = domBefore ? indexOf( domBefore ) + 1 : 0;
@@ -230,15 +212,15 @@ export default class DomConverter {
 	 * @returns {engine.treeView.Node|engine.treeView.DocumentFragment} Converted node or document fragment.
 	 */
 	domToView( domNode, options = {} ) {
-		if ( this.isBlockFiller( domNode )  ) {
+		if ( isBlockFiller( domNode, this.blockFiller )  ) {
 			return null;
 		}
 
 		if ( domNode instanceof Text ) {
-			if ( this.isInlineFiller( domNode ) ) {
+			if ( isInlineFiller( domNode ) ) {
 				return null;
 			} else {
-				return new ViewText( this.getDataWithoutFiller( domNode ) );
+				return new ViewText( getDataWithoutFiller( domNode ) );
 			}
 		} else {
 			if ( this.getCorrespondingView( domNode ) ) {
@@ -340,20 +322,20 @@ export default class DomConverter {
 	}
 
 	domPositionToView( domParent, domOffset ) {
-		if ( this.isBlockFiller( domParent ) ) {
+		if ( isBlockFiller( domParent, this.blockFiller ) ) {
 			return this.domPositionToView( domParent.parentNode, indexOf( domParent ) );
 		}
 
 		if ( domParent instanceof Text ) {
-			if ( this.isInlineFiller( domParent ) ) {
+			if ( isInlineFiller( domParent ) ) {
 				return this.domPositionToView( domParent.parentNode, indexOf( domParent ) );
 			}
 
 			const viewParent = this.getCorrespondingViewText( domParent );
 			let offset = domOffset;
 
-			if ( this.startsWithFiller( domParent ) ) {
-				offset -= INLINE_FILLER_SIZE;
+			if ( startsWithFiller( domParent ) ) {
+				offset -= INLINE_FILLER_LENGTH;
 				offset = offset < 0 ? 0 : offset;
 			}
 
@@ -416,7 +398,7 @@ export default class DomConverter {
 	 * corresponding node.
 	 */
 	getCorrespondingViewText( domText ) {
-		if ( this.isInlineFiller( domText ) ) {
+		if ( isInlineFiller( domText ) ) {
 			return null;
 		}
 
@@ -531,24 +513,4 @@ export default class DomConverter {
 
 		return null;
 	}
-
-	startsWithFiller( domText ) {
-		return ( domText.data.substr( 0, INLINE_FILLER_SIZE ) === INLINE_FILLER );
-	}
-
-	isInlineFiller( domText ) {
-		return domText.data.length == INLINE_FILLER_SIZE && this.startsWithFiller( domText );
-	}
-
-	getDataWithoutFiller( domText ) {
-		if ( this.startsWithFiller( domText ) ) {
-			return domText.data.slice( INLINE_FILLER_SIZE );
-		} else {
-			return domText.data;
-		}
-	}
-
-	isBlockFiller( domNode ) {
-		return domNode.isEqualNode( this._templateBlockFiller );
-	}
 }

+ 61 - 0
packages/ckeditor5-engine/src/treeview/filler.js

@@ -0,0 +1,61 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+/**
+ * Set of utils related to keyboard support.
+ *
+ * @namespace engine.treeView.filler
+ */
+
+/**
+ * @member {Object} engine.treeView.filler.BR_FILLER
+ */
+export const BR_FILLER = ( domDocument ) => {
+	const fillerBr = domDocument.createElement( 'br' );
+	fillerBr.dataset.filler = true;
+
+	return fillerBr;
+};
+
+export const NBSP_FILLER = ( domDocument ) => domDocument.createTextNode( '&nbsp;' );
+
+export const INLINE_FILLER_LENGTH = 7;
+
+export let INLINE_FILLER = '';
+
+for ( let i = 0; i < INLINE_FILLER_LENGTH; i++ ) {
+	INLINE_FILLER += '\u200b';
+}
+
+export function startsWithFiller( domText ) {
+	return ( domText.data.substr( 0, INLINE_FILLER_LENGTH ) === INLINE_FILLER );
+}
+
+export function isInlineFiller( domText ) {
+	return domText.data.length == INLINE_FILLER_LENGTH && startsWithFiller( domText );
+}
+
+export function getDataWithoutFiller( domText ) {
+	if ( startsWithFiller( domText ) ) {
+		return domText.data.slice( INLINE_FILLER_LENGTH );
+	} else {
+		return domText.data;
+	}
+}
+
+const templateBlockFillers = new WeakMap();
+
+export function isBlockFiller( domNode, blockFiller ) {
+	let templateBlockFiller = templateBlockFillers.get( blockFiller );
+
+	if ( !templateBlockFiller ) {
+		templateBlockFiller = blockFiller( window.document );
+		templateBlockFillers.set( blockFiller, templateBlockFiller );
+	}
+
+	return domNode.isEqualNode( templateBlockFiller );
+}

+ 3 - 2
packages/ckeditor5-engine/src/treeview/observer/mutationobserver.js

@@ -6,6 +6,7 @@
 'use strict';
 
 import Observer from './observer.js';
+import { startsWithFiller, getDataWithoutFiller } from '../filler.js';
 
 /**
  * Mutation observer class observes changes in the DOM, fires {@link engine.treeView.TreeView#mutations} event, mark view elements
@@ -152,14 +153,14 @@ export default class MutationObserver extends Observer {
 					mutatedTexts.set( text, {
 						type: 'text',
 						oldText: text.data,
-						newText: domConverter.getDataWithoutFiller( mutation.target ),
+						newText: getDataWithoutFiller( mutation.target ),
 						node: text
 					} );
 				}
 				// When we added first letter to the text node which had only inline filler, for the DOM it is mutation
 				// on text, but for the view, where filler text node did not existed, new text node was created, so we
 				// need to fire 'children' mutation instead of 'text'.
-				else if ( !text && domConverter.startsWithFiller( mutation.target ) ) {
+				else if ( !text && startsWithFiller( mutation.target ) ) {
 					mutatedElements.add( domConverter.getCorrespondingViewElement( mutation.target.parentNode ) );
 				}
 			}

+ 6 - 5
packages/ckeditor5-engine/src/treeview/renderer.js

@@ -8,7 +8,7 @@
 import ViewText from './text.js';
 import ViewElement from './element.js';
 import ViewPosition from './position.js';
-import { INLINE_FILLER, INLINE_FILLER_SIZE } from './domconverter.js';
+import { INLINE_FILLER, INLINE_FILLER_LENGTH, startsWithFiller, isInlineFiller, isBlockFiller } from './filler.js';
 
 import diff from '../../utils/diff.js';
 import insertAt from '../../utils/dom/insertat.js';
@@ -203,7 +203,7 @@ export default class Renderer {
 		const domFillerPosition = this.domConverter.viewPositionToDom( this._inlineFillerPosition );
 		const domFillerNode = domFillerPosition.parent;
 
-		if ( !this.domConverter.startsWithFiller( domFillerNode ) ) {
+		if ( !startsWithFiller( domFillerNode ) ) {
 			/**
 			 * No inline filler on expected position.
 			 *
@@ -212,10 +212,10 @@ export default class Renderer {
 			throw new CKEditorError( 'renderer-render-no-inline-filler: No inline filler on expected position.' );
 		}
 
-		if ( this.domConverter.isInlineFiller( domFillerNode ) ) {
+		if ( isInlineFiller( domFillerNode ) ) {
 			domFillerNode.parentNode.removeChild( domFillerNode );
 		} else {
-			domFillerNode.data = domFillerNode.data.substr( INLINE_FILLER_SIZE );
+			domFillerNode.data = domFillerNode.data.substr( INLINE_FILLER_LENGTH );
 		}
 	}
 
@@ -327,7 +327,8 @@ export default class Renderer {
 				return actualDomChild.data === expectedDomChild.data;
 			}
 			// Block fillers.
-			else if ( domConverter.isBlockFiller( actualDomChild ) && domConverter.isBlockFiller( expectedDomChild ) ) {
+			else if ( isBlockFiller( actualDomChild, domConverter.blockFiller ) &&
+				isBlockFiller( expectedDomChild, domConverter.blockFiller ) ) {
 				return true;
 			}
 

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

@@ -9,7 +9,7 @@ import Selection from './selection.js';
 import Renderer from './renderer.js';
 import Writer from './writer.js';
 import DomConverter from './domconverter.js';
-import { INLINE_FILLER_SIZE } from './domconverter.js';
+import { INLINE_FILLER_LENGTH, startsWithFiller } from './filler.js';
 
 import mix from '../../utils/mix.js';
 import EmitterMixin from '../../utils/emittermixin.js';
@@ -209,7 +209,7 @@ export default class TreeView {
 					const domParent = domSelection.getRangeAt( 0 ).startContainer;
 					const domOffset = domSelection.getRangeAt( 0 ).startOffset;
 
-					if ( this.domConverter.startsWithFiller( domParent ) && domOffset <= INLINE_FILLER_SIZE ) {
+					if ( startsWithFiller( domParent ) && domOffset <= INLINE_FILLER_LENGTH ) {
 						const domRange = new Range();
 						domRange.setStart( domParent, 0 );
 						domRange.collapse( true );

+ 6 - 6
packages/ckeditor5-engine/tests/treeview/treeview/jumpoverinlinefiller.js

@@ -10,7 +10,7 @@
 import ViewRange from '/ckeditor5/engine/treeview/range.js';
 import TreeView from '/ckeditor5/engine/treeview/treeview.js';
 import KeyObserver from '/ckeditor5/engine/treeview/observer/keyobserver.js';
-import { INLINE_FILLER_SIZE } from '/ckeditor5/engine/treeview/domconverter.js';
+import { INLINE_FILLER_LENGTH, isInlineFiller, startsWithFiller } from '/ckeditor5/engine/treeview/filler.js';
 
 import { keyNames } from '/ckeditor5/utils/keyboard.js';
 
@@ -36,7 +36,7 @@ describe( 'TreeView', () => {
 			treeView.fire( 'keydown', { keyCode: keyNames.arrowleft, domTarget: treeView.domRoots.get( 'main' ) } );
 
 			const domRange = document.getSelection().getRangeAt( 0 );
-			expect( treeView.domConverter.isInlineFiller( domRange.startContainer ) ).to.be.true;
+			expect( isInlineFiller( domRange.startContainer ) ).to.be.true;
 			expect( domRange.startOffset ).to.equal( 0 );
 			expect( domRange.collapsed ).to.be.true;
 		} );
@@ -48,8 +48,8 @@ describe( 'TreeView', () => {
 			treeView.fire( 'keydown', { keyCode: keyNames.arrowright, domTarget: treeView.domRoots.get( 'main' ) } );
 
 			const domRange = document.getSelection().getRangeAt( 0 );
-			expect( treeView.domConverter.isInlineFiller( domRange.startContainer ) ).to.be.true;
-			expect( domRange.startOffset ).to.equal( INLINE_FILLER_SIZE );
+			expect( isInlineFiller( domRange.startContainer ) ).to.be.true;
+			expect( domRange.startOffset ).to.equal( INLINE_FILLER_LENGTH );
 			expect( domRange.collapsed ).to.be.true;
 		} );
 
@@ -93,8 +93,8 @@ describe( 'TreeView', () => {
 			treeView.fire( 'keydown', { keyCode: keyNames.arrowleft, domTarget: treeView.domRoots.get( 'main' ) } );
 
 			const domRange = document.getSelection().getRangeAt( 0 );
-			expect( treeView.domConverter.startsWithFiller( domRange.startContainer ) ).to.be.true;
-			expect( domRange.startOffset ).to.equal( INLINE_FILLER_SIZE + 1 );
+			expect( startsWithFiller( domRange.startContainer ) ).to.be.true;
+			expect( domRange.startOffset ).to.equal( INLINE_FILLER_LENGTH + 1 );
 			expect( domRange.collapsed ).to.be.true;
 		} );
 	} );