diff --git a/src/components/ContactDetails.vue b/src/components/ContactDetails.vue index 7ed646394..c559bd9a6 100644 --- a/src/components/ContactDetails.vue +++ b/src/components/ContactDetails.vue @@ -109,6 +109,10 @@ + + + @@ -175,13 +179,13 @@ export default { /** * Warning messages * - * @returns {Object|Boolean} + * @returns {Object|boolean} */ warning() { if (!this.contact.dav) { return { icon: 'icon-error-white header-icon--pulse', - msg: t('contacts', 'This contact is not yet synced. Edit it to trigger a change.') + msg: t('contacts', 'This contact is not yet synced. Edit it to save it to the server.') } } else if (this.isReadOnly) { return { @@ -195,7 +199,7 @@ export default { /** * Conflict message * - * @returns {String|Boolean} + * @returns {string|boolean} */ conflict() { if (this.contact.conflict) { @@ -283,6 +287,39 @@ export default { } }, + /** + * Fake model to use the propertyGroups component + * + * @returns {Object} + */ + groupsModel() { + return { + readableName: t('contacts', 'Groups'), + icon: 'icon-contacts' + } + }, + + /** + * Usable groups object linked to the local contact + * + * @param {string[]} data An array of groups + * @returns {Array} + */ + groups: { + get: function() { + return this.contact.groups + }, + set: function(data) { + let property = this.contact.vCard.getFirstProperty('categories') + if (!property) { + // Ical.js store comma separated by an Array of array of string + property = this.contact.vCard.addPropertyWithValue('categories', [data]) + } + property.setValues(data) + this.updateContact() + } + }, + /** * Store getters filtered and mapped to usable object * diff --git a/src/components/ContactDetails/ContactDetailsAddNewProp.vue b/src/components/ContactDetails/ContactDetailsAddNewProp.vue index 448b52466..74baa7a03 100644 --- a/src/components/ContactDetails/ContactDetailsAddNewProp.vue +++ b/src/components/ContactDetails/ContactDetailsAddNewProp.vue @@ -56,17 +56,42 @@ export default { }, computed: { + /** + * List of properties that the contact already have + * + * @returns {string[]} + */ + usedProperties() { + return this.contact.jCal[1].map(prop => prop[0]) + }, + + /** + * List of every properties you are allowed to add + * on this contact + * + * @returns {Object[]} + */ availableProperties() { - return Object.keys(rfcProps.properties).map(key => { - return { - id: key, - name: rfcProps.properties[key].readableName - } - }).sort((a, b) => a.name.localeCompare(b.name)) + return Object.keys(rfcProps.properties) + // only allow to add multiple properties OR props that are not yet in the contact + .filter(prop => prop.multiple || this.usedProperties.indexOf(prop) === -1) + // usable array of objects + .map(key => { + return { + id: key, + name: rfcProps.properties[key].readableName + } + }).sort((a, b) => a.name.localeCompare(b.name)) } }, methods: { + /** + * Add a new prop to the contact + * + * @param {Object} data destructuring object + * @param {string} data.id the id of the property. e.g fn + */ addProp({ id }) { let defaultData = rfcProps.properties[id].defaultValue let property = this.contact.vCard.addPropertyWithValue(id, defaultData ? defaultData.value : '') diff --git a/src/components/ContactDetails/ContactDetailsAvatar.vue b/src/components/ContactDetails/ContactDetailsAvatar.vue index c142c82f6..c98264b6c 100644 --- a/src/components/ContactDetails/ContactDetailsAvatar.vue +++ b/src/components/ContactDetails/ContactDetailsAvatar.vue @@ -57,6 +57,11 @@ export default { } }, methods: { + /** + * Handler to store a new photo on the current contact + * + * @param {Object} event the event object containing the image + */ processFile(event) { if (event.target.files) { let file = event.target.files[0] @@ -73,10 +78,18 @@ export default { reader.readAsDataURL(file) } }, + + /** + * Toggle the full image preview + */ toggleSize() { // maximise or minimise avatar photo this.maximizeAvatar = !this.maximizeAvatar }, + + /** + * Remove the contact's picture + */ removePhoto() { this.contact.vCard.removeProperty('photo') this.maximizeAvatar = !this.maximizeAvatar diff --git a/src/components/ContactDetails/ContactDetailsProperty.vue b/src/components/ContactDetails/ContactDetailsProperty.vue index 4191ef16e..129a4dd27 100644 --- a/src/components/ContactDetails/ContactDetailsProperty.vue +++ b/src/components/ContactDetails/ContactDetailsProperty.vue @@ -38,7 +38,6 @@ import Contact from 'Models/contact' import PropertyText from 'Components/Properties/PropertyText' import PropertyMultipleText from 'Components/Properties/PropertyMultipleText' import PropertyDateTime from 'Components/Properties/PropertyDateTime' -import propertyGroups from 'Components/Properties/PropertyGroups' import PropertySelect from 'Components/Properties/PropertySelect' export default { @@ -68,11 +67,6 @@ export default { computed: { // dynamically load component based on property type componentInstance() { - // groups - if (this.propName === 'categories') { - return propertyGroups - } - // dynamic matching if (this.property.isMultiValue && this.propType === 'text') { return PropertyMultipleText @@ -119,7 +113,7 @@ export default { /** * Return the type of the prop e.g. FN * - * @returns {String} + * @returns {string} */ propName() { return this.property.name @@ -128,7 +122,7 @@ export default { * Return the type or property * * @see src/models/rfcProps - * @returns {String} + * @returns {string} */ propType() { // if we have a force type set, use it! @@ -153,7 +147,7 @@ export default { * but make sure to include the selected one * in the final list * - * @returns {Array} + * @returns {Object[]} */ sortedModelOptions() { if (this.propModel.options) { diff --git a/src/components/ContactsList/ContactsListItem.vue b/src/components/ContactsList/ContactsListItem.vue index 8bda16a74..4453390b8 100644 --- a/src/components/ContactsList/ContactsListItem.vue +++ b/src/components/ContactsList/ContactsListItem.vue @@ -58,7 +58,7 @@ export default { /** * Is this matching the current search ? * - * @returns {Boolean} + * @returns {boolean} */ matchSearch() { if (this.searchQuery !== '') { @@ -69,7 +69,7 @@ export default { /** * avatar color based on server toRgb method and the displayName - * @returns {String} the color in css format + * @returns {string} the color in css format */ colorAvatar() { try { diff --git a/src/components/Properties/PropertyGroups.vue b/src/components/Properties/PropertyGroups.vue index 15677320c..0ee7f23c9 100644 --- a/src/components/Properties/PropertyGroups.vue +++ b/src/components/Properties/PropertyGroups.vue @@ -23,15 +23,18 @@