source: Dev/trunk/src/client/dojox/editor/plugins/FindReplace.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

  • Property svn:executable set to *
File size: 26.0 KB
Line 
1define([
2        "dojo",
3        "dijit",
4        "dojox",
5        "dijit/_base/manager",  // getUniqueId
6        "dijit/_base/popup",
7        "dijit/_Widget",
8        "dijit/_TemplatedMixin",
9        "dijit/_KeyNavContainer",
10        "dijit/_WidgetsInTemplateMixin",
11        "dijit/TooltipDialog",
12        "dijit/Toolbar",
13        "dijit/form/CheckBox",
14        "dijit/form/_TextBoxMixin",     // selectInputText
15        "dijit/form/TextBox",
16        "dijit/_editor/_Plugin",
17        "dijit/form/Button",
18        "dijit/form/DropDownButton",
19        "dijit/form/ToggleButton",
20        "./ToolbarLineBreak",
21        "dojo/_base/connect",
22        "dojo/_base/declare",
23        "dojo/i18n",
24        "dojo/string",
25        "dojo/i18n!dojox/editor/plugins/nls/FindReplace"
26], function(dojo, dijit, dojox, manager, popup,
27                        _Widget, _TemplatedMixin, _KeyNavContainer, _WidgetsInTemplateMixin, TooltipDialog,
28                        Toolbar, CheckBox, _TextBoxMixin, TextBox, _Plugin) {
29
30dojo.experimental("dojox.editor.plugins.FindReplace");
31
32var FindReplaceCloseBox = dojo.declare("dojox.editor.plugins._FindReplaceCloseBox",
33        [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], {
34        // summary:
35        //              Base class for widgets that contains a button labeled X
36        //              to close the tool bar.
37       
38        btnId: "",
39        widget: null,
40        widgetsInTemplate: true,
41       
42        templateString:
43                "<span style='float: right' class='dijitInline' tabindex='-1'>" +
44                        "<button class='dijit dijitReset dijitInline' " +
45                                "id='${btnId}' dojoAttachPoint='button' dojoType='dijit.form.Button' tabindex='-1' iconClass='dijitEditorIconsFindReplaceClose' showLabel='false'>X</button>" +
46                "</span>",
47       
48        postMixInProperties: function(){
49                // Set some substitution variables used in the template
50                this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
51                this.btnId = this.id + "_close";
52                this.inherited(arguments);
53        },
54        startup: function(){
55                this.connect(this.button, "onClick", "onClick");
56        },
57        onClick: function(){
58        }
59});
60
61
62var FindReplaceTextBox = dojo.declare("dojox.editor.plugins._FindReplaceTextBox",
63        [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin],{
64        // summary:
65        //              Base class for widgets that contains a label (like "Font:")
66        //              and a TextBox to pick a value.
67        //              Used as Toolbar entry.
68
69        // textId: [public] String
70        //              The id of the enhanced textbox
71        textId: "",
72       
73        // label: [public] String
74        //              The label of the enhanced textbox
75        label: "",
76       
77        // tooltip: [public] String
78        //              The tooltip of the enhanced textbox when the mouse is hovering on it
79        toolTip: "",
80        widget: null,
81        widgetsInTemplate: true,
82
83        templateString:
84                "<span style='white-space: nowrap' class='dijit dijitReset dijitInline dijitEditorFindReplaceTextBox' " +
85                        "title='${tooltip}' tabindex='-1'>" +
86                        "<label class='dijitLeft dijitInline' for='${textId}' tabindex='-1'>${label}</label>" +
87                        "<input dojoType='dijit.form.TextBox' intermediateChanges='true' class='focusTextBox' " +
88                                        "tabIndex='0' id='${textId}' dojoAttachPoint='textBox, focusNode' value='' dojoAttachEvent='onKeyPress: _onKeyPress'/>" +
89                "</span>",
90
91        postMixInProperties: function(){
92                // Set some substitution variables used in the template
93                this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
94                this.textId = this.id + "_text";
95               
96                this.inherited(arguments);
97        },
98
99        postCreate: function(){
100                this.textBox.set("value", "");
101                this.disabled =  this.textBox.get("disabled");
102                this.connect(this.textBox, "onChange", "onChange");
103                dojo.attr(this.textBox.textbox, "formnovalidate", "true");
104        },
105
106        _setValueAttr: function(/*String*/ value){
107                //If the value is not a permitted value, just set empty string to prevent showing the warning icon
108                this.value = value;
109                this.textBox.set("value", value);
110        },
111
112        focus: function(){
113                this.textBox.focus();
114        },
115
116        _setDisabledAttr: function(/*Boolean*/ value){
117                // summary:
118                //              Over-ride for the textbox's 'disabled' attribute so that it can be
119                //              disabled programmatically.
120                // value:
121                //              The boolean value to indicate if the textbox should be disabled or not
122                // tags:
123                //              private
124                this.disabled = value;
125                this.textBox.set("disabled", value);
126        },
127
128        onChange: function(/*String*/ val){
129                // summary:
130                //              Stub function for change events on the box.
131                // tags:
132                //              public
133                this.value= val;
134        },
135       
136        _onKeyPress: function(/*Event*/ evt){
137                // summary:
138                //              Handle the arrow key events
139                // evt:
140                //              Event object passed to this handler
141                // tags:
142                //              private
143                var start = 0;
144                var end = 0;
145               
146                // If CTRL, ALT or SHIFT is not held on
147                if(evt.target && !evt.ctrlKey && !evt.altKey && !evt.shiftKey){
148                        if(evt.keyCode == dojo.keys.LEFT_ARROW){
149                                start = evt.target.selectionStart;
150                                end = evt.target.selectionEnd;
151                                if(start < end){
152                                        dijit.selectInputText(evt.target, start, start);
153                                        dojo.stopEvent(evt);
154                                }
155                        }else if(evt.keyCode == dojo.keys.RIGHT_ARROW){
156                                start = evt.target.selectionStart;
157                                end = evt.target.selectionEnd;
158                                if(start < end){
159                                        dijit.selectInputText(evt.target, end, end);
160                                        dojo.stopEvent(evt);
161                                }
162                        }
163                }
164        }
165});
166
167
168var FindReplaceCheckBox = dojo.declare("dojox.editor.plugins._FindReplaceCheckBox",
169        [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin],{
170        // summary:
171        //              Base class for widgets that contains a label (like "Match case: ")
172        //              and a checkbox to indicate if it is checked or not.
173        //              Used as Toolbar entry.
174
175        // checkId: [public] String
176        //              The id of the enhanced checkbox
177        checkId: "",
178       
179        // label: [public] String
180        //              The label of the enhanced checkbox
181        label: "",
182       
183        // tooltip: [public] String
184        //              The tooltip of the enhanced checkbox when the mouse is hovering it
185        tooltip: "",
186       
187        widget: null,
188        widgetsInTemplate: true,
189
190        templateString:
191                "<span style='white-space: nowrap' tabindex='-1' " +
192                        "class='dijit dijitReset dijitInline dijitEditorFindReplaceCheckBox' title='${tooltip}' >" +
193                        "<input dojoType='dijit.form.CheckBox' " +
194                                        "tabIndex='0' id='${checkId}' dojoAttachPoint='checkBox, focusNode' value=''/>" +
195                        "<label tabindex='-1' class='dijitLeft dijitInline' for='${checkId}'>${label}</label>" +
196                "</span>",
197
198        postMixInProperties: function(){
199                // Set some substitution variables used in the template
200                this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
201                this.checkId = this.id + "_check";
202                this.inherited(arguments);
203        },
204
205        postCreate: function(){
206                this.checkBox.set("checked", false);
207                this.disabled =  this.checkBox.get("disabled");
208                this.checkBox.isFocusable = function(){ return false; };
209        },
210
211        _setValueAttr: function(/*Boolean*/ value){
212                // summary:
213                //              Passthrough for checkbox.
214                // tags:
215                //              private
216                this.checkBox.set('value', value);
217        },
218
219        _getValueAttr: function(){
220                // summary:
221                //              Passthrough for checkbox.
222                // tags:
223                //              private
224                return this.checkBox.get('value');
225        },
226
227        focus: function(){
228                // summary:
229                //              Handle the focus event when this widget gets focused
230                // tags:
231                //              private
232                this.checkBox.focus();
233        },
234
235        _setDisabledAttr: function(/*Boolean*/ value){
236                // summary:
237                //              Over-ride for the button's 'disabled' attribute so that it can be
238                //              disabled programmatically.
239                // value:
240                //              The flag that indicates if the checkbox is disabled or not.
241                // tags:
242                //              private
243                this.disabled = value;
244                this.checkBox.set("disabled", value);
245        }
246});
247
248
249var FindReplaceToolbar = dojo.declare("dojox.editor.plugins._FindReplaceToolbar", Toolbar, {
250        // summary:
251        //              A toolbar that derived from dijit.Toolbar, which
252        //              eliminates some unnecessary event response such as LEFT_ARROW pressing
253        //              and click bubbling.
254
255        postCreate: function(){
256                this.connectKeyNavHandlers([], []); // Prevent arrow key navigation
257                this.connect(this.containerNode, "onclick", "_onToolbarEvent");
258                this.connect(this.containerNode, "onkeydown", "_onToolbarEvent");
259                dojo.addClass(this.domNode, "dijitToolbar");
260        },
261       
262        addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
263                // summary:
264                //              Add a child to our _Container and prevent the default
265                //              arrow key navigation function. This function may bring in
266                //              side effect
267                dijit._KeyNavContainer.superclass.addChild.apply(this, arguments);
268        },
269       
270        _onToolbarEvent: function(/*Event*/ evt){
271                // Editor may have special treatment to some events, so stop the bubbling.
272                // evt:
273                //              The Event object
274                // tages:
275                //              private
276                evt.stopPropagation();
277        }
278});
279
280var FindReplace = dojo.declare("dojox.editor.plugins.FindReplace",[_Plugin],{
281        // summary:
282        //              This plugin provides a Find/Replace capability for the editor.
283        //              Note that this plugin is NOT supported on Opera currently, as opera
284        //              does not implement a window.find or equiv function.
285
286        // buttonClass: [protected]
287        //              Define the class of button the editor uses.
288        buttonClass: dijit.form.ToggleButton,
289
290        // iconClassPrefix: [const] String
291        //              The CSS class name for the button node is formed from `iconClassPrefix` and `command`
292        iconClassPrefix: "dijitEditorIconsFindReplace",
293
294        // editor: [protected]
295        //              The editor this plugin belongs to
296        editor: null,
297       
298        // button: [protected]
299        //              The toggle button
300        button: null,
301       
302        // _frToolbar: [private]
303        //              The toolbar that contain all the entries and buttons
304        _frToolbar: null,
305       
306        // _closeBox: [private]
307        //              The close button of the F/R toolbar
308        _closeBox: null,
309       
310        // _findField: [private]
311        //              The Find field of the F/R toolbar
312        _findField: null,
313       
314        // _replaceField: [private]
315        //              The Replace field of the F/R toolbar
316        _replaceField: null,
317       
318        // _findButton: [private]
319        //              The Find button of the F/R toolbar
320        _findButton: null,
321       
322        // _replaceButton: [private]
323        //              The Replace button of the F/R toolbar
324        _replaceButton: null,
325       
326        // _replaceAllButton: [private]
327        //              The ReplaceAll button of the F/R toolbar
328        _replaceAllButton: null,
329       
330        // _caseSensitive: [private]
331        //              The case sensitive checkbox
332        _caseSensitive: null,
333       
334        // _backwards: [private]
335        //              The backwards checkbox
336        _backwards: null,
337       
338        // _promDialog: [private]
339        //              The prompt message box that shows the user some messages
340        //              such as the end of a search, the end of a replacement, etc.
341        _promDialog: null,
342        _promDialogTimeout: null,
343
344        // _strings: [private]
345        //              The array that contains globalized strings
346        _strings: null,
347
348        _initButton: function(){
349                // summary:
350                //              Over-ride for creation of the resize button.
351                this._strings = dojo.i18n.getLocalization("dojox.editor.plugins", "FindReplace");
352                this.button = new dijit.form.ToggleButton({
353                        label: this._strings["findReplace"],
354                        showLabel: false,
355                        iconClass: this.iconClassPrefix + " dijitEditorIconFindString",
356                        tabIndex: "-1",
357                        onChange: dojo.hitch(this, "_toggleFindReplace")
358                });
359                if(dojo.isOpera){
360                        // Not currently supported on Opera!
361                        this.button.set("disabled", true);
362                }
363                //Link up so that if the toggle is disabled, then the view of Find/Replace is closed.
364                this.connect(this.button, "set", dojo.hitch(this, function(attr, val){
365                        if(attr === "disabled"){
366                                this._toggleFindReplace((!val && this._displayed), true, true);
367                        }
368                }));
369        },
370
371        setEditor: function(editor){
372                // summary:
373                //              This is a callback handler that set a reference to the editor this plugin
374                //              hosts in
375                this.editor = editor;
376                this._initButton();
377        },
378
379        toggle: function(){
380                // summary:
381                //              Function to allow programmatic toggling of the find toolbar.
382                // tags:
383                //              public
384                this.button.set("checked", !this.button.get("checked"));
385        },
386
387        _toggleFindReplace: function(/*Boolean*/ show, /*Boolean?*/ ignoreState, /*Boolean?*/ buttonDisabled){
388                // summary:
389                //              Function to toggle whether or not find/replace is displayed.
390                // show:
391                //              Indicate if the toolbar is shown or not
392                // ignoreState:
393                //              Indicate if the status should be ignored or not
394                // blurEditor:
395                //              Indicate if the focus should be removed from the editor or not
396                // tags:
397                //              private
398                var size = dojo.marginBox(this.editor.domNode);
399                if(show && !dojo.isOpera){
400                        dojo.style(this._frToolbar.domNode, "display", "block");
401                        // Auto populate the Find field
402                        this._populateFindField();
403                        if(!ignoreState){
404                                this._displayed = true;
405                        }
406                }else{
407                        dojo.style(this._frToolbar.domNode, "display", "none");
408                        if(!ignoreState){
409                                this._displayed = false;
410                        }
411                       
412                        // If the toggle button is disabled, it is most likely that
413                        // another plugin such as ViewSource disables it.
414                        // So we do not need to focus the text area of the editor to
415                        // prevent the editor from an invalid status.
416                        // Please refer to dijit._editor.plugins.ViewSource for more details.
417                        if(!buttonDisabled){
418                                this.editor.focus();
419                        }
420                }
421
422                // Resize the editor.
423                this.editor.resize({h: size.h});
424        },
425
426        _populateFindField: function(){
427                // summary:
428                //              Populate the Find field with selected text when dialog initially displayed.
429                //              Auto-select text in Find field after it is populated.
430                //              If nothing selected, restore previous entry from the same session.
431                // tags:
432                //              private
433                var ed = this.editor;
434                var win = ed.window;
435                var selectedTxt = ed._sCall("getSelectedText", [null]);
436                if(this._findField && this._findField.textBox){
437                        if(selectedTxt){
438                                this._findField.textBox.set("value", selectedTxt);
439                        }
440                        this._findField.textBox.focus();
441                        dijit.selectInputText(this._findField.textBox.focusNode);
442                }
443        },
444
445        setToolbar: function(/*dijit.Toolbar*/ toolbar){
446                // summary:
447                //              Over-ride so that find/replace toolbar is appended after the current toolbar.
448                // toolbar:
449                //              The current toolbar of the editor
450                // tags:
451                //              public
452                this.inherited(arguments);
453                if(!dojo.isOpera){
454                        var _tb = (this._frToolbar = new FindReplaceToolbar());
455                        dojo.style(_tb.domNode, "display", "none");
456                        dojo.place(_tb.domNode, toolbar.domNode, "after");
457                        _tb.startup();
458
459                        // IE6 will put the close box in a new line when its style is "float: right".
460                        // So place the close box ahead of the other fields, which makes it align with
461                        // the other components.
462                        this._closeBox = new FindReplaceCloseBox();
463                        _tb.addChild(this._closeBox);
464                       
465                        // Define the search/replace fields.
466                        this._findField = new FindReplaceTextBox(
467                                {label: this._strings["findLabel"], tooltip: this._strings["findTooltip"]});
468                        _tb.addChild(this._findField);
469                       
470                        this._replaceField = new FindReplaceTextBox(
471                                {label: this._strings["replaceLabel"], tooltip: this._strings["replaceTooltip"]});
472                        _tb.addChild(this._replaceField);
473
474                        // Define the Find/Replace/ReplaceAll buttons.
475                        _tb.addChild(new dojox.editor.plugins.ToolbarLineBreak());
476                       
477                        this._findButton = new dijit.form.Button({label: this._strings["findButton"], showLabel: true,
478                                iconClass: this.iconClassPrefix + " dijitEditorIconFind"});
479                        this._findButton.titleNode.title = this._strings["findButtonTooltip"];
480                        _tb.addChild(this._findButton);
481                       
482                        this._replaceButton = new dijit.form.Button({label: this._strings["replaceButton"], showLabel: true,
483                                iconClass: this.iconClassPrefix + " dijitEditorIconReplace"});
484                        this._replaceButton.titleNode.title = this._strings["replaceButtonTooltip"];
485                        _tb.addChild(this._replaceButton);
486                       
487                        this._replaceAllButton = new dijit.form.Button({label: this._strings["replaceAllButton"], showLabel: true,
488                                iconClass: this.iconClassPrefix + " dijitEditorIconReplaceAll"});
489                        this._replaceAllButton.titleNode.title = this._strings["replaceAllButtonTooltip"];
490                        _tb.addChild(this._replaceAllButton);
491                       
492                        // Define the option checkboxes.
493                        this._caseSensitive = new FindReplaceCheckBox(
494                                {label: this._strings["matchCase"], tooltip: this._strings["matchCaseTooltip"]});
495                        _tb.addChild(this._caseSensitive);
496                       
497                        this._backwards = new FindReplaceCheckBox(
498                                {label: this._strings["backwards"], tooltip: this._strings["backwardsTooltip"]});
499                        _tb.addChild(this._backwards);
500
501                        // Set initial states, buttons should be disabled unless content is
502                        // present in the fields.
503                        this._findButton.set("disabled", true);
504                        this._replaceButton.set("disabled", true);
505                        this._replaceAllButton.set("disabled", true);
506
507                        // Connect the event to the status of the items
508                        this.connect(this._findField, "onChange", "_checkButtons");
509                        this.connect(this._findField, "onKeyDown", "_onFindKeyDown");
510                        this.connect(this._replaceField, "onKeyDown", "_onReplaceKeyDown");
511
512                        // Connect up the actual search events.
513                        this.connect(this._findButton, "onClick", "_find");
514                        this.connect(this._replaceButton, "onClick", "_replace");
515                        this.connect(this._replaceAllButton, "onClick", "_replaceAll");
516                       
517                        // Connect up the close event
518                        this.connect(this._closeBox, "onClick", "toggle");
519                       
520                        // Prompt for the message
521                        this._promDialog = new dijit.TooltipDialog();
522                        this._promDialog.startup();
523                        this._promDialog.set("content", "");
524                }
525        },
526
527        _checkButtons: function(){
528                // summary:
529                //              Ensure that all the buttons are in a correct status
530                //              when certain events are fired.
531                var fText = this._findField.get("value");
532
533                if(fText){
534                        // Only enable if find text is not empty or just blank/spaces.
535                        this._findButton.set("disabled", false);
536                        this._replaceButton.set("disabled", false);
537                        this._replaceAllButton.set("disabled", false);
538                }else{
539                        this._findButton.set("disabled", true);
540                        this._replaceButton.set("disabled", true);
541                        this._replaceAllButton.set("disabled", true);
542                }
543        },
544       
545        _onFindKeyDown: function(evt){
546                if(evt.keyCode == dojo.keys.ENTER){
547                        // Perform the default search action
548                        this._find();
549                        dojo.stopEvent(evt);
550                }
551        },
552       
553        _onReplaceKeyDown: function(evt){
554                if(evt.keyCode == dojo.keys.ENTER){
555                        // Perform the default replace action
556                        if(!this._replace()) this._replace();
557                        dojo.stopEvent(evt);
558                }
559        },
560
561        _find: function(/*Boolean?*/ showMessage){
562                // summary:
563                //              This function invokes a find on the editor document with the noted options for
564                //              find.
565                // showMessage:
566                //              Indicated whether the tooltip is shown or not when the search reaches the end
567                // tags:
568                //              private.
569                // returns:
570                //              Boolean indicating if the content was found or not.
571                var txt = this._findField.get("value") || "";
572                if(txt){
573                        var caseSensitive = this._caseSensitive.get("value");
574                        var backwards = this._backwards.get("value");
575                        var isFound = this._findText(txt, caseSensitive, backwards);
576                        if(!isFound && showMessage){
577                                this._promDialog.set("content", dojo.string.substitute(
578                                        this._strings["eofDialogText"], {"0": this._strings["eofDialogTextFind"]}));
579                                dijit.popup.open({popup: this._promDialog, around: this._findButton.domNode});
580                                this._promDialogTimeout = setTimeout(dojo.hitch(this, function(){
581                                        clearTimeout(this._promDialogTimeout);
582                                        this._promDialogTimeout = null;
583                                        dijit.popup.close(this._promDialog);
584                                }), 3000);
585                                setTimeout(dojo.hitch(this, function(){
586                                        this.editor.focus();
587                                }), 0);
588                        }
589                        return isFound;
590                }
591               
592                return false;
593        },
594
595        _replace: function(/*Boolean?*/ showMessage){
596                // summary:
597                //              This function invokes a replace on the editor document with the noted options for replace
598                // showMessage:
599                //              Indicate if the prompt message is shown or not when the replacement
600                //              reaches the end
601                // tags:
602                //              private
603                // returns:
604                //              Boolean indicating if the content was replaced or not.
605                var isReplaced = false;
606                var ed = this.editor;
607                ed.focus();
608                var txt = this._findField.get("value") || "";
609                var repTxt = this._replaceField.get("value") || "";
610                 
611                if(txt){
612                        var caseSensitive = this._caseSensitive.get("value");
613                        // Check if it is forced to be forwards or backwards
614                        var backwards = this._backwards.get("value");
615                       
616                        //Replace the current selected text if it matches the pattern
617                        var selected = ed._sCall("getSelectedText", [null]);
618                        // Handle checking/replacing current selection.  For some reason on Moz
619                        // leading whitespace is trimmed, so we have to trim it down on this check
620                        // or we don't always replace.  Moz bug!
621                        if(dojo.isMoz){
622                                txt = dojo.trim(txt);
623                                selected = dojo.trim(selected);
624                        }
625                       
626                        var regExp = this._filterRegexp(txt, !caseSensitive);
627                        if(selected && regExp.test(selected)){
628                                ed.execCommand("inserthtml", repTxt);
629                                isReplaced = true;
630                       
631                                if(backwards){
632                                        // Move to the beginning of the replaced text
633                                        // to avoid the infinite recursive replace
634                                        this._findText(repTxt, caseSensitive, backwards);
635                                        ed._sCall("collapse", [true]);
636                                }
637                        }
638                       
639                        if(!this._find(false) && showMessage){  // Find the next
640                                this._promDialog.set("content", dojo.string.substitute(
641                                        this._strings["eofDialogText"], {"0": this._strings["eofDialogTextReplace"]}));
642                                dijit.popup.open({popup: this._promDialog, around: this._replaceButton.domNode});
643                                this._promDialogTimeout = setTimeout(dojo.hitch(this, function(){
644                                        clearTimeout(this._promDialogTimeout);
645                                        this._promDialogTimeout = null;
646                                        dijit.popup.close(this._promDialog);
647                                }), 3000);
648                                setTimeout(dojo.hitch(this, function(){
649                                        this.editor.focus();
650                                }), 0);
651                        }
652                        return isReplaced;
653                 }
654                 return null;
655        },
656       
657        _replaceAll: function(/*Boolean?*/ showMessage){
658                // summary:
659                //              This function replaces all the matched content on the editor document
660                //              with the noted options for replace
661                // showMessage:
662                //              Indicate if the prompt message is shown or not when the action is done.
663                // tags:
664                //              private
665                var replaced = 0;
666                var backwards = this._backwards.get("value");
667               
668                if(backwards){
669                        this.editor.placeCursorAtEnd();
670                }else{
671                        this.editor.placeCursorAtStart();
672                }
673               
674                // The _replace will return false if the current selection deos not match
675                // the searched text. So try the first attempt so that the selection
676                // is always the searched text if there is one that matches
677                if(this._replace(false)) { replaced++; }
678                // Do the replace via timeouts to avoid locking the browser up for a lot of replaces.
679                var loopBody = dojo.hitch(this, function(){
680                        if(this._replace(false)){
681                                replaced++;
682                                setTimeout(loopBody, 10);
683                        }else{
684                                if(showMessage){
685                                        this._promDialog.set("content", dojo.string.substitute(
686                                                this._strings["replaceDialogText"], {"0": "" + replaced}));
687                                        dijit.popup.open({
688                                                popup: this._promDialog,
689                                                around: this._replaceAllButton.domNode
690                                        });
691                                        this._promDialogTimeout = setTimeout(dojo.hitch(this, function(){
692                                                clearTimeout(this._promDialogTimeout);
693                                                this._promDialogTimeout = null;
694                                                dijit.popup.close(this._promDialog);
695                                        }), 3000);
696                                        setTimeout(dojo.hitch(this, function(){
697                                                this._findField.focus();
698                                                this._findField.textBox.focusNode.select();
699                                        }), 0);
700                                }
701                        }
702                });
703                loopBody();
704        },
705
706        _findText: function(/*String*/ txt, /*Boolean*/ caseSensitive, /*Boolean*/ backwards){
707                // summary:
708                //              This function invokes a find with specific options
709                // txt: String
710                //              The text to locate in the document.
711                // caseSensitive: Boolean
712                //              Whether or ot to search case-sensitively.
713                // backwards: Boolean
714                //              Whether or not to search backwards in the document.
715                // tags:
716                //              private.
717                // returns:
718                //              Boolean indicating if the content was found or not.
719                var ed = this.editor;
720                var win = ed.window;
721                var found = false;
722                if(txt){
723                        if(win.find){
724                                found = win.find(txt, caseSensitive, backwards, false, false, false, false);
725                        }else{
726                                var doc = ed.document;
727                                if(doc.selection){
728                                        /* IE */
729                                        // Focus to restore position/selection,
730                                        // then shift to search from current position.
731                                        this.editor.focus();
732                                        var txtRg = doc.body.createTextRange();
733                                        var curPos = doc.selection?doc.selection.createRange():null;
734                                        if(curPos){
735                                                if(backwards){
736                                                        txtRg.setEndPoint("EndToStart", curPos);
737                                                }else{
738                                                        txtRg.setEndPoint("StartToEnd", curPos);
739                                                }
740                                        }
741                                        var flags = caseSensitive?4:0;
742                                        if(backwards){
743                                                flags = flags | 1;
744                                        }
745                                        //flags = flags |
746                                        found = txtRg.findText(txt,txtRg.text.length,flags);
747                                        if(found){
748                                                txtRg.select();
749                                        }
750                                }
751                        }
752                }
753                return found;
754        },
755
756        _filterRegexp: function(/*String*/ pattern, /*Boolean*/ ignoreCase){
757                // summary:
758                //              Helper function to convert a simple pattern to a regular expression for matching.
759                // description:
760                //              Returns a regular expression object that conforms to the defined conversion rules.
761                //              For example:
762                //
763                //              - ca*   -> /^ca.*$/
764                //              - *ca*  -> /^.*ca.*$/
765                //              - *c\*a*  -> /^.*c\*a.*$/
766                //              - *c\*a?*  -> /^.*c\*a..*$/
767                //
768                //              and so on.
769                // pattern: string
770                //              A simple matching pattern to convert that follows basic rules:
771                //
772                //              - * Means match anything, so ca* means match anything starting with ca
773                //              - ? Means match single character.  So, b?b will match to bob and bab, and so on.
774                //              - \ is an escape character.  So for example, \* means do not treat * as a match, but literal character *.
775                //                To use a \ as a character in the string, it must be escaped.  So in the pattern it should be
776                //                represented by \\ to be treated as an ordinary \ character instead of an escape.
777                // ignoreCase:
778                //              An optional flag to indicate if the pattern matching should be treated as case-sensitive or not when comparing
779                //              By default, it is assumed case sensitive.
780                // tags:
781                //              private
782
783                var rxp = "";
784                var c = null;
785                for(var i = 0; i < pattern.length; i++){
786                        c = pattern.charAt(i);
787                        switch(c){
788                                case '\\':
789                                        rxp += c;
790                                        i++;
791                                        rxp += pattern.charAt(i);
792                                        break;
793                                case '$':
794                                case '^':
795                                case '/':
796                                case '+':
797                                case '.':
798                                case '|':
799                                case '(':
800                                case ')':
801                                case '{':
802                                case '}':
803                                case '[':
804                                case ']':
805                                        rxp += "\\"; //fallthrough
806                                default:
807                                        rxp += c;
808                        }
809                }
810                rxp = "^" + rxp + "$";
811                if(ignoreCase){
812                        return new RegExp(rxp,"mi"); //RegExp
813                }else{
814                        return new RegExp(rxp,"m"); //RegExp
815                }
816               
817        },
818       
819        updateState: function(){
820                // summary:
821                //              Over-ride for button state control for disabled to work.
822                this.button.set("disabled", this.get("disabled"));
823        },
824
825        destroy: function(){
826                // summary:
827                //              Cleanup of our custom toolbar.
828                this.inherited(arguments);
829                if(this._promDialogTimeout){
830                        clearTimeout(this._promDialogTimeout);
831                        this._promDialogTimeout = null;
832                        dijit.popup.close(this._promDialog);
833                }
834                if(this._frToolbar){
835                        this._frToolbar.destroyRecursive();
836                        this._frToolbar = null;
837                }
838                if(this._promDialog){
839                        this._promDialog.destroyRecursive();
840                        this._promDialog = null;
841                }
842        }
843});
844
845// For monkey patching
846FindReplace._FindReplaceCloseBox = FindReplaceCloseBox;
847FindReplace._FindReplaceTextBox = FindReplaceTextBox;
848FindReplace._FindReplaceCheckBox = FindReplaceCheckBox;
849FindReplace._FindReplaceToolbar = FindReplaceToolbar;
850
851// Register this plugin.
852dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
853        if(o.plugin){ return; }
854        var name = o.args.name.toLowerCase();
855        if(name ===  "findreplace"){
856                o.plugin = new FindReplace({});
857        }
858});
859
860return FindReplace;
861
862});
Note: See TracBrowser for help on using the repository browser.