浏览代码

refactor: sfc-setup in vm-import/export

+ show ✔Import script data and ✔Import settings in notification
+ prettify json for settings in export
tophf 2 年之前
父节点
当前提交
263ad67493
共有 2 个文件被更改,包括 84 次插入101 次删除
  1. 32 48
      src/options/views/tab-settings/vm-export.vue
  2. 52 53
      src/options/views/tab-settings/vm-import.vue

+ 32 - 48
src/options/views/tab-settings/vm-export.vue

@@ -9,18 +9,18 @@
           <icon name="info"/>
           <icon name="info"/>
         </a>
         </a>
       </tooltip>
       </tooltip>
-      <span hidden v-text="getFileName()"/>
+      <span hidden v-text="fileName"/>
     </div>
     </div>
     <div class="mt-1">
     <div class="mt-1">
       <setting-check name="exportValues" :label="i18n('labelExportScriptData')" />
       <setting-check name="exportValues" :label="i18n('labelExportScriptData')" />
     </div>
     </div>
     <modal
     <modal
-      v-if="store.ffDownload"
+      v-if="ffDownload"
       transition="in-out"
       transition="in-out"
-      :visible="!!store.ffDownload.url"
-      @close="store.ffDownload = {}">
+      :visible="!!ffDownload.url"
+      @close="ffDownload = {}">
       <div class="modal-content">
       <div class="modal-content">
-        <a :download="store.ffDownload.name" :href="store.ffDownload.url">
+        <a :download="ffDownload.name" :href="ffDownload.url">
           Right click and save as<br />
           Right click and save as<br />
           <strong>scripts.zip</strong>
           <strong>scripts.zip</strong>
         </a>
         </a>
@@ -29,7 +29,8 @@
   </div>
   </div>
 </template>
 </template>
 
 
-<script>
+<script setup>
+import { computed, ref } from 'vue';
 import Modal from 'vueleton/lib/modal';
 import Modal from 'vueleton/lib/modal';
 import Tooltip from 'vueleton/lib/tooltip';
 import Tooltip from 'vueleton/lib/tooltip';
 import Icon from '@/common/ui/icon';
 import Icon from '@/common/ui/icon';
@@ -41,65 +42,48 @@ import SettingCheck from '@/common/ui/setting-check';
 import SettingText from '@/common/ui/setting-text';
 import SettingText from '@/common/ui/setting-text';
 import { downloadBlob } from '@/common/download';
 import { downloadBlob } from '@/common/download';
 import loadZip from '@/common/zip';
 import loadZip from '@/common/zip';
-import { store } from '../../utils';
 
 
-/**
- * Note:
- * - Firefox does not support multiline <select>
- */
-if (IS_FIREFOX) store.ffDownload = {};
 let ua;
 let ua;
 
 
-export default {
-  components: {
-    SettingCheck,
-    SettingText,
-    Icon,
-    Modal,
-    Tooltip,
-  },
-  data() {
-    return {
-      store,
-      dateTokens: Object.keys(DATE_FMT).join(', '),
-      exporting: false,
-    };
-  },
-  methods: {
-    async handleExport() {
-      try {
-        this.exporting = true;
-        if (IS_FIREFOX && !ua) ua = await sendCmdDirectly('UA');
-        download(await exportData(), this.getFileName());
-      } finally {
-        this.exporting = false;
-      }
-    },
-    getFileName() {
-      const { tpl } = this.$refs;
-      return tpl && `${formatDate(tpl.value?.trim() || tpl.defaultValue)}.zip`;
-    },
-  },
-};
+const tpl = ref();
+const dateTokens = ref(Object.keys(DATE_FMT).join(', '));
+const exporting = ref(false);
+const ffDownload = ref(IS_FIREFOX && {});
+const fileName = computed(() => {
+  const tplComp = tpl.value;
+  const text = tplComp?.text.trim();
+  return text && `${formatDate(text || tplComp.defaultValue)}.zip`;
+});
+
+async function handleExport() {
+  try {
+    exporting.value = true;
+    if (IS_FIREFOX && !ua) ua = await sendCmdDirectly('UA');
+    download(await exportData());
+  } finally {
+    exporting.value = false;
+  }
+}
 
 
-function download(blob, fileName) {
+function download(blob) {
   /* Old FF can't download blobs https://bugzil.la/1420419, fixed by enabling OOP:
   /* Old FF can't download blobs https://bugzil.la/1420419, fixed by enabling OOP:
    * v56 in Windows https://bugzil.la/1357486
    * v56 in Windows https://bugzil.la/1357486
    * v61 in MacOS https://bugzil.la/1385403
    * v61 in MacOS https://bugzil.la/1385403
    * v63 in Linux https://bugzil.la/1357487 */
    * v63 in Linux https://bugzil.la/1357487 */
   // TODO: remove when strict_min_version >= 63
   // TODO: remove when strict_min_version >= 63
   const FF = IS_FIREFOX && parseFloat(ua.version);
   const FF = IS_FIREFOX && parseFloat(ua.version);
+  const name = fileName.value;
   if (FF && (ua.os === 'win' ? FF < 56 : ua.os === 'mac' ? FF < 61 : FF < 63)) {
   if (FF && (ua.os === 'win' ? FF < 56 : ua.os === 'mac' ? FF < 61 : FF < 63)) {
     const reader = new FileReader();
     const reader = new FileReader();
     reader.onload = () => {
     reader.onload = () => {
-      store.ffDownload = {
-        name: fileName,
+      ffDownload.value = {
+        name,
         url: reader.result,
         url: reader.result,
       };
       };
     };
     };
     reader.readAsDataURL(blob);
     reader.readAsDataURL(blob);
   } else {
   } else {
-    downloadBlob(blob, fileName);
+    downloadBlob(blob, name);
   }
   }
 }
 }
 
 
