diff options
Diffstat (limited to 'core/dom/walker.js')
| -rw-r--r-- | core/dom/walker.js | 477 |
1 files changed, 0 insertions, 477 deletions
diff --git a/core/dom/walker.js b/core/dom/walker.js deleted file mode 100644 index 0f360e0..0000000 --- a/core/dom/walker.js +++ /dev/null @@ -1,477 +0,0 @@ -/** - * @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.html or http://ckeditor.com/license - */ - -(function() { - // This function is to be called under a "walker" instance scope. - function iterate( rtl, breakOnFalse ) { - var range = this.range; - - // Return null if we have reached the end. - if ( this._.end ) - return null; - - // This is the first call. Initialize it. - if ( !this._.start ) { - this._.start = 1; - - // A collapsed range must return null at first call. - if ( range.collapsed ) { - this.end(); - return null; - } - - // Move outside of text node edges. - range.optimize(); - } - - var node, - startCt = range.startContainer, - endCt = range.endContainer, - startOffset = range.startOffset, - endOffset = range.endOffset, - guard, - userGuard = this.guard, - type = this.type, - getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' ); - - // Create the LTR guard function, if necessary. - if ( !rtl && !this._.guardLTR ) { - // The node that stops walker from moving up. - var limitLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt : endCt.getParent(); - - // The node that stops the walker from going to next. - var blockerLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt.getChild( endOffset ) : endCt.getNext(); - - this._.guardLTR = function( node, movingOut ) { - return ( ( !movingOut || !limitLTR.equals( node ) ) && ( !blockerLTR || !node.equals( blockerLTR ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) ); - }; - } - - // Create the RTL guard function, if necessary. - if ( rtl && !this._.guardRTL ) { - // The node that stops walker from moving up. - var limitRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startCt : startCt.getParent(); - - // The node that stops the walker from going to next. - var blockerRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startOffset ? startCt.getChild( startOffset - 1 ) : null : startCt.getPrevious(); - - this._.guardRTL = function( node, movingOut ) { - return ( ( !movingOut || !limitRTL.equals( node ) ) && ( !blockerRTL || !node.equals( blockerRTL ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) ); - }; - } - - // Define which guard function to use. - var stopGuard = rtl ? this._.guardRTL : this._.guardLTR; - - // Make the user defined guard function participate in the process, - // otherwise simply use the boundary guard. - if ( userGuard ) { - guard = function( node, movingOut ) { - if ( stopGuard( node, movingOut ) === false ) - return false; - - return userGuard( node, movingOut ); - }; - } else - guard = stopGuard; - - if ( this.current ) - node = this.current[ getSourceNodeFn ]( false, type, guard ); - else { - // Get the first node to be returned. - if ( rtl ) { - node = endCt; - - if ( node.type == CKEDITOR.NODE_ELEMENT ) { - if ( endOffset > 0 ) - node = node.getChild( endOffset - 1 ); - else - node = ( guard( node, true ) === false ) ? null : node.getPreviousSourceNode( true, type, guard ); - } - } else { - node = startCt; - - if ( node.type == CKEDITOR.NODE_ELEMENT ) { - if ( !( node = node.getChild( startOffset ) ) ) - node = ( guard( startCt, true ) === false ) ? null : startCt.getNextSourceNode( true, type, guard ); - } - } - - if ( node && guard( node ) === false ) - node = null; - } - - while ( node && !this._.end ) { - this.current = node; - - if ( !this.evaluator || this.evaluator( node ) !== false ) { - if ( !breakOnFalse ) - return node; - } else if ( breakOnFalse && this.evaluator ) - return false; - - node = node[ getSourceNodeFn ]( false, type, guard ); - } - - this.end(); - return this.current = null; - } - - function iterateToLast( rtl ) { - var node, - last = null; - - while ( ( node = iterate.call( this, rtl ) ) ) - last = node; - - return last; - } - - /** - * Utility class to "walk" the DOM inside a range boundaries. If - * necessary, partially included nodes (text nodes) are broken to - * reflect the boundaries limits, so DOM and range changes may happen. - * Outside changes to the range may break the walker. - * - * The walker may return nodes that are not totaly included into the - * range boundaires. Let's take the following range representation, - * where the square brackets indicate the boundaries: - * - * [<p>Some <b>sample] text</b> - * - * While walking forward into the above range, the following nodes are - * returned: `<p>`, `"Some "`, `<b>` and `"sample"`. Going - * backwards instead we have: `"sample"` and `"Some "`. So note that the - * walker always returns nodes when "entering" them, but not when - * "leaving" them. The guard function is instead called both when - * entering and leaving nodes. - * - * @class - */ - CKEDITOR.dom.walker = CKEDITOR.tools.createClass({ - /** - * Creates a walker class instance. - * - * @constructor - * @param {CKEDITOR.dom.range} range The range within which walk. - */ - $: function( range ) { - this.range = range; - - /** - * A function executed for every matched node, to check whether - * it's to be considered into the walk or not. If not provided, all - * matched nodes are considered good. - * - * If the function returns `false` the node is ignored. - * - * @property {Function} evaluator - */ - // this.evaluator = null; - - /** - * A function executed for every node the walk pass by to check - * whether the walk is to be finished. It's called when both - * entering and exiting nodes, as well as for the matched nodes. - * - * If this function returns `false`, the walking ends and no more - * nodes are evaluated. - - * @property {Function} guard - */ - // this.guard = null; - - /** @private */ - this._ = {}; - }, - - // statics : - // { - // /* Creates a CKEDITOR.dom.walker instance to walk inside DOM boundaries set by nodes. - // * @param {CKEDITOR.dom.node} startNode The node from wich the walk - // * will start. - // * @param {CKEDITOR.dom.node} [endNode] The last node to be considered - // * in the walk. No more nodes are retrieved after touching or - // * passing it. If not provided, the walker stops at the - // * <body> closing boundary. - // * @returns {CKEDITOR.dom.walker} A DOM walker for the nodes between the - // * provided nodes. - // */ - // createOnNodes : function( startNode, endNode, startInclusive, endInclusive ) - // { - // var range = new CKEDITOR.dom.range(); - // if ( startNode ) - // range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ; - // else - // range.setStartAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_AFTER_START ) ; - // - // if ( endNode ) - // range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ; - // else - // range.setEndAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_BEFORE_END ) ; - // - // return new CKEDITOR.dom.walker( range ); - // } - // }, - // - proto: { - /** - * Stops walking. No more nodes are retrieved if this function gets called. - */ - end: function() { - this._.end = 1; - }, - - /** - * Retrieves the next node (at right). - * - * @returns {CKEDITOR.dom.node} The next node or null if no more - * nodes are available. - */ - next: function() { - return iterate.call( this ); - }, - - /** - * Retrieves the previous node (at left). - * - * @returns {CKEDITOR.dom.node} The previous node or null if no more - * nodes are available. - */ - previous: function() { - return iterate.call( this, 1 ); - }, - - /** - * Check all nodes at right, executing the evaluation fuction. - * - * @returns {Boolean} `false` if the evaluator function returned - * `false` for any of the matched nodes. Otherwise `true`. - */ - checkForward: function() { - return iterate.call( this, 0, 1 ) !== false; - }, - - /** - * Check all nodes at left, executing the evaluation fuction. - * - * @returns {Boolean} `false` if the evaluator function returned - * `false` for any of the matched nodes. Otherwise `true`. - */ - checkBackward: function() { - return iterate.call( this, 1, 1 ) !== false; - }, - - /** - * Executes a full walk forward (to the right), until no more nodes - * are available, returning the last valid node. - * - * @returns {CKEDITOR.dom.node} The last node at the right or null - * if no valid nodes are available. - */ - lastForward: function() { - return iterateToLast.call( this ); - }, - - /** - * Executes a full walk backwards (to the left), until no more nodes - * are available, returning the last valid node. - * - * @returns {CKEDITOR.dom.node} The last node at the left or null - * if no valid nodes are available. - */ - lastBackward: function() { - return iterateToLast.call( this, 1 ); - }, - - /** - * Resets walker. - */ - reset: function() { - delete this.current; - this._ = {}; - } - - } - }); - - // Anything whose display computed style is block, list-item, table, - // table-row-group, table-header-group, table-footer-group, table-row, - // table-column-group, table-column, table-cell, table-caption, or whose node - // name is hr, br (when enterMode is br only) is a block boundary. - var blockBoundaryDisplayMatch = { block:1,'list-item':1,table:1,'table-row-group':1,'table-header-group':1,'table-footer-group':1,'table-row':1,'table-column-group':1,'table-column':1,'table-cell':1,'table-caption':1 }; - - /** - * @member CKEDITOR.dom.element - * @todo - */ - CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames ) { - var nodeNameMatches = customNodeNames ? CKEDITOR.tools.extend( {}, CKEDITOR.dtd.$block, customNodeNames || {} ) : CKEDITOR.dtd.$block; - - // Don't consider floated formatting as block boundary, fall back to dtd check in that case. (#6297) - return this.getComputedStyle( 'float' ) == 'none' && blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ] || nodeNameMatches[ this.getName() ]; - }; - - /** - * @static - * @todo - */ - CKEDITOR.dom.walker.blockBoundary = function( customNodeNames ) { - return function( node, type ) { - return !( node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary( customNodeNames ) ); - }; - }; - - /** - * @static - * @todo - */ - CKEDITOR.dom.walker.listItemBoundary = function() { - return this.blockBoundary( { br:1 } ); - }; - - /** - * Whether the to-be-evaluated node is a bookmark node OR bookmark node - * inner contents. - * - * @static - * @param {Boolean} [contentOnly=false] Whether only test against the text content of - * bookmark node instead of the element itself (default). - * @param {Boolean} [isReject=false] Whether should return `false` for the bookmark - * node instead of `true` (default). - * @returns {Function} - */ - CKEDITOR.dom.walker.bookmark = function( contentOnly, isReject ) { - function isBookmarkNode( node ) { - return ( node && node.getName && node.getName() == 'span' && node.data( 'cke-bookmark' ) ); - } - - return function( node ) { - var isBookmark, parent; - // Is bookmark inner text node? - isBookmark = ( node && node.type != CKEDITOR.NODE_ELEMENT && ( parent = node.getParent() ) && isBookmarkNode( parent ) ); - // Is bookmark node? - isBookmark = contentOnly ? isBookmark : isBookmark || isBookmarkNode( node ); - return !!( isReject ^ isBookmark ); - }; - }; - - /** - * Whether the node is a text node containing only whitespaces characters. - * - * @static - * @param {Boolean} [isReject=false] - * @returns {Function} - */ - CKEDITOR.dom.walker.whitespaces = function( isReject ) { - return function( node ) { - var isWhitespace; - if ( node && node.type == CKEDITOR.NODE_TEXT ) { - // whitespace, as well as the text cursor filler node we used in Webkit. (#9384) - isWhitespace = !CKEDITOR.tools.trim( node.getText() ) || - CKEDITOR.env.webkit && node.getText() == '\u200b'; - } - - return !! ( isReject ^ isWhitespace ); - }; - }; - - /** - * Whether the node is invisible in wysiwyg mode. - * - * @static - * @param {Boolean} [isReject=false] - * @returns {Function} - */ - CKEDITOR.dom.walker.invisible = function( isReject ) { - var whitespace = CKEDITOR.dom.walker.whitespaces(); - return function( node ) { - var invisible; - - if ( whitespace( node ) ) - invisible = 1; - else { - // Visibility should be checked on element. - if ( node.type == CKEDITOR.NODE_TEXT ) - node = node.getParent(); - - // Nodes that take no spaces in wysiwyg: - // 1. White-spaces but not including NBSP; - // 2. Empty inline elements, e.g. <b></b> we're checking here - // 'offsetHeight' instead of 'offsetWidth' for properly excluding - // all sorts of empty paragraph, e.g. <br />. - invisible = !node.$.offsetHeight; - } - - return !!( isReject ^ invisible ); - }; - }; - - /** - * @static - * @param {Number} type - * @param {Boolean} [isReject=false] - * @returns {Function} - * @todo - */ - CKEDITOR.dom.walker.nodeType = function( type, isReject ) { - return function( node ) { - return !!( isReject ^ ( node.type == type ) ); - }; - }; - - /** - * @static - * @param {Boolean} [isReject=false] - * @returns {Function} - * @todo - */ - CKEDITOR.dom.walker.bogus = function( isReject ) { - function nonEmpty( node ) { - return !isWhitespaces( node ) && !isBookmark( node ); - } - - return function( node ) { - var isBogus = !CKEDITOR.env.ie ? node.is && node.is( 'br' ) : node.getText && tailNbspRegex.test( node.getText() ); - - if ( isBogus ) { - var parent = node.getParent(), - next = node.getNext( nonEmpty ); - - isBogus = parent.isBlockBoundary() && ( !next || next.type == CKEDITOR.NODE_ELEMENT && next.isBlockBoundary() ); - } - - return !!( isReject ^ isBogus ); - }; - }; - - var tailNbspRegex = /^[\t\r\n ]*(?: |\xa0)$/, - isWhitespaces = CKEDITOR.dom.walker.whitespaces(), - isBookmark = CKEDITOR.dom.walker.bookmark(), - toSkip = function( node ) { - return isBookmark( node ) || isWhitespaces( node ) || node.type == CKEDITOR.NODE_ELEMENT && node.getName() in CKEDITOR.dtd.$inline && !( node.getName() in CKEDITOR.dtd.$empty ); - }; - - /** - * Check if there's a filler node at the end of an element, and return it. - * - * @member CKEDITOR.dom.element - * @returns {Boolean} - */ - CKEDITOR.dom.element.prototype.getBogus = function() { - // Bogus are not always at the end, e.g. <p><a>text<br /></a></p> (#7070). - var tail = this; - do { - tail = tail.getPreviousSourceNode(); - } - while ( toSkip( tail ) ) - - if ( tail && ( !CKEDITOR.env.ie ? tail.is && tail.is( 'br' ) : tail.getText && tailNbspRegex.test( tail.getText() ) ) ) { - return tail; - } - return false; - }; - -})(); |
