mirror of https://github.com/keeweb/keeweb.git
auto-type popup
This commit is contained in:
parent
8cd5d2b1d7
commit
6a4c6594a7
|
@ -1,9 +1,13 @@
|
|||
'use strict';
|
||||
|
||||
var AutoTypeParser = require('./auto-type-parser'),
|
||||
var Backbone = require('backbone'),
|
||||
AutoTypeParser = require('./auto-type-parser'),
|
||||
AutoTypeHelperFactory = require('./auto-type-helper-factory'),
|
||||
Launcher = require('../comp/launcher'),
|
||||
Alerts = require('../comp/alerts'),
|
||||
AutoTypePopupView = require('../views/auto-type/auto-type-popup-view'),
|
||||
Logger = require('../util/logger'),
|
||||
Locale = require('../util/locale'),
|
||||
Timeouts = require('../const/timeouts');
|
||||
|
||||
var logger = new Logger('auto-type');
|
||||
|
@ -14,6 +18,43 @@ var AutoType = {
|
|||
|
||||
enabled: !!Launcher,
|
||||
|
||||
selectEntryView: null,
|
||||
|
||||
init: function() {
|
||||
Backbone.on('auto-type', this.handleEvent.bind(this));
|
||||
},
|
||||
|
||||
handleEvent: function(e) {
|
||||
let entry = e && entry || null;
|
||||
logger.debug('Auto type event', entry);
|
||||
if (entry) {
|
||||
this.hideWindow(() => { this.runAndHandleResult(entry); });
|
||||
} else {
|
||||
if (this.selectEntryView) {
|
||||
return;
|
||||
}
|
||||
if (Launcher.isAppFocused()) {
|
||||
return Alerts.error({
|
||||
header: Locale.autoTypeError,
|
||||
body: Locale.autoTypeErrorGlobal,
|
||||
skipIfAlertDisplayed: true
|
||||
});
|
||||
}
|
||||
this.selectEntryAndRun();
|
||||
}
|
||||
},
|
||||
|
||||
runAndHandleResult: function(entry) {
|
||||
this.run(entry, err => {
|
||||
if (err) {
|
||||
Alerts.error({
|
||||
header: Locale.autoTypeError,
|
||||
body: Locale.autoTypeErrorGeneric.replace('{}', err.toString())
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
run: function(entry, callback) {
|
||||
var sequence = entry.getEffectiveAutoTypeSeq();
|
||||
logger.debug('Start', sequence);
|
||||
|
@ -83,7 +124,8 @@ var AutoType = {
|
|||
|
||||
hideWindow: function(callback) {
|
||||
logger.debug('Hide window');
|
||||
if (Launcher.hideWindowIfActive()) {
|
||||
if (Launcher.isAppFocused()) {
|
||||
Launcher.hideApp();
|
||||
setTimeout(callback, Timeouts.AutoTypeAfterHide);
|
||||
} else {
|
||||
callback();
|
||||
|
@ -98,9 +140,36 @@ var AutoType = {
|
|||
} else {
|
||||
logger.debug('Window title', title, url);
|
||||
}
|
||||
return callback(err, title);
|
||||
return callback(err, title, url);
|
||||
});
|
||||
},
|
||||
|
||||
selectEntryAndRun: function() {
|
||||
this.getActiveWindowTitle((e, title, url) => {
|
||||
let entries = this.getMatchingEntries(title, url);
|
||||
if (entries.length === 1) {
|
||||
this.runAndHandleResult(entries[0]);
|
||||
return;
|
||||
}
|
||||
Launcher.hideMainWindow();
|
||||
this.selectEntryView = new AutoTypePopupView().render();
|
||||
this.selectEntryView.on('closed', e => {
|
||||
Launcher.unhideMainWindow();
|
||||
Launcher.hideApp();
|
||||
logger.debug('Popup closed', e.result);
|
||||
this.selectEntryView = null;
|
||||
// this.hideWindow(() => { /* this.runAndHandleResult(e.result); */ });
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getMatchingEntries: function() {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
if (AutoType.enabled) {
|
||||
AutoType.init();
|
||||
}
|
||||
|
||||
module.exports = AutoType;
|
||||
|
|
|
@ -14,6 +14,9 @@ var Alerts = {
|
|||
},
|
||||
|
||||
alert: function(config) {
|
||||
if (config.skipIfAlertDisplayed && Alerts.alertDisplayed) {
|
||||
return null;
|
||||
}
|
||||
Alerts.alertDisplayed = true;
|
||||
var view = new ModalView({ model: config });
|
||||
view.render();
|
||||
|
|
|
@ -125,19 +125,22 @@ if (window.process && window.process.versions && window.process.versions.electro
|
|||
openWindow: function(opts) {
|
||||
return this.remoteApp().openWindow(opts);
|
||||
},
|
||||
hideWindowIfActive: function() {
|
||||
hideApp: function() {
|
||||
var app = this.remoteApp();
|
||||
var win = app.getMainWindow();
|
||||
var visible = win.isVisible(), focused = win.isFocused();
|
||||
if (!visible || !focused) {
|
||||
return false;
|
||||
}
|
||||
if (process.platform === 'darwin') {
|
||||
app.hide();
|
||||
if (this.canMinimize()) {
|
||||
app.getMainWindow().minimize();
|
||||
} else {
|
||||
win.minimize();
|
||||
app.hide();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
hideMainWindow: function() {
|
||||
this.remoteApp().getMainWindow().hide();
|
||||
},
|
||||
unhideMainWindow: function() {
|
||||
this.remoteApp().getMainWindow().showInactive();
|
||||
},
|
||||
isAppFocused: function() {
|
||||
return !!this.electron().remote.BrowserWindow.getFocusedWindow();
|
||||
},
|
||||
spawn: function(config) {
|
||||
var ts = logger.ts();
|
||||
|
|
|
@ -253,6 +253,10 @@ var Locale = {
|
|||
autoTypeModifiers: 'Modifier keys',
|
||||
autoTypeKeys: 'Keys',
|
||||
autoTypeLink: 'more...',
|
||||
autoTypeError: 'Auto-type error',
|
||||
autoTypeErrorGeneric: 'There was an error performing auto-type: {}',
|
||||
autoTypeErrorGlobal: 'To use system-wide shortcut, please focus the app where you want to type your password',
|
||||
autoTypePopup: 'KeeWeb: Auto Type',
|
||||
|
||||
appSecWarn: 'Not Secure!',
|
||||
appSecWarnBody1: 'You have loaded this app with insecure connection. ' +
|
||||
|
|
|
@ -16,13 +16,17 @@ var ThemeChanger = {
|
|||
document.body.classList.remove(cls);
|
||||
}
|
||||
});
|
||||
document.body.classList.add('th-' + theme);
|
||||
document.body.classList.add(this.getThemeClass(theme));
|
||||
var metaThemeColor = document.head.querySelector('meta[name=theme-color]');
|
||||
if (metaThemeColor) {
|
||||
metaThemeColor.content = window.getComputedStyle(document.body).backgroundColor;
|
||||
}
|
||||
},
|
||||
|
||||
getThemeClass: function(theme) {
|
||||
return 'th-' + theme;
|
||||
},
|
||||
|
||||
setFontSize: function(fontSize) {
|
||||
document.documentElement.style.fontSize = fontSize ? (12 + fontSize * 2) + 'px' : '';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
'use strict';
|
||||
|
||||
const Backbone = require('backbone');
|
||||
const Launcher = require('../../comp/launcher');
|
||||
const Locale = require('../../util/locale');
|
||||
const ThemeChanger = require('../../util/theme-changer');
|
||||
const Keys = require('../../const/keys');
|
||||
const AppSettingsModel = require('../../models/app-settings-model');
|
||||
|
||||
class AutoTypePopupView {
|
||||
constructor() {
|
||||
this.template = require('templates/auto-type/popup.hbs');
|
||||
this.popupWindow = null;
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
render() {
|
||||
let themeClass = ThemeChanger.getThemeClass(AppSettingsModel.instance.get('theme'));
|
||||
let styleSheet = document.styleSheets[0];
|
||||
let css = styleSheet.ownerNode.textContent;
|
||||
if (!css) {
|
||||
// dev mode, external stylesheet
|
||||
css = _.map(styleSheet.rules, rule => rule.cssText).join('\n');
|
||||
}
|
||||
let html = this.template({
|
||||
themeClass: themeClass,
|
||||
css: css
|
||||
});
|
||||
|
||||
this.popupWindow = Launcher.openWindow({
|
||||
show: false,
|
||||
width: 600,
|
||||
minWidth: 600,
|
||||
height: 300,
|
||||
minHeight: 300,
|
||||
minimizable: false,
|
||||
maximizable: false,
|
||||
alwaysOnTop: true,
|
||||
fullscreenable: false,
|
||||
title: Locale.autoTypePopup,
|
||||
modal: true
|
||||
// icon: TODO
|
||||
});
|
||||
this.popupWindow.on('closed', () => this.remove());
|
||||
this.popupWindow.on('blur', () => this.popupWindow.close());
|
||||
this.popupWindow.on('ready-to-show', () => this.popupWindow.show());
|
||||
this.popupWindow.loadURL('data:text/html;charset=utf-8,' + encodeURI(html));
|
||||
this.popupWindow.webContents.executeJavaScript('(' + this.init.toString() + ')()');
|
||||
|
||||
Backbone.on('auto-type-popup-keydown', e => this.keydown(e));
|
||||
Backbone.on('auto-type-popup-keypress', e => this.keypress(e));
|
||||
Backbone.on('auto-type-popup-select', e => this.select(e));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (this.popupWindow) {
|
||||
this.popupWindow = null;
|
||||
Backbone.off('auto-type-popup-keydown');
|
||||
Backbone.off('auto-type-popup-keypress');
|
||||
Backbone.off('auto-type-popup-select');
|
||||
this.trigger('closed', { result: this.result });
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
// note: this function will be executed in popup
|
||||
function emitBackboneEvent(name, arg) {
|
||||
window.require('electron').remote.app.emitBackboneEvent('auto-type-popup-' + name, arg);
|
||||
}
|
||||
document.body.addEventListener('keydown', e => {
|
||||
emitBackboneEvent('keydown', {keyCode: e.keyCode});
|
||||
});
|
||||
document.body.addEventListener('keypress', e => {
|
||||
emitBackboneEvent('keypress', {keyCode: e.keyCode, text: e.key});
|
||||
});
|
||||
}
|
||||
|
||||
keydown(e) {
|
||||
if (e.keyCode === Keys.DOM_VK_ESCAPE) {
|
||||
return this.popupWindow.close();
|
||||
} else if (e.keyCode === Keys.DOM_VK_ENTER || e.keyCode === Keys.DOM_VK_RETURN) {
|
||||
this.result = 'entry';
|
||||
return this.popupWindow.close();
|
||||
}
|
||||
}
|
||||
|
||||
keypress(e) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
select(e) {
|
||||
this.result = e.result;
|
||||
}
|
||||
}
|
||||
|
||||
_.extend(AutoTypePopupView.prototype, Backbone.Events);
|
||||
|
||||
module.exports = AutoTypePopupView;
|
|
@ -67,7 +67,6 @@ var DetailsView = Backbone.View.extend({
|
|||
this.initScroll();
|
||||
this.listenTo(Backbone, 'select-entry', this.showEntry);
|
||||
this.listenTo(Backbone, 'copy-password', this.copyPassword);
|
||||
this.listenTo(Backbone, 'auto-type', this.autoTypeGlobal);
|
||||
this.listenTo(Backbone, 'copy-user', this.copyUserName);
|
||||
this.listenTo(Backbone, 'copy-url', this.copyUrl);
|
||||
this.listenTo(Backbone, 'toggle-settings', this.settingsToggled);
|
||||
|
@ -794,17 +793,7 @@ var DetailsView = Backbone.View.extend({
|
|||
},
|
||||
|
||||
autoType: function() {
|
||||
var entry = this.model;
|
||||
// AutoType.getActiveWindowTitle(function() {
|
||||
// console.log(arguments);
|
||||
// });
|
||||
AutoType.hideWindow(() => {
|
||||
AutoType.run(entry);
|
||||
});
|
||||
},
|
||||
|
||||
autoTypeGlobal: function() {
|
||||
// TODO
|
||||
Backbone.emit('auto-type', { entry: this.model });
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.at-popup {
|
||||
padding: $base-padding;
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
@import "common/tip";
|
||||
|
||||
@import "areas/app";
|
||||
@import "areas/auto-type";
|
||||
@import "areas/details";
|
||||
@import "areas/footer";
|
||||
@import "areas/grp";
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{res 'autoTypePopup'}}</title>
|
||||
<style>{{{css}}}</style>
|
||||
</head>
|
||||
<body class="{{themeClass}} at-popup">
|
||||
Hello!
|
||||
{{res 'autoTypePopup'}}
|
||||
<button class="btn-silent">Select</button>
|
||||
</body>
|
||||
</html>
|
|
@ -24,6 +24,6 @@
|
|||
<div><span class="shortcut {{#if globalIsLarge}}shortcut-large{{/if}}">{{{global}}}C</span> {{res 'setShCopyPassGlobal'}}</div>
|
||||
<div><span class="shortcut {{#if globalIsLarge}}shortcut-large{{/if}}">{{{global}}}B</span> {{res 'setShCopyUserGlobal'}}</div>
|
||||
<div><span class="shortcut {{#if globalIsLarge}}shortcut-large{{/if}}">{{{global}}}U</span> {{res 'setShCopyUrlGlobal'}}</div>
|
||||
{{!--<div><span class="shortcut {{#if globalIsLarge}}shortcut-large{{/if}}">{{{global}}}T</span> {{res 'setShAutoTypeGlobal'}}</div>--}}
|
||||
<div><span class="shortcut {{#if globalIsLarge}}shortcut-large{{/if}}">{{{global}}}T</span> {{res 'setShAutoTypeGlobal'}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -88,6 +88,7 @@ app.minimizeApp = function () {
|
|||
app.getMainWindow = function () {
|
||||
return mainWindow;
|
||||
};
|
||||
app.emitBackboneEvent = emitBackboneEvent;
|
||||
|
||||
function checkSingleInstance() {
|
||||
var shouldQuit = app.makeSingleInstance((/* commandLine, workingDirectory */) => {
|
||||
|
@ -112,6 +113,7 @@ function createMainWindow() {
|
|||
});
|
||||
setMenu();
|
||||
mainWindow.loadURL('file://' + htmlPath);
|
||||
mainWindow.setContentProtection(true);
|
||||
mainWindow.webContents.on('dom-ready', () => {
|
||||
setTimeout(() => {
|
||||
mainWindow.show();
|
||||
|
@ -215,8 +217,9 @@ function restoreMainWindowPosition() {
|
|||
});
|
||||
}
|
||||
|
||||
function emitBackboneEvent(e) {
|
||||
mainWindow.webContents.executeJavaScript('Backbone.trigger("' + e + '");');
|
||||
function emitBackboneEvent(e, arg) {
|
||||
arg = JSON.stringify(arg);
|
||||
mainWindow.webContents.executeJavaScript(`Backbone.trigger('${e}', ${arg});`);
|
||||
}
|
||||
|
||||
function setMenu() {
|
||||
|
|
Loading…
Reference in New Issue