Browse Source

fix: extract search and replace to vm-code

Gerald 8 years ago
parent
commit
46311c2b0d

+ 154 - 7
src/common/ui/code.vue

@@ -1,7 +1,38 @@
 <template>
-  <vue-code class="editor-code"
-    :options="cmOptions" v-model="content" @ready="onReady"
-  />
+  <div class="flex flex-col">
+    <vue-code class="editor-code flex-auto"
+      :options="cmOptions" v-model="content" @ready="onReady"
+    />
+    <div class="frame-block" v-show="search.show">
+      <button class="pull-right" @click="clearSearch">&times;</button>
+      <form class="inline-block mr-1" @submit.prevent="goToLine()">
+        <span v-text="i18n('labelLineNumber')"></span>
+        <input class="w-1" v-model="search.line">
+      </form>
+      <form class="inline-block mr-1" @submit.prevent="findNext()">
+        <span v-text="i18n('labelSearch')"></span>
+        <tooltip title="Ctrl-F">
+          <input ref="search" v-model="search.state.query">
+        </tooltip>
+        <tooltip title="Shift-Ctrl-G">
+          <button type="button" @click="findNext(1)">&lt;</button>
+        </tooltip>
+        <tooltip title="Ctrl-G">
+          <button type="submit">&gt;</button>
+        </tooltip>
+      </form>
+      <form class="inline-block mr-1" @submit.prevent="replace()" v-if="!readonly">
+        <span v-text="i18n('labelReplace')"></span>
+        <input v-model="search.state.replace">
+        <tooltip title="Shift-Ctrl-F">
+          <button type="submit" v-text="i18n('buttonReplace')"></button>
+        </tooltip>
+        <tooltip title="Shift-Ctrl-R">
+          <button type="button" v-text="i18n('buttonReplaceAll')" @click="replace(1)"></button>
+        </tooltip>
+      </form>
+    </div>
+  </div>
 </template>
 
 <script>
@@ -20,6 +51,7 @@ import 'codemirror/addon/search/match-highlighter';
 import 'codemirror/addon/search/searchcursor';
 import 'codemirror/addon/selection/active-line';
 import CodeMirror from 'codemirror';
