From 7d55ef06a60ba1cf18ae5bc63113d6fa7490d08a Mon Sep 17 00:00:00 2001 From: muwoo <2424880409@qq.com> Date: Fri, 2 Jul 2021 17:12:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=BF=AB=E6=8D=B7?= =?UTF-8?q?=E9=94=AE=E8=AE=BE=E7=BD=AE;=E6=94=AF=E6=8C=81=E8=B6=85?= =?UTF-8?q?=E7=BA=A7=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 + src/main/browsers/index.js | 1 + src/main/browsers/superPanel.js | 54 +++++ src/main/common/common.js | 87 +++++++- src/main/common/config.js | 9 +- src/renderer/App.vue | 14 +- src/renderer/assets/common/utils.js | 29 ++- src/renderer/assets/keycode.js | 194 +++++------------- src/renderer/pages/plugins/index.vue | 10 +- .../pages/search/subpages/settings.vue | 42 +++- src/renderer/store/modules/main.js | 17 +- static/plugins/superPanel/assets/link.png | Bin 0 -> 1049 bytes static/plugins/superPanel/assets/logo.png | Bin 0 -> 8013 bytes static/plugins/superPanel/assets/new.png | Bin 0 -> 345 bytes static/plugins/superPanel/assets/terminal.png | Bin 0 -> 309 bytes static/plugins/superPanel/index.html | 101 +++++++++ static/plugins/superPanel/index.js | 185 +++++++++++++++++ static/preload.js | 11 +- 18 files changed, 586 insertions(+), 172 deletions(-) create mode 100644 src/main/browsers/superPanel.js create mode 100644 static/plugins/superPanel/assets/link.png create mode 100644 static/plugins/superPanel/assets/logo.png create mode 100644 static/plugins/superPanel/assets/new.png create mode 100644 static/plugins/superPanel/assets/terminal.png create mode 100644 static/plugins/superPanel/index.html create mode 100644 static/plugins/superPanel/index.js diff --git a/package.json b/package.json index 40d85db..2c47471 100644 --- a/package.json +++ b/package.json @@ -62,13 +62,17 @@ "download": "^8.0.0", "download-git-repo": "^3.0.2", "electron-store": "^8.0.0", + "is-chinese": "^1.4.2", "keycode": "^2.2.0", "marked": "^2.0.7", + "md5": "^2.3.0", + "mime-types": "^2.1.31", "node-fetch": "^2.6.1", "osx-mouse": "git+https://github.com/Toinane/osx-mouse.git", "puppeteer-core": "^10.0.0", "puppeteer-in-electron": "^3.0.3", "query-string": "^7.0.0", + "request-promise": "^4.2.6", "robotjs": "git+ssh://git@github.com/Toinane/robotjs.git", "semver": "^7.3.5", "sudo-prompt": "^9.2.1", diff --git a/src/main/browsers/index.js b/src/main/browsers/index.js index d2d059d..1c095bb 100644 --- a/src/main/browsers/index.js +++ b/src/main/browsers/index.js @@ -2,4 +2,5 @@ module.exports = () => ({ picker: require("./picker")(), separator: require("./separate")(), capture: require("./capture")(), + superPanel: require("./superPanel")(), }); diff --git a/src/main/browsers/superPanel.js b/src/main/browsers/superPanel.js new file mode 100644 index 0000000..6113bcd --- /dev/null +++ b/src/main/browsers/superPanel.js @@ -0,0 +1,54 @@ +const { BrowserWindow, ipcMain, app } = require("electron"); + +module.exports = () => { + let win; + + let init = (mainWindow) => { + if (win === null || win === undefined) { + createWindow(); + ipcMain.on('superPanel-hidden', () => { + win.hide(); + }); + ipcMain.on('superPanel-setSize', (e, height) => { + win.setSize(250, height); + }); + ipcMain.on('superPanel-openPlugin', (e, args) => { + mainWindow.webContents.send('superPanel-openPlugin', args); + }); + } + }; + + let createWindow = () => { + win = new BrowserWindow({ + frame: false, + autoHideMenuBar: true, + width: 250, + height: 50, + show: false, + alwaysOnTop: true, + webPreferences: { + webSecurity: false, + enableRemoteModule: true, + backgroundThrottling: false, + nodeIntegration: true, + devTools: false, + }, + }); + win.loadURL(`file://${__static}/plugins/superPanel/index.html`); + win.once('ready-to-show', () => win.show()); + win.on("closed", () => { + win = undefined; + }); + // 打包后,失焦隐藏 + win.on('blur', () => { + win.hide(); + }); + }; + + let getWindow = () => win; + + return { + init: init, + getWindow: getWindow, + }; +}; diff --git a/src/main/common/common.js b/src/main/common/common.js index 610aaee..336d7c7 100644 --- a/src/main/common/common.js +++ b/src/main/common/common.js @@ -4,6 +4,7 @@ import { BrowserWindow, clipboard, Notification, + app, } from 'electron'; import Api from './api'; import robot from 'robotjs'; @@ -11,7 +12,9 @@ import './config'; const browsers = require("../browsers")(); const mouseEvents = require("osx-mouse"); -const {picker, separator} = browsers; +const {picker, separator, superPanel} = browsers; +// 需要在超级面板展示的插件 +let optionPlugin = []; let closePicker = (newColor) => { if (picker.getWindow()) { @@ -34,18 +37,88 @@ function registerShortCut(mainWindow) { }); } +const getSelectedText = () => { + return new Promise((resolve) => { + const lastText = clipboard.readText('clipboard'); + + const platform = process.platform; + if (platform === 'darwin') { + robot.keyTap('c', 'command'); + } else { + robot.keyTap('c', 'control'); + } + + setTimeout(() => { + const text = clipboard.readText('clipboard') || '' + const fileUrl = clipboard.read('public.file-url'); + clipboard.writeText(lastText); + + resolve({ + text, + fileUrl + }) + }, 100); + }) +} + export default function init(mainWindow) { + ipcMain.on('optionPlugin', (e, args) => { + optionPlugin = args; + }); const mouseTrack = mouseEvents(); let down_time = 0; + let isPress = false; mouseTrack.on('right-down', () => { + isPress = true; down_time = Date.now(); + const config = global.opConfig.get(); + setTimeout(async () => { + if (isPress) { + const copyResult = await getSelectedText(); + let win = superPanel.getWindow(); + + if (win) { + win.webContents.send('trigger-super-panel', { + ...copyResult, + optionPlugin: optionPlugin.plugins, + }); + } else { + superPanel.init(mainWindow); + win = superPanel.getWindow(); + + win.once('ready-to-show', () => { + win.webContents.send('trigger-super-panel', { + ...copyResult, + optionPlugin: optionPlugin.plugins, + }); + }); + } + const pos = robot.getMousePos(); + win.setPosition(parseInt(pos.x), parseInt(pos.y)); + win.show(); + } + }, config.superPanel.mouseDownTime); }) mouseTrack.on('right-up', () => { - if ((Date.now() - down_time) > 1000) { - new Notification({ title: 'Rubick 通知', body: '长按了' }).show(); + isPress = false; + }); + + // 注册快捷键 + registerShortCut(mainWindow); + + // 设置开机启动 + const config = global.opConfig.get(); + app.setLoginItemSettings({ + openAtLogin: config.perf.common.start, + openAsHidden: true, + }); + + mainWindow.once("ready-to-show", () => { + // 非隐藏式启动需要显示主窗口 + if (!app.getLoginItemSettings().wasOpenedAsHidden) { + mainWindow.show(); } }); - registerShortCut(mainWindow); ipcMain.on('re-register', (event, arg) => { registerShortCut(mainWindow); @@ -55,10 +128,12 @@ export default function init(mainWindow) { mainWindow.setSize(arg.width || 800, arg.height); }); + // 打包后,失焦隐藏 mainWindow.on('blur', () => { - mainWindow.hide(); + app.isPackaged && mainWindow.hide(); }); + // 响应 preload.js 事件 ipcMain.on('msg-trigger', async (event, arg) => { const window = arg.winId ? BrowserWindow.fromId(arg.winId) : mainWindow const operators = arg.type.split('.'); @@ -70,6 +145,7 @@ export default function init(mainWindow) { event.sender.send(`msg-back-${arg.type}`, data); }); + // 窗口分离 ipcMain.on('new-window', (event, arg) => { const opts = { ...arg, @@ -78,6 +154,7 @@ export default function init(mainWindow) { separator.init(opts); }); + // 拾色器 ipcMain.on('start-picker', () => { const mouseTrack = mouseEvents(); picker.init(); diff --git a/src/main/common/config.js b/src/main/common/config.js index c5e8b5a..028ad1b 100644 --- a/src/main/common/config.js +++ b/src/main/common/config.js @@ -20,9 +20,15 @@ let defaultConfig = { search: true, } }, + superPanel: { + baiduAPI: { + key: '', + appid: '', + }, + mouseDownTime: 500 + } } } - global.opConfig = { config: null, get() { @@ -38,7 +44,6 @@ global.opConfig = { } }, set(key, value) { - console.log(opConfig.config); opConfig.config[key] = value; fs.writeFileSync(configPath, JSON.stringify(opConfig.config)); } diff --git a/src/renderer/App.vue b/src/renderer/App.vue index 6a23680..09f51f9 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -80,15 +80,23 @@ export default { } }, mounted() { - // 注册快捷键 - ipcRenderer.send('init-shortcut'); ipcRenderer.on('init-rubick', this.closeTag); ipcRenderer.on('new-window', this.newWindow); + // 超级面板打开插件 + ipcRenderer.on('superPanel-openPlugin', (e, args) => { + this.openPlugin({ + cmd: args.cmd, + plugin: args.plugin, + feature: args.feature, + router: this.$router, + payload: args.data, + }) + }); const searchNd = document.getElementById('search'); searchNd && searchNd.addEventListener('keydown', this.checkNeedInit) }, methods: { - ...mapActions('main', ['onSearch', 'showMainUI']), + ...mapActions('main', ['onSearch', 'showMainUI', 'openPlugin']), ...mapMutations('main', ['commonUpdate']), search(v) { if (!this.searchFn) { diff --git a/src/renderer/assets/common/utils.js b/src/renderer/assets/common/utils.js index d233181..1668661 100644 --- a/src/renderer/assets/common/utils.js +++ b/src/renderer/assets/common/utils.js @@ -4,7 +4,7 @@ import fs from 'fs'; import process from 'child_process'; import Store from 'electron-store'; import downloadFile from 'download'; -import {nativeImage} from 'electron'; +import {nativeImage, ipcRenderer} from 'electron'; import {APP_FINDER_PATH} from './constans'; import {getlocalDataFile} from "../../../main/common/utils"; @@ -57,6 +57,19 @@ async function downloadZip(downloadRepoUrl, name) { const sysFile = { savePlugins(plugins) { + ipcRenderer.send('optionPlugin', { + plugins: plugins.filter((plugin) => { + let hasOption = false; + plugin.features.forEach(fe => { + fe.cmds.forEach(cmd => { + if (cmd.type) { + hasOption = true; + } + }) + }); + return hasOption; + }) + }); store.set('user-plugins', plugins); }, getUserPlugins() { @@ -72,7 +85,7 @@ const sysFile = { } function mergePlugins(plugins) { - return [ + const result = [ ...plugins, ...SYSTEM_PLUGINS.map(plugin => { return { @@ -81,8 +94,18 @@ function mergePlugins(plugins) { sourceFile: '', type: 'system', } - }), + }) ] + + return result.filter((item, i) => { + let targetIndex; + result.forEach((tg, j) => { + if (tg.tag === item.tag && tg.type === 'system') { + targetIndex = j + } + }); + return i === targetIndex; + }); } function find(p, target = 'plugin.json') { diff --git a/src/renderer/assets/keycode.js b/src/renderer/assets/keycode.js index 13adf27..59fcc11 100644 --- a/src/renderer/assets/keycode.js +++ b/src/renderer/assets/keycode.js @@ -18,19 +18,14 @@ export default { 32: 'space', 33: 'page up', 34: 'page down', - 35: 'end', - 36: 'home', - 37: 'left arrow', - 38: 'up arrow', - 39: 'right arrow', - 40: 'down arrow', - 41: 'select', - 42: 'print', - 43: 'execute', - 44: 'Print Screen', - 45: 'insert', - 46: 'delete', - 47: 'help', + 35: 'End', + 36: 'Home', + 37: 'Left', + 38: 'Up', + 39: 'Right', + 40: 'Down', + 45: 'Insert', + 46: 'Delete', 48: '0', 49: '1', 50: '2', @@ -41,130 +36,55 @@ export default { 55: '7', 56: '8', 57: '9', - 58: ':', - 59: 'semicolon (firefox), equals', - 60: '<', - 61: 'equals (firefox)', - 63: 'ß', - 64: '@ (firefox)', - 65: 'a', - 66: 'b', - 67: 'c', - 68: 'd', - 69: 'e', - 70: 'f', - 71: 'g', - 72: 'h', - 73: 'i', - 74: 'j', - 75: 'k', - 76: 'l', - 77: 'm', - 78: 'n', - 79: 'o', - 80: 'p', - 81: 'q', - 82: 'r', - 83: 's', - 84: 't', - 85: 'u', - 86: 'v', - 87: 'w', - 88: 'x', - 89: 'y', - 90: 'z', - 91: 'Windows Key / Left ⌘ / Chromebook Search key', - 92: 'right window key', - 93: 'Windows Menu / Right ⌘', - 95: 'sleep', - 96: 'numpad 0', - 97: 'numpad 1', - 98: 'numpad 2', - 99: 'numpad 3', - 100: 'numpad 4', - 101: 'numpad 5', - 102: 'numpad 6', - 103: 'numpad 7', - 104: 'numpad 8', - 105: 'numpad 9', - 106: 'multiply', - 107: 'add', - 108: 'numpad period (firefox)', - 109: 'subtract', - 110: 'decimal point', - 111: 'divide', - 112: 'f1', - 113: 'f2', - 114: 'f3', - 115: 'f4', - 116: 'f5', - 117: 'f6', - 118: 'f7', - 119: 'f8', - 120: 'f9', - 121: 'f10', - 122: 'f11', - 123: 'f12', - 124: 'f13', - 125: 'f14', - 126: 'f15', - 127: 'f16', - 128: 'f17', - 129: 'f18', - 130: 'f19', - 131: 'f20', - 132: 'f21', - 133: 'f22', - 134: 'f23', - 135: 'f24', - 136: 'f25', - 137: 'f26', - 138: 'f27', - 139: 'f28', - 140: 'f29', - 141: 'f30', - 142: 'f31', - 143: 'f32', - 144: 'num lock', - 145: 'scroll lock', - 151: 'airplane mode', - 160: '^', - 161: '!', - 162: '؛ (arabic semicolon)', - 163: '#', - 164: '$', - 165: 'ù', - 166: 'page backward', - 167: 'page forward', - 168: 'refresh', - 169: 'closing paren (AZERTY)', - 170: '*', - 171: '~ + * key', - 172: 'home key', - 173: 'minus (firefox), mute/unmute', - 174: 'decrease volume level', - 175: 'increase volume level', - 176: 'next', - 177: 'previous', - 178: 'stop', - 179: 'play/pause', - 180: 'e-mail', - 181: 'mute/unmute (firefox)', - 182: 'decrease volume level (firefox)', - 183: 'increase volume level (firefox)', - 186: 'semi-colon / ñ', - 187: 'equal sign', - 188: 'comma', - 189: 'dash', - 190: 'period', - 191: 'forward slash / ç', - 192: 'grave accent / ñ / æ / ö', - 193: '?, / or °', - 194: 'numpad period (chrome)', - 219: 'open bracket', - 220: 'back slash', - 221: 'close bracket / å', - 222: 'single quote / ø / ä', + 65: 'A', + 66: 'B', + 67: 'C', + 68: 'D', + 69: 'E', + 70: 'F', + 71: 'G', + 72: 'H', + 73: 'I', + 74: 'J', + 75: 'K', + 76: 'L', + 77: 'M', + 78: 'N', + 79: 'O', + 80: 'P', + 81: 'Q', + 82: 'R', + 83: 'S', + 84: 'T', + 85: 'U', + 86: 'V', + 87: 'W', + 88: 'X', + 89: 'Y', + 90: 'Z', + 112: 'F1', + 113: 'F2', + 114: 'F3', + 115: 'F4', + 116: 'F5', + 117: 'F6', + 118: 'F7', + 119: 'F8', + 120: 'F9', + 121: 'F10', + 122: 'F11', + 123: 'F12', + 186: ';', + 187: '=', + 188: ',', + 189: '-', + 190: '.', + 191: '/', + 192: '`', + 219: '[', + 220: '\\', + 221: ']', + 222: "'", 223: '`', 224: 'left or right ⌘ key (firefox)', 225: 'altgr', diff --git a/src/renderer/pages/plugins/index.vue b/src/renderer/pages/plugins/index.vue index adf872e..2d7b895 100644 --- a/src/renderer/pages/plugins/index.vue +++ b/src/renderer/pages/plugins/index.vue @@ -30,8 +30,8 @@ export default { mounted() { this.webview = document.querySelector('webview'); this.webview.addEventListener('dom-ready', () => { - this.webview.send('onPluginReady', this.$route.query); - this.webview.send('onPluginEnter', this.$route.query); + this.webview.send('onPluginReady', this.pluginInfo); + this.webview.send('onPluginEnter', this.pluginInfo); }); this.setSubPlaceHolder('Hi, Rubick'); this.webview.addEventListener('ipc-message', (event) => { @@ -74,14 +74,16 @@ export default { ...mapMutations('main', ['setSubPlaceHolder', 'commonUpdate']), }, beforeRouteUpdate() { - this.path = `File://${this.$route.query.sourceFile}` + this.path = `File://${this.$route.query.sourceFile}`; + console.log(this.pluginInfo) + this.webview.send('onPluginEnter', this.pluginInfo); }, beforeDestroy() { const webview = document.querySelector('webview'); webview && webview.send('onPluginOut', this.$route.query) }, computed: { - ...mapState('main', ['searchValue', 'devPlugins']), + ...mapState('main', ['searchValue', 'devPlugins', 'pluginInfo']), pluginDetail() { return (this.devPlugins.filter(plugin => plugin.name === this.query.name)[0] || {}).features }, diff --git a/src/renderer/pages/search/subpages/settings.vue b/src/renderer/pages/search/subpages/settings.vue index 589bdf8..7302761 100644 --- a/src/renderer/pages/search/subpages/settings.vue +++ b/src/renderer/pages/search/subpages/settings.vue @@ -6,13 +6,7 @@ 偏好设置 - 本地启动文件 - - - 全局快捷键 - - - 所有关键字 + 超级面板
@@ -47,6 +41,30 @@
+
+
+
弹出面板
+ + 长按鼠标右键 + +
+
+
长按以下设置的毫秒响应
+ +
+
+
百度搜索配置
+ + + + + + + + +
+ +
@@ -63,7 +81,7 @@ export default { data() { return { currentSelect: [0], - config: JSON.parse(JSON.stringify(opConfig.get())) + config: JSON.parse(JSON.stringify(opConfig.get())), } }, methods: { @@ -96,6 +114,7 @@ export default { deep: true, handler() { opConfig.set('perf', this.config.perf); + opConfig.set('superPanel', this.config.superPanel); ipcRenderer.send('re-register'); } } @@ -111,14 +130,19 @@ export default { height: 100%; display: flex; align-items: flex-start; - background: #F8FAFC; + background: #fff; } .settings-detail { padding: 20px; box-sizing: border-box; flex: 1; + overflow: auto; + height: 100%; .setting-item { margin-bottom: 20px; + .ant-form-item { + margin-bottom: 0; + } .title { color: #6C9FE2; font-size: 15px; diff --git a/src/renderer/store/modules/main.js b/src/renderer/store/modules/main.js index f840c1c..eb667f1 100644 --- a/src/renderer/store/modules/main.js +++ b/src/renderer/store/modules/main.js @@ -22,6 +22,7 @@ const state = { searchValue: '', devPlugins: mergePlugins(sysFile.getUserPlugins() || []), subPlaceHolder: '', + pluginInfo: {}, } const mutations = { @@ -29,7 +30,7 @@ const mutations = { Object.keys(payload).forEach((key) => { state[key] = payload[key]; if (key === 'devPlugins') { - sysFile.savePlugins(payload) + sysFile.savePlugins(payload[key]) } }); }, @@ -236,7 +237,7 @@ const actions = { devPlugins: [pluginConfig, ...state.devPlugins], }); }, - openPlugin({commit}, {cmd, plugin, feature, router}) { + openPlugin({commit}, {cmd, plugin, feature, router, payload}) { if (plugin.type === 'app') { execSync(plugin.action); commit('commonUpdate', { @@ -253,7 +254,7 @@ const actions = { commit('commonUpdate', { selected: { key: 'plugin-container', - name: cmd, + name: cmd.label ? cmd.label : cmd, icon: 'image://' + path.join(plugin.sourceFile, `../${plugin.logo}`), }, searchValue: '', @@ -277,10 +278,20 @@ const actions = { }); return; } + commit('commonUpdate', { + pluginInfo: { + cmd, + ...plugin, + detail: feature, + payload, + } + }); + router.push({ path: '/plugin', query: { ...plugin, + _modify: Date.now(), detail: JSON.stringify(feature) }, }) diff --git a/static/plugins/superPanel/assets/link.png b/static/plugins/superPanel/assets/link.png new file mode 100644 index 0000000000000000000000000000000000000000..e14799b25be21efd9daa9c2d87f359a8bdcbe5c4 GIT binary patch literal 1049 zcmV+!1m^pRP)--W9ml-H5VZi|Zj|?my58 z$Zq$W5N}yTKJ$J5*f>$O*87O)1po&Vb}J&XqLlg`z=d9~_erDT&oNowWSRu}F_(yFvD4{% zo`xfpfY$mUBKmj&;LbE}2^}M%M*z%E5?@62`@X-N^w~h5(P-=p!|*f_-5NI*k#j_J zRz$vXV13{JWfA~cww~whR!Yr_$UG4}3*g3tkDKoRGyf2OKSZEjuWzkXDjxyZn*e`2 z48z54xBFKXkZFuJo6S3Vz21>^BJq&RVHnnzmX-81oZ=+hTDKF>}j34@$^ddrCwO|CiM7W3kr0B_dD62(*~_&=3J* zj3ktMl$qbpQd4W~+Tu%Dc4^~zOH^xJBcjvs7|eV{{6Pki1e8+uwA<}-S-?_=XSocG z_koOas?}=MYPEW4A_8k`Yt=k$vmk-X%zQ%@V{7fbBJyPxfnNdqySj`S;{};x zalj(-r0@H0&w_;KdG{-&+=ew!AHZM_*g!yQy@QC{g=27>a7H3>a&B(!M61>MaWjZC zo6Rj@7``kb&nM=)6h+a2APCM5)@l-v*7`6Jok{`vrz1i{7nD*f?RNW{X_B$lZWodJ z0J!gd0C%Uvf0~)!jK3dsp}Csf^;%zOQV*6RuasBW->=1$(v|SYQ}NhKz2|ukRw|X} zM5K|kT&7BZh}vNoz7_<*nNjm+{wv`e8;!;u5vhsD!|NSk8-T5ephZi_-Ll-#eHFlm zN~tq>)>$qBIn|$uSxI0fvd1PZGf-xrpaNwH6%??rdzpd45*7?lW}u*eh28%KNk5@L TCNeB100000NkvXXu0mjf@hI%# literal 0 HcmV?d00001 diff --git a/static/plugins/superPanel/assets/logo.png b/static/plugins/superPanel/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5373de3fd364cf516d057605d38f26dc010ee007 GIT binary patch literal 8013 zcmV-TAF|+yP)bC z@t^^KPaJ{<02%=J#CzZqZ+?RYXaL|7?}1Oe`3)L?0RT8!S~?mV%PbS}KE%{@b#w-x zy|tM;h9Nxw0B3mu$+^0&xS^KUp39kp0WcW=;0OR1R#iJN42eMy48jngP_S?DMIsSh z?bQhYCobm<0APVyrT72i>LCcSJu$z~P2bg}1c18m&6+fgJ9z4Rmo$FTlaq(` zwHFEnt<@?ARhG9x!QM^>wfgP^I`V60Wxg6gu)}J3i-&*x&ELyiTup6k?M4ECb*ib{ zd)_x<4(!+hhgkTC6$*9_I{K0{0P4cGv9)`<)BX4t>J7-t$%#1k_a8`N{F`1H4Lkd( zfuN}+m$|rlPnk8>)Y!!2YcjBD3ZKP7htV}bBn5zagW9(15dX({kB*W;F({HqfLt!C z(5BMjl9!jy{Dr&-3+|=~0#6`WNTve}HI1XCr6r4nK0y!+|8g6fHhFdB?xQ#6md$38 zZBtzeAJ$1L0P4c;+^y&PV`r~?Ml?nylLB!;0Vt9b0;yD5p^Y+`G|A7~GxLu3jX}f@ z3I)3@9cqkh=hB%@Q}~^__KY}s=8`>&#j+z?Ze0tXEC3ix*n7ahoc+g7H?OWSq5=UZ z6p27-X=z0eq-9AzE}Y#CFN~&%4A~B*Go2Hc;|0o>cVOMGyIzi;JgqyG^6EqQWC1t} z0GJOG-+%Tp&e)_;mzo+@{GkX4^7BDS@ds71fB!g=9R4(@EdYSe6G-5{AJx;&%G?D( zFu2SEQ)kbMSh;RfZz>I}FX58{K)IAjhKXk{S{A%y)tbR%8dp+M0@CxIjj5?AxOP7{-i*WPNVc-|Equ}d zw6``JhGEDP_=4-U-J#gRLwsrS`O1K{5Z1-seDU?}Qf)3gVQ zvf$SbR=I8rpYq-OK4kg@rlCXl?XAs*%H>8WR3_S5R{=zWoVc6-0KiZHfaq~lJSlUg zTqXnjqy&JX82C_B`26Q(3;V(RFbr9fBrH@nl925;Mx|5NjCVt$BTO4NCN=icA$+yf z8l`y_X#mu~D26Kl`OZyibJO|!me97HBrNR7C}~ox3|#iH z*$Ox}vK%^U?7eOKkBlRe12IZ3#0+7jMKp~gK zt(-rLSVoFiEOaOV!*!I;ev{3jbF5JMpJuW63Ke%TiEQBYJkdiH_ zMCuK5;&N14phxe%Mbo}tkkEJFpcY2PCe@leONxs@S_*DTz@NzHVQ)?yJw)t=86*Tw zTuuQT|N9Rfc6rZ{KWA4be5tf7tttV;N7HmhSo{2Sk8v!{Fm-y>TN zWdPvh$B3l}fO7%$3Qn9lGiCamMFRUaZHTYCLjB=90L}+K76_cU9Na{{bk!QK?-ng{ zu4(w$@3t|;@3t2K0ra5Kc~h)9;luJp1;VH)BM0LBPj-$)833Z8N=*Q@0bClY9&<}e z@cp7?FUC)vX4%w?quMxv2|gwW2mm(kIrL=Y*As@<1OPOB?A@|H&HwIg=mrKKogk=5 z_%KtMR4N+VzZJ!iSlOMFp|WBL?7p z7Co?8a_I9$Dw1I-cL2MfMJ+$%jy*cPeTHn zYSIK$gb(xa^}6o&`_8TSa75cOkPPMOX+AaxG(CT&e?LEP#m^fnOoYkw5!@l&uyRRZ z#Iw-$RY5>i_%M&%o7ROr^79=C07&5pB*cWX#_H(23Lw+Sk4+OOcmJUI7w_BwLx$bi z<$j_gg0P4$nM$_+6h*UKmoF-U);o0wbP>K>E{_<~w~KN!iY8MqrPgUAHgrv(6h7P% z$7k8&CQtQWzioF<3yO_l z(~)+%sS^!g=$b&e6AHh4T=uh+0Fxom6#ljQ0Z*)L>~NodCO!UlZlBw`bvwaMobwsknlm&*~g&X0bmLQng$*_yH;<`-MU|3 zY-~iz1G+BZc>C(*qm}b#j#QSZv+(O>6;NGA)#t=eQ}`Xbbc;B8`brZcBX*5Pxa(5r z%Chn=oI3IT%*ms0xd$IH0KkPOkic^rIz5cg07T8}0|HG0kJ7^z+V)%N)T1=KgdiaQ z^~;#3qx*MtdH*J^rLu?=77LwRTc1is0Z`Y&fu`^$PMh_3%_cYK-`AK1Ia1D2E|tc= zcorIaY~S_)Ioa8&030yFh#X}Pqq5wqu5iWyP*)HrwGBMbiCg!6-m>eT2~(ymp)4gG zUdT*O4SVTFlT%niOA>6pBM84eJLF#i)Gt0 zxrN2+-R^%D+1cCo<67I)rte6-i=t@i(pi%~BqzQnCUlGuK5T%&0H6;D?Ax@B-@NMp zhOiJ^7}mD7z=}&J1X%IU%NJ!tzj&&2_8{-6Ly9gvBr+%fY72p*las`C+g=fy%~q|c zZJIX+&8%wW)Kje(_WruzmA~(;uF3?AjErJ%0MG$}t(_gPY{u2Y_w-*DXHOmrIe+Rn z5f|wePat93Zlb{r0qPQ}joG*=O`r<|Ff5*Flg7Zrq)`QUyslo1IJSQmzEh`9tDRm6 zRc2<88i42s{X@_KK5XJ(neO@Ms}S7rsGj0J@BmbE ze*rBJXoPtIeFqFlTDbBjQ-wlS?7Cu+O-XSHH1rsZ@C|wh&~)GG-m6dIsBsh15AFI@ zf104BJutT@H{PiWe{_HI68~p~_?Gb(U3(^o1i8(#GBb#vS&TCDXwxPJsR1-Scm@v} z&7ZwwSrY_7Y*UhX{(HBqC*l#*S`)yrJ>>BN)#VM}47N<0|E+cF8xIAc9`_40-Ng(_ z_y(x~G=)FGdB(f>%U87)=I1pbXirP#J>I=#{Rrj%YX!lp=*U;c5AMMyd=rOSrY@Ys zbxA^Gaf2*SAEME4dk+Crl3i3dH zZmz0tGE(^gJ2(DZtKlFnCQ^Lz_uue|-Nd05sY{$~9HbTR#{iy>g<)6k32`4i<>gMp z4G98+0YFpuE7txJH)YnGE^MR!qO(+PU-aW+}fe zZ_y?_TLwy{cx7|=04rDWgnQ>hMZoH|pP0gDQRAU8Wp^-6ATPWZ2DejuWpR~Qbioca6N zsbjz6f~!gRL}pTX`EXEDR(Vd~6Ik%Lfl{BqMw>5cmcZJU@3wK-`Z2uYP6Z>VQ!I zXs+>xj~Soxqw8ifOD?xooAvN&yPWL*AQ0r_#%x}@qJlFfRpFC?;9ijE`DvegMnk|D z05pX^dHU@1g)3d`IOgWnM&Tx{1^~dXw9C%QP`x6|&wsgT^)gkwW3peqNng)kfEX!c zuh-dQMG1I>ubPH~J3*rGvp)Iwu*1YT0V4o_YkY-*eTKMkbLmfOqbJXp)3b3Cm2r=X ztgB61C>De4%yj(sJ2$U~_;_B$w{FP_ADG%FoAkX_9_kg9Cdy)#0s;b=3dme~$f5UHHlhu)o+9$hH|# zZiAoz!M$Kn_-O`0P_F=JM&H`twkLkngh?IQY_`7ST`8ZFzwZsWe(@Y`A}0OiYviI0 zg0x&ID5*jd_=SnX|Mkja)NoL50B9O`cDkR4{c7k4Qfqu&>ClJpiL!NuAVeJg?=9v) zP%i*z3jg=N&L#Bd(~k(0sH=Qyd{3XkuPp>jniJGH0PU^K+%XKnZ?s~uSmM7fd*?ZQ z_8Ac`mlok4-@h}+^XjD`RMfulm*+x&Y0F0P*dLk^6TPY`SCb}?%Q29aQ}x8~Ua;u- z>D%?cM66Q))D1k=w#_B(f1m%*%ApPE>(zCk<9SGM?8cv#;zP@~LoM?5t!_=~D3HmJ z(0l+8Yt4zCJ|SR&v8YY}&~)GG)U{{Awgc`hZEWpuhf2Dhl%zx;m6qk~-MYRBpU30C za(s_=2ybWKNb9ASHGSFogrL67#rLzGkxI)zR(hJjKydT1FziYlyO+@dfTr+& zaNWq8H0?VlV`G!LlD(=NbqH82R>t9dJBr`Dj8-i<>tjw(lP0+FND%7bSMF_G7kdYK z2SC$(Ys;R4@k2+Cqt&{njVcI1Mrx|$)bZc*o&`Q3E^AV~#xw}7KNN&sQ@Whf4S`+( z&@}KIJb60#%YFlid-Al&iPqnbAJ`q_dF29b3jhF|W3kY~D9VDjm*Xct>IDK61L-+3 zP*hxbPH^LaAjHGJ0N<>l69T;fpc#GZKZ^r%ht2(aD zbO^587X;sYSb%#g(V+=y4S>4vEv>8yPhPmuxOt0~#w^l#b`iDR#05lCeeFh9l*}VH;o9fQglNXzQQi?^Q$Ic`A z6K4ap3ZE#I2@s$tz&(qqg5aXBFz{BO5O+q=mnNVLK&8W(Q>KM4clo7HQ!_LDNUxT; ze2^4IP8`}7UgU^Jcwn*6o>W4uG97~RKKTJYK_Xo1>H`AG061|us%RY3=Pr1?VEO9K zjjOTlVHhTsh{eeq3kwGXL1>>8mX(zxOdm7Ywn$P`tB9OThv1yA;E8Ww!Ek**KnVc# z3E$As6TdmMZJXS)&w$Jxz52+8jvhz( zawBbu0Y%ZwrL!i9lM@s45|NWB5M<;@L19tlIl&np!IQf|wTFN-080No`1OMxz4|5` z{OfE77OUdLnO;{f#vR+gi-?m`t;}Z3TNJ5rc*!D2Ti;@fkYV*T-O{czsGb4{=S*}$p2{} zaf{elo#}riU~FVKaaNzyt<~+UIo}`{ z@PU==)~iq8;Zql?JnOHm5$b`P=nl%rbO^SdOnV=nR7PArO*&Q)NdP#>@JjP3-_4C! z<+_=;tPuFzxcbO_j~h-N2EfK7fn=XHp%K5UZyc@JPI*nG8W;u{?J1Ha_kEOZFCVtpKQx|2~1?@0xNr_@oU*(cDqJJ1NI*>?luA1aIV^ z^t89)EWr?P3cmC(;!Q4##nL(#$jQ!%{BHbk;&?Y{D<7qbX-Uik2%yC!44cIh7I{$ZWG5@m zK!AWy_@1YK=*wnYuIjXIRe6;Z7sXB()EjCFXyvOH;WKGCC@w{D2vGDtG3E;7Q7iZH zzbw}R*l=xk5NQRVy|uX;hGE-ahL5A-p^C@-x+0&41-hK8_or0 ztm7%8mTJGDgem|60017WAvHNEc)`^1_--45uzDrti=(J?9!%Tb*1`!>po#GBvz~W@ z9on`dcJC@=g<)9U$X;JSlOrK~(z9Hub)uTSJ|Mt8Bu2<0=i!raI20sjlvM~{cl2`h ztKjG&7~E3pmGUG2FdK$p2yOwq8yb~l+PDesQzw;{C4Ak#d%5Ke0j|7!$w8`}=fveW z0|0Kq_xzr{OfWHNRMq)F`P5N^;tPcNxZw%IkTrB%ph&gu>gnqm0{P43uTXKUDqOu# zEC*Tn|7n414}>qT`wP26>!3En5G4RE-hL3)(%yl%xf)Cv^;MooD6jzt@Z;r6@JkY? zJngK^+z{5yG5$?QWxli+dZ^U7y0mo#K~?3$;1usu%g;Z+ z=f&%yfCFc<@%pNa`*s%HuesV>F2!s zOb`U9j5Y^$ZjQR=<%zF7@dpEcBLI8IW|{iE%g>i|0>Gry+I%!X(LQj@Cz6eGo*L!4 zb@zYo0RW<&Kl53)V!=d16+Y26y+9xn$4H-!tMLma%FD`=0b!v6AOOpo=E_sfr}VH4 zR0BYz1%6z=CCGW!9O94#o+LRj!F%O`nL|p8i#0uepx-?_;7}pl+u?sMcy#-+&rJ0% z@7>$iK`XwWO5|Iwh8}%rgjzvh*~>znum_;|!K46yOFP6|yRl6uy2H9Vzm?dA;e_iIa-D_v~YCVPyqF!Bh(V zm!6UwG|zb)+{Dnyk&{Xr>LabLnt*IwOQk5_rAdLHP#(8@Cm*+$=xsAdvl8mNgYdVl z``iPDkI~)7FEsG6-_|uh5KBFnC1b37WCcJb9i0&53S}TiD3feHmVqRul|lFH6orD_ zLoeIGRW(kzLkO3KxcBYwvEL-ET(=?Hiff}X5^3ucp&&2pPxphIhj&$%D~kaD3wQzv z%=e>w=zstoHIL_)fh{M}-@i*PB^*LX?~{;P2392v*ceQ~I!nw6V45ML#wIz>oSXhd z*Dh^MOiU|9_m)aa)84*{OZM`(U?24GzUr7ZTRJK6c)&uuKQ+Ot_lKqiZEA{$-Bz@U_a-51&XqGUJ2^?NZ5&= zB_(btg?$L;PA)uw2K&`ru{+A&XGMO=7AHuGxwhaK#FGEI`&;S6V z#Y2DP8UUcbj~QJ;0|1N`5B-&E0D%5JW^@S+05DoS^jEF{0Q&ow(IxyJjx$)xpBw7i P00000NkvXXu0mjfyUiWd literal 0 HcmV?d00001 diff --git a/static/plugins/superPanel/assets/new.png b/static/plugins/superPanel/assets/new.png new file mode 100644 index 0000000000000000000000000000000000000000..34eb3b7eab5c2108395a4864dcd7acb5cc589e89 GIT binary patch literal 345 zcmV-f0jB-+fEaniRkY;f!nn%u=#d z@ijPmo+PaRGQ|WC+CoUxS-VD^LIPN+fD}M%!NjNs&}%SLRVG#nNCD6K+7+}WT99VVqamdR7pH&1n{HDG=(&U%nWJPU{?vY;=be#I|l?XRUoPYY}I4N rLt`{%LhN1wU@I0nUJ8V+D7)Sl5+00Ed&|}m%k+tLYU!>2Q-K=R^0+P!0?YHlmNr^*EN+u&k0P#|uU10}00000NkvXX Hu0mjf*OGp- literal 0 HcmV?d00001 diff --git a/static/plugins/superPanel/index.html b/static/plugins/superPanel/index.html new file mode 100644 index 0000000..bb05c7b --- /dev/null +++ b/static/plugins/superPanel/index.html @@ -0,0 +1,101 @@ + + + + + Title + + + + + +
+
+ + 选择的文本 {{selectData.text.length}} 个 +
+
+
+
{{trans.src}}
+
n. {{trans.dst}}
+
+
+
+
+ + {{op.name}} +
+
+
+ + diff --git a/static/plugins/superPanel/index.js b/static/plugins/superPanel/index.js new file mode 100644 index 0000000..6314940 --- /dev/null +++ b/static/plugins/superPanel/index.js @@ -0,0 +1,185 @@ +const {ipcRenderer, nativeImage, remote, clipboard} = require('electron') +const md5 = require("md5"); +const rp = require("request-promise"); +const isChinese = require('is-chinese'); +const path = require('path'); +const fs = require('fs'); +const { spawn } = require ('child_process'); +const mineType = require("mime-types"); + +const opConfig = remote.getGlobal('opConfig'); + +new Vue({ + el: '#app', + data: { + code: '', + current: {}, + selectData: { + translate: {}, + optionPlugin: [], + }, + options: { + translate: [], + common: [ + { + type: 'default', + name: '终端中打开', + icon: './assets/terminal.png', + click: (fileUrl) => { + spawn('open', [ '-a', 'Terminal', fileUrl ]); + } + }, + { + type: 'default', + name: '新建文件', + icon: './assets/new.png', + click: (fileUrl) => { + remote.dialog.showSaveDialog({ + title: "请选择要保存的文件名", + buttonLabel: "保存", + defaultPath: fileUrl.replace('file://', ''), + showsTagField: false, + nameFieldLabel: '', + }).then(result => { + fs.writeFileSync(result.filePath, ''); + }); + } + }, + { + type: 'default', + name: '复制当前路径', + icon: './assets/link.png', + click: (fileUrl) => { + clipboard.writeText(fileUrl.replace('file://', '')) + } + } + ], + selected: [ + { + type: 'default', + name: '复制当前路径', + icon: './assets/link.png', + click: (fileUrl) => { + clipboard.writeText(fileUrl.replace('file://', '')) + } + } + ] + }, + targetOptions: [], + }, + created() { + // 简单唤起超级面板 + ipcRenderer.on('trigger-super-panel', (e, args) => { + this.selectData = args; + const ext = path.extname(this.selectData.fileUrl); + // 剪切板只有文本时,显示翻译 + if (!this.selectData.fileUrl) { + const word = this.selectData.text; + const isCh = isChinese(word); + this.translate(word, isCh ? 'en' : 'zh'); + this.targetOptions = this.options.translate; + } else if (!ext || path.parse(this.selectData.fileUrl).base === 'Desktop') { + // 如果在桌面上或者没有选择任何文件,则展示通用选项 + this.targetOptions = this.options.common; + } else { + // 有文件选择 + this.targetOptions = JSON.parse(JSON.stringify(this.options.selected)); + // 检测上传 + (this.selectData.optionPlugin || []).forEach(plugin => { + plugin.features.forEach(fe => { + fe.cmds.forEach(cmd => { + // 如果是图片,则唤起图片选项 + const regImg = /\.(png|jpg|gif|jpeg|webp)$/; + if (cmd.type === 'img' && regImg.test(ext)) { + console.log(plugin); + this.targetOptions.push({ + type: 'ext', + name: cmd.label, + icon: plugin.icon, + click: (fileUrl) => { + const base64 = this.fileToBase64(fileUrl); + ipcRenderer.send('superPanel-openPlugin', { + cmd: cmd, + plugin: plugin, + feature: fe, + data: base64, + }); + } + }) + } + // 如果是文件,且符合文件正则类型 + if (cmd.type === 'file' && new RegExp(cmd.match).test(ext)) { + this.targetOptions.push({ + type: 'ext', + name: cmd.label, + icon: '', + click: () => { + ipcRenderer.send('superPanel-openPlugin', { + cmd: cmd, + plugin: plugin, + feature: fe, + data: { + isFile: true, + isDirectory: false, + name: path.basename(this.selectData.fileUrl), + path: this.selectData.fileUrl + } + }) + } + }) + } + }) + }); + }); + } + }); + + }, + + methods: { + translate(msg, to) { + const {appid, key} = opConfig.get().superPanel.baiduAPI; + if (!appid || !key) return; + const q = msg; + const salt = parseInt(Math.random() * 1000000000); //加盐 + const sign = md5(appid + q + salt + key); //生成签名 + const params = encodeURI( + `q=${q}&from=auto&to=${to}&appid=${appid}&salt=${salt}&sign=${sign}` + ); + const options = { + uri: `https://fanyi-api.baidu.com/api/trans/vip/translate?${params}`, + }; + return rp(options).then((res) => { + this.$set(this.selectData, 'translate', JSON.parse(res).trans_result) + }) + }, + commonClick(item, fileUrl) { + ipcRenderer.send('superPanel-hidden') + item.click(fileUrl); + }, + + fileToBase64 (filePath) { + let data = fs.readFileSync(filePath.replace('file://', '')); + data = new Buffer(data).toString("base64"); + let base64 = "data:" + mineType.lookup(filePath) + ";base64," + data; + return base64; + }, + + openMainWindow() { + ipcRenderer.send('msg-trigger', { + type: 'showMainWindow', + }); + } + }, + + watch: { + selectData: { + deep: true, + handler() { + this.$nextTick(() => { + ipcRenderer.send('superPanel-setSize', parseInt(getComputedStyle(document.getElementById('app')).height)) + }) + } + } + } +}) diff --git a/static/preload.js b/static/preload.js index 1a0a552..090620e 100644 --- a/static/preload.js +++ b/static/preload.js @@ -43,16 +43,15 @@ function convertImgToBase64(url, callback, outputFormat){ window.utools = window.rubick = { // 事件 onPluginEnter(cb) { - ipcRenderer.once('onPluginEnter', (e, message) => { - const feature = JSON.parse(message.detail) - console.log(feature) - cb({...feature, type: 'text'}) + ipcRenderer.on('onPluginEnter', (e, message) => { + const feature = message.detail; + cb({...feature, type: message.cmd.type ? message.cmd.type : 'text', payload: message.payload}) }) }, onPluginReady(cb) { ipcRenderer.once('onPluginReady', (e, message) => { - const feature = JSON.parse(message.detail) - cb({...feature, type: 'text'}) + const feature = message.detail + cb({...feature, type: message.cmd.type ? message.cmd.type : 'text', payload: message.payload}) }) }, onPluginOut(cb) {