Nation Notes module contributed by Z&H Healthcare.
[openemr.git] / library / custom_template / ckeditor / _source / plugins / find / dialogs / find.js
blobe36a18dce16383bc43d8ddc09dae07b8118a5df3
1 /*
2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
4 */
6 (function()
8         var isReplace;
10         function findEvaluator( node )
11         {
12                 return node.type == CKEDITOR.NODE_TEXT && node.getLength() > 0 && ( !isReplace || !node.isReadOnly() );
13         }
15         /**
16          * Elements which break characters been considered as sequence.
17         */
18         function nonCharactersBoundary( node )
19         {
20                 return !( node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary(
21                         CKEDITOR.tools.extend( {}, CKEDITOR.dtd.$empty, CKEDITOR.dtd.$nonEditable ) ) );
22         }
24         /**
25          * Get the cursor object which represent both current character and it's dom
26          * position thing.
27          */
28         var cursorStep = function()
29         {
30                 return {
31                         textNode : this.textNode,
32                         offset : this.offset,
33                         character : this.textNode ?
34                                 this.textNode.getText().charAt( this.offset ) : null,
35                         hitMatchBoundary : this._.matchBoundary
36                 };
37         };
39         var pages = [ 'find', 'replace' ],
40                 fieldsMapping = [
41                 [ 'txtFindFind', 'txtFindReplace' ],
42                 [ 'txtFindCaseChk', 'txtReplaceCaseChk' ],
43                 [ 'txtFindWordChk', 'txtReplaceWordChk' ],
44                 [ 'txtFindCyclic', 'txtReplaceCyclic' ] ];
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;
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                         sourceField = this.getContentElement( pages[ sourceIndex ],
61                                         fieldsMapping[ i ][ sourceIndex ] );
62                         targetField = this.getContentElement( pages[ targetIndex ],
63                                         fieldsMapping[ i ][ targetIndex ] );
65                         targetField.setValue( sourceField.getValue() );
66                 }
67         }
69         var findDialog = function( editor, startupPage )
70         {
71                 // Style object for highlights: (#5018)
72                 // 1. Defined as full match style to avoid compromising ordinary text color styles.
73                 // 2. Must be apply onto inner-most text to avoid conflicting with ordinary text color styles visually.
74                 var highlightStyle = new CKEDITOR.style( CKEDITOR.tools.extend( { fullMatch : true, childRule : function(){ return 0; } },
75                         editor.config.find_highlight ) );
77                 /**
78                  * Iterator which walk through the specified range char by char. By
79                  * default the walking will not stop at the character boundaries, until
80                  * the end of the range is encountered.
81                  * @param { CKEDITOR.dom.range } range
82                  * @param {Boolean} matchWord Whether the walking will stop at character boundary.
83                  */
84                 var characterWalker = function( range , matchWord )
85                 {
86                         var self = this;
87                         var walker =
88                                 new CKEDITOR.dom.walker( range );
89                         walker.guard = matchWord ? nonCharactersBoundary : function( node )
90                         {
91                                 !nonCharactersBoundary( node ) && ( self._.matchBoundary = true );
92                         };
93                         walker[ 'evaluator' ] = findEvaluator;
94                         walker.breakOnFalse = 1;
96                         if ( range.startContainer.type == CKEDITOR.NODE_TEXT )
97                         {
98                                 this.textNode = range.startContainer;
99                                 this.offset = range.startOffset - 1;
100                         }
102                         this._ = {
103                                 matchWord : matchWord,
104                                 walker : walker,
105                                 matchBoundary : false
106                         };
107                 };
109                 characterWalker.prototype = {
110                         next : function()
111                         {
112                                 return this.move();
113                         },
115                         back : function()
116                         {
117                                 return this.move( true );
118                         },
120                         move : function( rtl )
121                         {
122                                 var currentTextNode = this.textNode;
123                                 // Already at the end of document, no more character available.
124                                 if ( currentTextNode === null )
125                                         return cursorStep.call( this );
127                                 this._.matchBoundary = false;
129                                 // There are more characters in the text node, step forward.
130                                 if ( currentTextNode
131                                     && rtl
132                                         && this.offset > 0 )
133                                 {
134                                         this.offset--;
135                                         return cursorStep.call( this );
136                                 }
137                                 else if ( currentTextNode
138                                         && this.offset < currentTextNode.getLength() - 1 )
139                                 {
140                                         this.offset++;
141                                         return cursorStep.call( this );
142                                 }
143                                 else
144                                 {
145                                         currentTextNode = null;
146                                         // At the end of the text node, walking foward for the next.
147                                         while ( !currentTextNode )
148                                         {
149                                                 currentTextNode =
150                                                         this._.walker[ rtl ? 'previous' : 'next' ].call( this._.walker );
152                                                 // Stop searching if we're need full word match OR
153                                                 // already reach document end.
154                                                 if ( this._.matchWord && !currentTextNode
155                                                          || this._.walker._.end )
156                                                         break;
157                                         }
158                                         // Found a fresh text node.
159                                         this.textNode = currentTextNode;
160                                         if ( currentTextNode )
161                                                 this.offset = rtl ? currentTextNode.getLength() - 1 : 0;
162                                         else
163                                                 this.offset = 0;
164                                 }
166                                 return cursorStep.call( this );
167                         }
169                 };
171                 /**
172                  * A range of cursors which represent a trunk of characters which try to
173                  * match, it has the same length as the pattern  string.
174                  */
175                 var characterRange = function( characterWalker, rangeLength )
176                 {
177                         this._ = {
178                                 walker : characterWalker,
179                                 cursors : [],
180                                 rangeLength : rangeLength,
181                                 highlightRange : null,
182                                 isMatched : 0
183                         };
184                 };
186                 characterRange.prototype = {
187                         /**
188                          * Translate this range to {@link CKEDITOR.dom.range}
189                          */
190                         toDomRange : function()
191                         {
192                                 var range = new CKEDITOR.dom.range( editor.document );
193                                 var cursors = this._.cursors;
194                                 if ( cursors.length < 1 )
195                                 {
196                                         var textNode = this._.walker.textNode;
197                                         if ( textNode )
198                                                         range.setStartAfter( textNode );
199                                         else
200                                                 return null;
201                                 }
202                                 else
203                                 {
204                                         var first = cursors[0],
205                                                         last = cursors[ cursors.length - 1 ];
207                                         range.setStart( first.textNode, first.offset );
208                                         range.setEnd( last.textNode, last.offset + 1 );
209                                 }
211                                 return range;
212                         },
213                         /**
214                          * Reflect the latest changes from dom range.
215                          */
216                         updateFromDomRange : function( domRange )
217                         {
218                                 var cursor,
219                                                 walker = new characterWalker( domRange );
220                                 this._.cursors = [];
221                                 do
222                                 {
223                                         cursor = walker.next();
224                                         if ( cursor.character )
225                                                 this._.cursors.push( cursor );
226                                 }
227                                 while ( cursor.character );
228                                 this._.rangeLength = this._.cursors.length;
229                         },
231                         setMatched : function()
232                         {
233                                 this._.isMatched = true;
234                         },
236                         clearMatched : function()
237                         {
238                                 this._.isMatched = false;
239                         },
241                         isMatched : function()
242                         {
243                                 return this._.isMatched;
244                         },
246                         /**
247                          * Hightlight the current matched chunk of text.
248                          */
249                         highlight : function()
250                         {
251                                 // Do not apply if nothing is found.
252                                 if ( this._.cursors.length < 1 )
253                                         return;
255                                 // Remove the previous highlight if there's one.
256                                 if ( this._.highlightRange )
257                                         this.removeHighlight();
259                                 // Apply the highlight.
260                                 var range = this.toDomRange(),
261                                         bookmark = range.createBookmark();
262                                 highlightStyle.applyToRange( range );
263                                 range.moveToBookmark( bookmark );
264                                 this._.highlightRange = range;
266                                 // Scroll the editor to the highlighted area.
267                                 var element = range.startContainer;
268                                 if ( element.type != CKEDITOR.NODE_ELEMENT )
269                                         element = element.getParent();
270                                 element.scrollIntoView();
272                                 // Update the character cursors.
273                                 this.updateFromDomRange( range );
274                         },
276                         /**
277                          * Remove highlighted find result.
278                          */
279                         removeHighlight : function()
280                         {
281                                 if ( !this._.highlightRange )
282                                         return;
284                                 var bookmark = this._.highlightRange.createBookmark();
285                                 highlightStyle.removeFromRange( this._.highlightRange );
286                                 this._.highlightRange.moveToBookmark( bookmark );
287                                 this.updateFromDomRange( this._.highlightRange );
288                                 this._.highlightRange = null;
289                         },
291                         isReadOnly : function()
292                         {
293                                 if ( !this._.highlightRange )
294                                         return 0;
296                                 return this._.highlightRange.startContainer.isReadOnly();
297                         },
299                         moveBack : function()
300                         {
301                                 var retval = this._.walker.back(),
302                                         cursors = this._.cursors;
304                                 if ( retval.hitMatchBoundary )
305                                         this._.cursors = cursors = [];
307                                 cursors.unshift( retval );
308                                 if ( cursors.length > this._.rangeLength )
309                                         cursors.pop();
311                                 return retval;
312                         },
314                         moveNext : function()
315                         {
316                                 var retval = this._.walker.next(),
317                                         cursors = this._.cursors;
319                                 // Clear the cursors queue if we've crossed a match boundary.
320                                 if ( retval.hitMatchBoundary )
321                                         this._.cursors = cursors = [];
323                                 cursors.push( retval );
324                                 if ( cursors.length > this._.rangeLength )
325                                         cursors.shift();
327                                 return retval;
328                         },
330                         getEndCharacter : function()
331                         {
332                                 var cursors = this._.cursors;
333                                 if ( cursors.length < 1 )
334                                         return null;
336                                 return cursors[ cursors.length - 1 ].character;
337                         },
339                         getNextCharacterRange : function( maxLength )
340                         {
341                                 var lastCursor,
342                                                 nextRangeWalker,
343                                                 cursors = this._.cursors;
345                                 if ( ( lastCursor = cursors[ cursors.length - 1 ] ) && lastCursor.textNode )
346                                         nextRangeWalker = new characterWalker( getRangeAfterCursor( lastCursor ) );
347                                 // In case it's an empty range (no cursors), figure out next range from walker (#4951).
348                                 else
349                                         nextRangeWalker = this._.walker;
351                                 return new characterRange( nextRangeWalker, maxLength );
352                         },
354                         getCursors : function()
355                         {
356                                 return this._.cursors;
357                         }
358                 };
361                 // The remaining document range after the character cursor.
362                 function getRangeAfterCursor( cursor , inclusive )
363                 {
364                         var range = new CKEDITOR.dom.range();
365                         range.setStart( cursor.textNode,
366                                                    ( inclusive ? cursor.offset : cursor.offset + 1 ) );
367                         range.setEndAt( editor.document.getBody(),
368                                                         CKEDITOR.POSITION_BEFORE_END );
369                         return range;
370                 }
372                 // The document range before the character cursor.
373                 function getRangeBeforeCursor( cursor )
374                 {
375                         var range = new CKEDITOR.dom.range();
376                         range.setStartAt( editor.document.getBody(),
377                                                         CKEDITOR.POSITION_AFTER_START );
378                         range.setEnd( cursor.textNode, cursor.offset );
379                         return range;
380                 }
382                 var KMP_NOMATCH = 0,
383                         KMP_ADVANCED = 1,
384                         KMP_MATCHED = 2;
385                 /**
386                  * Examination the occurrence of a word which implement KMP algorithm.
387                  */
388                 var kmpMatcher = function( pattern, ignoreCase )
389                 {
390                         var overlap = [ -1 ];
391                         if ( ignoreCase )
392                                 pattern = pattern.toLowerCase();
393                         for ( var i = 0 ; i < pattern.length ; i++ )
394                         {
395                                 overlap.push( overlap[i] + 1 );
396                                 while ( overlap[ i + 1 ] > 0
397                                         && pattern.charAt( i ) != pattern
398                                                 .charAt( overlap[ i + 1 ] - 1 ) )
399                                         overlap[ i + 1 ] = overlap[ overlap[ i + 1 ] - 1 ] + 1;
400                         }
402                         this._ = {
403                                 overlap : overlap,
404                                 state : 0,
405                                 ignoreCase : !!ignoreCase,
406                                 pattern : pattern
407                         };
408                 };
410                 kmpMatcher.prototype =
411                 {
412                         feedCharacter : function( c )
413                         {
414                                 if ( this._.ignoreCase )
415                                         c = c.toLowerCase();
417                                 while ( true )
418                                 {
419                                         if ( c == this._.pattern.charAt( this._.state ) )
420                                         {
421                                                 this._.state++;
422                                                 if ( this._.state == this._.pattern.length )
423                                                 {
424                                                         this._.state = 0;
425                                                         return KMP_MATCHED;
426                                                 }
427                                                 return KMP_ADVANCED;
428                                         }
429                                         else if ( !this._.state )
430                                                 return KMP_NOMATCH;
431                                         else
432                                                 this._.state = this._.overlap[ this._.state ];
433                                 }
435                                 return null;
436                         },
438                         reset : function()
439                         {
440                                 this._.state = 0;
441                         }
442                 };
444                 var wordSeparatorRegex =
445                 /[.,"'?!;: \u0085\u00a0\u1680\u280e\u2028\u2029\u202f\u205f\u3000]/;
447                 var isWordSeparator = function( c )
448                 {
449                         if ( !c )
450                                 return true;
451                         var code = c.charCodeAt( 0 );
452                         return ( code >= 9 && code <= 0xd )
453                                 || ( code >= 0x2000 && code <= 0x200a )
454                                 || wordSeparatorRegex.test( c );
455                 };
457                 var finder = {
458                         searchRange : null,
459                         matchRange : null,
460                         find : function( pattern, matchCase, matchWord, matchCyclic, highlightMatched, cyclicRerun )
461                         {
462                                 if ( !this.matchRange )
463                                         this.matchRange =
464                                                 new characterRange(
465                                                         new characterWalker( this.searchRange ),
466                                                         pattern.length );
467                                 else
468                                 {
469                                         this.matchRange.removeHighlight();
470                                         this.matchRange = this.matchRange.getNextCharacterRange( pattern.length );
471                                 }
473                                 var matcher = new kmpMatcher( pattern, !matchCase ),
474                                         matchState = KMP_NOMATCH,
475                                         character = '%';
477                                 while ( character !== null )
478                                 {
479                                         this.matchRange.moveNext();
480                                         while ( ( character = this.matchRange.getEndCharacter() ) )
481                                         {
482                                                 matchState = matcher.feedCharacter( character );
483                                                 if ( matchState == KMP_MATCHED )
484                                                         break;
485                                                 if ( this.matchRange.moveNext().hitMatchBoundary )
486                                                         matcher.reset();
487                                         }
489                                         if ( matchState == KMP_MATCHED )
490                                         {
491                                                 if ( matchWord )
492                                                 {
493                                                         var cursors = this.matchRange.getCursors(),
494                                                                 tail = cursors[ cursors.length - 1 ],
495                                                                 head = cursors[ 0 ];
497                                                         var headWalker = new characterWalker( getRangeBeforeCursor( head ), true ),
498                                                                 tailWalker = new characterWalker( getRangeAfterCursor( tail ), true );
500                                                         if ( ! ( isWordSeparator( headWalker.back().character )
501                                                                                 && isWordSeparator( tailWalker.next().character ) ) )
502                                                                 continue;
503                                                 }
504                                                 this.matchRange.setMatched();
505                                                 if ( highlightMatched !== false )
506                                                         this.matchRange.highlight();
507                                                 return true;
508                                         }
509                                 }
511                                 this.matchRange.clearMatched();
512                                 this.matchRange.removeHighlight();
513                                 // Clear current session and restart with the default search
514                                 // range.
515                                 // Re-run the finding once for cyclic.(#3517)
516                                 if ( matchCyclic && !cyclicRerun )
517                                 {
518                                         this.searchRange = getSearchRange( 1 );
519                                         this.matchRange = null;
520                                         return arguments.callee.apply( this,
521                                                 Array.prototype.slice.call( arguments ).concat( [ true ] ) );
522                                 }
524                                 return false;
525                         },
527                         /**
528                          * Record how much replacement occurred toward one replacing.
529                          */
530                         replaceCounter : 0,
532                         replace : function( dialog, pattern, newString, matchCase, matchWord,
533                                 matchCyclic , isReplaceAll )
534                         {
535                                 isReplace = 1;
537                                 // Successiveness of current replace/find.
538                                 var result = 0;
540                                 // 1. Perform the replace when there's already a match here.
541                                 // 2. Otherwise perform the find but don't replace it immediately.
542                                 if ( this.matchRange && this.matchRange.isMatched()
543                                                 && !this.matchRange._.isReplaced && !this.matchRange.isReadOnly() )
544                                 {
545                                         // Turn off highlight for a while when saving snapshots.
546                                         this.matchRange.removeHighlight();
547                                         var domRange = this.matchRange.toDomRange();
548                                         var text = editor.document.createText( newString );
549                                         if ( !isReplaceAll )
550                                         {
551                                                 // Save undo snaps before and after the replacement.
552                                                 var selection = editor.getSelection();
553                                                 selection.selectRanges( [ domRange ] );
554                                                 editor.fire( 'saveSnapshot' );
555                                         }
556                                         domRange.deleteContents();
557                                         domRange.insertNode( text );
558                                         if ( !isReplaceAll )
559                                         {
560                                                 selection.selectRanges( [ domRange ] );
561                                                 editor.fire( 'saveSnapshot' );
562                                         }
563                                         this.matchRange.updateFromDomRange( domRange );
564                                         if ( !isReplaceAll )
565                                                 this.matchRange.highlight();
566                                         this.matchRange._.isReplaced = true;
567                                         this.replaceCounter++;
568                                         result = 1;
569                                 }
570                                 else
571                                         result = this.find( pattern, matchCase, matchWord, matchCyclic, !isReplaceAll );
573                                 isReplace = 0;
575                                 return result;
576                         }
577                 };
579                 /**
580                  * The range in which find/replace happened, receive from user
581                  * selection prior.
582                  */
583                 function getSearchRange( isDefault )
584                 {
585                         var searchRange,
586                                 sel = editor.getSelection(),
587                                 body = editor.document.getBody();
588                         if ( sel && !isDefault )
589                         {
590                                 searchRange = sel.getRanges()[ 0 ].clone();
591                                 searchRange.collapse( true );
592                         }
593                         else
594                         {
595                                 searchRange = new CKEDITOR.dom.range();
596                                 searchRange.setStartAt( body, CKEDITOR.POSITION_AFTER_START );
597                         }
598                         searchRange.setEndAt( body, CKEDITOR.POSITION_BEFORE_END );
599                         return searchRange;
600                 }
602                 var lang = editor.lang.findAndReplace;
603                 return {
604                         title : lang.title,
605                         resizable : CKEDITOR.DIALOG_RESIZE_NONE,
606                         minWidth : 350,
607                         minHeight : 170,
608                         buttons : [ CKEDITOR.dialog.cancelButton ],             // Cancel button only.
609                         contents : [
610                                 {
611                                         id : 'find',
612                                         label : lang.find,
613                                         title : lang.find,
614                                         accessKey : '',
615                                         elements : [
616                                                 {
617                                                         type : 'hbox',
618                                                         widths : [ '230px', '90px' ],
619                                                         children :
620                                                         [
621                                                                 {
622                                                                         type : 'text',
623                                                                         id : 'txtFindFind',
624                                                                         label : lang.findWhat,
625                                                                         isChanged : false,
626                                                                         labelLayout : 'horizontal',
627                                                                         accessKey : 'F'
628                                                                 },
629                                                                 {
630                                                                         type : 'button',
631                                                                         align : 'left',
632                                                                         style : 'width:100%',
633                                                                         label : lang.find,
634                                                                         onClick : function()
635                                                                         {
636                                                                                 var dialog = this.getDialog();
637                                                                                 if ( !finder.find( dialog.getValueOf( 'find', 'txtFindFind' ),
638                                                                                                         dialog.getValueOf( 'find', 'txtFindCaseChk' ),
639                                                                                                         dialog.getValueOf( 'find', 'txtFindWordChk' ),
640                                                                                                         dialog.getValueOf( 'find', 'txtFindCyclic' ) ) )
641                                                                                         alert( lang
642                                                                                                 .notFoundMsg );
643                                                                         }
644                                                                 }
645                                                         ]
646                                                 },
647                                                 {
648                                                         type : 'vbox',
649                                                         padding : 0,
650                                                         children :
651                                                         [
652                                                                 {
653                                                                         type : 'checkbox',
654                                                                         id : 'txtFindCaseChk',
655                                                                         isChanged : false,
656                                                                         style : 'margin-top:28px',
657                                                                         label : lang.matchCase
658                                                                 },
659                                                                 {
660                                                                         type : 'checkbox',
661                                                                         id : 'txtFindWordChk',
662                                                                         isChanged : false,
663                                                                         label : lang.matchWord
664                                                                 },
665                                                                 {
666                                                                         type : 'checkbox',
667                                                                         id : 'txtFindCyclic',
668                                                                         isChanged : false,
669                                                                         'default' : true,
670                                                                         label : lang.matchCyclic
671                                                                 }
672                                                         ]
673                                                 }
674                                         ]
675                                 },
676                                 {
677                                         id : 'replace',
678                                         label : lang.replace,
679                                         accessKey : 'M',
680                                         elements : [
681                                                 {
682                                                         type : 'hbox',
683                                                         widths : [ '230px', '90px' ],
684                                                         children :
685                                                         [
686                                                                 {
687                                                                         type : 'text',
688                                                                         id : 'txtFindReplace',
689                                                                         label : lang.findWhat,
690                                                                         isChanged : false,
691                                                                         labelLayout : 'horizontal',
692                                                                         accessKey : 'F'
693                                                                 },
694                                                                 {
695                                                                         type : 'button',
696                                                                         align : 'left',
697                                                                         style : 'width:100%',
698                                                                         label : lang.replace,
699                                                                         onClick : function()
700                                                                         {
701                                                                                 var dialog = this.getDialog();
702                                                                                 if ( !finder.replace( dialog,
703                                                                                                         dialog.getValueOf( 'replace', 'txtFindReplace' ),
704                                                                                                         dialog.getValueOf( 'replace', 'txtReplace' ),
705                                                                                                         dialog.getValueOf( 'replace', 'txtReplaceCaseChk' ),
706                                                                                                         dialog.getValueOf( 'replace', 'txtReplaceWordChk' ),
707                                                                                                         dialog.getValueOf( 'replace', 'txtReplaceCyclic' ) ) )
708                                                                                         alert( lang
709                                                                                                 .notFoundMsg );
710                                                                         }
711                                                                 }
712                                                         ]
713                                                 },
714                                                 {
715                                                         type : 'hbox',
716                                                         widths : [ '230px', '90px' ],
717                                                         children :
718                                                         [
719                                                                 {
720                                                                         type : 'text',
721                                                                         id : 'txtReplace',
722                                                                         label : lang.replaceWith,
723                                                                         isChanged : false,
724                                                                         labelLayout : 'horizontal',
725                                                                         accessKey : 'R'
726                                                                 },
727                                                                 {
728                                                                         type : 'button',
729                                                                         align : 'left',
730                                                                         style : 'width:100%',
731                                                                         label : lang.replaceAll,
732                                                                         isChanged : false,
733                                                                         onClick : function()
734                                                                         {
735                                                                                 var dialog = this.getDialog();
736                                                                                 var replaceNums;
738                                                                                 finder.replaceCounter = 0;
740                                                                                 // Scope to full document.
741                                                                                 finder.searchRange = getSearchRange( 1 );
742                                                                                 if ( finder.matchRange )
743                                                                                 {
744                                                                                         finder.matchRange.removeHighlight();
745                                                                                         finder.matchRange = null;
746                                                                                 }
747                                                                                 editor.fire( 'saveSnapshot' );
748                                                                                 while ( finder.replace( dialog,
749                                                                                         dialog.getValueOf( 'replace', 'txtFindReplace' ),
750                                                                                         dialog.getValueOf( 'replace', 'txtReplace' ),
751                                                                                         dialog.getValueOf( 'replace', 'txtReplaceCaseChk' ),
752                                                                                         dialog.getValueOf( 'replace', 'txtReplaceWordChk' ),
753                                                                                         false, true ) )
754                                                                                 { /*jsl:pass*/ }
756                                                                                 if ( finder.replaceCounter )
757                                                                                 {
758                                                                                         alert( lang.replaceSuccessMsg.replace( /%1/, finder.replaceCounter ) );
759                                                                                         editor.fire( 'saveSnapshot' );
760                                                                                 }
761                                                                                 else
762                                                                                         alert( lang.notFoundMsg );
763                                                                         }
764                                                                 }
765                                                         ]
766                                                 },
767                                                 {
768                                                         type : 'vbox',
769                                                         padding : 0,
770                                                         children :
771                                                         [
772                                                                 {
773                                                                         type : 'checkbox',
774                                                                         id : 'txtReplaceCaseChk',
775                                                                         isChanged : false,
776                                                                         label : lang
777                                                                                 .matchCase
778                                                                 },
779                                                                 {
780                                                                         type : 'checkbox',
781                                                                         id : 'txtReplaceWordChk',
782                                                                         isChanged : false,
783                                                                         label : lang
784                                                                                 .matchWord
785                                                                 },
786                                                                 {
787                                                                         type : 'checkbox',
788                                                                         id : 'txtReplaceCyclic',
789                                                                         isChanged : false,
790                                                                         'default' : true,
791                                                                         label : lang
792                                                                                 .matchCyclic
793                                                                 }
794                                                         ]
795                                                 }
796                                         ]
797                                 }
798                         ],
799                         onLoad : function()
800                         {
801                                 var dialog = this;
803                                 // Keep track of the current pattern field in use.
804                                 var patternField, wholeWordChkField;
806                                 // Ignore initial page select on dialog show
807                                 var isUserSelect = 0;
808                                 this.on( 'hide', function()
809                                                 {
810                                                         isUserSelect = 0;
811                                                 });
812                                 this.on( 'show', function()
813                                                 {
814                                                         isUserSelect = 1;
815                                                 });
817                                 this.selectPage = CKEDITOR.tools.override( this.selectPage, function( originalFunc )
818                                         {
819                                                 return function( pageId )
820                                                 {
821                                                         originalFunc.call( dialog, pageId );
823                                                         var currPage = dialog._.tabs[ pageId ];
824                                                         var patternFieldInput, patternFieldId, wholeWordChkFieldId;
825                                                         patternFieldId = pageId === 'find' ? 'txtFindFind' : 'txtFindReplace';
826                                                         wholeWordChkFieldId = pageId === 'find' ? 'txtFindWordChk' : 'txtReplaceWordChk';
828                                                         patternField = dialog.getContentElement( pageId,
829                                                                 patternFieldId );
830                                                         wholeWordChkField = dialog.getContentElement( pageId,
831                                                                 wholeWordChkFieldId );
833                                                         // Prepare for check pattern text filed 'keyup' event
834                                                         if ( !currPage.initialized )
835                                                         {
836                                                                 patternFieldInput = CKEDITOR.document
837                                                                         .getById( patternField._.inputId );
838                                                                 currPage.initialized = true;
839                                                         }
841                                                         // Synchronize fields on tab switch.
842                                                         if ( isUserSelect )
843                                                                 syncFieldsBetweenTabs.call( this, pageId );
844                                                 };
845                                         } );
847                         },
848                         onShow : function()
849                         {
850                                 // Establish initial searching start position.
851                                 finder.searchRange = getSearchRange();
853                                 this.selectPage( startupPage );
854                         },
855                         onHide : function()
856                         {
857                                 var range;
858                                 if ( finder.matchRange && finder.matchRange.isMatched() )
859                                 {
860                                         finder.matchRange.removeHighlight();
861                                         editor.focus();
863                                         range = finder.matchRange.toDomRange();
864                                         if ( range )
865                                                 editor.getSelection().selectRanges( [ range ] );
866                                 }
868                                 // Clear current session before dialog close
869                                 delete finder.matchRange;
870                         },
871                         onFocus : function()
872                         {
873                                 if ( startupPage == 'replace' )
874                                         return this.getContentElement( 'replace', 'txtFindReplace' );
875                                 else
876                                         return this.getContentElement( 'find', 'txtFindFind' );
877                         }
878                 };
879         };
881         CKEDITOR.dialog.add( 'find', function( editor )
882                 {
883                         return findDialog( editor, 'find' );
884                 });
886         CKEDITOR.dialog.add( 'replace', function( editor )
887                 {
888                         return findDialog( editor, 'replace' );
889                 });
890 })();