@@ -148,7 +132,7 @@ async function exportData() {
   });
   });
   files.push({
   files.push({
     name: 'violentmonkey',
     name: 'violentmonkey',
-    content: JSON.stringify(vm),
+    content: JSON.stringify(vm, null, 2), // prettify to help users diff or view it
   });
   });
   const zip = await loadZip();
   const zip = await loadZip();
   const blobWriter = new zip.BlobWriter('application/zip');
   const blobWriter = new zip.BlobWriter('application/zip');

+ 52 - 53
src/options/views/tab-settings/vm-import.vue

@@ -6,9 +6,9 @@
       <button @click="vacuum" :disabled="vacuuming" v-text="labelVacuum" />
       <button @click="vacuum" :disabled="vacuuming" v-text="labelVacuum" />
     </tooltip>
     </tooltip>
     <div class="mt-1">
     <div class="mt-1">
-      <setting-check name="importScriptData" :label="i18n('labelImportScriptData')" />
+      <setting-check name="importScriptData" :label="labelImportScriptData" />
       <br>
       <br>
-      <setting-check name="importSettings" :label="i18n('labelImportSettings')" />
+      <setting-check name="importSettings" :label="labelImportSettings" />
     </div>
     </div>
     <table class="import-report">
     <table class="import-report">
       <tr v-for="({ type, name, text }, i) in reports" :key="i" :data-type="type">
       <tr v-for="({ type, name, text }, i) in reports" :key="i" :data-type="type">
@@ -19,10 +19,10 @@
   </div>
   </div>
 </template>
 </template>
 
 
-<script>
-import { reactive } from 'vue';
+<script setup>
+import { onMounted, reactive, ref } from 'vue';
 import Tooltip from 'vueleton/lib/tooltip';
 import Tooltip from 'vueleton/lib/tooltip';
-import { ensureArray, i18n, sendCmdDirectly } from '@/common';
+import { ensureArray, i18n, sendCmdDirectly, trueJoin } from '@/common';
 import { RUN_AT_RE } from '@/common/consts';
 import { RUN_AT_RE } from '@/common/consts';
 import options from '@/common/options';
 import options from '@/common/options';
 import SettingCheck from '@/common/ui/setting-check';
 import SettingCheck from '@/common/ui/setting-check';
@@ -31,46 +31,37 @@ import { showConfirmation, showMessage } from '@/common/ui';
 import { store } from '../../utils';
 import { store } from '../../utils';
 
 
 const reports = reactive([]);
 const reports = reactive([]);
