From bb78e8e8a7bc705182f7f660c2228b6bf959d120 Mon Sep 17 00:00:00 2001 From: antelle Date: Mon, 26 Apr 2021 12:49:25 +0200 Subject: [PATCH] adding multiple websites to entries --- app/scripts/locales/base.json | 3 +- app/scripts/models/entry-model.js | 15 ++++++++- app/scripts/views/details/details-fields.js | 7 +++-- app/scripts/views/details/details-view.js | 31 ++++++++++++++++--- app/scripts/views/fields/field-view-custom.js | 5 +-- 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/app/scripts/locales/base.json b/app/scripts/locales/base.json index 008a58d5..11ca9b04 100644 --- a/app/scripts/locales/base.json +++ b/app/scripts/locales/base.json @@ -286,7 +286,8 @@ "detCopyHint": "You can copy field value by clicking its title", "detMore": "more", "detClickToAddField": "click to add a new field", - "detMenuAddNewField": "Add new field", + "detMenuAddNewField": "Add a new field", + "detMenuAddNewWebsite": "Add another website", "detMenuShowEmpty": "Show empty fields", "detMenuHideEmpty": "Hide empty fields", "detMenuAddField": "Add {}", diff --git a/app/scripts/models/entry-model.js b/app/scripts/models/entry-model.js index ddd11ea8..17fddec4 100644 --- a/app/scripts/models/entry-model.js +++ b/app/scripts/models/entry-model.js @@ -16,6 +16,7 @@ const UrlRegex = /^https?:\/\//i; const FieldRefRegex = /^\{REF:([TNPAU])@I:(\w{32})}$/; const FieldRefFields = ['title', 'password', 'user', 'url', 'notes']; const FieldRefIds = { T: 'Title', U: 'UserName', P: 'Password', A: 'URL', N: 'Notes' }; +const ExtraUrlFieldName = 'KP2A_URL'; class EntryModel extends Model { constructor(props) { @@ -639,6 +640,18 @@ class EntryModel extends Model { this._entryModified(); } + getNextUrlFieldName() { + const takenFields = new Set( + Object.keys(this.entry.fields).filter((f) => f.startsWith(ExtraUrlFieldName)) + ); + for (let i = 0; ; i++) { + const fieldName = i ? `${ExtraUrlFieldName}_${i}` : ExtraUrlFieldName; + if (!takenFields.has(fieldName)) { + return fieldName; + } + } + } + static fromEntry(entry, group, file) { const model = new EntryModel(); model.setEntry(entry, group, file); @@ -667,4 +680,4 @@ class EntryModel extends Model { EntryModel.defineModelProperties({}, { extensions: true }); -export { EntryModel }; +export { EntryModel, ExtraUrlFieldName }; diff --git a/app/scripts/views/details/details-fields.js b/app/scripts/views/details/details-fields.js index 520a2ae6..94aa8c22 100644 --- a/app/scripts/views/details/details-fields.js +++ b/app/scripts/views/details/details-fields.js @@ -13,6 +13,7 @@ import { FieldViewDate } from 'views/fields/field-view-date'; import { FieldViewHistory } from 'views/fields/field-view-history'; import { FieldViewCustom } from 'views/fields/field-view-custom'; import { FieldViewReadOnlyWithOptions } from 'views/fields/field-view-read-only-with-options'; +import { ExtraUrlFieldName } from 'models/entry-model'; function createDetailsFields(detailsView) { const model = detailsView.model; @@ -238,11 +239,13 @@ function createDetailsFields(detailsView) { ); } } else { + const isUrl = field.startsWith(ExtraUrlFieldName); fieldViews.push( new FieldViewCustom({ name: '$' + field, - title: field, - multiline: true, + title: isUrl ? StringFormat.capFirst(Locale.website) : field, + multiline: !isUrl, + titleEditable: !isUrl, value() { return model.fields[field]; }, diff --git a/app/scripts/views/details/details-view.js b/app/scripts/views/details/details-view.js index 1017a7ea..fd4429c4 100644 --- a/app/scripts/views/details/details-view.js +++ b/app/scripts/views/details/details-view.js @@ -30,6 +30,8 @@ import template from 'templates/details/details.hbs'; import emptyTemplate from 'templates/details/details-empty.hbs'; import groupTemplate from 'templates/details/details-group.hbs'; import { Launcher } from 'comp/launcher'; +import { ExtraUrlFieldName } from 'models/entry-model'; +import { StringFormat } from '../../util/formatting/string-format'; class DetailsView extends View { parent = '.app__details'; @@ -196,10 +198,10 @@ class DetailsView extends View { } } - addNewField() { + addNewField(title) { this.moreView.remove(); this.moreView = null; - let newFieldTitle = Locale.detNetField; + let newFieldTitle = title || Locale.detNetField; if (this.model.fields[newFieldTitle]) { for (let i = 1; ; i++) { const newFieldTitleVariant = newFieldTitle + i; @@ -209,12 +211,15 @@ class DetailsView extends View { } } } + + const isUrl = newFieldTitle.startsWith(ExtraUrlFieldName); const fieldView = new FieldViewCustom( { name: '$' + newFieldTitle, - title: newFieldTitle, + title: isUrl ? StringFormat.capFirst(Locale.website) : newFieldTitle, newField: newFieldTitle, - multiline: true, + multiline: !isUrl, + titleEditable: !isUrl, value() { return ''; } @@ -223,6 +228,7 @@ class DetailsView extends View { parent: this.$el.find('.details__body-fields')[0] } ); + fieldView.on('change', this.fieldChanged.bind(this)); fieldView.render(); fieldView.edit(); @@ -255,6 +261,13 @@ class DetailsView extends View { icon: 'plus', text: Locale.detMenuAddNewField }); + if (this.model.url) { + moreOptions.push({ + value: 'add-website', + icon: 'plus', + text: Locale.detMenuAddNewWebsite + }); + } moreOptions.push({ value: 'toggle-empty', icon: 'eye', @@ -266,6 +279,13 @@ class DetailsView extends View { icon: 'plus', text: Locale.detMenuAddNewField }); + if (this.model.url) { + moreOptions.push({ + value: 'add-website', + icon: 'plus', + text: Locale.detMenuAddNewWebsite + }); + } moreOptions.push({ value: 'toggle-empty', icon: 'eye-slash', @@ -303,6 +323,9 @@ class DetailsView extends View { case 'add-new': this.addNewField(); break; + case 'add-website': + this.addNewField(this.model.getNextUrlFieldName()); + break; case 'toggle-empty': { const hideEmptyFields = AppSettingsModel.hideEmptyFields; AppSettingsModel.hideEmptyFields = !hideEmptyFields; diff --git a/app/scripts/views/fields/field-view-custom.js b/app/scripts/views/fields/field-view-custom.js index 3a419b82..da531bdd 100644 --- a/app/scripts/views/fields/field-view-custom.js +++ b/app/scripts/views/fields/field-view-custom.js @@ -96,9 +96,10 @@ class FieldViewCustom extends FieldViewText { fieldLabelClick(e) { e.stopImmediatePropagation(); - if (this.model.newField) { + + if (this.model.titleEditable && this.model.newField) { this.startEditTitle(true); - } else if (this.editing) { + } else if (this.model.titleEditable && this.editing) { this.startEditTitle(); } else { super.fieldLabelClick.call(this, e);