Ticket #2905: 2905_3.patch
File 2905_3.patch, 27.3 KB (added by , 15 years ago) |
---|
-
_source/plugins/toolbar/plugin.js
213 213 'Outdent', 'Indent', 'Blockquote', '-', 214 214 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 215 215 'Subscript', 'Superscript', '-', 216 'Find', 'Replace', '-', 216 217 'SelectAll', 'RemoveFormat', '-', 217 218 'Link', 'Unlink', 'Anchor', '-', 218 219 'Table', 'Smiley', 'HorizontalRule', 'SpecialChar', 'PageBreak' -
_source/plugins/find/dialogs/find.js
5 5 6 6 (function() 7 7 { 8 // Element tag names which prevent characters counting. 9 var characterBoundaryElementsEnum = 10 { 11 address :1, blockquote :1, dl :1, h1 :1, h2 :1, h3 :1, 12 h4 :1, h5 :1, h6 :1, p :1, pre :1, li :1, dt :1, de :1, div :1, td:1, th:1 13 }; 14 8 15 var guardDomWalkerNonEmptyTextNode = function( evt ) 9 16 { 10 if ( evt.data.to && evt.data.to.type == CKEDITOR.NODE_TEXT && evt.data.to.$.length > 0 ) 17 if ( evt.data.to && evt.data.to.type == CKEDITOR.NODE_TEXT 18 && evt.data.to.$.length > 0 ) 11 19 this.stop(); 12 20 CKEDITOR.dom.domWalker.blockBoundary( { br : 1 } ).call( this, evt ); 13 21 }; 14 15 var domWalkerEventBridge = function() 16 { 17 var me = this, 18 handler = function( evt ){ me.fire( evt.data.type, evt.data ); me._.actionEvents.push( evt.data ); }; 19 this._.walker.on( 'up', handler ); 20 this._.walker.on( 'down', handler ); 21 this._.walker.on( 'sibling', handler ); 22 }; 23 24 var fireCharacterEvent = function() 22 23 24 /** 25 * Get the cursor object which represent both current character and it's dom 26 * position thing. 27 */ 28 var getCurrentCursor = function() 25 29 { 26 30 var obj = { 27 type : 'character', 31 textNode : this.textNode, 32 offset : this.offset, 28 33 character : this.textNode ? this.textNode.getText().charAt( this.offset ) : null, 29 34 hitMatchBoundary : this._.matchBoundary 30 35 }; 31 this.fire( 'character', obj ); 32 this._.actionEvents.push( obj ); 33 return { character : obj.character, events : this._.actionEvents }; 36 return obj; 34 37 }; 38 39 var pages = [ 'find', 'replace' ], 40 fieldsMapping = [ 41 [ 'txtFindFind', 'txtFindReplace' ], 42 [ 'txtFindCaseChk', 'txtReplaceCaseChk' ], 43 [ 'txtFindWordChk', 'txtReplaceWordChk' ], 44 [ 'txtFindCyclic', 'txtReplaceCyclic' ] ], 45 46 /** 47 * Synchronize corresponding filed values between 'replace' and 'find' pages. 48 * @param {String} currentPageId The page id which receive values. 49 */ 50 function syncFieldsBetweenTabs( currentPageId) 51 { 52 var sourceIndex, targetIndex, 53 sourceField, targetField; 54 55 sourceIndex = currentPageId === 'find' ? 1 : 0; 56 targetIndex = 1 - sourceIndex; 57 var i, l = fieldsMapping.length; 58 for ( i = 0 ; i < l ; i++ ) 59 { 60 var sourceField = this 61 .getContentElement( pages[ sourceIndex ], 62 fieldsMapping[ i ][ sourceIndex ] ), 63 targetField = this 64 .getContentElement( pages[ targetIndex ], 65 fieldsMapping[ i ][ targetIndex ] ); 66 67 targetField.setValue( sourceField.getValue() ); 68 } 69 } 35 70 36 71 var findDialog = function( editor, startupPage ) 37 72 { 38 var characterWalker = function( cursorOrTextNode, offset ) 73 //back refer the dialog instance. 74 var dialog; 75 76 /** 77 * Iterator which walk through document char by char. 78 * @param {Object} start 79 * @param {Number} offset 80 */ 81 var characterWalker = function( start, offset ) 39 82 { 40 var isCursor = ( cursorOrTextNode instanceof characterWalker ); 83 var isCursor = typeof start.textNode !== 'undefined'; 84 this.textNode = isCursor ? start.textNode : start; 85 this.offset = isCursor ? start.offset : offset; 41 86 this._ = { 42 matchBoundary : false,43 actionEvents : null87 walker : new CKEDITOR.dom.domWalker( this.textNode ), 88 matchBoundary : false 44 89 }; 45 this.textNode = isCursor ? cursorOrTextNode.textNode : cursorOrTextNode,46 this.offset = isCursor ? cursorOrTextNode.offset : offset,47 this._.walker = new CKEDITOR.dom.domWalker( this.textNode );48 CKEDITOR.event.implementOn( this );49 domWalkerEventBridge.call( this );50 90 }; 51 91 52 92 characterWalker.prototype = { … … 52 92 characterWalker.prototype = { 53 93 next : function() 54 94 { 55 // Clear any previous action events and related flags. 56 this._.actionEvents = []; 95 // Already at the end of document, no more character available. 96 if( this.textNode === null && this._.matchBoundary ) 97 return getCurrentCursor.call( this ); 98 57 99 this._.matchBoundary = false; 58 59 // If there are more characters in the text node, get it and raise an event. 60 if ( this.textNode.type == CKEDITOR.NODE_TEXT && this.offset < this.textNode.getLength() - 1 ) 100 101 // If there are more characters in the text node, get it and 102 // raise an event. 103 if( this.textNode.type == CKEDITOR.NODE_TEXT 104 && this.offset < this.textNode.getLength() - 1 ) 61 105 { 62 106 this.offset++; 63 return fireCharacterEvent.call( this );107 return getCurrentCursor.call( this ); 64 108 } 65 109 66 // If we are at the end of the text node, use dom walker to get the next text node. 110 // If we are at the end of the text node, use dom walker to get 111 // the next text node. 67 112 var data = null; 68 while ( !data || ( data.node && data.node.type != CKEDITOR.NODE_TEXT ) ) 113 while ( !data || ( data.node && data.node.type != 114 CKEDITOR.NODE_TEXT ) ) 69 115 { 70 data = this._.walker.forward( guardDomWalkerNonEmptyTextNode ); 71 116 data = this._.walker.forward( 117 guardDomWalkerNonEmptyTextNode ); 118 72 119 // Block boundary? BR? Document boundary? 73 if ( !data.node || data.node.type != CKEDITOR.NODE_TEXT ) 120 if ( !data.node 121 || ( data.node.type !== CKEDITOR.NODE_TEXT 122 && data.node.getName() in 123 characterBoundaryElementsEnum ) ) 74 124 this._.matchBoundary = true; 75 125 } 76 126 this.textNode = data.node; … … 75 125 } 76 126 this.textNode = data.node; 77 127 this.offset = 0; 78 return fireCharacterEvent.call( this );128 return getCurrentCursor.call( this ); 79 129 }, 80 130 81 131 back : function() 82 132 { 83 // Clear any previous action events and related flags.84 this._.actionEvents = [];85 133 this._.matchBoundary = false; 86 134 87 135 // More characters -> decrement offset and return. … … 88 136 if ( this.textNode.type == CKEDITOR.NODE_TEXT && this.offset > 0 ) 89 137 { 90 138 this.offset--; 91 return fireCharacterEvent.call( this );139 return getCurrentCursor.call( this ); 92 140 } 93 141 94 142 // Start of text node -> use dom walker to get the previous text node. … … 93 141 94 142 // Start of text node -> use dom walker to get the previous text node. 95 143 var data = null; 96 while ( !data || ( data.node && data.node.type != CKEDITOR.NODE_TEXT ) ) 144 while ( !data 145 || ( data.node && data.node.type != CKEDITOR.NODE_TEXT ) ) 97 146 { 98 147 data = this._.walker.reverse( guardDomWalkerNonEmptyTextNode ); 99 148 … … 98 147 data = this._.walker.reverse( guardDomWalkerNonEmptyTextNode ); 99 148 100 149 // Block boundary? BR? Document boundary? 101 if ( !data.node || data.node.type != CKEDITOR.NODE_TEXT ) 150 if ( !data.node || ( data.node.type !== CKEDITOR.NODE_TEXT && 151 data.node.getName() in characterBoundaryElementsEnum ) ) 102 152 this._.matchBoundary = true; 103 153 } 104 154 this.textNode = data.node; … … 103 153 } 104 154 this.textNode = data.node; 105 155 this.offset = data.node.length - 1; 106 return fireCharacterEvent.call( this ); 107 }, 108 109 getChar : function() 110 { 111 return this.textNode ? this.textNode.getText().charAt( this.offset ) : null; 156 return getCurrentCursor.call( this ); 112 157 } 113 158 }; 114 115 var characterRange = function( initCursor, maxLength ) 159 160 /** 161 * A range of cursors which represent a trunk of characters which try to 162 * match, it has the same length as the pattern string. 163 */ 164 var characterRange = function( characterWalker, rangeLength ) 116 165 { 117 166 this._ = { 118 cursors : initCursor.push ? initCursor : [ initCursor ], 119 maxLength : maxLength, 120 highlightRange : null 167 walker : characterWalker, 168 cursors : [], 169 rangeLength : rangeLength, 170 highlightRange : null, 171 isMatched : false 121 172 }; 122 173 }; 123 174 … … 122 173 }; 123 174 124 175 characterRange.prototype = { 176 /** 177 * Translate this range to {@link CKEDITOR.dom.range} 178 */ 125 179 toDomRange : function() 126 180 { 127 181 var cursors = this._.cursors; … … 136 190 range.setEnd( last.textNode, last.offset + 1 ); 137 191 return range; 138 192 }, 139 193 194 setMatched : function() 195 { 196 this._.isMatched = true; 197 this.highlight(); 198 }, 199 200 clearMatched : function() 201 { 202 this._.isMatched = false; 203 this.removeHighlight(); 204 }, 205 206 isMatched : function() 207 { 208 return this._.isMatched; 209 }, 210 211 /** 212 * Hightlight the current matched chunk of text, using selection 213 * system to represent highlight until marking-style is implemented. 214 */ 140 215 highlight : function() 141 216 { 142 // TODO: wait till Fred has implemented style removal for this. 217 if(CKEDITOR.env.ie) 218 dialog.restoreSelection(); 219 143 220 editor.getSelection().selectRanges( [ this.toDomRange() ] ); 221 222 if(CKEDITOR.env.ie) 223 { 224 dialog.saveSelection(); 225 226 // since IE broke text nodes, update these changes back to 227 // character range. 228 var dirtyRange = editor.getSelection().getRanges()[0]; 229 var cursors = this._.cursors; 230 var first = cursors[0], 231 last = cursors[ cursors.length - 1 ]; 232 first.textNode = dirtyRange.startContainer; 233 first.offset = dirtyRange.startOffset; 234 last.textNode = dirtyRange.endContainer; 235 last.offset = dirtyRange.endOffset; 236 } 144 237 }, 145 238 239 /** 240 * Wait for highlight marking-style in order to perform removal. 241 */ 146 242 removeHighlight : function() 147 243 { 148 // TODO: wait till Fred has implemented style removal for this.244 this._.highlightRange = null; 149 245 }, 150 246 151 getHighlightDomRange: function()247 moveBack : function() 152 248 { 153 // TODO: wait till Fred has implemented style removal for this. 154 return this.toDomRange(); 155 }, 156 157 moveNext : function() 158 { 159 var next = new characterWalker( this._.cursors[ this._.cursors.length - 1 ] ), 160 retval = next.next(), 249 var retval = this._.walker.back(), 161 250 cursors = this._.cursors; 162 251 163 // Clear the cursors queue if we've crossed a match boundary.164 252 if ( retval.hitMatchBoundary ) 165 253 this._.cursors = cursors = []; 166 254 167 cursors. push( next);168 if ( cursors.length > this._. maxLength )169 cursors. shift();255 cursors.unshift( retval ); 256 if ( cursors.length > this._.rangeLength ) 257 cursors.pop(); 170 258 171 259 return retval; 172 260 }, 173 174 move Back: function()261 262 moveNext : function() 175 263 { 176 var prev = new characterWalker( this._.cursors[0] ), 177 retval = prev.back(), 264 var retval = this._.walker.next(), 178 265 cursors = this._.cursors; 179 266 267 // Clear the cursors queue if we've crossed a match boundary. 180 268 if ( retval.hitMatchBoundary ) 181 269 this._.cursors = cursors = []; 182 270 183 cursors. unshift( prev);184 if ( cursors.length > this._. maxLength )185 cursors. pop();271 cursors.push( retval ); 272 if ( cursors.length > this._.rangeLength ) 273 cursors.shift(); 186 274 187 275 return retval; 188 276 }, … … 193 281 if ( cursors.length < 1 ) 194 282 return null; 195 283 196 return cursors[ cursors.length - 1 ]. getChar();284 return cursors[ cursors.length - 1 ].character; 197 285 }, 198 286 199 getNextRange : function( maxLength )287 updateRange : function( newrangeLength ) 200 288 { 201 var cursors = this._.cursors; 202 if ( cursors.length < 1 ) 203 return null; 204 205 var next = new characterWalker( cursors[ cursors.length - 1 ] ); 206 next.next(); 207 return new characterRange( next, maxLength ); 289 this._.cursors = []; 290 this._.rangeLength = newrangeLength; 291 this.removeHighlight(); 208 292 }, 209 293 210 294 getCursors : function() … … 216 300 var KMP_NOMATCH = 0, 217 301 KMP_ADVANCED = 1, 218 302 KMP_MATCHED = 2; 303 /** 304 * Examination the occurrence of a word which implement KMP algorithm. 305 */ 219 306 var kmpMatcher = function( pattern, ignoreCase ) 220 307 { 221 308 var overlap = [ -1 ]; … … 224 311 for ( var i = 0 ; i < pattern.length ; i++ ) 225 312 { 226 313 overlap.push( overlap[i] + 1 ); 227 while ( overlap[ i + 1 ] > 0 && pattern.charAt( i ) != pattern.charAt( overlap[ i + 1 ] - 1 ) ) 314 while ( overlap[ i + 1 ] > 0 315 && pattern.charAt( i ) != pattern 316 .charAt( overlap[ i + 1 ] - 1 ) ) 228 317 overlap[ i + 1 ] = overlap[ overlap[ i + 1 ] - 1 ] + 1; 229 318 } 230 319 … … 268 357 } 269 358 }; 270 359 271 var wordSeparatorRegex = /[.,"'?!;: \u0085\u00a0\u1680\u280e\u2028\u2029\u202f\u205f\u3000]/, 360 var wordSeparatorRegex = 361 /[.,"'?!;: \u0085\u00a0\u1680\u280e\u2028\u2029\u202f\u205f\u3000]/, 272 362 isWordSeparator = function( c ) 273 363 { 274 364 if ( !c ) … … 274 364 if ( !c ) 275 365 return true; 276 366 var code = c.charCodeAt( 0 ); 277 return ( code >= 9 && code <= 0xd ) || ( code >= 0x2000 && code <= 0x200a ) || wordSeparatorRegex.test( c ); 367 return ( code >= 9 && code <= 0xd ) 368 || ( code >= 0x2000 && code <= 0x200a ) 369 || wordSeparatorRegex.test( c ); 278 370 }; 279 371 280 372 var finder = { 373 startCursor : null, 281 374 range : null, 282 find : function( pattern, matchCase, matchWord )375 find : function( pattern, matchCase, matchWord, matchCyclic ) 283 376 { 284 if ( !this.range ) 285 this.range = new characterRange( new characterWalker( editor.document.getBody(), 0 ), pattern.length ); 377 if( !this.range ) 378 this.range = new characterRange( new characterWalker( 379 this.startCursor ) , pattern.length ); 286 380 else 287 381 { 288 this.range.removeHighlight(); 289 this.range = this.range.getNextRange( pattern.length ); 382 this.range.updateRange( pattern.length ); 290 383 } 291 384 292 385 var matcher = new kmpMatcher( pattern, !matchCase ), … … 295 388 296 389 while ( character != null ) 297 390 { 391 this.range.moveNext(); 298 392 while ( ( character = this.range.getEndCharacter() ) ) 299 393 { 300 394 matchState = matcher.feedCharacter( character ); … … 309 403 if ( matchWord ) 310 404 { 311 405 var cursors = this.range.getCursors(), 312 head = new characterCursor( cursors[ cursors.length - 1 ] ), 313 tail = new characterCursor( cursors[0] ); 314 if ( !( head.next().character || isWordSeparator( head.getChar() ) ) ) 315 continue; 316 if ( !( tail.back().character || isWordSeparator( tail.getChar() ) ) ) 406 tail = cursors[ cursors.length - 1 ], 407 head = cursors[ 0 ], 408 headWalker = new characterWalker(head), 409 tailWalker = new characterWalker(tail); 410 411 if ( ! ( isWordSeparator( 412 headWalker.back().character ) 413 && isWordSeparator( 414 tailWalker.next().character ) ) ) 317 415 continue; 318 416 } 319 417 320 this.range. highlight();418 this.range.setMatched(); 321 419 return true; 322 420 } 323 421 } 422 423 this.range.clearMatched(); 424 425 // clear current session and restart from beginning 426 if ( matchCyclic ) 427 this.range = null; 428 429 return false; 430 }, 431 432 /** 433 * Record how much replacement occurred toward one replacing. 434 */ 435 replaceCounter : 0, 436 437 replace : function( pattern, newString, matchCase, matchWord, 438 matchCyclic, matchReplaceAll ) 439 { 440 var replaceResult = false; 441 if ( this.range && this.range.isMatched() ) 442 { 443 if ( CKEDITOR.env.ie ) 444 dialog.restoreSelection(); 324 445 325 this.range = null; 326 return false; 446 var domrange = this.range.toDomRange(); 447 var documentFragment = domrange.extractContents(); 448 // Use the first text container as holder, no matter what 449 // kind of element it is. 450 var contentHolder = documentFragment.getFirst(); 451 452 if ( contentHolder.type === CKEDITOR.NODE_ELEMENT ) 453 contentHolder.setText( newString ); 454 else 455 contentHolder = editor.document.createText( newString ); 456 457 domrange.insertNode( contentHolder ); 458 459 if ( CKEDITOR.env.ie ) 460 dialog.saveSelection(); 461 462 this.replaceCounter++; 463 replaceResult = true; 464 } 465 466 var findResult = this.find( 467 pattern, matchCase, matchWord, matchCyclic ); 468 if ( findResult && matchReplaceAll ) 469 { 470 this.replace.apply( this, 471 Array.prototype.slice.call( arguments ) ); 472 } 473 return matchReplaceAll ? 474 this.replaceCounter : replaceResult || findResult; 327 475 } 476 328 477 }; 478 479 /** 480 * Get the default cursor which is the start of this document. 481 */ 482 function getDefaultStartCursor() 483 { 484 return {textNode : editor.document.getBody(), offset: 0}; 485 } 486 487 /** 488 * Get cursor that indicate search begin with, receive from user 489 * selection prior. 490 */ 491 function getStartCursor() 492 { 493 if ( CKEDITOR.env.ie ) 494 dialog.restoreSelection(); 329 495 496 var sel = editor.getSelection(); 497 if ( sel ) 498 { 499 var lastRange = sel.getRanges()[ sel.getRanges().length - 1 ]; 500 return { 501 textNode : lastRange.getBoundaryNodes().endNode, 502 offset : lastRange.endContainer.type === 503 CKEDITOR.NODE_ELEMENT ? 504 0 : lastRange.endOffset 505 }; 506 } 507 else 508 return getDefaultStartCursor(); 509 } 510 330 511 return { 331 512 title : editor.lang.findAndReplace.title, 332 513 resizable : CKEDITOR.DIALOG_RESIZE_NONE, … … 331 512 title : editor.lang.findAndReplace.title, 332 513 resizable : CKEDITOR.DIALOG_RESIZE_NONE, 333 514 minWidth : 400, 334 minHeight : 2 45,515 minHeight : 255, 335 516 buttons : [ CKEDITOR.dialog.cancelButton ], //Cancel button only. 336 517 contents : [ 337 518 { … … 351 532 label : editor.lang.findAndReplace.findWhat, 352 533 isChanged : false, 353 534 labelLayout : 'horizontal', 354 accessKey : 'F' ,535 accessKey : 'F' 355 536 }, 356 537 { 357 538 type : 'button', … … 361 542 onClick : function() 362 543 { 363 544 var dialog = this.getDialog(); 364 if ( !finder.find( dialog.getValueOf( 'find', 'txtFindFind' ), 365 dialog.getValueOf( 'find', 'txtFindCaseChk' ), 366 dialog.getValueOf( 'find', 'txtFindWordChk' ) ) ) 367 alert( editor.lang.findAndReplace.notFoundMsg ); 545 if ( !finder.find( dialog.getValueOf( 546 'find', 'txtFindFind' ), dialog 547 .getValueOf( 'find', 548 'txtFindCaseChk' ), dialog 549 .getValueOf( 'find', 550 'txtFindWordChk' ), dialog 551 .getValueOf( 'find', 552 'txtFindCyclic' ) ) ) 553 alert( editor.lang.findAndReplace 554 .notFoundMsg ); 368 555 } 369 } ,556 } 370 557 ] 371 558 }, 372 559 { … … 374 561 id : 'txtFindCaseChk', 375 562 isChanged : false, 376 563 style : 'margin-top:28px', 377 label : editor.lang.findAndReplace.matchCase ,564 label : editor.lang.findAndReplace.matchCase 378 565 }, 379 566 { 380 567 type : 'checkbox', … … 380 567 type : 'checkbox', 381 568 id : 'txtFindWordChk', 382 569 isChanged : false, 383 label : editor.lang.findAndReplace.matchWord ,570 label : editor.lang.findAndReplace.matchWord 384 571 }, 385 572 { 386 573 type : 'checkbox', … … 387 574 id : 'txtFindCyclic', 388 575 isChanged : false, 389 576 checked : true, 390 label : editor.lang.findAndReplace.matchCyclic ,391 } ,577 label : editor.lang.findAndReplace.matchCyclic 578 } 392 579 ] 393 580 }, 394 581 { … … 407 594 label : editor.lang.findAndReplace.findWhat, 408 595 isChanged : false, 409 596 labelLayout : 'horizontal', 410 accessKey : 'F' ,597 accessKey : 'F' 411 598 }, 412 599 { 413 600 type : 'button', … … 416 603 label : editor.lang.findAndReplace.replace, 417 604 onClick : function() 418 605 { 419 alert( editor.lang.findAndReplace.notFoundMsg ); 606 var dialog = this.getDialog(); 607 if ( !finder.replace( dialog 608 .getValueOf( 'replace', 609 'txtFindReplace' ), dialog 610 .getValueOf( 'replace', 611 'txtReplace' ), dialog 612 .getValueOf( 'replace', 613 'txtReplaceCaseChk' ), dialog 614 .getValueOf( 'replace', 615 'txtReplaceWordChk' ), dialog 616 .getValueOf( 'replace', 617 'txtReplaceCyclic' ) ) ) 618 alert( editor.lang.findAndReplace 619 .notFoundMsg ); 420 620 } 421 } ,621 } 422 622 ] 423 623 }, 424 624 { … … 429 629 { 430 630 type : 'text', 431 631 id : 'txtReplace', 432 label : editor.lang.findAndReplace.replaceWith, 632 label : editor.lang.findAndReplace 633 .replaceWith, 433 634 isChanged : false, 434 635 labelLayout : 'horizontal', 435 accessKey : 'R' ,636 accessKey : 'R' 436 637 }, 437 638 { 438 639 type : 'button', … … 438 639 type : 'button', 439 640 align : 'left', 440 641 style : 'width:100%', 441 label : editor.lang.findAndReplace.replaceAll, 642 label : editor.lang.findAndReplace 643 .replaceAll, 442 644 isChanged : false, 443 645 onClick : function() 444 646 { 445 alert( editor.lang.findAndReplace.notFoundMsg ); 647 var dialog = this.getDialog(); 648 var replaceNums; 649 650 finder.replaceCounter = 0; 651 if ( ( replaceNums = finder.replace( 652 dialog.getValueOf( 'replace', 653 'txtFindReplace' ), dialog 654 .getValueOf( 'replace', 655 'txtReplace' ), dialog 656 .getValueOf( 'replace', 657 'txtReplaceCaseChk' ), 658 dialog.getValueOf( 'replace', 659 'txtReplaceWordChk' ), dialog 660 .getValueOf( 'replace', 661 'txtReplaceCyclic' ), true ) ) ) 662 alert( editor.lang.findAndReplace 663 .replaceSuccMsg 664 .replace( /%1/, replaceNums ) ); 665 else 666 alert( editor.lang.findAndReplace 667 .notFoundMsg ); 446 668 } 447 } ,669 } 448 670 ] 449 671 }, 450 672 { … … 451 673 type : 'checkbox', 452 674 id : 'txtReplaceCaseChk', 453 675 isChanged : false, 454 label : editor.lang.findAndReplace.matchCase, 676 label : editor.lang.findAndReplace 677 .matchCase 455 678 }, 456 679 { 457 680 type : 'checkbox', … … 457 680 type : 'checkbox', 458 681 id : 'txtReplaceWordChk', 459 682 isChanged : false, 460 label : editor.lang.findAndReplace.matchWord, 683 label : editor.lang.findAndReplace 684 .matchWord 461 685 }, 462 686 { 463 687 type : 'checkbox', … … 464 688 id : 'txtReplaceCyclic', 465 689 isChanged : false, 466 690 checked : true, 467 label : editor.lang.findAndReplace.matchCyclic, 468 }, 691 label : editor.lang.findAndReplace 692 .matchCyclic 693 } 469 694 ] 470 695 } 471 696 ], 697 onLoad : function() 698 { 699 dialog = this; 700 701 //keep trac of the current pattern field in use. 702 var patternField, wholeWordChkField; 703 704 /** 705 * Check the whether the 'wholeworld' match mode could be 706 * toggled on. 707 */ 708 function checkWholeWordState() 709 { 710 var isWord = /^\w+$/.test( patternField.getValue() ); 711 var wholeWordChkFieldEl = wholeWordChkField.getElement(); 712 if ( isWord ) 713 wholeWordChkFieldEl.show(); 714 else 715 wholeWordChkFieldEl.hide(); 716 } 717 718 //Ignore initial page select on dialog show 719 var isUserSelect = false; 720 this.on('hide', function(){ 721 isUserSelect = false; 722 }); 723 this.on('show', function(){ 724 isUserSelect = true; 725 }); 726 727 this.selectPage = CKEDITOR.tools.override( this.selectPage, 728 function( originalFunc ) 729 { 730 return function( pageId ) 731 { 732 originalFunc.call( dialog, pageId ); 733 734 var currPage = dialog._.tabs[ pageId ]; 735 var patternFieldInput, patternFieldId, wholeWordChkFieldId; 736 patternFieldId = pageId === 'find' ? 'txtFindFind' 737 : 'txtFindReplace'; 738 wholeWordChkFieldId = pageId === 'find' ? 'txtFindWordChk' 739 : 'txtReplaceWordChk'; 740 741 patternField = dialog.getContentElement( pageId, 742 patternFieldId ); 743 wholeWordChkField = dialog.getContentElement( pageId, 744 wholeWordChkFieldId ); 745 746 // prepare for check pattern text filed 'keyup' event 747 if ( !currPage.initialized ) 748 { 749 patternFieldInput = CKEDITOR.document 750 .getById( patternField._.inputId ); 751 patternFieldInput.on( 'keyup', checkWholeWordState ); 752 currPage.initialized = true; 753 } 754 755 if(isUserSelect) 756 // synchronize fields on tab switch. 757 syncFieldsBetweenTabs.call( this, pageId ); 758 759 //check wholeword match status on tab switch 760 checkWholeWordState(); 761 }; 762 } ); 763 764 }, 472 765 onShow : function() 473 766 { 767 //Establish initial searching start position. 768 finder.startCursor = getStartCursor(); 769 474 770 if ( startupPage == 'replace' ) 475 771 this.getContentElement( 'replace', 'txtFindReplace' ).focus(); 476 772 else … … 478 774 }, 479 775 onHide : function() 480 776 { 481 if ( finder.range )777 if ( finder.range && finder.range.isMatched() ) 482 778 { 483 finder.range.removeHighlight();484 editor.getSelection().selectRanges( [finder.range.toDomRange()] );779 editor.getSelection().selectRanges( 780 [ finder.range.toDomRange() ] ); 485 781 } 782 //clear current session before dialog close 783 delete finder.range; 486 784 } 487 785 }; 488 786 }; -
_source/core/dom/document.js
70 70 71 71 createText : function( text ) 72 72 { 73 return new CKEDITOR.dom.text( '', this );73 return new CKEDITOR.dom.text( text, this ); 74 74 }, 75 75 76 76 /** -
_source/core/config.js
147 147 * config.plugins = 'basicstyles,button,htmldataprocessor,toolbar,wysiwygarea'; 148 148 */ 149 149 150 plugins : 'basicstyles,button,elementspath,horizontalrule,htmldataprocessor,keystrokes,newpage,pagebreak,preview,removeformat,smiley,indent,link,list, justify,blockquote,sourcearea,table,specialchar,tab,toolbar,wysiwygarea',150 plugins : 'basicstyles,button,elementspath,horizontalrule,htmldataprocessor,keystrokes,newpage,pagebreak,preview,removeformat,smiley,indent,link,list,sourcearea,table,specialchar,tab,toolbar,wysiwygarea,find', 151 151 152 152 /** 153 153 * The theme to be used to build the UI.