summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2019-01-30 11:16:29 +0100
committerJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2019-01-30 12:17:23 +0100
commita1561dfe3a728f3b636852df05d36c1947883dd7 (patch)
tree91e90dae3ec08878ae81a2f68a90fba4050ebfc2 /src
parent7af5d37ac8428784843fd3cca531fb30ecf71fe3 (diff)
Add property-defined actions
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/components/ContactDetails.vue4
-rw-r--r--src/components/ContactDetails/ContactDetailsProperty.vue12
-rw-r--r--src/components/Properties/PropertyDateTime.vue5
-rw-r--r--src/components/Properties/PropertyMultipleText.vue5
-rw-r--r--src/components/Properties/PropertySelect.vue5
-rw-r--r--src/components/Properties/PropertyText.vue11
-rw-r--r--src/main.js3
-rw-r--r--src/mixins/PropertyMixin.js11
-rw-r--r--src/models/rfcProps.js23
-rw-r--r--src/services/checks/missingFN.js4
-rw-r--r--src/store/contacts.js4
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