2017-01-31 07:50:28 +01:00
|
|
|
const Backbone = require('backbone');
|
|
|
|
const kdbxweb = require('kdbxweb');
|
|
|
|
const OpenConfigView = require('./open-config-view');
|
|
|
|
const Keys = require('../const/keys');
|
|
|
|
const Alerts = require('../comp/alerts');
|
|
|
|
const SecureInput = require('../comp/secure-input');
|
2017-04-16 17:00:35 +02:00
|
|
|
const DropboxChooser = require('../comp/dropbox-chooser');
|
2017-11-26 21:00:45 +01:00
|
|
|
const KeyHandler = require('../comp/key-handler');
|
2017-11-26 17:26:58 +01:00
|
|
|
const StorageFileListView = require('../views/storage-file-list-view');
|
2017-01-31 07:50:28 +01:00
|
|
|
const FeatureDetector = require('../util/feature-detector');
|
|
|
|
const Logger = require('../util/logger');
|
|
|
|
const Locale = require('../util/locale');
|
|
|
|
const UrlUtil = require('../util/url-util');
|
|
|
|
const InputFx = require('../util/input-fx');
|
2017-11-26 17:26:58 +01:00
|
|
|
const Comparators = require('../util/comparators');
|
2017-01-31 07:50:28 +01:00
|
|
|
const Storage = require('../storage');
|
2017-02-05 22:01:46 +01:00
|
|
|
const Launcher = require('../comp/launcher');
|
2017-01-31 07:50:28 +01:00
|
|
|
|
|
|
|
const logger = new Logger('open-view');
|
|
|
|
|
|
|
|
const OpenView = Backbone.View.extend({
|
2015-12-16 22:50:45 +01:00
|
|
|
template: require('templates/open.hbs'),
|
2015-10-17 23:49:24 +02:00
|
|
|
|
|
|
|
events: {
|
2015-11-05 21:58:33 +01:00
|
|
|
'change .open__file-ctrl': 'fileSelected',
|
|
|
|
'click .open__icon-open': 'openFile',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__icon-open': 'labelOnKeydown',
|
2015-11-05 21:58:33 +01:00
|
|
|
'click .open__icon-new': 'createNew',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__icon-new': 'labelOnKeydown',
|
2016-03-09 21:52:19 +01:00
|
|
|
'click .open__icon-import-xml': 'importFromXml',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__icon-import-xml': 'labelOnKeydown',
|
2015-11-05 21:58:33 +01:00
|
|
|
'click .open__icon-demo': 'createDemo',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__icon-demo': 'labelOnKeydown',
|
2016-03-09 21:52:19 +01:00
|
|
|
'click .open__icon-more': 'toggleMore',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__icon-more': 'labelOnKeydown',
|
2016-03-13 17:08:25 +01:00
|
|
|
'click .open__icon-storage': 'openStorage',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__icon-storage': 'labelOnKeydown',
|
2016-03-13 18:33:25 +01:00
|
|
|
'click .open__icon-settings': 'openSettings',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__icon-settings': 'labelOnKeydown',
|
2015-11-05 21:58:33 +01:00
|
|
|
'click .open__pass-input[readonly]': 'openFile',
|
|
|
|
'input .open__pass-input': 'inputInput',
|
|
|
|
'keydown .open__pass-input': 'inputKeydown',
|
2016-02-18 19:57:18 +01:00
|
|
|
'keyup .open__pass-input': 'inputKeyup',
|
2015-11-05 21:58:33 +01:00
|
|
|
'keypress .open__pass-input': 'inputKeypress',
|
2015-11-06 21:14:47 +01:00
|
|
|
'click .open__pass-enter-btn': 'openDb',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__pass-enter-btn': 'labelOnKeydown',
|
2015-11-05 21:58:33 +01:00
|
|
|
'click .open__settings-key-file': 'openKeyFile',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__settings-key-file': 'labelOnKeydown',
|
2015-11-07 20:02:45 +01:00
|
|
|
'click .open__last-item': 'openLast',
|
2017-12-23 20:00:55 +01:00
|
|
|
'keydown .open__last-item': 'labelOnKeydown',
|
2015-10-17 23:49:24 +02:00
|
|
|
'dragover': 'dragover',
|
|
|
|
'dragleave': 'dragleave',
|
|
|
|
'drop': 'drop'
|
|
|
|
},
|
|
|
|
|
2016-03-12 12:22:35 +01:00
|
|
|
views: null,
|
2015-12-06 21:32:41 +01:00
|
|
|
params: null,
|
2015-11-05 21:58:33 +01:00
|
|
|
passwordInput: null,
|
2015-12-06 21:32:41 +01:00
|
|
|
busy: false,
|
2015-11-05 21:58:33 +01:00
|
|
|
|
2015-10-17 23:49:24 +02:00
|
|
|
initialize: function () {
|
2016-03-12 12:22:35 +01:00
|
|
|
this.views = {};
|
2015-12-06 21:32:41 +01:00
|
|
|
this.params = {
|
|
|
|
id: null,
|
|
|
|
name: '',
|
|
|
|
storage: null,
|
|
|
|
path: null,
|
|
|
|
keyFileName: null,
|
|
|
|
keyFileData: null,
|
2016-12-11 14:39:59 +01:00
|
|
|
keyFilePath: null,
|
2015-12-07 20:07:56 +01:00
|
|
|
fileData: null,
|
|
|
|
rev: null
|
2015-12-06 21:32:41 +01:00
|
|
|
};
|
2015-11-05 21:58:33 +01:00
|
|
|
this.passwordInput = new SecureInput();
|
2017-11-26 21:00:45 +01:00
|
|
|
KeyHandler.onKey(Keys.DOM_VK_Z, this.undoKeyPress, this, KeyHandler.SHORTCUT_ACTION);
|
2015-11-17 21:57:32 +01:00
|
|
|
},
|
|
|
|
|
2015-10-17 23:49:24 +02:00
|
|
|
render: function () {
|
|
|
|
if (this.dragTimeout) {
|
|
|
|
clearTimeout(this.dragTimeout);
|
|
|
|
}
|
2017-01-31 07:50:28 +01:00
|
|
|
const storageProviders = [];
|
2016-07-17 13:30:38 +02:00
|
|
|
Object.keys(Storage).forEach(name => {
|
2017-01-31 07:50:28 +01:00
|
|
|
const prv = Storage[name];
|
2016-03-13 17:08:25 +01:00
|
|
|
if (!prv.system && prv.enabled) {
|
|
|
|
storageProviders.push(prv);
|
|
|
|
}
|
|
|
|
});
|
2016-07-17 13:30:38 +02:00
|
|
|
storageProviders.sort((x, y) => (x.uipos || Infinity) - (y.uipos || Infinity));
|
2017-01-31 07:50:28 +01:00
|
|
|
const showMore = storageProviders.length || this.model.settings.get('canOpenSettings');
|
|
|
|
const showLogo = !showMore && !this.model.settings.get('canOpen') && !this.model.settings.get('canCreate') &&
|
2016-08-21 20:23:09 +02:00
|
|
|
!(this.model.settings.get('canOpenDemo') && !this.model.settings.get('demoOpened'));
|
2016-03-13 10:54:16 +01:00
|
|
|
this.renderTemplate({
|
|
|
|
lastOpenFiles: this.getLastOpenFiles(),
|
2017-04-16 17:00:35 +02:00
|
|
|
canOpenKeyFromDropbox: !Launcher && Storage.dropbox.enabled,
|
2016-03-13 17:08:25 +01:00
|
|
|
demoOpened: this.model.settings.get('demoOpened'),
|
2016-08-21 20:23:09 +02:00
|
|
|
storageProviders: storageProviders,
|
|
|
|
canOpen: this.model.settings.get('canOpen'),
|
|
|
|
canOpenDemo: this.model.settings.get('canOpenDemo'),
|
|
|
|
canOpenSettings: this.model.settings.get('canOpenSettings'),
|
|
|
|
canCreate: this.model.settings.get('canCreate'),
|
|
|
|
canImportXml: this.model.settings.get('canImportXml'),
|
2017-01-29 12:03:33 +01:00
|
|
|
canRemoveLatest: this.model.settings.get('canRemoveLatest'),
|
2016-08-21 20:23:09 +02:00
|
|
|
showMore: showMore,
|
|
|
|
showLogo: showLogo
|
2016-03-13 10:54:16 +01:00
|
|
|
});
|
2015-11-05 21:58:33 +01:00
|
|
|
this.inputEl = this.$el.find('.open__pass-input');
|
|
|
|
this.passwordInput.setElement(this.inputEl);
|
2015-10-17 23:49:24 +02:00
|
|
|
return this;
|
2015-11-06 21:14:47 +01:00
|
|
|
},
|
|
|
|
|
2016-05-13 14:09:21 +02:00
|
|
|
focusInput: function() {
|
2016-07-17 21:08:23 +02:00
|
|
|
if (!FeatureDetector.isMobile) {
|
2016-05-13 14:09:21 +02:00
|
|
|
this.inputEl.focus();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-11-07 20:02:45 +01:00
|
|
|
getLastOpenFiles: function() {
|
2016-07-17 13:30:38 +02:00
|
|
|
return this.model.fileInfos.map(f => {
|
2017-01-31 07:50:28 +01:00
|
|
|
let icon = 'file-text';
|
|
|
|
const storage = Storage[f.get('storage')];
|
2016-03-27 08:14:15 +02:00
|
|
|
if (storage && storage.icon) {
|
|
|
|
icon = storage.icon;
|
|
|
|
}
|
|
|
|
if (storage && storage.iconSvg) {
|
|
|
|
icon = null;
|
2015-11-07 20:02:45 +01:00
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
return {
|
|
|
|
id: f.get('id'),
|
|
|
|
name: f.get('name'),
|
2017-02-04 23:51:17 +01:00
|
|
|
path: this.getDisplayedPath(f),
|
2016-03-27 08:14:15 +02:00
|
|
|
icon: icon,
|
|
|
|
iconSvg: storage ? storage.iconSvg : undefined
|
2015-12-06 21:32:41 +01:00
|
|
|
};
|
2015-11-07 20:02:45 +01:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-02-04 23:51:17 +01:00
|
|
|
getDisplayedPath: function(fileInfo) {
|
|
|
|
const storage = fileInfo.get('storage');
|
|
|
|
if (storage === 'file' || storage === 'webdav') {
|
|
|
|
return fileInfo.get('path');
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
|
2015-11-06 21:14:47 +01:00
|
|
|
remove: function() {
|
|
|
|
this.passwordInput.reset();
|
2017-11-26 21:00:45 +01:00
|
|
|
KeyHandler.offKey(Keys.DOM_VK_Z, this.undoKeyPress, this);
|
2015-11-06 21:14:47 +01:00
|
|
|
Backbone.View.prototype.remove.apply(this, arguments);
|
|
|
|
},
|
|
|
|
|
2016-02-23 07:08:57 +01:00
|
|
|
showLocalFileAlert: function() {
|
|
|
|
if (this.model.settings.get('skipOpenLocalWarn')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Alerts.alert({
|
|
|
|
header: Locale.openLocalFile,
|
|
|
|
body: Locale.openLocalFileBody,
|
|
|
|
icon: 'file-text',
|
|
|
|
buttons: [
|
|
|
|
{result: 'skip', title: Locale.openLocalFileDontShow, error: true},
|
|
|
|
{result: 'ok', title: Locale.alertOk}
|
|
|
|
],
|
|
|
|
click: '',
|
|
|
|
esc: '',
|
|
|
|
enter: '',
|
2016-07-17 13:30:38 +02:00
|
|
|
success: res => {
|
|
|
|
this.focusInput();
|
2016-02-23 07:08:57 +01:00
|
|
|
if (res === 'skip') {
|
2016-07-17 13:30:38 +02:00
|
|
|
this.model.settings.set('skipOpenLocalWarn', true);
|
2016-02-23 07:08:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2015-11-06 21:14:47 +01:00
|
|
|
fileSelected: function(e) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const file = e.target.files[0];
|
2015-11-06 21:14:47 +01:00
|
|
|
if (file) {
|
2016-07-17 13:30:38 +02:00
|
|
|
this.processFile(file, success => {
|
2016-03-04 20:21:34 +01:00
|
|
|
if (success && !file.path && this.reading === 'fileData') {
|
|
|
|
this.showLocalFileAlert();
|
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
});
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
processFile: function(file, complete) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const reader = new FileReader();
|
2016-07-17 13:30:38 +02:00
|
|
|
reader.onload = e => {
|
2017-01-31 07:50:28 +01:00
|
|
|
let success = false;
|
2016-03-01 04:29:20 +01:00
|
|
|
switch (this.reading) {
|
|
|
|
case 'fileData':
|
2016-03-04 19:45:37 +01:00
|
|
|
if (!this.checkOpenFileFormat(e.target.result)) {
|
2016-03-04 20:21:34 +01:00
|
|
|
break;
|
2016-03-04 19:45:37 +01:00
|
|
|
}
|
2016-03-01 04:29:20 +01:00
|
|
|
this.params.id = null;
|
|
|
|
this.params.fileData = e.target.result;
|
2016-08-13 16:35:08 +02:00
|
|
|
this.params.name = file.name.replace(/(.+)\.\w+$/i, '$1');
|
2016-03-01 04:29:20 +01:00
|
|
|
this.params.path = file.path || null;
|
|
|
|
this.params.storage = file.path ? 'file' : null;
|
|
|
|
this.params.rev = null;
|
2016-04-07 18:43:19 +02:00
|
|
|
if (!this.params.keyFileData) {
|
|
|
|
this.params.keyFileName = null;
|
|
|
|
}
|
2016-03-01 04:29:20 +01:00
|
|
|
this.displayOpenFile();
|
2016-04-07 18:43:19 +02:00
|
|
|
this.displayOpenKeyFile();
|
2016-03-04 20:21:34 +01:00
|
|
|
success = true;
|
2016-03-01 04:29:20 +01:00
|
|
|
break;
|
|
|
|
case 'fileXml':
|
|
|
|
this.params.id = null;
|
|
|
|
this.params.fileXml = e.target.result;
|
|
|
|
this.params.name = file.name.replace(/\.\w+$/i, '');
|
2016-03-04 18:06:18 +01:00
|
|
|
this.params.path = null;
|
|
|
|
this.params.storage = null;
|
2016-03-01 04:29:20 +01:00
|
|
|
this.params.rev = null;
|
2016-03-04 18:06:18 +01:00
|
|
|
this.importDbWithXml();
|
2016-03-04 20:21:34 +01:00
|
|
|
success = true;
|
2016-03-01 04:29:20 +01:00
|
|
|
break;
|
2016-03-04 20:21:34 +01:00
|
|
|
case 'keyFileData':
|
2016-03-01 04:29:20 +01:00
|
|
|
this.params.keyFileData = e.target.result;
|
|
|
|
this.params.keyFileName = file.name;
|
2016-12-11 14:39:59 +01:00
|
|
|
if (this.model.settings.get('rememberKeyFiles') === 'path') {
|
|
|
|
this.params.keyFilePath = file.path;
|
|
|
|
}
|
2016-03-01 04:29:20 +01:00
|
|
|
this.displayOpenKeyFile();
|
2016-03-04 20:21:34 +01:00
|
|
|
success = true;
|
|
|
|
break;
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
|
|
|
if (complete) {
|
2016-03-04 20:21:34 +01:00
|
|
|
complete(success);
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
};
|
|
|
|
reader.onerror = () => {
|
2015-12-17 19:25:25 +01:00
|
|
|
Alerts.error({ header: Locale.openFailedRead });
|
2015-11-06 21:14:47 +01:00
|
|
|
if (complete) {
|
|
|
|
complete(false);
|
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
};
|
2016-03-01 22:17:19 +01:00
|
|
|
if (this.reading === 'fileXml') {
|
|
|
|
reader.readAsText(file);
|
|
|
|
} else {
|
|
|
|
reader.readAsArrayBuffer(file);
|
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
},
|
|
|
|
|
2016-03-04 19:45:37 +01:00
|
|
|
checkOpenFileFormat: function(fileData) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const fileSig = fileData.byteLength < 8 ? null : new Uint32Array(fileData, 0, 2);
|
2016-08-16 19:21:52 +02:00
|
|
|
if (!fileSig || fileSig[0] !== kdbxweb.Consts.Signatures.FileMagic) {
|
2016-03-04 19:45:37 +01:00
|
|
|
Alerts.error({ header: Locale.openWrongFile, body: Locale.openWrongFileBody });
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (fileSig[1] === kdbxweb.Consts.Signatures.Sig2Kdb) {
|
|
|
|
Alerts.error({ header: Locale.openWrongFile, body: Locale.openKdbFileBody });
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (fileSig[1] !== kdbxweb.Consts.Signatures.Sig2Kdbx) {
|
|
|
|
Alerts.error({ header: Locale.openWrongFile, body: Locale.openWrongFileBody });
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
2015-11-06 21:14:47 +01:00
|
|
|
displayOpenFile: function() {
|
|
|
|
this.$el.addClass('open--file');
|
2015-11-11 19:37:31 +01:00
|
|
|
this.$el.find('.open__settings-key-file').removeClass('hide');
|
2015-11-06 21:14:47 +01:00
|
|
|
this.inputEl[0].removeAttribute('readonly');
|
2015-12-17 19:25:25 +01:00
|
|
|
this.inputEl[0].setAttribute('placeholder', Locale.openPassFor + ' ' + this.params.name);
|
2016-05-13 14:09:21 +02:00
|
|
|
this.focusInput();
|
2015-11-06 21:14:47 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
displayOpenKeyFile: function() {
|
2016-04-06 23:13:44 +02:00
|
|
|
this.$el.toggleClass('open--key-file', !!this.params.keyFileName);
|
2017-12-03 20:31:54 +01:00
|
|
|
this.$el.find('.open__settings-key-file-name').text(this.params.keyFileName || this.params.keyFilePath || Locale.openKeyFile);
|
2016-05-13 14:09:21 +02:00
|
|
|
this.focusInput();
|
2015-11-06 21:14:47 +01:00
|
|
|
},
|
|
|
|
|
2016-03-04 20:21:34 +01:00
|
|
|
setFile: function(file, keyFile, fileReadyCallback) {
|
2015-11-06 21:14:47 +01:00
|
|
|
this.reading = 'fileData';
|
2016-07-17 13:30:38 +02:00
|
|
|
this.processFile(file, success => {
|
2015-11-06 21:14:47 +01:00
|
|
|
if (success && keyFile) {
|
|
|
|
this.reading = 'keyFileData';
|
|
|
|
this.processFile(keyFile);
|
|
|
|
}
|
2016-03-04 20:21:34 +01:00
|
|
|
if (success && typeof fileReadyCallback === 'function') {
|
|
|
|
fileReadyCallback();
|
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
});
|
2015-11-06 21:14:47 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
openFile: function() {
|
2017-11-26 19:21:16 +01:00
|
|
|
if (this.model.settings.get('canOpen') === false) {
|
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
if (!this.busy) {
|
2016-03-12 12:22:35 +01:00
|
|
|
this.closeConfig();
|
2015-11-07 20:02:45 +01:00
|
|
|
this.openAny('fileData');
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-12-23 20:00:55 +01:00
|
|
|
labelOnKeydown: function(e) {
|
|
|
|
const code = e.keyCode || e.which;
|
|
|
|
if (code === Keys.DOM_VK_RETURN) {
|
|
|
|
this.labelOnEnter(e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
labelOnEnter: function(e) {
|
|
|
|
if ($(e.target).hasClass('open__icon-open')) {
|
|
|
|
this.openFile();
|
|
|
|
} else if (($(e.target).hasClass('open__icon-new'))) {
|
|
|
|
this.createNew();
|
|
|
|
} else if (($(e.target).hasClass('open__icon-demo'))) {
|
|
|
|
this.createDemo();
|
|
|
|
} else if (($(e.target).hasClass('open__icon-more'))) {
|
|
|
|
this.toggleMore();
|
|
|
|
} else if (($(e.target).hasClass('open__icon-storage'))) {
|
|
|
|
this.openStorage(e);
|
|
|
|
} else if (($(e.target).hasClass('open__icon-settings'))) {
|
|
|
|
this.openSettings();
|
|
|
|
} else if (($(e.target).hasClass('open__icon-import-xml'))) {
|
|
|
|
this.importFromXml();
|
|
|
|
} else if (($(e.target).hasClass('open__pass-enter-btn'))) {
|
|
|
|
this.openDb();
|
|
|
|
} else if (($(e.target).hasClass('open__settings-key-file'))) {
|
|
|
|
this.openKeyFile(e);
|
|
|
|
} else if (($(e.target).hasClass('open__last-item'))) {
|
|
|
|
this.openLast(e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-03-01 04:29:20 +01:00
|
|
|
importFromXml: function() {
|
|
|
|
if (!this.busy) {
|
2016-03-12 12:22:35 +01:00
|
|
|
this.closeConfig();
|
2016-03-01 04:29:20 +01:00
|
|
|
this.openAny('fileXml', 'xml');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-11-06 21:14:47 +01:00
|
|
|
openKeyFile: function(e) {
|
|
|
|
if ($(e.target).hasClass('open__settings-key-file-dropbox')) {
|
|
|
|
this.openKeyFileFromDropbox();
|
2015-12-06 21:32:41 +01:00
|
|
|
} else if (!this.busy && this.params.name) {
|
2016-12-11 14:39:59 +01:00
|
|
|
if (this.params.keyFileName) {
|
2015-12-06 21:32:41 +01:00
|
|
|
this.params.keyFileData = null;
|
2016-12-11 14:39:59 +01:00
|
|
|
this.params.keyFilePath = null;
|
2015-12-06 21:32:41 +01:00
|
|
|
this.params.keyFileName = '';
|
2015-11-06 21:14:47 +01:00
|
|
|
this.$el.removeClass('open--key-file');
|
2016-04-06 23:13:44 +02:00
|
|
|
this.$el.find('.open__settings-key-file-name').text(Locale.openKeyFile);
|
2015-11-06 21:14:47 +01:00
|
|
|
} else {
|
|
|
|
this.openAny('keyFileData');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
openKeyFileFromDropbox: function() {
|
2015-12-06 21:32:41 +01:00
|
|
|
if (!this.busy) {
|
2017-04-16 17:00:35 +02:00
|
|
|
new DropboxChooser((err, res) => {
|
2015-11-08 21:23:12 +01:00
|
|
|
if (err) {
|
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
this.params.keyFileData = res.data;
|
|
|
|
this.params.keyFileName = res.name;
|
2015-11-06 21:14:47 +01:00
|
|
|
this.displayOpenKeyFile();
|
2017-04-16 17:00:35 +02:00
|
|
|
}).choose();
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
openAny: function(reading, ext) {
|
|
|
|
this.reading = reading;
|
2015-12-06 21:32:41 +01:00
|
|
|
this.params[reading] = null;
|
2017-02-05 22:01:46 +01:00
|
|
|
|
2017-02-22 01:12:42 +01:00
|
|
|
const fileInput = this.$el.find('.open__file-ctrl').attr('accept', ext || '').val(null);
|
|
|
|
|
2017-04-12 00:06:44 +02:00
|
|
|
if (Launcher && Launcher.openFileChooser) {
|
2017-03-19 00:30:29 +01:00
|
|
|
Launcher.openFileChooser((err, file) => {
|
|
|
|
if (err) {
|
2017-04-10 23:51:03 +02:00
|
|
|
logger.error('Error opening file chooser', err);
|
2017-03-19 00:30:29 +01:00
|
|
|
} else {
|
|
|
|
this.processFile(file);
|
|
|
|
}
|
2017-04-12 00:06:44 +02:00
|
|
|
});
|
2017-02-05 22:01:46 +01:00
|
|
|
} else {
|
2017-02-22 01:12:42 +01:00
|
|
|
fileInput.click();
|
2017-02-05 22:01:46 +01:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
},
|
|
|
|
|
2015-12-06 21:32:41 +01:00
|
|
|
openLast: function(e) {
|
|
|
|
if (this.busy) {
|
|
|
|
return;
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
2017-01-31 07:50:28 +01:00
|
|
|
const id = $(e.target).closest('.open__last-item').data('id').toString();
|
2015-12-06 21:32:41 +01:00
|
|
|
if ($(e.target).is('.open__last-item-icon-del')) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const fileInfo = this.model.fileInfos.get(id);
|
2016-03-19 07:15:20 +01:00
|
|
|
if (!fileInfo.get('storage') || fileInfo.get('modified')) {
|
2016-02-23 07:08:57 +01:00
|
|
|
Alerts.yesno({
|
|
|
|
header: Locale.openRemoveLastQuestion,
|
2016-03-19 07:15:20 +01:00
|
|
|
body: fileInfo.get('modified') ? Locale.openRemoveLastQuestionModBody : Locale.openRemoveLastQuestionBody,
|
2016-02-23 07:08:57 +01:00
|
|
|
buttons: [
|
|
|
|
{result: 'yes', title: Locale.alertYes},
|
|
|
|
{result: '', title: Locale.alertNo}
|
|
|
|
],
|
2016-07-17 13:30:38 +02:00
|
|
|
success: () => {
|
|
|
|
this.removeFile(id);
|
2016-02-23 07:08:57 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.removeFile(id);
|
2015-12-06 21:32:41 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-02-05 22:01:46 +01:00
|
|
|
|
2017-04-14 23:22:33 +02:00
|
|
|
const fileInfo = this.model.fileInfos.get(id);
|
|
|
|
this.showOpenFileInfo(fileInfo);
|
|
|
|
|
|
|
|
if (fileInfo && Launcher && Launcher.fingerprints) {
|
|
|
|
this.openFileWithFingerprint(fileInfo);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
openFileWithFingerprint(fileInfo) {
|
|
|
|
if (fileInfo.get('fingerprint')) {
|
|
|
|
Launcher.fingerprints.auth(fileInfo.id, fileInfo.get('fingerprint'), password => {
|
2017-02-05 22:01:46 +01:00
|
|
|
this.inputEl.val(password);
|
|
|
|
this.inputEl.trigger('input');
|
|
|
|
this.openDb();
|
|
|
|
});
|
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
},
|
|
|
|
|
2016-02-23 07:08:57 +01:00
|
|
|
removeFile: function(id) {
|
|
|
|
this.model.removeFileInfo(id);
|
|
|
|
this.$el.find('.open__last-item[data-id="' + id + '"]').remove();
|
|
|
|
this.initialize();
|
|
|
|
this.render();
|
|
|
|
},
|
|
|
|
|
2015-11-06 21:14:47 +01:00
|
|
|
inputKeydown: function(e) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const code = e.keyCode || e.which;
|
2015-12-08 19:02:50 +01:00
|
|
|
if (code === Keys.DOM_VK_RETURN) {
|
2015-11-06 21:14:47 +01:00
|
|
|
this.openDb();
|
|
|
|
} else if (code === Keys.DOM_VK_CAPS_LOCK) {
|
2016-02-18 19:57:18 +01:00
|
|
|
this.toggleCapsLockWarning(false);
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-02-18 19:57:18 +01:00
|
|
|
inputKeyup: function(e) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const code = e.keyCode || e.which;
|
2016-02-18 19:57:18 +01:00
|
|
|
if (code === Keys.DOM_VK_CAPS_LOCK) {
|
|
|
|
this.toggleCapsLockWarning(false);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-11-06 21:14:47 +01:00
|
|
|
inputKeypress: function(e) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const charCode = e.keyCode || e.which;
|
|
|
|
const ch = String.fromCharCode(charCode);
|
|
|
|
const lower = ch.toLowerCase();
|
|
|
|
const upper = ch.toUpperCase();
|
2015-11-06 21:14:47 +01:00
|
|
|
if (lower !== upper && !e.shiftKey) {
|
|
|
|
this.toggleCapsLockWarning(ch !== lower);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleCapsLockWarning: function(on) {
|
2016-02-18 19:57:18 +01:00
|
|
|
this.$el.find('.open__pass-warning').toggleClass('invisible', !on);
|
2015-11-06 21:14:47 +01:00
|
|
|
},
|
|
|
|
|
2015-12-06 21:32:41 +01:00
|
|
|
dragover: function(e) {
|
2016-08-21 20:23:09 +02:00
|
|
|
if (this.model.settings.get('canOpen') === false) {
|
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
e.preventDefault();
|
|
|
|
if (this.dragTimeout) {
|
|
|
|
clearTimeout(this.dragTimeout);
|
|
|
|
}
|
|
|
|
if (!this.$el.hasClass('open--drag')) {
|
|
|
|
this.$el.addClass('open--drag');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
dragleave: function() {
|
2016-08-21 20:23:09 +02:00
|
|
|
if (this.model.settings.get('canOpen') === false) {
|
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
if (this.dragTimeout) {
|
|
|
|
clearTimeout(this.dragTimeout);
|
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
this.dragTimeout = setTimeout(() => {
|
2015-12-06 21:32:41 +01:00
|
|
|
this.$el.removeClass('open--drag');
|
2016-07-17 13:30:38 +02:00
|
|
|
}, 100);
|
2015-12-06 21:32:41 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
drop: function(e) {
|
2016-08-21 20:23:09 +02:00
|
|
|
if (this.model.settings.get('canOpen') === false) {
|
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
e.preventDefault();
|
2016-03-12 12:22:35 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
if (this.dragTimeout) {
|
|
|
|
clearTimeout(this.dragTimeout);
|
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
this.closeConfig();
|
2015-12-06 21:32:41 +01:00
|
|
|
this.$el.removeClass('open--drag');
|
2017-01-31 07:50:28 +01:00
|
|
|
const files = e.target.files || e.originalEvent.dataTransfer.files;
|
|
|
|
const dataFile = _.find(files, file => file.name.split('.').pop().toLowerCase() === 'kdbx');
|
|
|
|
const keyFile = _.find(files, file => file.name.split('.').pop().toLowerCase() === 'key');
|
2015-12-06 21:32:41 +01:00
|
|
|
if (dataFile) {
|
2016-03-04 20:21:34 +01:00
|
|
|
this.setFile(dataFile, keyFile,
|
|
|
|
dataFile.path ? null : this.showLocalFileAlert.bind(this));
|
2015-12-06 21:32:41 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-11-26 21:00:45 +01:00
|
|
|
undoKeyPress: function(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
},
|
|
|
|
|
2015-12-07 20:07:56 +01:00
|
|
|
showOpenFileInfo: function(fileInfo) {
|
|
|
|
if (this.busy || !fileInfo) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.params.id = fileInfo.id;
|
|
|
|
this.params.storage = fileInfo.get('storage');
|
|
|
|
this.params.path = fileInfo.get('path');
|
|
|
|
this.params.name = fileInfo.get('name');
|
|
|
|
this.params.fileData = null;
|
|
|
|
this.params.rev = null;
|
2016-04-06 23:13:44 +02:00
|
|
|
this.params.keyFileName = fileInfo.get('keyFileName');
|
2016-12-11 14:39:59 +01:00
|
|
|
this.params.keyFilePath = fileInfo.get('keyFilePath');
|
2017-03-26 11:15:36 +02:00
|
|
|
this.params.keyFileData = null;
|
2015-12-07 20:07:56 +01:00
|
|
|
this.displayOpenFile();
|
2016-04-06 23:13:44 +02:00
|
|
|
this.displayOpenKeyFile();
|
2015-11-07 20:02:45 +01:00
|
|
|
},
|
|
|
|
|
2017-12-03 20:31:54 +01:00
|
|
|
showOpenLocalFile: function(path, keyFilePath) {
|
2015-12-07 20:07:56 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.params.id = null;
|
|
|
|
this.params.storage = 'file';
|
|
|
|
this.params.path = path;
|
|
|
|
this.params.name = path.match(/[^/\\]*$/)[0];
|
|
|
|
this.params.rev = null;
|
|
|
|
this.params.fileData = null;
|
|
|
|
this.displayOpenFile();
|
2017-12-03 20:31:54 +01:00
|
|
|
if (keyFilePath) {
|
|
|
|
const parsed = Launcher.parsePath(keyFilePath);
|
|
|
|
this.params.keyFileName = parsed.file;
|
|
|
|
this.params.keyFilePath = keyFilePath;
|
|
|
|
this.params.keyFileData = null;
|
|
|
|
this.displayOpenKeyFile();
|
|
|
|
}
|
2015-11-07 20:02:45 +01:00
|
|
|
},
|
|
|
|
|
2015-12-06 21:32:41 +01:00
|
|
|
createDemo: function() {
|
|
|
|
if (!this.busy) {
|
2016-03-12 12:22:35 +01:00
|
|
|
this.closeConfig();
|
2015-12-06 21:32:41 +01:00
|
|
|
if (!this.model.createDemoFile()) {
|
|
|
|
this.trigger('close');
|
|
|
|
}
|
2016-03-13 10:54:16 +01:00
|
|
|
if (!this.model.settings.get('demoOpened')) {
|
|
|
|
this.model.settings.set('demoOpened', true);
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
}
|
2015-11-07 20:02:45 +01:00
|
|
|
},
|
|
|
|
|
2015-12-06 21:32:41 +01:00
|
|
|
createNew: function() {
|
|
|
|
if (!this.busy) {
|
|
|
|
this.model.createNewFile();
|
2015-11-07 20:02:45 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-12-06 21:32:41 +01:00
|
|
|
openDb: function() {
|
2016-06-05 16:49:00 +02:00
|
|
|
if (this.params.id && this.model.files.get(this.params.id)) {
|
2016-06-05 12:25:50 +02:00
|
|
|
this.trigger('close');
|
|
|
|
return;
|
|
|
|
}
|
2015-12-08 22:00:31 +01:00
|
|
|
if (this.busy || !this.params.name) {
|
|
|
|
return;
|
2015-11-07 20:02:45 +01:00
|
|
|
}
|
2015-12-08 22:00:31 +01:00
|
|
|
this.$el.toggleClass('open--opening', true);
|
|
|
|
this.inputEl.attr('disabled', 'disabled');
|
|
|
|
this.busy = true;
|
|
|
|
this.params.password = this.passwordInput.value;
|
|
|
|
this.afterPaint(this.model.openFile.bind(this.model, this.params, this.openDbComplete.bind(this)));
|
2015-11-07 20:02:45 +01:00
|
|
|
},
|
|
|
|
|
2015-12-06 21:32:41 +01:00
|
|
|
openDbComplete: function(err) {
|
|
|
|
this.busy = false;
|
|
|
|
this.$el.toggleClass('open--opening', false);
|
|
|
|
this.inputEl.removeAttr('disabled').toggleClass('input--error', !!err);
|
|
|
|
if (err) {
|
2015-12-12 09:53:50 +01:00
|
|
|
logger.error('Error opening file', err);
|
2016-05-13 14:09:21 +02:00
|
|
|
this.focusInput();
|
2015-12-06 21:32:41 +01:00
|
|
|
this.inputEl[0].selectionStart = 0;
|
|
|
|
this.inputEl[0].selectionEnd = this.inputEl.val().length;
|
2016-08-13 18:22:55 +02:00
|
|
|
if (err.code === 'InvalidKey') {
|
|
|
|
InputFx.shake(this.inputEl);
|
|
|
|
} else {
|
2016-07-31 09:47:56 +02:00
|
|
|
if (err.notFound) {
|
|
|
|
err = Locale.openErrorFileNotFound;
|
|
|
|
}
|
2016-03-15 20:08:08 +01:00
|
|
|
Alerts.error({
|
|
|
|
header: Locale.openError,
|
2016-07-17 13:30:38 +02:00
|
|
|
body: Locale.openErrorDescription + '<pre class="modal__pre">' + _.escape(err.toString()) + '</pre>'
|
2016-03-15 20:08:08 +01:00
|
|
|
});
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
} else {
|
|
|
|
this.trigger('close');
|
2015-11-07 20:02:45 +01:00
|
|
|
}
|
2016-03-01 04:29:20 +01:00
|
|
|
},
|
|
|
|
|
2016-03-04 18:06:18 +01:00
|
|
|
importDbWithXml: function() {
|
2016-03-01 04:29:20 +01:00
|
|
|
if (this.busy || !this.params.name) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.$el.toggleClass('open--opening', true);
|
|
|
|
this.inputEl.attr('disabled', 'disabled');
|
|
|
|
this.busy = true;
|
2017-09-29 20:35:35 +02:00
|
|
|
this.afterPaint(() => this.model.importFileWithXml(this.params, err => {
|
|
|
|
if (err) {
|
|
|
|
this.params.name = '';
|
|
|
|
this.params.fileXml = null;
|
|
|
|
}
|
|
|
|
this.openDbComplete(err);
|
|
|
|
}));
|
2016-03-09 21:52:19 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
toggleMore: function() {
|
2016-03-12 12:22:35 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.closeConfig();
|
2016-03-09 21:52:19 +01:00
|
|
|
this.$el.find('.open__icons--lower').toggleClass('hide');
|
2016-03-12 12:22:35 +01:00
|
|
|
},
|
|
|
|
|
2016-03-13 18:33:25 +01:00
|
|
|
openSettings: function() {
|
|
|
|
Backbone.trigger('toggle-settings');
|
|
|
|
},
|
|
|
|
|
2016-03-13 17:08:25 +01:00
|
|
|
openStorage: function(e) {
|
2016-03-12 12:22:35 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
2017-01-31 07:50:28 +01:00
|
|
|
const storage = Storage[$(e.target).closest('.open__icon').data('storage')];
|
2016-03-13 17:08:25 +01:00
|
|
|
if (!storage) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (storage.needShowOpenConfig && storage.needShowOpenConfig()) {
|
|
|
|
this.showConfig(storage);
|
|
|
|
} else if (storage.list) {
|
|
|
|
this.listStorage(storage);
|
|
|
|
} else {
|
|
|
|
Alerts.notImplemented();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-11-26 17:26:58 +01:00
|
|
|
listStorage: function(storage, config) {
|
2016-03-13 17:08:25 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.closeConfig();
|
2017-01-31 07:50:28 +01:00
|
|
|
const icon = this.$el.find('.open__icon-storage[data-storage=' + storage.name + ']');
|
2016-07-17 13:30:38 +02:00
|
|
|
this.busy = true;
|
2016-03-13 17:08:25 +01:00
|
|
|
icon.toggleClass('flip3d', true);
|
2017-11-26 17:26:58 +01:00
|
|
|
storage.list(config && config.dir, (err, files) => {
|
2016-03-13 17:08:25 +01:00
|
|
|
icon.toggleClass('flip3d', false);
|
2016-07-17 13:30:38 +02:00
|
|
|
this.busy = false;
|
2016-03-13 17:08:25 +01:00
|
|
|
if (err || !files) {
|
2017-06-11 19:41:56 +02:00
|
|
|
err = err ? err.toString() : '';
|
2017-11-27 19:00:39 +01:00
|
|
|
if (err.lastIndexOf('OAuth', 0) !== 0 && !Alerts.alertDisplayed) {
|
2017-06-11 19:41:56 +02:00
|
|
|
Alerts.error({
|
|
|
|
header: Locale.openError,
|
|
|
|
body: Locale.openListErrorBody + '<pre class="modal__pre">' + _.escape(err.toString()) + '</pre>'
|
|
|
|
});
|
|
|
|
}
|
2016-03-13 17:08:25 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-11-26 17:26:58 +01:00
|
|
|
if (!files.length) {
|
2016-03-14 06:16:33 +01:00
|
|
|
Alerts.error({
|
|
|
|
header: Locale.openNothingFound,
|
2017-04-16 17:00:35 +02:00
|
|
|
body: Locale.openNothingFoundBody
|
2016-03-14 06:16:33 +01:00
|
|
|
});
|
2016-03-13 17:08:25 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-11-26 17:26:58 +01:00
|
|
|
|
|
|
|
const fileNameComparator = Comparators.stringComparator('path', true);
|
|
|
|
files.sort((x, y) => {
|
|
|
|
if (x.dir !== y.dir) {
|
|
|
|
return !!y.dir - !!x.dir;
|
|
|
|
}
|
|
|
|
return fileNameComparator(x, y);
|
|
|
|
});
|
|
|
|
if (config && config.dir) {
|
|
|
|
files.unshift({
|
|
|
|
path: config.prevDir,
|
|
|
|
name: '..',
|
|
|
|
dir: true
|
|
|
|
});
|
|
|
|
}
|
|
|
|
const listView = new StorageFileListView({
|
|
|
|
model: {
|
|
|
|
files,
|
|
|
|
showHiddenFiles: config && config.showHiddenFiles
|
|
|
|
}
|
|
|
|
});
|
|
|
|
listView.on('selected', file => {
|
|
|
|
if (file.dir) {
|
|
|
|
this.listStorage(storage, {
|
|
|
|
dir: file.path,
|
|
|
|
prevDir: config && config.dir || '',
|
|
|
|
showHiddenFiles: true
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.openStorageFile(storage, file);
|
|
|
|
}
|
|
|
|
});
|
2016-03-13 17:08:25 +01:00
|
|
|
Alerts.alert({
|
|
|
|
header: Locale.openSelectFile,
|
|
|
|
body: Locale.openSelectFileBody,
|
|
|
|
icon: storage.icon || 'files-o',
|
2017-11-26 17:26:58 +01:00
|
|
|
buttons: [{result: '', title: Locale.alertCancel}],
|
2016-03-13 17:08:25 +01:00
|
|
|
esc: '',
|
|
|
|
click: '',
|
2017-11-26 17:26:58 +01:00
|
|
|
view: listView
|
2016-03-13 17:08:25 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
openStorageFile: function(storage, file) {
|
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.params.id = null;
|
|
|
|
this.params.storage = storage.name;
|
|
|
|
this.params.path = file.path;
|
|
|
|
this.params.name = UrlUtil.getDataFileName(file.name);
|
|
|
|
this.params.rev = file.rev;
|
|
|
|
this.params.fileData = null;
|
|
|
|
this.displayOpenFile();
|
2016-03-12 12:22:35 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
showConfig: function(storage) {
|
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this.views.openConfig) {
|
|
|
|
this.views.openConfig.remove();
|
|
|
|
}
|
2017-01-31 07:50:28 +01:00
|
|
|
const config = _.extend({
|
2016-03-12 12:22:35 +01:00
|
|
|
id: storage.name,
|
|
|
|
name: Locale[storage.name] || storage.name,
|
2017-11-27 22:11:00 +01:00
|
|
|
icon: storage.icon,
|
|
|
|
buttons: true
|
2016-03-13 17:45:55 +01:00
|
|
|
}, storage.getOpenConfig());
|
2016-03-12 12:22:35 +01:00
|
|
|
this.views.openConfig = new OpenConfigView({ el: this.$el.find('.open__config-wrap'), model: config }).render();
|
|
|
|
this.views.openConfig.on('cancel', this.closeConfig.bind(this));
|
|
|
|
this.views.openConfig.on('apply', this.applyConfig.bind(this));
|
2016-03-13 17:08:25 +01:00
|
|
|
this.$el.find('.open__pass-area').addClass('hide');
|
|
|
|
this.$el.find('.open__icons--lower').addClass('hide');
|
2016-03-12 12:22:35 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
closeConfig: function() {
|
|
|
|
if (this.busy) {
|
|
|
|
this.storageWaitId = null;
|
|
|
|
this.busy = false;
|
|
|
|
}
|
|
|
|
if (this.views.openConfig) {
|
|
|
|
this.views.openConfig.remove();
|
|
|
|
delete this.views.openConfig;
|
|
|
|
}
|
|
|
|
this.$el.find('.open__pass-area').removeClass('hide');
|
|
|
|
this.$el.find('.open__config').addClass('hide');
|
2016-05-13 14:09:21 +02:00
|
|
|
this.focusInput();
|
2016-03-12 12:22:35 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
applyConfig: function(config) {
|
|
|
|
if (this.busy || !config) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.busy = true;
|
|
|
|
this.views.openConfig.setDisabled(true);
|
2017-01-31 07:50:28 +01:00
|
|
|
const storage = Storage[config.storage];
|
2016-03-12 12:22:35 +01:00
|
|
|
this.storageWaitId = Math.random();
|
2017-01-31 07:50:28 +01:00
|
|
|
const path = config.path;
|
|
|
|
const opts = _.omit(config, ['path', 'storage']);
|
|
|
|
const req = {
|
2016-03-12 17:49:52 +01:00
|
|
|
waitId: this.storageWaitId,
|
|
|
|
storage: config.storage,
|
|
|
|
path: path,
|
|
|
|
opts: opts
|
|
|
|
};
|
2016-03-13 17:45:55 +01:00
|
|
|
if (storage.applyConfig) {
|
|
|
|
storage.applyConfig(opts, this.storageApplyConfigComplete.bind(this, req));
|
|
|
|
} else {
|
|
|
|
storage.stat(path, opts, this.storageStatComplete.bind(this, req));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
storageApplyConfigComplete: function(req, err) {
|
|
|
|
if (this.storageWaitId !== req.waitId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.storageWaitId = null;
|
|
|
|
this.busy = false;
|
|
|
|
if (err) {
|
|
|
|
this.views.openConfig.setDisabled(false);
|
|
|
|
this.views.openConfig.setError(err);
|
|
|
|
} else {
|
|
|
|
this.closeConfig();
|
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
},
|
|
|
|
|
2016-03-12 17:49:52 +01:00
|
|
|
storageStatComplete: function(req, err, stat) {
|
|
|
|
if (this.storageWaitId !== req.waitId) {
|
2016-03-12 12:22:35 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.storageWaitId = null;
|
|
|
|
this.busy = false;
|
|
|
|
if (err) {
|
2016-03-12 17:49:52 +01:00
|
|
|
this.views.openConfig.setDisabled(false);
|
2016-03-12 12:22:35 +01:00
|
|
|
this.views.openConfig.setError(err);
|
2016-03-12 17:49:52 +01:00
|
|
|
} else {
|
|
|
|
this.closeConfig();
|
|
|
|
this.params.id = null;
|
|
|
|
this.params.storage = req.storage;
|
|
|
|
this.params.path = req.path;
|
|
|
|
this.params.opts = req.opts;
|
|
|
|
this.params.name = UrlUtil.getDataFileName(req.path);
|
|
|
|
this.params.rev = stat.rev;
|
|
|
|
this.params.fileData = null;
|
|
|
|
this.displayOpenFile();
|
2016-03-12 12:22:35 +01:00
|
|
|
}
|
2015-10-17 23:49:24 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = OpenView;
|