diff --git a/src/components/ContactDetails/ContactDetailsProperty.vue b/src/components/ContactDetails/ContactDetailsProperty.vue index 94109bc8f9..014f421dba 100644 --- a/src/components/ContactDetails/ContactDetailsProperty.vue +++ b/src/components/ContactDetails/ContactDetailsProperty.vue @@ -199,6 +199,11 @@ export default { * @return {Array} */ propGroup() { + const group = this.property.getParameter('group') + if (group) { + return [group, this.property.name] + } + // for group embedded in the name, e.g. ITEMXX.tel return this.property.name.split('.') }, @@ -208,7 +213,20 @@ export default { * @return {ICAL.Property} */ propLabel() { - return this.localContact.vCard.getFirstProperty(`${this.propGroup[0]}.x-ablabel`) + if (!this.propGroup[1]) { + return null + } // not a grouped property + const group = this.propGroup[0] + + const dottedLabel = this.localContact.vCard.getFirstProperty(`${group}.x-ablabel`) + if (dottedLabel) { + return dottedLabel + } + return ( + this.localContact.vCard + .getAllProperties('x-ablabel') + .find((prop) => prop.getParameter('group') === group) || null + ) }, /** @@ -272,18 +290,31 @@ export default { } else { // ical.js take types as arrays this.type = data.id.split(',') - // only one can coexist - this.localContact.vCard.removeProperty(`${this.propGroup[0]}.x-ablabel`) - // checking if there is any other property in this group + const group = this.propGroup[0] + this.localContact.vCard.removeProperty(`${group}.x-ablabel`) + + const paramLabel = this.localContact.vCard + .getAllProperties('x-ablabel') + .find((p) => p.getParameter('group') === group) + if (paramLabel) { + this.localContact.vCard.removeProperty(paramLabel) + } + const groups = this.localContact.jCal[1] .map((prop) => prop[0]) - .filter((name) => name.startsWith(`${this.propGroup[0]}.`)) - if (groups.length === 1) { - // then this prop is the latest of its group - // -> converting back to simple prop - // eslint-disable-next-line vue/no-mutating-props + .filter((name) => name.startsWith(`${group}.`)) + + const paramGroups = this.localContact.jCal[1].filter((prop) => prop[1] && prop[1].group === group) + const allGroups = [ + ...new Set([...groups, ...paramGroups.map((p) => p[0])]), + ] + + if (allGroups.length === 1) { this.property.jCal[0] = this.propGroup[1] + if (this.property.getParameter('group')) { + delete this.property.jCal[1].group + } } } }, diff --git a/src/mixins/PropertyMixin.js b/src/mixins/PropertyMixin.js index aa116fb6d7..69426dcc11 100644 --- a/src/mixins/PropertyMixin.js +++ b/src/mixins/PropertyMixin.js @@ -123,16 +123,31 @@ export default { createLabel(label) { let propGroup = this.property.name - if (!this.property.name.startsWith('nextcloud')) { + const existingGroup = this.property.getParameter('group') + + if (existingGroup) { + // Server-loaded form: embed group into name, remove group param to avoid double prefix + propGroup = `${existingGroup}.${this.property.name}` + this.property.jCal[0] = propGroup + delete this.property.jCal[1].group // prevent NEXTCLOUD1.NEXTCLOUD1.TEL + + // Remove old X-ABLABEL in server-loaded form (group-param form) + const oldLabel = this.localContact.vCard + .getAllProperties('x-ablabel') + .find((p) => p.getParameter('group') === existingGroup) + if (oldLabel) { + this.localContact.vCard.removeProperty(oldLabel) + } + } else if (!this.property.name.startsWith('nextcloud')) { propGroup = `nextcloud${this.getNcGroupCount() + 1}.${this.property.name}` this.property.jCal[0] = propGroup } + // else: already has a valid nextcloud group prefix in name — reuse it + const group = propGroup.split('.')[0] const name = propGroup.split('.')[1] this.localContact.vCard.addPropertyWithValue(`${group}.x-ablabel`, label.name) - - // force update the main design sets setPropertyAlias(name, propGroup) this.$emit('update') @@ -140,12 +155,17 @@ export default { getNcGroupCount() { const props = this.localContact.jCal[1] - .map((prop) => prop[0].split('.')[0]) // itemxxx.adr => itemxxx - .filter((name) => name.startsWith('nextcloud')) // filter nextcloudxxx.adr - .map((prop) => parseInt(prop.split('nextcloud')[1])) // nextcloudxxx => xxx - return props.length > 0 - ? Math.max.apply(null, props) // get max iteration of nextcloud grouped props - : 0 + .map((prop) => { + const nameGroup = prop[0].split('.')[0] + if (nameGroup.startsWith('nextcloud')) { + return nameGroup + } + return (prop[1] && prop[1].group) || '' + }) + .filter((name) => name.startsWith('nextcloud')) + .map((prop) => parseInt(prop.replace('nextcloud', ''))) + .filter((n) => !isNaN(n)) + return props.length > 0 ? Math.max.apply(null, props) : 0 }, }, }