Просмотр исходного кода

fix: update view on setting change

Gerald 8 лет назад
Родитель
Сommit
8e52d43d6e

+ 2 - 1
src/options/utils/index.js

@@ -1,9 +1,10 @@
 import Vue from 'vue';
 import './dropdown';
-import './settings';
 import resetFeatures from './features';
 import Message from '../views/message';
 
+export hookSetting from './settings';
+
 export const store = {
   messages: null,
 };

+ 15 - 29
src/options/utils/settings.js

@@ -1,37 +1,23 @@
-import Vue from 'vue';
 import options from 'src/common/options';
 
 const hooks = {};
-options.hook((data) => {
-  Object.keys(data).forEach((key) => {
+
+options.hook(data => {
+  Object.keys(data).forEach(key => {
     const list = hooks[key];
-    if (list) list.forEach((el) => { el.checked = data[key]; });
+    if (list) list.forEach(update => { update(data[key]); });
   });
 });
 
-function onSettingChange(e) {
-  const { target } = e;
-  options.set(target.dataset.setting, target.checked);
-}
-
-Vue.directive('setting', {
-  bind(el, binding) {
-    const { value } = binding;
-    el.dataset.setting = value;
-    el.addEventListener('change', onSettingChange, false);
-    let list = hooks[value];
-    if (!list) {
-      list = [];
-      hooks[value] = list;
-    }
-    list.push(el);
-    el.checked = options.get(value);
-  },
-  unbind(el, binding) {
-    const { value } = binding;
-    el.removeEventListener('change', onSettingChange, false);
-    const list = hooks[value] || [];
-    const i = list.indexOf(el);
+export default function hook(key, item) {
+  let list = hooks[key];
+  if (!list) {
+    list = [];
+    hooks[key] = list;
+  }
+  list.push(item);
+  return () => {
+    const i = list.indexOf(item);
     if (i >= 0) list.splice(i, 1);
-  },
-});
+  };
+}

+ 9 - 16
src/options/views/confirm.vue

@@ -6,11 +6,11 @@
           <button dropdown-toggle v-text="i18n('buttonInstallOptions')"></button>
           <div class="dropdown-menu options-panel" @mousedown.stop>
             <label>
-              <input type=checkbox v-setting="'closeAfterInstall'" @change="checkClose">
+              <setting-check name="closeAfterInstall" @change="checkClose" ref="closeAfterInstall" />
               <span v-text="i18n('installOptionClose')"></span>
             </label>
             <label>
-              <input type=checkbox v-setting="'trackLocalFile'" :disabled="settings.closeAfterInstall">
+              <setting-check name="trackLocalFile" :disabled="closeAfterInstall" />
               <span v-text="i18n('installOptionTrack')"></span>
             </label>
           </div>
@@ -35,29 +35,21 @@ import options from 'src/common/options';
 import initCache from 'src/common/cache';
 import VmCode from './code';
 import { store } from '../utils';
+import SettingCheck from './setting-check';
 
 const cache = initCache({});
 
-const settings = {
-  closeAfterInstall: options.get('closeAfterInstall'),
-};
-
-options.hook(changes => {
-  if ('closeAfterInstall' in changes) {
-    settings.closeAfterInstall = changes.closeAfterInstall;
-  }
-});
-
 export default {
   components: {
     VmCode,
+    SettingCheck,
   },
   data() {
     return {
       store,
-      settings,
       installable: false,
       dependencyOK: false,
+      closeAfterInstall: options.get('closeAfterInstall'),
       message: '',
       code: '',
       commands: {
@@ -214,7 +206,7 @@ export default {
       })
       .then(res => {
         this.message = `${res.message}[${this.getTimeString()}]`;
-        if (this.settings.closeAfterInstall) this.close();
+        if (this.closeAfterInstall) this.close();
         else if (this.isLocal && options.get('trackLocalFile')) this.trackLocalFile();
       });
     },
@@ -231,8 +223,9 @@ export default {
         this.trackLocalFile();
       });
     },
-    checkClose(e) {
-      if (e.target.checked) options.set('trackLocalFile', false);
+    checkClose(value) {
+      this.closeAfterInstall = value;
+      if (value) options.set('trackLocalFile', false);
     },
   },
 };

+ 41 - 0
src/options/views/setting-check.vue

@@ -0,0 +1,41 @@
+<template>
+  <input type="checkbox" v-model="value" @change="onChange" :disabled="disabled">
+</template>
+
+<script>
+import options from 'src/common/options';
+import { hookSetting } from 'src/options/utils';
+
+export default {
+  props: {
+    name: String,
+    disabled: Boolean,
+    sync: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  data() {
+    return {
+      value: null,
+    };
+  },
+  created() {
+    this.value = options.get(this.name);
+    this.revoke = hookSetting(this.name, value => {
+      this.value = value;
+    });
+  },
+  beforeDestroy() {
+    this.revoke();
+  },
+  methods: {
+    onChange() {
+      if (this.sync) {
+        options.set(this.name, this.value);
+      }
+      this.$emit('change', this.value);
+    },
+  },
+};
+</script>

+ 43 - 0
src/options/views/setting-text.vue

@@ -0,0 +1,43 @@
+<template>
+  <textarea v-model="value" @change="onChange" :disabled="disabled" />
+</template>
+
+<script>
+import options from 'src/common/options';
+import { hookSetting } from 'src/options/utils';
+
+export default {
+  props: {
+    name: String,
+    disabled: Boolean,
+    sync: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  data() {
+    return {
+      value: null,
+    };
+  },
+  created() {
+    // XXX compatible with old data format
+    const handle = value => (Array.isArray(value) ? value.join('\n') : (value || ''));
+    this.value = handle(options.get(this.name));
+    this.revoke = hookSetting(this.name, value => {
+      this.value = handle(value);
+    });
+  },
+  beforeDestroy() {
+    this.revoke();
+  },
+  methods: {
+    onChange() {
+      if (this.sync) {
+        options.set(this.name, this.value);
+      }
+      this.$emit('change', this.value);
+    },
+  },
+};
+</script>

+ 7 - 5
src/options/views/tab-settings/index.vue

@@ -5,33 +5,33 @@
       <h3 v-text="i18n('labelGeneral')"></h3>
       <div class="mb-1">
         <label>
-          <input type=checkbox v-setting="'autoUpdate'" @change="updateAutoUpdate">
+          <setting-check name="autoUpdate" @change="updateAutoUpdate" />
           <span v-text="i18n('labelAutoUpdate')"></span>
         </label>
       </div>
       <div class="mb-1">
         <label>
-          <input type=checkbox v-setting="'showBadge'">
+          <setting-check name="showBadge" />
           <span v-text="i18n('labelShowBadge')"></span>
         </label>
       </div>
       <!--
       <div class="mb-1">
         <label>
-          <input type=checkbox v-setting="'ignoreGrant'">
+          <setting-check name="ignoreGrant" />
           <span v-text="i18n('labelIgnoreGrant')"></span>
         </label>
       </div>
       -->
       <div class="mb-1">
         <label>
-          <input type=checkbox v-setting="'autoReload'">
+          <setting-check name="autoReload" />
           <span v-text="i18n('labelAutoReloadCurrentTab')"></span>
         </label>
       </div>
       <div class="mb-1">
         <label>
-          <input type=checkbox v-setting="'notifyUpdates'">
+          <setting-check name="notifyUpdates" />
           <span v-text="i18n('labelNotifyUpdates')"></span>
         </label>
       </div>
@@ -51,6 +51,7 @@ import VmExport from './vm-export';
 import VmSync from './vm-sync';
 import VmBlacklist from './vm-blacklist';
 import VmCss from './vm-css';
+import SettingCheck from '../setting-check';
 
 export default {
   components: {
@@ -59,6 +60,7 @@ export default {
     VmSync,
     VmBlacklist,
     VmCss,
+    SettingCheck,
   },
   methods: {
     updateAutoUpdate() {

+ 6 - 10
src/options/views/tab-settings/vm-blacklist.vue

@@ -7,7 +7,7 @@
       {{i18n('descBlacklist')}}
       <a href="https://violentmonkey.github.io/2017/04/15/Smart-rules-for-blacklist/#Blacklist-patterns" target="_blank" v-text="i18n('learnBlacklist')"></a>
     </p>
-    <textarea v-model="rules"></textarea>
+    <setting-text name="blacklist" ref="blacklist" />
     <button v-text="i18n('buttonSaveBlacklist')" @click="onSave"></button>
   </section>
 </template>
@@ -15,20 +15,16 @@
 <script>
 import { i18n, sendMessage } from 'src/common';
 import options from 'src/common/options';
-import { showMessage } from '../../utils';
+import { showMessage } from 'src/options/utils';
+import SettingText from '../setting-text';
 
 export default {
-  data() {
-    let rules = options.get('blacklist');
-    // XXX compatible
-    if (Array.isArray(rules)) rules = rules.join('\n');
-    return {
-      rules,
-    };
+  components: {
+    SettingText,
   },
   methods: {
     onSave() {
-      options.set('blacklist', this.rules);
+      options.set('blacklist', this.$refs.blacklist.value);
       showMessage({ text: i18n('msgSavedBlacklist') });
       sendMessage({ cmd: 'BlacklistReset' });
     },

+ 6 - 7
src/options/views/tab-settings/vm-css.vue

@@ -4,7 +4,7 @@
       <span class="feature-text" v-text="i18n('labelCustomCSS')"></span>
     </h3>
     <p v-html="i18n('descCustomCSS')"></p>
-    <textarea v-model="css"></textarea>
+    <setting-text name="customCSS" ref="css" />
     <button v-text="i18n('buttonSaveCustomCSS')" @click="onSave"></button>
   </section>
 </template>
@@ -12,17 +12,16 @@
 <script>
 import { i18n } from 'src/common';
 import options from 'src/common/options';
-import { showMessage } from '../../utils';
+import { showMessage } from 'src/options/utils';
+import SettingText from '../setting-text';
 
 export default {
-  data() {
-    return {
-      css: options.get('customCSS'),
-    };
+  components: {
+    SettingText,
   },
   methods: {
     onSave() {
-      options.set('customCSS', (this.css || '').trim());
+      options.set('customCSS', this.$refs.css.value);
       showMessage({ text: i18n('msgSavedCustomCSS') });
     },
   },

+ 5 - 1
src/options/views/tab-settings/vm-export.vue

@@ -11,7 +11,7 @@
     <button v-text="i18n('buttonAllNone')" @click="toggleSelection()"></button>
     <button v-text="i18n('buttonExportData')" @click="exportData" :disabled="exporting"></button>
     <label>
-      <input type=checkbox v-setting="'exportValues'">
+      <setting-check name="exportValues" />
       <span v-text="i18n('labelExportScriptData')"></span>
     </label>
   </section>
@@ -21,6 +21,7 @@
 import { sendMessage } from 'src/common';
 import options from 'src/common/options';
 import { store } from '../../utils';
+import SettingCheck from '../setting-check';
 
 /**
  * Note:
@@ -28,6 +29,9 @@ import { store } from '../../utils';
  */
 
 export default {
+  components: {
+    SettingCheck,
+  },
   data() {
     return {
       store,

+ 5 - 1
src/options/views/tab-settings/vm-import.vue

@@ -5,7 +5,7 @@
     <button :title="i18n('hintVacuum')" @click="vacuum" :disabled="vacuuming" v-text="labelVacuum"></button>
     <div class="mt-1">
       <label>
-        <input type="checkbox" v-setting="'importSettings'">
+        <setting-check name="importSettings" />
         <span v-text="i18n('labelImportSettings')"></span>
       </label>
     </div>
@@ -16,8 +16,12 @@
 import { i18n, sendMessage } from 'src/common';
 import options from 'src/common/options';
 import { showMessage } from '../../utils';
+import SettingCheck from '../setting-check';
 
 export default {
+  components: {
+    SettingCheck,
+  },
   data() {
     return {
       vacuuming: false,

+ 5 - 1
src/options/views/tab-settings/vm-sync.vue

@@ -17,7 +17,7 @@
     <p class="mt-1" v-text="message"></p>
     <div class="mt-1">
       <label>
-        <input type="checkbox" v-setting="'syncScriptStatus'">
+        <setting-check name="syncScriptStatus" />
         <span v-text="i18n('labelSyncScriptStatus')"></span>
       </label>
     </div>
@@ -28,6 +28,7 @@
 import { sendMessage } from 'src/common';
 import options from 'src/common/options';
 import { store } from '../../utils';
+import SettingCheck from '../setting-check';
 
 const SYNC_CURRENT = 'sync.current';
 const syncConfig = {
@@ -40,6 +41,9 @@ options.hook((data) => {
 });
 
 export default {
+  components: {
+    SettingCheck,
+  },
   data() {
     return {
       syncConfig,