mirror of https://github.com/keeweb/keeweb.git
add/edit groups
This commit is contained in:
parent
b1620be716
commit
4f4c984620
6
TODO.md
6
TODO.md
|
@ -1,8 +1,4 @@
|
|||
# MVP
|
||||
|
||||
- [ ] add/edit groups
|
||||
|
||||
# FUTURE
|
||||
# TODO
|
||||
|
||||
- [ ] trash: groups/empty/untrash
|
||||
- [ ] move groups/entries
|
||||
|
|
|
@ -22,6 +22,10 @@ _.extend(Backbone.View.prototype, {
|
|||
return this;
|
||||
},
|
||||
|
||||
isHidden: function() {
|
||||
return this._hidden;
|
||||
},
|
||||
|
||||
afterPaint: function(callback) {
|
||||
this.requestAnimationFrame(function() {
|
||||
this.requestAnimationFrame(callback);
|
||||
|
|
|
@ -4,6 +4,7 @@ var Backbone = require('backbone'),
|
|||
AppSettingsModel = require('./app-settings-model'),
|
||||
MenuModel = require('./menu/menu-model'),
|
||||
EntryModel = require('./entry-model'),
|
||||
GroupModel = require('./group-model'),
|
||||
FileCollection = require('../collections/file-collection'),
|
||||
EntryCollection = require('../collections/entry-collection');
|
||||
|
||||
|
@ -139,7 +140,7 @@ var AppModel = Backbone.Model.extend({
|
|||
return filter;
|
||||
},
|
||||
|
||||
createNewEntry: function() {
|
||||
getFirstSelectedGroup: function() {
|
||||
var selGroupId = this.filter.group;
|
||||
var file, group;
|
||||
if (selGroupId) {
|
||||
|
@ -155,7 +156,17 @@ var AppModel = Backbone.Model.extend({
|
|||
file = this.files.first();
|
||||
group = file.get('groups').first();
|
||||
}
|
||||
return EntryModel.newEntry(group, file);
|
||||
return { group: group, file: file };
|
||||
},
|
||||
|
||||
createNewEntry: function() {
|
||||
var sel = this.getFirstSelectedGroup();
|
||||
return EntryModel.newEntry(sel.group, sel.file);
|
||||
},
|
||||
|
||||
createNewGroup: function() {
|
||||
var sel = this.getFirstSelectedGroup();
|
||||
return GroupModel.newGroup(sel.group, sel.file);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -245,6 +245,7 @@ var FileModel = Backbone.Model.extend({
|
|||
this.db.meta.name = name;
|
||||
this.db.meta.nameChanged = new Date();
|
||||
this.set('name', name);
|
||||
this.get('groups').first().setName(name);
|
||||
this.setModified();
|
||||
},
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@ var GroupModel = MenuItemModel.extend({
|
|||
defaults: _.extend({}, MenuItemModel.prototype.defaults, {
|
||||
iconId: 0,
|
||||
entries: null,
|
||||
filterKey: 'group'
|
||||
filterKey: 'group',
|
||||
editable: true,
|
||||
top: false
|
||||
}),
|
||||
|
||||
initialize: function() {
|
||||
|
@ -23,9 +25,6 @@ var GroupModel = MenuItemModel.extend({
|
|||
var isRecycleBin = file.db.meta.recycleBinUuid && file.db.meta.recycleBinUuid.id === group.uuid.id;
|
||||
this.set({
|
||||
id: group.uuid.id,
|
||||
title: group.name,
|
||||
iconId: group.icon,
|
||||
icon: this._iconFromId(group.icon),
|
||||
expanded: true,
|
||||
visible: !isRecycleBin,
|
||||
items: new GroupCollection(),
|
||||
|
@ -33,16 +32,25 @@ var GroupModel = MenuItemModel.extend({
|
|||
}, { silent: true });
|
||||
this.group = group;
|
||||
this.file = file;
|
||||
this._fillByGroup(true);
|
||||
var items = this.get('items'),
|
||||
entries = this.get('entries');
|
||||
group.groups.forEach(function(subGroup) {
|
||||
items.add(GroupModel.fromGroup(subGroup, file));
|
||||
});
|
||||
items.add(GroupModel.fromGroup(subGroup, file, this));
|
||||
}, this);
|
||||
group.entries.forEach(function(entry) {
|
||||
entries.add(EntryModel.fromEntry(entry, this, file));
|
||||
}, this);
|
||||
},
|
||||
|
||||
_fillByGroup: function(silent) {
|
||||
this.set({
|
||||
title: this.group.name,
|
||||
iconId: this.group.icon,
|
||||
icon: this._iconFromId(this.group.icon)
|
||||
}, { silent: silent });
|
||||
},
|
||||
|
||||
_iconFromId: function(id) {
|
||||
if (id === KdbxIcons.Folder || id === KdbxIcons.FolderOpen) {
|
||||
return undefined;
|
||||
|
@ -50,6 +58,14 @@ var GroupModel = MenuItemModel.extend({
|
|||
return IconMap[id];
|
||||
},
|
||||
|
||||
_groupModified: function() {
|
||||
this.file.setModified();
|
||||
if (this.isJustCreated) {
|
||||
this.isJustCreated = false;
|
||||
}
|
||||
this.group.times.update();
|
||||
},
|
||||
|
||||
forEachGroup: function(callback, includeDisabled) {
|
||||
var result = true;
|
||||
this.get('items').forEach(function(group) {
|
||||
|
@ -74,12 +90,72 @@ var GroupModel = MenuItemModel.extend({
|
|||
|
||||
addEntry: function(entry) {
|
||||
this.get('entries').add(entry);
|
||||
},
|
||||
|
||||
removeGroup: function(group) {
|
||||
this.get('items').remove(group);
|
||||
},
|
||||
|
||||
addGroup: function(group) {
|
||||
this.get('items').add(group);
|
||||
this.trigger('insert', group);
|
||||
},
|
||||
|
||||
setName: function(name) {
|
||||
this._groupModified();
|
||||
this.group.name = name;
|
||||
this._fillByGroup();
|
||||
},
|
||||
|
||||
setIcon: function(iconId) {
|
||||
this._groupModified();
|
||||
this.group.icon = iconId;
|
||||
this._fillByGroup();
|
||||
},
|
||||
|
||||
moveToTrash: function() {
|
||||
this.file.setModified();
|
||||
this.file.db.remove(this.group, this.parentGroup.group);
|
||||
this.parentGroup.removeGroup(this);
|
||||
var trashGroup = this.file.getTrashGroup();
|
||||
if (trashGroup) {
|
||||
//trashGroup.addGroup(this); // TODO: groups in trash are currently not displayed
|
||||
this.parentGroup = trashGroup;
|
||||
this.deleted = true;
|
||||
}
|
||||
this.trigger('delete');
|
||||
},
|
||||
|
||||
removeWithoutHistory: function() {
|
||||
var ix = this.parentGroup.group.groups.indexOf(this.group);
|
||||
if (ix >= 0) {
|
||||
this.parentGroup.group.groups.splice(ix, 1);
|
||||
}
|
||||
this.parentGroup.removeGroup(this);
|
||||
}
|
||||
});
|
||||
|
||||
GroupModel.fromGroup = function(group, file) {
|
||||
GroupModel.fromGroup = function(group, file, parentGroup) {
|
||||
var model = new GroupModel();
|
||||
model.setFromGroup(group, file);
|
||||
if (parentGroup) {
|
||||
model.parentGroup = parentGroup;
|
||||
} else {
|
||||
model.set({ top: true }, { silent: true });
|
||||
}
|
||||
return model;
|
||||
};
|
||||
|
||||
GroupModel.newGroup = function(group, file) {
|
||||
var model = new GroupModel();
|
||||
var grp = file.db.createGroup(group.group);
|
||||
model.setFromGroup(grp, file);
|
||||
model.group.times.update();
|
||||
model.parentGroup = group;
|
||||
model.unsaved = true;
|
||||
model.isJustCreated = true;
|
||||
group.addGroup(model);
|
||||
file.setModified();
|
||||
return model;
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ var Backbone = require('backbone'),
|
|||
FooterView = require('../views/footer-view'),
|
||||
ListView = require('../views/list-view'),
|
||||
DetailsView = require('../views/details/details-view'),
|
||||
GrpView = require('../views/grp-view'),
|
||||
OpenView = require('../views/open-view'),
|
||||
SettingsView = require('../views/settings/settings-view'),
|
||||
Alerts = require('../comp/alerts'),
|
||||
|
@ -37,6 +38,7 @@ var AppView = Backbone.View.extend({
|
|||
this.views.listDrag = new DragView('x');
|
||||
this.views.details = new DetailsView();
|
||||
this.views.details.appModel = this.model;
|
||||
this.views.grp = new GrpView();
|
||||
|
||||
this.views.menu.listenDrag(this.views.menuDrag);
|
||||
this.views.list.listenDrag(this.views.listDrag);
|
||||
|
@ -44,6 +46,7 @@ var AppView = Backbone.View.extend({
|
|||
this.listenTo(this.model.settings, 'change:theme', this.setTheme);
|
||||
this.listenTo(this.model.files, 'update reset', this.fileListUpdated);
|
||||
|
||||
this.listenTo(Backbone, 'select-all', this.selectAll);
|
||||
this.listenTo(Backbone, 'menu-select', this.menuSelect);
|
||||
this.listenTo(Backbone, 'lock-workspace', this.lockWorkspace);
|
||||
this.listenTo(Backbone, 'show-file', this.showFileSettings);
|
||||
|
@ -53,6 +56,7 @@ var AppView = Backbone.View.extend({
|
|||
this.listenTo(Backbone, 'toggle-settings', this.toggleSettings);
|
||||
this.listenTo(Backbone, 'toggle-menu', this.toggleMenu);
|
||||
this.listenTo(Backbone, 'toggle-details', this.toggleDetails);
|
||||
this.listenTo(Backbone, 'edit-group', this.editGroup);
|
||||
this.listenTo(Backbone, 'launcher-open-file', this.launcherOpenFile);
|
||||
|
||||
window.onbeforeunload = this.beforeUnload.bind(this);
|
||||
|
@ -71,6 +75,7 @@ var AppView = Backbone.View.extend({
|
|||
this.views.list.setElement(this.$el.find('.app__list')).render();
|
||||
this.views.listDrag.setElement(this.$el.find('.app__list-drag')).render();
|
||||
this.views.details.setElement(this.$el.find('.app__details')).render();
|
||||
this.views.grp.setElement(this.$el.find('.app__grp')).render().hide();
|
||||
return this;
|
||||
},
|
||||
|
||||
|
@ -80,6 +85,7 @@ var AppView = Backbone.View.extend({
|
|||
this.views.list.hide();
|
||||
this.views.listDrag.hide();
|
||||
this.views.details.hide();
|
||||
this.views.grp.hide();
|
||||
this.views.footer.toggle(this.model.files.hasOpenFiles());
|
||||
this.hideSettings();
|
||||
this.hideOpenFile();
|
||||
|
@ -103,6 +109,7 @@ var AppView = Backbone.View.extend({
|
|||
this.views.list.show();
|
||||
this.views.listDrag.show();
|
||||
this.views.details.show();
|
||||
this.views.grp.hide();
|
||||
this.views.footer.show();
|
||||
this.hideOpenFile();
|
||||
this.hideSettings();
|
||||
|
@ -130,6 +137,7 @@ var AppView = Backbone.View.extend({
|
|||
this.views.list.hide();
|
||||
this.views.listDrag.hide();
|
||||
this.views.details.hide();
|
||||
this.views.grp.hide();
|
||||
this.hideOpenFile();
|
||||
this.views.settings = new SettingsView();
|
||||
this.views.settings.setElement(this.$el.find('.app__body')).render();
|
||||
|
@ -140,6 +148,13 @@ var AppView = Backbone.View.extend({
|
|||
this.views.menu.switchVisibility(false);
|
||||
},
|
||||
|
||||
showEditGroup: function() {
|
||||
this.views.list.hide();
|
||||
this.views.listDrag.hide();
|
||||
this.views.details.hide();
|
||||
this.views.grp.show();
|
||||
},
|
||||
|
||||
fileListUpdated: function() {
|
||||
if (this.model.files.hasOpenFiles()) {
|
||||
this.showEntries();
|
||||
|
@ -193,8 +208,15 @@ var AppView = Backbone.View.extend({
|
|||
}
|
||||
},
|
||||
|
||||
menuSelect: function(item) {
|
||||
this.model.menu.select(item);
|
||||
selectAll: function() {
|
||||
this.menuSelect({ item: this.model.menu.allItemsSection.get('items').first() });
|
||||
},
|
||||
|
||||
menuSelect: function(opt) {
|
||||
this.model.menu.select(opt);
|
||||
if (!this.views.grp.isHidden()) {
|
||||
this.showEntries();
|
||||
}
|
||||
},
|
||||
|
||||
lockWorkspace: function() {
|
||||
|
@ -261,6 +283,15 @@ var AppView = Backbone.View.extend({
|
|||
this.views.menu.switchVisibility(false);
|
||||
},
|
||||
|
||||
editGroup: function(group) {
|
||||
if (group && this.views.grp.isHidden()) {
|
||||
this.showEditGroup();
|
||||
this.views.grp.showGroup(group);
|
||||
} else {
|
||||
this.showEntries();
|
||||
}
|
||||
},
|
||||
|
||||
contextmenu: function(e) {
|
||||
if (['input', 'textarea'].indexOf(e.target.tagName.toLowerCase()) < 0) {
|
||||
e.preventDefault();
|
||||
|
|
|
@ -9,7 +9,7 @@ var Backbone = require('backbone'),
|
|||
FieldViewReadOnly = require('../fields/field-view-read-only'),
|
||||
FieldViewHistory = require('../fields/field-view-history'),
|
||||
FieldViewCustom = require('../fields/field-view-custom'),
|
||||
DetailsIconView = require('./details-icon-view'),
|
||||
IconSelectView = require('../icon-select-view'),
|
||||
DetailsHistoryView = require('./details-history-view'),
|
||||
DetailsAttachmentView = require('./details-attachment-view'),
|
||||
Keys = require('../../const/keys'),
|
||||
|
@ -175,12 +175,12 @@ var DetailsView = Backbone.View.extend({
|
|||
},
|
||||
|
||||
toggleIcons: function() {
|
||||
if (this.views.sub && this.views.sub instanceof DetailsIconView) {
|
||||
if (this.views.sub && this.views.sub instanceof IconSelectView) {
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
this.removeSubView();
|
||||
var subView = new DetailsIconView({ el: this.scroller, model: this.model });
|
||||
var subView = new IconSelectView({ el: this.scroller, model: this.model });
|
||||
this.listenTo(subView, 'select', this.iconSelected);
|
||||
subView.render();
|
||||
this.pageResized();
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
'use strict';
|
||||
|
||||
var Backbone = require('backbone'),
|
||||
Scrollable = require('../mixins/scrollable'),
|
||||
IconSelectView = require('./icon-select-view'),
|
||||
baron = require('baron');
|
||||
|
||||
var GrpView = Backbone.View.extend({
|
||||
template: require('templates/grp.html'),
|
||||
|
||||
events: {
|
||||
'click .grp__icon': 'showIconsSelect',
|
||||
'click .grp__buttons-trash': 'moveToTrash',
|
||||
'blur #grp__field-title': 'titleBlur'
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
this.views = {};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.removeSubView();
|
||||
if (this.model) {
|
||||
this.$el.html(this.template({
|
||||
title: this.model.get('title'),
|
||||
icon: this.model.get('icon') || 'folder',
|
||||
readonly: this.model.get('top')
|
||||
}));
|
||||
}
|
||||
this.scroll = baron({
|
||||
root: this.$el.find('.details__body')[0],
|
||||
scroller: this.$el.find('.scroller')[0],
|
||||
bar: this.$el.find('.scroller__bar')[0],
|
||||
$: Backbone.$
|
||||
});
|
||||
this.scroller = this.$el.find('.scroller');
|
||||
this.scrollerBar = this.$el.find('.scroller__bar');
|
||||
this.scrollerBarWrapper = this.$el.find('.scroller__bar-wrapper');
|
||||
this.pageResized();
|
||||
return this;
|
||||
},
|
||||
|
||||
removeSubView: function() {
|
||||
if (this.views.sub) {
|
||||
this.views.sub.remove();
|
||||
delete this.views.sub;
|
||||
}
|
||||
},
|
||||
|
||||
showGroup: function(group) {
|
||||
this.model = group;
|
||||
this.render();
|
||||
},
|
||||
|
||||
titleBlur: function(e) {
|
||||
var title = $.trim(e.target.value);
|
||||
if (title) {
|
||||
if (!this.model.get('top') && e.target.value !== this.model.get('title')) {
|
||||
this.model.setName(e.target.value);
|
||||
}
|
||||
} else {
|
||||
if (this.model.isJustCreated) {
|
||||
this.model.removeWithoutHistory();
|
||||
Backbone.trigger('edit-group');
|
||||
} else {
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
showIconsSelect: function() {
|
||||
if (this.views.sub) {
|
||||
this.removeSubView();
|
||||
} else {
|
||||
var subView = new IconSelectView({el: this.$el.find('.grp__icons'), model: {iconId: this.model.get('iconId')}});
|
||||
this.listenTo(subView, 'select', this.iconSelected);
|
||||
subView.render();
|
||||
this.views.sub = subView;
|
||||
}
|
||||
this.pageResized();
|
||||
},
|
||||
|
||||
iconSelected: function(iconId) {
|
||||
if (iconId !== this.model.get('iconId')) {
|
||||
this.model.setIcon(iconId);
|
||||
}
|
||||
this.render();
|
||||
},
|
||||
|
||||
moveToTrash: function() {
|
||||
this.model.moveToTrash();
|
||||
Backbone.trigger('select-all');
|
||||
}
|
||||
});
|
||||
|
||||
_.extend(GrpView.prototype, Scrollable);
|
||||
|
||||
module.exports = GrpView;
|
|
@ -1,13 +1,13 @@
|
|||
'use strict';
|
||||
|
||||
var Backbone = require('backbone'),
|
||||
IconMap = require('../../const/icon-map');
|
||||
IconMap = require('../const/icon-map');
|
||||
|
||||
var DetailsIconView = Backbone.View.extend({
|
||||
template: require('templates/details/details-icon.html'),
|
||||
var IconSelectView = Backbone.View.extend({
|
||||
template: require('templates/icon-select.html'),
|
||||
|
||||
events: {
|
||||
'click .details__icons-icon': 'iconClick'
|
||||
'click .icon-select__icon': 'iconClick'
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@ -26,4 +26,4 @@ var DetailsIconView = Backbone.View.extend({
|
|||
}
|
||||
});
|
||||
|
||||
module.exports = DetailsIconView;
|
||||
module.exports = IconSelectView;
|
|
@ -31,6 +31,7 @@ var ListView = Backbone.View.extend({
|
|||
this.listenTo(this.views.search, 'select-prev', this.selectPrev);
|
||||
this.listenTo(this.views.search, 'select-next', this.selectNext);
|
||||
this.listenTo(this.views.search, 'create-entry', this.createEntry);
|
||||
this.listenTo(this.views.search, 'create-group', this.createGroup);
|
||||
this.listenTo(this, 'show', this.viewShown);
|
||||
this.listenTo(this, 'hide', this.viewHidden);
|
||||
this.listenTo(Backbone, 'filter', this.filterChanged);
|
||||
|
@ -105,6 +106,11 @@ var ListView = Backbone.View.extend({
|
|||
this.selectItem(newEntry);
|
||||
},
|
||||
|
||||
createGroup: function() {
|
||||
var newGroup = this.model.createNewGroup();
|
||||
Backbone.trigger('edit-group', newGroup);
|
||||
},
|
||||
|
||||
selectItem: function(item) {
|
||||
this.items.setActive(item);
|
||||
Backbone.trigger('select-entry', item);
|
||||
|
|
|
@ -13,7 +13,8 @@ var MenuItemView = Backbone.View.extend({
|
|||
'mouseout': 'mouseout',
|
||||
'click .menu__item-option': 'selectOption',
|
||||
'click': 'selectItem',
|
||||
'dblclick': 'expandItem'
|
||||
'dblclick': 'expandItem',
|
||||
'click .menu__item-edit': 'editItem'
|
||||
},
|
||||
|
||||
iconEl: null,
|
||||
|
@ -22,9 +23,12 @@ var MenuItemView = Backbone.View.extend({
|
|||
initialize: function () {
|
||||
this.itemViews = [];
|
||||
this.listenTo(this.model, 'change:title', this.changeTitle);
|
||||
this.listenTo(this.model, 'change:icon', this.changeIcon);
|
||||
this.listenTo(this.model, 'change:active', this.changeActive);
|
||||
this.listenTo(this.model, 'change:expanded', this.changeExpanded);
|
||||
this.listenTo(this.model, 'change:cls', this.changeCls);
|
||||
this.listenTo(this.model, 'delete', this.remove);
|
||||
this.listenTo(this.model, 'insert', this.insertItem);
|
||||
var shortcut = this.model.get('shortcut');
|
||||
if (shortcut) {
|
||||
KeyHandler.onKey(shortcut, this.selectItem, this, KeyHandler.SHORTCUT_OPT);
|
||||
|
@ -42,15 +46,16 @@ var MenuItemView = Backbone.View.extend({
|
|||
if (items && this.model.get('expanded')) {
|
||||
items.forEach(function (item) {
|
||||
if (item.get('visible')) {
|
||||
var itemView = new MenuItemView({el: this.$el, model: item});
|
||||
itemView.listenTo(itemView, 'select', this.itemSelected);
|
||||
itemView.render();
|
||||
this.itemViews.push(itemView);
|
||||
this.insertItem(item);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
insertItem: function(item) {
|
||||
this.itemViews.push(new MenuItemView({el: this.$el, model: item}).render());
|
||||
},
|
||||
|
||||
remove : function() {
|
||||
this.removeInnerViews();
|
||||
var shortcut = this.model.get('shortcut');
|
||||
|
@ -69,7 +74,11 @@ var MenuItemView = Backbone.View.extend({
|
|||
},
|
||||
|
||||
changeTitle: function(model, title) {
|
||||
this.$el.find('.menu__item-title').text(title);
|
||||
this.$el.find('.menu__item-title').first().text(title);
|
||||
},
|
||||
|
||||
changeIcon: function(model, icon) {
|
||||
this.iconEl[0].className = 'menu__item-icon fa ' + (icon ? 'fa-' + icon : 'menu__item-icon--no-icon');
|
||||
},
|
||||
|
||||
changeActive: function(model, active) {
|
||||
|
@ -129,6 +138,13 @@ var MenuItemView = Backbone.View.extend({
|
|||
this.model.toggleExpanded();
|
||||
}
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
editItem: function(e) {
|
||||
if (this.model.get('active') && this.model.get('editable')) {
|
||||
e.stopPropagation();
|
||||
Backbone.trigger('edit-group', this.model);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -66,6 +66,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__grp {
|
||||
@include flex(1);
|
||||
@include display(flex);
|
||||
overflow: hidden;
|
||||
padding: $base-spacing;
|
||||
position: relative;
|
||||
@include mobile {
|
||||
padding: $base-padding;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
@include flex(0 0 auto);
|
||||
@include th { border-top: light-border(); }
|
||||
|
|
|
@ -365,25 +365,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__icons {
|
||||
@include display(flex);
|
||||
@include align-items(flex-start);
|
||||
@include flex-direction(row);
|
||||
@include justify-content(flex-start);
|
||||
@include flex-wrap(wrap);
|
||||
@include user-select(none);
|
||||
&-icon {
|
||||
@include area-selectable(bottom);
|
||||
width: 26px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
padding: 10px;
|
||||
&.details__icons-icon--active {
|
||||
@include area-selected(bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__history {
|
||||
@include flex(1 0 auto);
|
||||
@include display(flex);
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
.grp {
|
||||
@include flex(1);
|
||||
@include display(flex);
|
||||
@include align-items(stretch);
|
||||
@include flex-direction(column);
|
||||
@include justify-content(flex-start);
|
||||
@include scrollbar-on-hover;
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
|
||||
>.scroller {
|
||||
@include flex(1);
|
||||
@include display(flex);
|
||||
@include align-items(stretch);
|
||||
@include flex-direction(column);
|
||||
@include justify-content(flex-start);
|
||||
overflow-x: hidden;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
display: block;
|
||||
font-size: $large-header-font-size;
|
||||
padding: $base-padding-px;
|
||||
@include align-self(flex-start);
|
||||
@include area-selectable();
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
@include display(flex);
|
||||
@include flex-direction(row);
|
||||
margin-top: $base-padding-v;
|
||||
|
||||
&-trash {
|
||||
@include icon-btn($error:true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@
|
|||
&__item {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
@include display(flex);
|
||||
@include align-items(stretch);
|
||||
@include flex-direction(column);
|
||||
|
@ -121,6 +122,26 @@
|
|||
}
|
||||
}
|
||||
|
||||
&-edit {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: .8em;
|
||||
top: .6em;
|
||||
cursor: pointer;
|
||||
transition: opacity $base-duration $base-timing, color $base-duration $base-timing;
|
||||
@include th {
|
||||
color: muted-color();
|
||||
&:hover { color: medium-color(); }
|
||||
}
|
||||
.menu__item--active>.menu__item-body>& {
|
||||
display: block;
|
||||
}
|
||||
.menu__item--active>.menu__item-body:hover>& {
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
|
||||
.fa {
|
||||
margin-right: $base-padding-h / 2;
|
||||
}
|
||||
|
|
|
@ -53,13 +53,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__select, &__input, &__pre, &__file-master-pass-label {
|
||||
width: 60%;
|
||||
@include tablet {
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
}
|
||||
|
||||
&__select, &__input {
|
||||
height: 2em;
|
||||
}
|
||||
|
|
|
@ -243,3 +243,12 @@ $thumb-size: 14px;
|
|||
@include th { background: text-color(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.input-base {
|
||||
width: 60%;
|
||||
@include tablet {
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
&.icon-select {
|
||||
@include display(flex);
|
||||
@include align-items(flex-start);
|
||||
@include flex-direction(row);
|
||||
@include justify-content(flex-start);
|
||||
@include flex-wrap(wrap);
|
||||
@include user-select(none);
|
||||
&__icon {
|
||||
@include area-selectable(bottom);
|
||||
width: 26px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
padding: 10px;
|
||||
&.icon-select__icon--active {
|
||||
@include area-selected(bottom);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,12 +16,14 @@
|
|||
@import "common/empty";
|
||||
@import "common/fx";
|
||||
@import "common/help-tip";
|
||||
@import "common/icon-select";
|
||||
@import "common/modal";
|
||||
@import "common/scroll";
|
||||
|
||||
@import "areas/app";
|
||||
@import "areas/details";
|
||||
@import "areas/footer";
|
||||
@import "areas/grp";
|
||||
@import "areas/generator";
|
||||
@import "areas/list";
|
||||
@import "areas/menu";
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<div class="app__list"></div>
|
||||
<div class="app__list-drag"></div>
|
||||
<div class="app__details"></div>
|
||||
<div class="app__grp"></div>
|
||||
</div>
|
||||
<div class="app__footer"></div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<div class="details__icons">
|
||||
<% icons.forEach(function(icon, ix) { %>
|
||||
<i class="fa fa-<%= icon %> details__icons-icon <%= ix === sel ? 'details__icons-icon--active' : '' %>" data-val="<%= ix %>"></i>
|
||||
<% }); %>
|
||||
</div>
|
|
@ -0,0 +1,19 @@
|
|||
<div class="grp">
|
||||
<div class="scroller">
|
||||
<h1>Group</h1>
|
||||
<div class="grp__field">
|
||||
<label for="grp__field-title">Name:</label>
|
||||
<input type="text" class="input-base" id="grp__field-title" value="<%- title %>" size="50" maxlength="1024"
|
||||
required <%= readonly ? 'readonly' : '' %> />
|
||||
</div>
|
||||
<label>Icon:</label>
|
||||
<i class="fa fa-<%- icon %> grp__icon"></i>
|
||||
<div class="grp__icons"></div>
|
||||
</div>
|
||||
<div class="scroller__bar-wrapper"><div class="scroller__bar"></div></div>
|
||||
<% if (!readonly) { %>
|
||||
<div class="grp__buttons">
|
||||
<i class="grp__buttons-trash fa fa-trash-o"></i>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
|
@ -0,0 +1,5 @@
|
|||
<div class="icon-select">
|
||||
<% icons.forEach(function(icon, ix) { %>
|
||||
<i class="fa fa-<%= icon %> icon-select__icon <%= ix === sel ? 'icon-select__icon--active' : '' %>" data-val="<%= ix %>"></i>
|
||||
<% }); %>
|
||||
</div>
|
|
@ -14,5 +14,8 @@
|
|||
<% }); %>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<% if (typeof editable !== 'undefined') { %>
|
||||
<i class="menu__item-edit fa fa-cog"></i>
|
||||
<% } %>
|
||||
</i>
|
||||
</div>
|
||||
|
|
|
@ -24,34 +24,34 @@
|
|||
</div>
|
||||
|
||||
<h2>Settings</h2>
|
||||
<label for="settings__file-master-pass" class="settings__file-master-pass-label">Master password:
|
||||
<label for="settings__file-master-pass" class="settings__file-master-pass-label input-base">Master password:
|
||||
<span class="settings__file-master-pass-warning">
|
||||
<i class="fa fa-warning"></i> password was changed; leave the field blank to use old password
|
||||
</span>
|
||||
</label>
|
||||
<input type="password" class="settings__input" id="settings__file-master-pass" value="<%= password %>" />
|
||||
<input type="password" class="settings__input input-base" id="settings__file-master-pass" value="<%= password %>" />
|
||||
<label for="settings__file-key-file">Key file:</label>
|
||||
<select class="settings__select settings__select-no-margin" id="settings__file-key-file"></select>
|
||||
<select class="settings__select settings__select-no-margin input-base" id="settings__file-key-file"></select>
|
||||
<a id="settings__file-file-select-link">Select a key file</a>
|
||||
<input type="file" accept=".key" id="settings__file-file-select" class="hide" />
|
||||
|
||||
<h2>Names</h2>
|
||||
<label for="settings__file-name">Name:</label>
|
||||
<input type="text" class="settings__input" id="settings__file-name" value="<%- name %>" required />
|
||||
<input type="text" class="settings__input input-base" id="settings__file-name" value="<%- name %>" required />
|
||||
<label for="settings__file-def-user">Default username:</label>
|
||||
<input type="text" class="settings__input" id="settings__file-def-user" value="<%- defaultUser %>" />
|
||||
<input type="text" class="settings__input input-base" id="settings__file-def-user" value="<%- defaultUser %>" />
|
||||
|
||||
<h2>History</h2>
|
||||
<div>
|
||||
<input type="checkbox" class="settings__input" id="settings__file-trash" <%- recycleBinEnabled ? 'checked' : '' %> />
|
||||
<input type="checkbox" class="settings__input input-base" id="settings__file-trash" <%- recycleBinEnabled ? 'checked' : '' %> />
|
||||
<label for="settings__file-trash">Enable trash</label>
|
||||
</div>
|
||||
<label for="settings__file-hist-len">History length, keep last records per entry:</label>
|
||||
<input type="text" pattern="\d+" required class="settings__input" id="settings__file-hist-len" value="<%= historyMaxItems %>" />
|
||||
<input type="text" pattern="\d+" required class="settings__input input-base" id="settings__file-hist-len" value="<%= historyMaxItems %>" />
|
||||
<label for="settings__file-hist-size">History size, total MB per file:</label>
|
||||
<input type="text" pattern="\d+" required class="settings__input" id="settings__file-hist-size" value="<%= historyMaxSize %>" />
|
||||
<input type="text" pattern="\d+" required class="settings__input input-base" id="settings__file-hist-size" value="<%= historyMaxSize %>" />
|
||||
|
||||
<h2>Advanced</h2>
|
||||
<label for="settings__file-key-rounds">Key encryption rounds:</label>
|
||||
<input type="text" pattern="\d+" required class="settings__input" id="settings__file-key-rounds" value="<%= keyEncryptionRounds %>" />
|
||||
<input type="text" pattern="\d+" required class="settings__input input-base" id="settings__file-key-rounds" value="<%= keyEncryptionRounds %>" />
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<h2>Appearance</h2>
|
||||
<div>
|
||||
<label for="settings__general-theme">Theme:</label>
|
||||
<select class="settings__general-theme settings__select" id="settings__general-theme">
|
||||
<select class="settings__general-theme settings__select input-base" id="settings__general-theme">
|
||||
<% _.forEach(themes, function(name, key) { %>
|
||||
<option value="<%= key %>" <%= key === activeTheme ? 'selected' : '' %>><%- name %></option>
|
||||
<% }); %>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
or <a href="http://antelle.net/" target="_blank">contact a developer</a> directly.
|
||||
</p>
|
||||
<p>App information:</p>
|
||||
<pre class="settings__pre"><%= appInfo %></pre>
|
||||
<pre class="settings__pre input-base"><%= appInfo %></pre>
|
||||
<h2>Other platforms</h2>
|
||||
<ul>
|
||||
<li>
|
||||
|
|
Loading…
Reference in New Issue