+const buttonImport = ref();
+const vacuuming = ref(false);
+const labelImportScriptData = i18n('labelImportScriptData');
+const labelImportSettings = i18n('labelImportSettings');
+const labelVacuum = ref(i18n('buttonVacuum'));
 
 
-export default {
-  components: {
-    SettingCheck,
-    Tooltip,
-  },
-  data() {
-    return {
-      reports,
-      store,
-      vacuuming: false,
-      labelVacuum: this.i18n('buttonVacuum'),
-    };
-  },
-  methods: {
-    pickBackup() {
-      const input = document.createElement('input');
-      input.type = 'file';
-      input.accept = '.zip';
-      input.onchange = () => importBackup(input.files?.[0]);
-      input.click();
-    },
-    async vacuum() {
-      this.vacuuming = true;
-      this.labelVacuum = i18n('buttonVacuuming');
-      const { fixes, errors } = await sendCmdDirectly('Vacuum');
-      const errorText = errors?.join('\n');
-      this.vacuuming = false;
-      this.labelVacuum = i18n('buttonVacuumed') + (fixes ? ` (${fixes})` : '');
-      if (errorText) {
-        showConfirmation(i18n('msgErrorFetchingResource') + '\n\n' + errorText, { cancel: false });
-      }
-    },
-  },
-  mounted() {
-    const toggleDragDrop = initDragDrop(this.$refs.buttonImport);
-    addEventListener('hashchange', toggleDragDrop);
-    toggleDragDrop();
-  },
-};
+onMounted(() => {
+  const toggleDragDrop = initDragDrop(buttonImport.value);
+  addEventListener('hashchange', toggleDragDrop);
+  toggleDragDrop();
+});
+
+function pickBackup() {
+  const input = document.createElement('input');
+  input.type = 'file';
+  input.accept = '.zip';
+  input.onchange = () => importBackup(input.files?.[0]);
+  input.click();
+}
+
+async function vacuum() {
+  vacuuming.value = true;
+  labelVacuum.value = i18n('buttonVacuuming');
+  const { fixes, errors } = await sendCmdDirectly('Vacuum');
+  const errorText = errors?.join('\n');
+  vacuuming.value = false;
+  labelVacuum.value = i18n('buttonVacuumed') + (fixes ? ` (${fixes})` : '');
+  if (errorText) {
+    showConfirmation(i18n('msgErrorFetchingResource') + '\n\n' + errorText, { cancel: false });
+  }
+}
 
 
 async function importBackup(file) {
 async function importBackup(file) {
   if (!store.importing) {
   if (!store.importing) {
@@ -85,6 +76,8 @@ async function importBackup(file) {
 async function doImportBackup(file) {
 async function doImportBackup(file) {
   if (!file) return;
   if (!file) return;
   reports.length = 0;
   reports.length = 0;
+  const importScriptData = options.get('importScriptData');
+  const importSettings = options.get('importSettings');
   const zip = await loadZipLibrary();
   const zip = await loadZipLibrary();
   const reader = new zip.ZipReader(new zip.BlobReader(file));
   const reader = new zip.ZipReader(new zip.BlobReader(file));
   const entries = await reader.getEntries().catch(report) || [];
   const entries = await reader.getEntries().catch(report) || [];
@@ -98,16 +91,22 @@ async function doImportBackup(file) {
   if (!vm.values) vm.values = {};
   if (!vm.values) vm.values = {};
   await processAll(readScriptOptions, '.options.json');
   await processAll(readScriptOptions, '.options.json');
   await processAll(readScript, '.user.js');
   await processAll(readScript, '.user.js');
-  if (options.get('importScriptData')) {
+  if (importScriptData) {
     await processAll(readScriptStorage, '.storage.json');
     await processAll(readScriptStorage, '.storage.json');
     sendCmdDirectly('SetValueStores', vm.values);
     sendCmdDirectly('SetValueStores', vm.values);
   }
   }
-  if (options.get('importSettings')) {
+  if (importSettings) {
     sendCmdDirectly('SetOptions',
     sendCmdDirectly('SetOptions',
       toObjectArray(vm.settings, ([key, value]) => key !== 'sync' && { key, value }));
       toObjectArray(vm.settings, ([key, value]) => key !== 'sync' && { key, value }));
   }
   }
   sendCmdDirectly('CheckPosition');
   sendCmdDirectly('CheckPosition');
-  showMessage({ text: reportProgress() });
+  showMessage({
+    text: [
+      reportProgress(),
+      importScriptData ? '✔' + labelImportScriptData : '',
+      importSettings ? '✔' + labelImportSettings : '',
+    ]::trueJoin('\n'),
+  });
   await reader.close();
   await reader.close();
 
 
   function parseJson(text, entry) {
   function parseJson(text, entry) {
@@ -234,12 +233,12 @@ function initDragDrop(targetElement) {
     await importBackup(file);
     await importBackup(file);
   };
   };
   return () => {
   return () => {
-    const isSettingsTab = window.location.hash === '#settings';
-    const onOff = document[`${isSettingsTab ? 'add' : 'remove'}EventListener`];
-    document::onOff('dragend', onDragEnd);
-    document::onOff('dragleave', onDragLeave);
-    document::onOff('dragover', onDragOver);
-    document::onOff('drop', onDrop);
+    const isSettingsTab = store.route.hash === TAB_SETTINGS;
+    const onOff = isSettingsTab ? addEventListener : removeEventListener;
+    onOff('dragend', onDragEnd);
+    onOff('dragleave', onDragLeave);
+    onOff('dragover', onDragOver);
+    onOff('drop', onDrop);
   };
   };
 }
 }
 </script>
 </script>