diff options
author | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-09-24 23:46:01 +0200 |
---|---|---|
committer | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-09-25 14:53:28 +0200 |
commit | f3c1f13792d78e3617e3d3f726d1324f3ea576ee (patch) | |
tree | 29197f5d49c4cbc9c4d3bcf4d36fd25a2e09224f /src | |
parent | 19a56a6fba9ad82f9b0c34d92bb4cd256ae88a94 (diff) |
Fixed select property
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/components/ContactDetails.vue | 51 | ||||
-rw-r--r-- | src/components/ContactDetails/ContactDetailsProperty.vue | 10 | ||||
-rw-r--r-- | src/components/Properties/PropertySelect.vue | 50 | ||||
-rw-r--r-- | src/components/Settings/SettingsNewAddressbook.vue | 5 | ||||
-rw-r--r-- | src/models/rfcProps.js | 7 | ||||
-rw-r--r-- | src/store/addressbooks.js | 1 | ||||
-rw-r--r-- | src/store/contacts.js | 63 | ||||
-rw-r--r-- | src/views/Contacts.vue | 51 |
8 files changed, 153 insertions, 85 deletions
diff --git a/src/components/ContactDetails.vue b/src/components/ContactDetails.vue index f3c4b647..889dc973 100644 --- a/src/components/ContactDetails.vue +++ b/src/components/ContactDetails.vue @@ -95,7 +95,7 @@ <!-- addressbook change select - no last property because class is not applied here--> <property-select :prop-model="addressbookModel" :value.sync="addressbook" :is-first-property="true" - :is-last-property="false" :options="addressbooksOptions" class="property--addressbooks" /> + :is-last-property="false" class="property--addressbooks" /> <!-- new property select --> <add-new-prop :contact="contact" /> @@ -158,11 +158,7 @@ export default { localContact: undefined, loadingData: true, loadingUpdate: false, - openedMenu: false, - addressbookModel: { - readableName: t('contacts', 'Addressbook'), - icon: 'icon-addressbook' - } + openedMenu: false } }, @@ -212,16 +208,24 @@ export default { }) }, + /** + * Fake model to use the propertySelect component + */ + addressbookModel() { + return { + readableName: t('contacts', 'Addressbook'), + icon: 'icon-addressbook', + options: this.addressbooksOptions + } + }, + // usable addressbook object linked to the local contact addressbook: { get: function() { - return { - id: this.contact.addressbook.id, - name: this.contact.addressbook.displayName - } + return this.contact.addressbook.id }, - set: function(addressbook) { - this.moveContactToAddressbook(addressbook) + set: function(addressbookId) { + this.moveContactToAddressbook(addressbookId) } }, @@ -291,13 +295,16 @@ export default { }, /** - * Trigger an full fetch and + * Select a contac, and update the localContact + * Fetch updated data if necessary */ selectContact(uid) { // local version of the contact this.loadingData = true let contact = this.$store.getters.getContact(uid) - if (contact) { + + // if contact exists AND if exists on server + if (contact && contact.dav) { this.$store.dispatch('fetchFullContact', contact) .then(() => { // create empty contact and copy inner data @@ -309,6 +316,14 @@ export default { this.localContact = localContact this.loadingData = false }) + } else if (contact) { + // create empty contact and copy inner data + // wait for an update to really push the contact on the server! + this.localContact = new Contact( + 'BEGIN:VCARD\nUID:' + contact.uid + '\nEND:VCARD', + contact.addressbook + ) + this.loadingData = false } }, @@ -322,12 +337,10 @@ export default { /** * Move contact to the specified addressbook * - * @param {Object} addressbook the desired addressbook + * @param {string} addressbookId the desired addressbook ID */ - moveContactToAddressbook(addressbook) { - addressbook = this.addressbooks.find( - search => search.id === addressbook.id - ) + moveContactToAddressbook(addressbookId) { + let addressbook = this.addressbooks.find(search => search.id === addressbookId) // TODO Make sure we do not overwrite contacts if (addressbook) { this.$store diff --git a/src/components/ContactDetails/ContactDetailsProperty.vue b/src/components/ContactDetails/ContactDetailsProperty.vue index 4b0428fb..3be03f70 100644 --- a/src/components/ContactDetails/ContactDetailsProperty.vue +++ b/src/components/ContactDetails/ContactDetailsProperty.vue @@ -37,7 +37,7 @@ import PropertyText from '../Properties/PropertyText' import PropertyMultipleText from '../Properties/PropertyMultipleText' import PropertyDateTime from '../Properties/PropertyDateTime' import propertyGroups from '../Properties/PropertyGroups' -// import PropertySelect from '../Properties/PropertyMultipleText' +import PropertySelect from '../Properties/PropertySelect' export default { name: 'ContactDetailsProperty', @@ -76,6 +76,8 @@ export default { return PropertyMultipleText } else if (this.propType && ['date-and-or-time', 'date-time', 'time', 'date'].indexOf(this.propType) > -1) { return PropertyDateTime + } else if (this.propType && this.propType === 'select') { + return PropertySelect } else if (this.propType && this.propType !== 'unknown') { return PropertyText } @@ -111,6 +113,10 @@ export default { return this.property.name }, propType() { + // if we have a force type set, use it! + if (this.propModel && this.propModel.force) { + return this.propModel.force + } return this.property.getDefaultType() }, @@ -141,6 +147,8 @@ export default { } }) + console.log(matchingTypes) + // Sort by score, filtering out the null score and selecting the first match let matchingType = matchingTypes .sort((a, b) => b.score - a.score) diff --git a/src/components/Properties/PropertySelect.vue b/src/components/Properties/PropertySelect.vue index fb1aa827..3769967f 100644 --- a/src/components/Properties/PropertySelect.vue +++ b/src/components/Properties/PropertySelect.vue @@ -26,14 +26,9 @@ <property-title v-if="isFirstProperty && propModel.icon" :icon="propModel.icon" :readable-name="propModel.readableName" /> <div class="property__row"> - <!-- type selector --> - <multiselect v-if="propModel.options" v-model="localType" - :options="propModel.options" :searchable="false" :placeholder="t('contacts', 'Select type')" - class="multiselect-vue 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> + <div v-if="selectType" class="property__label">{{ selectType.name }}</div> <!-- no options, empty space --> <div v-else class="property__label">{{ propModel.readableName }}</div> @@ -41,9 +36,10 @@ <!-- delete the prop --> <button :title="t('contacts', 'Delete')" class="property__delete icon-delete" @click="deleteProperty" /> - <multiselect v-model="localValue" :options="options" :placeholder="t('contacts', 'Select option')" + <multiselect v-model="matchedOptions" :options="propModel.options" :placeholder="t('contacts', 'Select option')" class="multiselect-vue property__value" track-by="id" label="name" - @input="updateValue" /> + @input="updateValue"> + </multiselect> </div> </div> </template> @@ -76,11 +72,6 @@ export default { default: '', required: true }, - options: { - type: Array, - default: () => [], - required: true - }, isFirstProperty: { type: Boolean, default: true @@ -93,8 +84,8 @@ export default { data() { return { - localValue: this.value, - localType: this.selectType + localValue: this.value + // localType: this.selectType } }, @@ -104,7 +95,20 @@ export default { let isLast = this.isLastProperty ? 1 : 0 // length is one & add one space at the end return hasTitle + 1 + isLast + }, + matchedOptions: { + get() { + let selected = this.propModel.options.find(option => option.id === this.localValue) + return selected || { + id: this.localValue, + name: this.localValue + } + }, + set(value) { + this.localValue = value.id + } } + }, watch: { @@ -115,10 +119,10 @@ export default { */ value: function() { this.localValue = this.value - }, - selectType: function() { - this.localType = this.selectType } + // selectType: function() { + // this.localType = this.selectType + // } }, methods: { @@ -136,12 +140,12 @@ export default { 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) + + // 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/Settings/SettingsNewAddressbook.vue b/src/components/Settings/SettingsNewAddressbook.vue index 609fd1bd..1b1773ce 100644 --- a/src/components/Settings/SettingsNewAddressbook.vue +++ b/src/components/Settings/SettingsNewAddressbook.vue @@ -47,8 +47,9 @@ export default { return { loading: false, displayName: '', - // no slash!! - addressBookRegex: '[^/\\]+' + // no slashes! + // eslint-disable-next-line + addressBookRegex: '[^/\\\\]+' } }, methods: { diff --git a/src/models/rfcProps.js b/src/models/rfcProps.js index cae39970..e2cdb40b 100644 --- a/src/models/rfcProps.js +++ b/src/models/rfcProps.js @@ -140,7 +140,7 @@ const properties = { default: true, defaultValue: { value: '', - type: ['HOME,VOICE'] + type: ['HOME', 'VOICE'] }, options: [ { id: 'HOME,VOICE', name: t('contacts', 'Home') }, @@ -183,6 +183,7 @@ const properties = { }, relationship: { readableName: t('contacts', 'Relationship'), + force: 'select', info: t( 'contacts', 'Specify a relationship between you and the entity represented by this vCard.' @@ -234,6 +235,10 @@ const properties = { }, gender: { readableName: t('contacts', 'Gender'), + defaultValue: { + // default to Female 🙋 + value: ['F'] + }, options: [ { id: 'F', name: t('contacts', 'Female') }, { id: 'M', name: t('contacts', 'Male') }, diff --git a/src/store/addressbooks.js b/src/store/addressbooks.js index 68be9067..669e6585 100644 --- a/src/store/addressbooks.js +++ b/src/store/addressbooks.js @@ -244,7 +244,6 @@ const actions = { return client.addressBookHomes[0].createAddressBookCollection(addressbook.displayName) .then((response) => { addressbook = mapDavCollectionToAddressbook(response) - console.log(response, addressbook) context.commit('addAddressbooks', addressbook) }) .catch((error) => { throw error }) diff --git a/src/store/contacts.js b/src/store/contacts.js index c1d7ecb9..7b577467 100644 --- a/src/store/contacts.js +++ b/src/store/contacts.js @@ -88,11 +88,21 @@ const mutations = { for (var i = 0, len = state.sortedContacts.length; i < len; i++) { var nameA = state.sortedContacts[i].value.toUpperCase() // ignore upper and lowercase var nameB = sortedContact.value.toUpperCase() // ignore upper and lowercase - if (nameA.localeCompare(nameB) > 0) { + if (nameA.localeCompare(nameB) >= 0) { state.sortedContacts.splice(i, 0, sortedContact) break + } else if (i + 1 === len) { + // we reached the end insert it now + state.sortedContacts.push(sortedContact) } } + + // sortedContact is empty, just push it + if (state.sortedContacts.length === 0) { + state.sortedContacts.push(sortedContact) + } + + // default contacts list Vue.set(state.contacts, contact.key, contact) } else { @@ -116,7 +126,9 @@ const mutations = { // has the sort key changed for this contact ? let hasChanged = sortedContact.value !== contact[state.orderKey] if (hasChanged) { - // then we sort again + // then update the new data + sortedContact.value = contact[state.orderKey] + // and then we sort again state.sortedContacts .sort((a, b) => { var nameA = a.value.toUpperCase() // ignore upper and lowercase @@ -196,16 +208,16 @@ const actions = { * @param {Object} context * @param {Contact} contact the contact to delete */ - deleteContact(context, contact) { - contact.dav.delete() - .then((response) => { - context.commit('deleteContact', contact) - context.commit('deleteContactFromAddressbook', contact) - }) - .catch((error) => { - console.error(error) - OC.Notification.showTemporary(t('contacts', 'An error occurred')) - }) + async deleteContact(context, contact) { + if (contact.dav) { + await contact.dav.delete() + .catch((error) => { + console.error(error) + OC.Notification.showTemporary(t('contacts', 'An error occurred')) + }) + } + context.commit('deleteContact', contact) + context.commit('deleteContactFromAddressbook', contact) }, /** @@ -214,14 +226,9 @@ const actions = { * @param {Object} context * @param {Contact} contact the contact to delete */ - addContact(context, contact) { - return contact.addressbook.dav.createVCard(ICAL.stringify(contact.vCard.jCal)) - .then((response) => { - console.log(response) - context.commit('addContact', contact) - context.commit('addContactToAddressbook', contact) - }) - .catch((error) => { throw error }) + async addContact(context, contact) { + await context.commit('addContact', contact) + await context.commit('addContactToAddressbook', contact) }, /** @@ -230,8 +237,20 @@ const actions = { * @param {Object} context * @param {Contact} contact the contact to update */ - updateContact(context, contact) { - contact.dav.data = ICAL.stringify(contact.vCard.jCal) + async updateContact(context, contact) { + let vData = ICAL.stringify(contact.vCard.jCal) + + // if no dav key, contact does not exists on server + if (!contact.dav) { + // create contact + await contact.addressbook.dav.createVCard(vData) + .then((response) => { + contact.dav = response + }) + .catch((error) => { throw error }) + } + + contact.dav.data = vData return contact.dav.update() .then((response) => context.commit('updateContact', contact)) .catch((error) => { throw error }) diff --git a/src/views/Contacts.vue b/src/views/Contacts.vue index f6117b49..245711f6 100644 --- a/src/views/Contacts.vue +++ b/src/views/Contacts.vue @@ -201,15 +201,18 @@ export default { client.connect({ enableCardDAV: true }).then(() => { console.debug('Connected to dav!', client) this.$store.dispatch('getAddressbooks') - .then(() => { - // wait for all addressbooks to have fetch their contacts - Promise.all(this.addressbooks.map(addressbook => this.$store.dispatch('getContactsFromAddressBook', { addressbook }))) - .then(results => { - this.loading = false - this.selectFirstContactIfNone() - }) - // no need for a catch, the action does not throw - // and the error is handled there + .then((addressbooks) => { + + // No addressbooks? Create a new one! + if (addressbooks.length === 0) { + this.$store.dispatch('appendAddressbook', { displayName: t('contacts', 'Contacts') }) + .then(() => { + this.fetchContacts() + }) + // else, let's get those contacts! + } else { + this.fetchContacts() + } }) // check local storage for orderKey if (localStorage.getItem('orderKey')) { @@ -240,13 +243,15 @@ export default { contact.vCard.addPropertyWithValue('categories', this.selectedGroup) } this.$store.dispatch('addContact', contact) - this.$router.push({ - name: 'contact', - params: { - selectedGroup: this.selectedGroup, - selectedContact: contact.key - } - }) + .then(() => { + this.$router.push({ + name: 'contact', + params: { + selectedGroup: this.selectedGroup, + selectedContact: contact.key + } + }) + }) }, /** @@ -261,6 +266,20 @@ export default { }, /** + * Fetch the contacts of each addressbooks + */ + fetchContacts() { + // wait for all addressbooks to have fetch their contacts + Promise.all(this.addressbooks.map(addressbook => this.$store.dispatch('getContactsFromAddressBook', { addressbook }))) + .then(results => { + this.loading = false + this.selectFirstContactIfNone() + }) + // no need for a catch, the action does not throw + // and the error is handled there + }, + + /** * Select the first contact of the list * if none are selected already */ |