mirror of https://github.com/keeweb/keeweb.git
event listeners
This commit is contained in:
parent
1aa29237e2
commit
0dea89c0de
|
@ -4,6 +4,11 @@ import { Tip } from 'util/ui/tip';
|
|||
import { KeyHandler } from 'comp/browser/key-handler';
|
||||
import { Logger } from 'util/logger';
|
||||
|
||||
const OnlyDirectEvents = {
|
||||
mouseenter: true,
|
||||
mouseleave: true
|
||||
};
|
||||
|
||||
class View extends EventEmitter {
|
||||
parent = undefined;
|
||||
template = undefined;
|
||||
|
@ -13,7 +18,7 @@ class View extends EventEmitter {
|
|||
views = {};
|
||||
hidden = false;
|
||||
removed = false;
|
||||
boundEvents = [];
|
||||
eventListeners = {};
|
||||
debugLogger = localStorage.debugViews ? new Logger('view', this.constructor.name) : undefined;
|
||||
|
||||
constructor(model = undefined, options = {}) {
|
||||
|
@ -40,9 +45,7 @@ class View extends EventEmitter {
|
|||
Tip.destroyTips(this.el);
|
||||
}
|
||||
|
||||
this.unbindEvents();
|
||||
this.renderElement(templateData);
|
||||
this.bindEvents();
|
||||
|
||||
Tip.createTips(this.el);
|
||||
|
||||
|
@ -81,6 +84,7 @@ class View extends EventEmitter {
|
|||
this.el = root;
|
||||
parent.appendChild(this.el);
|
||||
}
|
||||
this.bindEvents();
|
||||
} else {
|
||||
throw new Error(
|
||||
`Error rendering ${this.constructor.name}: I don't know how to insert the view`
|
||||
|
@ -91,32 +95,56 @@ class View extends EventEmitter {
|
|||
}
|
||||
|
||||
bindEvents() {
|
||||
const eventsMap = {};
|
||||
for (const [eventDef, method] of Object.entries(this.events)) {
|
||||
const spaceIx = eventDef.indexOf(' ');
|
||||
let event, targets;
|
||||
let event, selector;
|
||||
if (spaceIx > 0) {
|
||||
event = eventDef.substr(0, spaceIx);
|
||||
const selector = eventDef.substr(spaceIx + 1);
|
||||
targets = this.el.querySelectorAll(selector);
|
||||
selector = eventDef.substr(spaceIx + 1);
|
||||
if (OnlyDirectEvents[event]) {
|
||||
throw new Error(
|
||||
`Event listener ${eventDef} defined in ${this.constructor.name} ` +
|
||||
`can be installed only on the view itself`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
event = eventDef;
|
||||
targets = [this.el];
|
||||
}
|
||||
for (const target of targets) {
|
||||
const listener = e => {
|
||||
this.debugLogger && this.debugLogger.debug('Listener', method);
|
||||
this[method](e);
|
||||
};
|
||||
target.addEventListener(event, listener);
|
||||
this.boundEvents.push({ target, event, listener });
|
||||
if (!eventsMap[event]) {
|
||||
eventsMap[event] = [];
|
||||
}
|
||||
eventsMap[event].push({ selector, method });
|
||||
}
|
||||
for (const [event, handlers] of Object.entries(eventsMap)) {
|
||||
this.debugLogger && this.debugLogger.debug('Bind', event, handlers);
|
||||
const listener = e => this.eventListener(e, handlers);
|
||||
this.eventListeners[event] = listener;
|
||||
this.el.addEventListener(event, listener);
|
||||
}
|
||||
}
|
||||
|
||||
unbindEvents() {
|
||||
for (const boundEvent of this.boundEvents) {
|
||||
const { target, event, listener } = boundEvent;
|
||||
target.removeEventListener(event, listener);
|
||||
for (const [event, listener] of Object.values(this.eventListeners)) {
|
||||
this.el.removeEventListener(event, listener);
|
||||
}
|
||||
}
|
||||
|
||||
eventListener(e, handlers) {
|
||||
this.debugLogger && this.debugLogger.debug('Listener fired', e.type);
|
||||
for (const { selector, method } of handlers) {
|
||||
if (selector) {
|
||||
const closest = e.target.closest(selector);
|
||||
if (!closest || !this.el.contains(closest)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!this[method]) {
|
||||
this.debugLogger && this.debugLogger.debug('Method not defined', method);
|
||||
continue;
|
||||
}
|
||||
this.debugLogger && this.debugLogger.debug('Handling event', e.type, method);
|
||||
this[method](e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -743,7 +743,7 @@ class AppView extends View {
|
|||
|
||||
dragover(e) {
|
||||
e.preventDefault();
|
||||
e.originalEvent.dataTransfer.dropEffect = 'none';
|
||||
e.dataTransfer.dropEffect = 'none';
|
||||
}
|
||||
|
||||
drop(e) {
|
||||
|
|
|
@ -727,7 +727,7 @@ class DetailsView extends View {
|
|||
dragover(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const dt = e.originalEvent.dataTransfer;
|
||||
const dt = e.dataTransfer;
|
||||
if (
|
||||
!dt.types ||
|
||||
(dt.types.indexOf ? dt.types.indexOf('Files') === -1 : !dt.types.contains('Files'))
|
||||
|
@ -765,7 +765,7 @@ class DetailsView extends View {
|
|||
}
|
||||
this.$el.find('.details').removeClass('details--drag');
|
||||
this.dragging = false;
|
||||
const files = e.target.files || e.originalEvent.dataTransfer.files;
|
||||
const files = e.target.files || e.dataTransfer.files;
|
||||
this.addAttachedFiles(files);
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ class FieldView extends View {
|
|||
if (!this.value) {
|
||||
return;
|
||||
}
|
||||
const dt = e.originalEvent.dataTransfer;
|
||||
const dt = e.dataTransfer;
|
||||
const txtval = this.value.isProtected ? this.value.getText() : this.value;
|
||||
if (this.valueEl[0].tagName.toLowerCase() === 'a') {
|
||||
dt.setData('text/uri-list', txtval);
|
||||
|
|
|
@ -265,8 +265,8 @@ class ListView extends View {
|
|||
const id = $(e.target)
|
||||
.closest('.list__item')
|
||||
.attr('id');
|
||||
e.originalEvent.dataTransfer.setData('text/entry', id);
|
||||
e.originalEvent.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData('text/entry', id);
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
DragDropInfo.dragObject = this.items.get(id);
|
||||
}
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ class MenuItemView extends View {
|
|||
}
|
||||
|
||||
dropAllowed(e) {
|
||||
const types = e.originalEvent.dataTransfer.types;
|
||||
const types = e.dataTransfer.types;
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
if (types[i] === 'text/group' || types[i] === 'text/entry') {
|
||||
return true;
|
||||
|
@ -190,8 +190,8 @@ class MenuItemView extends View {
|
|||
dragstart(e) {
|
||||
e.stopPropagation();
|
||||
if (this.model.get('drag')) {
|
||||
e.originalEvent.dataTransfer.setData('text/group', this.model.id);
|
||||
e.originalEvent.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData('text/group', this.model.id);
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
DragDropInfo.dragObject = this.model;
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ class MenuItemView extends View {
|
|||
}
|
||||
|
||||
dropTopAllowed(e) {
|
||||
const types = e.originalEvent.dataTransfer.types;
|
||||
const types = e.dataTransfer.types;
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
if (types[i] === 'text/group') {
|
||||
return true;
|
||||
|
|
|
@ -34,7 +34,7 @@ class OpenView extends View {
|
|||
'click .open__icon-more': 'toggleMore',
|
||||
'click .open__icon-storage': 'openStorage',
|
||||
'click .open__icon-settings': 'openSettings',
|
||||
'click .open__pass-input': 'passInputClick',
|
||||
'click .open__pass-input[readonly]': 'openFile',
|
||||
'input .open__pass-input': 'inputInput',
|
||||
'keydown .open__pass-input': 'inputKeydown',
|
||||
'keyup .open__pass-input': 'inputKeyup',
|
||||
|
@ -322,12 +322,6 @@ class OpenView extends View {
|
|||
});
|
||||
}
|
||||
|
||||
passInputClick(e) {
|
||||
if (e.target.readOnly) {
|
||||
this.openFile();
|
||||
}
|
||||
}
|
||||
|
||||
openFile() {
|
||||
if (this.model.settings.get('canOpen') === false) {
|
||||
return;
|
||||
|
@ -466,7 +460,7 @@ class OpenView extends View {
|
|||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const dt = e.originalEvent.dataTransfer;
|
||||
const dt = e.dataTransfer;
|
||||
if (
|
||||
!dt.types ||
|
||||
(dt.types.indexOf ? dt.types.indexOf('Files') === -1 : !dt.types.contains('Files'))
|
||||
|
@ -508,7 +502,7 @@ class OpenView extends View {
|
|||
}
|
||||
this.closeConfig();
|
||||
this.$el.removeClass('open--drag');
|
||||
const files = [...(e.target.files || e.originalEvent.dataTransfer.files)];
|
||||
const files = [...(e.target.files || e.dataTransfer.files)];
|
||||
const dataFile = files.find(file => /\.kdbx$/i.test(file.name));
|
||||
const keyFile = files.find(file => /\.key$/i.test(file.name));
|
||||
if (dataFile) {
|
||||
|
|
Loading…
Reference in New Issue