field views

This commit is contained in:
antelle 2019-09-16 19:55:06 +02:00
parent 927278317e
commit 8869a27ac9
14 changed files with 291 additions and 335 deletions

View File

@ -131,100 +131,80 @@ class DetailsHistoryView extends View {
this.bodyEl.html('');
const colorCls = this.record.color ? this.record.color + '-color' : '';
this.fieldViews.push(
new FieldViewReadOnly({
model: { name: 'Rev', title: Locale.detHistoryVersion, value: ix + 1 }
})
new FieldViewReadOnly({ name: 'Rev', title: Locale.detHistoryVersion, value: ix + 1 })
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: 'Updated',
title: Locale.detHistorySaved,
value:
DateFormat.dtStr(this.record.updated) +
(this.record.unsaved ? ' (' + Locale.detHistoryCurUnsavedState + ')' : '') +
(ix === this.history.length - 1 && !this.record.unsaved
? ' (' + Locale.detHistoryCurState + ')'
: '')
}
name: 'Updated',
title: Locale.detHistorySaved,
value:
DateFormat.dtStr(this.record.updated) +
(this.record.unsaved ? ' (' + Locale.detHistoryCurUnsavedState + ')' : '') +
(ix === this.history.length - 1 && !this.record.unsaved
? ' (' + Locale.detHistoryCurState + ')'
: '')
})
);
this.fieldViews.push(
new FieldViewReadOnlyRaw({
model: {
name: '$Title',
title: StringFormat.capFirst(Locale.title),
value:
'<i class="fa fa-' +
this.record.icon +
' ' +
colorCls +
'"></i> ' +
_.escape(this.record.title) || '(' + Locale.detHistoryNoTitle + ')'
}
name: '$Title',
title: StringFormat.capFirst(Locale.title),
value:
'<i class="fa fa-' +
this.record.icon +
' ' +
colorCls +
'"></i> ' +
_.escape(this.record.title) || '(' + Locale.detHistoryNoTitle + ')'
})
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: '$UserName',
title: StringFormat.capFirst(Locale.user),
value: this.record.user
}
name: '$UserName',
title: StringFormat.capFirst(Locale.user),
value: this.record.user
})
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: '$Password',
title: StringFormat.capFirst(Locale.password),
value: this.record.password
}
name: '$Password',
title: StringFormat.capFirst(Locale.password),
value: this.record.password
})
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: '$URL',
title: StringFormat.capFirst(Locale.website),
value: this.record.url
}
name: '$URL',
title: StringFormat.capFirst(Locale.website),
value: this.record.url
})
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: '$Notes',
title: StringFormat.capFirst(Locale.notes),
value: this.record.notes
}
name: '$Notes',
title: StringFormat.capFirst(Locale.notes),
value: this.record.notes
})
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: 'Tags',
title: StringFormat.capFirst(Locale.tags),
value: this.record.tags.join(', ')
}
name: 'Tags',
title: StringFormat.capFirst(Locale.tags),
value: this.record.tags.join(', ')
})
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: 'Expires',
title: Locale.detExpires,
value: this.record.expires ? DateFormat.dtStr(this.record.expires) : ''
}
name: 'Expires',
title: Locale.detExpires,
value: this.record.expires ? DateFormat.dtStr(this.record.expires) : ''
})
);
_.forEach(
this.record.fields,
function(value, field) {
(value, field) => {
this.fieldViews.push(
new FieldViewReadOnly({
model: { name: '$' + field, title: field, value }
})
new FieldViewReadOnly({ name: '$' + field, title: field, value })
);
},
this
@ -232,18 +212,17 @@ class DetailsHistoryView extends View {
if (this.record.attachments.length) {
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: 'Attachments',
title: Locale.detAttachments,
value: this.record.attachments.map(att => att.title).join(', ')
}
name: 'Attachments',
title: Locale.detAttachments,
value: this.record.attachments.map(att => att.title).join(', ')
})
);
}
this.fieldViews.forEach(function(fieldView) {
fieldView.setElement(this.bodyEl).render();
this.fieldViews.forEach(fieldView => {
fieldView.parent = this.bodyEl[0];
fieldView.render();
fieldView.on('copy', this.fieldCopied.bind(this));
}, this);
});
const buttons = this.$el.find('.details__history-buttons');
buttons.find('.details__history-button-revert').toggle(ix < this.history.length - 1);
buttons.find('.details__history-button-delete').toggle(ix < this.history.length - 1);

