适配Linux Gnome的复制plugin.json文件的功能。修复粘贴plugin.json受定时器影响不跳出按钮、搜索栏为空时退格路由报错两个Bug

This commit is contained in:
tcsnzh 2021-09-20 23:37:13 +08:00
parent 9d3e7fc4a5
commit db12d66ff7
3 changed files with 285 additions and 202 deletions

View File

@ -126,6 +126,7 @@ import {
searchKeyValues, searchKeyValues,
fileLists, fileLists,
} from "./assets/common/utils"; } from "./assets/common/utils";
import { commonConst } from "../main/common/utils";
const opConfig = remote.getGlobal("opConfig"); const opConfig = remote.getGlobal("opConfig");
const { Menu, MenuItem } = remote; const { Menu, MenuItem } = remote;
@ -217,7 +218,7 @@ export default {
...mapMutations("main", ["commonUpdate"]), ...mapMutations("main", ["commonUpdate"]),
shouldPaste(e) { shouldPaste(e) {
let filePath = ""; let filePath = "";
if (process.platform === "win32") { if (commonConst.windows()) {
const rawFilePath = clipboard.read("FileNameW"); const rawFilePath = clipboard.read("FileNameW");
filePath = rawFilePath.replace( filePath = rawFilePath.replace(
new RegExp(String.fromCharCode(0), "g"), new RegExp(String.fromCharCode(0), "g"),
@ -226,11 +227,46 @@ export default {
if (filePath.indexOf("plugin.json") >= 0) { if (filePath.indexOf("plugin.json") >= 0) {
this.search({ this.search({
filePath, 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.valuev.filePath 参见 src/renderer/store/modules/main.js的onSearch函数
*/
search(v) { search(v) {
console.log("search was called , param v is :", v);
if (!v.disableDebounce) {
this.onSearch(v);
return;
}
if (!this.searchFn) { if (!this.searchFn) {
this.searchFn = debounce(this.onSearch, 200); this.searchFn = debounce(this.onSearch, 200);
} }
@ -297,9 +333,13 @@ export default {
ipcRenderer.send("changeWindowSize-rubick", { ipcRenderer.send("changeWindowSize-rubick", {
height: getWindowHeight([]), height: getWindowHeight([]),
}); });
if (this.$router.history.current.fullPath !== "/home") {
// if
// (退)
this.$router.push({ this.$router.push({
path: "/home", path: "/home",
}); });
}
}, },
newWindow() { newWindow() {
ipcRenderer.send("new-window", { ipcRenderer.send("new-window", {

View File

@ -9,7 +9,12 @@
> >
<a-icon type="left-circle" /> <a-icon type="left-circle" />
</div> </div>
<div slot="nextArrow" slot-scope="props" class="custom-slick-arrow" style="right: 10px"> <div
slot="nextArrow"
slot-scope="props"
class="custom-slick-arrow"
style="right: 10px"
>
<a-icon type="right-circle" /> <a-icon type="right-circle" />
</div> </div>
<div v-for="banner in bannerList"> <div v-for="banner in bannerList">
@ -18,22 +23,33 @@
</a-carousel> </a-carousel>
<a-divider v-if="bannerList && !!bannerList.length"></a-divider> <a-divider v-if="bannerList && !!bannerList.length"></a-divider>
<h2>插件</h2> <h2>插件</h2>
<a-list item-layout="horizontal" style="width: 100%" :grid="{ gutter: 16, column: 2 }" :data-source="pluginList"> <a-list
item-layout="horizontal"
style="width: 100%"
:grid="{ gutter: 16, column: 2 }"
:data-source="pluginList"
>
<a-list-item slot="renderItem" slot-scope="item, index"> <a-list-item slot="renderItem" slot-scope="item, index">
<a-button v-if="showButton(item)" :loading="loading[index]" type="link" slot="actions" @click="download(index, item)"> <a-button
<a-icon v-show="!loading[index]" style="font-size: 20px;" type="cloud-download" /> v-if="showButton(item)"
:loading="loading[index]"
type="link"
slot="actions"
@click="download(index, item)"
>
<a-icon
v-show="!loading[index]"
style="font-size: 20px;"
type="cloud-download"
/>
</a-button> </a-button>
<a-list-item-meta <a-list-item-meta
@click="showPannel(item, index)" @click="showPannel(item, index)"
:description="item.description" :description="item.description"
> >
<div slot="title">{{ item.pluginName }}</div> <div slot="title">{{ item.pluginName }}</div>
<a-avatar <a-avatar slot="avatar" :src="item.logo" />
slot="avatar"
:src="item.logo"
/>
</a-list-item-meta> </a-list-item-meta>
</a-list-item> </a-list-item>
</a-list> </a-list>
@ -70,8 +86,8 @@
</template> </template>
<script> <script>
import api from '../../../assets/api'; import api from "../../../assets/api";
import {mapActions, mapState} from 'vuex'; import { mapActions, mapState } from "vuex";
import marked from "marked"; import marked from "marked";
import { shell } from "electron"; import { shell } from "electron";
const rendererMD = new marked.Renderer(); const rendererMD = new marked.Renderer();
@ -83,8 +99,8 @@ export default {
loading: {}, loading: {},
bannerList: [], bannerList: [],
show: false, show: false,
currentSelect: {} currentSelect: {},
} };
}, },
async created() { async created() {
const [result, bannerRes] = await Promise.all([ const [result, bannerRes] = await Promise.all([
@ -93,7 +109,7 @@ export default {
]); ]);
this.pluginList = result.result; this.pluginList = result.result;
this.bannerList = bannerRes.result; this.bannerList = bannerRes.result;
console.log(bannerRes) console.log(bannerRes);
}, },
methods: { methods: {
@ -108,7 +124,9 @@ export default {
this.$set(this.loading, index, false); this.$set(this.loading, index, false);
}, },
showButton(item) { showButton(item) {
return !this.devPlugins.filter(plugin => (plugin.name === item.name && plugin.type === 'prod')).length; return !this.devPlugins.filter(
(plugin) => plugin.name === item.name && plugin.type === "prod"
).length;
}, },
showPannel(item, index) { showPannel(item, index) {
this.show = true; this.show = true;
@ -117,13 +135,13 @@ export default {
}, },
jumpTo(link) { jumpTo(link) {
if (link) { if (link) {
shell.openExternal(link) shell.openExternal(link);
} }
}, },
...mapActions('main', ['downloadPlugin']) ...mapActions("main", ["downloadPlugin"]),
}, },
computed: { computed: {
...mapState('main', ['devPlugins']), ...mapState("main", ["devPlugins"]),
readme() { readme() {
marked.setOptions({ marked.setOptions({
renderer: rendererMD, renderer: rendererMD,
@ -133,17 +151,16 @@ export default {
pedantic: false, pedantic: false,
sanitize: false, sanitize: false,
smartLists: true, smartLists: true,
smartypants: false smartypants: false,
}); });
try { try {
return marked(this.currentSelect.detail); return marked(this.currentSelect.detail);
} catch (e) { } catch (e) {
return '暂无描述信息' return "暂无描述信息";
}
}
}
} }
},
},
};
</script> </script>
<style lang="less"> <style lang="less">
@ -178,7 +195,7 @@ export default {
} }
} }
.market { .market {
height: calc(~'100vh - 110px'); height: calc(~"100vh - 110px");
background: #fff; background: #fff;
padding: 20px; padding: 20px;
box-sizing: border-box; box-sizing: border-box;
@ -221,5 +238,4 @@ export default {
white-space: nowrap; white-space: nowrap;
} }
} }
</style> </style>

View File

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