removed dependency on built-editor.min.js
[ccsdk/distribution.git] / dgbuilder / public / ace / ext-searchbox.js
1 define("ace/ext/searchbox",["require","exports","module","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/keyboard/hash_handler","ace/lib/keys"], function(require, exports, module) {
2 "use strict";
3
4 var dom = require("../lib/dom");
5 var lang = require("../lib/lang");
6 var event = require("../lib/event");
7 var searchboxCss = "\
8 .ace_search {\
9 background-color: #ddd;\
10 color: #666;\
11 border: 1px solid #cbcbcb;\
12 border-top: 0 none;\
13 overflow: hidden;\
14 margin: 0;\
15 padding: 4px 6px 0 4px;\
16 position: absolute;\
17 top: 0;\
18 z-index: 99;\
19 white-space: normal;\
20 }\
21 .ace_search.left {\
22 border-left: 0 none;\
23 border-radius: 0px 0px 5px 0px;\
24 left: 0;\
25 }\
26 .ace_search.right {\
27 border-radius: 0px 0px 0px 5px;\
28 border-right: 0 none;\
29 right: 0;\
30 }\
31 .ace_search_form, .ace_replace_form {\
32 margin: 0 20px 4px 0;\
33 overflow: hidden;\
34 line-height: 1.9;\
35 }\
36 .ace_replace_form {\
37 margin-right: 0;\
38 }\
39 .ace_search_form.ace_nomatch {\
40 outline: 1px solid red;\
41 }\
42 .ace_search_field {\
43 border-radius: 3px 0 0 3px;\
44 background-color: white;\
45 color: black;\
46 border: 1px solid #cbcbcb;\
47 border-right: 0 none;\
48 box-sizing: border-box!important;\
49 outline: 0;\
50 padding: 0;\
51 font-size: inherit;\
52 margin: 0;\
53 line-height: inherit;\
54 padding: 0 6px;\
55 min-width: 17em;\
56 vertical-align: top;\
57 }\
58 .ace_searchbtn {\
59 border: 1px solid #cbcbcb;\
60 line-height: inherit;\
61 display: inline-block;\
62 padding: 0 6px;\
63 background: #fff;\
64 border-right: 0 none;\
65 border-left: 1px solid #dcdcdc;\
66 cursor: pointer;\
67 margin: 0;\
68 position: relative;\
69 box-sizing: content-box!important;\
70 color: #666;\
71 }\
72 .ace_searchbtn:last-child {\
73 border-radius: 0 3px 3px 0;\
74 border-right: 1px solid #cbcbcb;\
75 }\
76 .ace_searchbtn:disabled {\
77 background: none;\
78 cursor: default;\
79 }\
80 .ace_searchbtn:hover {\
81 background-color: #eef1f6;\
82 }\
83 .ace_searchbtn.prev, .ace_searchbtn.next {\
84 padding: 0px 0.7em\
85 }\
86 .ace_searchbtn.prev:after, .ace_searchbtn.next:after {\
87 content: \"\";\
88 border: solid 2px #888;\
89 width: 0.5em;\
90 height: 0.5em;\
91 border-width:  2px 0 0 2px;\
92 display:inline-block;\
93 transform: rotate(-45deg);\
94 }\
95 .ace_searchbtn.next:after {\
96 border-width: 0 2px 2px 0 ;\
97 }\
98 .ace_searchbtn_close {\
99 background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;\
100 border-radius: 50%;\
101 border: 0 none;\
102 color: #656565;\
103 cursor: pointer;\
104 font: 16px/16px Arial;\
105 padding: 0;\
106 height: 14px;\
107 width: 14px;\
108 top: 9px;\
109 right: 7px;\
110 position: absolute;\
111 }\
112 .ace_searchbtn_close:hover {\
113 background-color: #656565;\
114 background-position: 50% 100%;\
115 color: white;\
116 }\
117 .ace_button {\
118 margin-left: 2px;\
119 cursor: pointer;\
120 -webkit-user-select: none;\
121 -moz-user-select: none;\
122 -o-user-select: none;\
123 -ms-user-select: none;\
124 user-select: none;\
125 overflow: hidden;\
126 opacity: 0.7;\
127 border: 1px solid rgba(100,100,100,0.23);\
128 padding: 1px;\
129 box-sizing:    border-box!important;\
130 color: black;\
131 }\
132 .ace_button:hover {\
133 background-color: #eee;\
134 opacity:1;\
135 }\
136 .ace_button:active {\
137 background-color: #ddd;\
138 }\
139 .ace_button.checked {\
140 border-color: #3399ff;\
141 opacity:1;\
142 }\
143 .ace_search_options{\
144 margin-bottom: 3px;\
145 text-align: right;\
146 -webkit-user-select: none;\
147 -moz-user-select: none;\
148 -o-user-select: none;\
149 -ms-user-select: none;\
150 user-select: none;\
151 clear: both;\
152 }\
153 .ace_search_counter {\
154 float: left;\
155 font-family: arial;\
156 padding: 0 8px;\
157 }";
158 var HashHandler = require("../keyboard/hash_handler").HashHandler;
159 var keyUtil = require("../lib/keys");
160
161 var MAX_COUNT = 999;
162
163 dom.importCssString(searchboxCss, "ace_searchbox");
164
165 var html = '<div class="ace_search right">\
166     <span action="hide" class="ace_searchbtn_close"></span>\
167     <div class="ace_search_form">\
168         <input class="ace_search_field" placeholder="Search for" spellcheck="false"></input>\
169         <span action="findPrev" class="ace_searchbtn prev"></span>\
170         <span action="findNext" class="ace_searchbtn next"></span>\
171         <span action="findAll" class="ace_searchbtn" title="Alt-Enter">All</span>\
172     </div>\
173     <div class="ace_replace_form">\
174         <input class="ace_search_field" placeholder="Replace with" spellcheck="false"></input>\
175         <span action="replaceAndFindNext" class="ace_searchbtn">Replace</span>\
176         <span action="replaceAll" class="ace_searchbtn">All</span>\
177     </div>\
178     <div class="ace_search_options">\
179         <span action="toggleReplace" class="ace_button" title="Toggel Replace mode"\
180             style="float:left;margin-top:-2px;padding:0 5px;">+</span>\
181         <span class="ace_search_counter"></span>\
182         <span action="toggleRegexpMode" class="ace_button" title="RegExp Search">.*</span>\
183         <span action="toggleCaseSensitive" class="ace_button" title="CaseSensitive Search">Aa</span>\
184         <span action="toggleWholeWords" class="ace_button" title="Whole Word Search">\\b</span>\
185         <span action="searchInSelection" class="ace_button" title="Search In Selection">S</span>\
186     </div>\
187 </div>'.replace(/> +/g, ">");
188
189 var SearchBox = function(editor, range, showReplaceForm) {
190     var div = dom.createElement("div");
191     div.innerHTML = html;
192     this.element = div.firstChild;
193     
194     this.setSession = this.setSession.bind(this);
195
196     this.$init();
197     this.setEditor(editor);
198 };
199
200 (function() {
201     this.setEditor = function(editor) {
202         editor.searchBox = this;
203         editor.renderer.scroller.appendChild(this.element);
204         this.editor = editor;
205     };
206     
207     this.setSession = function(e) {
208         this.searchRange = null;
209         this.$syncOptions(true);
210     };
211
212     this.$initElements = function(sb) {
213         this.searchBox = sb.querySelector(".ace_search_form");
214         this.replaceBox = sb.querySelector(".ace_replace_form");
215         this.searchOption = sb.querySelector("[action=searchInSelection]");
216         this.replaceOption = sb.querySelector("[action=toggleReplace]");
217         this.regExpOption = sb.querySelector("[action=toggleRegexpMode]");
218         this.caseSensitiveOption = sb.querySelector("[action=toggleCaseSensitive]");
219         this.wholeWordOption = sb.querySelector("[action=toggleWholeWords]");
220         this.searchInput = this.searchBox.querySelector(".ace_search_field");
221         this.replaceInput = this.replaceBox.querySelector(".ace_search_field");
222         this.searchCounter = sb.querySelector(".ace_search_counter");
223     };
224     
225     this.$init = function() {
226         var sb = this.element;
227         
228         this.$initElements(sb);
229         
230         var _this = this;
231         event.addListener(sb, "mousedown", function(e) {
232             setTimeout(function(){
233                 _this.activeInput.focus();
234             }, 0);
235             event.stopPropagation(e);
236         });
237         event.addListener(sb, "click", function(e) {
238             var t = e.target || e.srcElement;
239             var action = t.getAttribute("action");
240             if (action && _this[action])
241                 _this[action]();
242             else if (_this.$searchBarKb.commands[action])
243                 _this.$searchBarKb.commands[action].exec(_this);
244             event.stopPropagation(e);
245         });
246
247         event.addCommandKeyListener(sb, function(e, hashId, keyCode) {
248             var keyString = keyUtil.keyCodeToString(keyCode);
249             var command = _this.$searchBarKb.findKeyCommand(hashId, keyString);
250             if (command && command.exec) {
251                 command.exec(_this);
252                 event.stopEvent(e);
253             }
254         });
255
256         this.$onChange = lang.delayedCall(function() {
257             _this.find(false, false);
258         });
259
260         event.addListener(this.searchInput, "input", function() {
261             _this.$onChange.schedule(20);
262         });
263         event.addListener(this.searchInput, "focus", function() {
264             _this.activeInput = _this.searchInput;
265             _this.searchInput.value && _this.highlight();
266         });
267         event.addListener(this.replaceInput, "focus", function() {
268             _this.activeInput = _this.replaceInput;
269             _this.searchInput.value && _this.highlight();
270         });
271     };
272     this.$closeSearchBarKb = new HashHandler([{
273         bindKey: "Esc",
274         name: "closeSearchBar",
275         exec: function(editor) {
276             editor.searchBox.hide();
277         }
278     }]);
279     this.$searchBarKb = new HashHandler();
280     this.$searchBarKb.bindKeys({
281         "Ctrl-f|Command-f": function(sb) {
282             var isReplace = sb.isReplace = !sb.isReplace;
283             sb.replaceBox.style.display = isReplace ? "" : "none";
284             sb.replaceOption.checked = false;
285             sb.$syncOptions();
286             sb.searchInput.focus();
287         },
288         "Ctrl-H|Command-Option-F": function(sb) {
289             sb.replaceOption.checked = true;
290             sb.$syncOptions();
291             sb.replaceInput.focus();
292         },
293         "Ctrl-G|Command-G": function(sb) {
294             sb.findNext();
295         },
296         "Ctrl-Shift-G|Command-Shift-G": function(sb) {
297             sb.findPrev();
298         },
299         "esc": function(sb) {
300             setTimeout(function() { sb.hide();});
301         },
302         "Return": function(sb) {
303             if (sb.activeInput == sb.replaceInput)
304                 sb.replace();
305             sb.findNext();
306         },
307         "Shift-Return": function(sb) {
308             if (sb.activeInput == sb.replaceInput)
309                 sb.replace();
310             sb.findPrev();
311         },
312         "Alt-Return": function(sb) {
313             if (sb.activeInput == sb.replaceInput)
314                 sb.replaceAll();
315             sb.findAll();
316         },
317         "Tab": function(sb) {
318             (sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus();
319         }
320     });
321
322     this.$searchBarKb.addCommands([{
323         name: "toggleRegexpMode",
324         bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"},
325         exec: function(sb) {
326             sb.regExpOption.checked = !sb.regExpOption.checked;
327             sb.$syncOptions();
328         }
329     }, {
330         name: "toggleCaseSensitive",
331         bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"},
332         exec: function(sb) {
333             sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked;
334             sb.$syncOptions();
335         }
336     }, {
337         name: "toggleWholeWords",
338         bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"},
339         exec: function(sb) {
340             sb.wholeWordOption.checked = !sb.wholeWordOption.checked;
341             sb.$syncOptions();
342         }
343     }, {
344         name: "toggleReplace",
345         exec: function(sb) {
346             sb.replaceOption.checked = !sb.replaceOption.checked;
347             sb.$syncOptions();
348         }
349     }, {
350         name: "searchInSelection",
351         exec: function(sb) {
352             sb.searchOption.checked = !sb.searchRange;
353             sb.setSearchRange(sb.searchOption.checked && sb.editor.getSelectionRange());
354             sb.$syncOptions();
355         }
356     }]);
357     
358     this.setSearchRange = function(range) {
359         this.searchRange = range;
360         if (range) {
361             this.searchRangeMarker = this.editor.session.addMarker(range, "ace_active-line");
362         } else if (this.searchRangeMarker) {
363             this.editor.session.removeMarker(this.searchRangeMarker);
364             this.searchRangeMarker = null;
365         }
366     };
367
368     this.$syncOptions = function(preventScroll) {
369         dom.setCssClass(this.replaceOption, "checked", this.searchRange);
370         dom.setCssClass(this.searchOption, "checked", this.searchOption.checked);
371         this.replaceOption.textContent = this.replaceOption.checked ? "-" : "+";
372         dom.setCssClass(this.regExpOption, "checked", this.regExpOption.checked);
373         dom.setCssClass(this.wholeWordOption, "checked", this.wholeWordOption.checked);
374         dom.setCssClass(this.caseSensitiveOption, "checked", this.caseSensitiveOption.checked);
375         this.replaceBox.style.display = this.replaceOption.checked ? "" : "none";
376         this.find(false, false, preventScroll);
377     };
378
379     this.highlight = function(re) {
380         this.editor.session.highlight(re || this.editor.$search.$options.re);
381         this.editor.renderer.updateBackMarkers();
382     };
383     this.find = function(skipCurrent, backwards, preventScroll) {
384         var range = this.editor.find(this.searchInput.value, {
385             skipCurrent: skipCurrent,
386             backwards: backwards,
387             wrap: true,
388             regExp: this.regExpOption.checked,
389             caseSensitive: this.caseSensitiveOption.checked,
390             wholeWord: this.wholeWordOption.checked,
391             preventScroll: preventScroll,
392             range: this.searchRange
393         });
394         var noMatch = !range && this.searchInput.value;
395         dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
396         this.editor._emit("findSearchBox", { match: !noMatch });
397         this.highlight();
398         this.updateCounter();
399     };
400     this.updateCounter = function() {
401         var editor = this.editor;
402         var regex = editor.$search.$options.re;
403         var all = 0;
404         var before = 0;
405         if (regex) {
406             var value = this.searchRange
407                 ? editor.session.getTextRange(this.searchRange)
408                 : editor.getValue();
409             
410             var offset = editor.session.doc.positionToIndex(editor.selection.anchor);
411             if (this.searchRange)
412                 offset -= editor.session.doc.positionToIndex(this.searchRange.start);
413                 
414             var last = regex.lastIndex = 0;
415             var m;
416             while ((m = regex.exec(value))) {
417                 all++;
418                 last = m.index;
419                 if (last <= offset)
420                     before++;
421                 if (all > MAX_COUNT)
422                     break;
423                 if (!m[0]) {
424                     regex.lastIndex = last += 1;
425                     if (last >= value.length)
426                         break;
427                 }
428             }
429         }
430         this.searchCounter.textContent = before + " of " + (all > MAX_COUNT ? MAX_COUNT + "+" : all);
431     };
432     this.findNext = function() {
433         this.find(true, false);
434     };
435     this.findPrev = function() {
436         this.find(true, true);
437     };
438     this.findAll = function(){
439         var range = this.editor.findAll(this.searchInput.value, {            
440             regExp: this.regExpOption.checked,
441             caseSensitive: this.caseSensitiveOption.checked,
442             wholeWord: this.wholeWordOption.checked
443         });
444         var noMatch = !range && this.searchInput.value;
445         dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
446         this.editor._emit("findSearchBox", { match: !noMatch });
447         this.highlight();
448         this.hide();
449     };
450     this.replace = function() {
451         if (!this.editor.getReadOnly())
452             this.editor.replace(this.replaceInput.value);
453     };    
454     this.replaceAndFindNext = function() {
455         if (!this.editor.getReadOnly()) {
456             this.editor.replace(this.replaceInput.value);
457             this.findNext();
458         }
459     };
460     this.replaceAll = function() {
461         if (!this.editor.getReadOnly())
462             this.editor.replaceAll(this.replaceInput.value);
463     };
464
465     this.hide = function() {
466         this.active = false;
467         this.setSearchRange(null);
468         this.editor.off("changeSession", this.setSession);
469         
470         this.element.style.display = "none";
471         this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb);
472         this.editor.focus();
473     };
474     this.show = function(value, isReplace) {
475         this.active = true;
476         this.editor.on("changeSession", this.setSession);
477         this.element.style.display = "";
478         this.replaceOption.checked = isReplace;
479         
480         if (value)
481             this.searchInput.value = value;
482         
483         this.searchInput.focus();
484         this.searchInput.select();
485
486         this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb);
487         
488         this.$syncOptions(true);
489     };
490
491     this.isFocused = function() {
492         var el = document.activeElement;
493         return el == this.searchInput || el == this.replaceInput;
494     };
495 }).call(SearchBox.prototype);
496
497 exports.SearchBox = SearchBox;
498
499 exports.Search = function(editor, isReplace) {
500     var sb = editor.searchBox || new SearchBox(editor);
501     sb.show(editor.session.getTextRange(), isReplace);
502 };
503
504 });
505                 (function() {
506                     window.require(["ace/ext/searchbox"], function() {});
507                 })();
508