mirror of https://github.com/keeweb/keeweb.git
fix #163: allow opening same file twice
This commit is contained in:
parent
5fe2ec0c15
commit
c7240edca9
|
@ -23,7 +23,7 @@ var FileCollection = Backbone.Collection.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
getById: function(id) {
|
getById: function(id) {
|
||||||
return this.find(function(file) { return file.get('id') === id; });
|
return this.find(function(file) { return file.id === id; });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -263,7 +263,7 @@ var AppModel = Backbone.Model.extend({
|
||||||
createDemoFile: function() {
|
createDemoFile: function() {
|
||||||
var that = this;
|
var that = this;
|
||||||
if (!this.files.getByName('Demo')) {
|
if (!this.files.getByName('Demo')) {
|
||||||
var demoFile = new FileModel();
|
var demoFile = new FileModel({ id: IdGenerator.uuid() });
|
||||||
demoFile.openDemo(function() {
|
demoFile.openDemo(function() {
|
||||||
that.addFile(demoFile);
|
that.addFile(demoFile);
|
||||||
});
|
});
|
||||||
|
@ -281,7 +281,7 @@ var AppModel = Backbone.Model.extend({
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var newFile = new FileModel();
|
var newFile = new FileModel({ id: IdGenerator.uuid() });
|
||||||
newFile.create(name);
|
newFile.create(name);
|
||||||
this.addFile(newFile);
|
this.addFile(newFile);
|
||||||
},
|
},
|
||||||
|
@ -383,6 +383,7 @@ var AppModel = Backbone.Model.extend({
|
||||||
params.keyFileData = FileModel.createKeyFileWithHash(fileInfo.get('keyFileHash'));
|
params.keyFileData = FileModel.createKeyFileWithHash(fileInfo.get('keyFileHash'));
|
||||||
}
|
}
|
||||||
var file = new FileModel({
|
var file = new FileModel({
|
||||||
|
id: fileInfo ? fileInfo.id : IdGenerator.uuid(),
|
||||||
name: params.name,
|
name: params.name,
|
||||||
storage: params.storage,
|
storage: params.storage,
|
||||||
path: params.path,
|
path: params.path,
|
||||||
|
@ -407,11 +408,9 @@ var AppModel = Backbone.Model.extend({
|
||||||
if (fileInfo) {
|
if (fileInfo) {
|
||||||
file.set('syncDate', fileInfo.get('syncDate'));
|
file.set('syncDate', fileInfo.get('syncDate'));
|
||||||
}
|
}
|
||||||
var cacheId = fileInfo && fileInfo.id || IdGenerator.uuid();
|
|
||||||
file.set('cacheId', cacheId);
|
|
||||||
if (updateCacheOnSuccess) {
|
if (updateCacheOnSuccess) {
|
||||||
logger.info('Save loaded file to cache');
|
logger.info('Save loaded file to cache');
|
||||||
Storage.cache.save(cacheId, null, params.fileData);
|
Storage.cache.save(file.id, null, params.fileData);
|
||||||
}
|
}
|
||||||
var rev = params.rev || fileInfo && fileInfo.get('rev');
|
var rev = params.rev || fileInfo && fileInfo.get('rev');
|
||||||
that.setFileOpts(file, params.opts);
|
that.setFileOpts(file, params.opts);
|
||||||
|
@ -426,6 +425,7 @@ var AppModel = Backbone.Model.extend({
|
||||||
var logger = new Logger('import', params.name);
|
var logger = new Logger('import', params.name);
|
||||||
logger.info('File import request with supplied xml');
|
logger.info('File import request with supplied xml');
|
||||||
var file = new FileModel({
|
var file = new FileModel({
|
||||||
|
id: IdGenerator.uuid(),
|
||||||
name: params.name,
|
name: params.name,
|
||||||
storage: params.storage,
|
storage: params.storage,
|
||||||
path: params.path
|
path: params.path
|
||||||
|
@ -442,10 +442,10 @@ var AppModel = Backbone.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
addToLastOpenFiles: function(file, rev) {
|
addToLastOpenFiles: function(file, rev) {
|
||||||
this.appLogger.debug('Add last open file', file.get('cacheId'), file.get('name'), file.get('storage'), file.get('path'), rev);
|
this.appLogger.debug('Add last open file', file.id, file.get('name'), file.get('storage'), file.get('path'), rev);
|
||||||
var dt = new Date();
|
var dt = new Date();
|
||||||
var fileInfo = new FileInfoModel({
|
var fileInfo = new FileInfoModel({
|
||||||
id: file.get('cacheId'),
|
id: file.id,
|
||||||
name: file.get('name'),
|
name: file.get('name'),
|
||||||
storage: file.get('storage'),
|
storage: file.get('storage'),
|
||||||
path: file.get('path'),
|
path: file.get('path'),
|
||||||
|
@ -462,7 +462,7 @@ var AppModel = Backbone.Model.extend({
|
||||||
keyFileHash: file.getKeyFileHash()
|
keyFileHash: file.getKeyFileHash()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.fileInfos.remove(file.get('cacheId'));
|
this.fileInfos.remove(file.id);
|
||||||
this.fileInfos.unshift(fileInfo);
|
this.fileInfos.unshift(fileInfo);
|
||||||
this.fileInfos.save();
|
this.fileInfos.save();
|
||||||
},
|
},
|
||||||
|
@ -504,7 +504,7 @@ var AppModel = Backbone.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
getFileInfo: function(file) {
|
getFileInfo: function(file) {
|
||||||
return file.get('cacheId') ? this.fileInfos.get(file.get('cacheId')) :
|
return this.fileInfos.get(file.id) ||
|
||||||
this.fileInfos.getMatch(file.get('storage'), file.get('name'), file.get('path'));
|
this.fileInfos.getMatch(file.get('storage'), file.get('name'), file.get('path'));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -549,7 +549,6 @@ var AppModel = Backbone.Model.extend({
|
||||||
if (!err) { savedToCache = true; }
|
if (!err) { savedToCache = true; }
|
||||||
logger.info('Sync finished', err || 'no error');
|
logger.info('Sync finished', err || 'no error');
|
||||||
file.setSyncComplete(path, storage, err ? err.toString() : null, savedToCache);
|
file.setSyncComplete(path, storage, err ? err.toString() : null, savedToCache);
|
||||||
file.set('cacheId', fileInfo.id);
|
|
||||||
fileInfo.set({
|
fileInfo.set({
|
||||||
name: file.get('name'),
|
name: file.get('name'),
|
||||||
storage: storage,
|
storage: storage,
|
||||||
|
@ -557,8 +556,7 @@ var AppModel = Backbone.Model.extend({
|
||||||
opts: that.getStoreOpts(file),
|
opts: that.getStoreOpts(file),
|
||||||
modified: file.get('modified'),
|
modified: file.get('modified'),
|
||||||
editState: file.getLocalEditState(),
|
editState: file.getLocalEditState(),
|
||||||
syncDate: file.get('syncDate'),
|
syncDate: file.get('syncDate')
|
||||||
cacheId: fileInfo.id
|
|
||||||
});
|
});
|
||||||
if (that.settings.get('rememberKeyFiles')) {
|
if (that.settings.get('rememberKeyFiles')) {
|
||||||
fileInfo.set({
|
fileInfo.set({
|
||||||
|
@ -573,7 +571,7 @@ var AppModel = Backbone.Model.extend({
|
||||||
if (callback) { callback(err); }
|
if (callback) { callback(err); }
|
||||||
};
|
};
|
||||||
if (!storage) {
|
if (!storage) {
|
||||||
if (!file.get('modified') && fileInfo.id === file.get('cacheId')) {
|
if (!file.get('modified') && fileInfo.id === file.id) {
|
||||||
logger.info('Local, not modified');
|
logger.info('Local, not modified');
|
||||||
return complete();
|
return complete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ var EntryModel = Backbone.Model.extend({
|
||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
if (this.id === entry.uuid.id) {
|
if (this.get('uuid') === entry.uuid.id) {
|
||||||
this._checkUpdatedEntry();
|
this._checkUpdatedEntry();
|
||||||
}
|
}
|
||||||
this._fillByEntry();
|
this._fillByEntry();
|
||||||
|
@ -29,7 +29,7 @@ var EntryModel = Backbone.Model.extend({
|
||||||
|
|
||||||
_fillByEntry: function() {
|
_fillByEntry: function() {
|
||||||
var entry = this.entry;
|
var entry = this.entry;
|
||||||
this.set({id: entry.uuid.id}, {silent: true});
|
this.set({id: this.file.subId(entry.uuid.id), uuid: entry.uuid.id}, {silent: true});
|
||||||
this.fileName = this.file.get('name');
|
this.fileName = this.file.get('name');
|
||||||
this.groupName = this.group.get('title');
|
this.groupName = this.group.get('title');
|
||||||
this.title = entry.fields.Title || '';
|
this.title = entry.fields.Title || '';
|
||||||
|
|
|
@ -13,6 +13,7 @@ var logger = new Logger('file');
|
||||||
var FileModel = Backbone.Model.extend({
|
var FileModel = Backbone.Model.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
id: '',
|
id: '',
|
||||||
|
uuid: '',
|
||||||
name: '',
|
name: '',
|
||||||
keyFileName: '',
|
keyFileName: '',
|
||||||
passwordLength: 0,
|
passwordLength: 0,
|
||||||
|
@ -31,8 +32,7 @@ var FileModel = Backbone.Model.extend({
|
||||||
keyFileChanged: false,
|
keyFileChanged: false,
|
||||||
syncing: false,
|
syncing: false,
|
||||||
syncError: null,
|
syncError: null,
|
||||||
syncDate: null,
|
syncDate: null
|
||||||
cacheId: null
|
|
||||||
},
|
},
|
||||||
|
|
||||||
db: null,
|
db: null,
|
||||||
|
@ -136,7 +136,7 @@ var FileModel = Backbone.Model.extend({
|
||||||
readModel: function() {
|
readModel: function() {
|
||||||
var groups = new GroupCollection();
|
var groups = new GroupCollection();
|
||||||
this.set({
|
this.set({
|
||||||
id: this.db.getDefaultGroup().uuid.toString(),
|
uuid: this.db.getDefaultGroup().uuid.toString(),
|
||||||
groups: groups,
|
groups: groups,
|
||||||
defaultUser: this.db.meta.defaultUser,
|
defaultUser: this.db.meta.defaultUser,
|
||||||
recycleBinEnabled: this.db.meta.recycleBinEnabled,
|
recycleBinEnabled: this.db.meta.recycleBinEnabled,
|
||||||
|
@ -145,18 +145,21 @@ var FileModel = Backbone.Model.extend({
|
||||||
keyEncryptionRounds: this.db.header.keyEncryptionRounds
|
keyEncryptionRounds: this.db.header.keyEncryptionRounds
|
||||||
}, { silent: true });
|
}, { silent: true });
|
||||||
this.db.groups.forEach(function(group) {
|
this.db.groups.forEach(function(group) {
|
||||||
var groupModel = this.getGroup(group.uuid.id);
|
var groupModel = this.getGroup(this.subId(group.uuid.id));
|
||||||
if (groupModel) {
|
if (groupModel) {
|
||||||
groupModel.setGroup(group, this);
|
groupModel.setGroup(group, this);
|
||||||
} else {
|
} else {
|
||||||
groupModel = GroupModel.fromGroup(group, this);
|
groupModel = GroupModel.fromGroup(group, this);
|
||||||
}
|
}
|
||||||
groupModel.set({title: this.get('name')});
|
|
||||||
groups.add(groupModel);
|
groups.add(groupModel);
|
||||||
}, this);
|
}, this);
|
||||||
this.buildObjectMap();
|
this.buildObjectMap();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
subId: function(id) {
|
||||||
|
return this.id + ':' + id;
|
||||||
|
},
|
||||||
|
|
||||||
buildObjectMap: function() {
|
buildObjectMap: function() {
|
||||||
var entryMap = {};
|
var entryMap = {};
|
||||||
var groupMap = {};
|
var groupMap = {};
|
||||||
|
@ -257,7 +260,7 @@ var FileModel = Backbone.Model.extend({
|
||||||
forEachEntry: function(filter, callback) {
|
forEachEntry: function(filter, callback) {
|
||||||
var top = this;
|
var top = this;
|
||||||
if (filter.trash) {
|
if (filter.trash) {
|
||||||
top = this.getGroup(this.db.meta.recycleBinUuid ? this.db.meta.recycleBinUuid.id : null);
|
top = this.getGroup(this.db.meta.recycleBinUuid ? this.subId(this.db.meta.recycleBinUuid.id) : null);
|
||||||
} else if (filter.group) {
|
} else if (filter.group) {
|
||||||
top = this.getGroup(filter.group);
|
top = this.getGroup(filter.group);
|
||||||
}
|
}
|
||||||
|
@ -282,7 +285,7 @@ var FileModel = Backbone.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
getTrashGroup: function() {
|
getTrashGroup: function() {
|
||||||
return this.db.meta.recycleBinEnabled ? this.getGroup(this.db.meta.recycleBinUuid.id) : null;
|
return this.db.meta.recycleBinEnabled ? this.getGroup(this.subId(this.db.meta.recycleBinUuid.id)) : null;
|
||||||
},
|
},
|
||||||
|
|
||||||
setModified: function() {
|
setModified: function() {
|
||||||
|
@ -455,9 +458,9 @@ var FileModel = Backbone.Model.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
addCustomIcon: function(iconData) {
|
addCustomIcon: function(iconData) {
|
||||||
var id = kdbxweb.KdbxUuid.random();
|
var uuid = kdbxweb.KdbxUuid.random();
|
||||||
this.db.meta.customIcons[id] = kdbxweb.ByteUtils.arrayToBuffer(kdbxweb.ByteUtils.base64ToBytes(iconData));
|
this.db.meta.customIcons[uuid] = kdbxweb.ByteUtils.arrayToBuffer(kdbxweb.ByteUtils.base64ToBytes(iconData));
|
||||||
return id.toString();
|
return uuid.toString();
|
||||||
},
|
},
|
||||||
|
|
||||||
renameTag: function(from, to) {
|
renameTag: function(from, to) {
|
||||||
|
|
|
@ -31,13 +31,15 @@ var GroupModel = MenuItemModel.extend({
|
||||||
|
|
||||||
setGroup: function(group, file, parentGroup) {
|
setGroup: function(group, file, parentGroup) {
|
||||||
var isRecycleBin = file.db.meta.recycleBinUuid && file.db.meta.recycleBinUuid.id === group.uuid.id;
|
var isRecycleBin = file.db.meta.recycleBinUuid && file.db.meta.recycleBinUuid.id === group.uuid.id;
|
||||||
|
var id = file.subId(group.uuid.id);
|
||||||
this.set({
|
this.set({
|
||||||
id: group.uuid.id,
|
id: id,
|
||||||
|
uuid: group.uuid.id,
|
||||||
expanded: group.expanded,
|
expanded: group.expanded,
|
||||||
visible: !isRecycleBin,
|
visible: !isRecycleBin,
|
||||||
items: new GroupCollection(),
|
items: new GroupCollection(),
|
||||||
entries: new EntryCollection(),
|
entries: new EntryCollection(),
|
||||||
filterValue: group.uuid.id,
|
filterValue: id,
|
||||||
enableSearching: group.enableSearching,
|
enableSearching: group.enableSearching,
|
||||||
enableAutoType: group.enableAutoType,
|
enableAutoType: group.enableAutoType,
|
||||||
autoTypeSeq: group.defaultAutoTypeSeq,
|
autoTypeSeq: group.defaultAutoTypeSeq,
|
||||||
|
@ -52,7 +54,7 @@ var GroupModel = MenuItemModel.extend({
|
||||||
var items = this.get('items'),
|
var items = this.get('items'),
|
||||||
entries = this.get('entries');
|
entries = this.get('entries');
|
||||||
group.groups.forEach(function(subGroup) {
|
group.groups.forEach(function(subGroup) {
|
||||||
var existing = file.getGroup(subGroup.uuid);
|
var existing = file.getGroup(file.subId(subGroup.uuid.id));
|
||||||
if (existing) {
|
if (existing) {
|
||||||
existing.setGroup(subGroup, file, this);
|
existing.setGroup(subGroup, file, this);
|
||||||
items.add(existing);
|
items.add(existing);
|
||||||
|
@ -61,7 +63,7 @@ var GroupModel = MenuItemModel.extend({
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
group.entries.forEach(function(entry) {
|
group.entries.forEach(function(entry) {
|
||||||
var existing = file.getEntry(entry.uuid);
|
var existing = file.getEntry(file.subId(entry.uuid.id));
|
||||||
if (existing) {
|
if (existing) {
|
||||||
existing.setEntry(entry, this, file);
|
existing.setEntry(entry, this, file);
|
||||||
entries.add(existing);
|
entries.add(existing);
|
||||||
|
@ -73,7 +75,7 @@ var GroupModel = MenuItemModel.extend({
|
||||||
|
|
||||||
_fillByGroup: function(silent) {
|
_fillByGroup: function(silent) {
|
||||||
this.set({
|
this.set({
|
||||||
title: this.group.name,
|
title: this.parentGroup ? this.group.name : this.file.get('name'),
|
||||||
iconId: this.group.icon,
|
iconId: this.group.icon,
|
||||||
icon: this._iconFromId(this.group.icon),
|
icon: this._iconFromId(this.group.icon),
|
||||||
customIcon: this._buildCustomIcon(),
|
customIcon: this._buildCustomIcon(),
|
||||||
|
|
|
@ -19,7 +19,7 @@ EntryPresenter.prototype = {
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
get id() { return this.entry ? this.entry.id : this.group.get('id'); },
|
get id() { return this.entry ? this.entry.id : this.group.id; },
|
||||||
get icon() { return this.entry ? this.entry.icon : (this.group.get('icon') || 'folder'); },
|
get icon() { return this.entry ? this.entry.icon : (this.group.get('icon') || 'folder'); },
|
||||||
get customIcon() { return this.entry ? this.entry.customIcon : undefined; },
|
get customIcon() { return this.entry ? this.entry.customIcon : undefined; },
|
||||||
get color() { return this.entry ? (this.entry.color || (this.entry.customIcon ? this.noColor : undefined)) : undefined; },
|
get color() { return this.entry ? (this.entry.color || (this.entry.customIcon ? this.noColor : undefined)) : undefined; },
|
||||||
|
|
|
@ -107,7 +107,7 @@ var StorageWebDav = StorageBase.extend({
|
||||||
fileOptsToStoreOpts: function(opts, file) {
|
fileOptsToStoreOpts: function(opts, file) {
|
||||||
var result = {user: opts.user, encpass: opts.encpass};
|
var result = {user: opts.user, encpass: opts.encpass};
|
||||||
if (opts.password) {
|
if (opts.password) {
|
||||||
var fileId = file.get('id');
|
var fileId = file.get('uuid');
|
||||||
var password = opts.password;
|
var password = opts.password;
|
||||||
var encpass = '';
|
var encpass = '';
|
||||||
for (var i = 0; i < password.length; i++) {
|
for (var i = 0; i < password.length; i++) {
|
||||||
|
@ -121,7 +121,7 @@ var StorageWebDav = StorageBase.extend({
|
||||||
storeOptsToFileOpts: function(opts, file) {
|
storeOptsToFileOpts: function(opts, file) {
|
||||||
var result = {user: opts.user, password: opts.password};
|
var result = {user: opts.user, password: opts.password};
|
||||||
if (opts.encpass) {
|
if (opts.encpass) {
|
||||||
var fileId = file.get('id');
|
var fileId = file.get('uuid');
|
||||||
var encpass = atob(opts.encpass);
|
var encpass = atob(opts.encpass);
|
||||||
var password = '';
|
var password = '';
|
||||||
for (var i = 0; i < encpass.length; i++) {
|
for (var i = 0; i < encpass.length; i++) {
|
||||||
|
|
|
@ -449,6 +449,10 @@ var OpenView = Backbone.View.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
openDb: function() {
|
openDb: function() {
|
||||||
|
if (this.params.id && this.model.files.getById(this.params.id)) {
|
||||||
|
this.trigger('close');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.busy || !this.params.name) {
|
if (this.busy || !this.params.name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ Auto-type, ui improvements
|
||||||
`+` logout from remote storages on disable
|
`+` logout from remote storages on disable
|
||||||
`*` don't check updates at startup
|
`*` don't check updates at startup
|
||||||
`*` repos moved to github organization account
|
`*` repos moved to github organization account
|
||||||
|
`*` allow opening same file twice
|
||||||
`-` prevent second app instance on windows
|
`-` prevent second app instance on windows
|
||||||
`-` fix drag-drop in Safari
|
`-` fix drag-drop in Safari
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue