openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

search.min.js (10306B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: http://codemirror.net/LICENSE
      3 
      4 // Define search commands. Depends on dialog.js or another
      5 // implementation of the openDialog method.
      6 
      7 // Replace works a little oddly -- it will do the replace on the next
      8 // Ctrl-G (or whatever is bound to findNext) press. You prevent a
      9 // replace by making sure the match is no longer selected when hitting
     10 // Ctrl-G.
     11 
     12 (function(mod) {
     13   if (typeof exports == "object" && typeof module == "object") // CommonJS
     14     mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
     15   else if (typeof define == "function" && define.amd) // AMD
     16     define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
     17   else // Plain browser env
     18     mod(CodeMirror);
     19 })(function(CodeMirror) {
     20   "use strict";
     21 
     22   function searchOverlay(query, caseInsensitive) {
     23     if (typeof query == "string")
     24       query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
     25     else if (!query.global)
     26       query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
     27 
     28     return {token: function(stream) {
     29       query.lastIndex = stream.pos;
     30       var match = query.exec(stream.string);
     31       if (match && match.index == stream.pos) {
     32         stream.pos += match[0].length || 1;
     33         return "searching";
     34       } else if (match) {
     35         stream.pos = match.index;
     36       } else {
     37         stream.skipToEnd();
     38       }
     39     }};
     40   }
     41 
     42   function SearchState() {
     43     this.posFrom = this.posTo = this.lastQuery = this.query = null;
     44     this.overlay = null;
     45   }
     46 
     47   function getSearchState(cm) {
     48     return cm.state.search || (cm.state.search = new SearchState());
     49   }
     50 
     51   function queryCaseInsensitive(query) {
     52     return typeof query == "string" && query == query.toLowerCase();
     53   }
     54 
     55   function getSearchCursor(cm, query, pos) {
     56     // Heuristic: if the query string is all lowercase, do a case insensitive search.
     57     return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true});
     58   }
     59 
     60   function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
     61     cm.openDialog(text, onEnter, {
     62       value: deflt,
     63       selectValueOnOpen: true,
     64       closeOnEnter: false,
     65       onClose: function() { clearSearch(cm); },
     66       onKeyDown: onKeyDown
     67     });
     68   }
     69 
     70   function dialog(cm, text, shortText, deflt, f) {
     71     if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
     72     else f(prompt(shortText, deflt));
     73   }
     74 
     75   function confirmDialog(cm, text, shortText, fs) {
     76     if (cm.openConfirm) cm.openConfirm(text, fs);
     77     else if (confirm(shortText)) fs[0]();
     78   }
     79 
     80   function parseString(string) {
     81     return string.replace(/\\(.)/g, function(_, ch) {
     82       if (ch == "n") return "\n"
     83       if (ch == "r") return "\r"
     84       return ch
     85     })
     86   }
     87 
     88   function parseQuery(query) {
     89     var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
     90     if (isRE) {
     91       try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
     92       catch(e) {} // Not a regular expression after all, do a string search
     93     } else {
     94       query = parseString(query)
     95     }
     96     if (typeof query == "string" ? query == "" : query.test(""))
     97       query = /x^/;
     98     return query;
     99   }
    100 
    101   var queryDialog =
    102     '<span class="CodeMirror-search-label">Search:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
    103 
    104   function startSearch(cm, state, query) {
    105     state.queryText = query;
    106     state.query = parseQuery(query);
    107     cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
    108     state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
    109     cm.addOverlay(state.overlay);
    110     if (cm.showMatchesOnScrollbar) {
    111       if (state.annotate) { state.annotate.clear(); state.annotate = null; }
    112       state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
    113     }
    114   }
    115 
    116   function doSearch(cm, rev, persistent, immediate) {
    117     var state = getSearchState(cm);
    118     if (state.query) return findNext(cm, rev);
    119     var q = cm.getSelection() || state.lastQuery;
    120     if (q instanceof RegExp && q.source == "x^") q = null
    121     if (persistent && cm.openDialog) {
    122       var hiding = null
    123       var searchNext = function(query, event) {
    124         CodeMirror.e_stop(event);
    125         if (!query) return;
    126         if (query != state.queryText) {
    127           startSearch(cm, state, query);
    128           state.posFrom = state.posTo = cm.getCursor();
    129         }
    130         if (hiding) hiding.style.opacity = 1
    131         findNext(cm, event.shiftKey, function(_, to) {
    132           var dialog
    133           if (to.line < 3 && document.querySelector &&
    134               (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
    135               dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
    136             (hiding = dialog).style.opacity = .4
    137         })
    138       };
    139       persistentDialog(cm, queryDialog, q, searchNext, function(event, query) {
    140         var keyName = CodeMirror.keyName(event)
    141         var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
    142         if (cmd == "findNext" || cmd == "findPrev" ||
    143           cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
    144           CodeMirror.e_stop(event);
    145           startSearch(cm, getSearchState(cm), query);
    146           cm.execCommand(cmd);
    147         } else if (cmd == "find" || cmd == "findPersistent") {
    148           CodeMirror.e_stop(event);
    149           searchNext(query, event);
    150         }
    151       });
    152       if (immediate && q) {
    153         startSearch(cm, state, q);
    154         findNext(cm, rev);
    155       }
    156     } else {
    157       dialog(cm, queryDialog, "Search for:", q, function(query) {
    158         if (query && !state.query) cm.operation(function() {
    159           startSearch(cm, state, query);
    160           state.posFrom = state.posTo = cm.getCursor();
    161           findNext(cm, rev);
    162         });
    163       });
    164     }
    165   }
    166 
    167   function findNext(cm, rev, callback) {cm.operation(function() {
    168     var state = getSearchState(cm);
    169     var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
    170     if (!cursor.find(rev)) {
    171       cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
    172       if (!cursor.find(rev)) return;
    173     }
    174     cm.setSelection(cursor.from(), cursor.to());
    175     cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
    176     state.posFrom = cursor.from(); state.posTo = cursor.to();
    177     if (callback) callback(cursor.from(), cursor.to())
    178   });}
    179 
    180   function clearSearch(cm) {cm.operation(function() {
    181     var state = getSearchState(cm);
    182     state.lastQuery = state.query;
    183     if (!state.query) return;
    184     state.query = state.queryText = null;
    185     cm.removeOverlay(state.overlay);
    186     if (state.annotate) { state.annotate.clear(); state.annotate = null; }
    187   });}
    188 
    189   var replaceQueryDialog =
    190     ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
    191   var replacementQueryDialog = '<span class="CodeMirror-search-label">With:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
    192   var doReplaceConfirm = '<span class="CodeMirror-search-label">Replace?</span> <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>';
    193 
    194   function replaceAll(cm, query, text) {
    195     cm.operation(function() {
    196       for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
    197         if (typeof query != "string") {
    198           var match = cm.getRange(cursor.from(), cursor.to()).match(query);
    199           cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
    200         } else cursor.replace(text);
    201       }
    202     });
    203   }
    204 
    205   function replace(cm, all) {
    206     if (cm.getOption("readOnly")) return;
    207     var query = cm.getSelection() || getSearchState(cm).lastQuery;
    208     var dialogText = '<span class="CodeMirror-search-label">' + (all ? 'Replace all:' : 'Replace:') + '</span>';
    209     dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
    210       if (!query) return;
    211       query = parseQuery(query);
    212       dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
    213         text = parseString(text)
    214         if (all) {
    215           replaceAll(cm, query, text)
    216         } else {
    217           clearSearch(cm);
    218           var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
    219           var advance = function() {
    220             var start = cursor.from(), match;
    221             if (!(match = cursor.findNext())) {
    222               cursor = getSearchCursor(cm, query);
    223               if (!(match = cursor.findNext()) ||
    224                   (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
    225             }
    226             cm.setSelection(cursor.from(), cursor.to());
    227             cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
    228             confirmDialog(cm, doReplaceConfirm, "Replace?",
    229                           [function() {doReplace(match);}, advance,
    230                            function() {replaceAll(cm, query, text)}]);
    231           };
    232           var doReplace = function(match) {
    233             cursor.replace(typeof query == "string" ? text :
    234                            text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
    235             advance();
    236           };
    237           advance();
    238         }
    239       });
    240     });
    241   }
    242 
    243   CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
    244   CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
    245   CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
    246   CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
    247   CodeMirror.commands.findNext = doSearch;
    248   CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
    249   CodeMirror.commands.clearSearch = clearSearch;
    250   CodeMirror.commands.replace = replace;
    251   CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
    252 });