+import { debounce } from 'src/common';
 
 function getHandler(key) {
   return (cm) => {
@@ -39,7 +71,7 @@ function indentWithTab(cm) {
 }
 
 [
-  'save', 'cancel', 'find', 'findNext', 'findPrev', 'replace', 'replaceAll',
+  'save', 'cancel', 'find', 'findNext', 'findPrev', 'replace', 'replaceAll', 'close',
 ].forEach((key) => {
   CodeMirror.commands[key] = getHandler(key);
 });
@@ -58,6 +90,44 @@ const cmOptions = {
   theme: 'eclipse',
 };
 
+function findNext(cm, state, reversed) {
+  cm.operation(() => {
+    const query = state.query || '';
+    let cursor = cm.getSearchCursor(query, reversed ? state.posFrom : state.posTo);
+    if (!cursor.find(reversed)) {
+      cursor = cm.getSearchCursor(query,
+        reversed ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
+      if (!cursor.find(reversed)) return;
+    }
+    cm.setSelection(cursor.from(), cursor.to());
+    state.posFrom = cursor.from();
+    state.posTo = cursor.to();
+  });
+}
+function replaceOne(cm, state) {
+  const start = cm.getCursor('start');
+  const end = cm.getCursor('end');
+  state.posTo = state.posFrom;
+  findNext(cm, state);
+  const start2 = cm.getCursor('start');
+  const end2 = cm.getCursor('end');
+  if (
+    start.line === start2.line && start.ch === start2.ch
+    && end.line === end2.line && end.ch === end2.ch
+  ) {
+    cm.replaceRange(state.replace, start, end);
+    findNext(cm, state);
+  }
+}
+function replaceAll(cm, state) {
+  cm.operation(() => {
+    const query = state.query || '';
+    for (let cursor = cm.getSearchCursor(query); cursor.findNext();) {
+      cursor.replace(state.replace);
+    }
+  });
+}
+
 export default {
   props: {
     readonly: {
@@ -76,8 +146,15 @@ export default {
   },
   data() {
     return {
-      content: this.value,
       cmOptions,
+      content: this.value,
+      search: {
+        show: false,
+        state: {
+          query: null,
+          replace: null,
+        },
+      },
     };
   },
   watch: {
@@ -92,12 +169,32 @@ export default {
       cm.getDoc().clearHistory();
       cm.focus();
     },
+    'search.state.query'() {
+      this.debouncedFind();
+    },
   },
   methods: {
     onReady(cm) {
       this.cm = cm;
       if (this.readonly) cm.setOption('readOnly', true);
-      cm.state.commands = this.commands;
+      cm.state.commands = Object.assign({
+        cancel: () => {
+          if (this.search.show) {
+            this.clearSearch();
+          } else {
+            cm.execCommand('close');
+          }
+        },
+        find: this.find,
+        findNext: this.findNext,
+        findPrev: () => {
+          this.findNext(1);
+        },
+        replace: this.replace,
+        replaceAll: () => {
+          this.replace(1);
+        },
+      }, this.commands);
       cm.setOption('extraKeys', {
         Esc: 'cancel',
         Tab: indentWithTab,
@@ -117,7 +214,7 @@ export default {
         let stop = false;
         if (keyMap) {
           CodeMirror.lookupKey(name, keyMap, (b) => {
-            if (this.commands[b]) {
+            if (cm.state.commands[b]) {
               e.preventDefault();
               e.stopPropagation();
               cm.execCommand(b);
@@ -128,8 +225,58 @@ export default {
         return stop;
       });
     },
+    doFind(reversed) {
+      const { state } = this.search;
+      const { cm } = this;
+      if (state.query) {
+        findNext(cm, state, reversed);
+      }
+      this.search.show = true;
+    },
+    find() {
+      const { state } = this.search;
+      state.posTo = state.posFrom;
+      this.doFind();
+      this.$nextTick(() => {
+        const { search } = this.$refs;
+        search.select();
+        search.focus();
+      });
+    },
+    findNext(reversed) {
+      this.doFind(reversed);
+      this.$nextTick(() => {
+        this.$refs.search.focus();
+      });
+    },
+    clearSearch() {
+      const { cm } = this;
+      cm.operation(() => {
+        const { state } = this.search;
+        state.posFrom = null;
+        state.posTo = null;
+        this.search.show = false;
+      });
+      cm.focus();
+    },
+    replace(all) {
+      const { cm } = this;
+      const { state } = this.search;
+      if (!state.query) {
+        this.find();
+        return;
+      }
+      (all ? replaceAll : replaceOne)(cm, state);
+    },
+    goToLine() {
+      const line = this.search.line - 1;
+      const { cm } = this;
+      if (!isNaN(line)) cm.setCursor(line, 0);
+      cm.focus();
+    },
   },
   mounted() {
+    this.debouncedFind = debounce(this.doFind, 100);
     if (this.global) window.addEventListener('keydown', this.onKeyDown, false);
   },
   beforeDestroy() {

+ 1 - 1
src/confirm/views/app.vue

@@ -53,7 +53,7 @@ export default {
       message: '',
       code: '',
       commands: {
-        cancel: this.close,
+        close: this.close,
       },
       info: {},
     };

+ 2 - 143
src/options/views/edit/index.vue

@@ -22,35 +22,6 @@
         :value="value" :settings="settings"
       />
     </div>
-    <div class="frame-block" v-show="search.show">
-      <button class="pull-right" @click="clearSearch">&times;</button>
-      <form class="inline-block mr-1" @submit.prevent="goToLine()">
-        <span v-text="i18n('labelLineNumber')"></span>
-        <input class="w-1" v-model="search.line">
-      </form>
-      <form class="inline-block mr-1" @submit.prevent="findNext()">
-        <span v-text="i18n('labelSearch')"></span>
-        <tooltip title="Ctrl-F">
-          <input ref="search" v-model="search.state.query">
-        </tooltip>
-        <tooltip title="Shift-Ctrl-G">
-          <button type="button" @click="findNext(1)">&lt;</button>
-        </tooltip>
-        <tooltip title="Ctrl-G">
-          <button type="submit">&gt;</button>
-        </tooltip>
-      </form>
-      <form class="inline-block mr-1" @submit.prevent="replace()">
-        <span v-text="i18n('labelReplace')"></span>
-        <input v-model="search.state.replace">
-        <tooltip title="Shift-Ctrl-F">
-          <button type="submit" v-text="i18n('buttonReplace')"></button>
-        </tooltip>
-        <tooltip title="Shift-Ctrl-R">
-          <button type="button" v-text="i18n('buttonReplaceAll')" @click="replace(1)"></button>
-        </tooltip>
-      </form>
-    </div>
     <div class="frame-block">
       <div class="pull-right">
         <button v-text="i18n('buttonSave')" @click="save" :disabled="!canSave"></button>
@@ -63,7 +34,7 @@
 
 <script>
 import CodeMirror from 'codemirror';
-import { i18n, debounce, sendMessage, noop } from 'src/common';
+import { i18n, sendMessage, noop } from 'src/common';
 import VmCode from 'src/common/ui/code';
 import { showMessage } from '../../utils';
 import VmSettings from './settings';
@@ -77,43 +48,6 @@ function toList(text) {
   .map(line => line.trim())
   .filter(Boolean);
 }
-function findNext(cm, state, reversed) {
-  cm.operation(() => {
-    const query = state.query || '';
-    let cursor = cm.getSearchCursor(query, reversed ? state.posFrom : state.posTo);
-    if (!cursor.find(reversed)) {
-      cursor = cm.getSearchCursor(query,
-        reversed ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
-      if (!cursor.find(reversed)) return;
-    }
-    cm.setSelection(cursor.from(), cursor.to());
-    state.posFrom = cursor.from();
-    state.posTo = cursor.to();
-  });
-}
-function replaceOne(cm, state) {
-  const start = cm.getCursor('start');
-  const end = cm.getCursor('end');
-  state.posTo = state.posFrom;
-  findNext(cm, state);
-  const start2 = cm.getCursor('start');
-  const end2 = cm.getCursor('end');
-  if (
-    start.line === start2.line && start.ch === start2.ch
-    && end.line === end2.line && end.ch === end2.ch
-  ) {
-    cm.replaceRange(state.replace, start, end);
-    findNext(cm, state);
-  }
-}
-function replaceAll(cm, state) {
-  cm.operation(() => {
-    const query = state.query || '';
-    for (let cursor = cm.getSearchCursor(query); cursor.findNext();) {
-      cursor.replace(state.replace);
-    }
-  });
-}
 
 export default {
   props: ['value'],
@@ -123,37 +57,14 @@ export default {
     Tooltip,
   },
   data() {
-    this.debouncedFind = debounce(this.doFind, 100);
     return {
       nav: 'code',
       canSave: false,
       code: '',
       settings: {},
-      search: {
-        show: false,
-        state: {
-          query: null,
-          replace: null,
-        },
-      },
       commands: {
         save: this.save,
-        cancel: () => {
-          if (this.search.show) {
-            this.clearSearch();
-          } else {
-            this.close();
-          }
-        },
-        find: this.find,
-        findNext: this.findNext,
-        findPrev: () => {
-          this.findNext(1);
-        },
-        replace: this.replace,
-        replaceAll: () => {
-          this.replace(1);
-        },
+        close: this.close,
       },
     };
   },
@@ -167,9 +78,6 @@ export default {
         this.canSave = true;
       },
     },
-    'search.state.query'() {
-      this.debouncedFind();
-    },
   },
   mounted() {
     (this.value.id ? sendMessage({
@@ -278,55 +186,6 @@ export default {
     initEditor(cm) {
       this.cm = cm;
     },
-    doFind(reversed) {
-      const { state } = this.search;
-      const { cm } = this;
-      if (state.query) {
-        findNext(cm, state, reversed);
-      }
-      this.search.show = true;
-    },
-    find() {
-      const { state } = this.search;
-      state.posTo = state.posFrom;
-      this.doFind();
-      this.$nextTick(() => {
-        const { search } = this.$refs;
-        search.select();
-        search.focus();
-      });
-    },
-    findNext(reversed) {
-      this.doFind(reversed);
-      this.$nextTick(() => {
-        this.$refs.search.focus();
-      });
-    },
-    clearSearch() {
-      const { cm } = this;
-      cm.operation(() => {
-        const { state } = this.search;
-        state.posFrom = null;
-        state.posTo = null;
-        this.search.show = false;
-      });
-      cm.focus();
-    },
-    replace(all) {
-      const { cm } = this;
-      const { state } = this.search;
-      if (!state.query) {
-        this.find();
-        return;
-      }
-      (all ? replaceAll : replaceOne)(cm, state);
-    },
-    goToLine() {
-      const line = this.search.line - 1;
-      const { cm } = this;
-      if (!isNaN(line)) cm.setCursor(line, 0);
-      cm.focus();
-    },
   },
 };
 </script>

+ 2 - 2
src/options/views/edit/settings.vue

@@ -99,8 +99,8 @@ export default {
     custom() {
       return this.settings.custom || {};
     },
-    more() {
-      return this.settings.more || {};
+    config() {
+      return this.settings.config || {};
     },
     placeholders() {
       const { value } = this;