JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.0
[ckeditor.git] / _source / plugins / find / dialogs / find.js
diff --git a/_source/plugins/find/dialogs/find.js b/_source/plugins/find/dialogs/find.js
new file mode 100644 (file)
index 0000000..cc1c2c1
--- /dev/null
@@ -0,0 +1,843 @@
+/*\r
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r
+For licensing, see LICENSE.html or http://ckeditor.com/license\r
+*/\r
+\r
+(function()\r
+{\r
+       function guardDomWalkerNonEmptyTextNode( node )\r
+       {\r
+               return ( node.type == CKEDITOR.NODE_TEXT && node.getLength() > 0 );\r
+       }\r
+\r
+       /**\r
+        * Elements which break characters been considered as sequence.\r
+       */\r
+       function checkCharactersBoundary ( node )\r
+       {\r
+               var dtd = CKEDITOR.dtd;\r
+               return node.isBlockBoundary(\r
+                       CKEDITOR.tools.extend( {}, dtd.$empty, dtd.$nonEditable ) );\r
+       }\r
+\r
+       /**\r
+        * Get the cursor object which represent both current character and it's dom\r
+        * position thing.\r
+        */\r
+       var cursorStep = function()\r
+       {\r
+               return {\r
+                       textNode : this.textNode,\r
+                       offset : this.offset,\r
+                       character : this.textNode ?\r
+                               this.textNode.getText().charAt( this.offset ) : null,\r
+                       hitMatchBoundary : this._.matchBoundary\r
+               };\r
+       };\r
+\r
+       var pages = [ 'find', 'replace' ],\r
+               fieldsMapping = [\r
+               [ 'txtFindFind', 'txtFindReplace' ],\r
+               [ 'txtFindCaseChk', 'txtReplaceCaseChk' ],\r
+               [ 'txtFindWordChk', 'txtReplaceWordChk' ],\r
+               [ 'txtFindCyclic', 'txtReplaceCyclic' ] ];\r
+\r
+       /**\r
+        * Synchronize corresponding filed values between 'replace' and 'find' pages.\r
+        * @param {String} currentPageId        The page id which receive values.\r
+        */\r
+       function syncFieldsBetweenTabs( currentPageId )\r
+       {\r
+               var sourceIndex, targetIndex,\r
+                       sourceField, targetField;\r
+\r
+               sourceIndex = currentPageId === 'find' ? 1 : 0;\r
+               targetIndex = 1 - sourceIndex;\r
+               var i, l = fieldsMapping.length;\r
+               for ( i = 0 ; i < l ; i++ )\r
+               {\r
+                       sourceField = this.getContentElement( pages[ sourceIndex ],\r
+                                       fieldsMapping[ i ][ sourceIndex ] );\r
+                       targetField = this.getContentElement( pages[ targetIndex ],\r
+                                       fieldsMapping[ i ][ targetIndex ] );\r
+\r
+                       targetField.setValue( sourceField.getValue() );\r
+               }\r
+       }\r
+\r
+       var findDialog = function( editor, startupPage )\r
+       {\r
+               // Style object for highlights.\r
+               var highlightStyle = new CKEDITOR.style( editor.config.find_highlight );\r
+\r
+               /**\r
+                * Iterator which walk through the specified range char by char. By\r
+                * default the walking will not stop at the character boundaries, until\r
+                * the end of the range is encountered.\r
+                * @param { CKEDITOR.dom.range } range\r
+                * @param {Boolean} matchWord Whether the walking will stop at character boundary.\r
+                */\r
+               var characterWalker = function( range , matchWord )\r
+               {\r
+                       var walker =\r
+                               new CKEDITOR.dom.walker( range );\r
+                       walker[ matchWord ? 'guard' : 'evaluator' ] =\r
+                               guardDomWalkerNonEmptyTextNode;\r
+                       walker.breakOnFalse = true;\r
+\r
+                       this._ = {\r
+                               matchWord : matchWord,\r
+                               walker : walker,\r
+                               matchBoundary : false\r
+                       };\r
+               };\r
+\r
+               characterWalker.prototype = {\r
+                       next : function()\r
+                       {\r
+                               return this.move();\r
+                       },\r
+\r
+                       back : function()\r
+                       {\r
+                               return this.move( true );\r
+                       },\r
+\r
+                       move : function( rtl )\r
+                       {\r
+                               var currentTextNode = this.textNode;\r
+                               // Already at the end of document, no more character available.\r
+                               if(  currentTextNode === null )\r
+                                       return cursorStep.call( this );\r
+\r
+                               this._.matchBoundary = false;\r
+\r
+                               // There are more characters in the text node, step forward.\r
+                               if( currentTextNode\r
+                                   && rtl\r
+                                       && this.offset > 0 )\r
+                               {\r
+                                       this.offset--;\r
+                                       return cursorStep.call( this );\r
+                               }\r
+                               else if( currentTextNode\r
+                                       && this.offset < currentTextNode.getLength() - 1 )\r
+                               {\r
+                                       this.offset++;\r
+                                       return cursorStep.call( this );\r
+                               }\r
+                               else\r
+                               {\r
+                                       currentTextNode = null;\r
+                                       // At the end of the text node, walking foward for the next.\r
+                                       while ( !currentTextNode )\r
+                                       {\r
+                                               currentTextNode =\r
+                                                       this._.walker[ rtl ? 'previous' : 'next' ].call( this._.walker );\r
+\r
+                                               // Stop searching if we're need full word match OR\r
+                                               // already reach document end.\r
+                                               if ( this._.matchWord && !currentTextNode\r
+                                                        ||this._.walker._.end )\r
+                                                       break;\r
+\r
+                                               // Marking as match character boundaries.\r
+                                               if( !currentTextNode\r
+                                                  && checkCharactersBoundary( this._.walker.current ) )\r
+                                                       this._.matchBoundary = true;\r
+\r
+                                       }\r
+                                       // Found a fresh text node.\r
+                                       this.textNode = currentTextNode;\r
+                                       if ( currentTextNode )\r
+                                               this.offset = rtl ? currentTextNode.getLength() - 1 : 0;\r
+                                       else\r
+                                               this.offset = 0;\r
+                               }\r
+\r
+                               return cursorStep.call( this );\r
+                       }\r
+\r
+               };\r
+\r
+               /**\r
+                * A range of cursors which represent a trunk of characters which try to\r
+                * match, it has the same length as the pattern  string.\r
+                */\r
+               var characterRange = function( characterWalker, rangeLength )\r
+               {\r
+                       this._ = {\r
+                               walker : characterWalker,\r
+                               cursors : [],\r
+                               rangeLength : rangeLength,\r
+                               highlightRange : null,\r
+                               isMatched : false\r
+                       };\r
+               };\r
+\r
+               characterRange.prototype = {\r
+                       /**\r
+                        * Translate this range to {@link CKEDITOR.dom.range}\r
+                        */\r
+                       toDomRange : function()\r
+                       {\r
+                               var cursors = this._.cursors;\r
+                               if ( cursors.length < 1 )\r
+                                       return null;\r
+\r
+                               var first = cursors[0],\r
+                                       last = cursors[ cursors.length - 1 ],\r
+                                       range = new CKEDITOR.dom.range( editor.document );\r
+\r
+                               range.setStart( first.textNode, first.offset );\r
+                               range.setEnd( last.textNode, last.offset + 1 );\r
+                               return range;\r
+                       },\r
+                       /**\r
+                        * Reflect the latest changes from dom range.\r
+                        */\r
+                       updateFromDomRange : function( domRange )\r
+                       {\r
+                               var cursor,\r
+                                               walker = new characterWalker( domRange );\r
+                               this._.cursors = [];\r
+                               do\r
+                               {\r
+                                       cursor = walker.next();\r
+                                       if ( cursor.character )\r
+                                               this._.cursors.push( cursor );\r
+                               }\r
+                               while ( cursor.character );\r
+                               this._.rangeLength = this._.cursors.length;\r
+                       },\r
+\r
+                       setMatched : function()\r
+                       {\r
+                               this._.isMatched = true;\r
+                       },\r
+\r
+                       clearMatched : function()\r
+                       {\r
+                               this._.isMatched = false;\r
+                       },\r
+\r
+                       isMatched : function()\r
+                       {\r
+                               return this._.isMatched;\r
+                       },\r
+\r
+                       /**\r
+                        * Hightlight the current matched chunk of text.\r
+                        */\r
+                       highlight : function()\r
+                       {\r
+                               // Do not apply if nothing is found.\r
+                               if ( this._.cursors.length < 1 )\r
+                                       return;\r
+\r
+                               // Remove the previous highlight if there's one.\r
+                               if ( this._.highlightRange )\r
+                                       this.removeHighlight();\r
+\r
+                               // Apply the highlight.\r
+                               var range = this.toDomRange();\r
+                               highlightStyle.applyToRange( range );\r
+                               this._.highlightRange = range;\r
+\r
+                               // Scroll the editor to the highlighted area.\r
+                               var element = range.startContainer;\r
+                               if ( element.type != CKEDITOR.NODE_ELEMENT )\r
+                                       element = element.getParent();\r
+                               element.scrollIntoView();\r
+\r
+                               // Update the character cursors.\r
+                               this.updateFromDomRange( range );\r
+                       },\r
+\r
+                       /**\r
+                        * Remove highlighted find result.\r
+                        */\r
+                       removeHighlight : function()\r
+                       {\r
+                               if ( !this._.highlightRange )\r
+                                       return;\r
+\r
+                               highlightStyle.removeFromRange( this._.highlightRange );\r
+                               this.updateFromDomRange( this._.highlightRange );\r
+                               this._.highlightRange = null;\r
+                       },\r
+\r
+                       moveBack : function()\r
+                       {\r
+                               var retval = this._.walker.back(),\r
+                                       cursors = this._.cursors;\r
+\r
+                               if ( retval.hitMatchBoundary )\r
+                                       this._.cursors = cursors = [];\r
+\r
+                               cursors.unshift( retval );\r
+                               if ( cursors.length > this._.rangeLength )\r
+                                       cursors.pop();\r
+\r
+                               return retval;\r
+                       },\r
+\r
+                       moveNext : function()\r
+                       {\r
+                               var retval = this._.walker.next(),\r
+                                       cursors = this._.cursors;\r
+\r
+                               // Clear the cursors queue if we've crossed a match boundary.\r
+                               if ( retval.hitMatchBoundary )\r
+                                       this._.cursors = cursors = [];\r
+\r
+                               cursors.push( retval );\r
+                               if ( cursors.length > this._.rangeLength )\r
+                                       cursors.shift();\r
+\r
+                               return retval;\r
+                       },\r
+\r
+                       getEndCharacter : function()\r
+                       {\r
+                               var cursors = this._.cursors;\r
+                               if ( cursors.length < 1 )\r
+                                       return null;\r
+\r
+                               return cursors[ cursors.length - 1 ].character;\r
+                       },\r
+\r
+                       getNextCharacterRange : function( maxLength )\r
+                       {\r
+                               var lastCursor,\r
+                                               cursors = this._.cursors;\r
+                               if ( !( lastCursor = cursors[ cursors.length - 1 ] ) )\r
+                                       return null;\r
+                               return new characterRange(\r
+                                                                               new characterWalker(\r
+                                                                                       getRangeAfterCursor( lastCursor ) ),\r
+                                                                               maxLength );\r
+                       },\r
+\r
+                       getCursors : function()\r
+                       {\r
+                               return this._.cursors;\r
+                       }\r
+               };\r
+\r
+\r
+               // The remaining document range after the character cursor.\r
+               function getRangeAfterCursor( cursor , inclusive )\r
+               {\r
+                       var range = new CKEDITOR.dom.range();\r
+                       range.setStart( cursor.textNode,\r
+                                                  ( inclusive ? cursor.offset : cursor.offset + 1 ) );\r
+                       range.setEndAt( editor.document.getBody(),\r
+                                                       CKEDITOR.POSITION_BEFORE_END );\r
+                       return range;\r
+               }\r
+\r
+               // The document range before the character cursor.\r
+               function getRangeBeforeCursor( cursor )\r
+               {\r
+                       var range = new CKEDITOR.dom.range();\r
+                       range.setStartAt( editor.document.getBody(),\r
+                                                       CKEDITOR.POSITION_AFTER_START );\r
+                       range.setEnd( cursor.textNode, cursor.offset );\r
+                       return range;\r
+               }\r
+\r
+               var KMP_NOMATCH = 0,\r
+                       KMP_ADVANCED = 1,\r
+                       KMP_MATCHED = 2;\r
+               /**\r
+                * Examination the occurrence of a word which implement KMP algorithm.\r
+                */\r
+               var kmpMatcher = function( pattern, ignoreCase )\r
+               {\r
+                       var overlap = [ -1 ];\r
+                       if ( ignoreCase )\r
+                               pattern = pattern.toLowerCase();\r
+                       for ( var i = 0 ; i < pattern.length ; i++ )\r
+                       {\r
+                               overlap.push( overlap[i] + 1 );\r
+                               while ( overlap[ i + 1 ] > 0\r
+                                       && pattern.charAt( i ) != pattern\r
+                                               .charAt( overlap[ i + 1 ] - 1 ) )\r
+                                       overlap[ i + 1 ] = overlap[ overlap[ i + 1 ] - 1 ] + 1;\r
+                       }\r
+\r
+                       this._ = {\r
+                               overlap : overlap,\r
+                               state : 0,\r
+                               ignoreCase : !!ignoreCase,\r
+                               pattern : pattern\r
+                       };\r
+               };\r
+\r
+               kmpMatcher.prototype =\r
+               {\r
+                       feedCharacter : function( c )\r
+                       {\r
+                               if ( this._.ignoreCase )\r
+                                       c = c.toLowerCase();\r
+\r
+                               while ( true )\r
+                               {\r
+                                       if ( c == this._.pattern.charAt( this._.state ) )\r
+                                       {\r
+                                               this._.state++;\r
+                                               if ( this._.state == this._.pattern.length )\r
+                                               {\r
+                                                       this._.state = 0;\r
+                                                       return KMP_MATCHED;\r
+                                               }\r
+                                               return KMP_ADVANCED;\r
+                                       }\r
+                                       else if ( !this._.state )\r
+                                               return KMP_NOMATCH;\r
+                                       else\r
+                                               this._.state = this._.overlap[ this._.state ];\r
+                               }\r
+\r
+                               return null;\r
+                       },\r
+\r
+                       reset : function()\r
+                       {\r
+                               this._.state = 0;\r
+                       }\r
+               };\r
+\r
+               var wordSeparatorRegex =\r
+               /[.,"'?!;: \u0085\u00a0\u1680\u280e\u2028\u2029\u202f\u205f\u3000]/;\r
+\r
+               var isWordSeparator = function( c )\r
+               {\r
+                       if ( !c )\r
+                               return true;\r
+                       var code = c.charCodeAt( 0 );\r
+                       return ( code >= 9 && code <= 0xd )\r
+                               || ( code >= 0x2000 && code <= 0x200a )\r
+                               || wordSeparatorRegex.test( c );\r
+               };\r
+\r
+               var finder = {\r
+                       searchRange : null,\r
+                       matchRange : null,\r
+                       find : function( pattern, matchCase, matchWord, matchCyclic, highlightMatched )\r
+                       {\r
+                               if( !this.matchRange )\r
+                                       this.matchRange =\r
+                                               new characterRange(\r
+                                                       new characterWalker( this.searchRange ),\r
+                                                       pattern.length );\r
+                               else\r
+                               {\r
+                                       this.matchRange.removeHighlight();\r
+                                       this.matchRange = this.matchRange.getNextCharacterRange( pattern.length );\r
+                               }\r
+\r
+                               var matcher = new kmpMatcher( pattern, !matchCase ),\r
+                                       matchState = KMP_NOMATCH,\r
+                                       character = '%';\r
+\r
+                               while ( character !== null )\r
+                               {\r
+                                       this.matchRange.moveNext();\r
+                                       while ( ( character = this.matchRange.getEndCharacter() ) )\r
+                                       {\r
+                                               matchState = matcher.feedCharacter( character );\r
+                                               if ( matchState == KMP_MATCHED )\r
+                                                       break;\r
+                                               if ( this.matchRange.moveNext().hitMatchBoundary )\r
+                                                       matcher.reset();\r
+                                       }\r
+\r
+                                       if ( matchState == KMP_MATCHED )\r
+                                       {\r
+                                               if ( matchWord )\r
+                                               {\r
+                                                       var cursors = this.matchRange.getCursors(),\r
+                                                               tail = cursors[ cursors.length - 1 ],\r
+                                                               head = cursors[ 0 ];\r
+\r
+                                                       var headWalker = new characterWalker( getRangeBeforeCursor( head ), true ),\r
+                                                               tailWalker = new characterWalker( getRangeAfterCursor( tail ), true );\r
+\r
+                                                       if ( ! ( isWordSeparator( headWalker.back().character )\r
+                                                                               && isWordSeparator( tailWalker.next().character ) ) )\r
+                                                               continue;\r
+                                               }\r
+                                               this.matchRange.setMatched();\r
+                                               if ( highlightMatched !== false )\r
+                                                       this.matchRange.highlight();\r
+                                               return true;\r
+                                       }\r
+                               }\r
+\r
+                               this.matchRange.clearMatched();\r
+                               this.matchRange.removeHighlight();\r
+                               // Clear current session and restart with the default search\r
+                               // range.\r
+                               if ( matchCyclic )\r
+                               {\r
+                                       this.searchRange = getSearchRange( true );\r
+                                       this.matchRange = null;\r
+                               }\r
+\r
+                               return false;\r
+                       },\r
+\r
+                       /**\r
+                        * Record how much replacement occurred toward one replacing.\r
+                        */\r
+                       replaceCounter : 0,\r
+\r
+                       replace : function( dialog, pattern, newString, matchCase, matchWord,\r
+                               matchCyclic , isReplaceAll )\r
+                       {\r
+                               // Successiveness of current replace/find.\r
+                               var result = false;\r
+\r
+                               // 1. Perform the replace when there's already a match here.\r
+                               // 2. Otherwise perform the find but don't replace it immediately.\r
+                               if ( this.matchRange && this.matchRange.isMatched()\r
+                                               && !this.matchRange._.isReplaced )\r
+                               {\r
+                                       // Turn off highlight for a while when saving snapshots.\r
+                                       this.matchRange.removeHighlight();\r
+                                       var domRange = this.matchRange.toDomRange();\r
+                                       var text = editor.document.createText( newString );\r
+                                       if ( !isReplaceAll )\r
+                                       {\r
+                                               // Save undo snaps before and after the replacement.\r
+                                               var selection = editor.getSelection();\r
+                                               selection.selectRanges( [ domRange ] );\r
+                                               editor.fire( 'saveSnapshot' );\r
+                                       }\r
+                                       domRange.deleteContents();\r
+                                       domRange.insertNode( text );\r
+                                       if ( !isReplaceAll )\r
+                                       {\r
+                                               selection.selectRanges( [ domRange ] );\r
+                                               editor.fire( 'saveSnapshot' );\r
+                                       }\r
+                                       this.matchRange.updateFromDomRange( domRange );\r
+                                       if ( !isReplaceAll )\r
+                                               this.matchRange.highlight();\r
+                                       this.matchRange._.isReplaced = true;\r
+                                       this.replaceCounter++;\r
+                                       result = true;\r
+                               }\r
+                               else\r
+                                       result = this.find( pattern, matchCase, matchWord, matchCyclic, !isReplaceAll );\r
+\r
+                               return result;\r
+                       }\r
+               };\r
+\r
+               /**\r
+                * The range in which find/replace happened, receive from user\r
+                * selection prior.\r
+                */\r
+               function getSearchRange( isDefault )\r
+               {\r
+                       var searchRange,\r
+                               sel = editor.getSelection(),\r
+                               body = editor.document.getBody();\r
+                       if ( sel && !isDefault )\r
+                       {\r
+                               searchRange = sel.getRanges()[ 0 ].clone();\r
+                               searchRange.collapse( true );\r
+                       }\r
+                       else\r
+                       {\r
+                               searchRange = new CKEDITOR.dom.range();\r
+                               searchRange.setStartAt( body, CKEDITOR.POSITION_AFTER_START );\r
+                       }\r
+                       searchRange.setEndAt( body, CKEDITOR.POSITION_BEFORE_END );\r
+                       return searchRange;\r
+               }\r
+\r
+               return {\r
+                       title : editor.lang.findAndReplace.title,\r
+                       resizable : CKEDITOR.DIALOG_RESIZE_NONE,\r
+                       minWidth : 350,\r
+                       minHeight : 165,\r
+                       buttons : [ CKEDITOR.dialog.cancelButton ],             //Cancel button only.\r
+                       contents : [\r
+                               {\r
+                                       id : 'find',\r
+                                       label : editor.lang.findAndReplace.find,\r
+                                       title : editor.lang.findAndReplace.find,\r
+                                       accessKey : '',\r
+                                       elements : [\r
+                                               {\r
+                                                       type : 'hbox',\r
+                                                       widths : [ '230px', '90px' ],\r
+                                                       children :\r
+                                                       [\r
+                                                               {\r
+                                                                       type : 'text',\r
+                                                                       id : 'txtFindFind',\r
+                                                                       label : editor.lang.findAndReplace.findWhat,\r
+                                                                       isChanged : false,\r
+                                                                       labelLayout : 'horizontal',\r
+                                                                       accessKey : 'F'\r
+                                                               },\r
+                                                               {\r
+                                                                       type : 'button',\r
+                                                                       align : 'left',\r
+                                                                       style : 'width:100%',\r
+                                                                       label : editor.lang.findAndReplace.find,\r
+                                                                       onClick : function()\r
+                                                                       {\r
+                                                                               var dialog = this.getDialog();\r
+                                                                               if ( !finder.find( dialog.getValueOf( 'find', 'txtFindFind' ),\r
+                                                                                                       dialog.getValueOf( 'find', 'txtFindCaseChk' ),\r
+                                                                                                       dialog.getValueOf( 'find', 'txtFindWordChk' ),\r
+                                                                                                       dialog.getValueOf( 'find', 'txtFindCyclic' ) ) )\r
+                                                                                       alert( editor.lang.findAndReplace\r
+                                                                                               .notFoundMsg );\r
+                                                                       }\r
+                                                               }\r
+                                                       ]\r
+                                               },\r
+                                               {\r
+                                                       type : 'vbox',\r
+                                                       padding : 0,\r
+                                                       children :\r
+                                                       [\r
+                                                               {\r
+                                                                       type : 'checkbox',\r
+                                                                       id : 'txtFindCaseChk',\r
+                                                                       isChanged : false,\r
+                                                                       style : 'margin-top:28px',\r
+                                                                       label : editor.lang.findAndReplace.matchCase\r
+                                                               },\r
+                                                               {\r
+                                                                       type : 'checkbox',\r
+                                                                       id : 'txtFindWordChk',\r
+                                                                       isChanged : false,\r
+                                                                       label : editor.lang.findAndReplace.matchWord\r
+                                                               },\r
+                                                               {\r
+                                                                       type : 'checkbox',\r
+                                                                       id : 'txtFindCyclic',\r
+                                                                       isChanged : false,\r
+                                                                       'default' : true,\r
+                                                                       label : editor.lang.findAndReplace.matchCyclic\r
+                                                               }\r
+                                                       ]\r
+                                               }\r
+                                       ]\r
+                               },\r
+                               {\r
+                                       id : 'replace',\r
+                                       label : editor.lang.findAndReplace.replace,\r
+                                       accessKey : 'M',\r
+                                       elements : [\r
+                                               {\r
+                                                       type : 'hbox',\r
+                                                       widths : [ '230px', '90px' ],\r
+                                                       children :\r
+                                                       [\r
+                                                               {\r
+                                                                       type : 'text',\r
+                                                                       id : 'txtFindReplace',\r
+                                                                       label : editor.lang.findAndReplace.findWhat,\r
+                                                                       isChanged : false,\r
+                                                                       labelLayout : 'horizontal',\r
+                                                                       accessKey : 'F'\r
+                                                               },\r
+                                                               {\r
+                                                                       type : 'button',\r
+                                                                       align : 'left',\r
+                                                                       style : 'width:100%',\r
+                                                                       label : editor.lang.findAndReplace.replace,\r
+                                                                       onClick : function()\r
+                                                                       {\r
+                                                                               var dialog = this.getDialog();\r
+                                                                               if ( !finder.replace( dialog,\r
+                                                                                                       dialog.getValueOf( 'replace', 'txtFindReplace' ),\r
+                                                                                                       dialog.getValueOf( 'replace', 'txtReplace' ),\r
+                                                                                                       dialog.getValueOf( 'replace', 'txtReplaceCaseChk' ),\r
+                                                                                                       dialog.getValueOf( 'replace', 'txtReplaceWordChk' ),\r
+                                                                                                       dialog.getValueOf( 'replace', 'txtReplaceCyclic' ) ) )\r
+                                                                                       alert( editor.lang.findAndReplace\r
+                                                                                               .notFoundMsg );\r
+                                                                       }\r
+                                                               }\r
+                                                       ]\r
+                                               },\r
+                                               {\r
+                                                       type : 'hbox',\r
+                                                       widths : [ '230px', '90px' ],\r
+                                                       children :\r
+                                                       [\r
+                                                               {\r
+                                                                       type : 'text',\r
+                                                                       id : 'txtReplace',\r
+                                                                       label : editor.lang.findAndReplace.replaceWith,\r
+                                                                       isChanged : false,\r
+                                                                       labelLayout : 'horizontal',\r
+                                                                       accessKey : 'R'\r
+                                                               },\r
+                                                               {\r
+                                                                       type : 'button',\r
+                                                                       align : 'left',\r
+                                                                       style : 'width:100%',\r
+                                                                       label : editor.lang.findAndReplace.replaceAll,\r
+                                                                       isChanged : false,\r
+                                                                       onClick : function()\r
+                                                                       {\r
+                                                                               var dialog = this.getDialog();\r
+                                                                               var replaceNums;\r
+\r
+                                                                               finder.replaceCounter = 0;\r
+\r
+                                                                               // Scope to full document.\r
+                                                                               finder.searchRange = getSearchRange( true );\r
+                                                                               if ( finder.matchRange )\r
+                                                                               {\r
+                                                                                       finder.matchRange.removeHighlight();\r
+                                                                                       finder.matchRange = null;\r
+                                                                               }\r
+                                                                               editor.fire( 'saveSnapshot' );\r
+                                                                               while( finder.replace( dialog,\r
+                                                                                       dialog.getValueOf( 'replace', 'txtFindReplace' ),\r
+                                                                                       dialog.getValueOf( 'replace', 'txtReplace' ),\r
+                                                                                       dialog.getValueOf( 'replace', 'txtReplaceCaseChk' ),\r
+                                                                                       dialog.getValueOf( 'replace', 'txtReplaceWordChk' ),\r
+                                                                                       false, true ) )\r
+                                                                               { /*jsl:pass*/ }\r
+\r
+                                                                               if ( finder.replaceCounter )\r
+                                                                               {\r
+                                                                                       alert( editor.lang.findAndReplace.replaceSuccessMsg.replace( /%1/, finder.replaceCounter ) );\r
+                                                                                       editor.fire( 'saveSnapshot' );\r
+                                                                               }\r
+                                                                               else\r
+                                                                                       alert( editor.lang.findAndReplace.notFoundMsg );\r
+                                                                       }\r
+                                                               }\r
+                                                       ]\r
+                                               },\r
+                                               {\r
+                                                       type : 'vbox',\r
+                                                       padding : 0,\r
+                                                       children :\r
+                                                       [\r
+                                                               {\r
+                                                                       type : 'checkbox',\r
+                                                                       id : 'txtReplaceCaseChk',\r
+                                                                       isChanged : false,\r
+                                                                       label : editor.lang.findAndReplace\r
+                                                                               .matchCase\r
+                                                               },\r
+                                                               {\r
+                                                                       type : 'checkbox',\r
+                                                                       id : 'txtReplaceWordChk',\r
+                                                                       isChanged : false,\r
+                                                                       label : editor.lang.findAndReplace\r
+                                                                               .matchWord\r
+                                                               },\r
+                                                               {\r
+                                                                       type : 'checkbox',\r
+                                                                       id : 'txtReplaceCyclic',\r
+                                                                       isChanged : false,\r
+                                                                       'default' : true,\r
+                                                                       label : editor.lang.findAndReplace\r
+                                                                               .matchCyclic\r
+                                                               }\r
+                                                       ]\r
+                                               }\r
+                                       ]\r
+                               }\r
+                       ],\r
+                       onLoad : function()\r
+                       {\r
+                               var dialog = this;\r
+\r
+                               //keep track of the current pattern field in use.\r
+                               var patternField, wholeWordChkField;\r
+\r
+                               //Ignore initial page select on dialog show\r
+                               var isUserSelect = false;\r
+                               this.on('hide', function()\r
+                                               {\r
+                                                       isUserSelect = false;\r
+                                               } );\r
+                               this.on('show', function()\r
+                                               {\r
+                                                       isUserSelect = true;\r
+                                               } );\r
+\r
+                               this.selectPage = CKEDITOR.tools.override( this.selectPage, function( originalFunc )\r
+                                       {\r
+                                               return function( pageId )\r
+                                               {\r
+                                                       originalFunc.call( dialog, pageId );\r
+\r
+                                                       var currPage = dialog._.tabs[ pageId ];\r
+                                                       var patternFieldInput, patternFieldId, wholeWordChkFieldId;\r
+                                                       patternFieldId = pageId === 'find' ? 'txtFindFind' : 'txtFindReplace';\r
+                                                       wholeWordChkFieldId = pageId === 'find' ? 'txtFindWordChk' : 'txtReplaceWordChk';\r
+\r
+                                                       patternField = dialog.getContentElement( pageId,\r
+                                                               patternFieldId );\r
+                                                       wholeWordChkField = dialog.getContentElement( pageId,\r
+                                                               wholeWordChkFieldId );\r
+\r
+                                                       // prepare for check pattern text filed 'keyup' event\r
+                                                       if ( !currPage.initialized )\r
+                                                       {\r
+                                                               patternFieldInput = CKEDITOR.document\r
+                                                                       .getById( patternField._.inputId );\r
+                                                               currPage.initialized = true;\r
+                                                       }\r
+\r
+                                                       if( isUserSelect )\r
+                                                               // synchronize fields on tab switch.\r
+                                                               syncFieldsBetweenTabs.call( this, pageId );\r
+                                               };\r
+                                       } );\r
+\r
+                       },\r
+                       onShow : function()\r
+                       {\r
+                               // Establish initial searching start position.\r
+                               finder.searchRange = getSearchRange();\r
+\r
+                               if ( startupPage == 'replace' )\r
+                                       this.getContentElement( 'replace', 'txtFindReplace' ).focus();\r
+                               else\r
+                                       this.getContentElement( 'find', 'txtFindFind' ).focus();\r
+                       },\r
+                       onHide : function()\r
+                       {\r
+                               if ( finder.matchRange && finder.matchRange.isMatched() )\r
+                               {\r
+                                       finder.matchRange.removeHighlight();\r
+                                       editor.focus();\r
+                                       editor.getSelection().selectRanges(\r
+                                               [ finder.matchRange.toDomRange() ] );\r
+                               }\r
+\r
+                               // Clear current session before dialog close\r
+                               delete finder.matchRange;\r
+                       }\r
+               };\r
+       };\r
+\r
+       CKEDITOR.dialog.add( 'find', function( editor )\r
+               {\r
+                       return findDialog( editor, 'find' );\r
+               });\r
+\r
+       CKEDITOR.dialog.add( 'replace', function( editor )\r
+               {\r
+                       return findDialog( editor, 'replace' );\r
+               });\r
+})();\r