| 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 | // Normalized address ready to be put into a bookmark. |
| | 102 | GetAddress : function() |
| | 103 | { |
| | 104 | if ( !this._textNode ) |
| | 105 | return null ; |
| | 106 | var nodeAddress = FCKDomTools.GetNodeAddress( this._textNode, true ) ; |
| | 107 | var textAddress = this._offset ; |
| | 108 | var curTextNode = this._textNode ; |
| | 109 | while ( ( curTextNode = curTextNode.previousSibling ) && ( curTextNode.nodeType == 3 ) ) |
| | 110 | textAddress += curTextNode.length ; |
| | 111 | return nodeAddress.concat( [textAddress] ) ; |
| | 112 | }, |
| 131 | | function GetMatchWord() |
| | 147 | var crossed = false ; |
| | 148 | var curNode = this._textNode ; |
| | 149 | while ( ( curNode = FCKDomTools.GetPreviousSourceNode( curNode ) ) |
| | 150 | && curNode && ( curNode.nodeType != 3 || curNode.length < 1 ) ) |
| | 151 | { |
| | 152 | var tag = curNode.tagName.toLowerCase() ; |
| | 153 | if ( FCKListsLib.BlockElements[tag] || tag == 'br' ) |
| | 154 | crossed = true ; |
| | 155 | } |
| | 156 | |
| | 157 | this._textNode = curNode ; |
| | 158 | this._offset = 0 ; |
| | 159 | return crossed ; |
| | 160 | }, |
| | 161 | |
| | 162 | Clone : function() |
| | 163 | { |
| | 164 | return new CharacterCursor( this._textNode, this._offset ) ; |
| | 165 | } |
| | 166 | } ; |
| | 167 | |
| | 168 | CharacterRange = function( initCursor, maxLength ) |
| 142 | | var target = bookmark[i] ; |
| 143 | | var currentIndex = -1 ; |
| 144 | | if ( cursor.nodeType != 3 ) |
| 145 | | { |
| 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 ; |
| 162 | | } |
| | 178 | var firstCursor = this._cursors[0] ; |
| | 179 | var lastCursor = this._cursors[ this._cursors.length - 1 ] ; |
| | 180 | var domRange = new FCKDomRange( FCKTools.GetElementWindow( firstCursor.GetTextNode() ) ) ; |
| | 181 | var w3cRange = domRange._Range = domRange.CreateRange() ; |
| | 182 | w3cRange.setStart( firstCursor.GetTextNode(), firstCursor.GetIndex() ) ; |
| | 183 | w3cRange.setEnd( lastCursor.GetTextNode(), lastCursor.GetIndex() + 1 ) ; |
| | 184 | domRange._UpdateElementInfo() ; |
| | 185 | return domRange ; |
| | 186 | }, |
| | 187 | |
| | 188 | Highlight : function() |
| | 189 | { |
| | 190 | if ( this._cursors.length < 1 ) |
| | 191 | return ; |
| | 192 | |
| | 193 | var domRange = this.ToDomRange() ; |
| | 194 | HighlightStyle.ApplyToRange( domRange, false, true ) ; |
| | 195 | this._highlightRange = domRange ; |
| | 196 | |
| | 197 | var charRange = CharacterRange.CreateFromDomRange( domRange ) ; |
| | 198 | var focusNode = domRange.StartNode ; |
| | 199 | if ( focusNode.nodeType != 1 ) |
| | 200 | focusNode = focusNode.parentNode ; |
| | 201 | if ( oEditor.FCKBrowserInfo.IsSafari ) |
| | 202 | FCKDomTools.ScrollIntoView( focusNode ) ; |
| 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 ; |
| | 212 | HighlightStyle.RemoveFromRange( this._highlightRange, false, true ) ; |
| | 213 | var charRange = CharacterRange.CreateFromDomRange( this._highlightRange ) ; |
| | 214 | this._cursors = charRange._cursors ; |
| | 215 | this._highlightRange = null ; |
| | 217 | }, |
| | 218 | |
| | 219 | GetHighlightDomRange : function() |
| | 220 | { |
| | 221 | return this._highlightRange; |
| | 222 | }, |
| | 223 | |
| | 224 | MoveNext : function() |
| | 225 | { |
| | 226 | var next = this._cursors[ this._cursors.length - 1 ].Clone() ; |
| | 227 | var retval = next.MoveNext() ; |
| | 228 | if ( retval ) |
| | 229 | this._cursors = [] ; |
| | 230 | this._cursors.push( next ) ; |
| | 231 | if ( this._cursors.length > this._maxLength ) |
| | 232 | this._cursors.shift() ; |
| | 233 | return retval ; |
| | 234 | }, |
| | 235 | |
| | 236 | MoveBack : function() |
| | 237 | { |
| | 238 | var prev = this._cursors[0].Clone() ; |
| | 239 | var retval = prev.MoveBack() ; |
| | 240 | if ( retval ) |
| | 241 | this._cursors = [] ; |
| | 242 | this._cursors.unshift( prev ) ; |
| | 243 | if ( this._cursors.length > this._maxLength ) |
| | 244 | this._cursors.pop() ; |
| | 245 | return retval ; |
| | 246 | }, |
| | 247 | |
| | 248 | GetEndCharacter : function() |
| | 249 | { |
| | 250 | if ( this._cursors.length < 1 ) |
| | 251 | return null ; |
| | 252 | var retval = this._cursors[ this._cursors.length - 1 ].GetCharacter() ; |
| | 253 | return retval ; |
| | 254 | }, |
| | 255 | |
| | 256 | GetNextRange : function( len ) |
| | 257 | { |
| | 258 | if ( this._cursors.length == 0 ) |
| | 259 | return null ; |
| | 260 | var cur = this._cursors[ this._cursors.length - 1 ].Clone() ; |
| | 261 | cur.MoveNext() ; |
| | 262 | return new CharacterRange( cur, len ) ; |
| 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 ; |
| | 273 | if ( startContainer.nodeType == 3 ) |
| | 274 | { |
| | 275 | startTextNode = startContainer ; |
| | 276 | startIndex = w3cRange.startOffset ; |
| | 277 | } |
| | 278 | else if ( domRange.StartNode.nodeType == 3 ) |
| | 279 | { |
| | 280 | startTextNode = domRange.StartNode ; |
| | 281 | startIndex = 0 ; |
| | 282 | } |
| | 283 | else |
| | 284 | { |
| | 285 | startTextNode = GetNextNonEmptyTextNode( domRange.StartNode, domRange.StartNode.parentNode ) ; |
| | 286 | if ( !startTextNode ) |
| | 287 | return null ; |
| | 288 | startIndex = 0 ; |
| | 289 | } |
| 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 ) |
| | 304 | var cursors = [] ; |
| | 305 | var current = new CharacterCursor( startTextNode, startIndex ) ; |
| | 306 | cursors.push( current ) ; |
| | 307 | do |
| 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 = [] ; |
| | 376 | // First of all, translate the dialog box texts. |
| | 377 | oEditor.FCKLanguageManager.TranslatePage( document ) ; |
| 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) ; |
| | 382 | dialog.SetSelectedTab( 'Find' ) ; |
| | 383 | dialog.SetAutoSize( true ) ; |
| | 384 | } |
| | 385 | else |
| | 386 | dialog.SetSelectedTab( 'Replace' ) ; |
| 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( [] )] ; |
| | 388 | SelectField( 'txtFind' + dialogArguments.CustomValue ) ; |
| | 389 | } |
| 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 | | } |
| | 399 | function btnStatDelayed() |
| | 400 | { |
| | 401 | setTimeout( btnStat, 1 ) ; |
| | 402 | } |
| 377 | | // Perform DFS across the document, until we've reached the end. |
| 378 | | cursor = NextPosition( cursor ) ; |
| 379 | | if ( cursor == null ) |
| 380 | | break; |
| | 414 | function GetCheckCase() |
| | 415 | { |
| | 416 | return !! ( GetE(idMap['CheckCase']).checked ) ; |
| | 417 | } |
| | 418 | |
| | 419 | function GetMatchWord() |
| | 420 | { |
| | 421 | return !! ( GetE(idMap['CheckWord']).checked ) ; |
| | 422 | } |
| | 423 | |
| | 424 | // Is this character a unicode whitespace? |
| | 425 | // Reference: http://unicode.org/Public/UNIDATA/PropList.txt |
| | 426 | function CheckIsWhitespace( c ) |
| | 427 | { |
| | 428 | var code = c.charCodeAt( 0 ); |
| | 429 | if ( code >= 9 && code <= 0xd ) |
| | 430 | return true; |
| | 431 | if ( code >= 0x2000 && code <= 0x200a ) |
| | 432 | return true; |
| | 433 | switch ( code ) |
| | 434 | { |
| | 435 | case 0x20: |
| | 436 | case 0x85: |
| | 437 | case 0xa0: |
| | 438 | case 0x1680: |
| | 439 | case 0x180e: |
| | 440 | case 0x2028: |
| | 441 | case 0x2029: |
| | 442 | case 0x202f: |
| | 443 | case 0x205f: |
| | 444 | case 0x3000: |
| | 445 | return true; |
| | 446 | default: |
| | 447 | return false; |
| 383 | | // If we've found a match, highlight the match. |
| | 451 | FindRange = null ; |
| | 452 | function _Find() |
| | 453 | { |
| | 454 | var searchString = GetSearchString() ; |
| | 455 | if ( !FindRange ) |
| | 456 | FindRange = new CharacterRange( new CharacterCursor( EditorDocument ), searchString.length ) ; |
| | 457 | else |
| | 458 | { |
| | 459 | FindRange.RemoveHighlight() ; |
| | 460 | FindRange = FindRange.GetNextRange( searchString.length ) ; |
| | 461 | } |
| | 462 | var matcher = new KmpMatch( searchString, ! GetCheckCase() ) ; |
| | 463 | var matchState = KMP_NOMATCH ; |
| | 464 | var character = null ; |
| | 465 | |
| | 466 | while ( ( character = FindRange.GetEndCharacter() ) ) |
| | 467 | { |
| | 468 | matchState = matcher.FeedCharacter( character ) ; |