summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2018-11-10 10:06:01 +0100
committerJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2018-11-12 22:38:05 +0100
commit6822a6d6c232ad138ffd866d54b7204938c222a1 (patch)
tree3d78ca6b013a19b3fa9b94ed09e7f5e10f719206
parentfaf4e4adea598aafafd36265922e865d8afe260a (diff)
Cleanup code with Property Mixin
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
-rw-r--r--css/ContactDetails.scss6
-rw-r--r--css/Properties/Properties.scss28
-rw-r--r--css/Settings/SettingsAddressbook.scss2
-rw-r--r--css/icons.scss6
-rw-r--r--img/address-book.svg2
-rw-r--r--img/eye.svg2
-rw-r--r--package.json2
-rw-r--r--src/components/ContactDetails.vue47
-rw-r--r--src/components/ContactDetails/ContactDetailsProperty.vue8
-rw-r--r--src/components/Properties/PropertyDateTime.vue68
-rw-r--r--src/components/Properties/PropertyGroups.vue25
-rw-r--r--src/components/Properties/PropertyMultipleText.vue93
-rw-r--r--src/components/Properties/PropertySelect.vue72
-rw-r--r--src/components/Properties/PropertyText.vue75
-rw-r--r--src/components/Settings/SettingsAddressbookShare.vue2
-rw-r--r--src/mixins/PropertyMixin.js100
-rw-r--r--src/services/api.js127
-rw-r--r--webpack.common.js1
18 files changed, 231 insertions, 435 deletions
diff --git a/css/ContactDetails.scss b/css/ContactDetails.scss
index dc8aaa87..451bb4da 100644
--- a/css/ContactDetails.scss
+++ b/css/ContactDetails.scss
@@ -78,6 +78,12 @@
padding: 14px;
border-radius: 22px;
cursor: pointer;
+ background-size: 16px;
+ opacity: .7;
+ &:hover,
+ &:focus {
+ opacity: 1;
+ }
&.header-icon--pulse {
margin: 8px;
width: 16px;
diff --git a/css/Properties/Properties.scss b/css/Properties/Properties.scss
index 5add862b..817627c8 100644
--- a/css/Properties/Properties.scss
+++ b/css/Properties/Properties.scss
@@ -98,13 +98,21 @@
}
// mouse feedback
- &.multiselect {
- &:hover,
- &:focus,
- &:active {
- opacity: 1;
- .multiselect__tags {
- border-color: var(--color-border-dark);
+ &:hover,
+ &:focus,
+ &:active {
+ opacity: 1;
+ .multiselect__tags {
+ border-color: var(--color-border-dark);
+ }
+ }
+
+ // read-only mode
+ &.multiselect--disabled {
+ &, .multiselect__single {
+ &, &:hover, &:focus &:active {
+ background-color: var(--color-main-background) !important;
+ border-color: transparent !important;
}
}
}
@@ -124,10 +132,16 @@
// property value within row, after label
&__value {
flex: 1 1;
+
textarea& {
align-self: flex-start;
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);
+ }
}
}
diff --git a/css/Settings/SettingsAddressbook.scss b/css/Settings/SettingsAddressbook.scss
index 34d27e9e..e3c98ea0 100644
--- a/css/Settings/SettingsAddressbook.scss
+++ b/css/Settings/SettingsAddressbook.scss
@@ -59,4 +59,4 @@
&--disabled &__name {
opacity: .5;
}
-} \ No newline at end of file
+}
diff --git a/css/icons.scss b/css/icons.scss
index e5b18450..00f390e9 100644
--- a/css/icons.scss
+++ b/css/icons.scss
@@ -26,4 +26,8 @@
.icon-address-book {
@include icon-color('address-book', 'contacts', $color-black, 1);
-} \ No newline at end of file
+}
+
+.icon-eye-white {
+ @include icon-color('eye', 'contacts', $color-white, 1);
+}
diff --git a/img/address-book.svg b/img/address-book.svg
index 6be6e4ab..f026938b 100644
--- a/img/address-book.svg
+++ b/img/address-book.svg
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
-<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1703 478q40 57 18 129l-275 906q-19 64-76.5 107.5t-122.5 43.5h-923q-77 0-148.5-53.5t-99.5-131.5q-24-67-2-127 0-4 3-27t4-37q1-8-3-21.5t-3-19.5q2-11 8-21t16.5-23.5 16.5-23.5q23-38 45-91.5t30-91.5q3-10 .5-30t-.5-28q3-11 17-28t17-23q21-36 42-92t25-90q1-9-2.5-32t.5-28q4-13 22-30.5t22-22.5q19-26 42.5-84.5t27.5-96.5q1-8-3-25.5t-2-26.5q2-8 9-18t18-23 17-21q8-12 16.5-30.5t15-35 16-36 19.5-32 26.5-23.5 36-11.5 47.5 5.5l-1 3q38-9 51-9h761q74 0 114 56t18 130l-274 906q-36 119-71.5 153.5t-128.5 34.5h-869q-27 0-38 15-11 16-1 43 24 70 144 70h923q29 0 56-15.5t35-41.5l300-987q7-22 5-57 38 15 59 43zm-1064 2q-4 13 2 22.5t20 9.5h608q13 0 25.5-9.5t16.5-22.5l21-64q4-13-2-22.5t-20-9.5h-608q-13 0-25.5 9.5t-16.5 22.5zm-83 256q-4 13 2 22.5t20 9.5h608q13 0 25.5-9.5t16.5-22.5l21-64q4-13-2-22.5t-20-9.5h-608q-13 0-25.5 9.5t-16.5 22.5z"/></svg> \ No newline at end of file
+<svg width="16" height="16" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1703 478q40 57 18 129l-275 906q-19 64-76.5 107.5t-122.5 43.5h-923q-77 0-148.5-53.5t-99.5-131.5q-24-67-2-127 0-4 3-27t4-37q1-8-3-21.5t-3-19.5q2-11 8-21t16.5-23.5 16.5-23.5q23-38 45-91.5t30-91.5q3-10 .5-30t-.5-28q3-11 17-28t17-23q21-36 42-92t25-90q1-9-2.5-32t.5-28q4-13 22-30.5t22-22.5q19-26 42.5-84.5t27.5-96.5q1-8-3-25.5t-2-26.5q2-8 9-18t18-23 17-21q8-12 16.5-30.5t15-35 16-36 19.5-32 26.5-23.5 36-11.5 47.5 5.5l-1 3q38-9 51-9h761q74 0 114 56t18 130l-274 906q-36 119-71.5 153.5t-128.5 34.5h-869q-27 0-38 15-11 16-1 43 24 70 144 70h923q29 0 56-15.5t35-41.5l300-987q7-22 5-57 38 15 59 43zm-1064 2q-4 13 2 22.5t20 9.5h608q13 0 25.5-9.5t16.5-22.5l21-64q4-13-2-22.5t-20-9.5h-608q-13 0-25.5 9.5t-16.5 22.5zm-83 256q-4 13 2 22.5t20 9.5h608q13 0 25.5-9.5t16.5-22.5l21-64q4-13-2-22.5t-20-9.5h-608q-13 0-25.5 9.5t-16.5 22.5z"/></svg> \ No newline at end of file
diff --git a/img/eye.svg b/img/eye.svg
new file mode 100644
index 00000000..2aa0dd0a
--- /dev/null
+++ b/img/eye.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="16" height="16" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1664 960q-152-236-381-353 61 104 61 225 0 185-131.5 316.5t-316.5 131.5-316.5-131.5-131.5-316.5q0-121 61-225-229 117-381 353 133 205 333.5 326.5t434.5 121.5 434.5-121.5 333.5-326.5zm-720-384q0-20-14-34t-34-14q-125 0-214.5 89.5t-89.5 214.5q0 20 14 34t34 14 34-14 14-34q0-86 61-147t147-61q20 0 34-14t14-34zm848 384q0 34-20 69-140 230-376.5 368.5t-499.5 138.5-499.5-139-376.5-368q-20-35-20-69t20-69q140-229 376.5-368t499.5-139 499.5 139 376.5 368q20 35 20 69z"/></svg> \ No newline at end of file
diff --git a/package.json b/package.json
index e78025d2..b92c0bd6 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,6 @@
},
"dependencies": {
"@babel/polyfill": "^7.0.0",
- "axios": "^0.18.0",
"cdav-library": "github:nextcloud/cdav-library",
"debounce": "^1.2.0",
"ical.js": "^1.3.0",
@@ -48,7 +47,6 @@
"vue": "^2.5.17",
"vue-click-outside": "^1.0.7",
"vue-clipboard2": "^0.2.1",
- "vue-multiselect": "^2.1.3",
"vue-router": "^3.0.1",
"vuex": "^3.0.1",
"vuex-router-sync": "^5.0.0"
diff --git a/src/components/ContactDetails.vue b/src/components/ContactDetails.vue
index 35c3487b..211fe45d 100644
--- a/src/components/ContactDetails.vue
+++ b/src/components/ContactDetails.vue
@@ -48,17 +48,17 @@
<!-- fullname, org, title -->
<div id="contact-header-infos">
<h2>
- <input id="contact-fullname" v-model="contact.fullName" :disabled="contact.addressbook.readOnly"
+ <input id="contact-fullname" v-model="contact.fullName" :readonly="contact.addressbook.readOnly"
:placeholder="t('contacts', 'Name')" type="text" autocomplete="off"
autocorrect="off" spellcheck="false" name="fullname"
value="" @input="debounceUpdateContact">
</h2>
<div id="details-org-container">
- <input id="contact-org" v-model="contact.org" :disabled="contact.addressbook.readOnly"
+ <input id="contact-org" v-model="contact.org" :readonly="contact.addressbook.readOnly"
:placeholder="t('contacts', 'Company')" type="text" autocomplete="off"
autocorrect="off" spellcheck="false" name="org"
value="" @input="debounceUpdateContact">
- <input id="contact-title" v-model="contact.title" :disabled="contact.addressbook.readOnly"
+ <input id="contact-title" v-model="contact.title" :readonly="contact.addressbook.readOnly"
:placeholder="t('contacts', 'Title')" type="text" autocomplete="off"
autocorrect="off" spellcheck="false" name="title"
value="" @input="debounceUpdateContact">
@@ -67,7 +67,13 @@
<!-- actions -->
<div id="contact-header-actions">
- <div v-tooltip.bottom="warning" :class="{'icon-loading-small': loadingUpdate, 'header-icon--pulse icon-error-white': warning}" class="header-icon" />
+ <a v-tooltip.bottom="{
+ content: warning ? warning.msg : '',
+ trigger: 'hover focus'
+ }"
+ v-if="loadingUpdate || warning"
+ :class="{'icon-loading-small': loadingUpdate,
+ [`${warning.icon}`]: warning}" class="header-icon" href="#" />
<div v-tooltip="{
content: conflict,
show: true,
@@ -95,12 +101,15 @@
:sorted-properties="sortedProperties" :property="property" :contact="contact"
@updatedcontact="updateContact" />
- <!-- addressbook change select - no last property because class is not applied here-->
+ <!-- addressbook change select - no last property because class is not applied here,
+ empty property because this is a required prop on regular property-select. But since
+ we are hijacking this... (this is supposed to be used with a ICAL.property, but to avoid code
+ duplication, we created a fake propModel and property with our own options here) -->
<property-select :prop-model="addressbookModel" :value.sync="addressbook" :is-first-property="true"
- :is-last-property="false" class="property--addressbooks" />
+ :is-last-property="false" :property="{}" class="property--addressbooks" />
<!-- new property select -->
- <add-new-prop :contact="contact" />
+ <add-new-prop v-if="!isReadOnly" :contact="contact" />
</section>
</template>
</div>
@@ -155,27 +164,43 @@ export default {
},
computed: {
+ isReadOnly() {
+ if (this.contact.addressbook) {
+ return this.contact.addressbook.readOnly
+ }
+ return false
+ },
/**
- * Warning message
+ * Warning messages
*
- * @returns {string|undefined}
+ * @returns {Object|Boolean}
*/
warning() {
if (!this.contact.dav) {
- return t('contacts', 'This contact is not yet synced. Edit it to trigger a change.')
+ return {
+ icon: 'icon-error-white header-icon--pulse',
+ msg: t('contacts', 'This contact is not yet synced. Edit it to trigger a change.')
+ }
+ } else if (this.isReadOnly) {
+ return {
+ icon: 'icon-eye-white',
+ msg: t('contacts', 'This contact is in read-only mode. You do not have permission to edit this contact.')
+ }
}
+ return false
},
/**
* Conflict message
*
- * @returns {string|undefined}
+ * @returns {String|Boolean}
*/
conflict() {
if (this.contact.conflict) {
return t('contacts', 'The contact you were trying to edit has changed. Please manually refresh the contact. Any further edits will be discarded.')
}
+ return false
},
/**
diff --git a/src/components/ContactDetails/ContactDetailsProperty.vue b/src/components/ContactDetails/ContactDetailsProperty.vue
index dca5a7d9..4191ef16 100644
--- a/src/components/ContactDetails/ContactDetailsProperty.vue
+++ b/src/components/ContactDetails/ContactDetailsProperty.vue
@@ -26,7 +26,7 @@
:prop-model="propModel" :value.sync="value" :is-first-property="isFirstProperty"
:property="property" :is-last-property="isLastProperty" :class="{'property--last': isLastProperty}"
:contact="contact" :prop-name="propName" :prop-type="propType"
- :options="sortedModelOptions"
+ :options="sortedModelOptions" :is-read-only="isReadOnly"
@delete="deleteProp" />
</template>
@@ -109,6 +109,12 @@ export default {
}
return true
},
+ isReadOnly() {
+ if (this.contact.addressbook) {
+ return this.contact.addressbook.readOnly
+ }
+ return false
+ },
/**
* Return the type of the prop e.g. FN
diff --git a/src/components/Properties/PropertyDateTime.vue b/src/components/Properties/PropertyDateTime.vue
index 4a68f594..13e9038f 100644
--- a/src/components/Properties/PropertyDateTime.vue
+++ b/src/components/Properties/PropertyDateTime.vue
@@ -30,8 +30,8 @@
<!-- type selector -->
<multiselect v-if="propModel.options" v-model="localType"
:options="options" :searchable="false" :placeholder="t('contacts', 'Select type')"
- class="property__label" track-by="id" label="name"
- @input="updateType" />
+ :disabled="isReadOnly" class="property__label" track-by="id"
+ label="name" @input="updateType" />
<!-- if we do not support any type on our model but one is set anyway -->
<div v-else-if="selectType" class="property__label">{{ selectType.name }}</div>
@@ -40,12 +40,13 @@
<div v-else class="property__label">{{ propModel.readableName }}</div>
<!-- delete the prop -->
- <button :title="t('contacts', 'Delete')" class="property__delete icon-delete" @click="deleteProperty" />
+ <button v-if="!isReadOnly" :title="t('contacts', 'Delete')" class="property__delete icon-delete"
+ @click="deleteProperty" />
<!-- Real input where the picker shows -->
<datetime-picker :value="localValue.toJSDate()" :minute-step="10" :lang="lang"
:clearable="false" :first-day-of-week="firstDay" :type="inputType"
- confirm @confirm="updateValue" />
+ :readonly="isReadOnly" confirm @confirm="updateValue" />
</div>
</div>
</template>
@@ -56,6 +57,7 @@ import moment from 'moment'
import { DatetimePicker } from 'nextcloud-vue'
import { VCardTime } from 'ical.js'
+import PropertyMixin from 'Mixins/PropertyMixin'
import PropertyTitle from './PropertyTitle'
/**
@@ -137,45 +139,18 @@ export default {
PropertyTitle
},
+ mixins: [PropertyMixin],
+
props: {
- selectType: {
- type: [Object, Boolean],
- default: () => {}
- },
- propModel: {
- type: Object,
- default: () => {},
- required: true
- },
value: {
type: VCardTime,
default: '',
required: true
- },
- options: {
- type: Array,
- default: () => []
- },
- property: {
- type: Object,
- default: () => {},
- required: true
- },
- isFirstProperty: {
- type: Boolean,
- default: true
- },
- isLastProperty: {
- type: Boolean,
- default: true
}
},
data() {
return {
- localValue: this.value,
- localType: this.selectType,
-
// input type following DatePicker docs
inputType: this.property.getDefaultType() === 'date-time' || this.property.getDefaultType() === 'date-and-or-time'
? 'datetime'
@@ -205,20 +180,6 @@ export default {
}
},
- watch: {
- /**
- * Since we're updating a local data based on the value prop,
- * we need to make sure to update the local data on pop change
- * TODO: check if this create performance drop
- */
- value: function() {
- this.localValue = this.value
- },
- selectType: function() {
- this.localType = this.selectType
- }
- },
-
mounted() {
// Load the locale
// convert format like en_GB to en-gb for `moment.js`
@@ -245,14 +206,6 @@ export default {
},
methods: {
-
- /**
- * Delete the property
- */
- deleteProperty() {
- this.$emit('delete')
- },
-
/**
* Debounce and send update event to parent
*/
@@ -274,11 +227,6 @@ export default {
// https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier
// Use moment to convert the JsDate to Object
this.$emit('update:value', this.localValue)
- }, 500),
-
- updateType: debounce(function(e) {
- // https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier
- this.$emit('update:selectType', this.localType)
}, 500)
}
}
diff --git a/src/components/Properties/PropertyGroups.vue b/src/components/Properties/PropertyGroups.vue
index b4de6185..15677320 100644
--- a/src/components/Properties/PropertyGroups.vue
+++ b/src/components/Properties/PropertyGroups.vue
@@ -29,9 +29,9 @@
<!-- multiselect taggable groups with a limit to 3 groups shown -->
<multiselect v-model="localValue" :options="groups" :placeholder="t('contacts', 'Add contact in group')"
:limit="3" :multiple="true" :taggable="true"
- :close-on-select="false" tag-placeholder="create" class="property__value"
- @input="updateValue" @tag="validateGroup" @select="addContactToGroup"
- @remove="removeContactToGroup">
+ :close-on-select="false" :readonly="isReadOnly" tag-placeholder="create"
+ class="property__value" @input="updateValue" @tag="validateGroup"
+ @select="addContactToGroup" @remove="removeContactToGroup">
<!-- show how many groups are hidden and add tooltip -->
<span v-tooltip.auto="formatGroupsTitle" slot="limit" class="multiselect__limit">+{{ localValue.length - 3 }}</span>
@@ -63,6 +63,11 @@ export default {
type: Contact,
default: null,
required: true
+ },
+ // Is it read-only?
+ isReadOnly: {
+ type: Boolean,
+ default: false
}
},
@@ -88,20 +93,6 @@ export default {
}
},
- watch: {
- /**
- * Since we're updating a local data based on the value prop,
- * we need to make sure to update the local data on pop change
- * TODO: check if this create performance drop
- */
- value: function() {
- this.localValue = this.value
- },
- selectType: function() {
- this.localType = this.selectType
- }
- },
-
methods: {
/**
diff --git a/src/components/Properties/PropertyMultipleText.vue b/src/components/Properties/PropertyMultipleText.vue
index 79386ba2..51a76bc9 100644
--- a/src/components/Properties/PropertyMultipleText.vue
+++ b/src/components/Properties/PropertyMultipleText.vue
@@ -30,8 +30,8 @@
<!-- type selector -->
<multiselect v-if="propModel.options" v-model="localType"
:options="options" :searchable="false" :placeholder="t('contacts', 'Select type')"
- class="property__label" track-by="id" label="name"
- @input="updateType" />
+ :disabled="isReadOnly" class="property__label" track-by="id"
+ label="name" @input="updateType" />
<!-- if we do not support any type on our model but one is set anyway -->
<div v-else-if="selectType" class="property__label">{{ selectType.name }}</div>
@@ -40,19 +40,20 @@
<div v-else class="property__label">{{ propModel.readableName }}</div>
<!-- show the first input if not -->
- <input v-if="!property.isStructuredValue" v-model.trim="localValue[0]" class="property__value"
- type="text" @input="updateValue">
+ <input v-if="!property.isStructuredValue" v-model.trim="localValue[0]" :readonly="isReadOnly"
+ class="property__value" type="text" @input="updateValue">
<!-- delete the prop -->
- <button :title="t('contacts', 'Delete')" class="property__delete icon-delete" @click="deleteProperty" />
+ <button v-if="!isReadOnly" :title="t('contacts', 'Delete')" class="property__delete icon-delete"
+ @click="deleteProperty" />
</div>
<!-- force order based on model -->
<template v-if="propModel.displayOrder && propModel.readableValues">
<div v-for="index in propModel.displayOrder" :key="index" class="property__row">
<div class="property__label">{{ propModel.readableValues[index] }}</div>
- <input v-model.trim="localValue[index]" class="property__value" type="text"
- @input="updateValue">
+ <input v-model.trim="localValue[index]" :readonly="isReadOnly" class="property__value"
+ type="text" @input="updateValue">
</div>
</template>
@@ -61,16 +62,16 @@
<div v-for="(value, index) in localValue" v-if="index > 0" :key="index"
class="property__row">
<div class="property__label" />
- <input v-model.trim="localValue[index]" class="property__value" type="text"
- @input="updateValue">
+ <input v-model.trim="localValue[index]" :readonly="isReadOnly" class="property__value"
+ type="text" @input="updateValue">
</div>
</template>
</div>
</template>
<script>
+import PropertyMixin from 'Mixins/PropertyMixin'
import PropertyTitle from './PropertyTitle'
-import debounce from 'debounce'
export default {
name: 'PropertyText',
@@ -79,44 +80,13 @@ export default {
PropertyTitle
},
+ mixins: [PropertyMixin],
+
props: {
- selectType: {
- type: [Object, Boolean],
- default: () => {}
- },
- propModel: {
- type: Object,
- default: () => {},
- required: true
- },
value: {
type: [Array, Object],
default: () => [],
required: true
- },
- options: {
- type: Array,
- default: () => []
- },
- property: {
- type: Object,
- default: () => {},
- required: true
- },
- isFirstProperty: {
- type: Boolean,
- default: true
- },
- isLastProperty: {
- type: Boolean,
- default: true
- }
- },
-
- data() {
- return {
- localValue: this.value,
- localType: this.selectType
}
},
@@ -128,43 +98,6 @@ export default {
let length = this.propModel.displayOrder ? this.propModel.displayOrder.length : this.value.length
return hasValueNames + hasTitle + length + isLast
}
- },
-
- watch: {
- /**
- * Since we're updating a local data based on the value prop,
- * we need to make sure to update the local data on pop change
- * TODO: check if this create performance drop
- */
- value: function() {
- this.localValue = this.value
- },
- selectType: function() {
- this.localType = this.selectType
- }
- },
-
- methods: {
-
- /**
- * Delete the property
- */
- deleteProperty() {
- this.$emit('delete')
- },
-
- /**
- * Debounce and send update event to parent
- */
- updateValue: debounce(function(e) {
- // https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier
- this.$emit('update:value', this.localValue)
- }, 500),
-
- updateType: debounce(function(e) {
- // https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier
- this.$emit('update:selectType', this.localType)
- }, 500)
}
}
diff --git a/src/components/Properties/PropertySelect.vue b/src/components/Properties/PropertySelect.vue
index 92508124..5c2b4d4b 100644
--- a/src/components/Properties/PropertySelect.vue
+++ b/src/components/Properties/PropertySelect.vue
@@ -35,18 +35,19 @@
<div v-else class="property__label">{{ propModel.readableName }}</div>
<!-- delete the prop -->
- <button :title="t('contacts', 'Delete')" class="property__delete icon-delete" @click="deleteProperty" />
+ <button v-if="!isReadOnly" :title="t('contacts', 'Delete')" class="property__delete icon-delete"
+ @click="deleteProperty" />
<multiselect v-model="matchedOptions" :options="propModel.options" :placeholder="t('contacts', 'Select option')"
- :disabled="isSingleOption" class="multiselect-vue property__value" track-by="id"
+ :disabled="isSingleOption || isReadOnly" class="multiselect-vue property__value" track-by="id"
label="name" @input="updateValue" />
</div>
</div>
</template>
<script>
+import PropertyMixin from 'Mixins/PropertyMixin'
import PropertyTitle from './PropertyTitle'
-import debounce from 'debounce'
export default {
name: 'PropertySelect',
@@ -55,36 +56,13 @@ export default {
PropertyTitle
},
+ mixins: [PropertyMixin],
+
props: {
- selectType: {
- type: [Object, Boolean],
- default: () => {}
- },
- propModel: {
- type: Object,
- default: () => {},
- required: true
- },
value: {
type: [Object, String],
default: '',
required: true
- },
- isFirstProperty: {
- type: Boolean,
- default: true
- },
- isLastProperty: {
- type: Boolean,
- default: true
- }
- },
-
- data() {
- return {
- // value is represented by the ID of the possible options
- localValue: this.value
- // localType: this.selectType
}
},
@@ -113,44 +91,6 @@ export default {
this.localValue = value.id
}
}
-
- },
-
- watch: {
- /**
- * Since we're updating a local data based on the value prop,
- * we need to make sure to update the local data on pop change
- * TODO: check if this create performance drop
- */
- value: function() {
- this.localValue = this.value
- }
- // selectType: function() {
- // this.localType = this.selectType
- // }
- },
-
- methods: {
-
- /**
- * Delete the property
- */
- deleteProperty() {
- this.$emit('delete')
- },
-
- /**
- * Debounce and send update event to parent
- */
- updateValue: debounce(function(e) {
- // https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier
- this.$emit('update:value', this.localValue)
- }, 500)
-
- // updateType: debounce(function(e) {
- // // https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier
- // this.$emit('update:selectType', this.localType)
- // }, 500)
}
}
diff --git a/src/components/Properties/PropertyText.vue b/src/components/Properties/PropertyText.vue
index b67514f0..7c9fd99e 100644
--- a/src/components/Properties/PropertyText.vue
+++ b/src/components/Properties/PropertyText.vue
@@ -30,8 +30,8 @@
<!-- type selector -->
<multiselect v-if="propModel.options" v-model="localType"
:options="options" :searchable="false" :placeholder="t('contacts', 'Select type')"
- class="property__label" track-by="id" label="name"
- @input="updateType" />
+ :disabled="isReadOnly" class="property__label" track-by="id"
+ label="name" @input="updateType" />
<!-- if we do not support any type on our model but one is set anyway -->
<div v-else-if="selectType" class="property__label">{{ selectType.name }}</div>