From cb4921a5af52153ff26774f9d7cd728e9eec88c1 Mon Sep 17 00:00:00 2001 From: Elliott Zheng Date: Fri, 1 Feb 2019 10:01:47 +0800 Subject: [PATCH] window controll system completed --- .eslintrc.js | 5 +- DeveloperGuide.md | 29 ++++++++ Developer_guide.md | 3 - package-lock.json | 83 ++++++++++++---------- package.json | 2 +- src/components/StatusBar.vue | 23 +----- src/components/WindowController.vue | 25 +++++++ src/core/controller.ts | 82 +++------------------- src/main.ts | 6 +- src/tools/ciba.ts | 43 ------------ src/tools/windowController.ts | 46 ++++++++++++ src/tools/windows.ts | 34 +++++++++ src/tools/youdao.ts | 105 ---------------------------- src/views/Contrast.vue | 32 ++++----- src/views/Focus.vue | 8 +-- src/views/GeneralConfig.vue | 0 src/views/ShortcutConfig.vue | 0 17 files changed, 215 insertions(+), 311 deletions(-) create mode 100644 DeveloperGuide.md delete mode 100644 Developer_guide.md create mode 100644 src/components/WindowController.vue delete mode 100644 src/tools/ciba.ts create mode 100644 src/tools/windowController.ts create mode 100644 src/tools/windows.ts delete mode 100644 src/tools/youdao.ts create mode 100644 src/views/GeneralConfig.vue create mode 100644 src/views/ShortcutConfig.vue diff --git a/.eslintrc.js b/.eslintrc.js index 41d4c0c4..a0d45c9a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,10 +3,11 @@ module.exports = { env: { node: true }, - extends: ["plugin:vue/essential", "@vue/prettier",'@vue/typescript'], + extends: ["plugin:vue/essential","@vue/prettier",'@vue/typescript'], rules: { "no-console": process.env.NODE_ENV === "production" ? "error" : "off", - "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" + "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", + "no-multiple-empty-lines":1 }, parserOptions: { parser: 'typescript-eslint-parser' diff --git a/DeveloperGuide.md b/DeveloperGuide.md new file mode 100644 index 00000000..5e0ae7f0 --- /dev/null +++ b/DeveloperGuide.md @@ -0,0 +1,29 @@ +## Project structure +- src + - core: anything about translation and string process + - tools: + + +## Conpoments +### BrowserWindow Control System +In main process +```ts +import { windowController } from "../tools/windowController"; +windowController.bind(); +``` +In render process + +```vue + + + +``` + + diff --git a/Developer_guide.md b/Developer_guide.md deleted file mode 100644 index 88755b37..00000000 --- a/Developer_guide.md +++ /dev/null @@ -1,3 +0,0 @@ -Project structure -- src - - core: anything about translation and string process \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4ef0a569..dd417944 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2315,6 +2315,11 @@ } } }, + "body-scroll-lock": { + "version": "2.6.1", + "resolved": "http://registry.npm.taobao.org/body-scroll-lock/download/body-scroll-lock-2.6.1.tgz", + "integrity": "sha1-N4L/N0BIhvqu42aWjO7kDDlk2PI=" + }, "bonjour": { "version": "3.5.0", "resolved": "http://registry.npm.taobao.org/bonjour/download/bonjour-3.5.0.tgz", @@ -3808,6 +3813,11 @@ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", "dev": true }, + "dayjs": { + "version": "1.8.0", + "resolved": "http://registry.npm.taobao.org/dayjs/download/dayjs-1.8.0.tgz", + "integrity": "sha1-UHljrDAj9LH585mieDVpRvxMmuk=" + }, "de-indent": { "version": "1.0.2", "resolved": "http://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz", @@ -5963,8 +5973,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5985,14 +5994,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6007,20 +6014,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -6137,8 +6141,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -6150,7 +6153,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6165,7 +6167,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6173,14 +6174,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -6199,7 +6198,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -6280,8 +6278,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -6293,7 +6290,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6379,8 +6375,7 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -6416,7 +6411,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6436,7 +6430,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6480,14 +6473,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -8065,6 +8056,11 @@ } } }, + "keycode": { + "version": "2.2.0", + "resolved": "http://registry.npm.taobao.org/keycode/download/keycode-2.2.0.tgz", + "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=" + }, "killable": { "version": "1.0.1", "resolved": "http://registry.npm.taobao.org/killable/download/killable-1.0.1.tgz", @@ -8786,6 +8782,18 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, + "muse-ui": { + "version": "3.0.1", + "resolved": "http://registry.npm.taobao.org/muse-ui/download/muse-ui-3.0.1.tgz", + "integrity": "sha1-bCLMQk81c7fI3cxaZi1A8uTIyuo=", + "requires": { + "body-scroll-lock": "^2.5.7", + "dayjs": "^1.6.5", + "keycode": "^2.1.9", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0" + } + }, "mute-stream": { "version": "0.0.7", "resolved": "http://registry.npm.taobao.org/mute-stream/download/mute-stream-0.0.7.tgz", @@ -8994,6 +9002,11 @@ "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=", "dev": true }, + "normalize-wheel": { + "version": "1.0.1", + "resolved": "http://registry.npm.taobao.org/normalize-wheel/download/normalize-wheel-1.0.1.tgz", + "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" + }, "npm-install-package": { "version": "2.1.0", "resolved": "http://registry.npm.taobao.org/npm-install-package/download/npm-install-package-2.1.0.tgz", @@ -10986,6 +10999,11 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "http://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ=" + }, "resolve": { "version": "1.9.0", "resolved": "http://registry.npm.taobao.org/resolve/download/resolve-1.9.0.tgz", @@ -13417,11 +13435,6 @@ "integrity": "sha1-3EJpcTMwLOMBdSQ1amxht7abShg=", "dev": true }, - "vuetify": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/vuetify/download/vuetify-1.4.1.tgz", - "integrity": "sha1-ncmdWfk81/aFhk8QBIxmBrjTgUU=" - }, "vuex": { "version": "3.0.1", "resolved": "http://registry.npm.taobao.org/vuex/download/vuex-3.0.1.tgz", diff --git a/package.json b/package.json index 3adce162..1f7b9d23 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,10 @@ "iohook": "^0.3.1", "lodash": "^4.17.11", "log4js": "^4.0.1", + "muse-ui": "^3.0.1", "translation.js": "^0.7.5", "vue": "^2.5.21", "vue-router": "^3.0.1", - "vuetify": "^1.4.1", "vuex": "^3.0.1" }, "devDependencies": { diff --git a/src/components/StatusBar.vue b/src/components/StatusBar.vue index 236f6324..691bf3b1 100644 --- a/src/components/StatusBar.vue +++ b/src/components/StatusBar.vue @@ -1,28 +1,11 @@ diff --git a/src/components/WindowController.vue b/src/components/WindowController.vue new file mode 100644 index 00000000..3a69dd8b --- /dev/null +++ b/src/components/WindowController.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/core/controller.ts b/src/core/controller.ts index 53ca269b..6e1d44e2 100644 --- a/src/core/controller.ts +++ b/src/core/controller.ts @@ -1,95 +1,32 @@ import { Translator, GoogleTranslator } from "../tools/translator"; -import { RuleName } from "../tools/rule"; import { initConfig, ConfigParser } from "../tools/configuration"; -import { BrowserWindow } from "electron"; -import { createProtocol } from "vue-cli-plugin-electron-builder/lib"; +import { MessageType } from "../tools/enums"; +import { WindowWrapper } from "../tools/windows"; +import { windowController } from "../tools/windowController"; const os = require("os"); const path = require("path"); const clipboard = require("electron-clipboard-extended"); const defaultConfigPath = path.join(os.homedir(), "copytranslator.json"); -const ioHook = require("iohook"); -const ipc = require("electron").ipcMain; -import { MessageType } from "../tools/enums"; class Controller { src: string = ""; result: string = ""; lastAppend: string = ""; - focusWin: BrowserWindow | null = null; + focusWin: WindowWrapper = new WindowWrapper(); translator: Translator = new GoogleTranslator(); config: ConfigParser; source: string = "English"; target: string = "Chinese(Simplified)"; - dragConfig = { - isFollow: false, - x: 0, - y: 0 - }; constructor() { this.config = initConfig(); this.config.loadValues(defaultConfigPath); this.setWatch(true); } - bindWindowEvent() { - ipc.on(MessageType.DragWindow.toString(), (event: any, arg: any) => { - this.dragConfig.isFollow = arg.status; - this.dragConfig.x = arg.x; - this.dragConfig.y = arg.y; - }); - ipc.on(MessageType.MinifyWindow.toString(), (event: any, arg: any) => { - if (this.focusWin) { - this.focusWin.minimize(); - } - }); - // ioHook.on("mousedown", (event: MouseEvent) => { - // if (this.focusWin) this.focusWin.webContents.send("news", event); - // }); - ioHook.on("mouseup", (event: MouseEvent) => { - this.dragConfig.isFollow = false; - }); - ioHook.on("mousedrag", (event: MouseEvent) => { - if (this.dragConfig.isFollow && this.focusWin && event.button === 0) { - let x_now = event.x; - let y_now = event.y; - let dx = x_now - this.dragConfig.x; - let dy = y_now - this.dragConfig.y; - this.dragConfig.x = x_now; - this.dragConfig.y = y_now; - let bounds = this.focusWin.getBounds(); - bounds.x += dx; - bounds.y += dy; - this.focusWin.setBounds(bounds); - } - }); - //注册的指令。send到主进程main.js中。 - // Register and start hook - ioHook.start(false); - } createWindow() { - // Create the browser window. - this.focusWin = new BrowserWindow({ - width: 800, - height: 600, - // transparent: true, - frame: false - }); - this.focusWin.setAlwaysOnTop(true); - - if (process.env.WEBPACK_DEV_SERVER_URL) { - // Load the url of the dev server if in development mode - this.focusWin.loadURL(process.env.WEBPACK_DEV_SERVER_URL); - if (!process.env.IS_TEST) this.focusWin.webContents.openDevTools(); - } else { - createProtocol("app"); - // Load the index.html when not in development - this.focusWin.loadURL("app://./index.html"); - } - - this.focusWin.on("closed", () => { - this.focusWin = null; - }); - this.bindWindowEvent(); + this.focusWin.createWindow(); + windowController.bind(); + this.checkClipboard(); } checkClipboard() { let text = clipboard.readText(); @@ -102,9 +39,6 @@ class Controller { onError(msg: string) { (global).log.error(msg); } - sendMsg(type: string, msg: any) { - if (this.focusWin) this.focusWin.webContents.send(type, msg); - } doTranslate(text: string) { this.src = text; this.translator @@ -112,7 +46,7 @@ class Controller { .then(res => { if (res) { this.result = res; - this.sendMsg(MessageType.TrnaslateResult.toString(), { + this.focusWin.sendMsg(MessageType.TrnaslateResult.toString(), { src: this.src, result: this.result, source: this.source, diff --git a/src/main.ts b/src/main.ts index 125bbb20..c2034cf7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,14 +2,14 @@ import Vue from "vue"; import App from "./App.vue"; import router from "./router"; import store from "./store"; -import Vuetify from "vuetify"; -import "vuetify/dist/vuetify.min.css"; +import MuseUI from "muse-ui"; import { ipcRenderer } from "electron"; import { MessageType } from "./tools/enums"; +import "muse-ui/dist/muse-ui.css"; var remote = require("electron").remote; -Vue.use(Vuetify); +Vue.use(MuseUI); Vue.prototype.$ipcRenderer = ipcRenderer; Vue.prototype.$log = remote.getGlobal("log"); diff --git a/src/tools/ciba.ts b/src/tools/ciba.ts deleted file mode 100644 index 25a3d6f8..00000000 --- a/src/tools/ciba.ts +++ /dev/null @@ -1,43 +0,0 @@ -// import axios from "axios"; - -// class CibaDict { -// constructor() {} -// async query(expression: string) { -// // Make a request for a user with a given ID -// try { -// let res = await axios.get( -// `http://open.iciba.com/huaci_v3/dict.php?word=${expression}` -// ); -// console.log(res.data); -// } catch (e) { -// console.log(e); -// } -// } -// /**金山词霸排版*/ -// static parseIciba(rst: string): any { -// try { -// rst = rst -// .replace(/class=\\"icIBahyI-prons\\"/g, "__mystyle__") // 音标 -// .replace(/\\"/g, '"') // 引号 -// // A标签 -// .replace(/]*)?>详细释义<\/a([^>]*)?>/g, "") -// .replace(/]*)?>/g, "") -// .replace(/<\/a([^>]*)?>/g, "") -// // 清理属性、标签、多余空格 -// .replace(/(?:class|id|style|xml:lang|lang)="([^"]*)"/g, "") -// .replace(/(?:label>|strong>)/g, "span>") -// .replace(/(?:)/g, "div>") -// .replace(/[ ]+/g, " ") -// // 音标 -// .replace(/__mystyle__/g, ' style="color:#777;"'); -// var match = /dict.innerHTML='(.*)?';/g.exec(rst); -// return (match)[1]; -// } catch (error) { -// console.log(error); -// return error; -// } -// } -// } - -// export { CibaDict }; diff --git a/src/tools/windowController.ts b/src/tools/windowController.ts new file mode 100644 index 00000000..becaec87 --- /dev/null +++ b/src/tools/windowController.ts @@ -0,0 +1,46 @@ +import { BrowserWindow } from "electron"; +const ioHook = require("iohook"); +const ipc = require("electron").ipcMain; +import { MessageType } from "./enums"; + +class WindowController { + x: number = 0; + y: number = 0; + isFollow: boolean = false; + currentWindow: BrowserWindow | undefined = undefined; + bind() { + ipc.on(MessageType.DragWindow.toString(), (event: any, arg: any) => { + this.currentWindow = BrowserWindow.fromWebContents(event.sender); + this.isFollow = arg.status; + this.x = arg.x; + this.y = arg.y; + }); + ipc.on(MessageType.MinifyWindow.toString(), (event: any, arg: any) => { + BrowserWindow.fromWebContents(event.sender).minimize(); + }); + ioHook.on("mouseup", (event: MouseEvent) => { + this.isFollow = false; + this.currentWindow = undefined; + }); + ioHook.on("mousedrag", (event: MouseEvent) => { + if (this.isFollow && this.currentWindow && event.button === 0) { + let x_now = event.x; + let y_now = event.y; + let dx = x_now - this.x; + let dy = y_now - this.y; + this.x = x_now; + this.y = y_now; + let bounds = this.currentWindow.getBounds(); + bounds.x += dx; + bounds.y += dy; + this.currentWindow.setBounds(bounds); + } + }); + //注册的指令。send到主进程main.js中。 + // Register and start hook + ioHook.start(false); + } +} + +let windowController = new WindowController(); +export { windowController }; diff --git a/src/tools/windows.ts b/src/tools/windows.ts new file mode 100644 index 00000000..d5f12e30 --- /dev/null +++ b/src/tools/windows.ts @@ -0,0 +1,34 @@ +import { BrowserWindow } from "electron"; +import { createProtocol } from "vue-cli-plugin-electron-builder/lib"; + +class WindowWrapper { + window: BrowserWindow | undefined = undefined; + constructor() {} + sendMsg(type: string, msg: any) { + if (this.window) this.window.webContents.send(type, msg); + } + createWindow() { + // Create the browser window. + this.window = new BrowserWindow({ + width: 800, + height: 600, + frame: false + }); + + if (process.env.WEBPACK_DEV_SERVER_URL) { + // Load the url of the dev server if in development mode + this.window.loadURL(process.env.WEBPACK_DEV_SERVER_URL); + if (!process.env.IS_TEST) this.window.webContents.openDevTools(); + } else { + createProtocol("app"); + // Load the index.html when not in development + this.window.loadURL("app://./index.html"); + } + + this.window.on("closed", () => { + this.window = undefined; + }); + } +} + +export { WindowWrapper }; diff --git a/src/tools/youdao.ts b/src/tools/youdao.ts deleted file mode 100644 index 320c700e..00000000 --- a/src/tools/youdao.ts +++ /dev/null @@ -1,105 +0,0 @@ -// import axios from "axios"; -// import cheerio from "cheerio"; -// import { YoudaoStatus } from "./enums"; - -// class YoudaoSpider { -// async query(expression: string) { -// try { -// let res = await axios.get( -// `http://dict.youdao.com/w/eng/${expression}/#keyfrom=dict2.index` -// ); -// return YoudaoSpider.parseHtml(expression, res.data); -// } catch (e) { -// console.log(e); -// return { -// status: YoudaoStatus.Fail -// }; -// } -// } -// static parseHtml(word: string, html: string): Object { -// /* -// 解析web版有道的网页 -// :param html:网页内容 -// :return:result -// */ -// let result: { [key: string]: any } = { -// query: "", -// errorCode: YoudaoStatus.Success -// }; -// const $ = cheerio.load(html); - -// let root = $("#results-contents"); - -// // query 搜索的关键字 -// let keyword = root.find(".keyword").first(); -// if (keyword == null) { -// result["query"] = word; -// } else { -// result["query"] = keyword.text(); -// } -// // 基本解释 -// let basic = root.find("#phrsListTab").first(); -// if (basic) { -// let trans = basic.find(".trans-container"); - -// if (trans) { -// result["basic"] = {}; -// result["basic"]["explains"] = trans -// .find("li") -// .map((i: number, el) => { -// return $(el).text(); -// }) -// .get(); - -// // 中文 -// if (result["basic"]["explains"].length == 0) { -// result["basic"]["explains"] = trans -// .find(".wordGroup") -// .map(function(i, el) { -// return $(el).text(); -// }) -// .get() -// .join(" "); -// } -// // 音标 -// let phons = basic -// .find(".phonetic") -// .map((i: number, el) => { -// return $(el).text(); -// }) -// .get(); -// if (phons.length == 2) { -// result["basic"]["uk-phonetic"] = phons[0]; -// result["basic"]["us-phonetic"] = phons[1]; -// } else if (phons.length == 1) { -// result["basic"]["phonetic"] = phons[0]; -// } -// } -// } -// // 网络释义(短语) -// let web = root.find("#webPhrase"); -// if (web) { -// result["web"] = web -// .find(".wordGroup") -// .map((i: number, wordGroup) => { -// let text = $(wordGroup) -// .find(".search-js") -// .first() -// .text(); -// return { -// key: text, -// value: $(wordGroup) -// .text() -// .replace(text, "") -// .replace(/ {2,}/g, "") -// .replace(/[\r\n\t]/g, "") -// .replace(/\|{2,}/g, "") -// }; -// }) -// .get(); -// } -// return result; -// } -// } - -// export { YoudaoSpider }; diff --git a/src/views/Contrast.vue b/src/views/Contrast.vue index d1f78d54..1990639a 100644 --- a/src/views/Contrast.vue +++ b/src/views/Contrast.vue @@ -1,25 +1,18 @@ @@ -37,6 +30,7 @@ export default { }, data: () => { return { + lang: undefined, languages: ["1", "2"] }; } diff --git a/src/views/Focus.vue b/src/views/Focus.vue index 0753316d..cb2e213e 100644 --- a/src/views/Focus.vue +++ b/src/views/Focus.vue @@ -1,12 +1,8 @@ diff --git a/src/views/GeneralConfig.vue b/src/views/GeneralConfig.vue new file mode 100644 index 00000000..e69de29b diff --git a/src/views/ShortcutConfig.vue b/src/views/ShortcutConfig.vue new file mode 100644 index 00000000..e69de29b