keeweb/app/scripts/views/app-view.js

856 lines
27 KiB
JavaScript
Raw Normal View History

2019-09-16 20:42:33 +02:00
import { View } from 'framework/views/view';
2019-09-16 22:57:56 +02:00
import { Events } from 'framework/events';
2019-09-15 14:16:32 +02:00
import { IdleTracker } from 'comp/browser/idle-tracker';
import { KeyHandler } from 'comp/browser/key-handler';
import { Launcher } from 'comp/launcher';
import { SettingsManager } from 'comp/settings/settings-manager';
import { Alerts } from 'comp/ui/alerts';
import { Keys } from 'const/keys';
import { UpdateModel } from 'models/update-model';
import { Features } from 'util/features';
import { Locale } from 'util/locale';
2019-09-25 23:24:38 +02:00
import { Logger } from 'util/logger';
import { CsvParser } from 'util/data/csv-parser';
2019-09-15 14:16:32 +02:00
import { DetailsView } from 'views/details/details-view';
import { DragView } from 'views/drag-view';
import { DropdownView } from 'views/dropdown-view';
import { FooterView } from 'views/footer-view';
import { GeneratorPresetsView } from 'views/generator-presets-view';
import { GrpView } from 'views/grp-view';
import { KeyChangeView } from 'views/key-change-view';
import { ListView } from 'views/list-view';
import { ListWrapView } from 'views/list-wrap-view';
import { MenuView } from 'views/menu/menu-view';
import { OpenView } from 'views/open-view';
import { SettingsView } from 'views/settings/settings-view';
import { TagView } from 'views/tag-view';
2019-09-25 23:24:38 +02:00
import { ImportCsvView } from 'views/import-csv-view';
2019-09-16 17:43:57 +02:00
import template from 'templates/app.hbs';
2017-01-31 07:50:28 +01:00
2019-09-16 17:43:57 +02:00
class AppView extends View {
parent = 'body';
2015-10-17 23:49:24 +02:00
2019-09-16 17:43:57 +02:00
template = template;
2015-10-17 23:49:24 +02:00
2019-09-16 17:43:57 +02:00
events = {
contextmenu: 'contextMenu',
drop: 'drop',
dragenter: 'dragover',
dragover: 'dragover',
2015-11-17 22:49:12 +01:00
'click a[target=_blank]': 'extLinkClick',
2019-09-16 17:43:57 +02:00
mousedown: 'bodyClick'
};
2015-10-17 23:49:24 +02:00
2019-09-16 17:43:57 +02:00
titlebarStyle = 'default';
2015-10-17 23:49:24 +02:00
2019-09-16 17:43:57 +02:00
constructor(model) {
super(model);
this.views.menu = new MenuView(this.model.menu, { ownParent: true });
2019-09-15 21:22:23 +02:00
this.views.menuDrag = new DragView('x', { parent: '.app__menu-drag' });
2019-09-16 17:58:44 +02:00
this.views.footer = new FooterView(this.model, { ownParent: true });
this.views.listWrap = new ListWrapView(this.model, { ownParent: true });
this.views.list = new ListView(this.model, { ownParent: true });
2019-09-15 21:22:23 +02:00
this.views.listDrag = new DragView('x', { parent: '.app__list-drag' });
2015-11-21 15:55:42 +01:00
this.views.list.dragView = this.views.listDrag;
2019-09-16 19:24:15 +02:00
this.views.details = new DetailsView(undefined, { ownParent: true });
2015-10-17 23:49:24 +02:00
this.views.details.appModel = this.model;
this.views.menu.listenDrag(this.views.menuDrag);
this.views.list.listenDrag(this.views.listDrag);
2019-09-17 19:50:42 +02:00
this.titlebarStyle = this.model.settings.titlebarStyle;
2015-10-17 23:49:24 +02:00
this.listenTo(this.model.settings, 'change:theme', this.setTheme);
2016-08-21 23:12:49 +02:00
this.listenTo(this.model.settings, 'change:locale', this.setLocale);
this.listenTo(this.model.settings, 'change:fontSize', this.setFontSize);
this.listenTo(this.model.settings, 'change:autoSaveInterval', this.setupAutoSave);
2019-09-17 21:39:06 +02:00
this.listenTo(this.model.files, 'change', this.fileListUpdated);
2015-10-17 23:49:24 +02:00
2019-09-16 22:57:56 +02:00
this.listenTo(Events, 'select-all', this.selectAll);
this.listenTo(Events, 'menu-select', this.menuSelect);
this.listenTo(Events, 'lock-workspace', this.lockWorkspace);
this.listenTo(Events, 'show-file', this.showFileSettings);
this.listenTo(Events, 'open-file', this.toggleOpenFile);
this.listenTo(Events, 'save-all', this.saveAll);
this.listenTo(Events, 'remote-key-changed', this.remoteKeyChanged);
this.listenTo(Events, 'key-change-pending', this.keyChangePending);
this.listenTo(Events, 'toggle-settings', this.toggleSettings);
this.listenTo(Events, 'toggle-menu', this.toggleMenu);
this.listenTo(Events, 'toggle-details', this.toggleDetails);
this.listenTo(Events, 'edit-group', this.editGroup);
this.listenTo(Events, 'edit-tag', this.editTag);
this.listenTo(Events, 'edit-generator-presets', this.editGeneratorPresets);
this.listenTo(Events, 'launcher-open-file', this.launcherOpenFile);
this.listenTo(Events, 'user-idle', this.userIdle);
this.listenTo(Events, 'os-lock', this.osLocked);
this.listenTo(Events, 'power-monitor-suspend', this.osLocked);
this.listenTo(Events, 'app-minimized', this.appMinimized);
this.listenTo(Events, 'show-context-menu', this.showContextMenu);
this.listenTo(Events, 'second-instance', this.showSingleInstanceAlert);
this.listenTo(Events, 'enter-full-screen', this.enterFullScreen);
this.listenTo(Events, 'leave-full-screen', this.leaveFullScreen);
2019-09-25 23:24:38 +02:00
this.listenTo(Events, 'import-csv-requested', this.showImportCsv);
this.listenTo(Events, 'launcher-before-quit', this.launcherBeforeQuit);
2019-09-25 23:24:38 +02:00
this.listenTo(UpdateModel, 'change:updateReady', this.updateApp);
2015-10-17 23:49:24 +02:00
window.onbeforeunload = this.beforeUnload.bind(this);
window.onresize = this.windowResize.bind(this);
2016-09-05 21:14:50 +02:00
window.onblur = this.windowBlur.bind(this);
2015-10-17 23:49:24 +02:00
2019-09-16 17:43:57 +02:00
this.onKey(Keys.DOM_VK_ESCAPE, this.escPressed);
this.onKey(Keys.DOM_VK_BACK_SPACE, this.backspacePressed);
if (Launcher && Launcher.devTools) {
2019-09-16 19:09:57 +02:00
this.onKey(
Keys.DOM_VK_I,
this.openDevTools,
KeyHandler.SHORTCUT_ACTION + KeyHandler.SHORTCUT_OPT,
'*'
);
}
2017-02-05 15:05:45 +01:00
this.setWindowClass();
this.setupAutoSave();
2019-09-16 17:43:57 +02:00
}
2017-02-05 15:05:45 +01:00
2019-08-18 10:17:09 +02:00
setWindowClass() {
2019-09-15 08:11:11 +02:00
const getBrowserCssClass = Features.getBrowserCssClass();
2017-05-25 21:37:04 +02:00
if (getBrowserCssClass) {
2019-09-16 19:09:57 +02:00
document.body.classList.add(getBrowserCssClass);
2017-02-05 15:05:45 +01:00
}
if (this.titlebarStyle !== 'default') {
2019-09-16 19:09:57 +02:00
document.body.classList.add('titlebar-' + this.titlebarStyle);
}
if (Features.isMobile) {
document.body.classList.add('mobile');
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
render() {
2019-09-16 17:43:57 +02:00
super.render({
beta: this.model.isBeta,
titlebarStyle: this.titlebarStyle
});
2016-08-13 21:13:16 +02:00
this.panelEl = this.$el.find('.app__panel:first');
2019-09-15 23:08:36 +02:00
this.views.listWrap.render();
2019-09-16 17:43:57 +02:00
this.views.menu.render();
2019-09-15 21:22:23 +02:00
this.views.menuDrag.render();
2019-09-15 18:33:45 +02:00
this.views.footer.render();
2019-09-16 17:43:57 +02:00
this.views.list.render();
2019-09-15 21:22:23 +02:00
this.views.listDrag.render();
2019-09-16 19:24:15 +02:00
this.views.details.render();
2015-12-06 21:32:41 +01:00
this.showLastOpenFile();
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
showOpenFile() {
2016-07-30 11:25:22 +02:00
this.hideContextMenu();
2015-10-17 23:49:24 +02:00
this.views.menu.hide();
this.views.menuDrag.hide();
2015-11-21 15:55:42 +01:00
this.views.listWrap.hide();
2015-10-17 23:49:24 +02:00
this.views.list.hide();
this.views.listDrag.hide();
this.views.details.hide();
this.views.footer.toggle(this.model.files.hasOpenFiles());
2016-08-13 21:13:16 +02:00
this.hidePanelView();
2015-10-17 23:49:24 +02:00
this.hideSettings();
this.hideOpenFile();
this.hideKeyChange();
2019-09-25 23:24:38 +02:00
this.hideImportCsv();
2019-09-16 17:43:57 +02:00
this.views.open = new OpenView(this.model);
this.views.open.render();
this.views.open.on('close', () => {
2019-10-12 08:20:44 +02:00
this.showEntries();
});
this.views.open.on('remove', () => {
2019-09-16 22:57:56 +02:00
Events.emit('closed-open-view');
2019-09-16 17:43:57 +02:00
});
}
2015-12-06 21:32:41 +01:00
2019-08-18 10:17:09 +02:00
showLastOpenFile() {
2015-12-06 21:32:41 +01:00
this.showOpenFile();
2019-09-17 21:39:06 +02:00
const lastOpenFile = this.model.fileInfos[0];
2015-12-06 21:32:41 +01:00
if (lastOpenFile) {
this.views.open.currentSelectedIndex = 0;
2015-12-06 21:32:41 +01:00
this.views.open.showOpenFileInfo(lastOpenFile);
2015-10-24 21:06:44 +02:00
}
2019-09-16 17:43:57 +02:00
}
2015-10-24 21:06:44 +02:00
2019-08-18 10:17:09 +02:00
launcherOpenFile(file) {
if (file && file.data && /\.kdbx$/i.test(file.data)) {
2015-12-06 21:32:41 +01:00
this.showOpenFile();
this.views.open.showOpenLocalFile(file.data, file.key);
2015-10-24 21:06:44 +02:00
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
updateApp() {
2019-09-18 07:12:06 +02:00
if (UpdateModel.updateStatus === 'ready' && !Launcher && !this.model.files.hasOpenFiles()) {
window.location.reload();
2015-10-29 22:20:01 +01:00
}
2019-09-16 17:43:57 +02:00
}
2015-10-29 22:20:01 +01:00
2019-08-18 10:17:09 +02:00
showEntries() {
2015-10-17 23:49:24 +02:00
this.views.menu.show();
this.views.menuDrag.show();
2015-11-21 15:55:42 +01:00
this.views.listWrap.show();
2015-10-17 23:49:24 +02:00
this.views.list.show();
this.views.listDrag.show();
this.views.details.show();
this.views.footer.show();
2016-08-13 21:13:16 +02:00
this.hidePanelView();
2015-10-17 23:49:24 +02:00
this.hideOpenFile();
this.hideSettings();
this.hideKeyChange();
2019-09-25 23:24:38 +02:00
this.hideImportCsv();
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
hideOpenFile() {
2015-10-17 23:49:24 +02:00
if (this.views.open) {
this.views.open.remove();
this.views.open = null;
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
hidePanelView() {
2016-08-13 21:13:16 +02:00
if (this.views.panel) {
this.views.panel.remove();
this.views.panel = null;
this.panelEl.addClass('hide');
}
2019-09-16 17:43:57 +02:00
}
2016-08-13 21:13:16 +02:00
2019-08-18 10:17:09 +02:00
showPanelView(view) {
2016-08-13 21:13:16 +02:00
this.views.listWrap.hide();
this.views.list.hide();
this.views.listDrag.hide();
this.views.details.hide();
this.hidePanelView();
2019-09-15 18:33:45 +02:00
view.render();
this.views.panel = view;
2016-08-13 21:13:16 +02:00
this.panelEl.removeClass('hide');
2019-09-16 17:43:57 +02:00
}
2016-08-13 21:13:16 +02:00
2019-08-18 10:17:09 +02:00
hideSettings() {
2015-10-17 23:49:24 +02:00
if (this.views.settings) {
this.model.menu.setMenu('app');
this.views.settings.remove();
this.views.settings = null;
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
hideKeyChange() {
if (this.views.keyChange) {
this.views.keyChange.hide();
this.views.keyChange = null;
}
2019-09-16 17:43:57 +02:00
}
2019-09-25 23:24:38 +02:00
hideImportCsv() {
if (this.views.importCsv) {
this.views.importCsv.remove();
this.views.importCsv = null;
}
}
2019-08-18 10:17:09 +02:00
showSettings(selectedMenuItem) {
2015-10-17 23:49:24 +02:00
this.model.menu.setMenu('settings');
this.views.menu.show();
this.views.menuDrag.show();
2015-11-21 15:55:42 +01:00
this.views.listWrap.hide();
2015-10-17 23:49:24 +02:00
this.views.list.hide();
this.views.listDrag.hide();
this.views.details.hide();
2016-08-13 21:13:16 +02:00
this.hidePanelView();
2015-10-17 23:49:24 +02:00
this.hideOpenFile();
this.hideKeyChange();
2019-09-25 23:24:38 +02:00
this.hideImportCsv();
2019-09-16 23:19:54 +02:00
this.views.settings = new SettingsView(this.model);
2019-09-16 20:40:20 +02:00
this.views.settings.render();
2015-10-17 23:49:24 +02:00
if (!selectedMenuItem) {
2019-09-18 23:37:57 +02:00
selectedMenuItem = this.model.menu.generalSection.items[0];
2015-10-17 23:49:24 +02:00
}
this.model.menu.select({ item: selectedMenuItem });
2015-10-26 22:07:19 +01:00
this.views.menu.switchVisibility(false);
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
showEditGroup(group) {
2019-09-15 18:33:45 +02:00
this.showPanelView(new GrpView(group));
2019-09-16 17:43:57 +02:00
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
showEditTag() {
2019-09-15 18:33:45 +02:00
this.showPanelView(new TagView(this.model));
2019-09-16 17:43:57 +02:00
}
2016-04-17 22:02:39 +02:00
2019-08-18 10:17:09 +02:00
showKeyChange(file, viewConfig) {
2016-07-03 18:46:43 +02:00
if (Alerts.alertDisplayed) {
return;
}
if (this.views.keyChange && this.views.keyChange.model.remote) {
return;
}
2016-03-27 18:38:21 +02:00
this.hideSettings();
2016-08-13 21:13:16 +02:00
this.hidePanelView();
this.views.menu.hide();
this.views.listWrap.hide();
this.views.list.hide();
this.views.listDrag.hide();
this.views.details.hide();
2016-07-03 18:46:43 +02:00
this.views.keyChange = new KeyChangeView({
2019-09-16 07:13:56 +02:00
file,
expired: viewConfig.expired,
remote: viewConfig.remote
2016-07-03 18:46:43 +02:00
});
2019-09-16 07:13:56 +02:00
this.views.keyChange.render();
this.views.keyChange.on('accept', this.keyChangeAccept.bind(this));
this.views.keyChange.on('cancel', this.showEntries.bind(this));
2019-09-16 17:43:57 +02:00
}
2019-08-18 10:17:09 +02:00
fileListUpdated() {
2015-10-17 23:49:24 +02:00
if (this.model.files.hasOpenFiles()) {
this.showEntries();
} else {
this.showOpenFile();
this.selectLastOpenFile();
2015-10-17 23:49:24 +02:00
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
showFileSettings(e) {
2020-06-01 16:53:51 +02:00
const menuItem = this.model.menu.filesSection.items.find(
(item) => item.file.id === e.fileId
);
2015-10-17 23:49:24 +02:00
if (this.views.settings) {
2019-09-18 23:37:57 +02:00
if (this.views.settings.file === menuItem.file) {
2015-10-17 23:49:24 +02:00
this.showEntries();
} else {
this.model.menu.select({ item: menuItem });
}
} else {
this.showSettings(menuItem);
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
toggleOpenFile() {
2015-10-17 23:49:24 +02:00
if (this.views.open) {
2016-04-07 18:36:34 +02:00
if (this.model.files.hasOpenFiles()) {
this.showEntries();
}
2015-10-17 23:49:24 +02:00
} else {
this.showOpenFile();
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
launcherBeforeQuit() {
// this is currently called only on macos
const event = {
fromBeforeQuit: true,
preventDefault() {}
};
const result = this.beforeUnload(event);
if (result !== false) {
Launcher.exit();
}
}
2019-08-18 10:17:09 +02:00
beforeUnload(e) {
2019-08-16 23:05:39 +02:00
const exitEvent = {
preventDefault() {
this.prevented = true;
}
};
2019-09-16 22:57:56 +02:00
Events.emit('main-window-will-close', exitEvent);
if (exitEvent.prevented) {
return Launcher ? Launcher.preventExit(e) : false;
}
let minimizeInsteadOfClose = this.model.settings.minimizeOnClose;
if (e.fromBeforeQuit) {
if (Launcher.quitOnRealQuitEventIfMinimizeOnQuitIsEnabled()) {
minimizeInsteadOfClose = false;
}
}
2015-12-12 09:53:50 +01:00
if (this.model.files.hasDirtyFiles()) {
2017-01-31 07:50:28 +01:00
const exit = () => {
if (minimizeInsteadOfClose) {
Launcher.minimizeApp();
} else {
Launcher.exit();
}
};
2017-11-26 19:13:48 +01:00
if (Launcher && Launcher.exitRequested) {
return;
}
if (Launcher) {
2015-11-14 12:09:36 +01:00
if (!this.exitAlertShown) {
2019-09-17 19:50:42 +02:00
if (this.model.settings.autoSave) {
2020-06-01 16:53:51 +02:00
this.saveAndLock((result) => {
2019-08-16 23:05:39 +02:00
if (result) {
exit();
}
});
2016-02-22 07:59:50 +01:00
return Launcher.preventExit(e);
2016-01-13 19:18:45 +01:00
}
2016-07-17 13:30:38 +02:00
this.exitAlertShown = true;
2015-11-14 12:09:36 +01:00
Alerts.yesno({
2015-12-17 19:25:25 +01:00
header: Locale.appUnsavedWarn,
body: Locale.appUnsavedWarnBody,
2016-01-13 19:18:45 +01:00
buttons: [
2019-08-16 23:05:39 +02:00
{ result: 'save', title: Locale.saveChanges },
{ result: 'exit', title: Locale.discardChanges, error: true },
{ result: '', title: Locale.appDontExitBtn }
2016-01-13 19:18:45 +01:00
],
2020-06-01 16:53:51 +02:00
success: (result) => {
2016-01-13 19:18:45 +01:00
if (result === 'save') {
2020-06-01 16:53:51 +02:00
this.saveAndLock((result) => {
2019-08-16 23:05:39 +02:00
if (result) {
exit();
}
});
2016-01-13 19:18:45 +01:00
} else {
exit();
2016-01-13 19:18:45 +01:00
}
2015-11-14 12:09:36 +01:00
},
2016-07-17 13:30:38 +02:00
cancel: () => {
2015-11-14 12:09:36 +01:00
Launcher.cancelRestart(false);
},
2016-07-17 13:30:38 +02:00
complete: () => {
this.exitAlertShown = false;
2015-11-14 12:09:36 +01:00
}
});
}
return Launcher.preventExit(e);
2015-11-04 07:16:39 +01:00
}
2016-01-13 19:18:45 +01:00
return Locale.appUnsavedWarnBody;
2019-08-16 23:05:39 +02:00
} else if (
Launcher &&
!Launcher.exitRequested &&
!Launcher.restartPending &&
minimizeInsteadOfClose
2019-08-16 23:05:39 +02:00
) {
2015-11-21 08:29:49 +01:00
Launcher.minimizeApp();
return Launcher.preventExit(e);
2015-10-17 23:49:24 +02:00
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
windowResize() {
2019-09-16 22:57:56 +02:00
Events.emit('page-geometry', { source: 'window' });
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
windowBlur(e) {
2016-09-05 21:14:50 +02:00
if (e.target === window) {
2019-09-16 22:57:56 +02:00
Events.emit('page-blur');
2016-09-05 21:14:50 +02:00
}
2019-09-16 17:43:57 +02:00
}
2016-09-05 21:14:50 +02:00
2019-08-18 10:17:09 +02:00
enterFullScreen() {
this.$el.addClass('fullscreen');
2019-09-16 17:43:57 +02:00
}
2019-08-18 10:17:09 +02:00
leaveFullScreen() {
this.$el.removeClass('fullscreen');
2019-09-16 17:43:57 +02:00
}
2019-08-18 10:17:09 +02:00
escPressed() {
2015-10-17 23:49:24 +02:00
if (this.views.open && this.model.files.hasOpenFiles()) {
this.showEntries();
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
backspacePressed(e) {
2015-10-17 23:49:24 +02:00
if (e.target === document.body) {
e.preventDefault();
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
openDevTools() {
2016-03-19 12:37:52 +01:00
if (Launcher && Launcher.devTools) {
Launcher.openDevTools();
}
2019-09-16 17:43:57 +02:00
}
2016-03-19 12:37:52 +01:00
2019-08-18 10:17:09 +02:00
selectAll() {
2019-09-18 23:37:57 +02:00
this.menuSelect({ item: this.model.menu.allItemsSection.items[0] });
2019-09-16 17:43:57 +02:00
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
menuSelect(opt) {
2015-10-31 20:09:32 +01:00
this.model.menu.select(opt);
2016-08-13 21:13:16 +02:00
if (this.views.panel && !this.views.panel.isHidden()) {
2015-10-31 20:09:32 +01:00
this.showEntries();
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
userIdle() {
2015-11-17 23:31:13 +01:00
this.lockWorkspace(true);
2019-09-16 17:43:57 +02:00
}
2015-11-17 23:31:13 +01:00
2019-08-18 10:17:09 +02:00
osLocked() {
2019-09-17 19:50:42 +02:00
if (this.model.settings.lockOnOsLock) {
2017-06-02 20:16:09 +02:00
this.lockWorkspace(true);
}
2019-09-16 17:43:57 +02:00
}
2017-06-02 20:16:09 +02:00
2019-08-18 10:17:09 +02:00
appMinimized() {
2019-09-17 19:50:42 +02:00
if (this.model.settings.lockOnMinimize) {
this.lockWorkspace(true);
}
2019-09-16 17:43:57 +02:00
}
2019-08-18 10:17:09 +02:00
lockWorkspace(autoInit) {
2015-11-21 07:49:39 +01:00
if (Alerts.alertDisplayed) {
2015-11-18 19:33:04 +01:00
return;
}
2015-10-25 10:19:00 +01:00
if (this.model.files.hasUnsavedFiles()) {
2019-09-17 19:50:42 +02:00
if (this.model.settings.autoSave) {
2016-01-13 19:18:45 +01:00
this.saveAndLock();
2015-11-17 21:57:32 +01:00
} else {
2017-01-31 07:50:28 +01:00
const message = autoInit ? Locale.appCannotLockAutoInit : Locale.appCannotLock;
2015-11-17 21:57:32 +01:00
Alerts.alert({
icon: 'lock',
header: 'Lock',
body: message,
2015-11-17 21:57:32 +01:00
buttons: [
2016-08-23 22:20:13 +02:00
{ result: 'save', title: Locale.saveChanges },
{ result: 'discard', title: Locale.discardChanges, error: true },
2015-12-17 19:25:25 +01:00
{ result: '', title: Locale.alertCancel }
2015-11-17 21:57:32 +01:00
],
2015-12-17 19:25:25 +01:00
checkbox: Locale.appAutoSave,
2016-07-17 13:30:38 +02:00
success: (result, autoSaveChecked) => {
2015-11-17 21:57:32 +01:00
if (result === 'save') {
if (autoSaveChecked) {
2019-09-17 19:50:42 +02:00
this.model.settings.autoSave = autoSaveChecked;
2015-11-17 21:57:32 +01:00
}
2016-07-17 13:30:38 +02:00
this.saveAndLock();
2015-11-17 21:57:32 +01:00
} else if (result === 'discard') {
2016-07-17 13:30:38 +02:00
this.model.closeAllFiles();
2015-11-17 21:57:32 +01:00
}
}
});
}
2015-10-25 10:19:00 +01:00
} else {
2015-11-17 21:57:32 +01:00
this.closeAllFilesAndShowFirst();
}
2019-09-16 17:43:57 +02:00
}
2015-11-17 21:57:32 +01:00
2019-08-18 10:17:09 +02:00
saveAndLock(complete) {
2017-01-31 07:50:28 +01:00
let pendingCallbacks = 0;
const errorFiles = [];
const that = this;
2020-06-01 16:53:51 +02:00
this.model.files.forEach(function (file) {
2019-09-17 21:39:06 +02:00
if (!file.dirty) {
2015-11-17 21:57:32 +01:00
return;
}
this.model.syncFile(file, null, fileSaved.bind(this, file));
2015-12-13 22:18:02 +01:00
pendingCallbacks++;
2015-11-17 21:57:32 +01:00
}, this);
if (!pendingCallbacks) {
this.closeAllFilesAndShowFirst();
}
function fileSaved(file, err) {
if (err) {
2019-09-17 21:39:06 +02:00
errorFiles.push(file.name);
2015-11-17 21:57:32 +01:00
}
if (--pendingCallbacks === 0) {
2015-12-12 16:43:43 +01:00
if (errorFiles.length && that.model.files.hasDirtyFiles()) {
if (!Alerts.alertDisplayed) {
2019-08-18 08:05:38 +02:00
const alertBody =
errorFiles.length > 1
? Locale.appSaveErrorBodyMul
: Locale.appSaveErrorBody;
2015-11-17 22:49:12 +01:00
Alerts.error({
2015-12-17 19:25:25 +01:00
header: Locale.appSaveError,
body: alertBody + ' ' + errorFiles.join(', ')
2015-11-17 22:49:12 +01:00
});
}
2019-08-16 23:05:39 +02:00
if (complete) {
2020-05-30 17:40:18 +02:00
complete(false);
2019-08-16 23:05:39 +02:00
}
2015-11-17 21:57:32 +01:00
} else {
that.closeAllFilesAndShowFirst();
2019-08-16 23:05:39 +02:00
if (complete) {
complete(true);
}
2015-11-17 21:57:32 +01:00
}
}
}
2019-09-16 17:43:57 +02:00
}
2015-11-17 21:57:32 +01:00
2019-08-18 10:17:09 +02:00
closeAllFilesAndShowFirst() {
2020-05-05 20:57:26 +02:00
let fileToShow = this.model.files.find(
2020-06-01 16:53:51 +02:00
(file) => !file.demo && !file.created && !file.external
2020-05-05 20:57:26 +02:00
);
2015-11-17 21:57:32 +01:00
this.model.closeAllFiles();
2016-02-06 08:27:11 +01:00
if (!fileToShow) {
2019-09-17 21:39:06 +02:00
fileToShow = this.model.fileInfos[0];
2016-02-06 08:27:11 +01:00
}
if (fileToShow) {
2019-08-16 23:05:39 +02:00
const fileInfo = this.model.fileInfos.getMatch(
2019-09-17 21:39:06 +02:00
fileToShow.storage,
fileToShow.name,
fileToShow.path
2019-08-16 23:05:39 +02:00
);
2015-12-07 22:00:44 +01:00
if (fileInfo) {
this.views.open.showOpenFileInfo(fileInfo);
}
2015-10-25 10:19:00 +01:00
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
selectLastOpenFile() {
const fileToShow = this.model.fileInfos[0];
if (fileToShow) {
this.views.open.showOpenFileInfo(fileToShow);
}
}
2019-08-18 10:17:09 +02:00
saveAll() {
2020-06-01 16:53:51 +02:00
this.model.files.forEach(function (file) {
this.model.syncFile(file);
}, this);
2019-09-16 17:43:57 +02:00
}
setupAutoSave() {
if (this.autoSaveTimer) {
clearInterval(this.autoSaveTimer);
}
2020-03-15 18:44:20 +01:00
if (this.model.settings.autoSaveInterval) {
this.autoSaveTimer = setInterval(
2020-03-15 18:44:20 +01:00
this.saveAll.bind(this),
this.model.settings.autoSaveInterval * 1000 * 60
);
}
}
2019-08-18 10:17:09 +02:00
remoteKeyChanged(e) {
2016-07-03 18:46:43 +02:00
this.showKeyChange(e.file, { remote: true });
2019-09-16 17:43:57 +02:00
}
2016-07-03 18:46:43 +02:00
2019-08-18 10:17:09 +02:00
keyChangePending(e) {
2016-07-03 18:46:43 +02:00
this.showKeyChange(e.file, { expired: true });
2019-09-16 17:43:57 +02:00
}
2019-08-18 10:17:09 +02:00
keyChangeAccept(e) {
this.showEntries();
2016-07-03 18:46:43 +02:00
if (e.expired) {
e.file.setPassword(e.password);
if (e.keyFileData && e.keyFileName) {
e.file.setKeyFile(e.keyFileData, e.keyFileName);
} else {
e.file.removeKeyFile();
}
2016-07-03 18:46:43 +02:00
} else {
this.model.syncFile(e.file, {
remoteKey: {
password: e.password,
keyFileName: e.keyFileName,
keyFileData: e.keyFileData
}
});
}
2019-09-16 17:43:57 +02:00
}
2019-08-18 10:17:09 +02:00
toggleSettings(page) {
2017-01-31 07:50:28 +01:00
let menuItem = page ? this.model.menu[page + 'Section'] : null;
2015-10-22 20:03:44 +02:00
if (menuItem) {
2019-09-18 23:37:57 +02:00
menuItem = menuItem.items[0];
2015-10-22 20:03:44 +02:00
}
2015-10-17 23:49:24 +02:00
if (this.views.settings) {
2015-10-22 20:08:11 +02:00
if (this.views.settings.page === page || !menuItem) {
2016-02-23 06:20:01 +01:00
if (this.model.files.hasOpenFiles()) {
this.showEntries();
} else {
this.showLastOpenFile();
2016-03-14 21:57:14 +01:00
this.views.open.toggleMore();
2016-02-23 06:20:01 +01:00
}
2015-10-22 20:03:44 +02:00
} else {
if (menuItem) {
2019-08-16 23:05:39 +02:00
this.model.menu.select({ item: menuItem });
2015-10-22 20:03:44 +02:00
}
}
2015-10-17 23:49:24 +02:00
} else {
this.showSettings();
2015-10-22 20:03:44 +02:00
if (menuItem) {
2019-08-16 23:05:39 +02:00
this.model.menu.select({ item: menuItem });
2015-10-22 20:03:44 +02:00
}
2015-10-17 23:49:24 +02:00
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
toggleMenu() {
2015-10-24 11:15:54 +02:00
this.views.menu.switchVisibility();
2019-09-16 17:43:57 +02:00
}
2015-10-24 11:15:54 +02:00
2019-08-18 10:17:09 +02:00
toggleDetails(visible) {
2019-09-28 13:31:52 +02:00
this.$el.toggleClass('app--details-visible', visible);
2015-10-26 22:07:19 +01:00
this.views.menu.switchVisibility(false);
2019-09-16 17:43:57 +02:00
}
2015-10-26 22:07:19 +01:00
2019-08-18 10:17:09 +02:00
editGroup(group) {
2016-08-13 21:13:16 +02:00
if (group && !(this.views.panel instanceof GrpView)) {
this.showEditGroup(group);
2015-10-31 20:09:32 +01:00
} else {
this.showEntries();
}
2019-09-16 17:43:57 +02:00
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
editTag(tag) {
2016-08-13 21:13:16 +02:00
if (tag && !(this.views.panel instanceof TagView)) {
2016-04-17 22:02:39 +02:00
this.showEditTag();
2016-08-13 21:13:16 +02:00
this.views.panel.showTag(tag);
} else {
this.showEntries();
}
2019-09-16 17:43:57 +02:00
}
2016-08-13 21:13:16 +02:00
2019-08-18 10:17:09 +02:00
editGeneratorPresets() {
2016-08-13 21:13:16 +02:00
if (!(this.views.panel instanceof GeneratorPresetsView)) {
if (this.views.settings) {
this.showEntries();
}
2019-09-15 18:33:45 +02:00
this.showPanelView(new GeneratorPresetsView(this.model));
2016-04-17 22:02:39 +02:00
} else {
this.showEntries();
}
2019-09-16 17:43:57 +02:00
}
2016-04-17 22:02:39 +02:00
2016-07-30 11:25:22 +02:00
isContextMenuAllowed(e) {
return ['input', 'textarea'].indexOf(e.target.tagName.toLowerCase()) < 0;
2019-09-16 17:43:57 +02:00
}
2016-07-30 11:25:22 +02:00
2019-08-18 10:17:09 +02:00
contextMenu(e) {
2016-07-30 11:25:22 +02:00
if (this.isContextMenuAllowed(e)) {
2015-10-17 23:49:24 +02:00
e.preventDefault();
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
showContextMenu(e) {
2016-07-30 11:25:22 +02:00
if (e.options && this.isContextMenuAllowed(e)) {
e.stopImmediatePropagation();
e.preventDefault();
if (this.views.contextMenu) {
this.views.contextMenu.remove();
}
2019-09-16 07:06:55 +02:00
const menu = new DropdownView(e);
2016-07-30 11:25:22 +02:00
menu.render({
position: { left: e.pageX, top: e.pageY },
options: e.options
});
2020-06-01 16:53:51 +02:00
menu.on('cancel', (e) => this.hideContextMenu());
menu.on('select', (e) => this.contextMenuSelect(e));
2016-07-30 11:25:22 +02:00
this.views.contextMenu = menu;
}
2019-09-16 17:43:57 +02:00
}
2016-07-30 11:25:22 +02:00
2019-08-18 10:17:09 +02:00
hideContextMenu() {
2016-07-30 11:25:22 +02:00
if (this.views.contextMenu) {
this.views.contextMenu.remove();
delete this.views.contextMenu;
}
2019-09-16 17:43:57 +02:00
}
2016-07-30 11:25:22 +02:00
2019-08-18 10:17:09 +02:00
contextMenuSelect(e) {
2016-07-30 11:25:22 +02:00
this.hideContextMenu();
2019-09-16 22:57:56 +02:00
Events.emit('context-menu-select', e);
2019-09-16 17:43:57 +02:00
}
2016-07-30 11:25:22 +02:00
2019-08-18 10:17:09 +02:00
showSingleInstanceAlert() {
2016-09-16 19:33:38 +02:00
this.hideOpenFile();
Alerts.error({
2019-08-16 23:05:39 +02:00
header: Locale.appTabWarn,
body: Locale.appTabWarnBody,
esc: false,
enter: false,
click: false,
buttons: []
2016-09-16 19:33:38 +02:00
});
2019-09-16 17:43:57 +02:00
}
2016-09-16 19:33:38 +02:00
2019-08-18 10:17:09 +02:00
dragover(e) {
2015-10-17 23:49:24 +02:00
e.preventDefault();
2019-09-16 21:49:21 +02:00
e.dataTransfer.dropEffect = 'none';
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
drop(e) {
2015-10-17 23:49:24 +02:00
e.preventDefault();
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
setTheme() {
2019-09-17 19:50:42 +02:00
SettingsManager.setTheme(this.model.settings.theme);
2019-09-16 17:43:57 +02:00
}
2015-10-22 20:03:44 +02:00
2019-08-18 10:17:09 +02:00
setFontSize() {
2019-09-17 19:50:42 +02:00
SettingsManager.setFontSize(this.model.settings.fontSize);
2019-09-16 17:43:57 +02:00
}
2016-08-21 23:12:49 +02:00
2019-08-18 10:17:09 +02:00
setLocale() {
2019-09-17 19:50:42 +02:00
SettingsManager.setLocale(this.model.settings.locale);
2016-08-21 23:12:49 +02:00
if (this.views.settings.isVisible()) {
this.hideSettings();
this.showSettings();
}
2016-08-24 22:06:25 +02:00
this.$el.find('.app__beta:first').text(Locale.appBeta);
2019-09-16 17:43:57 +02:00
}
2019-08-18 10:17:09 +02:00
extLinkClick(e) {
2015-10-22 20:03:44 +02:00
if (Launcher) {
e.preventDefault();
Launcher.openLink(e.target.href);
}
2019-09-16 17:43:57 +02:00
}
2015-11-17 22:49:12 +01:00
2019-08-18 10:17:09 +02:00
bodyClick(e) {
2015-11-17 22:49:12 +01:00
IdleTracker.regUserAction();
2019-09-16 22:57:56 +02:00
Events.emit('click', e);
2015-10-17 23:49:24 +02:00
}
2019-09-25 23:24:38 +02:00
showImportCsv(file) {
const reader = new FileReader();
const logger = new Logger('import-csv');
logger.info('Reading CSV...');
2020-06-01 16:53:51 +02:00
reader.onload = (e) => {
2019-09-25 23:24:38 +02:00
logger.info('Parsing CSV...');
const ts = logger.ts();
const parser = new CsvParser();
let data;
try {
data = parser.parse(e.target.result);
} catch (e) {
logger.error('Error parsing CSV', e);
Alerts.error({ header: Locale.openFailedRead, body: e.toString() });
return;
}
logger.info(`Parsed CSV: ${data.rows.length} records, ${logger.ts(ts)}`);
// TODO: refactor this
this.hideSettings();
this.hidePanelView();
this.hideOpenFile();
this.hideKeyChange();
this.views.menu.hide();
this.views.listWrap.hide();
this.views.list.hide();
this.views.listDrag.hide();
this.views.details.hide();
this.views.importCsv = new ImportCsvView(data, {
appModel: this.model,
fileName: file.name
});
this.views.importCsv.render();
this.views.importCsv.on('cancel', () => {
if (this.model.files.hasOpenFiles()) {
this.showEntries();
} else {
this.showOpenFile();
}
});
this.views.importCsv.on('done', () => {
this.model.refresh();
this.showEntries();
});
};
reader.onerror = () => {
Alerts.error({ header: Locale.openFailedRead });
};
reader.readAsText(file);
}
2019-09-16 17:43:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-09-15 14:16:32 +02:00
export { AppView };