| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 /* 2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 /** 7 * @file DOM iterator, which iterates over list items, lines and paragraphs. 8 */ 9 10 CKEDITOR.plugins.add( 'domiterator' ); 11 12 (function() 13 { 14 /** 15 * @name CKEDITOR.dom.iterator 16 */ 17 function iterator( range ) 18 { 19 if ( arguments.length < 1 ) 20 return; 21 22 this.range = range; 23 this.forceBrBreak = false; 24 25 // Whether include <br>s into the enlarged range.(#3730). 26 this.enlargeBr = true; 27 this.enforceRealBlocks = false; 28 29 this._ || ( this._ = {} ); 30 } 31 32 var beginWhitespaceRegex = /^[\r\n\t ]+$/, 33 isBookmark = CKEDITOR.dom.walker.bookmark(); 34 35 iterator.prototype = { 36 getNextParagraph : function( blockTag ) 37 { 38 // The block element to be returned. 39 var block; 40 41 // The range object used to identify the paragraph contents. 42 var range; 43 44 // Indicats that the current element in the loop is the last one. 45 var isLast; 46 47 // Instructs to cleanup remaining BRs. 48 var removePreviousBr, removeLastBr; 49 50 // This is the first iteration. Let's initialize it. 51 if ( !this._.lastNode ) 52 { 53 range = this.range.clone(); 54 55 // Shrink the range to exclude harmful "noises" (#4087, #4450, #5435). 56 range.shrink( CKEDITOR.NODE_ELEMENT, true ); 57 58 range.enlarge( this.forceBrBreak || !this.enlargeBr ? 59 CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS : CKEDITOR.ENLARGE_BLOCK_CONTENTS ); 60 61 var walker = new CKEDITOR.dom.walker( range ), 62 ignoreBookmarkTextEvaluator = CKEDITOR.dom.walker.bookmark( true, true ); 63 // Avoid anchor inside bookmark inner text. 64 walker.evaluator = ignoreBookmarkTextEvaluator; 65 this._.nextNode = walker.next(); 66 // TODO: It's better to have walker.reset() used here. 67 walker = new CKEDITOR.dom.walker( range ); 68 walker.evaluator = ignoreBookmarkTextEvaluator; 69 var lastNode = walker.previous(); 70 this._.lastNode = lastNode.getNextSourceNode( true ); 71 72 // We may have an empty text node at the end of block due to [3770]. 73 // If that node is the lastNode, it would cause our logic to leak to the 74 // next block.(#3887) 75 if ( this._.lastNode && 76 this._.lastNode.type == CKEDITOR.NODE_TEXT && 77 !CKEDITOR.tools.trim( this._.lastNode.getText( ) ) && 78 this._.lastNode.getParent().isBlockBoundary() ) 79 { 80 var testRange = new CKEDITOR.dom.range( range.document ); 81 testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END ); 82 if ( testRange.checkEndOfBlock() ) 83 { 84 var path = new CKEDITOR.dom.elementPath( testRange.endContainer ); 85 var lastBlock = path.block || path.blockLimit; 86 this._.lastNode = lastBlock.getNextSourceNode( true ); 87 } 88 } 89 90 // Probably the document end is reached, we need a marker node. 91 if ( !this._.lastNode ) 92 { 93 this._.lastNode = this._.docEndMarker = range.document.createText( '' ); 94 this._.lastNode.insertAfter( lastNode ); 95 } 96 97 // Let's reuse this variable. 98 range = null; 99 } 100 101 var currentNode = this._.nextNode; 102 lastNode = this._.lastNode; 103 104 this._.nextNode = null; 105 while ( currentNode ) 106 { 107 // closeRange indicates that a paragraph boundary has been found, 108 // so the range can be closed. 109 var closeRange = false; 110 111 // includeNode indicates that the current node is good to be part 112 // of the range. By default, any non-element node is ok for it. 113 var includeNode = ( currentNode.type != CKEDITOR.NODE_ELEMENT ), 114 continueFromSibling = false; 115 116 // If it is an element node, let's check if it can be part of the 117 // range. 118 if ( !includeNode ) 119 { 120 var nodeName = currentNode.getName(); 121 122 if ( currentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) ) 123 { 124 // <br> boundaries must be part of the range. It will 125 // happen only if ForceBrBreak. 126 if ( nodeName == 'br' ) 127 includeNode = true; 128 else if ( !range && !currentNode.getChildCount() && nodeName != 'hr' ) 129 { 130 // If we have found an empty block, and haven't started 131 // the range yet, it means we must return this block. 132 block = currentNode; 133 isLast = currentNode.equals( lastNode ); 134 break; 135 } 136 137 // The range must finish right before the boundary, 138 // including possibly skipped empty spaces. (#1603) 139 if ( range ) 140 { 141 range.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START ); 142 143 // The found boundary must be set as the next one at this 144 // point. (#1717) 145 if ( nodeName != 'br' ) 146 this._.nextNode = currentNode; 147 } 148 149 closeRange = true; 150 } 151 else 152 { 153 // If we have child nodes, let's check them. 154 if ( currentNode.getFirst() ) 155 { 156 // If we don't have a range yet, let's start it. 157 if ( !range ) 158 { 159 range = new CKEDITOR.dom.range( this.range.document ); 160 range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START ); 161 } 162 163 currentNode = currentNode.getFirst(); 164 continue; 165 } 166 includeNode = true; 167 } 168 } 169 else if ( currentNode.type == CKEDITOR.NODE_TEXT ) 170 { 171 // Ignore normal whitespaces (i.e. not including or 172 // other unicode whitespaces) before/after a block node. 173 if ( beginWhitespaceRegex.test( currentNode.getText() ) ) 174 includeNode = false; 175 } 176 177 // The current node is good to be part of the range and we are 178 // starting a new range, initialize it first. 179 if ( includeNode && !range ) 180 { 181 range = new CKEDITOR.dom.range( this.range.document ); 182 range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START ); 183 } 184 185 // The last node has been found. 186 isLast = ( ( !closeRange || includeNode ) && currentNode.equals( lastNode ) ); 187 188 // If we are in an element boundary, let's check if it is time 189 // to close the range, otherwise we include the parent within it. 190 if ( range && !closeRange ) 191 { 192 while ( !currentNode.getNext() && !isLast ) 193 { 194 var parentNode = currentNode.getParent(); 195 196 if ( parentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) ) 197 { 198 closeRange = true; 199 isLast = isLast || ( parentNode.equals( lastNode) ); 200 break; 201 } 202 203 currentNode = parentNode; 204 includeNode = true; 205 isLast = ( currentNode.equals( lastNode ) ); 206 continueFromSibling = true; 207 } 208 } 209 210 // Now finally include the node. 211 if ( includeNode ) 212 range.setEndAt( currentNode, CKEDITOR.POSITION_AFTER_END ); 213 214 currentNode = currentNode.getNextSourceNode( continueFromSibling, null, lastNode ); 215 isLast = !currentNode; 216 217 // We have found a block boundary. Let's close the range and move out of the 218 // loop. 219 if ( isLast || ( closeRange && range ) ) 220 break; 221 } 222 223 // Now, based on the processed range, look for (or create) the block to be returned. 224 if ( !block ) 225 { 226 // If no range has been found, this is the end. 227 if ( !range ) 228 { 229 this._.docEndMarker && this._.docEndMarker.remove(); 230 this._.nextNode = null; 231 return null; 232 } 233 234 var startPath = new CKEDITOR.dom.elementPath( range.startContainer ); 235 var startBlockLimit = startPath.blockLimit, 236 checkLimits = { div : 1, th : 1, td : 1 }; 237 block = startPath.block; 238 239 if ( !block 240 && !this.enforceRealBlocks 241 && checkLimits[ startBlockLimit.getName() ] 242 && range.checkStartOfBlock() 243 && range.checkEndOfBlock() ) 244 block = startBlockLimit; 245 else if ( !block || ( this.enforceRealBlocks && block.getName() == 'li' ) ) 246 { 247 // Create the fixed block. 248 block = this.range.document.createElement( blockTag || 'p' ); 249 250 // Move the contents of the temporary range to the fixed block. 251 range.extractContents().appendTo( block ); 252 block.trim(); 253 254 // Insert the fixed block into the DOM. 255 range.insertNode( block ); 256 257 removePreviousBr = removeLastBr = true; 258 } 259 else if ( block.getName() != 'li' ) 260 { 261 // If the range doesn't includes the entire contents of the 262 // block, we must split it, isolating the range in a dedicated 263 // block. 264 if ( !range.checkStartOfBlock() || !range.checkEndOfBlock() ) 265 { 266 // The resulting block will be a clone of the current one. 267 block = block.clone( false ); 268 269 // Extract the range contents, moving it to the new block. 270 range.extractContents().appendTo( block ); 271 block.trim(); 272 273 // Split the block. At this point, the range will be in the 274 // right position for our intents. 275 var splitInfo = range.splitBlock(); 276 277 removePreviousBr = !splitInfo.wasStartOfBlock; 278 removeLastBr = !splitInfo.wasEndOfBlock; 279 280 // Insert the new block into the DOM. 281 range.insertNode( block ); 282 } 283 } 284 else if ( !isLast ) 285 { 286 // LIs are returned as is, with all their children (due to the 287 // nested lists). But, the next node is the node right after 288 // the current range, which could be an <li> child (nested 289 // lists) or the next sibling <li>. 290 291 this._.nextNode = ( block.equals( lastNode ) ? null : 292 range.getBoundaryNodes().endNode.getNextSourceNode( true, null, lastNode ) ); 293 } 294 } 295 296 if ( removePreviousBr ) 297 { 298 var previousSibling = block.getPrevious(); 299 if ( previousSibling && previousSibling.type == CKEDITOR.NODE_ELEMENT ) 300 { 301 if ( previousSibling.getName() == 'br' ) 302 previousSibling.remove(); 303 else if ( previousSibling.getLast() && previousSibling.getLast().$.nodeName.toLowerCase() == 'br' ) 304 previousSibling.getLast().remove(); 305 } 306 } 307 308 if ( removeLastBr ) 309 { 310 // Ignore bookmark nodes.(#3783) 311 var bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true ); 312 313 var lastChild = block.getLast(); 314 if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.getName() == 'br' ) 315 { 316 // Take care not to remove the block expanding <br> in non-IE browsers. 317 if ( CKEDITOR.env.ie 318 || lastChild.getPrevious( bookmarkGuard ) 319 || lastChild.getNext( bookmarkGuard ) ) 320 lastChild.remove(); 321 } 322 } 323 324 // Get a reference for the next element. This is important because the 325 // above block can be removed or changed, so we can rely on it for the 326 // next interation. 327 if ( !this._.nextNode ) 328 { 329 this._.nextNode = ( isLast || block.equals( lastNode ) ) ? null : 330 block.getNextSourceNode( true, null, lastNode ); 331 } 332 333 return block; 334 } 335 }; 336 337 CKEDITOR.dom.range.prototype.createIterator = function() 338 { 339 return new iterator( this ); 340 }; 341 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |