[ Index ] |
|
Code source de FCKeditor 2.4 |
1 /* 2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net 3 * Copyright (C) 2003-2007 Frederico Caldeira Knabben 4 * 5 * == BEGIN LICENSE == 6 * 7 * Licensed under the terms of any of the following licenses at your 8 * choice: 9 * 10 * - GNU General Public License Version 2 or later (the "GPL") 11 * http://www.gnu.org/licenses/gpl.html 12 * 13 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") 14 * http://www.gnu.org/licenses/lgpl.html 15 * 16 * - Mozilla Public License Version 1.1 or later (the "MPL") 17 * http://www.mozilla.org/MPL/MPL-1.1.html 18 * 19 * == END LICENSE == 20 * 21 * File Name: fckdomrange.js 22 * Class for working with a selection range, much like the W3C DOM Range, but 23 * it is not intented to be an implementation of the W3C interface. 24 * 25 * File Authors: 26 * Frederico Caldeira Knabben (www.fckeditor.net) 27 */ 28 29 var FCKDomRange = function( sourceWindow ) 30 { 31 this.Window = sourceWindow ; 32 } 33 34 FCKDomRange.prototype = 35 { 36 37 _UpdateElementInfo : function() 38 { 39 if ( !this._Range ) 40 this.Release( true ) ; 41 else 42 { 43 var eStart = this._Range.startContainer ; 44 var eEnd = this._Range.endContainer ; 45 46 var oElementPath = new FCKElementPath( eStart ) ; 47 this.StartContainer = oElementPath.LastElement ; 48 this.StartBlock = oElementPath.Block ; 49 this.StartBlockLimit = oElementPath.BlockLimit ; 50 51 if ( eStart != eEnd ) 52 oElementPath = new FCKElementPath( eEnd ) ; 53 this.EndContainer = oElementPath.LastElement ; 54 this.EndBlock = oElementPath.Block ; 55 this.EndBlockLimit = oElementPath.BlockLimit ; 56 } 57 }, 58 59 CreateRange : function() 60 { 61 return new FCKW3CRange( this.Window.document ) ; 62 }, 63 64 DeleteContents : function() 65 { 66 if ( this._Range ) 67 { 68 this._Range.deleteContents() ; 69 this._UpdateElementInfo() ; 70 } 71 }, 72 73 ExtractContents : function() 74 { 75 if ( this._Range ) 76 { 77 var docFrag = this._Range.extractContents() ; 78 this._UpdateElementInfo() ; 79 return docFrag ; 80 } 81 }, 82 83 CheckIsCollapsed : function() 84 { 85 if ( this._Range ) 86 return this._Range.collapsed ; 87 }, 88 89 Collapse : function( toStart ) 90 { 91 if ( this._Range ) 92 this._Range.collapse( toStart ) ; 93 94 this._UpdateElementInfo() ; 95 }, 96 97 Clone : function() 98 { 99 var oClone = FCKTools.CloneObject( this ) ; 100 101 if ( this._Range ) 102 oClone._Range = this._Range.cloneRange() ; 103 104 return oClone ; 105 }, 106 107 MoveToNodeContents : function( targetNode ) 108 { 109 if ( !this._Range ) 110 this._Range = this.CreateRange() ; 111 112 this._Range.selectNodeContents( targetNode ) ; 113 114 this._UpdateElementInfo() ; 115 }, 116 117 MoveToElementStart : function( targetElement ) 118 { 119 this.SetStart(targetElement,1) ; 120 this.SetEnd(targetElement,1) ; 121 }, 122 123 InsertNode : function( node ) 124 { 125 if ( this._Range ) 126 this._Range.insertNode( node ) ; 127 }, 128 129 CheckIsEmpty : function( ignoreEndBRs ) 130 { 131 if ( this.CheckIsCollapsed() ) 132 return true ; 133 134 // Inserts the contents of the range in a div tag. 135 var eToolDiv = this.Window.document.createElement( 'div' ) ; 136 this._Range.cloneContents().AppendTo( eToolDiv ) ; 137 138 FCKDomTools.TrimNode( eToolDiv, ignoreEndBRs ) ; 139 140 return ( eToolDiv.innerHTML.length == 0 ) ; 141 }, 142 143 CheckStartOfBlock : function() 144 { 145 // Create a clone of the current range. 146 var oTestRange = this.Clone() ; 147 148 // Collapse it to its start point. 149 oTestRange.Collapse( true ) ; 150 151 // Move the start boundary to the start of the block. 152 oTestRange.SetStart( oTestRange.StartBlock || oTestRange.StartBlockLimit, 1 ) ; 153 154 var bIsStartOfBlock = oTestRange.CheckIsEmpty() ; 155 156 oTestRange.Release() ; 157 158 return bIsStartOfBlock ; 159 }, 160 161 CheckEndOfBlock : function( refreshSelection ) 162 { 163 // Create a clone of the current range. 164 var oTestRange = this.Clone() ; 165 166 // Collapse it to its end point. 167 oTestRange.Collapse( false ) ; 168 169 // Move the end boundary to the end of the block. 170 oTestRange.SetEnd( oTestRange.EndBlock || oTestRange.EndBlockLimit, 2 ) ; 171 172 var bIsEndOfBlock = oTestRange.CheckIsEmpty( true ) ; 173 174 oTestRange.Release() ; 175 176 if ( refreshSelection ) 177 this.Select() ; 178 179 return bIsEndOfBlock ; 180 }, 181 182 CreateBookmark : function() 183 { 184 // Create the bookmark info (random IDs). 185 var oBookmark = 186 { 187 StartId : 'fck_dom_range_start_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000), 188 EndId : 'fck_dom_range_end_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000) 189 } ; 190 191 var oDoc = this.Window.document ; 192 var eSpan ; 193 var oClone ; 194 195 // For collapsed ranges, add just the start marker. 196 if ( !this.CheckIsCollapsed() ) 197 { 198 eSpan = oDoc.createElement( 'span' ) ; 199 eSpan.id = oBookmark.EndId ; 200 eSpan.innerHTML = ' ' ; // For IE, it must have something inside, otherwise it may be removed during operations. 201 202 oClone = this.Clone() ; 203 oClone.Collapse( false ) ; 204 oClone.InsertNode( eSpan ) ; 205 } 206 207 eSpan = oDoc.createElement( 'span' ) ; 208 eSpan.id = oBookmark.StartId ; 209 eSpan.innerHTML = ' ' ; // For IE, it must have something inside, otherwise it may be removed during operations. 210 211 oClone = this.Clone() ; 212 oClone.Collapse( true ) ; 213 oClone.InsertNode( eSpan ) ; 214 215 return oBookmark ; 216 }, 217 218 MoveToBookmark : function( bookmark, preserveBookmark ) 219 { 220 var oDoc = this.Window.document ; 221 222 var eStartSpan = oDoc.getElementById( bookmark.StartId ) ; 223 var eEndSpan = oDoc.getElementById( bookmark.EndId ) ; 224 225 this.SetStart( eStartSpan, 3 ) ; 226 227 if ( !preserveBookmark ) 228 FCKDomTools.RemoveNode( eStartSpan ) ; 229 230 // If collapsed, the start span will not be available. 231 if ( eEndSpan ) 232 { 233 this.SetEnd( eEndSpan, 3 ) ; 234 235 if ( !preserveBookmark ) 236 FCKDomTools.RemoveNode( eEndSpan ) ; 237 } 238 else 239 this.Collapse( true ) ; 240 }, 241 242 /* 243 * Moves the position of the start boundary of the range to a specific position 244 * relatively to a element. 245 * @position: 246 * 1 = After Start <target>^contents</target> 247 * 2 = Before End <target>contents^</target> 248 * 3 = Before Start ^<target>contents</target> 249 * 4 = After End <target>contents</target>^ 250 */ 251 SetStart : function( targetElement, position ) 252 { 253 var oRange = this._Range ; 254 if ( !oRange ) 255 oRange = this._Range = this.CreateRange() ; 256 257 switch( position ) 258 { 259 case 1 : // After Start <target>^contents</target> 260 oRange.setStart( targetElement, 0 ) ; 261 break ; 262 263 case 2 : // Before End <target>contents^</target> 264 oRange.setStart( targetElement, targetElement.childNodes.length ) ; 265 break ; 266 267 case 3 : // Before Start ^<target>contents</target> 268 oRange.setStartBefore( targetElement ) ; 269 break ; 270 271 case 4 : // After End <target>contents</target>^ 272 oRange.setStartAfter( targetElement ) ; 273 } 274 this._UpdateElementInfo() ; 275 }, 276 277 /* 278 * Moves the position of the start boundary of the range to a specific position 279 * relatively to a element. 280 * @position: 281 * 1 = After Start <target>^contents</target> 282 * 2 = Before End <target>contents^</target> 283 * 3 = Before Start ^<target>contents</target> 284 * 4 = After End <target>contents</target>^ 285 */ 286 SetEnd : function( targetElement, position ) 287 { 288 var oRange = this._Range ; 289 if ( !oRange ) 290 oRange = this._Range = this.CreateRange() ; 291 292 switch( position ) 293 { 294 case 1 : // After Start <target>^contents</target> 295 oRange.setEnd( targetElement, 0 ) ; 296 break ; 297 298 case 2 : // Before End <target>contents^</target> 299 oRange.setEnd( targetElement, targetElement.childNodes.length ) ; 300 break ; 301 302 case 3 : // Before Start ^<target>contents</target> 303 oRange.setEndBefore( targetElement ) ; 304 break ; 305 306 case 4 : // After End <target>contents</target>^ 307 oRange.setEndAfter( targetElement ) ; 308 } 309 this._UpdateElementInfo() ; 310 }, 311 312 Expand : function( unit ) 313 { 314 var oNode, oSibling ; 315 316 switch ( unit ) 317 { 318 case 'block_contents' : 319 if ( this.StartBlock ) 320 this.SetStart( this.StartBlock, 1 ) ; 321 else 322 { 323 // Get the start node for the current range. 324 oNode = this._Range.startContainer ; 325 326 // If it is an element, get the current child node for the range (in the offset). 327 // If the offset node is not available, the the first one. 328 if ( oNode.nodeType == 1 ) 329 { 330 if ( !( oNode = oNode.childNodes[ this._Range.startOffset ] ) ) 331 oNode = oNode.firstChild ; 332 } 333 334 // Not able to defined the current position. 335 if ( !oNode ) 336 return ; 337 338 // We must look for the left boundary, relative to the range 339 // start, which is limited by a block element. 340 while ( true ) 341 { 342 oSibling = oNode.previousSibling ; 343 344 if ( !oSibling ) 345 { 346 // Continue if we are not yet in the block limit (inside a <b>, for example). 347 if ( oNode.parentNode != this.StartBlockLimit ) 348 oNode = oNode.parentNode ; 349 else 350 break ; 351 } 352 else if ( oSibling.nodeType != 1 || !(/^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/).test( oSibling.nodeName.toUpperCase() ) ) 353 { 354 // Continue if the sibling is not a block tag. 355 oNode = oSibling ; 356 } 357 else 358 break ; 359 } 360 361 this._Range.setStartBefore( oNode ) ; 362 } 363 364 if ( this.EndBlock ) 365 this.SetEnd( this.EndBlock, 2 ) ; 366 else 367 { 368 oNode = this._Range.endContainer ; 369 if ( oNode.nodeType == 1 ) 370 oNode = oNode.childNodes[ this._Range.endOffset ] || oNode.lastChild ; 371 372 if ( !oNode ) 373 return ; 374 375 // We must look for the right boundary, relative to the range 376 // end, which is limited by a block element. 377 while ( true ) 378 { 379 oSibling = oNode.nextSibling ; 380 381 if ( !oSibling ) 382 { 383 // Continue if we are not yet in the block limit (inide a <b>, for example). 384 if ( oNode.parentNode != this.EndBlockLimit ) 385 oNode = oNode.parentNode ; 386 else 387 break ; 388 } 389 else if ( oSibling.nodeType != 1 || !(/^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/).test( oSibling.nodeName.toUpperCase() ) ) 390 { 391 // Continue if the sibling is not a block tag. 392 oNode = oSibling ; 393 } 394 else 395 break ; 396 } 397 398 this._Range.setEndAfter( oNode ) ; 399 } 400 401 this._UpdateElementInfo() ; 402 } 403 }, 404 405 Release : function( preserveWindow ) 406 { 407 if ( !preserveWindow ) 408 this.Window = null ; 409 410 this.StartContainer = null ; 411 this.StartBlock = null ; 412 this.StartBlockLimit = null ; 413 this.EndContainer = null ; 414 this.EndBlock = null ; 415 this.EndBlockLimit = null ; 416 this._Range = null ; 417 } 418 } ;
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 15:28:05 2007 | par Balluche grâce à PHPXref 0.7 |