diff options
author | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-08-28 14:53:19 +0200 |
---|---|---|
committer | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-08-28 14:53:19 +0200 |
commit | 670493bd8a029d8e3b6ab75778cb2fd0cb16378a (patch) | |
tree | 2745cc445e21da851f20337cea12ee98fbf1db4c /src/components/Properties | |
parent | 0b5f975b5288e1a9548260f9ac8f47453982f9a7 (diff) |
Dav lib 1
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Diffstat (limited to 'src/components/Properties')
-rw-r--r-- | src/components/Properties/PropertyDateTime.vue | 142 | ||||
-rw-r--r-- | src/components/Properties/PropertyGroups.vue | 157 | ||||
-rw-r--r-- | src/components/Properties/PropertyMultipleText.vue | 145 | ||||
-rw-r--r-- | src/components/Properties/PropertySelect.vue | 147 | ||||
-rw-r--r-- | src/components/Properties/PropertyText.vue | 139 | ||||
-rw-r--r-- | src/components/Properties/PropertyTitle.vue | 48 |
6 files changed, 778 insertions, 0 deletions
diff --git a/src/components/Properties/PropertyDateTime.vue b/src/components/Properties/PropertyDateTime.vue new file mode 100644 index 00000000..f4f843bc --- /dev/null +++ b/src/components/Properties/PropertyDateTime.vue @@ -0,0 +1,142 @@ +<!-- + - @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + - + - @author John Molakvoæ <skjnldsv@protonmail.com> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div v-if="propModel" :class="`grid-span-${gridLength}`" class="property"> + <!-- title if first element --> + <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> + + <!-- no options, empty space --> + <div v-else class="property__label">{{ propModel.readableName }}</div> + + <!-- delete the prop --> + <button :title="t('contacts', 'Delete')" class="property__delete icon-delete" @click="deleteProperty" /> + + <input v-model.trim="localValue" class="property__value" type="text" + @input="updateValue"> + </div> + </div> +</template> + +<script> +import Multiselect from 'vue-multiselect' +import propertyTitle from './PropertyTitle' +import debounce from 'debounce' +import { VCardTime } from 'ical.js' + +export default { + name: 'PropertyDateTime', + + components: { + Multiselect, + propertyTitle + }, + + props: { + selectType: { + type: [Object, Boolean], + default: () => {} + }, + propModel: { + type: Object, + default: () => {}, + required: true + }, + value: { + type: VCardTime, + default: '', + required: true + }, + isFirstProperty: { + type: Boolean, + default: true + }, + isLastProperty: { + type: Boolean, + default: true + } + }, + + data() { + return { + localValue: this.value, + localType: this.selectType + } + }, + + computed: { + gridLength() { + let hasTitle = this.isFirstProperty && this.propModel.icon ? 1 : 0 + let isLast = this.isLastProperty ? 1 : 0 + // length is always one & add one space at the end + return hasTitle + 1 + isLast + } + }, + + watch: { + /** + * Since we're updating a local data based on the value prop, + * we need to make sure to update the local data on pop change + */ + value: function() { + this.localValue = this.value + }, + selectType: function() { + this.localType = this.selectType + } + }, + + methods: { + + /** + * Delete the property + */ + deleteProperty() { + this.$emit('delete') + }, + + /** + * Debounce and send update event to parent + */ + 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) + } +} + +</script> diff --git a/src/components/Properties/PropertyGroups.vue b/src/components/Properties/PropertyGroups.vue new file mode 100644 index 00000000..56a6ce8e --- /dev/null +++ b/src/components/Properties/PropertyGroups.vue @@ -0,0 +1,157 @@ +<!-- + - @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + - + - @author John Molakvoæ <skjnldsv@protonmail.com> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div v-if="propModel" class="grid-span-1 property"> + + <div class="property__row"> + <div class="property__label">{{ propModel.readableName }}</div> + <!-- multiselect taggable groups with a limit to 3 groups shown --> + <multiselect v-model="localValue" :options="groups" :placeholder="t('contacts', 'Add contact in group')" + :limit="3" :multiple="true" :taggable="true" + :close-on-select="false" tag-placeholder="create" class="multiselect-vue property__value" + @tag="validateGroup" @select="addContactToGroup" @remove="removeContactToGroup"> + <!-- show how many groups are hidden and add tooltip --> + <span v-tooltip.auto="formatGroupsTitle" slot="limit" class="multiselect__limit">+{{ localValue.length - 3 }}</span> + <span slot="noResult">{{ t('settings', 'No results') }}</span> + </multiselect> + </div> + </div> +</template> + +<script> +import Multiselect from 'vue-multiselect' +import debounce from 'debounce' +import Contact from '../../models/contact' + +export default { + name: 'PropertyGroups', + + components: { + Multiselect + }, + + props: { + propModel: { + type: Object, + default: () => {}, + required: true + }, + value: { + type: Array, + default: () => [], + required: true + }, + contact: { + type: Contact, + default: null, + required: true + } + }, + + data() { + return { + localValue: this.value + } + }, + + computed: { + groups() { + return this.$store.getters.getGroups.slice(0).map(group => group.name) + }, + + /** + * Format array of groups objects to a string for the popup + * Based on the ultiselect limit + */ + formatGroupsTitle() { + return this.localValue.slice(3).join(', ') + } + }, + + watch: { + /** + * Since we're updating a local data based on the value prop, + * we need to make sure to update the local data on pop change + */ + value: function() { + this.localValue = this.value + }, + selectType: function() { + this.localType = this.selectType + } + }, + + methods: { + + /** + * Debounce and send update event to parent + */ + updateValue: debounce(function(e) { + // https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier + this.$emit('update:value', this.localValue) + }, 500), + + /** + * Dispatch contact addition to group + * + * @param {String} groupName the group name + */ + addContactToGroup(groupName) { + this.$store.dispatch('addContactToGroup', { + contact: this.contact, + groupName + }) + }, + + /** + * Dispatch contact removal from group + * + * @param {String} groupName the group name + */ + removeContactToGroup(groupName) { + this.$store.dispatch('removeContactToGroup', { + contact: this.contact, + groupName + }) + }, + + /** + * Validate groupname and dispatch creation + * + * @param {String} groupName the group name + * @returns {Boolean} + */ + validateGroup(groupName) { + // Only allow characters without vcard special chars + let groupRegex = /^[^;,:]+$/gmi + if (groupName.match(groupRegex)) { + this.addContactToGroup(groupName) + this.localValue.push(groupName) + return true + } + return false + } + } +} + +</script> diff --git a/src/components/Properties/PropertyMultipleText.vue b/src/components/Properties/PropertyMultipleText.vue new file mode 100644 index 00000000..45fc70ef --- /dev/null +++ b/src/components/Properties/PropertyMultipleText.vue @@ -0,0 +1,145 @@ +<!-- + - @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + - + - @author John Molakvoæ <skjnldsv@protonmail.com> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div v-if="propModel" :class="`grid-span-${gridLength}`" class="property"> + <!-- title if first element --> + <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> + + <!-- no options, empty space --> + <div v-else class="property__label">{{ propModel.readableName }}</div> + + <!-- delete the prop --> + <button :title="t('contacts', 'Delete')" class="property__delete icon-delete" @click="deleteProperty" /> + </div> + + <div v-for="index in propModel.displayOrder" :key="index" class="property__row"> + <div class="property__label">{{ propModel.readableValues[index] }}</div> + <input v-model.trim="localValue[index]" class="property__value" type="text" + @input="updateValue"> + </div> + </div> +</template> + +<script> +import Multiselect from 'vue-multiselect' +import propertyTitle from './PropertyTitle' +import debounce from 'debounce' + +export default { + name: 'PropertyText', + + components: { + Multiselect, + propertyTitle + }, + + props: { + selectType: { + type: [Object, Boolean], + default: () => {} + }, + propModel: { + type: Object, + default: () => {}, + required: true + }, + value: { + type: [Array, Object], + default: () => [], + required: true + }, + isFirstProperty: { + type: Boolean, + default: true + }, + isLastProperty: { + type: Boolean, + default: true + } + }, + + data() { + return { + localValue: this.value, + localType: this.selectType + } + }, + + computed: { + gridLength() { + let hasTitle = this.isFirstProperty && this.propModel.icon ? 1 : 0 + let isLast = this.isLastProperty + let length = this.propModel.displayOrder ? this.propModel.displayOrder.length : this.value.length + // always have a property__label + one extra space at the end + return 1 + hasTitle + length + isLast + } + }, + + watch: { + /** + * Since we're updating a local data based on the value prop, + * we need to make sure to update the local data on pop change + */ + value: function() { + this.localValue = this.value + }, + selectType: function() { + this.localType = this.selectType + } + }, + + methods: { + + /** + * Delete the property + */ + deleteProperty() { + this.$emit('delete') + }, + + /** + * Debounce and send update event to parent + */ + 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) + } +} + +</script> diff --git a/src/components/Properties/PropertySelect.vue b/src/components/Properties/PropertySelect.vue new file mode 100644 index 00000000..4981eb47 --- /dev/null +++ b/src/components/Properties/PropertySelect.vue @@ -0,0 +1,147 @@ +<!-- + - @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + - + - @author John Molakvoæ <skjnldsv@protonmail.com> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div v-if="propModel" :class="`grid-span-${gridLength}`" class="property"> + <!-- title if first element --> + <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> + + <!-- no options, empty space --> + <div v-else class="property__label">{{ propModel.readableName }}</div> + + <!-- 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')" + class="multiselect-vue property__value" track-by="id" label="name" + @input="updateValue" /> + </div> + </div> +</template> + +<script> +import Multiselect from 'vue-multiselect' +import propertyTitle from './PropertyTitle' +import debounce from 'debounce' + +export default { + name: 'PropertySelect', + + components: { + Multiselect, + propertyTitle + }, + + props: { + selectType: { + type: [Object, Boolean], + default: () => {} + }, + propModel: { + type: Object, + default: () => {}, + required: true + }, + value: { + type: [Object, String], + default: '', + required: true + }, + options: { + type: Array, + default: () => [], + required: true + }, + isFirstProperty: { + type: Boolean, + default: true + }, + isLastProperty: { + type: Boolean, + default: true + } + }, + + data() { + return { + localValue: this.value, + localType: this.selectType + } + }, + + computed: { + gridLength() { + let hasTitle = this.isFirstProperty && this.propModel.icon ? 1 : 0 + let isLast = this.isLastProperty ? 1 : 0 + // length is one & add one space at the end + return hasTitle + 1 + isLast + } + }, + + watch: { + /** + * Since we're updating a local data based on the value prop, + * we need to make sure to update the local data on pop change + */ + value: function() { + this.localValue = this.value + }, + selectType: function() { + this.localType = this.selectType + } + }, + + methods: { + + /** + * Delete the property + */ + deleteProperty() { + this.$emit('delete') + }, + + /** + * Debounce and send update event to parent + */ + 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) + } +} + +</script> diff --git a/src/components/Properties/PropertyText.vue b/src/components/Properties/PropertyText.vue new file mode 100644 index 00000000..32937db0 --- /dev/null +++ b/src/components/Properties/PropertyText.vue @@ -0,0 +1,139 @@ +<!-- + - @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + - + - @author John Molakvoæ <skjnldsv@protonmail.com> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div v-if="propModel" :class="`grid-span-${gridLength}`" class="property"> + <!-- title if first element --> + <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> + + <!-- no options, empty space --> + <div v-else class="property__label">{{ propModel.readableName }}</div> + + <!-- delete the prop --> + <button :title="t('contacts', 'Delete')" class="property__delete icon-delete" @click="deleteProperty" /> + + <input v-model.trim="localValue" class="property__value" type="text" + @input="updateValue"> + </div> + </div> +</template> + +<script> +import Multiselect from 'vue-multiselect' +import propertyTitle from './PropertyTitle' +import debounce from 'debounce' + +export default { + name: 'PropertyText', + + components: { + Multiselect, + propertyTitle + }, + + props: { + selectType: { + type: [Object, Boolean], + default: () => {} + }, + propModel: { + type: Object, + default: () => {}, + required: true + }, + value: { + type: String, + default: '', + required: true + }, + isFirstProperty: { + type: Boolean, + default: true + }, + isLastProperty: { + type: Boolean, + default: true + } + }, + + data() { + return { + localValue: this.value, + localType: this.selectType + } + }, + + computed: { + gridLength() { + let hasTitle = this.isFirstProperty && this.propModel.icon ? 1 : 0 + let isLast = this.isLastProperty ? 1 : 0 + // length is one & add one space at the end + return hasTitle + 1 + isLast + } + }, + + watch: { + /** + * Since we're updating a local data based on the value prop, + * we need to make sure to update the local data on pop change + */ + value: function() { + this.localValue = this.value + }, + selectType: function() { + this.localType = this.selectType + } + }, + + methods: { + /** + * Delete the property + */ + deleteProperty() { + this.$emit('delete') + }, + + /** + * Debounce and send update event to parent + */ + 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) + } +} +</script> diff --git a/src/components/Properties/PropertyTitle.vue b/src/components/Properties/PropertyTitle.vue new file mode 100644 index 00000000..cde06dd3 --- /dev/null +++ b/src/components/Properties/PropertyTitle.vue @@ -0,0 +1,48 @@ +<!-- + - @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + - + - @author John Molakvoæ <skjnldsv@protonmail.com> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <h3 class="property__title property__row"> + <div :class="icon" class="property__label property__title--icon" /> + {{ readableName }} + </h3> +</template> + +<script> +export default { + name: 'PropertyTitle', + + props: { + icon: { + type: String, + default: '', + required: true + }, + readableName: { + type: String, + default: '', + required: true + } + } + +} +</script> |