| | 1 | /* |
| | 2 | Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. |
| | 3 | For licensing, see LICENSE.html or http://ckeditor.com/license |
| | 4 | */ |
| | 5 | |
| | 6 | (function() |
| | 7 | { |
| | 8 | // This function is to be called under a "walker" instance scope. |
| | 9 | function iterate( rtl, breakOnFalse ) |
| | 10 | { |
| | 11 | if ( this._.end ) |
| | 12 | return null; |
| | 13 | |
| | 14 | var node, |
| | 15 | type = this.type, |
| | 16 | getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' ); |
| | 17 | |
| | 18 | var guard = this.guard, |
| | 19 | endNode = this.endNode; |
| | 20 | |
| | 21 | if ( endNode ) |
| | 22 | { |
| | 23 | if ( guard ) |
| | 24 | { |
| | 25 | var originalGuard; |
| | 26 | guard = function( node ) |
| | 27 | { |
| | 28 | if ( node.equals( endNode ) ) |
| | 29 | return false; |
| | 30 | |
| | 31 | return originalGuard( node ); |
| | 32 | } |
| | 33 | } |
| | 34 | else |
| | 35 | guard = endNode; |
| | 36 | } |
| | 37 | |
| | 38 | if ( this.current ) |
| | 39 | node = this.current[ getSourceNodeFn ]( false, type, guard ); |
| | 40 | else if ( this.startInclusive ) |
| | 41 | { |
| | 42 | node = this.startNode; |
| | 43 | if ( this.guard && this.guard( node ) === false ) |
| | 44 | node = null; |
| | 45 | } |
| | 46 | else |
| | 47 | node = this.startNode[ getSourceNodeFn ]( true, type, guard ); |
| | 48 | |
| | 49 | while ( node && !this._.end ) |
| | 50 | { |
| | 51 | this.current = node; |
| | 52 | |
| | 53 | if ( node == this.endNode && !this.endInclusive ) |
| | 54 | break; |
| | 55 | |
| | 56 | if ( !this.evaluator && this.evaluator( node ) !== false ) |
| | 57 | return node; |
| | 58 | else if ( breakOnFalse && this.evaluator ) |
| | 59 | return false; |
| | 60 | |
| | 61 | node = node[ getSourceNodeFn ]( false, type, guard ); |
| | 62 | } |
| | 63 | |
| | 64 | this.end(); |
| | 65 | return this.current = null; |
| | 66 | } |
| | 67 | |
| | 68 | function iterateToLast( rtl ) |
| | 69 | { |
| | 70 | var node, last; |
| | 71 | |
| | 72 | while ( node = iterate.call( this, rtl ) ) |
| | 73 | last = node; |
| | 74 | |
| | 75 | return last; |
| | 76 | } |
| | 77 | |
| | 78 | CKEDITOR.dom.walker = CKEDITOR.tools.createClass( |
| | 79 | { |
| | 80 | /** |
| | 81 | * Utility class to "walk" inside a DOM tree starting from a specific |
| | 82 | * node. Each step in the walk can be preciselly controlled. |
| | 83 | * @constructor |
| | 84 | * @param {CKEDITOR.dom.node} startNode The node from wich the walk |
| | 85 | * will start. |
| | 86 | * @param {CKEDITOR.dom.node} [endNode] The last node to be considered |
| | 87 | * in the walk. No more nodes are retrieved after touching or |
| | 88 | * passing it. |
| | 89 | */ |
| | 90 | $ : function( startNode, endNode ) |
| | 91 | { |
| | 92 | /** |
| | 93 | * The node from which start walking. |
| | 94 | * @type {CKEDITOR.dom.node} |
| | 95 | */ |
| | 96 | this.startNode = startNode; |
| | 97 | |
| | 98 | /** |
| | 99 | * The end boundary node of the walk. |
| | 100 | * @type {CKEDITOR.dom.node} |
| | 101 | */ |
| | 102 | this.endNode = endNode; |
| | 103 | |
| | 104 | /** |
| | 105 | * Indicates that the start node is to be included in the walk. |
| | 106 | * @name CKEDITOR.pluginDefinition.prototype.startInclusive |
| | 107 | * @property |
| | 108 | * @type Boolean |
| | 109 | * @default false |
| | 110 | */ |
| | 111 | // this.startInclusive = false; |
| | 112 | |
| | 113 | /** |
| | 114 | * Indicates that the end node is to be included in the walk. |
| | 115 | * @name CKEDITOR.pluginDefinition.prototype.endInclusive |
| | 116 | * @property |
| | 117 | * @type Boolean |
| | 118 | * @default false |
| | 119 | */ |
| | 120 | // this.endInclusive = false; |
| | 121 | |
| | 122 | /** |
| | 123 | * A function executed for every matched node, to check whether |
| | 124 | * it's to be considered into the walk or not. If not provided, all |
| | 125 | * matched nodes are considered good. |
| | 126 | * If the function returns "false" the node is ignored. |
| | 127 | * @name CKEDITOR.pluginDefinition.prototype.evaluator |
| | 128 | * @property |
| | 129 | * @type Function |
| | 130 | */ |
| | 131 | // this.evaluator = null; |
| | 132 | |
| | 133 | /** |
| | 134 | * A function executed for every node the walk pass by to check |
| | 135 | * whether the walk is to be finished. It's called when both |
| | 136 | * entering and exiting nodes, as well as for the matched nodes. |
| | 137 | * If this function returns "false", the walking ends and no more |
| | 138 | * nodes are evaluated. |
| | 139 | * @name CKEDITOR.pluginDefinition.prototype.guard |
| | 140 | * @property |
| | 141 | * @type Function |
| | 142 | */ |
| | 143 | // this.guard = null; |
| | 144 | |
| | 145 | /** @private */ |
| | 146 | this._ = {}; |
| | 147 | }, |
| | 148 | |
| | 149 | proto : |
| | 150 | { |
| | 151 | /** |
| | 152 | * Stop walking. No more nodes are retrieved if this function gets |
| | 153 | * called. |
| | 154 | */ |
| | 155 | end : function() |
| | 156 | { |
| | 157 | this._.end = 1; |
| | 158 | }, |
| | 159 | |
| | 160 | /** |
| | 161 | * Retrieves the next node (at right). |
| | 162 | * @returns {CKEDITOR.dom.node} The next node or null if no more |
| | 163 | * nodes are available. |
| | 164 | */ |
| | 165 | next : function() |
| | 166 | { |
| | 167 | return iterate.call( this ); |
| | 168 | }, |
| | 169 | |
| | 170 | /** |
| | 171 | * Retrieves the previous node (at left). |
| | 172 | * @returns {CKEDITOR.dom.node} The previous node or null if no more |
| | 173 | * nodes are available. |
| | 174 | */ |
| | 175 | previous : function() |
| | 176 | { |
| | 177 | return iterate.call( this, true ); |
| | 178 | }, |
| | 179 | |
| | 180 | /** |
| | 181 | * Executes a full walk forward (to the right), until no more nodes |
| | 182 | * are available, returning the last valid node. |
| | 183 | * @returns {CKEDITOR.dom.node} The last node at the right or null |
| | 184 | * if no valid nodes are available. |
| | 185 | */ |
| | 186 | lastForward : function() |
| | 187 | { |
| | 188 | return iterateToLast.call( this ); |
| | 189 | }, |
| | 190 | |
| | 191 | /** |
| | 192 | * Executes a full walk backwards (to the left), until no more nodes |
| | 193 | * are available, returning the last valid node. |
| | 194 | * @returns {CKEDITOR.dom.node} The last node at the left or null |
| | 195 | * if no valid nodes are available. |
| | 196 | */ |
| | 197 | lastBackward : function() |
| | 198 | { |
| | 199 | return iterateToLast.call( this, true ); |
| | 200 | }, |
| | 201 | |
| | 202 | /** |
| | 203 | * Check all nodes at right, executing the evaluation fuction. |
| | 204 | * @returns {Boolean} "false" if the evaluator function returned |
| | 205 | * "false" for any of the matched nodes. Otherwise "true". |
| | 206 | */ |
| | 207 | checkForward : function() |
| | 208 | { |
| | 209 | return iterate.call( this, false, true ) !== false; |
| | 210 | }, |
| | 211 | |
| | 212 | /** |
| | 213 | * Check all nodes at left, executing the evaluation fuction. |
| | 214 | * @returns {Boolean} "false" if the evaluator function returned |
| | 215 | * "false" for any of the matched nodes. Otherwise "true". |
| | 216 | */ |
| | 217 | checkBackward : function() |
| | 218 | { |
| | 219 | return iterate.call( this, true, true ) !== false; |
| | 220 | } |
| | 221 | } |
| | 222 | }); |
| | 223 | })(); |
| | 224 | No newline at end of file |