mirror of https://github.com/keeweb/keeweb.git
fix #112: entry templates
This commit is contained in:
parent
5f2eea2c29
commit
0bb7602bf8
|
@ -17,6 +17,8 @@
|
|||
"group": "group",
|
||||
"noTitle": "no title",
|
||||
"or": "or",
|
||||
"history": "history",
|
||||
"template": "template",
|
||||
"notImplemented": "Not Implemented",
|
||||
"saveChanges": "Save changes",
|
||||
"discardChanges": "Discard changes",
|
||||
|
@ -25,7 +27,6 @@
|
|||
"help": "Help",
|
||||
"settings": "Settings",
|
||||
"plugins": "Plugins",
|
||||
"history": "history",
|
||||
|
||||
"cache": "cache",
|
||||
"file": "file",
|
||||
|
|
|
@ -313,9 +313,30 @@ const AppModel = Backbone.Model.extend({
|
|||
return matches.map(m => m[0]);
|
||||
},
|
||||
|
||||
createNewEntry: function() {
|
||||
getEntryTemplates: function() {
|
||||
const entryTemplates = [];
|
||||
this.files.forEach(file => {
|
||||
file.forEachEntryTemplate(entry => {
|
||||
entryTemplates.push({ file, entry });
|
||||
});
|
||||
});
|
||||
return entryTemplates;
|
||||
},
|
||||
|
||||
createNewEntry: function(args) {
|
||||
const sel = this.getFirstSelectedGroup();
|
||||
return EntryModel.newEntry(sel.group, sel.file);
|
||||
if (args && args.template) {
|
||||
if (sel.file !== args.template.file) {
|
||||
sel.file = args.template.file;
|
||||
sel.group = args.template.file.get('groups').first();
|
||||
}
|
||||
const templateEntry = args.template.entry;
|
||||
const newEntry = EntryModel.newEntry(sel.group, sel.file);
|
||||
newEntry.copyFromTemplate(templateEntry);
|
||||
return newEntry;
|
||||
} else {
|
||||
return EntryModel.newEntry(sel.group, sel.file);
|
||||
}
|
||||
},
|
||||
|
||||
createNewGroup: function() {
|
||||
|
@ -724,27 +745,6 @@ const AppModel = Backbone.Model.extend({
|
|||
});
|
||||
});
|
||||
};
|
||||
const saveToCacheAndStorage = () => {
|
||||
logger.info('Getting file data for saving');
|
||||
file.getData((data, err) => {
|
||||
if (err) { return complete(err); }
|
||||
if (storage === 'file') {
|
||||
logger.info('Saving to file storage');
|
||||
saveToStorage(data);
|
||||
} else if (!file.get('dirty')) {
|
||||
logger.info('Saving to storage, skip cache because not dirty');
|
||||
saveToStorage(data);
|
||||
} else {
|
||||
logger.info('Saving to cache');
|
||||
Storage.cache.save(fileInfo.id, null, data, (err) => {
|
||||
if (err) { return complete(err); }
|
||||
file.set('dirty', false);
|
||||
logger.info('Saved to cache, saving to storage');
|
||||
saveToStorage(data);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
const saveToStorage = (data) => {
|
||||
logger.info('Save data to storage');
|
||||
Storage[storage].save(path, opts, data, (err, stat) => {
|
||||
|
@ -772,6 +772,27 @@ const AppModel = Backbone.Model.extend({
|
|||
}
|
||||
}, fileInfo.get('rev'));
|
||||
};
|
||||
const saveToCacheAndStorage = () => {
|
||||
logger.info('Getting file data for saving');
|
||||
file.getData((data, err) => {
|
||||
if (err) { return complete(err); }
|
||||
if (storage === 'file') {
|
||||
logger.info('Saving to file storage');
|
||||
saveToStorage(data);
|
||||
} else if (!file.get('dirty')) {
|
||||
logger.info('Saving to storage, skip cache because not dirty');
|
||||
saveToStorage(data);
|
||||
} else {
|
||||
logger.info('Saving to cache');
|
||||
Storage.cache.save(fileInfo.id, null, data, (err) => {
|
||||
if (err) { return complete(err); }
|
||||
file.set('dirty', false);
|
||||
logger.info('Saved to cache, saving to storage');
|
||||
saveToStorage(data);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
logger.info('Stat file');
|
||||
Storage[storage].stat(path, opts, (err, stat) => {
|
||||
if (err) {
|
||||
|
|
|
@ -622,6 +622,12 @@ const EntryModel = Backbone.Model.extend({
|
|||
newEntry._fillByEntry();
|
||||
this.file.reload();
|
||||
return newEntry;
|
||||
},
|
||||
|
||||
copyFromTemplate: function(templateEntry) {
|
||||
this.entry.copyFrom(templateEntry.entry);
|
||||
this.entry.fields.Title = '';
|
||||
this._fillByEntry();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -377,6 +377,17 @@ const FileModel = Backbone.Model.extend({
|
|||
return hash ? kdbxweb.ByteUtils.bytesToBase64(hash.getBinary()) : null;
|
||||
},
|
||||
|
||||
forEachEntryTemplate: function(callback) {
|
||||
if (!this.db.meta.entryTemplatesGroup) {
|
||||
return;
|
||||
}
|
||||
const group = this.getGroup(this.subId(this.db.meta.entryTemplatesGroup.id));
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
group.forEachOwnEntry({}, callback);
|
||||
},
|
||||
|
||||
setSyncProgress: function() {
|
||||
this.set({ syncing: true });
|
||||
},
|
||||
|
|
|
@ -29,7 +29,7 @@ const GroupModel = MenuItemModel.extend({
|
|||
},
|
||||
|
||||
setGroup: function(group, file, parentGroup) {
|
||||
const isRecycleBin = file.db.meta.recycleBinUuid && file.db.meta.recycleBinUuid.id === group.uuid.id;
|
||||
const isRecycleBin = group.uuid.equals(file.db.meta.recycleBinUuid);
|
||||
const id = file.subId(group.uuid.id);
|
||||
this.set({
|
||||
id: id,
|
||||
|
@ -125,7 +125,10 @@ const GroupModel = MenuItemModel.extend({
|
|||
},
|
||||
|
||||
matches: function(filter) {
|
||||
return (filter && filter.includeDisabled || this.group.enableSearching !== false) &&
|
||||
return (filter && filter.includeDisabled ||
|
||||
this.group.enableSearching !== false &&
|
||||
!this.group.uuid.equals(this.file.db.meta.entryTemplatesGroup)
|
||||
) &&
|
||||
(!filter || !filter.autoType || this.group.enableAutoType !== false);
|
||||
},
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ const DropdownView = require('./dropdown-view');
|
|||
const FeatureDetector = require('../util/feature-detector');
|
||||
const Format = require('../util/format');
|
||||
const Locale = require('../util/locale');
|
||||
const Comparators = require('../util/comparators');
|
||||
|
||||
const ListSearchView = Backbone.View.extend({
|
||||
template: require('templates/list-search.hbs'),
|
||||
|
@ -278,6 +279,7 @@ const ListSearchView = Backbone.View.extend({
|
|||
this.hideSearchOptions();
|
||||
return;
|
||||
}
|
||||
|
||||
this.hideSearchOptions();
|
||||
this.$el.find('.list__search-btn-new').addClass('sel--active');
|
||||
const view = new DropdownView();
|
||||
|
@ -288,11 +290,30 @@ const ListSearchView = Backbone.View.extend({
|
|||
top: this.$el.find('.list__search-btn-new')[0].getBoundingClientRect().bottom,
|
||||
right: this.$el[0].getBoundingClientRect().right + 1
|
||||
},
|
||||
options: this.createOptions
|
||||
options: this.createOptions.concat(this.getCreateEntryTemplateOptions())
|
||||
});
|
||||
this.views.searchDropdown = view;
|
||||
},
|
||||
|
||||
getCreateEntryTemplateOptions: function() {
|
||||
const entryTemplates = this.model.getEntryTemplates();
|
||||
const hasMultipleFiles = this.model.files.length > 1;
|
||||
this.entryTemplates = {};
|
||||
const options = [];
|
||||
entryTemplates.forEach(tmpl => {
|
||||
const id = 'tmpl:' + tmpl.entry.id;
|
||||
options.push({
|
||||
value: id,
|
||||
icon: tmpl.entry.icon,
|
||||
text: hasMultipleFiles ? tmpl.file.get('name') + ' / ' + tmpl.entry.title : tmpl.entry.title
|
||||
});
|
||||
this.entryTemplates[id] = tmpl;
|
||||
});
|
||||
options.sort(Comparators.stringComparator('text', true));
|
||||
options.push({ value: 'tmpl', icon: 'sticky-note-o', text: Format.capFirst(Locale.template) });
|
||||
return options;
|
||||
},
|
||||
|
||||
sortDropdownSelect: function(e) {
|
||||
this.hideSearchOptions();
|
||||
Backbone.trigger('set-sort', e.item);
|
||||
|
@ -307,6 +328,13 @@ const ListSearchView = Backbone.View.extend({
|
|||
case 'group':
|
||||
this.trigger('create-group');
|
||||
break;
|
||||
case 'tmpl':
|
||||
this.trigger('create-template');
|
||||
break;
|
||||
default:
|
||||
if (this.entryTemplates[e.item]) {
|
||||
this.trigger('create-entry', { template: this.entryTemplates[e.item] });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ const DragDropInfo = require('../comp/drag-drop-info');
|
|||
const AppSettingsModel = require('../models/app-settings-model');
|
||||
const Locale = require('../util/locale');
|
||||
const Format = require('../util/format');
|
||||
const Alerts = require('../comp/alerts');
|
||||
|
||||
const ListView = Backbone.View.extend({
|
||||
template: require('templates/list.hbs'),
|
||||
|
@ -47,6 +48,7 @@ const ListView = Backbone.View.extend({
|
|||
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.views.search, 'create-template', this.createTemplate);
|
||||
this.listenTo(this, 'show', this.viewShown);
|
||||
this.listenTo(this, 'hide', this.viewHidden);
|
||||
this.listenTo(this, 'view-resize', this.viewResized);
|
||||
|
@ -147,8 +149,8 @@ const ListView = Backbone.View.extend({
|
|||
}
|
||||
},
|
||||
|
||||
createEntry: function() {
|
||||
const newEntry = this.model.createNewEntry();
|
||||
createEntry: function(arg) {
|
||||
const newEntry = this.model.createNewEntry(arg);
|
||||
this.items.unshift(newEntry);
|
||||
this.render();
|
||||
this.selectItem(newEntry);
|
||||
|
@ -159,6 +161,10 @@ const ListView = Backbone.View.extend({
|
|||
Backbone.trigger('edit-group', newGroup);
|
||||
},
|
||||
|
||||
createTemplate: function() {
|
||||
Alerts.notImplemented();
|
||||
},
|
||||
|
||||
selectItem: function(item) {
|
||||
this.model.activeEntryId = item.id;
|
||||
Backbone.trigger('entry-selected', item);
|
||||
|
|
|
@ -4,6 +4,7 @@ Release notes
|
|||
`+` plugins
|
||||
`*` translations are available only as plugins
|
||||
`*` Dropbox API V2
|
||||
`+` entry templates
|
||||
`+` support cloud providers in iOS homescreen apps
|
||||
`+` mobile field editing improvements
|
||||
`+` file path hint in recent files list
|
||||
|
|
Loading…
Reference in New Issue