keeweb/app/scripts/models/group-model.js

376 lines
11 KiB
JavaScript
Raw Normal View History

2019-09-15 14:16:32 +02:00
import kdbxweb from 'kdbxweb';
import { IconMap } from 'const/icon-map';
import { EntryModel } from 'models/entry-model';
import { MenuItemModel } from 'models/menu/menu-item-model';
import { IconUrlFormat } from 'util/formatting/icon-url-format';
import { GroupCollection } from 'collections/group-collection';
import { EntryCollection } from 'collections/entry-collection';
2017-01-31 07:50:28 +01:00
const KdbxIcons = kdbxweb.Consts.Icons;
const DefaultAutoTypeSequence = '{USERNAME}{TAB}{PASSWORD}{ENTER}';
2019-09-18 23:37:57 +02:00
class GroupModel extends MenuItemModel {
2019-08-18 10:17:09 +02:00
setGroup(group, file, parentGroup) {
2017-05-02 21:22:08 +02:00
const isRecycleBin = group.uuid.equals(file.db.meta.recycleBinUuid);
2017-01-31 07:50:28 +01:00
const id = file.subId(group.uuid.id);
2019-08-16 23:05:39 +02:00
this.set(
{
2019-08-18 10:17:09 +02:00
id,
2019-08-16 23:05:39 +02:00
uuid: group.uuid.id,
expanded: group.expanded,
visible: !isRecycleBin,
items: new GroupCollection(),
entries: new EntryCollection(),
filterValue: id,
enableSearching: group.enableSearching,
enableAutoType: group.enableAutoType,
autoTypeSeq: group.defaultAutoTypeSeq,
top: !parentGroup,
drag: !!parentGroup,
collapsible: !!parentGroup
},
{ silent: true }
);
2015-10-17 23:49:24 +02:00
this.group = group;
this.file = file;
2015-12-05 14:04:09 +01:00
this.parentGroup = parentGroup;
2015-10-31 20:09:32 +01:00
this._fillByGroup(true);
2019-09-18 23:37:57 +02:00
const items = this.items;
const entries = this.entries;
2020-06-01 16:53:51 +02:00
const itemsArray = group.groups.map((subGroup) => {
let g = file.getGroup(file.subId(subGroup.uuid.id));
if (g) {
g.setGroup(subGroup, file, this);
2015-12-05 14:04:09 +01:00
} else {
g = GroupModel.fromGroup(subGroup, file, this);
2015-12-05 14:04:09 +01:00
}
return g;
2015-10-31 20:09:32 +01:00
}, this);
2019-09-18 23:37:57 +02:00
items.push(...itemsArray);
2020-06-01 16:53:51 +02:00
const entriesArray = group.entries.map((entry) => {
let e = file.getEntry(file.subId(entry.uuid.id));
if (e) {
e.setEntry(entry, this, file);
2015-12-05 14:04:09 +01:00
} else {
e = EntryModel.fromEntry(entry, this, file);
2015-12-05 14:04:09 +01:00
}
return e;
2015-10-17 23:49:24 +02:00
}, this);
2019-09-18 23:37:57 +02:00
entries.push(...entriesArray);
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
_fillByGroup(silent) {
2019-08-16 23:05:39 +02:00
this.set(
{
2019-09-17 21:39:06 +02:00
title: this.parentGroup ? this.group.name : this.file.name,
2019-08-16 23:05:39 +02:00
iconId: this.group.icon,
icon: this._iconFromId(this.group.icon),
customIcon: this._buildCustomIcon(),
customIconId: this.group.customIcon ? this.group.customIcon.toString() : null,
expanded: this.group.expanded !== false
},
2019-08-18 10:17:09 +02:00
{ silent }
2019-08-16 23:05:39 +02:00
);
2019-09-18 23:37:57 +02:00
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
_iconFromId(id) {
2015-10-17 23:49:24 +02:00
if (id === KdbxIcons.Folder || id === KdbxIcons.FolderOpen) {
return undefined;
}
return IconMap[id];
2019-09-18 23:37:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
_buildCustomIcon() {
2015-11-21 21:14:21 +01:00
this.customIcon = null;
if (this.group.customIcon) {
2019-09-15 08:11:11 +02:00
return IconUrlFormat.toDataUrl(this.file.db.meta.customIcons[this.group.customIcon]);
2015-11-21 21:14:21 +01:00
}
return null;
2019-09-18 23:37:57 +02:00
}
2015-11-21 21:14:21 +01:00
2019-08-18 10:17:09 +02:00
_groupModified() {
2015-10-31 20:09:32 +01:00
if (this.isJustCreated) {
this.isJustCreated = false;
}
this.file.setModified();
this.group.times.update();
2019-09-18 23:37:57 +02:00
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
forEachGroup(callback, filter) {
2017-01-31 07:50:28 +01:00
let result = true;
2020-06-01 16:53:51 +02:00
this.items.forEach((group) => {
2017-01-29 19:03:38 +01:00
if (group.matches(filter)) {
2019-08-18 08:05:38 +02:00
result =
callback(group) !== false && group.forEachGroup(callback, filter) !== false;
2015-10-17 23:49:24 +02:00
}
});
return result;
2019-09-18 23:37:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
forEachOwnEntry(filter, callback) {
2020-06-01 16:53:51 +02:00
this.entries.forEach(function (entry) {
2015-10-17 23:49:24 +02:00
if (entry.matches(filter)) {
callback(entry, this);
}
});
2019-09-18 23:37:57 +02:00
}
2015-10-17 23:49:24 +02:00
2019-08-18 10:17:09 +02:00
matches(filter) {
2019-08-16 23:05:39 +02:00
return (
((filter && filter.includeDisabled) ||
(this.group.enableSearching !== false &&
!this.group.uuid.equals(this.file.db.meta.entryTemplatesGroup))) &&
(!filter || !filter.autoType || this.group.enableAutoType !== false)
);
2019-09-18 23:37:57 +02:00
}
2017-01-29 19:03:38 +01:00
2019-08-18 10:17:09 +02:00
getOwnSubGroups() {
2015-11-08 22:25:00 +01:00
return this.group.groups;
2019-09-18 23:37:57 +02:00
}
2015-11-08 22:25:00 +01:00
2019-08-18 10:17:09 +02:00
addEntry(entry) {
2019-09-18 23:37:57 +02:00
this.entries.push(entry);
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
addGroup(group) {
2019-09-18 23:37:57 +02:00
this.items.push(group);
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
setName(name) {
2015-10-31 20:09:32 +01:00
this._groupModified();
this.group.name = name;
this._fillByGroup();
2019-09-18 23:37:57 +02:00
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
setIcon(iconId) {
2015-10-31 20:09:32 +01:00
this._groupModified();
this.group.icon = iconId;
2015-11-21 23:15:51 +01:00
this.group.customIcon = undefined;
this._fillByGroup();
2019-09-18 23:37:57 +02:00
}
2015-11-21 23:15:51 +01:00
2019-08-18 10:17:09 +02:00
setCustomIcon(customIconId) {
2015-11-21 23:15:51 +01:00
this._groupModified();
this.group.customIcon = new kdbxweb.KdbxUuid(customIconId);
2015-10-31 20:09:32 +01:00
this._fillByGroup();
2019-09-18 23:37:57 +02:00
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
setExpanded(expanded) {
// this._groupModified(); // it's not good to mark the file as modified when a group is collapsed
2015-12-05 14:04:09 +01:00
this.group.expanded = expanded;
2019-09-18 23:37:57 +02:00
this.expanded = expanded;
}
2015-12-05 14:04:09 +01:00
2019-08-18 10:17:09 +02:00
setEnableSearching(enabled) {
2015-12-08 18:21:12 +01:00
this._groupModified();
2017-01-31 07:50:28 +01:00
let parentEnableSearching = true;
let parentGroup = this.parentGroup;
2016-04-17 16:00:58 +02:00
while (parentGroup) {
2019-09-18 23:37:57 +02:00
if (typeof parentGroup.enableSearching === 'boolean') {
parentEnableSearching = parentGroup.enableSearching;
2016-04-17 16:00:58 +02:00
break;
}
parentGroup = parentGroup.parentGroup;
}
if (enabled === parentEnableSearching) {
2016-04-23 16:50:40 +02:00
enabled = null;
2016-04-17 16:00:58 +02:00
}
2015-12-08 18:21:12 +01:00
this.group.enableSearching = enabled;
2019-09-18 23:37:57 +02:00
this.enableSearching = this.group.enableSearching;
}
2016-04-17 16:00:58 +02:00
2019-08-18 10:17:09 +02:00
getEffectiveEnableSearching() {
2017-01-31 07:50:28 +01:00
let grp = this;
2016-04-17 16:00:58 +02:00
while (grp) {
2019-09-18 23:37:57 +02:00
if (typeof grp.enableSearching === 'boolean') {
return grp.enableSearching;
2016-04-17 16:00:58 +02:00
}
grp = grp.parentGroup;
}
return true;
2019-09-18 23:37:57 +02:00
}
2015-12-08 18:21:12 +01:00
2019-08-18 10:17:09 +02:00
setEnableAutoType(enabled) {
2016-04-17 14:31:08 +02:00
this._groupModified();
2017-01-31 07:50:28 +01:00
let parentEnableAutoType = true;
let parentGroup = this.parentGroup;
2016-04-17 16:00:58 +02:00
while (parentGroup) {
2019-09-18 23:37:57 +02:00
if (typeof parentGroup.enableAutoType === 'boolean') {
parentEnableAutoType = parentGroup.enableAutoType;
2016-04-17 16:00:58 +02:00
break;
}
parentGroup = parentGroup.parentGroup;
}
if (enabled === parentEnableAutoType) {
2016-04-23 16:50:40 +02:00
enabled = null;
2016-04-17 16:00:58 +02:00
}
2016-04-17 14:31:08 +02:00
this.group.enableAutoType = enabled;
2019-09-18 23:37:57 +02:00
this.enableAutoType = this.group.enableAutoType;
}
2016-04-17 16:00:58 +02:00
2019-08-18 10:17:09 +02:00
getEffectiveEnableAutoType() {
2017-01-31 07:50:28 +01:00
let grp = this;
2016-04-17 16:00:58 +02:00
while (grp) {
2019-09-18 23:37:57 +02:00
if (typeof grp.enableAutoType === 'boolean') {
return grp.enableAutoType;
2016-04-17 16:00:58 +02:00
}
grp = grp.parentGroup;
}
return true;
2019-09-18 23:37:57 +02:00
}
2016-04-17 14:31:08 +02:00
2019-08-18 10:17:09 +02:00
setAutoTypeSeq(seq) {
2016-04-17 14:31:08 +02:00
this._groupModified();
this.group.defaultAutoTypeSeq = seq || undefined;
2019-09-18 23:37:57 +02:00
this.autoTypeSeq = this.group.defaultAutoTypeSeq;
}
2016-04-17 14:31:08 +02:00
2019-08-18 10:17:09 +02:00
getEffectiveAutoTypeSeq() {
2017-01-31 07:50:28 +01:00
let grp = this;
2016-04-23 16:50:40 +02:00
while (grp) {
2019-09-18 23:37:57 +02:00
if (grp.autoTypeSeq) {
return grp.autoTypeSeq;
2016-04-23 16:50:40 +02:00
}
grp = grp.parentGroup;
}
2016-04-23 21:55:57 +02:00
return DefaultAutoTypeSequence;
2019-09-18 23:37:57 +02:00
}
2016-04-23 16:50:40 +02:00
2019-08-18 10:17:09 +02:00
getParentEffectiveAutoTypeSeq() {
2019-08-18 08:05:38 +02:00
return this.parentGroup
? this.parentGroup.getEffectiveAutoTypeSeq()
: DefaultAutoTypeSequence;
2019-09-18 23:37:57 +02:00
}
2016-04-23 21:59:28 +02:00
2019-08-18 10:17:09 +02:00
isEntryTemplatesGroup() {
2017-05-03 21:21:29 +02:00
return this.group.uuid.equals(this.file.db.meta.entryTemplatesGroup);
2019-09-18 23:37:57 +02:00
}
2017-05-03 21:21:29 +02:00
2019-08-18 10:17:09 +02:00
moveToTrash() {
2015-10-31 20:09:32 +01:00
this.file.setModified();
2015-11-04 09:06:49 +01:00
this.file.db.remove(this.group);
if (this.group.uuid.equals(this.file.db.meta.entryTemplatesGroup)) {
this.file.db.meta.entryTemplatesGroup = undefined;
}
2015-12-05 14:04:09 +01:00
this.file.reload();
2019-09-18 23:37:57 +02:00
}
2015-10-31 20:09:32 +01:00
2019-08-18 10:17:09 +02:00
deleteFromTrash() {
2015-11-09 19:15:39 +01:00
this.file.db.move(this.group, null);
2015-12-05 14:04:09 +01:00
this.file.reload();
2019-09-18 23:37:57 +02:00
}
2015-11-09 19:15:39 +01:00
2019-08-18 10:17:09 +02:00
removeWithoutHistory() {
2017-01-31 07:50:28 +01:00
const ix = this.parentGroup.group.groups.indexOf(this.group);
2015-10-31 20:09:32 +01:00
if (ix >= 0) {
this.parentGroup.group.groups.splice(ix, 1);
}
2015-12-05 14:04:09 +01:00
this.file.reload();
2019-09-18 23:37:57 +02:00
}
2015-11-08 09:59:46 +01:00
2019-08-18 10:17:09 +02:00
moveHere(object) {
2019-09-22 09:56:48 +02:00
if (!object || object.id === this.id) {
2015-11-08 09:59:46 +01:00
return;
}
2019-09-22 09:56:48 +02:00
if (object.file === this.file) {
this.file.setModified();
if (object instanceof GroupModel) {
for (let parent = this; parent; parent = parent.parentGroup) {
if (object === parent) {
return;
}
}
if (this.group.groups.indexOf(object.group) >= 0) {
return;
}
2019-09-22 09:56:48 +02:00
this.file.db.move(object.group, this.group);
this.file.reload();
} else if (object instanceof EntryModel) {
if (this.group.entries.indexOf(object.entry) >= 0) {
return;
}
this.file.db.move(object.entry, this.group);
this.file.reload();
}
2019-09-22 09:56:48 +02:00
} else {
if (object instanceof EntryModel) {
this.file.setModified();
const detachedEntry = object.detach();
this.file.db.importEntry(detachedEntry, this.group, object.file.db);
this.file.reload();
} else {
// moving groups between files is not supported for now
2015-11-08 09:59:46 +01:00
}
}
2019-09-18 23:37:57 +02:00
}
2016-07-30 20:41:15 +02:00
2019-08-18 10:17:09 +02:00
moveToTop(object) {
2019-08-18 08:05:38 +02:00
if (
!object ||
object.id === this.id ||
object.file !== this.file ||
!(object instanceof GroupModel)
) {
2016-07-30 20:41:15 +02:00
return;
}
this.file.setModified();
2017-01-31 07:50:28 +01:00
for (let parent = this; parent; parent = parent.parentGroup) {
2016-07-30 20:41:15 +02:00
if (object === parent) {
return;
}
}
let atIndex = this.parentGroup.group.groups.indexOf(this.group);
const selfIndex = this.parentGroup.group.groups.indexOf(object.group);
2018-08-23 22:14:44 +02:00
if (selfIndex >= 0 && selfIndex < atIndex) {
atIndex--;
}
2016-07-30 20:41:15 +02:00
if (atIndex >= 0) {
this.file.db.move(object.group, this.parentGroup.group, atIndex);
}
this.file.reload();
2015-10-17 23:49:24 +02:00
}
2019-09-18 23:37:57 +02:00
static fromGroup(group, file, parentGroup) {
const model = new GroupModel();
model.setGroup(group, file, parentGroup);
return model;
}
static newGroup(group, file) {
const model = new GroupModel();
const grp = file.db.createGroup(group.group);
model.setGroup(grp, file, group);
model.group.times.update();
model.isJustCreated = true;
group.addGroup(model);
file.setModified();
file.reload();
return model;
}
}
GroupModel.defineModelProperties({
2019-09-19 17:42:53 +02:00
id: '',
uuid: '',
2019-09-18 23:37:57 +02:00
iconId: 0,
entries: null,
filterKey: 'group',
editable: true,
top: false,
drag: true,
drop: true,
enableSearching: true,
enableAutoType: null,
2019-09-19 17:42:53 +02:00
autoTypeSeq: null,
group: null,
file: null,
parentGroup: null,
2019-09-20 23:25:43 +02:00
customIconId: null,
isJustCreated: false
2019-09-18 23:37:57 +02:00
});
2015-10-17 23:49:24 +02:00
2019-09-15 14:16:32 +02:00
export { GroupModel };