search.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // based on CodeMirror/addon/search/search.js
  2. // Modified by Gerald <[email protected]>
  3. (function() {
  4. function searchOverlay(query) {
  5. if (typeof query == "string") return {token: function(stream) {
  6. if (stream.match(query)) return "searching";
  7. stream.next();
  8. stream.skipTo(query.charAt(0)) || stream.skipToEnd();
  9. }};
  10. return {token: function(stream) {
  11. if (stream.match(query)) return "searching";
  12. while (!stream.eol()) {
  13. stream.next();
  14. if (stream.match(query, false)) break;
  15. }
  16. }};
  17. }
  18. function SearchState() {
  19. this.posFrom = this.posTo = this.query = null;
  20. this.overlay = null;
  21. }
  22. function getSearchState(cm) {
  23. return cm.state.search || (cm.state.search = new SearchState());
  24. }
  25. function getSearchCursor(cm, query, pos) {
  26. // Heuristic: if the query string is all lowercase, do a case insensitive search.
  27. return cm.getSearchCursor(query, pos, typeof query == "string" && query == query.toLowerCase());
  28. }
  29. var dialog=null;
  30. function openDialog(cm, state, rep) {
  31. function close(){
  32. if(closed) return; closed=true;
  33. cm.removeOverlay(state.overlay);
  34. dialog.parentNode.removeChild(dialog);
  35. dialog=null;clearSearch(cm);
  36. cm.focus();
  37. }
  38. if(!dialog) {
  39. var wrap = cm.getWrapperElement();
  40. dialog = wrap.appendChild(document.createElement("div"));
  41. dialog.className='CodeMirror-dialog';
  42. }
  43. var text=_('labelSearch')+'<input class=CodeMirror-search placeholder="'+_('labelSearchFor')+'"><button class=CodeMirror-findPrev>&lt;</button><button class=CodeMirror-findNext>&gt;</button><button class=CodeMirror-cancel>&times;</button>',closed=false,iS,iR;
  44. if(rep) text+='<br>'+_('labelReplace')+'<input class=CodeMirror-replace placeholder="'+_('labelReplaceWith')+'"><button class=CodeMirror-replaceNext>'+_('buttonReplace')+'</button><button class=CodeMirror-replaceAll>'+_('buttonReplaceAll')+'</button>';
  45. dialog.innerHTML=text;
  46. iS=dialog.querySelector('.CodeMirror-search');
  47. CodeMirror.on(dialog.querySelector('.CodeMirror-findNext'), "click", function(e) {findNext(cm);});
  48. CodeMirror.on(dialog.querySelector('.CodeMirror-findPrev'), "click", function(e) {findNext(cm, true);});
  49. CodeMirror.on(dialog.querySelector('.CodeMirror-cancel'), "click", close);
  50. CodeMirror.on(dialog, "keydown", function(e) {
  51. switch(e.keyCode) {
  52. case 27:
  53. close();break;
  54. default:
  55. return;
  56. }
  57. CodeMirror.e_stop(e);
  58. });
  59. CodeMirror.on(iS, "keydown", function(e) {
  60. switch(e.keyCode) {
  61. case 13:
  62. findNext(cm, e.shiftKey);break;
  63. default:
  64. return;
  65. }
  66. CodeMirror.e_stop(e);
  67. });
  68. CodeMirror.on(iS, "keyup", function(e) {
  69. if(state.query!=iS.value) {
  70. state.query=iS.value;
  71. cm.operation(function() {
  72. cm.removeOverlay(state.overlay);
  73. if(!state.query) return;
  74. state.overlay = searchOverlay(state.query);
  75. cm.addOverlay(state.overlay);
  76. state.posTo=state.posFrom;
  77. findNext(cm);
  78. });
  79. }
  80. });
  81. if(rep) {
  82. iR=dialog.querySelector('.CodeMirror-replace');
  83. function _replace(all) {
  84. state.replace=iR.value;
  85. replace(cm, all);
  86. }
  87. CodeMirror.on(dialog.querySelector('.CodeMirror-replaceNext'), "click", function(e) {_replace();});
  88. CodeMirror.on(dialog.querySelector('.CodeMirror-replaceAll'), "click", function(e) {_replace(true);});
  89. CodeMirror.on(iR, "keydown", function(e) {
  90. switch(e.keyCode) {
  91. default:
  92. return;
  93. }
  94. CodeMirror.e_stop(e);
  95. });
  96. }
  97. iS.focus();
  98. }
  99. function doSearch(cm, rev) {
  100. var state = getSearchState(cm);
  101. if (state.query) return findNext(cm, rev);
  102. openDialog(cm, state);
  103. }
  104. function findNext(cm, rev) {cm.operation(function() {
  105. var state = getSearchState(cm);
  106. var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
  107. if (!cursor.find(rev)) {
  108. cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
  109. if (!cursor.find(rev)) return;
  110. }
  111. cm.setSelection(cursor.from(), cursor.to());
  112. state.posFrom = cursor.from(); state.posTo = cursor.to();
  113. });}
  114. function clearSearch(cm) {cm.operation(function() {
  115. var state = getSearchState(cm);
  116. if (!state.query) return;
  117. state.query = null;
  118. cm.removeOverlay(state.overlay);
  119. });}
  120. function replace(cm, all) {
  121. var state = getSearchState(cm);
  122. if (!state.query) return openDialog(cm, state, true);
  123. if(all) cm.operation(function() {
  124. for (var cursor = getSearchCursor(cm, state.query); cursor.findNext();) {
  125. cursor.replace(state.replace);
  126. }
  127. }); else {
  128. var s=cm.getCursor('start'),e=cm.getCursor('end');
  129. state.posTo=state.posFrom;findNext(cm);
  130. var s1=cm.getCursor('start'),e1=cm.getCursor('end');
  131. if(s.line==s1.line&&s.ch==s1.ch&&e.line==e1.line&&e.ch==e1.ch) {
  132. cm.replaceRange(state.replace,s1,e1);findNext(cm);
  133. }
  134. }
  135. }
  136. CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
  137. CodeMirror.commands.findNext = doSearch;
  138. CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
  139. CodeMirror.commands.clearSearch = clearSearch;
  140. CodeMirror.commands.replace = replace;
  141. CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
  142. })();