mirror of https://github.com/keeweb/keeweb.git
show auto-type view inside app window
This commit is contained in:
parent
6a4c6594a7
commit
d9a6de570f
|
@ -5,7 +5,7 @@ var Backbone = require('backbone'),
|
|||
AutoTypeHelperFactory = require('./auto-type-helper-factory'),
|
||||
Launcher = require('../comp/launcher'),
|
||||
Alerts = require('../comp/alerts'),
|
||||
AutoTypePopupView = require('../views/auto-type/auto-type-popup-view'),
|
||||
AutoTypeSelectView = require('../views/auto-type/auto-type-select-view'),
|
||||
Logger = require('../util/logger'),
|
||||
Locale = require('../util/locale'),
|
||||
Timeouts = require('../const/timeouts');
|
||||
|
@ -15,12 +15,14 @@ var clearTextAutoTypeLog = localStorage.autoTypeDebug;
|
|||
|
||||
var AutoType = {
|
||||
helper: AutoTypeHelperFactory.create(),
|
||||
|
||||
enabled: !!Launcher,
|
||||
selectEntryView: false,
|
||||
|
||||
selectEntryView: null,
|
||||
|
||||
init: function() {
|
||||
init: function(appModel) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
this.appModel = appModel;
|
||||
Backbone.on('auto-type', this.handleEvent.bind(this));
|
||||
},
|
||||
|
||||
|
@ -146,30 +148,36 @@ var AutoType = {
|
|||
|
||||
selectEntryAndRun: function() {
|
||||
this.getActiveWindowTitle((e, title, url) => {
|
||||
let entries = this.getMatchingEntries(title, url);
|
||||
let filter = { title, url };
|
||||
let entries = this.getMatchingEntries(filter);
|
||||
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 = new AutoTypeSelectView({
|
||||
model: {
|
||||
appModel: this.appModel,
|
||||
filter: filter
|
||||
}
|
||||
}).render();
|
||||
this.selectEntryView.on('result', result => {
|
||||
logger.debug('Entry selected', result);
|
||||
this.selectEntryView.off('result');
|
||||
this.selectEntryView.remove();
|
||||
this.selectEntryView = null;
|
||||
// this.hideWindow(() => { /* this.runAndHandleResult(e.result); */ });
|
||||
this.hideWindow(() => {
|
||||
if (result) {
|
||||
this.runAndHandleResult(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => Launcher.showMainWindow(), Timeouts.RedrawInactiveWindow);
|
||||
});
|
||||
},
|
||||
|
||||
getMatchingEntries: function() {
|
||||
return [];
|
||||
return this.appModel.getEntries(); // TODO
|
||||
}
|
||||
};
|
||||
|
||||
if (AutoType.enabled) {
|
||||
AutoType.init();
|
||||
}
|
||||
|
||||
module.exports = AutoType;
|
||||
|
|
|
@ -44,7 +44,6 @@ var KeyHandler = {
|
|||
if (keyShortcuts && keyShortcuts.length) {
|
||||
keyShortcuts.forEach(function(sh) {
|
||||
if (this.modal && !sh.modal) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
@ -74,6 +73,8 @@ var KeyHandler = {
|
|||
e.charCode !== Keys.DOM_VK_TAB &&
|
||||
!e.altKey && !e.ctrlKey && !e.metaKey) {
|
||||
this.trigger('keypress', e);
|
||||
} else if (this.modal) {
|
||||
this.trigger('keypress:' + this.modal, e);
|
||||
}
|
||||
},
|
||||
reg: function() {
|
||||
|
|
|
@ -113,8 +113,11 @@ if (window.process && window.process.versions && window.process.versions.electro
|
|||
updaterEnabled: function() {
|
||||
return this.electron().remote.process.argv.indexOf('--disable-updater') === -1;
|
||||
},
|
||||
getMainWindow: function() {
|
||||
return this.remoteApp().getMainWindow();
|
||||
},
|
||||
resolveProxy: function(url, callback) {
|
||||
var window = this.remoteApp().getMainWindow();
|
||||
var window = this.getMainWindow();
|
||||
var session = window.webContents.session;
|
||||
session.resolveProxy(url, proxy => {
|
||||
var match = /^proxy\s+([\w\.]+):(\d+)+\s*/i.exec(proxy);
|
||||
|
@ -133,15 +136,12 @@ if (window.process && window.process.versions && window.process.versions.electro
|
|||
app.hide();
|
||||
}
|
||||
},
|
||||
hideMainWindow: function() {
|
||||
this.remoteApp().getMainWindow().hide();
|
||||
},
|
||||
unhideMainWindow: function() {
|
||||
this.remoteApp().getMainWindow().showInactive();
|
||||
},
|
||||
isAppFocused: function() {
|
||||
return !!this.electron().remote.BrowserWindow.getFocusedWindow();
|
||||
},
|
||||
showMainWindow: function() {
|
||||
this.getMainWindow().show();
|
||||
},
|
||||
spawn: function(config) {
|
||||
var ts = logger.ts();
|
||||
var complete = config.complete;
|
||||
|
|
|
@ -9,7 +9,8 @@ var Timeouts = {
|
|||
CheckWindowClosed: 300,
|
||||
OtpFadeDuration: 10000,
|
||||
AutoTypeAfterHide: 100,
|
||||
DrobDownClickWait: 500
|
||||
DrobDownClickWait: 500,
|
||||
RedrawInactiveWindow: 50
|
||||
};
|
||||
|
||||
module.exports = Timeouts;
|
||||
|
|
|
@ -14,7 +14,8 @@ var Backbone = require('backbone'),
|
|||
Timeouts = require('../const/timeouts'),
|
||||
IdGenerator = require('../util/id-generator'),
|
||||
Logger = require('../util/logger'),
|
||||
FeatureDetector = require('../util/feature-detector');
|
||||
FeatureDetector = require('../util/feature-detector'),
|
||||
AutoType = require('../auto-type');
|
||||
|
||||
require('../mixins/protected-value-ex');
|
||||
|
||||
|
@ -39,6 +40,8 @@ var AppModel = Backbone.Model.extend({
|
|||
this.listenTo(Backbone, 'empty-trash', this.emptyTrash);
|
||||
|
||||
this.appLogger = new Logger('app');
|
||||
|
||||
AutoType.init(this);
|
||||
},
|
||||
|
||||
loadConfig: function(configLocation, callback) {
|
||||
|
@ -189,20 +192,23 @@ var AppModel = Backbone.Model.extend({
|
|||
},
|
||||
|
||||
getEntries: function() {
|
||||
var entries = new EntryCollection();
|
||||
var filter = this.prepareFilter();
|
||||
this.files.forEach(file => {
|
||||
file.forEachEntry(filter, (entry) => {
|
||||
entries.push(entry);
|
||||
});
|
||||
});
|
||||
let entries = this.getEntriesByFilter(filter);
|
||||
entries.sortEntries(this.sort);
|
||||
if (this.filter.trash) {
|
||||
if (filter.trash) {
|
||||
this.addTrashGroups(entries);
|
||||
}
|
||||
return entries;
|
||||
},
|
||||
|
||||
getEntriesByFilter: function(filter) {
|
||||
var entries = new EntryCollection();
|
||||
this.files.forEach(file => {
|
||||
file.forEachEntry(filter, entry => entries.push(entry));
|
||||
});
|
||||
return entries;
|
||||
},
|
||||
|
||||
addTrashGroups: function(collection) {
|
||||
this.files.forEach(file => {
|
||||
var trashGroup = file.getTrashGroup();
|
||||
|
|
|
@ -256,7 +256,7 @@ var Locale = {
|
|||
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',
|
||||
autoTypeHeader: 'Auto-Type: Select Entry',
|
||||
|
||||
appSecWarn: 'Not Secure!',
|
||||
appSecWarnBody1: 'You have loaded this app with insecure connection. ' +
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
'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;
|
|
@ -0,0 +1,62 @@
|
|||
'use strict';
|
||||
|
||||
const Backbone = require('backbone');
|
||||
const Keys = require('../../const/keys');
|
||||
const KeyHandler = require('../../comp/key-handler');
|
||||
|
||||
let AutoTypePopupView = Backbone.View.extend({
|
||||
el: 'body',
|
||||
|
||||
template: require('templates/auto-type/auto-type-select.hbs'),
|
||||
|
||||
events: {
|
||||
},
|
||||
|
||||
result: null,
|
||||
|
||||
initialize() {
|
||||
KeyHandler.onKey(Keys.DOM_VK_ESCAPE, this.escPressed, this, false, true);
|
||||
KeyHandler.onKey(Keys.DOM_VK_RETURN, this.enterPressed, this, false, true);
|
||||
KeyHandler.onKey(Keys.DOM_VK_UP, this.upPressed, this, false, true);
|
||||
KeyHandler.onKey(Keys.DOM_VK_DOWN, this.downPressed, this, false, true);
|
||||
KeyHandler.on('keypress:auto-type', this.keyPressed.bind(this));
|
||||
KeyHandler.setModal('auto-type');
|
||||
},
|
||||
|
||||
render() {
|
||||
this.renderTemplate(this.model);
|
||||
document.activeElement.blur();
|
||||
return this;
|
||||
},
|
||||
|
||||
remove() {
|
||||
KeyHandler.offKey(Keys.DOM_VK_ESCAPE, this.escPressed, this);
|
||||
KeyHandler.offKey(Keys.DOM_VK_RETURN, this.enterPressed, this);
|
||||
KeyHandler.offKey(Keys.DOM_VK_UP, this.upPressed, this);
|
||||
KeyHandler.offKey(Keys.DOM_VK_DOWN, this.downPressed, this);
|
||||
KeyHandler.off('keypress:auto-type');
|
||||
KeyHandler.setModal(null);
|
||||
Backbone.View.prototype.remove.apply(this, arguments);
|
||||
},
|
||||
|
||||
escPressed() {
|
||||
this.result = null;
|
||||
this.trigger('result', this.result);
|
||||
},
|
||||
|
||||
enterPressed() {
|
||||
this.trigger('result', this.result);
|
||||
},
|
||||
|
||||
upPressed() {
|
||||
},
|
||||
|
||||
downPressed() {
|
||||
},
|
||||
|
||||
keyPressed(e) {
|
||||
// let char = e.charCode;
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = AutoTypePopupView;
|
|
@ -21,13 +21,13 @@ var ModalView = Backbone.View.extend({
|
|||
if (typeof this.model.enter === 'string') {
|
||||
KeyHandler.onKey(Keys.DOM_VK_RETURN, this.enterPressed, this, false, true);
|
||||
}
|
||||
KeyHandler.setModal(true);
|
||||
KeyHandler.setModal('alert');
|
||||
},
|
||||
|
||||
remove: function() {
|
||||
KeyHandler.offKey(Keys.DOM_VK_ESCAPE, this.escPressed, this);
|
||||
KeyHandler.offKey(Keys.DOM_VK_RETURN, this.enterPressed, this);
|
||||
KeyHandler.setModal(false);
|
||||
KeyHandler.setModal(null);
|
||||
Backbone.View.prototype.remove.apply(this, arguments);
|
||||
},
|
||||
|
||||
|
@ -39,6 +39,7 @@ var ModalView = Backbone.View.extend({
|
|||
el.addClass('modal--hidden');
|
||||
setTimeout(() => {
|
||||
el.removeClass('modal--hidden');
|
||||
document.activeElement.blur();
|
||||
}, 20);
|
||||
return this;
|
||||
},
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
.at-popup {
|
||||
.at-select {
|
||||
@include position(absolute, 0 null null 0);
|
||||
@include size(100%);
|
||||
@include th { background-color: background-color(); }
|
||||
box-sizing: border-box;
|
||||
z-index: $z-index-no-modal;
|
||||
opacity: 1;
|
||||
padding: $base-padding;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<div class="at-select">
|
||||
<h1>{{res 'autoTypeHeader'}}</h1>
|
||||
</div>
|
|
@ -1,13 +0,0 @@
|
|||
<!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>
|
Loading…
Reference in New Issue