Ticket #2150: 2150_6.patch
File 2150_6.patch, 22.6 KB (added by , 17 years ago) |
---|
-
_whatsnew.html
39 39 <ul> 40 40 <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2142">#2142</a>] HTML samples will 41 41 now use sampleposteddata.php in action parameter inside a form.</li> 42 <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2150">#2150</a>] The searching 43 speed of the Find/Replace dialog has been vastly improved.</li> 42 44 </ul> 43 45 <p> 44 46 Fixed Bugs:</p> … … 75 77 catch focus in IE on load when StartupFocus is false and the initial content is empty.</li> 76 78 <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2126">#2126</a>] Opening and closing floating 77 79 dialogs will no longer cause toolbar button states to become frozen.</li> 80 <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2159">#2159</a>] Selection are now 81 correctly restored when undoing changes made by the Replace dialog.</li> 82 <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2160">#2160</a>] "Match whole word" in the 83 Find and Replace dialog will now find words next to punctuation marks as well.</li> 78 84 </ul> 79 85 <h3> 80 86 Version 2.6</h3> -
editor/dialog/fck_replace.html
34 34 var dialogArguments = dialog.Args() ; 35 35 36 36 var FCKLang = oEditor.FCKLang ; 37 var FCKDomTools = oEditor.FCKDomTools ; 38 var FCKDomRange = oEditor.FCKDomRange ; 39 var FCKListsLib = oEditor.FCKListsLib ; 40 var FCKTools = oEditor.FCKTools ; 41 var EditorDocument = oEditor.FCK.EditorDocument ; 42 var HighlightStyle = oEditor.FCKStyles.GetStyle( '_FCK_SelectionHighlight' ) ; 37 43 38 44 dialog.AddTab( 'Find', FCKLang.DlgFindTitle ) ; 39 45 dialog.AddTab( 'Replace', FCKLang.DlgReplaceTitle ) ; … … 51 57 dialog.SetAutoSize( true ) ; 52 58 } 53 59 54 // Place a range at the start of document. 55 // This will be the starting point of our search. 56 var GlobalRange = new oEditor.FCKDomRange( oEditor.FCK.EditorWindow ) ; 57 58 function ResetGlobalRange() 60 GetNextNonEmptyTextNode = function( node, stopNode ) 59 61 { 60 GlobalRange.SetStart( oEditor.FCK.EditorDocument.body, 1 );61 GlobalRange.SetEnd( oEditor.FCK.EditorDocument.body,1 ) ;62 GlobalRange.Collapse( true );62 var node ; 63 while ( ( node = FCKDomTools.GetNextSourceNode( node, false, 3, stopNode ) ) && node && node.length < 1 ) ; 64 return node ; 63 65 } 64 ResetGlobalRange() ;65 66 66 var HighlightRange = null ; 67 function Highlight() 67 CharacterCursor = function( arg ) 68 68 { 69 if ( HighlightRange ) 70 ClearHighlight() ; 71 var cloneRange = GlobalRange.Clone() ; 72 oEditor.FCKStyles.GetStyle( '_FCK_SelectionHighlight' ).ApplyToRange( cloneRange, false, true ) ; 73 HighlightRange = cloneRange ; 74 GlobalRange = HighlightRange.Clone() ; 75 } 76 77 function ClearHighlight() 78 { 79 if ( HighlightRange ) 69 if ( arg.nodeType && arg.nodeType == 9 ) 80 70 { 81 oEditor.FCKStyles.GetStyle( '_FCK_SelectionHighlight' ).RemoveFromRange( HighlightRange, false, true ) ; 82 HighlightRange = null ; 71 this._textNode = GetNextNonEmptyTextNode( arg.body, arg.documentElement ) ; 72 this._offset = 0 ; 73 this._doc = arg ; 83 74 } 75 else 76 { 77 this._textNode = arguments[0] ; 78 this._offset = arguments[1] ; 79 this._doc = FCKTools.GetElementDocument( arguments[0] ) ; 80 } 84 81 } 85 86 function OnLoad() 82 CharacterCursor.prototype = 87 83 { 88 // First of all, translate the dialog box texts. 89 oEditor.FCKLanguageManager.TranslatePage( document ) ; 84 GetCharacter : function() 85 { 86 return ( this._textNode && this._textNode.nodeValue.charAt( this._offset ) ) || null ; 87 }, 90 88 91 // Show the appropriate tab at startup.92 if ( dialogArguments.CustomValue == 'Find')89 // Non-normalized. 90 GetTextNode : function() 93 91 { 94 dialog.SetSelectedTab( 'Find' ) ; 95 dialog.SetAutoSize( true ) ; 96 } 97 else 98 dialog.SetSelectedTab( 'Replace' ) ; 92 return this._textNode ; 93 }, 99 94 100 SelectField( 'txtFind' + dialogArguments.CustomValue ) ; 101 } 95 // Non-normalized. 96 GetIndex : function() 97 { 98 return this._offset ; 99 }, 102 100 103 function btnStat() 104 { 105 GetE('btnReplace').disabled = 106 GetE('btnReplaceAll').disabled = 107 GetE('btnFind').disabled = 108 ( GetE(idMap["FindText"]).value.length == 0 ) ; 109 } 101 // Return value means whehther we've crossed a line break or a paragraph boundary. 102 MoveNext : function() 103 { 104 if ( this._offset < this._textNode.length - 1 ) 105 { 106 this._offset++ ; 107 return false ; 108 } 110 109 111 function btnStatDelayed() 112 { 113 setTimeout( btnStat, 1 ) ; 114 } 110 var crossed = false ; 111 var curNode = this._textNode ; 112 while ( ( curNode = FCKDomTools.GetNextSourceNode( curNode ) ) 113 && curNode && ( curNode.nodeType != 3 || curNode.length < 1 ) ) 114 { 115 var tag = curNode.nodeName.toLowerCase() ; 116 if ( FCKListsLib.BlockElements[tag] || tag == 'br' ) 117 crossed = true ; 118 } 115 119 116 function GetSearchString() 117 { 118 return GetE(idMap['FindText']).value;119 } 120 this._textNode = curNode ; 121 this._offset = 0 ; 122 return crossed ; 123 }, 120 124 121 function GetReplaceString() 122 { 123 return GetE("txtReplace").value ; 124 } 125 // Return value means whehther we've crossed a line break or a paragraph boundary. 126 MoveBack : function() 127 { 128 if ( this._offset > 0 && this._textNode.length > 0 ) 129 { 130 this._offset = Math.min( this._offset - 1, this._textNode.length - 1 ) ; 131 return false ; 132 } 125 133 126 function GetCheckCase() 127 { 128 return !! ( GetE(idMap['CheckCase']).checked ) ; 129 } 134 var crossed = false ; 135 var curNode = this._textNode ; 136 while ( ( curNode = FCKDomTools.GetPreviousSourceNode( curNode ) ) 137 && curNode && ( curNode.nodeType != 3 || curNode.length < 1 ) ) 138 { 139 var tag = curNode.nodeName.toLowerCase() ; 140 if ( FCKListsLib.BlockElements[tag] || tag == 'br' ) 141 crossed = true ; 142 } 130 143 131 function GetMatchWord() 144 this._textNode = curNode ; 145 this._offset = curNode.length - 1 ; 146 return crossed ; 147 }, 148 149 Clone : function() 150 { 151 return new CharacterCursor( this._textNode, this._offset ) ; 152 } 153 } ; 154 155 CharacterRange = function( initCursor, maxLength ) 132 156 { 133 return !! ( GetE(idMap['CheckWord']).checked ) ; 157 this._cursors = initCursor.push ? initCursor : [initCursor] ; 158 this._maxLength = maxLength ; 159 this._highlightRange = null ; 134 160 } 135 136 // Get the data pointed to by a bookmark. 137 function GetData( bookmark ) 161 CharacterRange.prototype = 138 162 { 139 var cursor = oEditor.FCK.EditorDocument.documentElement ; 140 for ( var i = 0 ; i < bookmark.length ; i++ ) 163 ToDomRange : function() 141 164 { 142 var target = bookmark[i] ; 143 var currentIndex = -1 ; 144 if ( cursor.nodeType != 3 ) 165 var firstCursor = this._cursors[0] ; 166 var lastCursor = this._cursors[ this._cursors.length - 1 ] ; 167 var domRange = new FCKDomRange( FCKTools.GetElementWindow( firstCursor.GetTextNode() ) ) ; 168 var w3cRange = domRange._Range = domRange.CreateRange() ; 169 w3cRange.setStart( firstCursor.GetTextNode(), firstCursor.GetIndex() ) ; 170 w3cRange.setEnd( lastCursor.GetTextNode(), lastCursor.GetIndex() + 1 ) ; 171 domRange._UpdateElementInfo() ; 172 return domRange ; 173 }, 174 175 Highlight : function() 176 { 177 if ( this._cursors.length < 1 ) 178 return ; 179 180 var domRange = this.ToDomRange() ; 181 HighlightStyle.ApplyToRange( domRange, false, true ) ; 182 this._highlightRange = domRange ; 183 184 var charRange = CharacterRange.CreateFromDomRange( domRange ) ; 185 var focusNode = domRange.StartNode ; 186 if ( focusNode.nodeType != 1 ) 187 focusNode = focusNode.parentNode ; 188 focusNode.scrollIntoView( false ) ; 189 this._cursors = charRange._cursors ; 190 }, 191 192 RemoveHighlight : function() 193 { 194 if ( this._highlightRange ) 145 195 { 146 for (var j = 0 ; j < cursor.childNodes.length ; j++ ) 147 { 148 var candidate = cursor.childNodes[j] ; 149 if ( candidate.nodeType == 3 && 150 candidate.previousSibling && 151 candidate.previousSibling.nodeType == 3 ) 152 continue ; 153 currentIndex++ ; 154 if ( currentIndex == target ) 155 { 156 cursor = candidate ; 157 break ; 158 } 159 } 160 if ( currentIndex < target ) 161 return null ; 196 HighlightStyle.RemoveFromRange( this._highlightRange, false, true ) ; 197 var charRange = CharacterRange.CreateFromDomRange( this._highlightRange ) ; 198 this._cursors = charRange._cursors ; 199 this._highlightRange = null ; 162 200 } 163 else 164 { 165 if ( i != bookmark.length - 1 ) 166 return null ; 167 while ( target >= cursor.length && cursor.nextSibling && cursor.nextSibling.nodeType == 3 ) 168 { 169 target -= cursor.length ; 170 cursor = cursor.nextSibling ; 171 } 172 cursor = cursor.nodeValue.charAt( target ) ; 173 if ( cursor == "" ) 174 cursor = null ; 175 } 201 }, 202 203 GetHighlightDomRange : function() 204 { 205 return this._highlightRange; 206 }, 207 208 MoveNext : function() 209 { 210 var next = this._cursors[ this._cursors.length - 1 ].Clone() ; 211 var retval = next.MoveNext() ; 212 if ( retval ) 213 this._cursors = [] ; 214 this._cursors.push( next ) ; 215 if ( this._cursors.length > this._maxLength ) 216 this._cursors.shift() ; 217 return retval ; 218 }, 219 220 MoveBack : function() 221 { 222 var prev = this._cursors[0].Clone() ; 223 var retval = prev.MoveBack() ; 224 if ( retval ) 225 this._cursors = [] ; 226 this._cursors.unshift( prev ) ; 227 if ( this._cursors.length > this._maxLength ) 228 this._cursors.pop() ; 229 return retval ; 230 }, 231 232 GetEndCharacter : function() 233 { 234 if ( this._cursors.length < 1 ) 235 return null ; 236 var retval = this._cursors[ this._cursors.length - 1 ].GetCharacter() ; 237 return retval ; 238 }, 239 240 GetNextRange : function( len ) 241 { 242 if ( this._cursors.length == 0 ) 243 return null ; 244 var cur = this._cursors[ this._cursors.length - 1 ].Clone() ; 245 cur.MoveNext() ; 246 return new CharacterRange( cur, len ) ; 247 }, 248 249 GetCursors : function() 250 { 251 return this._cursors ; 176 252 } 177 return cursor ; 178 } 253 } ; 179 254 180 // With this function, we can treat the bookmark as an iterator for DFS. 181 function NextPosition( bookmark ) 255 CharacterRange.CreateFromDomRange = function( domRange ) 182 256 { 183 // See if there's anything further down the tree.184 var next = bookmark.concat( [0] );185 if ( GetData( next ) != null )186 return next;257 var w3cRange = domRange._Range ; 258 var startContainer = w3cRange.startContainer ; 259 var endContainer = w3cRange.endContainer ; 260 var startTextNode, startIndex, endTextNode, endIndex ; 187 261 188 // Nothing down there? See if there's anything next to me. 189 var next = bookmark.slice( 0, bookmark.length - 1 ).concat( [ bookmark[ bookmark.length - 1 ] + 1 ] ) ; 190 if ( GetData( next ) != null ) 191 return next ; 262 if ( startContainer.nodeType == 3 ) 263 { 264 startTextNode = startContainer ; 265 startIndex = w3cRange.startOffset ; 266 } 267 else if ( domRange.StartNode.nodeType == 3 ) 268 { 269 startTextNode = domRange.StartNode ; 270 startIndex = 0 ; 271 } 272 else 273 { 274 startTextNode = GetNextNonEmptyTextNode( domRange.StartNode, domRange.StartNode.parentNode ) ; 275 if ( !startTextNode ) 276 return null ; 277 startIndex = 0 ; 278 } 192 279 193 // Nothing even next to me? See if there's anything next to my ancestors. 194 for ( var i = bookmark.length - 1 ; i > 0 ; i-- ) 280 if ( endContainer.nodeType == 3 && w3cRange.endOffset > 0 ) 195 281 { 196 var next = bookmark.slice( 0, i - 1 ).concat( [ bookmark[ i - 1 ] + 1 ] ) ; 197 if ( GetData( next ) != null ) 198 return next ; 282 endTextNode = endContainer ; 283 endIndex = w3cRange.endOffset - 1 ; 199 284 } 285 else 286 { 287 endTextNode = domRange.EndNode ; 288 while ( endTextNode.nodeType != 3 ) 289 endTextNode = endTextNode.lastChild ; 290 endIndex = endTextNode.length - 1 ; 291 } 200 292 201 // There's absolutely nothing left to walk, return null. 202 return null ; 203 } 204 205 // Is this character a unicode whitespace? 206 // Reference: http://unicode.org/Public/UNIDATA/PropList.txt 207 function CheckIsWhitespace( c ) 208 { 209 var code = c.charCodeAt( 0 ); 210 if ( code >= 9 && code <= 0xd ) 211 return true; 212 if ( code >= 0x2000 && code <= 0x200a ) 213 return true; 214 switch ( code ) 293 var cursors = [] ; 294 var current = new CharacterCursor( startTextNode, startIndex ) ; 295 cursors.push( current ) ; 296 if ( !( current.GetTextNode() == endTextNode && current.GetIndex() == endIndex ) && !domRange.CheckIsEmpty() ) 215 297 { 216 case 0x20: 217 case 0x85: 218 case 0xa0: 219 case 0x1680: 220 case 0x180e: 221 case 0x2028: 222 case 0x2029: 223 case 0x202f: 224 case 0x205f: 225 case 0x3000: 226 return true; 227 default: 228 return false; 298 do 299 { 300 current = current.Clone() ; 301 current.MoveNext() ; 302 cursors.push( current ) ; 303 } 304 while ( !( current.GetTextNode() == endTextNode && current.GetIndex() == endIndex ) ) ; 229 305 } 306 307 return new CharacterRange( cursors, cursors.length ) ; 230 308 } 231 309 232 310 // Knuth-Morris-Pratt Algorithm for stream input 233 311 KMP_NOMATCH = 0 ; 234 312 KMP_ADVANCED = 1 ; 235 313 KMP_MATCHED = 2 ; 236 function KmpMatch( pattern, ignoreCase )314 KmpMatch = function( pattern, ignoreCase ) 237 315 { 238 316 var overlap = [ -1 ] ; 239 317 for ( var i = 0 ; i < pattern.length ; i++ ) … … 251 329 this.Pattern = pattern ; 252 330 } 253 331 KmpMatch.prototype = { 254 "FeedCharacter": function( c )332 FeedCharacter : function( c ) 255 333 { 256 334 if ( this._IgnoreCase ) 257 335 c = c.toLowerCase(); … … 277 355 278 356 return null ; 279 357 }, 280 "Reset" : function() 358 359 Reset : function() 281 360 { 282 361 this._State = 0 ; 283 362 } 284 363 }; 285 364 286 function _Find() 365 // Place a range at the start of document. 366 function OnLoad() 287 367 { 288 // Start from the end of the current selection. 289 var matcher = new KmpMatch( GetSearchString(), ! GetCheckCase() ) ; 290 var cursor = GlobalRange.CreateBookmark2().End ; 291 var matchState = KMP_NOMATCH ; 292 var matchBookmark = null ; 293 var matchBookmarkStart = [] ; 368 // First of all, translate the dialog box texts. 369 oEditor.FCKLanguageManager.TranslatePage( document ) ; 294 370 295 // Match finding.296 while ( true)371 // Show the appropriate tab at startup. 372 if ( dialogArguments.CustomValue == 'Find' ) 297 373 { 298 // Perform KMP stream matching. 299 // - Reset KMP matcher if we encountered a block element. 300 var data = GetData( cursor ) ; 301 if ( data ) 302 { 303 if ( data.tagName ) 304 { 305 if ( oEditor.FCKListsLib.BlockElements[ data.tagName.toLowerCase() ] ) 306 { 307 matcher.Reset(); 308 matchBookmarkStart = [] ; 309 } 310 } 311 else if ( data.charAt != undefined ) 312 { 313 matchState = matcher.FeedCharacter(data) ; 374 dialog.SetSelectedTab( 'Find' ) ; 375 dialog.SetAutoSize( true ) ; 376 } 377 else 378 dialog.SetSelectedTab( 'Replace' ) ; 314 379 315 // No possible match of any useful substring in the pattern for the currently scanned character. 316 // So delete any positional information. 317 if ( matchState == KMP_NOMATCH ) 318 matchBookmarkStart = [] ; 319 // We've matched something, but it's not a complete match, so let's just mark down the position for backtracking later. 320 else if ( matchState == KMP_ADVANCED ) 321 { 322 matchBookmarkStart.push( cursor.concat( [] ) ) ; 323 if ( matchBookmarkStart.length > matcher._State ) 324 matchBookmarkStart.shift() ; 325 } 326 // Found a complete match! Mark down the ending position as well. 327 else if ( matchState == KMP_MATCHED ) 328 { 329 // It is possible to get a KMP_MATCHED without KMP_ADVANCED when the match pattern is only 1 character. 330 // So need to check and mark down the starting position as well. 331 if ( matchBookmarkStart.length == 0 ) 332 matchBookmarkStart = [cursor.concat( [] )] ; 380 SelectField( 'txtFind' + dialogArguments.CustomValue ) ; 381 } 333 382 334 matchBookmark = { 'Start' : matchBookmarkStart.shift(), 'End' : cursor.concat( [] ) } ; 335 matchBookmark.End[ matchBookmark.End.length - 1 ]++; 383 function btnStat() 384 { 385 GetE('btnReplace').disabled = 386 GetE('btnReplaceAll').disabled = 387 GetE('btnFind').disabled = 388 ( GetE(idMap["FindText"]).value.length == 0 ) ; 389 } 336 390 337 // Wait, do we have to match a whole word? 338 // If yes, carry out additional checks on what we've got. 339 if ( GetMatchWord() ) 340 { 341 var startOk = false ; 342 var endOk = false ; 343 var start = matchBookmark.Start ; 344 var end = matchBookmark.End ; 345 if ( start[ start.length - 1 ] == 0 ) 346 startOk = true ; 347 else 348 { 349 var cursorBeforeStart = start.slice( 0, start.length - 1 ) ; 350 cursorBeforeStart.push( start[ start.length - 1 ] - 1 ) ; 351 var dataBeforeStart = GetData( cursorBeforeStart ) ; 352 if ( dataBeforeStart == null || dataBeforeStart.charAt == undefined ) 353 startOk = true ; 354 else if ( CheckIsWhitespace( dataBeforeStart ) ) 355 startOk = true ; 356 } 391 function btnStatDelayed() 392 { 393 setTimeout( btnStat, 1 ) ; 394 } 357 395 358 // this is already one character beyond the last char, no need to move 359 var cursorAfterEnd = end ; 360 var dataAfterEnd = GetData( cursorAfterEnd ); 361 if ( dataAfterEnd == null || dataAfterEnd.charAt == undefined ) 362 endOk = true ; 363 else if ( CheckIsWhitespace( dataAfterEnd ) ) 364 endOk = true ; 396 function GetSearchString() 397 { 398 return GetE(idMap['FindText']).value ; 399 } 365 400 366 if ( startOk && endOk ) 367 break ; 368 else 369 matcher.Reset() ; 370 } 371 else 372 break ; 373 } 374 } 375 } 401 function GetReplaceString() 402 { 403 return GetE("txtReplace").value ; 404 } 376 405 377 // Perform DFS across the document, until we've reached the end. 378 cursor = NextPosition( cursor ) ; 379 if ( cursor == null ) 380 break; 406 function GetCheckCase() 407 { 408 return !! ( GetE(idMap['CheckCase']).checked ) ; 409 } 410 411 function GetMatchWord() 412 { 413 return !! ( GetE(idMap['CheckWord']).checked ) ; 414 } 415 416 /* Is this character a unicode whitespace or a punctuation mark? 417 * References: 418 * http://unicode.org/Public/UNIDATA/PropList.txt (whitespaces) 419 * http://php.chinaunix.net/manual/tw/ref.regex.php (punctuation marks) 420 */ 421 function CheckIsWordSeparator( c ) 422 { 423 var code = c.charCodeAt( 0 ); 424 if ( code >= 9 && code <= 0xd ) 425 return true; 426 if ( code >= 0x2000 && code <= 0x200a ) 427 return true; 428 switch ( code ) 429 { 430 case 0x20: 431 case 0x85: 432 case 0xa0: 433 case 0x1680: 434 case 0x180e: 435 case 0x2028: 436 case 0x2029: 437 case 0x202f: 438 case 0x205f: 439 case 0x3000: 440 return true; 441 default: 381 442 } 443 return /[.,"'?!;:]/.test( c ) ; 444 } 382 445 383 // If we've found a match, highlight the match. 384 if ( matchState == KMP_MATCHED ) 446 FindRange = null ; 447 function _Find() 448 { 449 var searchString = GetSearchString() ; 450 if ( !FindRange ) 451 FindRange = new CharacterRange( new CharacterCursor( EditorDocument ), searchString.length ) ; 452 else 385 453 { 386 GlobalRange.MoveToBookmark2( matchBookmark ) ; 387 Highlight() ; 388 var focus = GlobalRange._Range.endContainer ; 389 while ( focus && focus.nodeType != 1 ) 390 focus = focus.parentNode ; 454 FindRange.RemoveHighlight() ; 455 FindRange = FindRange.GetNextRange( searchString.length ) ; 456 } 457 var matcher = new KmpMatch( searchString, ! GetCheckCase() ) ; 458 var matchState = KMP_NOMATCH ; 459 var character = '%' ; 391 460 392 if ( focus ) 461 while ( character != null ) 462 { 463 while ( ( character = FindRange.GetEndCharacter() ) ) 393 464 { 394 if ( oEditor.FCKBrowserInfo.IsSafari ) 395 oEditor.FCKDomTools.ScrollIntoView( focus, false ) ; 396 else 397 focus.scrollIntoView( false ) ; 465 matchState = matcher.FeedCharacter( character ) ; 466 if ( matchState == KMP_MATCHED ) 467 break ; 468 if ( FindRange.MoveNext() ) 469 matcher.Reset() ; 398 470 } 399 471 400 return true ; 472 if ( matchState == KMP_MATCHED ) 473 { 474 if ( GetMatchWord() ) 475 { 476 var cursors = FindRange.GetCursors() ; 477 var head = cursors[ cursors.length - 1 ].Clone() ; 478 var tail = cursors[0].Clone() ; 479 if ( !head.MoveNext() && !CheckIsWordSeparator( head.GetCharacter() ) ) 480 continue ; 481 if ( !tail.MoveBack() && !CheckIsWordSeparator( tail.GetCharacter() ) ) 482 continue ; 483 } 484 485 FindRange.Highlight() ; 486 return true ; 487 } 401 488 } 402 else 403 { 404 ResetGlobalRange() ; 405 return false ; 406 } 489 490 FindRange = null ; 491 return false ; 407 492 } 408 493 409 494 function Find() 410 495 { 411 496 if ( ! _Find() ) 412 {413 ClearHighlight() ;414 497 alert( FCKLang.DlgFindNotFoundMsg ) ; 415 }416 498 } 417 499 418 500 function Replace() 419 501 { 420 if ( GlobalRange.CheckIsCollapsed())502 var saveUndoStep = function( selectRange ) 421 503 { 422 if (! _Find() ) 504 var ieRange ; 505 if ( oEditor.FCKBrowserInfo.IsIE ) 506 ieRange = document.selection.createRange() ; 507 508 selectRange.Select() ; 509 oEditor.FCKUndo.SaveUndoStep() ; 510 var cloneRange = selectRange.Clone() ; 511 cloneRange.Collapse( false ) ; 512 cloneRange.Select() ; 513 514 if ( ieRange ) 515 setTimeout( function(){ ieRange.select() ; }, 1 ) ; 516 } 517 518 if ( FindRange && FindRange.GetHighlightDomRange() ) 519 { 520 var range = FindRange.GetHighlightDomRange() ; 521 var bookmark = range.CreateBookmark() ; 522 FindRange.RemoveHighlight() ; 523 range.MoveToBookmark( bookmark ) ; 524 525 saveUndoStep( range ) ; 526 range.DeleteContents() ; 527 range.InsertNode( EditorDocument.createTextNode( GetReplaceString() ) ) ; 528 range._UpdateElementInfo() ; 529 530 FindRange = CharacterRange.CreateFromDomRange( range ) ; 531 } 532 else 533 { 534 if ( ! _Find() ) 423 535 { 424 ClearHighlight() ;536 FindRange && FindRange.RemoveHighlight() ; 425 537 alert( FCKLang.DlgFindNotFoundMsg ) ; 426 538 } 427 539 } 428 else429 {430 oEditor.FCKUndo.SaveUndoStep() ;431 GlobalRange.DeleteContents() ;432 GlobalRange.InsertNode( oEditor.FCK.EditorDocument.createTextNode( GetReplaceString() ) ) ;433 GlobalRange.Collapse( false ) ;434 }435 540 } 436 541 437 542 function ReplaceAll() … … 441 546 442 547 while ( _Find() ) 443 548 { 444 dialog.Selection.EnsureSelection() ; 445 GlobalRange.DeleteContents() ; 446 GlobalRange.InsertNode( oEditor.FCK.EditorDocument.createTextNode( GetReplaceString() ) ) ; 447 GlobalRange.Collapse( false ) ; 549 var range = FindRange.GetHighlightDomRange() ; 550 var bookmark = range.CreateBookmark() ; 551 FindRange.RemoveHighlight() ; 552 range.MoveToBookmark( bookmark) ; 553 554 range.DeleteContents() ; 555 range.InsertNode( EditorDocument.createTextNode( GetReplaceString() ) ) ; 556 range._UpdateElementInfo() ; 557 558 FindRange = CharacterRange.CreateFromDomRange( range ) ; 448 559 replaceCount++ ; 449 560 } 450 561 if ( replaceCount == 0 ) 451 562 { 452 ClearHighlight() ;563 FindRange && FindRange.RemoveHighlight() ; 453 564 alert( FCKLang.DlgFindNotFoundMsg ) ; 454 565 } 455 566 dialog.Cancel() ; 456 567 } 457 568 458 window.onunload = function(){ ClearHighlight() ; } 569 window.onunload = function() 570 { 571 if ( FindRange ) 572 { 573 FindRange.RemoveHighlight() ; 574 FindRange.ToDomRange().Select() ; 575 } 576 } 459 577 </script> 460 578 </head> 461 579 <body onload="OnLoad()" style="overflow: hidden">