mirror of https://github.com/keeweb/keeweb.git
fix #58: hide empty fields
This commit is contained in:
parent
079d0f53c8
commit
ebf8baac94
|
@ -21,7 +21,8 @@ var AppSettingsModel = Backbone.Model.extend({
|
|||
lockOnMinimize: true,
|
||||
lockOnCopy: false,
|
||||
helpTipCopyShown: false,
|
||||
skipOpenLocalWarn: false
|
||||
skipOpenLocalWarn: false,
|
||||
hideEmptyFields: false
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
|
|
|
@ -163,7 +163,6 @@ var Locale = {
|
|||
detUpdated: 'Updated',
|
||||
detHistory: 'History',
|
||||
detNetField: 'New Field',
|
||||
detAddField: 'add field',
|
||||
detAttachments: 'Attachments',
|
||||
detDelFromTrash: 'Delete from trash?',
|
||||
detDelFromTrashBody: 'You will not be able to put it back.',
|
||||
|
@ -171,6 +170,12 @@ var Locale = {
|
|||
detFieldCopied: 'Copied',
|
||||
detFieldCopiedTime: 'Copied for {} seconds',
|
||||
detCopyHint: 'You can copy field value with click on its title',
|
||||
detMore: 'more',
|
||||
detClickToAddField: 'click to add a new field',
|
||||
detMenuAddNewField: 'Add new field',
|
||||
detMenuShowEmpty: 'Show empty fields',
|
||||
detMenuHideEmpty: 'Hide empty fields',
|
||||
detMenuAddField: 'Add {}',
|
||||
|
||||
appSecWarn: 'Not Secure!',
|
||||
appSecWarnBody1: 'You have loaded this app with insecure connection. ' +
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
var Backbone = require('backbone');
|
||||
|
||||
var DetailsAddFieldView = Backbone.View.extend({
|
||||
template: require('templates/details/details-add-field.hbs'),
|
||||
|
||||
events: {
|
||||
'click .details__field-label': 'fieldLabelClick',
|
||||
'click .details__field-value': 'fieldValueClick'
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.renderTemplate();
|
||||
this.labelEl = this.$el.find('.details__field-label');
|
||||
return this;
|
||||
},
|
||||
|
||||
fieldLabelClick: function() {
|
||||
this.trigger('more-click');
|
||||
},
|
||||
|
||||
fieldValueClick: function() {
|
||||
this.trigger('add-field');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = DetailsAddFieldView;
|
|
@ -1,6 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var Backbone = require('backbone'),
|
||||
kdbxweb = require('kdbxweb'),
|
||||
GroupModel = require('../../models/group-model'),
|
||||
AppSettingsModel = require('../../models/app-settings-model'),
|
||||
Scrollable = require('../../mixins/scrollable'),
|
||||
|
@ -15,6 +16,8 @@ var Backbone = require('backbone'),
|
|||
IconSelectView = require('../icon-select-view'),
|
||||
DetailsHistoryView = require('./details-history-view'),
|
||||
DetailsAttachmentView = require('./details-attachment-view'),
|
||||
DetailsAddFieldView = require('./details-add-field-view'),
|
||||
DropdownView = require('../../views/dropdown-view'),
|
||||
Keys = require('../../const/keys'),
|
||||
KeyHandler = require('../../comp/key-handler'),
|
||||
Alerts = require('../../comp/alerts'),
|
||||
|
@ -23,8 +26,7 @@ var Backbone = require('backbone'),
|
|||
Locale = require('../../util/locale'),
|
||||
Tip = require('../../util/tip'),
|
||||
Timeouts = require('../../const/timeouts'),
|
||||
FileSaver = require('filesaver'),
|
||||
kdbxweb = require('kdbxweb');
|
||||
FileSaver = require('filesaver');
|
||||
|
||||
var DetailsView = Backbone.View.extend({
|
||||
template: require('templates/details/details.hbs'),
|
||||
|
@ -36,7 +38,6 @@ var DetailsView = Backbone.View.extend({
|
|||
passEditView: null,
|
||||
userEditView: null,
|
||||
urlEditView: null,
|
||||
addNewFieldView: null,
|
||||
fieldCopyTip: null,
|
||||
|
||||
events: {
|
||||
|
@ -152,19 +153,8 @@ var DetailsView = Backbone.View.extend({
|
|||
this.fieldViews.push(new FieldViewCustom({ model: { name: '$' + field, title: field,
|
||||
value: function() { return model.fields[field]; } } }));
|
||||
}, this);
|
||||
var newFieldTitle = Locale.detNetField;
|
||||
if (model.fields[newFieldTitle]) {
|
||||
for (var i = 1; ; i++) {
|
||||
var newFieldTitleVariant = newFieldTitle + i;
|
||||
if (!model.fields[newFieldTitleVariant]) {
|
||||
newFieldTitle = newFieldTitleVariant;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.addNewFieldView = new FieldViewCustom({ model: { name: '$', title: Locale.detAddField, newField: newFieldTitle,
|
||||
value: function() { return ''; } } });
|
||||
this.fieldViews.push(this.addNewFieldView);
|
||||
|
||||
var hideEmptyFields = AppSettingsModel.instance.get('hideEmptyFields');
|
||||
|
||||
var fieldsMainEl = this.$el.find('.details__body-fields');
|
||||
var fieldsAsideEl = this.$el.find('.details__body-aside');
|
||||
|
@ -172,7 +162,92 @@ var DetailsView = Backbone.View.extend({
|
|||
fieldView.setElement(fieldView.readonly ? fieldsAsideEl : fieldsMainEl).render();
|
||||
fieldView.on('change', this.fieldChanged.bind(this));
|
||||
fieldView.on('copy', this.fieldCopied.bind(this));
|
||||
if (hideEmptyFields && !fieldView.model.value()) {
|
||||
fieldView.hide();
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.moreView = new DetailsAddFieldView();
|
||||
this.moreView.setElement(fieldsMainEl).render();
|
||||
this.moreView.on('add-field', this.addNewField.bind(this));
|
||||
this.moreView.on('more-click', this.toggleMoreOptions.bind(this));
|
||||
},
|
||||
|
||||
addNewField: function() {
|
||||
this.moreView.remove();
|
||||
this.moreView = null;
|
||||
var newFieldTitle = Locale.detNetField;
|
||||
if (this.model.fields[newFieldTitle]) {
|
||||
for (var i = 1; ; i++) {
|
||||
var newFieldTitleVariant = newFieldTitle + i;
|
||||
if (!this.model.fields[newFieldTitleVariant]) {
|
||||
newFieldTitle = newFieldTitleVariant;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
var fieldView = new FieldViewCustom({ model: { name: '$' + newFieldTitle, title: newFieldTitle, newField: newFieldTitle,
|
||||
value: function() { return ''; } } });
|
||||
fieldView.on('change', this.fieldChanged.bind(this));
|
||||
fieldView.setElement(this.$el.find('.details__body-fields')).render();
|
||||
fieldView.edit();
|
||||
this.fieldViews.push(fieldView);
|
||||
},
|
||||
|
||||
toggleMoreOptions: function() {
|
||||
if (this.views.dropdownView) {
|
||||
this.views.dropdownView.remove();
|
||||
this.views.dropdownView = null;
|
||||
} else {
|
||||
this.setTimeout(function() {
|
||||
var dropdownView = new DropdownView();
|
||||
this.listenTo(dropdownView, 'cancel', this.toggleMoreOptions);
|
||||
this.listenTo(dropdownView, 'select', this.moreOptionsSelect);
|
||||
var hideEmptyFields = AppSettingsModel.instance.get('hideEmptyFields');
|
||||
var moreOptions = [];
|
||||
if (hideEmptyFields) {
|
||||
this.fieldViews.forEach(function(fieldView) {
|
||||
if (!fieldView.model.value()) {
|
||||
moreOptions.push({value: 'add:' + fieldView.model.name, icon: 'pencil',
|
||||
text: Locale.detMenuAddField.replace('{}', fieldView.model.title)});
|
||||
}
|
||||
}, this);
|
||||
moreOptions.push({value: 'add-new', icon: 'plus', text: Locale.detMenuAddNewField});
|
||||
moreOptions.push({value: 'toggle-empty', icon: 'eye', text: Locale.detMenuShowEmpty});
|
||||
} else {
|
||||
moreOptions.push({value: 'add-new', icon: 'plus', text: Locale.detMenuAddNewField});
|
||||
moreOptions.push({value: 'toggle-empty', icon: 'eye-slash', text: Locale.detMenuHideEmpty});
|
||||
}
|
||||
var rect = this.moreView.labelEl[0].getBoundingClientRect();
|
||||
dropdownView.render({
|
||||
position: {top: rect.bottom, right: rect.right},
|
||||
options: moreOptions
|
||||
});
|
||||
this.views.dropdownView = dropdownView;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
moreOptionsSelect: function(e) {
|
||||
this.views.dropdownView.remove();
|
||||
this.views.dropdownView = null;
|
||||
switch (e.item) {
|
||||
case 'add-new':
|
||||
this.addNewField();
|
||||
break;
|
||||
case 'toggle-empty':
|
||||
var hideEmptyFields = AppSettingsModel.instance.get('hideEmptyFields');
|
||||
AppSettingsModel.instance.set('hideEmptyFields', !hideEmptyFields);
|
||||
this.render();
|
||||
break;
|
||||
default:
|
||||
if (e.item.lastIndexOf('add:', 0) === 0) {
|
||||
var fieldName = e.item.substr(4);
|
||||
var fieldView = _.find(this.fieldViews, function(f) { return f.model.name === fieldName; });
|
||||
fieldView.show();
|
||||
fieldView.edit();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getUserNameCompletions: function(part) {
|
||||
|
@ -289,7 +364,7 @@ var DetailsView = Backbone.View.extend({
|
|||
copyKeyPress: function(editView) {
|
||||
if (!window.getSelection().toString()) {
|
||||
var fieldValue = editView.value;
|
||||
var fieldText = fieldValue.isProtected ? fieldValue.getText() : fieldValue;
|
||||
var fieldText = fieldValue && fieldValue.isProtected ? fieldValue.getText() : fieldValue;
|
||||
if (!fieldText) {
|
||||
return;
|
||||
}
|
||||
|
@ -325,8 +400,8 @@ var DetailsView = Backbone.View.extend({
|
|||
}
|
||||
AppSettingsModel.instance.set('helpTipCopyShown', true);
|
||||
this.helpTipCopyShown = true;
|
||||
var newFieldLabel = this.addNewFieldView.labelEl;
|
||||
var tip = new Tip(newFieldLabel, { title: Locale.detCopyHint, placement: 'right' });
|
||||
var label = this.moreView.labelEl;
|
||||
var tip = new Tip(label, { title: Locale.detCopyHint, placement: 'right' });
|
||||
tip.show();
|
||||
setTimeout(function() { tip.hide(); }, Timeouts.AutoHideHint);
|
||||
},
|
||||
|
@ -335,7 +410,7 @@ var DetailsView = Backbone.View.extend({
|
|||
if (e.field) {
|
||||
if (e.field[0] === '$') {
|
||||
var fieldName = e.field.substr(1);
|
||||
if (e.newField && e.newField !== fieldName) {
|
||||
if (e.newField) {
|
||||
if (fieldName) {
|
||||
this.model.setField(fieldName, undefined);
|
||||
}
|
||||
|
@ -370,6 +445,9 @@ var DetailsView = Backbone.View.extend({
|
|||
fieldView.update();
|
||||
}
|
||||
}, this);
|
||||
} else if (e.newField) {
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
if (e.tab) {
|
||||
this.focusNextField(e.tab);
|
||||
|
@ -538,7 +616,7 @@ var DetailsView = Backbone.View.extend({
|
|||
var fieldView = this.fieldViews[i];
|
||||
if (fieldView.model.name === config.field) {
|
||||
found = true;
|
||||
} else if (found && !fieldView.readonly) {
|
||||
} else if (found && !fieldView.readonly && !fieldView.isHidden()) {
|
||||
nextFieldView = fieldView;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ var DropdownView = Backbone.View.extend({
|
|||
this.renderTemplate(config);
|
||||
this.$el.appendTo(document.body);
|
||||
var ownRect = this.$el[0].getBoundingClientRect();
|
||||
this.$el.css({ top: config.position.top, left: config.position.right - ownRect.right + ownRect.left });
|
||||
var left = config.position.left || (config.position.right - ownRect.right + ownRect.left);
|
||||
this.$el.css({ top: config.position.top, left: left });
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ var Backbone = require('backbone'),
|
|||
FieldViewText = require('./field-view-text'),
|
||||
FieldView = require('./field-view'),
|
||||
Keys = require('../../const/keys'),
|
||||
Locale = require('../../util/locale'),
|
||||
kdbxweb = require('kdbxweb');
|
||||
|
||||
var FieldViewCustom = FieldViewText.extend({
|
||||
|
@ -18,10 +17,6 @@ var FieldViewCustom = FieldViewText.extend({
|
|||
|
||||
startEdit: function() {
|
||||
FieldViewText.prototype.startEdit.call(this);
|
||||
if (this.model.newField && this.model.title === Locale.detAddField) {
|
||||
this.model.title = this.model.newField;
|
||||
this.$el.find('.details__field-label').text(this.model.newField);
|
||||
}
|
||||
this.$el.addClass('details__field--can-edit-title');
|
||||
if (this.isProtected === undefined) {
|
||||
this.isProtected = this.value instanceof kdbxweb.ProtectedValue;
|
||||
|
@ -50,10 +45,6 @@ var FieldViewCustom = FieldViewText.extend({
|
|||
}
|
||||
}
|
||||
FieldView.prototype.endEdit.call(this, newVal, extra);
|
||||
if (!newVal && this.model.newField) {
|
||||
this.model.title = Locale.detAddField;
|
||||
this.$el.find('.details__field-label').text(this.model.title);
|
||||
}
|
||||
if (this.model.titleChanged) {
|
||||
delete this.model.titleChanged;
|
||||
}
|
||||
|
@ -88,11 +79,10 @@ var FieldViewCustom = FieldViewText.extend({
|
|||
|
||||
fieldLabelClick: function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
if (this.editing) {
|
||||
this.startEditTitle();
|
||||
} else if (this.model.newField) {
|
||||
this.edit();
|
||||
if (this.model.newField) {
|
||||
this.startEditTitle(true);
|
||||
} else if (this.editing) {
|
||||
this.startEditTitle();
|
||||
} else {
|
||||
FieldViewText.prototype.fieldLabelClick.call(this, e);
|
||||
}
|
||||
|
|
|
@ -196,6 +196,9 @@
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-right: 20px;
|
||||
&-add-label {
|
||||
color: transparent;
|
||||
}
|
||||
.details__field--editable & {
|
||||
border-radius: $base-border-radius;
|
||||
&:hover {
|
||||
|
@ -204,6 +207,10 @@
|
|||
border: 1px solid light-border-color();
|
||||
box-shadow: 0 0 3px form-box-shadow-color();
|
||||
}
|
||||
.details__field-value-add-label {
|
||||
@include th { color: muted-color(); }
|
||||
transition: color $base-duration $base-timing;
|
||||
}
|
||||
}
|
||||
}
|
||||
.details__field--multiline & {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<div class="details__field details__field--editable">
|
||||
<div class="details__field-label">{{res 'detMore'}}…</div>
|
||||
<div class="details__field-value">
|
||||
<div class="details__field-value-add-label">{{res 'detClickToAddField'}}</div>
|
||||
</div>
|
||||
</div>
|
|
@ -17,6 +17,7 @@ Storage providers, usability improvements
|
|||
`+` build for 32-bit linux
|
||||
`+` ability to import xml
|
||||
`+` warning for kdb files
|
||||
`+` hide empty fields
|
||||
`-` fix #88: capslock indicator
|
||||
`-` fix file settings input behavior
|
||||
|
||||
|
|
Loading…
Reference in New Issue