소스 검색

feat: add sort/filter option for popup

tophf 6 년 전
부모
커밋
d18985f4d5
4개의 변경된 파일80개의 추가작업 그리고 16개의 파일을 삭제
  1. 9 0
      src/_locales/en/messages.yml
  2. 7 0
      src/common/options-defaults.js
  3. 27 0
      src/options/views/tab-settings/index.vue
  4. 37 16
      src/popup/views/app.vue

+ 9 - 0
src/_locales/en/messages.yml

@@ -331,6 +331,9 @@ labelNoSearchScripts:
 labelNotifyUpdates:
   description: Option to show notification when script is updated.
   message: Notify script updates
+labelPopupSort:
+  description: Label in the VM settings tab for script list sort order in popup
+  message: Sort scripts in popup by
 labelRelated:
   description: Label of related links.
   message: 'Related links: '
@@ -542,6 +545,12 @@ msgUpdating:
 noValues:
   description: Label shown when there is no value for current script.
   message: No value is stored
+optionPopupEnabledFirst:
+  description: Option to show enabled scripts first in popup.
+  message: Enabled first
+optionPopupHideDisabled:
+  description: Option to hide disabled scripts in popup.
+  message: Hide disabled
 optionShowEnabledFirst:
   description: Option to show enabled scripts first in alphabetical order.
   message: Show enabled scripts first

+ 7 - 0
src/common/options-defaults.js

@@ -20,8 +20,15 @@ export default {
   version: null,
   defaultInjectInto: 'page', // 'page' | 'auto',
   filters: {
+    /** @type 'exec' | 'alpha' | 'update' */
     sort: 'exec',
   },
+  filtersPopup: {
+    /** @type 'exec' | 'alpha' */
+    sort: 'exec',
+    enabledFirst: false,
+    hideDisabled: false,
+  },
   editor: {
     lineWrapping: false,
     indentWithTabs: false,

+ 27 - 0
src/options/views/tab-settings/index.vue

@@ -41,6 +41,21 @@
         </label>
         <a class="ml-1" href="https://violentmonkey.github.io/2018/11/23/inject-into-context/" target="_blank" rel="noopener noreferrer" v-text="i18n('learnInjectionMode')"></a>
       </div>
+      <div class="mb-1 multi-opt-row">
+        <label>
+          <span v-text="i18n('labelPopupSort')"></span>
+          <select v-model="popupSort">
+            <option value="exec" v-text="i18n('filterExecutionOrder')" />
+            <option value="alpha" v-text="i18n('filterAlphabeticalOrder')" />
+          </select>
+        </label>
+        <label>
+          <setting-check name="filtersPopup.enabledFirst" />{{i18n('optionPopupEnabledFirst')}}
+        </label>
+        <label>
+          <setting-check name="filtersPopup.hideDisabled" />{{i18n('optionPopupHideDisabled')}}
+        </label>
+      </div>
     </section>
     <vm-import></vm-import>
     <vm-export></vm-export>
@@ -88,6 +103,11 @@ const items = [
       return value === 'auto' ? 'auto' : 'page';
     },
   },
+  {
+    key: 'filtersPopup.sort',
+    name: 'popupSort',
+    normalize: value => value === 'exec' && value || 'alpha',
+  },
 ];
 const settings = {
   showAdvanced: false,
@@ -140,6 +160,13 @@ export default {
 <style>
 .tab-settings {
   overflow-y: auto;
+  .multi-opt-row {
+    display: flex;
+    align-items: center;
+    label {
+      margin-right: 1em;
+    }
+  }
   textarea {
     height: 10em;
   }

+ 37 - 16
src/popup/views/app.vue

@@ -112,11 +112,18 @@ import { store } from '../utils';
 
 const optionsData = {
   isApplied: options.get('isApplied'),
+  filtersPopup: options.get('filtersPopup') || {},
 };
 options.hook((changes) => {
   if ('isApplied' in changes) {
     optionsData.isApplied = changes.isApplied;
   }
+  if ('filtersPopup' in changes) {
+    optionsData.filtersPopup = {
+      ...optionsData.filtersPopup,
+      ...changes.filtersPopup,
+    };
+  }
 });
 
 export default {
@@ -134,25 +141,39 @@ export default {
   },
   computed: {
     injectionScopes() {
-      // returns "numEnabled / numTotal" or just "numTotal" if all are enabled
-      const getTotals = list => {
-        const numEnabled = list.reduce((num, script) => num + !!script.config.enabled, 0);
-        const numTotal = list.length;
-        return numEnabled < numTotal
-          ? `${numEnabled} / ${numTotal}`
-          : `${numTotal}`;
-      };
+      const { sort, enabledFirst, hideDisabled } = this.options.filtersPopup;
+      const isSorted = sort === 'alpha' || enabledFirst;
       return [
         ['scripts', i18n('menuMatchedScripts')],
         ['frameScripts', i18n('menuMatchedFrameScripts')],
-      ].map(([name, title]) => this.store[name].length && {
-        name,
-        title,
-        list: this.store[name].map(script => ({
-          name: script.custom.name || getLocaleString(script.meta, 'name'),
-          data: script,
-        })),
-        totals: getTotals(this.store[name]),
+      ].map(([name, title]) => {
+        let list = this.store[name];
+        const numTotal = list.length;
+        const numEnabled = list.reduce((num, script) => num + script.config.enabled, 0);
+        if (hideDisabled) list = list.filter(script => script.config.enabled);
+        list = list.map((script, i) => {
+          const scriptName = script.custom.name || getLocaleString(script.meta, 'name');
+          return {
+            name: scriptName,
+            data: script,
+            key: isSorted && `${
+              enabledFirst && +!script.config.enabled
+            }${
+              sort === 'alpha' ? scriptName.toLowerCase() : `${1e6 + i}`.slice(1)
+            }`,
+          };
+        });
+        if (isSorted) {
+          list.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key));
+        }
+        return numTotal && {
+          name,
+          title,
+          list,
+          totals: numEnabled < numTotal
+            ? `${numEnabled} / ${numTotal}`
+            : `${numTotal}`,
+        };
       }).filter(Boolean);
     },
     failureReason() {