diff --git a/src/renderer/App.vue b/src/renderer/App.vue index 58a863b..a7b6277 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -126,6 +126,7 @@ import { searchKeyValues, fileLists, } from "./assets/common/utils"; +import { commonConst } from "../main/common/utils"; const opConfig = remote.getGlobal("opConfig"); const { Menu, MenuItem } = remote; @@ -217,7 +218,7 @@ export default { ...mapMutations("main", ["commonUpdate"]), shouldPaste(e) { let filePath = ""; - if (process.platform === "win32") { + if (commonConst.windows()) { const rawFilePath = clipboard.read("FileNameW"); filePath = rawFilePath.replace( new RegExp(String.fromCharCode(0), "g"), @@ -226,11 +227,46 @@ export default { if (filePath.indexOf("plugin.json") >= 0) { this.search({ filePath, + disableDebounce: true, }); } + } else if (commonConst.linux()) { + const text = clipboard.readText("selection"); + // 在gnome的文件管理器中,复制文件的结果通常是 + // + // x-special/nautilus-clipboard + // copy + // file:///home/admin/dir/plugin.json + const splitLF = text.split(" "); + let pathUrl; + if ( + splitLF.length == 3 && + splitLF[0] === "x-special/nautilus-clipboard" && + splitLF[1] === "copy" && + (pathUrl = splitLF[2]).startsWith("file://") && + pathUrl.indexOf("plugin.json") >= 0 + ) { + filePath = pathUrl.slice(7); + this.search({ + filePath, + disableDebounce: true, + }); + } + // 其他的发行版、文件管理器尚未测试 } }, + /** + * @param {Object} v 搜索配置对象。 + * 若v.disableDebounce为true,则不会触发防抖动保护。 + * 该值的作用是让search()方法被多个监听器同时调用时,在某些情况下无视其他监听器的防抖动保护。 + * 其他属性 v.value、v.filePath 参见 src/renderer/store/modules/main.js的onSearch函数。 + */ search(v) { + console.log("search was called , param v is :", v); + if (!v.disableDebounce) { + this.onSearch(v); + return; + } if (!this.searchFn) { this.searchFn = debounce(this.onSearch, 200); } @@ -297,9 +333,13 @@ export default { ipcRenderer.send("changeWindowSize-rubick", { height: getWindowHeight([]), }); - this.$router.push({ - path: "/home", - }); + if (this.$router.history.current.fullPath !== "/home") { + // 该if是为了避免跳转到相同路由而报错。 + // (之前在输入栏为空时按退格会疯狂报错) + this.$router.push({ + path: "/home", + }); + } }, newWindow() { ipcRenderer.send("new-window", { diff --git a/src/renderer/pages/search/subpages/market.vue b/src/renderer/pages/search/subpages/market.vue index 7557702..17738dd 100644 --- a/src/renderer/pages/search/subpages/market.vue +++ b/src/renderer/pages/search/subpages/market.vue @@ -2,14 +2,19 @@
-
+
@@ -18,38 +23,49 @@

插件

- + - - + + -
{{ item.pluginName }}
- +
- +
-

{{currentSelect.pluginName}}

+

{{ currentSelect.pluginName }}

- 开发者:{{currentSelect.author}} + 开发者:{{ currentSelect.author }}
-
{{currentSelect.description}}
+
{{ currentSelect.description }}
@@ -70,10 +86,10 @@ diff --git a/src/renderer/store/modules/main.js b/src/renderer/store/modules/main.js index 7e78338..fa101a9 100644 --- a/src/renderer/store/modules/main.js +++ b/src/renderer/store/modules/main.js @@ -1,5 +1,5 @@ -import { clipboard, ipcRenderer, remote } from 'electron'; -import { v4 as uuidv4 } from 'uuid'; +import { clipboard, ipcRenderer, remote } from "electron"; +import { v4 as uuidv4 } from "uuid"; import { getWindowHeight, searchKeyValues, @@ -7,34 +7,34 @@ import { mergePlugins, find, downloadZip, - fileLists -} from '../../assets/common/utils'; -import systemMethod from '../../assets/common/system'; -import fs from 'fs'; -import path from 'path'; -import { execSync } from 'child_process'; + fileLists, +} from "../../assets/common/utils"; +import systemMethod from "../../assets/common/system"; +import fs from "fs"; +import path from "path"; +import { execSync } from "child_process"; const state = { selected: null, options: [], showMain: false, - current: ['market'], - searchValue: '', + current: ["market"], + searchValue: "", devPlugins: mergePlugins(sysFile.getUserPlugins() || []), - subPlaceHolder: '', + subPlaceHolder: "", pluginLoading: true, pluginInfo: (() => { try { return window.pluginInfo || {}; } catch (e) {} - })() + })(), }; const mutations = { commonUpdate(state, payload) { Object.keys(payload).forEach((key) => { state[key] = payload[key]; - if (key === 'devPlugins') { + if (key === "devPlugins") { sysFile.savePlugins(payload[key]); } }); @@ -43,11 +43,15 @@ const mutations = { state.subPlaceHolder = payload; }, deleteDevPlugin(state, payload) { - state.devPlugins = state.devPlugins.filter((plugin) => plugin.name !== payload.name); + state.devPlugins = state.devPlugins.filter( + (plugin) => plugin.name !== payload.name + ); sysFile.savePlugins(state.devPlugins); }, deleteProdPlugin(state, payload) { - state.devPlugins = state.devPlugins.filter((plugin) => plugin.id !== payload.id); + state.devPlugins = state.devPlugins.filter( + (plugin) => plugin.id !== payload.id + ); sysFile.savePlugins(state.devPlugins); // todo 删除 static 目录下的对应插件 }, @@ -59,124 +63,136 @@ const mutations = { }); state.devPlugins = [...state.devPlugins]; sysFile.savePlugins(state.devPlugins); - } + }, }; const actions = { showMainUI({ commit, state }, paylpad) { - ipcRenderer.send('changeWindowSize-rubick', { - height: getWindowHeight() + ipcRenderer.send("changeWindowSize-rubick", { + height: getWindowHeight(), }); setTimeout(() => { - commit('commonUpdate', { + commit("commonUpdate", { showMain: true, selected: { - key: 'market', - name: '插件中心' - } + key: "market", + name: "插件中心", + }, }); }, 50); }, reloadDevPlugin({ commit }, payload) { - const config = JSON.parse(fs.readFileSync(path.join(payload.sourceFile, '../plugin.json'), 'utf-8')); + const config = JSON.parse( + fs.readFileSync(path.join(payload.sourceFile, "../plugin.json"), "utf-8") + ); const pluginConfig = { ...config, - sourceFile: path.join(payload.sourceFile, `../${config.main}`) + sourceFile: path.join(payload.sourceFile, `../${config.main}`), }; const devPlugins = [...state.devPlugins]; - commit('commonUpdate', { + commit("commonUpdate", { devPlugins: devPlugins.map((plugin) => { if (plugin.name === payload.name) { return { ...plugin, - ...pluginConfig + ...pluginConfig, }; } return plugin; - }) + }), }); }, - async onSearch({ commit }, paylpad) { - if (state.selected && state.selected.key !== 'plugin-container') { - commit('commonUpdate', { searchValue: '' }); + /** + * @param {Object} payload payload.filePath为配置文件的绝对路径。payload.value为搜索栏文字值。 + */ + async onSearch({ commit }, payload) { + if (state.selected && state.selected.key !== "plugin-container") { + commit("commonUpdate", { searchValue: "" }); return; } - const value = paylpad.value; + const value = payload.value; // 在插件界面不触发其他功能 - if ((state.selected && state.selected.key === 'plugin-container') || paylpad.searchType === 'subWindow') { - commit('commonUpdate', { searchValue: value }); + if ( + (state.selected && state.selected.key === "plugin-container") || + payload.searchType === "subWindow" + ) { + commit("commonUpdate", { searchValue: value }); return; } - const fileUrl = paylpad.filePath || clipboard.read('public.file-url').replace('file://', ''); - commit('commonUpdate', { searchValue: value }); + const fileUrl = + payload.filePath || + clipboard.read("public.file-url").replace("file://", ""); + commit("commonUpdate", { searchValue: value }); // 复制文件 - if (paylpad.filePath || (fileUrl && value === 'plugin.json')) { - const config = JSON.parse(fs.readFileSync(fileUrl, 'utf-8')); + if (payload.filePath || (fileUrl && value === "plugin.json")) { + const config = JSON.parse(fs.readFileSync(fileUrl, "utf-8")); const pluginConfig = { ...config, - sourceFile: path.join(fileUrl, `../${config.main || 'index.html'}`), + sourceFile: path.join(fileUrl, `../${config.main || "index.html"}`), id: uuidv4(), - type: 'dev', - icon: 'image://' + path.join(fileUrl, `../${config.logo}`), + type: "dev", + icon: "image://" + path.join(fileUrl, `../${config.logo}`), subType: (() => { if (config.main) { - return ''; + return ""; } - return 'template'; - })() + return "template"; + })(), }; - commit('commonUpdate', { + commit("commonUpdate", { selected: { - key: 'plugin', - name: 'plugin.json' + key: "plugin", + name: "plugin.json", }, - searchValue: '', + searchValue: "", options: [ { - name: '新建rubick开发插件', - value: 'new-plugin', - icon: 'https://static.91jkys.com/activity/img/b37ff555c748489f88f3adac15b76f18.png', - desc: '新建rubick开发插件', + name: "新建rubick开发插件", + value: "new-plugin", + icon: + "https://static.91jkys.com/activity/img/b37ff555c748489f88f3adac15b76f18.png", + desc: "新建rubick开发插件", click: (router) => { - commit('commonUpdate', { + commit("commonUpdate", { showMain: true, devPlugins: [pluginConfig, ...state.devPlugins], selected: { - key: 'plugin', - name: '新建rubick开发插件' + key: "plugin", + name: "新建rubick开发插件", }, - current: ['dev'] + current: ["dev"], }); - ipcRenderer.send('changeWindowSize-rubick', { - height: getWindowHeight() + ipcRenderer.send("changeWindowSize-rubick", { + height: getWindowHeight(), }); - router.push('/home/dev'); - } + router.push("/home/dev"); + }, }, { - name: '复制路径', - desc: '复制路径', - value: 'copy-path', - icon: 'https://static.91jkys.com/activity/img/ac0d4df0247345b9a84c8cd7ea3dd696.png', + name: "复制路径", + desc: "复制路径", + value: "copy-path", + icon: + "https://static.91jkys.com/activity/img/ac0d4df0247345b9a84c8cd7ea3dd696.png", click: () => { clipboard.writeText(fileUrl); - commit('commonUpdate', { + commit("commonUpdate", { showMain: false, selected: null, - options: [] + options: [], }); - ipcRenderer.send('changeWindowSize-rubick', { - height: getWindowHeight([]) + ipcRenderer.send("changeWindowSize-rubick", { + height: getWindowHeight([]), }); - remote.Notification('Rubick 通知', { body: '复制成功' }); - } - } - ] + remote.Notification("Rubick 通知", { body: "复制成功" }); + }, + }, + ], }); // 调整窗口大小 - ipcRenderer.send('changeWindowSize-rubick', { - height: getWindowHeight(state.options) + ipcRenderer.send("changeWindowSize-rubick", { + height: getWindowHeight(state.options), }); return; } @@ -187,7 +203,7 @@ const actions = { if (value) { state.devPlugins.forEach((plugin) => { // dev 插件未开启 - if (plugin.type === 'dev' && !plugin.status) return; + if (plugin.type === "dev" && !plugin.status) return; const feature = plugin.features; feature.forEach((fe) => { const cmds = searchKeyValues(fe.cmds, value); @@ -195,14 +211,19 @@ const actions = { ...options, ...cmds.map((cmd) => ({ name: cmd, - value: 'plugin', - icon: plugin.sourceFile ? 'image://' + path.join(plugin.sourceFile, `../${plugin.logo}`) : plugin.logo, + value: "plugin", + icon: plugin.sourceFile + ? "image://" + path.join(plugin.sourceFile, `../${plugin.logo}`) + : plugin.logo, desc: fe.explain, type: plugin.type, click: (router) => { - actions.openPlugin({ commit }, { cmd, plugin, feature: fe, router }); - } - })) + actions.openPlugin( + { commit }, + { cmd, plugin, feature: fe, router } + ); + }, + })), ]; }); }); @@ -215,8 +236,12 @@ const actions = { if (!descMap.get(plugin)) { descMap.set(plugin, true); let has = false; - plugin.keyWords.some(keyWord => { - if (keyWord.toLocaleUpperCase().indexOf(value.toLocaleUpperCase()) >= 0) { + plugin.keyWords.some((keyWord) => { + if ( + keyWord + .toLocaleUpperCase() + .indexOf(value.toLocaleUpperCase()) >= 0 + ) { has = keyWord; plugin.name = keyWord; return true; @@ -233,17 +258,17 @@ const actions = { actions.openPlugin({ commit }, { plugin }); }; return plugin; - }) + }), ]; descMap = null; } - commit('commonUpdate', { - options + commit("commonUpdate", { + options, }); - ipcRenderer.send('changeWindowSize-rubick', { - height: getWindowHeight(state.options) + ipcRenderer.send("changeWindowSize-rubick", { + height: getWindowHeight(state.options), }); }, async downloadPlugin({ commit }, payload) { @@ -251,88 +276,90 @@ const actions = { const fileUrl = find(distUrl); // 复制文件 - const config = JSON.parse(fs.readFileSync(`${fileUrl}/plugin.json`, 'utf-8')); + const config = JSON.parse( + fs.readFileSync(`${fileUrl}/plugin.json`, "utf-8") + ); const pluginConfig = { ...config, id: uuidv4(), sourceFile: `${fileUrl}/${config.main}`, - type: 'prod', + type: "prod", icon: payload.logo, subType: (() => { if (config.main) { - return ''; + return ""; } - return 'template'; - })() + return "template"; + })(), }; - commit('commonUpdate', { - devPlugins: [pluginConfig, ...state.devPlugins] + commit("commonUpdate", { + devPlugins: [pluginConfig, ...state.devPlugins], }); }, openPlugin({ commit }, { cmd, plugin, feature, router, payload }) { - if (plugin.type === 'app') { + if (plugin.type === "app") { execSync(plugin.action); - commit('commonUpdate', { + commit("commonUpdate", { selected: null, showMain: false, options: [], - searchValue: '' + searchValue: "", }); - ipcRenderer.send('changeWindowSize-rubick', { - height: getWindowHeight([]) + ipcRenderer.send("changeWindowSize-rubick", { + height: getWindowHeight([]), }); return; } - commit('commonUpdate', { + commit("commonUpdate", { selected: { - key: 'plugin-container', + key: "plugin-container", name: cmd.label ? cmd.label : cmd, - icon: 'image://' + path.join(plugin.sourceFile, `../${plugin.logo}`) + icon: "image://" + path.join(plugin.sourceFile, `../${plugin.logo}`), }, - searchValue: '', - showMain: true + searchValue: "", + showMain: true, }); - ipcRenderer.send('changeWindowSize-rubick', { - height: getWindowHeight() + ipcRenderer.send("changeWindowSize-rubick", { + height: getWindowHeight(), }); - if (plugin.type === 'system') { + if (plugin.type === "system") { systemMethod[plugin.tag][feature.code](); - commit('commonUpdate', { + commit("commonUpdate", { selected: null, showMain: false, - options: [] + options: [], }); - ipcRenderer.send('changeWindowSize-rubick', { - height: getWindowHeight([]) + ipcRenderer.send("changeWindowSize-rubick", { + height: getWindowHeight([]), }); router.push({ - path: '/home' + path: "/home", }); return; } - commit('commonUpdate', { + commit("commonUpdate", { pluginInfo: { cmd, ...plugin, detail: feature, - payload - } + payload, + }, }); router.push({ - path: '/plugin', + path: "/plugin", query: { ...plugin, _modify: Date.now(), - detail: JSON.stringify(feature) - } + detail: JSON.stringify(feature), + }, }); - } + }, }; export default { namespaced: true, state, mutations, - actions + actions, };