diff options
author | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2019-01-30 11:16:29 +0100 |
---|---|---|
committer | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2019-01-30 12:17:23 +0100 |
commit | a1561dfe3a728f3b636852df05d36c1947883dd7 (patch) | |
tree | 91e90dae3ec08878ae81a2f68a90fba4050ebfc2 /src | |
parent | 7af5d37ac8428784843fd3cca531fb30ecf71fe3 (diff) |
Add property-defined actions
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/components/ContactDetails.vue | 4 | ||||
-rw-r--r-- | src/components/ContactDetails/ContactDetailsProperty.vue | 12 | ||||
-rw-r--r-- | src/components/Properties/PropertyDateTime.vue | 5 | ||||
-rw-r--r-- | src/components/Properties/PropertyMultipleText.vue | 5 | ||||
-rw-r--r-- | src/components/Properties/PropertySelect.vue | 5 | ||||
-rw-r--r-- | src/components/Properties/PropertyText.vue | 11 | ||||
-rw-r--r-- | src/main.js | 3 | ||||
-rw-r--r-- | src/mixins/PropertyMixin.js | 11 | ||||
-rw-r--r-- | src/models/rfcProps.js | 23 | ||||
-rw-r--r-- | src/services/checks/missingFN.js | 4 | ||||
-rw-r--r-- | src/store/contacts.js | 4 |
11 files changed, 63 insertions, 24 deletions
diff --git a/src/components/ContactDetails.vue b/src/components/ContactDetails.vue index ab55c221..1bc9b3cf 100644 --- a/src/components/ContactDetails.vue +++ b/src/components/ContactDetails.vue @@ -95,9 +95,11 @@ <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 --> <contact-property v-for="(property, index) in sortedProperties" :key="`${index}-${contact.key}-${property.name}`" :index="index" :sorted-properties="sortedProperties" :property="property" :contact="contact" - @updatedcontact="debounceUpdateContact" /> + :update-contact="debounceUpdateContact" @updatedcontact="debounceUpdateContact" /> <!-- 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 diff --git a/src/components/ContactDetails/ContactDetailsProperty.vue b/src/components/ContactDetails/ContactDetailsProperty.vue index f6bab167..35db5032 100644 --- a/src/components/ContactDetails/ContactDetailsProperty.vue +++ b/src/components/ContactDetails/ContactDetailsProperty.vue @@ -61,6 +61,14 @@ export default { contact: { type: Contact, default: null + }, + /** + * This is needed so that we can update + * the contact within the rfcProps actions + */ + updateContact: { + type: Function, + default: () => {} } }, @@ -139,7 +147,9 @@ export default { * @returns {Object} */ propModel() { - return this.properties[this.propName] + // passing this to properties to allow us to scope the properties object + // this make possible defining actions there + return this.properties(this)[this.propName] }, /** diff --git a/src/components/Properties/PropertyDateTime.vue b/src/components/Properties/PropertyDateTime.vue index 96c72f58..ff2df7e8 100644 --- a/src/components/Properties/PropertyDateTime.vue +++ b/src/components/Properties/PropertyDateTime.vue @@ -43,9 +43,8 @@ {{ propModel.readableName }} </div> - <!-- delete the prop --> - <button v-if="!isReadOnly" :title="t('contacts', 'Delete')" class="property__delete icon-delete" - @click="deleteProperty" /> + <!-- props actions --> + <action :actions="actions" class="property__actions" /> <!-- Real input where the picker shows --> <datetime-picker :value="localValue.toJSDate()" :minute-step="10" :lang="lang" diff --git a/src/components/Properties/PropertyMultipleText.vue b/src/components/Properties/PropertyMultipleText.vue index b2220e03..1408e3ff 100644 --- a/src/components/Properties/PropertyMultipleText.vue +++ b/src/components/Properties/PropertyMultipleText.vue @@ -47,9 +47,8 @@ <input v-if="!property.isStructuredValue" v-model.trim="localValue[0]" :readonly="isReadOnly" class="property__value" type="text" @input="updateValue"> - <!-- delete the prop --> - <button v-if="!isReadOnly" :title="t('contacts', 'Delete')" class="property__delete icon-delete" - @click="deleteProperty" /> + <!-- props actions --> + <action :actions="actions" class="property__actions" /> </div> <!-- force order based on model --> diff --git a/src/components/Properties/PropertySelect.vue b/src/components/Properties/PropertySelect.vue index 51ccd032..69593f8c 100644 --- a/src/components/Properties/PropertySelect.vue +++ b/src/components/Properties/PropertySelect.vue @@ -37,9 +37,8 @@ {{ propModel.readableName }} </div> - <!-- delete the prop --> - <button v-if="!isReadOnly" :title="t('contacts', 'Delete')" class="property__delete icon-delete" - @click="deleteProperty" /> + <!-- props actions --> + <action :actions="actions" class="property__actions" /> <multiselect v-model="matchedOptions" :options="propModel.options" :placeholder="t('contacts', 'Select option')" :disabled="isSingleOption || isReadOnly" class="property__value" track-by="id" diff --git a/src/components/Properties/PropertyText.vue b/src/components/Properties/PropertyText.vue index b61df21d..447775ab 100644 --- a/src/components/Properties/PropertyText.vue +++ b/src/components/Properties/PropertyText.vue @@ -58,9 +58,8 @@ <a v-if="haveExtHandler" :href="externalHandler" class="property__ext icon-external" target="_blank" /> - <!-- delete the prop --> - <button v-if="!isReadOnly" :title="t('contacts', 'Delete')" class="property__delete icon-delete" - @click="deleteProperty" /> + <!-- props actions --> + <action :actions="actions" class="property__actions" /> </div> </div> </template> @@ -157,12 +156,6 @@ export default { }, methods: { - /** - * Delete the property - */ - deleteProperty() { - this.$emit('delete') - }, /** * Watch textarea resize and update the gridSize accordingly diff --git a/src/main.js b/src/main.js index 1cbb209c..e0264e5f 100644 --- a/src/main.js +++ b/src/main.js @@ -27,7 +27,7 @@ import { sync } from 'vuex-router-sync' import { generateFilePath } from 'nextcloud-server/dist/router' /** GLOBAL COMPONENTS AND DIRECTIVE */ -import { AppNavigation, DatetimePicker, Multiselect, PopoverMenu } from 'nextcloud-vue' +import { Action, AppNavigation, DatetimePicker, Multiselect, PopoverMenu } from 'nextcloud-vue' import ClickOutside from 'vue-click-outside' import { VTooltip } from 'v-tooltip' import VueClipboard from 'vue-clipboard2' @@ -43,6 +43,7 @@ __webpack_nonce__ = btoa(OC.requestToken) // eslint-disable-next-line __webpack_public_path__ = generateFilePath('contacts', '', 'js/') +Vue.component('Action', Action) Vue.component('AppNavigation', AppNavigation) Vue.component('DatetimePicker', DatetimePicker) Vue.component('Multiselect', Multiselect) diff --git a/src/mixins/PropertyMixin.js b/src/mixins/PropertyMixin.js index 73b3f21c..cdb166f2 100644 --- a/src/mixins/PropertyMixin.js +++ b/src/mixins/PropertyMixin.js @@ -76,6 +76,17 @@ export default { } }, + computed: { + actions() { + const del = { + text: t('contacts', 'Delete'), + icon: 'icon-delete', + action: this.deleteProperty + } + return [del, ...this.propModel.actions ? this.propModel.actions : []] + } + }, + watch: { /** * Since we're updating a local data based on the value prop, diff --git a/src/models/rfcProps.js b/src/models/rfcProps.js index 122736f2..79c891e6 100644 --- a/src/models/rfcProps.js +++ b/src/models/rfcProps.js @@ -21,7 +21,17 @@ */ import { VCardTime } from 'ical.js' -const properties = { +const copyNtoFN = ({ contact, updateContact }) => () => { + if (contact.vCard.hasProperty('n')) { + // Stevenson;John;Philip,Paul;Dr.;Jr.,M.D.,A.C.P. + // -> John Stevenson + const n = contact.vCard.getFirstPropertyValue('n') + contact.fullName = n.slice(0, 2).reverse().join(' ') + updateContact() + } +} + +const properties = component => ({ nickname: { readableName: t('contacts', 'Nickname'), icon: 'icon-user' @@ -39,7 +49,14 @@ const properties = { defaultValue: { value: ['', '', '', '', ''] }, - icon: 'icon-user' + icon: 'icon-user', + actions: [ + { + text: t('contacts', 'Copy to full name'), + icon: 'icon-up', + action: copyNtoFN(component) + } + ] }, note: { readableName: t('contacts', 'Notes'), @@ -266,7 +283,7 @@ const properties = { { id: 'O', name: t('contacts', 'Other') } ] } -} +}) const fieldOrder = [ 'org', diff --git a/src/services/checks/missingFN.js b/src/services/checks/missingFN.js index 1f17afc8..449f4a43 100644 --- a/src/services/checks/missingFN.js +++ b/src/services/checks/missingFN.js @@ -29,6 +29,10 @@ export default { run: contact => { return !contact.vCard.hasProperty('fn') // No FN || contact.vCard.getFirstPropertyValue('fn') === '' // Empty FN + || ( // we don't want to fix newly created contacts + contact.dav // Existing contact + && contact.vCard.getFirstPropertyValue('fn') === t('contacts', 'New contact') // AND Unchanged FN + ) }, fix: contact => { if (contact.vCard.hasProperty('n')) { diff --git a/src/store/contacts.js b/src/store/contacts.js index 5258d861..d5538b6e 100644 --- a/src/store/contacts.js +++ b/src/store/contacts.js @@ -285,6 +285,10 @@ const actions = { * @returns {Promise} */ async updateContact(context, contact) { + + // Checking contact validity 🙈 + validate(contact) + let vData = ICAL.stringify(contact.vCard.jCal) // if no dav key, contact does not exists on server |