summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--css/ContactDetailsLayout.scss6
-rw-r--r--css/Properties/Properties.scss103
-rw-r--r--css/contacts.scss8
-rw-r--r--package-lock.json49
-rw-r--r--package.json1
-rw-r--r--src/components/ContactDetails.vue165
-rw-r--r--src/components/ContactDetails/ContactDetailsAddNewProp.vue5
-rw-r--r--src/components/ContactDetails/ContactDetailsAvatar.vue11
-rw-r--r--src/components/ContactDetails/ContactDetailsProperty.vue38
-rw-r--r--src/components/DetailsHeader.vue68
-rw-r--r--src/components/Properties/PropertyActions.vue3
-rw-r--r--src/components/Properties/PropertyDateTime.vue85
-rw-r--r--src/components/Properties/PropertyGroups.vue68
-rw-r--r--src/components/Properties/PropertyMultipleText.vue125
-rw-r--r--src/components/Properties/PropertyRev.vue23
-rw-r--r--src/components/Properties/PropertySelect.vue47
-rw-r--r--src/components/Properties/PropertyText.vue131
-rw-r--r--src/components/Properties/PropertyTitle.vue12
-rw-r--r--src/components/Properties/PropertyTitleIcon.vue6
-rw-r--r--src/mixins/PropertyMixin.js3
20 files changed, 501 insertions, 456 deletions
diff --git a/css/ContactDetailsLayout.scss b/css/ContactDetailsLayout.scss
index a4c0236b..5fbb45c1 100644
--- a/css/ContactDetailsLayout.scss
+++ b/css/ContactDetailsLayout.scss
@@ -20,12 +20,6 @@
*
*/
-$contact-details-label-min-width: 100px;
$contact-details-label-max-width: 200px;
-$contact-details-label-width: calc(($contact-details-label-min-width + $contact-details-label-max-width) / 2);
-
-$contact-details-value-min-width: 200px;
$contact-details-value-max-width: 300px;
-$contact-details-value-width: calc(($contact-details-value-min-width + $contact-details-value-max-width) / 2);
-
$contact-details-row-gap: 15px;
diff --git a/css/Properties/Properties.scss b/css/Properties/Properties.scss
index 58cea711..9bd8e99a 100644
--- a/css/Properties/Properties.scss
+++ b/css/Properties/Properties.scss
@@ -23,13 +23,8 @@
@import '../ContactDetailsLayout.scss';
-$property-label-min-width: $contact-details-label-min-width;
$property-label-max-width: $contact-details-label-max-width;
-$property-label-width: $contact-details-label-width;
-
-$property-value-min-width: $contact-details-value-min-width;
$property-value-max-width: $contact-details-value-max-width;
-$property-value-width: $contact-details-value-width;
$property-ext-padding-right: 8px;
$property-row-gap: $contact-details-row-gap;
@@ -42,13 +37,6 @@ $property-row-gap: $contact-details-row-gap;
display: flex;
align-items: center;
gap: $property-row-gap;
-
- .property__actions {
- // placeholder for the actions menu
- &__empty {
- width: 44px;
- }
- }
}
// property row
@@ -57,12 +45,6 @@ $property-row-gap: $contact-details-row-gap;
align-items: center;
gap: $property-row-gap;
- &--without-actions {
- .property__value {
- margin-right: $property-row-gap + 44px; // actions menu / button
- }
- }
-
// fix default margin from server stylesheet causing slight misalignment
input {
margin-right: 0;
@@ -71,88 +53,89 @@ $property-row-gap: $contact-details-row-gap;
// property label or multiselect within row
&__label {
+ // Global single column layout
display: flex;
- justify-content: end;
- flex: 1 auto;
-
- width: $property-label-width !important;
- min-width: $property-label-min-width !important;
- max-width: $property-label-max-width !important;
+ flex: 0 1 auto;
+ justify-content: flex-end;
+ width: $contact-details-label-max-width;
+ min-width: 0; // Has to be zero unless we implement wrapping
- &:not(.multiselect) {
+ // Text label styling
+ > :not(.multiselect):not(.material-design-icon) {
overflow: hidden;
- overflow-x: hidden;
white-space: nowrap;
text-overflow: ellipsis;
opacity: .7;
}
}
- // Hide delete buttons initially
- .action-item.icon-delete {
- opacity: 0;
- }
-
// Property value within row, after label
&__value {
- flex: 1 auto;
+ align-items: center;
- width: $property-value-width !important;
- //min-width: $property-value-min-width !important;
- min-width: unset !important;
- max-width: $property-value-max-width !important;
+ // Global single column layout
+ display: flex;
+ flex: 0 1 auto;
+ width: $property-value-max-width;
+ min-width: 0; // Has to be zero unless we implement wrapping
textarea {
- align-self: flex-start;
+ // Limit max height to make scrolling the form a bit easier
min-height: 2 * $grid-height-unit - 2*$grid-input-margin;
max-height: 5 * $grid-height-unit - 2*$grid-input-margin;
}
- // read-only mode
- &:read-only {
- border-color: var(--color-border-dark);
+ input,
+ textarea {
+ width: 100%;
+
+ // Remove default input styling for read-only inputs.
+ // We can't use plain divs because that would cause jumping on switching modes.
+ &[readonly] {
+ border: none;
+ overflow: auto;
+ outline: none;
+ resize: none;
+ padding: 0;
+ border-radius: 0;
+ }
}
- &--with-ext {
- // ext icon width + 8px padding
- padding-right: 24px;
+ }
+
+ &__label,
+ &__value {
+ // Fix default multiselect styling
+ > .multiselect {
+ width: 100%;
+ min-width: unset;
}
- // Show ext icon permanently on focus
- &:hover,
- &:focus,
- &:active {
- ~ .property__ext {
- opacity: .5;
- }
+ // Fix default date time picker styling
+ > .mx-datepicker {
+ width: 100%;
}
}
// Show ext buttons on full row hover
&:hover {
.property__ext {
- opacity: .5;
+ opacity: .7;
}
}
// External link (tel, mailto, http, ftp...)
&__ext {
- position: absolute;
- // 8px padding + actions
- right: 44px + $property-ext-padding-right;
opacity: 0;
+
&:hover,
- &:focus,
- &:active {
+ &:focus {
opacity: .7;
}
}
- .no-move {
- right: $property-ext-padding-right;
- }
-
// Delete property button + actions
&__actions {
z-index: 10;
+ width: 44px;
}
}
diff --git a/css/contacts.scss b/css/contacts.scss
index 60e0513f..116d943a 100644
--- a/css/contacts.scss
+++ b/css/contacts.scss
@@ -38,17 +38,19 @@ $grid-input-height-with-margin: $grid-height-unit - $grid-input-margin * 2;
// various
@import 'animations';
-
-
.app-content-details {
padding: calc(var(--default-grid-baseline) * 2);
padding-top: 0;
height: 100%;
overflow: auto;
+
+ // Compensate top padding reserved for the back button on mobile
+ @media (max-width: 1024px) {
+ height: calc(100% - 44px);
+ }
}
.app-content-list {
// Cancel scrolling
overflow: visible;
-
}
diff --git a/package-lock.json b/package-lock.json
index dd32914b..7437f8db 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -33,7 +33,6 @@
"ical.js": "^1.5.0",
"moment": "^2.29.4",
"p-limit": "^4.0.0",
- "p-queue": "^7.3.4",
"qr-image": "^3.2.0",
"string-natural-compare": "^3.0.1",
"uuid": "^9.0.0",
@@ -8268,7 +8267,9 @@
},
"node_modules/eventemitter3": {
"version": "4.0.7",
- "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true,
+ "peer": true
},
"node_modules/events": {
"version": "3.3.0",
@@ -13386,21 +13387,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-queue": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-7.3.4.tgz",
- "integrity": "sha512-esox8CWt0j9EZECFvkFl2WNPat8LN4t7WWeXq73D9ha0V96qPRufApZi4ZhPwXAln1uVVal429HVVKPa2X0yQg==",
- "dependencies": {
- "eventemitter3": "^4.0.7",
- "p-timeout": "^5.0.2"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/p-retry": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
@@ -13415,17 +13401,6 @@
"node": ">=8"
}
},
- "node_modules/p-timeout": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz",
- "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/p-try": {
"version": "2.2.0",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
@@ -23937,7 +23912,9 @@
},
"eventemitter3": {
"version": "4.0.7",
- "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true,
+ "peer": true
},
"events": {
"version": "3.3.0",
@@ -27631,15 +27608,6 @@
}
}
},
- "p-queue": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-7.3.4.tgz",
- "integrity": "sha512-esox8CWt0j9EZECFvkFl2WNPat8LN4t7WWeXq73D9ha0V96qPRufApZi4ZhPwXAln1uVVal429HVVKPa2X0yQg==",
- "requires": {
- "eventemitter3": "^4.0.7",
- "p-timeout": "^5.0.2"
- }
- },
"p-retry": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
@@ -27651,11 +27619,6 @@
"retry": "^0.13.1"
}
},
- "p-timeout": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz",
- "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew=="
- },
"p-try": {
"version": "2.2.0",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
diff --git a/package.json b/package.json
index 1e153fec..9633dce0 100644
--- a/package.json
+++ b/package.json
@@ -60,7 +60,6 @@
"ical.js": "^1.5.0",
"moment": "^2.29.4",
"p-limit": "^4.0.0",
- "p-queue": "^7.3.4",
"qr-image": "^3.2.0",
"string-natural-compare": "^3.0.1",
"uuid": "^9.0.0",
diff --git a/src/components/ContactDetails.vue b/src/components/ContactDetails.vue
index ad38b55b..5ccfcad1 100644
--- a/src/components/ContactDetails.vue
+++ b/src/components/ContactDetails.vue
@@ -32,12 +32,15 @@
</template>
</EmptyContent>
+ <!-- TODO: add empty content while this.loadingData === true -->
+
<template v-else>
<!-- contact header -->
<DetailsHeader>
<!-- avatar and upload photo -->
<ContactAvatar slot="avatar"
:contact="contact"
+ :is-read-only="isReadOnly"
@update-local-contact="updateLocalContact" />
<!-- fullname -->
@@ -55,7 +58,6 @@
autocorrect="off"
spellcheck="false"
name="fullname"
- @input="debounceUpdateContact"
@click="selectInput">
</template>
@@ -72,8 +74,7 @@
autocomplete="off"
autocorrect="off"
spellcheck="false"
- name="title"
- @input="debounceUpdateContact">
+ name="title">
<input id="contact-org"
v-model="contact.org"
:placeholder="t('contacts', 'Company')"
@@ -81,23 +82,21 @@
autocomplete="off"
autocorrect="off"
spellcheck="false"
- name="org"
- @input="debounceUpdateContact">
+ name="org">
</template>
</template>
<!-- actions -->
<template #actions>
<!-- warning message -->
- <a v-if="loadingUpdate || warning"
+ <component v-if="warning"
v-tooltip.bottom="{
content: warning ? warning.msg : '',
trigger: 'hover focus'
}"
- :class="{'icon-loading-small': loadingUpdate,
- [`${warning.icon}`]: warning}"
+ :is="warning.icon"
class="header-icon"
- @click="onWarningClick" />
+ :classes="warning.classes" />
<!-- conflict message -->
<div v-if="conflict"
@@ -118,6 +117,28 @@
}"
class="header-icon header-icon--pulse icon-up"
@click="updateContact" />
+
+ <!-- edit and save buttons -->
+ <template v-if="!addressbookIsReadOnly">
+ <NcButton v-if="!editMode"
+ type="tertiary"
+ @click="editMode = true">
+ <template #icon>
+ <PencilIcon :size="20" />
+ </template>
+ {{ t('contacts', 'Edit') }}
+ </NcButton>
+ <NcButton v-else
+ type="primary"
+ :disabled="loadingUpdate"
+ @click="onSave">
+ <template #icon>
+ <IconLoading v-if="loadingUpdate" :size="20" />
+ <CheckIcon v-else :size="20" />
+ </template>
+ {{ t('contacts', 'Save') }}
+ </NcButton>
+ </template>
</template>
<!-- menu actions -->
@@ -153,7 +174,8 @@
</template>
{{ excludeFromBirthdayLabel }}
</ActionButton>
- <ActionButton v-if="!isReadOnly" @click="deleteContact">
+ <ActionButton v-if="!addressbookIsReadOnly"
+ @click="deleteContact">
<template #icon>
<IconDelete :size="20" />
</template>
@@ -203,8 +225,6 @@
<section v-else class="contact-details">
<!-- properties iteration -->
<!-- using contact.key in the key and index as key to avoid conflicts between similar data and exact key -->
- <!-- passing the debounceUpdateContact so that the contact-property component contains the function
- and allow us to use it on the rfcProps since the scope is forwarded to the actions -->
<div v-for="(properties, name) in groupedProperties"
:key="name">
<ContactDetailsProperty v-for="(property, index) in properties"
@@ -214,9 +234,9 @@
:property="property"
:contact="contact"
:local-contact="localContact"
- :update-contact="debounceUpdateContact"
:contacts="contacts"
- :bus="bus" />
+ :bus="bus"
+ :is-read-only="isReadOnly" />
</div>
<!-- addressbook change select - no last property because class is not applied here,
@@ -235,7 +255,7 @@
<!-- Groups always visible -->
<PropertyGroups :prop-model="groupsModel"
- :value.sync="groups"
+ :value.sync="localContact.groups"
:contact="contact"
:is-read-only="isReadOnly"
class="property--groups property--last" />
@@ -255,9 +275,6 @@
<script>
import { showError } from '@nextcloud/dialogs'
import { stringify } from 'ical.js'
-import debounce from 'debounce'
-// eslint-disable-next-line import/no-unresolved, n/no-missing-import
-import PQueue from 'p-queue'
import qr from 'qr-image'
import Vue from 'vue'
@@ -269,11 +286,16 @@ import IconContact from 'vue-material-design-icons/AccountMultiple.vue'
import Modal from '@nextcloud/vue/dist/Components/NcModal.js'
import Multiselect from '@nextcloud/vue/dist/Components/NcMultiselect.js'
import IconLoading from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
+import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import IconDownload from 'vue-material-design-icons/Download.vue'
import IconDelete from 'vue-material-design-icons/Delete.vue'
import IconQr from 'vue-material-design-icons/Qrcode.vue'
import CakeIcon from 'vue-material-design-icons/Cake.vue'
import IconCopy from 'vue-material-design-icons/ContentCopy.vue'
+import PencilIcon from 'vue-material-design-icons/Pencil.vue'
+import CheckIcon from 'vue-material-design-icons/Check.vue'
+import AlertCircleIcon from 'vue-material-design-icons/AlertCircle.vue'
+import EyeCircleIcon from 'vue-material-design-icons/EyeCircle.vue'
import rfcProps from '../models/rfcProps.js'
import validate from '../services/validate.js'
@@ -286,8 +308,6 @@ import PropertyGroups from './Properties/PropertyGroups.vue'
import PropertyRev from './Properties/PropertyRev.vue'
import PropertySelect from './Properties/PropertySelect.vue'
-const updateQueue = new PQueue({ concurrency: 1 })
-
export default {
name: 'ContactDetails',
@@ -307,11 +327,14 @@ export default {
CakeIcon,
IconCopy,
IconLoading,
+ PencilIcon,
+ CheckIcon,
Modal,
Multiselect,
PropertyGroups,
PropertyRev,
PropertySelect,
+ NcButton,
},
props: {
@@ -338,10 +361,10 @@ export default {
localContact: undefined,
loadingData: true,
loadingUpdate: false,
- openedMenu: false,
qrcode: '',
showPickAddressbookModal: false,
pickedAddressbook: null,
+ editMode: false,
contactDetailsSelector: '.contact-details',
excludeFromBirthdayKey: 'x-nc-exclude-from-birthday-calendar',
@@ -352,11 +375,22 @@ export default {
},
computed: {
+ /**
+ * The address book is read-only (e.g. shared with me).
+ *
+ * @return {boolean}
+ */
+ addressbookIsReadOnly() {
+ return this.contact.addressbook?.readOnly
+ },
+
+ /**
+ * The address book is read-only or the contact is in read-only mode.
+ *
+ * @return {boolean}
+ */
isReadOnly() {
- if (this.contact.addressbook) {
- return this.contact.addressbook.readOnly
- }
- return false
+ return this.addressbookIsReadOnly || !this.editMode
},
/**
@@ -367,12 +401,14 @@ export default {
warning() {
if (!this.contact.dav) {
return {
- icon: 'icon-error header-icon--pulse',
+ icon: AlertCircleIcon,
+ classes: ['header-icon--pulse'],
msg: t('contacts', 'This contact is not yet synced. Edit it to save it to the server.'),
}
- } else if (this.isReadOnly) {
+ } else if (this.addressbookIsReadOnly) {
return {
- icon: 'icon-eye',
+ icon: EyeCircleIcon,
+ classes: [],
msg: t('contacts', 'This contact is in read-only mode. You do not have permission to edit this contact.'),
}
}
@@ -473,22 +509,6 @@ export default {
},
/**
- * Usable groups object linked to the local contact
- *
- * @param {string[]} data An array of groups
- * @return {Array}
- */
- groups: {
- get() {
- return this.contact.groups
- },
- set(data) {
- this.contact.groups = data
- this.debounceUpdateContact()
- },
- },
-
- /**
* Store getters filtered and mapped to usable object
* This is the list of addressbooks that are available
*
@@ -579,8 +599,11 @@ export default {
async updateContact() {
this.fixed = false
this.loadingUpdate = true
- await this.$store.dispatch('updateContact', this.localContact)
- this.loadingUpdate = false
+ try {
+ await this.$store.dispatch('updateContact', this.localContact)
+ } finally {
+ this.loadingUpdate = false
+ }
// if we just created the contact, we need to force update the
// localContact to match the proper store contact
@@ -593,14 +616,6 @@ export default {
},
/**
- * Debounce the contact update for the header props
- * photo, fn, org, title
- */
- debounceUpdateContact: debounce(function(e) {
- updateQueue.add(this.updateContact)
- }, 500),
-
- /**
* Generate a qrcode for the contact
*/
showQRcode() {
@@ -642,6 +657,7 @@ export default {
*/
async selectContact(key) {
this.loadingData = true
+ this.editMode = false
// local version of the contact
const contact = this.$store.getters.getContact(key)
@@ -668,6 +684,9 @@ export default {
} else {
// clone to a local editable variable
await this.updateLocalContact(contact)
+
+ // enable edit mode by default when creating a new contact
+ this.editMode = true
}
}
@@ -780,9 +799,13 @@ export default {
},
onCtrlSave(e) {
+ if (!this.editMode) {
+ return
+ }
+
if (e.keyCode === 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
e.preventDefault()
- this.debounceUpdateContact()
+ this.onSave()
}
},
@@ -809,20 +832,6 @@ export default {
},
/**
- * The user clicked the warning icon
- */
- onWarningClick() {
- // if the user clicked the readonly icon, let's focus the clone button
- if (this.isReadOnly && this.addressbooksOptions.length > 0) {
- this.openedMenu = true
- this.$nextTick(() => {
- // focus the clone button
- this.$refs.actions.onMouseFocusAction({ target: this.$refs.cloneAction.$el })
- })
- }
- },
-
- /**
* Should display the property
*
* @param {Property} property the property to check
@@ -838,6 +847,14 @@ export default {
return propModel && propType !== 'unknown'
},
+
+ /**
+ * Save the contact. This handler is triggered by the save button.
+ */
+ async onSave() {
+ await this.updateContact()
+ this.editMode = false
+ }
},
}
</script>
@@ -848,16 +865,6 @@ section.contact-details {
display: flex;
flex-direction: column;
gap: 40px;
-
- .property--rev {
- position: absolute;
- left: 125px;
- bottom: -25px;
- height: 44px;
- opacity: .5;
- color: var(--color-text-lighter);
- line-height: 44px;
- }
}
#qrcode-modal {
diff --git a/src/components/ContactDetails/ContactDetailsAddNewProp.vue b/src/components/ContactDetails/ContactDetailsAddNewProp.vue
index 8ff2df2d..e49c16df 100644
--- a/src/components/ContactDetails/ContactDetailsAddNewProp.vue
+++ b/src/components/ContactDetails/ContactDetailsAddNewProp.vue
@@ -22,7 +22,7 @@
-->
<template>
- <div class="property__row property__row--without-actions">
+ <div class="property__row">
<!-- Dummy label to keep the layout -->
<div class="property__label" />
@@ -78,6 +78,9 @@
</template>
</Actions>
</div>
+
+ <!-- Dummy actions to keep the layout -->
+ <div class="property__actions" />
</div>
</template>
diff --git a/src/components/ContactDetails/ContactDetailsAvatar.vue b/src/components/ContactDetails/ContactDetailsAvatar.vue
index dc7de849..de5746ba 100644
--- a/src/components/ContactDetails/ContactDetailsAvatar.vue
+++ b/src/components/ContactDetails/ContactDetailsAvatar.vue
@@ -4,6 +4,7 @@
- @author Team Popcorn <teampopcornberlin@gmail.com>
- @author John Molakvoæ <skjnldsv@protonmail.com>
- @author Matthias Heinisch <nextcloud@matthiasheinisch.de>
+ - @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@@ -159,6 +160,10 @@ export default {
type: Object,
required: true,
},
+ isReadOnly: {
+ type: Boolean,
+ required: true,
+ },
},
data() {
@@ -183,12 +188,6 @@ export default {
},
computed: {
- isReadOnly() {
- if (this.contact.addressbook) {
- return this.contact.addressbook.readOnly
- }
- return false
- },
supportedSocial() {
const emails = this.contact.vCard.getAllProperties('email')
// get social networks set for the current contact
diff --git a/src/components/ContactDetails/ContactDetailsProperty.vue b/src/components/ContactDetails/ContactDetailsProperty.vue
index e9282ddf..eed4c291 100644
--- a/src/components/ContactDetails/ContactDetailsProperty.vue
+++ b/src/components/ContactDetails/ContactDetailsProperty.vue
@@ -2,6 +2,7 @@
- @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
-
- @author John Molakvoæ <skjnldsv@protonmail.com>
+ - @author Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@@ -41,9 +42,7 @@
:is-read-only="isReadOnly"
:bus="bus"
:is-multiple="isMultiple"
- @delete="onDelete"
- @resize="onResize"
- @update="updateContact" />
+ @delete="onDelete" />
</template>
<script>
@@ -93,14 +92,6 @@ export default {
type: Contact,
default: null,
},
- /**
- * This is needed so that we can update
- * the contact within the rfcProps actions
- */
- updateContact: {
- type: Function,
- default: () => {},
- },
contacts: {
type: Array,
default: () => [],
@@ -109,6 +100,10 @@ export default {
type: Object,
required: true,
},
+ isReadOnly: {
+ type: Boolean,
+ required: true,
+ }
},
computed: {
@@ -140,12 +135,6 @@ export default {
isMultiple() {
return this.properties[this.property.name].multiple
},
- isReadOnly() {
- if (this.contact.addressbook) {
- return this.contact.addressbook.readOnly
- }
- return false
- },
/**
* Return the type of the prop e.g. FN
@@ -293,6 +282,11 @@ export default {
return null
},
set(data) {
+ // Skip setting type if select is cleared
+ if (!data) {
+ return
+ }
+
// if a custom label exists and this is the one we selected
if (this.propLabel && data.id === this.propLabel.name) {
this.propLabel.setValue(data.name)
@@ -315,7 +309,6 @@ export default {