diff --git a/README.md b/README.md
index 9b99f95..00b54c9 100644
--- a/README.md
+++ b/README.md
@@ -25,15 +25,18 @@ Google Translate网页版的封装,通过[Electron](https://www.electronjs.org
* 允许配置默认主窗口尺寸;
* Mini窗口自动获取输入焦点;
* 支持开机启动;
+* 允许Mini窗口隐藏时保持活跃以快速响应;
* 不支持离线使用;
* 不支持取词划词;
* 未测试Windows之外的平台;
-对于Mini窗口自动获取输入焦点,由于是通过`dom-ready`事件注入JavaScript实现,因此在`dom-ready`之前Mini窗口无法自动获取焦点。而这需要大概十几秒,因为`translate.google.cn`尝试从`google.com`获取一些资源,而访问google.com会等待超时后失败(国内环境),但这些资源并不是完成翻译功能所必须的,因此并不影响翻译功能的使用。但未完成的非ajax请求会让`dom-ready`事件迟迟不能触发,导致依赖此事件注入JavaScript的代码直到请求超时后才执行。
+对于Mini窗口自动获取输入焦点和自动清除输入,由于是通过`dom-ready`事件注入JavaScript实现,因此在`dom-ready`之后才能生效。而这需要大概十几秒,因为`translate.google.cn`尝试从`google.com`获取一些资源,而访问google.com会等待超时后失败(国内环境),但这些资源并不是完成翻译功能所必须的,因此并不影响翻译功能的使用。但未完成的非ajax请求会让`dom-ready`事件迟迟不能触发,导致依赖此事件注入JavaScript的代码直到请求超时后才执行。
但这只在程序启动时发生,个人认为勉强能够忍受,就没有再折腾。如果有必要,或许可以通过`ServiceWorker`拦截?
+另外,在此期间,对于0.2版本可能会出现输入内容离奇消失的情况(每次运行周期最多出现一次)。这是因为程序在Mini窗口隐藏时自动清除输入,但由于注入的JS代码需要`dom-ready`事件后才执行,所以清除输入的代码可能会在不合适的时机被执行。但至多只可能发生一次。
+
对于封装的url,本程序仅对translate.google.cn做了样式微调,如果换成其它的url,可能需要自行调整样式。配置项中允许更改url参数来加载其他网页。如果需要,还可以通过提供额外CSS来调整样式,它们将被注入页面,见[配置项](##配置项)。
注意,你可能需要为你的样式加上!important标记以覆盖更高优先级的原始样式,因为CSS以嵌入式CSS的方式插入。
@@ -72,14 +75,18 @@ Mini窗口的大小是固定的,想要修改只能修改代码。为了在更
| extraCssForMini | string | "" | 额外插入Mini窗口的的CSS
| minimizeToTrayWhenClose | boolean | true | 关闭主窗口时最小化到托盘
| minimizeToTrayWenStart | boolean | true | 启动时自动隐藏主窗口
+| keepActiveInterval | number | 60000 | 自动操作Mini窗口以使其保持活跃的周期,单位ms,最低1000,为0禁止
## 使用截图
-
+主窗口
+
-
+Mini窗口
+
+
diff --git a/src/config.js b/src/config.js
index 46a8f6c..8661222 100644
--- a/src/config.js
+++ b/src/config.js
@@ -14,6 +14,7 @@ const config = {
extraCssForMini: '',
minimizeToTrayWhenClose: true,
minimizeToTrayWenStart: true,
+ keepActiveInterval: 60000
};
try {
diff --git a/src/index.js b/src/index.js
index 86b7749..05b68fc 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,7 +1,7 @@
const path = require('path');
const { app, globalShortcut, BrowserWindow, Menu, Tray } = require('electron');
-const createMiniWindow = require('./mini');
-const createMainWindow = require('./main');
+const { createMiniWindow, toggleMiniWindowVisibility } = require('./mini');
+const { createMainWindow, toggleMainWindowVisibility } = require('./main');
const getMenu = require('./menu');
const { config, flushConfig } = require('./config');
const toast = require('./notify');
@@ -36,12 +36,14 @@ app.on('ready', () => {
mainWindow.on('hide', () => {
if (miniWindow) {
miniWindow.setParentWindow(mainWindow);
+ miniWindow.setSkipTaskbar(false);
}
});
//主窗口显示时如果mini窗口的父窗口是主窗口,mini窗口获得焦点时父窗口也会弹出来。。emm又没找到其他靠谱的方法
mainWindow.on('show', () => {
if (miniWindow) {
miniWindow.setParentWindow(null);
+ miniWindow.setSkipTaskbar(true);
}
});
if (!config.minimizeToTrayWenStart) {
@@ -59,10 +61,7 @@ app.on('ready', () => {
});
function registerMiniWindow() {
- // if (!config.miniWindowEnabled) {
- // return;
- // }
- miniWindow = createMiniWindow();
+ miniWindow = createMiniWindow();
miniWindow.setParentWindow(mainWindow);
const miniMenu = getMenu(mainWindow, miniWindow, miniWindow);
miniWindow.setMenu(miniMenu);
@@ -74,8 +73,8 @@ function registerMiniWindow() {
function setupTray() {
tray = new Tray(path.resolve(__dirname, 'assets/icon.ico'));
const contextMenu = Menu.buildFromTemplate([
- { label: "显示主界面", click: () => toggleMainWindowVisibility() },
- { label: "显示Mini窗口", click: () => toggleMiniWindowVisibility() },
+ { label: "显示主界面", click: () => toggleMainWindowVisibility(mainWindow) },
+ { label: "显示Mini窗口", click: () => toggleMiniWindowVisibility(miniWindow) },
{
type: 'checkbox',
label: "开机启动",
@@ -91,7 +90,7 @@ function setupTray() {
{ label: "退出", click: () => app.exit() }
]);
tray.setToolTip("Google Translate Desktop");
- tray.on('click', () => toggleMainWindowVisibility());
+ tray.on('click', () => toggleMainWindowVisibility(mainWindow));
tray.setContextMenu(contextMenu);
}
@@ -124,7 +123,7 @@ function toggleMiniShortcut(initial) {
let enabled = initial ? config.miniWindowEnabled : !config.miniWindowEnabled;
let success = true;
if (enabled) {
- if (!globalShortcut.register(config.miniShortcut, () => toggleMiniWindowVisibility())) {
+ if (!globalShortcut.register(config.miniShortcut, () => toggleMiniWindowVisibility(miniWindow))) {
toast.show("快捷键注册失败,请检查设置的快捷键是否被其他软件占用。", "错误", {
type: 'error'
});
@@ -142,25 +141,3 @@ function toggleMiniShortcut(initial) {
}
return enabled;
}
-
-function toggleMiniWindowVisibility() {
- if (!miniWindow) { return; }
- if (miniWindow.isVisible()) {
- miniWindow.hide();
- }
- else {
- miniWindow.show();
- miniWindow.focus();
- }
-}
-
-function toggleMainWindowVisibility() {
- if (!mainWindow) { return; }
- if (mainWindow.isVisible()) {
- mainWindow.hide();
- }
- else {
- mainWindow.show();
- mainWindow.focus();
- }
-}
diff --git a/src/main.js b/src/main.js
index 8c0baf0..1ee6ef6 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,6 +1,5 @@
const path = require('path');
const { BrowserWindow } = require('electron');
-const getMenu = require('./menu');
const { config } = require('./config');
function createMainWindow() {
@@ -36,4 +35,19 @@ function createMainWindow() {
return win;
}
-module.exports = createMainWindow;
\ No newline at end of file
+function toggleMainWindowVisibility(window) {
+ if (!window) { return; }
+ if (window.isVisible()) {
+ window.hide();
+ }
+ else {
+ window.show();
+ window.focus();
+ }
+}
+
+
+module.exports = {
+ createMainWindow,
+ toggleMainWindowVisibility
+}
\ No newline at end of file
diff --git a/src/mini.js b/src/mini.js
index dc42d9f..2df06a0 100644
--- a/src/mini.js
+++ b/src/mini.js
@@ -1,8 +1,14 @@
const path = require('path');
const { BrowserWindow } = require('electron');
-const getMenu = require('./menu');
const { config } = require('./config');
+const miniControl = {
+ /** 迷你窗口是否处于可视区域 */
+ isMiniWindowVisible: true,
+ previousPos: null
+}
+
+
function createMiniWindow () {
let miniWindow = new BrowserWindow({
width: 500,
@@ -22,7 +28,8 @@ function createMiniWindow () {
maximizable: true,
alwaysOnTop: true,
fullscreenable: false,
- skipTaskbar: true,
+ skipTaskbar: false,
+
});
miniWindow.on('focus', () => {
@@ -33,28 +40,11 @@ function createMiniWindow () {
});
miniWindow.on('close', ev => {
ev.preventDefault();
- miniWindow.hide();
+ toggleMiniWindowVisibility(miniWindow);
});
miniWindow.loadURL(config.url);
miniWindow.webContents.on('dom-ready', () => {
- miniWindow.webContents.executeJavaScript(`
- setTimeout(() => {
- console.log('throw');
- throw('crashed');
- }, 10000);
- var source = document.getElementById('source');
- if (source) {
- document.addEventListener('visibilitychange', () => {
- if (document.visibilityState === 'hidden') {
- source.value = '';
- }
- else {
- source.focus();
- }
- });
- }
- `);
miniWindow.webContents.insertCSS(`
/* 隐藏通知,文本/文件切换栏 */
.container .input-button-container,
@@ -62,8 +52,9 @@ function createMiniWindow () {
display: none !important;
}
/* mini窗口隐藏header和历史记录按钮和拼音 */
- .tlid-source-transliteration-container.source-transliteration-container,
- header.gb_sa.gb_2a.gb_5e.gb_ta, .gp-footer {
+ header,
+ .gp-footer,
+ .tlid-source-transliteration-container.source-transliteration-container {
display: none !important;
}
/* 防止高度较小时出现双滚动条 */
@@ -103,8 +94,64 @@ function createMiniWindow () {
miniWindow.insertCSS(config.extraCssForMini);
}
});
-
+ miniControl.previousPos = miniWindow.getPosition();
+ toggleMiniWindowVisibility(miniWindow);
+ miniWindow.show();
+ let interval = config.keepActiveInterval | 0;
+ if (miniWindow && interval !== 0) {
+ interval = Math.max(1000, interval);
+ setInterval(() => {
+ if (!miniControl.isMiniWindowVisible) {
+ miniWindow.webContents.executeJavaScript(`
+ var source = document.getElementById('source');
+ if (source) {
+ source.value = source.value;
+ }
+ `);
+ }
+ }, interval);
+ }
return miniWindow;
}
-module.exports = createMiniWindow;
+function toggleMiniWindowVisibility(window) {
+ if (!window) { return; }
+ miniControl.isMiniWindowVisible = !miniControl.isMiniWindowVisible;
+ if (miniControl.isMiniWindowVisible) {
+ if (miniControl.previousPos) {
+ window.setPosition(...miniControl.previousPos);
+ }
+ else {
+ window.show();
+ }
+ focusInput(window);
+ window.focus();
+ }
+ else {
+ miniControl.previousPos = window.getPosition();
+ window.setPosition(-1000, -1000, false);
+ clearInput(window);
+ }
+}
+
+function clearInput(window) {
+ window.webContents.executeJavaScript(`
+ var source = document.getElementById('source');
+ if (source) {
+ source.value = '';
+ }
+ `);
+}
+function focusInput (window) {
+ window.webContents.executeJavaScript(`
+ var source = document.getElementById('source');
+ if (source) {
+ source.focus();
+ }
+ `);
+}
+
+module.exports = {
+ createMiniWindow,
+ toggleMiniWindowVisibility
+}