View File

@ -156,141 +156,117 @@ class DetailsView extends View {
return { id: file.id, value: file.get('name'), selected: file === this.model.file };
}, this);
this.fileEditView = new FieldViewSelect({
model: {
name: '$File',
title: StringFormat.capFirst(Locale.file),
value() {
return fileNames;
}
name: '$File',
title: StringFormat.capFirst(Locale.file),
value() {
return fileNames;
}
});
this.fieldViews.push(this.fileEditView);
} else {
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: 'File',
title: StringFormat.capFirst(Locale.file),
value() {
return model.fileName;
}
name: 'File',
title: StringFormat.capFirst(Locale.file),
value() {
return model.fileName;
}
})
);
}
this.userEditView = new FieldViewAutocomplete({
model: {
name: '$UserName',
title: StringFormat.capFirst(Locale.user),
value() {
return model.user;
},
getCompletions: this.getUserNameCompletions.bind(this)
}
name: '$UserName',
title: StringFormat.capFirst(Locale.user),
value() {
return model.user;
},
getCompletions: this.getUserNameCompletions.bind(this)
});
this.fieldViews.push(this.userEditView);
this.passEditView = new FieldViewText({
model: {
name: '$Password',
title: StringFormat.capFirst(Locale.password),
canGen: true,
value() {
return model.password;
}
name: '$Password',
title: StringFormat.capFirst(Locale.password),
canGen: true,
value() {
return model.password;
}
});
this.fieldViews.push(this.passEditView);
this.urlEditView = new FieldViewUrl({
model: {
name: '$URL',
title: StringFormat.capFirst(Locale.website),
value() {
return model.url;
}
name: '$URL',
title: StringFormat.capFirst(Locale.website),
value() {
return model.url;
}
});
this.fieldViews.push(this.urlEditView);
this.fieldViews.push(
new FieldViewText({
model: {
name: '$Notes',
title: StringFormat.capFirst(Locale.notes),
multiline: 'true',
markdown: true,
value() {
return model.notes;
}
name: '$Notes',
title: StringFormat.capFirst(Locale.notes),
multiline: 'true',
markdown: true,
value() {
return model.notes;
}
})
);
this.fieldViews.push(
new FieldViewTags({
model: {
name: 'Tags',
title: StringFormat.capFirst(Locale.tags),
tags: this.appModel.tags,
value() {
return model.tags;
}
name: 'Tags',
title: StringFormat.capFirst(Locale.tags),
tags: this.appModel.tags,
value() {
return model.tags;
}
})
);
this.fieldViews.push(
new FieldViewDate({
model: {
name: 'Expires',
title: Locale.detExpires,
lessThanNow: '(' + Locale.detExpired + ')',
value() {
return model.expires;
}
name: 'Expires',
title: Locale.detExpires,
lessThanNow: '(' + Locale.detExpired + ')',
value() {
return model.expires;
}
})
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: 'Group',
title: Locale.detGroup,
value() {
return model.groupName;
},
tip() {
return model.getGroupPath().join(' / ');
}
name: 'Group',
title: Locale.detGroup,
value() {
return model.groupName;
},
tip() {
return model.getGroupPath().join(' / ');
}
})
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: 'Created',
title: Locale.detCreated,
value() {
return DateFormat.dtStr(model.created);
}
name: 'Created',
title: Locale.detCreated,
value() {
return DateFormat.dtStr(model.created);
}
})
);
this.fieldViews.push(
new FieldViewReadOnly({
model: {
name: 'Updated',
title: Locale.detUpdated,
value() {
return DateFormat.dtStr(model.updated);
}
name: 'Updated',
title: Locale.detUpdated,
value() {
return DateFormat.dtStr(model.updated);
}
})
);
this.fieldViews.push(
new FieldViewHistory({
model: {
name: 'History',
title: StringFormat.capFirst(Locale.history),
value() {
return { length: model.historyLength, unsaved: model.unsaved };
}
name: 'History',
title: StringFormat.capFirst(Locale.history),
value() {
return { length: model.historyLength, unsaved: model.unsaved };
}
})
);
@ -298,25 +274,21 @@ class DetailsView extends View {
if (field === 'otp' && this.model.otpGenerator) {
this.fieldViews.push(
new FieldViewOtp({
model: {
name: '$' + field,
title: field,
value() {
return model.otpGenerator;
}
name: '$' + field,
title: field,
value() {
return model.otpGenerator;
}
})
);
} else {
this.fieldViews.push(
new FieldViewCustom({
model: {
name: '$' + field,
title: field,
multiline: true,
value() {
return model.fields[field];
}
name: '$' + field,
title: field,
multiline: true,
value() {
return model.fields[field];
}
})
);
@ -328,7 +300,8 @@ class DetailsView extends View {
const fieldsMainEl = this.$el.find('.details__body-fields');
const fieldsAsideEl = this.$el.find('.details__body-aside');
this.fieldViews.forEach(fieldView => {
fieldView.setElement(fieldView.readonly ? fieldsAsideEl : fieldsMainEl).render();
fieldView.parent = fieldView.readonly ? fieldsAsideEl[0] : fieldsMainEl[0];
fieldView.render();
fieldView.on('change', this.fieldChanged.bind(this));
fieldView.on('copy', this.fieldCopied.bind(this));
if (hideEmptyFields) {
@ -364,8 +337,8 @@ class DetailsView extends View {
}
}
}
const fieldView = new FieldViewCustom({
model: {
const fieldView = new FieldViewCustom(
{
name: '$' + newFieldTitle,
title: newFieldTitle,
newField: newFieldTitle,
@ -373,10 +346,13 @@ class DetailsView extends View {
value() {
return '';
}
},
{
parent: this.$el.find('.details__body-fields')[0]
}
});
);
fieldView.on('change', this.fieldChanged.bind(this));
fieldView.setElement(this.$el.find('.details__body-fields')).render();
fieldView.render();
fieldView.edit();
this.fieldViews.push(fieldView);
}
@ -1059,16 +1035,19 @@ class DetailsView extends View {
} else {
this.moreView.remove();
this.moreView = null;
const fieldView = new FieldViewCustom({
model: {
const fieldView = new FieldViewCustom(
{
name: '$otp',
title: 'otp',
newField: 'otp',
value: kdbxweb.ProtectedValue.fromString('')
},
{
parent: this.$el.find('.details__body-fields')[0]
}
});
);
fieldView.on('change', this.fieldChanged.bind(this));
fieldView.setElement(this.$el.find('.details__body-fields')).render();
fieldView.render();
fieldView.edit();
this.fieldViews.push(fieldView);
}

View File

@ -1,18 +1,18 @@
import { Keys } from 'const/keys';
import { FieldViewText } from 'views/fields/field-view-text';
const FieldViewAutocomplete = FieldViewText.extend({
class FieldViewAutocomplete extends FieldViewText {
endEdit(newVal, extra) {
if (this.autocomplete) {
this.autocomplete.remove();
this.autocomplete = null;
}
delete this.selectedCopmletionIx;
FieldViewText.prototype.endEdit.call(this, newVal, extra);
},
super.endEdit(newVal, extra);
}
startEdit() {
FieldViewText.prototype.startEdit.call(this);
super.startEdit();
const fieldRect = this.input[0].getBoundingClientRect();
const shadowSpread = parseInt(this.input.css('--focus-shadow-spread'));
this.autocomplete = $('<div class="details__field-autocomplete"></div>').appendTo('body');
@ -28,13 +28,13 @@ const FieldViewAutocomplete = FieldViewText.extend({
} else {
this.updateAutocomplete();
}
},
}
fieldValueInput(e) {
e.stopPropagation();
this.updateAutocomplete();
FieldViewText.prototype.fieldValueInput.call(this, e);
},
super.fieldValueInput.call(this, e);
}
fieldValueKeydown(e) {
switch (e.which) {
@ -59,8 +59,8 @@ const FieldViewAutocomplete = FieldViewText.extend({
default:
delete this.selectedCopmletionIx;
}
FieldViewText.prototype.fieldValueKeydown.call(this, e);
},
super.fieldValueKeydown(e);
}
moveAutocomplete(next) {
const completions = this.model.getCompletions(this.input.val());
@ -72,7 +72,7 @@ const FieldViewAutocomplete = FieldViewText.extend({
this.selectedCopmletionIx = next ? 0 : completions.length - 1;
}
this.updateAutocomplete();
},
}
updateAutocomplete() {
const completions = this.model.getCompletions(this.input.val());
@ -93,7 +93,7 @@ const FieldViewAutocomplete = FieldViewText.extend({
.join('');
this.autocomplete.html(completionsHtml);
this.autocomplete.toggle(!!completionsHtml);
},
}
autocompleteClick(e) {
e.stopPropagation();
@ -107,6 +107,6 @@ const FieldViewAutocomplete = FieldViewText.extend({
});
}
}
});
}
export { FieldViewAutocomplete };

View File

@ -6,17 +6,16 @@ import { Tip } from 'util/ui/tip';
import { FieldView } from 'views/fields/field-view';
import { FieldViewText } from 'views/fields/field-view-text';
const FieldViewCustom = FieldViewText.extend({
events: {
'mousedown .details__field-label': 'fieldLabelMousedown'
},
initialize() {
_.extend(this.events, FieldViewText.prototype.events);
},
class FieldViewCustom extends FieldViewText {
events = Object.assign(
{
'mousedown .details__field-label': 'fieldLabelMousedown'
},
FieldViewText.prototype.events
);
startEdit() {
FieldViewText.prototype.startEdit.call(this);
super.startEdit();
this.$el.addClass('details__field--can-edit-title');
if (this.isProtected === undefined) {
this.isProtected = this.value instanceof kdbxweb.ProtectedValue;
@ -34,7 +33,7 @@ const FieldViewCustom = FieldViewText.extend({
title: securityTipTitle
});
securityTip.init();
},
}
endEdit(newVal, extra) {
this.$el.removeClass('details__field--can-edit-title');
@ -58,7 +57,7 @@ const FieldViewCustom = FieldViewText.extend({
if (this.model.titleChanged) {
delete this.model.titleChanged;
}
},
}
startEditTitle(emptyTitle) {
const text = emptyTitle ? '' : this.model.title || '';
@ -76,14 +75,14 @@ const FieldViewCustom = FieldViewText.extend({
mousedown: this.fieldLabelInputClick.bind(this),
click: this.fieldLabelInputClick.bind(this)
});
},
}
endEditTitle(newTitle) {
if (newTitle && newTitle !== this.model.title) {
this.model.title = newTitle;
this.model.titleChanged = true;
} else if (newTitle === '') {
this.trigger('change', {
this.emit('change', {
field: '$' + this.model.title,
val: ''
});
@ -93,7 +92,7 @@ const FieldViewCustom = FieldViewText.extend({
if (this.editing && this.input) {
this.input.focus();
}
},
}
fieldLabelClick(e) {
e.stopImmediatePropagation();
@ -102,15 +101,15 @@ const FieldViewCustom = FieldViewText.extend({
} else if (this.editing) {
this.startEditTitle();
} else {
FieldViewText.prototype.fieldLabelClick.call(this, e);
super.fieldLabelClick.call(this, e);
}
},
}
fieldLabelMousedown(e) {
if (this.editing) {
e.stopPropagation();
}
},
}
fieldValueBlur() {
if (this.labelInput) {
@ -119,15 +118,15 @@ const FieldViewCustom = FieldViewText.extend({
if (this.input) {
this.endEdit(this.input.val());
}
},
}
fieldLabelInput(e) {
e.stopPropagation();
},
}
fieldLabelInputClick(e) {
e.stopPropagation();
},
}
fieldLabelKeydown(e) {
e.stopPropagation();
@ -140,14 +139,14 @@ const FieldViewCustom = FieldViewText.extend({
e.preventDefault();
this.endEditTitle(e.target.value);
}
},
}
fieldValueInputClick() {
if (this.labelInput) {
this.endEditTitle(this.labelInput.val());
}
FieldViewText.prototype.fieldValueInputClick.call(this);
},
super.fieldValueInputClick.call(this);
}
protectBtnClick(e) {
e.stopPropagation();
@ -158,6 +157,6 @@ const FieldViewCustom = FieldViewText.extend({
}
setTimeout(() => this.input.focus());
}
});
}
export { FieldViewCustom };

View File

@ -1,23 +1,23 @@
import { Pikaday } from 'pikaday';
import Pikaday from 'pikaday';
import { DateFormat } from 'util/formatting/date-format';
import { Locale } from 'util/locale';
import { FieldViewText } from 'views/fields/field-view-text';
const FieldViewDate = FieldViewText.extend({
class FieldViewDate extends FieldViewText {
renderValue(value) {
let result = value ? DateFormat.dStr(value) : '';
if (value && this.model.lessThanNow && value < new Date()) {
result += ' ' + this.model.lessThanNow;
}
return result;
},
}
getEditValue(value) {
return value ? DateFormat.dStr(value) : '';
},
}
startEdit() {
FieldViewText.prototype.startEdit.call(this);
super.startEdit();
this.picker = new Pikaday({
field: this.input[0],
onSelect: this.pickerSelect.bind(this),
@ -35,7 +35,7 @@ const FieldViewDate = FieldViewText.extend({
});
this.picker.adjustPosition = this.adjustPickerPosition.bind(this);
_.defer(this.picker.show.bind(this.picker));
},
}
adjustPickerPosition(...args) {
window.Pikaday = Pikaday;
@ -47,13 +47,13 @@ const FieldViewDate = FieldViewText.extend({
const newTop = parseInt(this.picker.el.style.top) + offset;
this.picker.el.style.top = `${newTop}px`;
}
},
}
fieldValueBlur(e) {
if (!this.picker) {
FieldViewText.prototype.fieldValueBlur.call(this, e);
super.fieldValueBlur(e);
}
},
}
endEdit(newVal, extra) {
if (this.picker) {
@ -66,16 +66,16 @@ const FieldViewDate = FieldViewText.extend({
if (!newVal || isNaN(newVal.getTime())) {
newVal = null;
}
FieldViewText.prototype.endEdit.call(this, newVal, extra);
},
super.endEdit(newVal, extra);
}
pickerClose() {
this.endEdit(this.input.val());
},
}
pickerSelect(dt) {
this.endEdit(dt);
}
});
}
export { FieldViewDate };

View File

@ -1,7 +1,9 @@
import { Locale } from 'util/locale';
import { FieldView } from 'views/fields/field-view';
const FieldViewHistory = FieldView.extend({
class FieldViewHistory extends FieldView {
readonly = true;
renderValue(value) {
if (!value.length) {
return Locale.detHistoryEmpty;
@ -9,14 +11,12 @@ const FieldViewHistory = FieldView.extend({
let text =
value.length +
' ' +
(value.length % 10 === 1 ? Locale.detHistoryRec : Locale.detHistoryRecs);
(value.length === 1 ? Locale.detHistoryRec : Locale.detHistoryRecs);
if (value.unsaved) {
text += ' (' + Locale.detHistoryModified + ')';
}
return '<a class="details__history-link">' + text + '</a>';
},
readonly: true
});
}
}
export { FieldViewHistory };

View File

@ -3,14 +3,14 @@ import { FieldViewText } from 'views/fields/field-view-text';
const MinOpacity = 0.1;
const FieldViewOtp = FieldViewText.extend({
otpTimeout: null,
otpTickInterval: null,
otpValue: null,
otpGenerator: null,
otpTimeLeft: 0,
otpValidUntil: 0,
fieldOpacity: null,
class FieldViewOtp extends FieldViewText {
otpTimeout = null;
otpTickInterval = null;
otpValue = null;
otpGenerator = null;
otpTimeLeft = 0;
otpValidUntil = 0;
fieldOpacity = null;
renderValue(value) {
if (!value) {
@ -22,22 +22,22 @@ const FieldViewOtp = FieldViewText.extend({
this.requestOtpUpdate();
}
return this.otpValue;
},
}
getEditValue(value) {
return value && value.url;
},
}
render() {
FieldViewText.prototype.render.call(this);
super.render();
this.fieldOpacity = null;
this.otpTick();
},
}
remove() {
this.resetOtp();
FieldViewText.prototype.remove.apply(this);
},
super.remove();
}
resetOtp() {
this.otpGenerator = null;
@ -52,13 +52,13 @@ const FieldViewOtp = FieldViewText.extend({
clearInterval(this.otpTickInterval);
this.otpTickInterval = null;
}
},
}
requestOtpUpdate() {
if (this.value) {
this.value.next(this.otpUpdated.bind(this));
}
},
}
otpUpdated(pass, timeLeft) {
if (!this.value || !pass) {
@ -77,7 +77,7 @@ const FieldViewOtp = FieldViewText.extend({
this.otpTickInterval = setInterval(this.otpTick.bind(this), 300);
}
}
},
}
otpTick() {
if (!this.value || !this.otpValidUntil) {
@ -98,6 +98,6 @@ const FieldViewOtp = FieldViewText.extend({
this.fieldOpacity = opacity;
this.valueEl.css('opacity', opacity);
}
});
}
export { FieldViewOtp };

View File

@ -1,11 +1,11 @@
import { FieldView } from 'views/fields/field-view';
const FieldViewReadOnlyRaw = FieldView.extend({
class FieldViewReadOnlyRaw extends FieldView {
readonly = true;
renderValue(value) {
return value;
},
readonly: true
});
}
}
export { FieldViewReadOnlyRaw };

View File

@ -1,13 +1,13 @@
import { FieldView } from 'views/fields/field-view';
const FieldViewReadOnly = FieldView.extend({
class FieldViewReadOnly extends FieldView {
readonly = true;
renderValue(value) {
value = value.isProtected ? new Array(value.textLength + 1).join('•') : _.escape(value);
value = value.replace(/\n/g, '<br/>');
return value;
},
readonly: true
});
}
}
export { FieldViewReadOnly };

View File

@ -1,7 +1,7 @@
import { FieldView } from 'views/fields/field-view';
const FieldViewSelect = FieldView.extend({
readonly: true,
class FieldViewSelect extends FieldView {
readonly = true;
renderValue(value) {
return (
@ -22,31 +22,31 @@ const FieldViewSelect = FieldView.extend({
.join('') +
'</select>'
);
},
}
render() {
FieldView.prototype.render.call(this);
super.render();
this.valueEl.addClass('details__field-value--select');
this.valueEl.find('select:first').change(e => {
this.triggerChange({ val: e.target.value, field: this.model.name });
});
},
}
fieldLabelClick() {},
fieldLabelClick() {}
fieldValueClick() {},
fieldValueClick() {}
edit() {},
edit() {}
startEdit() {},
startEdit() {}
endEdit(newVal, extra) {
if (!this.editing) {
return;
}
delete this.input;
FieldView.prototype.endEdit.call(this, newVal, extra);
super.endEdit(newVal, extra);
}
});
}
export { FieldViewSelect };

View File

@ -1,13 +1,13 @@
import { FieldViewText } from 'views/fields/field-view-text';
const FieldViewTags = FieldViewText.extend({
class FieldViewTags extends FieldViewText {
renderValue(value) {
return value ? _.escape(value.join(', ')) : '';
},
}
getEditValue(value) {
return value ? value.join(', ') : '';
},
}
valueToTags(val) {
const allTags = {};
@ -22,7 +22,7 @@ const FieldViewTags = FieldViewText.extend({
return allTags[tag.toLowerCase()] || tag;
})
);
},
}
endEdit(newVal, extra) {
if (newVal !== undefined) {
@ -32,11 +32,11 @@ const FieldViewTags = FieldViewText.extend({
this.tagsAutocomplete.remove();
this.tagsAutocomplete = null;
}
FieldViewText.prototype.endEdit.call(this, newVal, extra);
},
super.endEdit(newVal, extra);
}
startEdit() {
FieldViewText.prototype.startEdit.call(this);
super.startEdit();
const fieldRect = this.input[0].getBoundingClientRect();
const shadowSpread = parseInt(this.input.css('--focus-shadow-spread'));
this.tagsAutocomplete = $('<div class="details__field-autocomplete"></div>').appendTo(
@ -49,13 +49,13 @@ const FieldViewTags = FieldViewText.extend({
});
this.tagsAutocomplete.mousedown(this.tagsAutocompleteClick.bind(this));
this.setTags();
},
}
fieldValueInput(e) {
e.stopPropagation();
this.setTags();
FieldViewText.prototype.fieldValueInput.call(this, e);
},
super.fieldValueInput(e);
}
getAvailableTags() {
const tags = this.valueToTags(this.input.val());
@ -67,7 +67,7 @@ const FieldViewTags = FieldViewText.extend({
(!isLastPart || tag.toLowerCase().indexOf(last.toLowerCase()) >= 0)
);
});
},
}
setTags() {
const availableTags = this.getAvailableTags();
@ -78,7 +78,7 @@ const FieldViewTags = FieldViewText.extend({
.join('');
this.tagsAutocomplete.html(tagsHtml);
this.tagsAutocomplete.toggle(!!tagsHtml);
},
}
tagsAutocompleteClick(e) {
e.stopPropagation();
@ -105,6 +105,6 @@ const FieldViewTags = FieldViewText.extend({
this.input.focus();
});
}
});
}
export { FieldViewTags };

View File

@ -9,7 +9,7 @@ import { Tip } from 'util/ui/tip';
import { FieldView } from 'views/fields/field-view';
import { GeneratorView } from 'views/generator-view';
const FieldViewText = FieldView.extend({
class FieldViewText extends FieldView {
renderValue(value) {
if (this.model.markdown) {
if (value && value.isProtected) {
@ -20,11 +20,11 @@ const FieldViewText = FieldView.extend({
return value && value.isProtected
? PasswordGenerator.presentValueWithLineBreaks(value)
: _.escape(value || '').replace(/\n/g, '<br/>');
},
}
getEditValue(value) {
return value && value.isProtected ? value.getText() : value || '';
},
}
startEdit() {
const text = this.getEditValue(this.value);
@ -61,7 +61,7 @@ const FieldViewText = FieldView.extend({
}
Tip.hideTip(this.valueEl[0]);
Tip.hideTip(this.labelEl[0]);
},
}
createMobileControls() {
this.mobileControls = {};
@ -77,14 +77,14 @@ const FieldViewText = FieldView.extend({
touchmove: this.mobileFieldControlTouchMove.bind(this)
});
});
},
}
showGeneratorClick(e) {
e.stopPropagation();
if (!this.gen) {
this.input.focus();
}
},
}
showGenerator() {
if (this.gen) {
@ -99,7 +99,7 @@ const FieldViewText = FieldView.extend({
this.gen.once('remove', this.generatorClosed.bind(this));
this.gen.once('result', this.generatorResult.bind(this));
}
},
}
hideGenerator() {
if (this.gen) {
@ -107,21 +107,21 @@ const FieldViewText = FieldView.extend({
delete this.gen;
gen.remove();
}
},
}
generatorClosed() {
if (this.gen) {
delete this.gen;
this.endEdit();
}
},
}
generatorResult(password) {
if (this.gen) {
delete this.gen;
this.endEdit(password);
}
},
}
setInputHeight() {
const MinHeight = 18;
@ -131,30 +131,30 @@ const FieldViewText = FieldView.extend({
newHeight = MinHeight;
}
this.input.height(newHeight);
},
}
fieldValueBlur() {
if (!this.gen && this.input) {
this.endEdit(this.input.val());
}
},
}
fieldValueInput(e) {
e.stopPropagation();
if (this.model.multiline) {
this.setInputHeight();
}
},
}
fieldValueInputClick() {
if (this.gen) {
this.hideGenerator();
}
},
}
fieldValueInputMouseDown(e) {
e.stopPropagation();
},
}
fieldValueKeydown(e) {
KeyHandler.reg();
@ -185,13 +185,13 @@ const FieldViewText = FieldView.extend({
return;
}
e.stopPropagation();
},
}
externalEndEdit() {
if (this.input) {
this.endEdit(this.input.val());
}
},
}
endEdit(newVal, extra) {
if (this.gen) {
@ -213,12 +213,12 @@ const FieldViewText = FieldView.extend({
if (typeof newVal === 'string') {
newVal = $.trim(newVal);
}
FieldView.prototype.endEdit.call(this, newVal, extra);
},
super.endEdit(newVal, extra);
}
stopBlurListener() {
this.stopListening(Backbone, 'click main-window-will-close', this.fieldValueBlur);
},
}
mobileFieldControlMouseDown(e) {
e.stopPropagation();
@ -229,11 +229,11 @@ const FieldViewText = FieldView.extend({
} else {
this.endEdit();
}
},
}
mobileFieldControlTouchStart(e) {
this.$el.attr('active-mobile-action', $(e.target).data('action'));
},
}
mobileFieldControlTouchEnd(e) {
const shouldExecute = this.$el.attr('active-mobile-action') === $(e.target).data('action');
@ -241,7 +241,7 @@ const FieldViewText = FieldView.extend({
if (shouldExecute) {
this.mobileFieldControlMouseDown(e);
}
},
}
mobileFieldControlTouchMove(e) {
const touch = e.originalEvent.targetTouches[0];
@ -256,11 +256,7 @@ const FieldViewText = FieldView.extend({
} else {
this.$el.removeAttr('active-mobile-action');
}
},
render() {
FieldView.prototype.render.call(this);
}
});
}
export { FieldViewText };

View File

@ -1,8 +1,8 @@
import { FieldViewText } from 'views/fields/field-view-text';
const FieldViewUrl = FieldViewText.extend({
displayUrlRegex: /^https:\/\//i,
cssClass: 'url',
class FieldViewUrl extends FieldViewText {
displayUrlRegex = /^https:\/\//i;
cssClass = 'url';
renderValue(value) {
return value
@ -12,15 +12,15 @@ const FieldViewUrl = FieldViewText.extend({
_.escape(this.displayUrl(value)) +
'</a>'
: '';
},
}
fixUrl(url) {
return url.indexOf(':') < 0 ? 'https://' + url : url;
},
}
displayUrl(url) {
return url.replace(this.displayUrlRegex, '');
}
});
}
export { FieldViewUrl };

View File

@ -1,19 +1,30 @@
import Backbone from 'backbone';
import { View } from 'view-engine/view';
import { CopyPaste } from 'comp/browser/copy-paste';
import { Tip } from 'util/ui/tip';
import template from 'templates/details/field.hbs';
const FieldView = Backbone.View.extend({
template: require('templates/details/field.hbs'),
class FieldView extends View {
template = template;
events: {
events = {
'click .details__field-label': 'fieldLabelClick',
'click .details__field-value': 'fieldValueClick',
'dragstart .details__field-label': 'fieldLabelDrag'
},
};
constructor(model, options) {
super(model, options);
this.once('remove', () => {
if (this.tip) {
Tip.hideTip(this.valueEl[0]);
}
});
}
render() {
this.value = typeof this.model.value === 'function' ? this.model.value() : this.model.value;
this.renderTemplate({
super.render({
cls: this.cssClass,
editable: !this.readonly,
multiline: this.model.multiline,
@ -31,15 +42,7 @@ const FieldView = Backbone.View.extend({
Tip.createTip(this.valueEl);
}
}
return this;
},
remove() {
if (this.tip) {
Tip.hideTip(this.valueEl[0]);
}
Backbone.View.prototype.remove.apply(this);
},
}
update() {
if (typeof this.model.value === 'function') {
@ -51,7 +54,7 @@ const FieldView = Backbone.View.extend({
this.render();
}
}
},
}
fieldLabelClick(e) {
e.stopImmediatePropagation();
@ -71,7 +74,7 @@ const FieldView = Backbone.View.extend({
CopyPaste.createHiddenInput(text);
}
copyRes = CopyPaste.copy(text);
this.trigger('copy', { source: this, copyRes });
this.emit('copy', { source: this, copyRes });
return;
}
}
@ -86,9 +89,9 @@ const FieldView = Backbone.View.extend({
copyRes = CopyPaste.copy(this.valueEl[0].innerText || this.valueEl.text());
if (copyRes) {
selection.removeAllRanges();
this.trigger('copy', { source: this, copyRes });
this.emit('copy', { source: this, copyRes });
}
},
}
fieldValueClick(e) {
if (['a', 'input', 'textarea'].indexOf(e.target.tagName.toLowerCase()) >= 0) {
@ -98,7 +101,7 @@ const FieldView = Backbone.View.extend({
if (!sel) {
this.edit();
}
},
}
fieldLabelDrag(e) {
e.stopPropagation();
@ -112,7 +115,7 @@ const FieldView = Backbone.View.extend({
}
dt.setData('text/plain', txtval);
dt.effectAllowed = 'copy';
},
}
edit() {
if (this.readonly || this.editing) {
@ -123,7 +126,7 @@ const FieldView = Backbone.View.extend({
this.editing = true;
this.preventCopy = true;
this.labelEl[0].setAttribute('draggable', 'false');
},
}
endEdit(newVal, extra) {
if (!this.editing) {
@ -159,12 +162,12 @@ const FieldView = Backbone.View.extend({
this.valueEl.html(this.renderValue(this.value));
this.$el.removeClass('details__field--edit');
this.labelEl[0].setAttribute('draggable', 'true');
},
}
triggerChange(arg) {
arg.sender = this;
this.trigger('change', arg);
this.emit('change', arg);
}
});
}
export { FieldView };