diff options
-rw-r--r-- | css/ContactDetailsAvatar.scss | 2 | ||||
-rw-r--r-- | package-lock.json | 10 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/components/ContactDetails/ContactDetailsAvatar.vue | 6 | ||||
-rw-r--r-- | src/components/Settings/SettingsAddressbook.vue | 240 | ||||
-rw-r--r-- | webpack.common.js | 2 |
6 files changed, 133 insertions, 129 deletions
diff --git a/css/ContactDetailsAvatar.scss b/css/ContactDetailsAvatar.scss index f86c1709..6ec6cfe8 100644 --- a/css/ContactDetailsAvatar.scss +++ b/css/ContactDetailsAvatar.scss @@ -76,7 +76,7 @@ &__popovermenu { // center margin: calc((100% - 44px) / 2); - & /deep/ .action-item__menutoggle { + & .action-item__menutoggle { // hide three dot menu, in favour of icon-picture-force-white z-index: -1; &::before { diff --git a/package-lock.json b/package-lock.json index 67eed9d2..28987fff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2319,8 +2319,8 @@ "dev": true }, "cdav-library": { - "version": "github:nextcloud/cdav-library#18b38778637386424dff1acf7f9a41b4ca757721", - "from": "github:nextcloud/cdav-library#18b38778637386424dff1acf7f9a41b4ca757721", + "version": "github:nextcloud/cdav-library#3e3fae357ccbc427d6e44df9cd572285caa71d9c", + "from": "github:nextcloud/cdav-library", "requires": { "@babel/polyfill": "^7.4.4" } @@ -7015,9 +7015,9 @@ } }, "nextcloud-vue": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/nextcloud-vue/-/nextcloud-vue-0.11.1.tgz", - "integrity": "sha512-gQnAyTyIjgSOPMLrTMfmVldjwP3lz+xWU6gynDj3InGl4EgjoRp+7fQfgvanPAoDJWLHYh/cmxm4O9AaVZCSSg==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/nextcloud-vue/-/nextcloud-vue-0.11.2.tgz", + "integrity": "sha512-N65Wi+J5sI8dh8RnZxBFvePiyeeMhOXlkc8A2v3vsurpiIIQQyt8VHVjYo1FKfGUhvTWG1HQog8FERimZucJlQ==", "requires": { "hammerjs": "^2.0.8", "md5": "^2.2.1", diff --git a/package.json b/package.json index 436bd2e2..92006aaf 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "ical.js": "^1.3.0", "moment": "^2.24.0", "nextcloud-server": "^0.15.9", - "nextcloud-vue": "^0.11.1", + "nextcloud-vue": "^0.11.2", "p-limit": "^2.2.0", "p-queue": "^5.0.0", "qr-image": "^3.2.0", diff --git a/src/components/ContactDetails/ContactDetailsAvatar.vue b/src/components/ContactDetails/ContactDetailsAvatar.vue index fb54cd89..cbccfdc9 100644 --- a/src/components/ContactDetails/ContactDetailsAvatar.vue +++ b/src/components/ContactDetails/ContactDetailsAvatar.vue @@ -108,8 +108,8 @@ export default { }, computed: { photo() { - const type = this.contact.vCard.getFirstProperty('photo').type - if (!this.contact.photo.startsWith('data') && type === 'binary') { + const photo = this.contact.vCard.getFirstProperty('photo') + if (photo && !this.contact.photo.startsWith('data') && photo.type === 'binary') { // split on coma in case of any leftover base64 data and retrieve last part // usually we come to this part when the base64 image type is unknown return `data:image;base64,${this.contact.photo.split(',').pop()}` @@ -242,7 +242,7 @@ export default { }, updateImgSize() { - if (this.contact.photo) { + if (this.contact.photo && this.$refs.img) { this.updateHeightWidth(this.$refs.img.naturalHeight, this.$refs.img.naturalWidth) } }, diff --git a/src/components/Settings/SettingsAddressbook.vue b/src/components/Settings/SettingsAddressbook.vue index e831b387..9e39cb8f 100644 --- a/src/components/Settings/SettingsAddressbook.vue +++ b/src/components/Settings/SettingsAddressbook.vue @@ -34,12 +34,55 @@ class="addressbook__share icon-shared" @click="toggleShare" /> <!-- popovermenu --> - <a v-click-outside="closeMenu" href="#" class="addressbook__menu"> - <div class="icon-more" @click="toggleMenu" /> - <div :class="{open: menuOpen}" class="popovermenu"> - <popover-menu :menu="menu" /> - </div> - </a> + <Actions class="addressbook__menu" menu-align="right"> + <!-- copy addressbook link --> + <ActionLink + :href="addressbook.url" + :icon="copyLoading ? 'icon-loading-small' : 'icon-public'" + @click.stop.prevent="copyLink"> + {{ copyButtonText }} + </ActionLink> + + <!-- download addressbook --> + <ActionLink + :href="addressbook.url + '?export'" + icon="icon-download"> + {{ t('contacts', 'Download') }} + </ActionLink> + + <template v-if="!addressbook.readOnly"> + <!-- rename addressbook --> + <ActionButton v-if="!editingName" + icon="icon-rename" + @click.stop.prevent="renameAddressbook"> + {{ t('contacts', 'Rename') }} + </ActionButton> + <ActionInput v-else + ref="renameInput" + :disabled="renameLoading" + :icon="renameLoading ? 'icon-loading-small' : 'icon-rename'" + :value="addressbook.displayName" + @submit="updateAddressbookName" /> + + <!-- enable/disable addressbook --> + <ActionCheckbox v-if="!toggleEnabledLoading" + :checked="enabled" + @change.stop.prevent="toggleAddressbookEnabled"> + {{ enabled ? t('contacts', 'Enabled') : t('contacts', 'Disabled') }} + </ActionCheckbox> + <ActionButton v-else + icon="icon-loading-small"> + {{ enabled ? t('contacts', 'Enabled') : t('contacts', 'Disabled') }} + </ActionButton> + </template> + + <!-- delete addressbook --> + <ActionButton v-if="hasMultipleAddressbooks" + :icon="deleteAddressbookLoading ? 'icon-loading-small' : 'icon-delete'" + @click="confirmDeletion"> + {{ t('contacts', 'Delete') }} + </ActionButton> + </Actions> <!-- sharing input --> <ShareAddressBook v-if="shareOpen && !addressbook.readOnly" :addressbook="addressbook" /> @@ -47,13 +90,18 @@ </template> <script> +import { ActionLink, ActionButton, ActionInput, ActionCheckbox } from 'nextcloud-vue' import ShareAddressBook from './SettingsAddressbookShare' export default { name: 'SettingsAddressbook', components: { - ShareAddressBook + ShareAddressBook, + ActionLink, + ActionButton, + ActionInput, + ActionCheckbox }, props: { @@ -84,6 +132,12 @@ export default { hasShares() { return this.addressbook.shares.length > 0 }, + addressbooks() { + return this.$store.getters.getAddressbooks + }, + hasMultipleAddressbooks() { + return this.addressbooks.length > 1 + }, // info tooltip about number of shares sharedWithTooltip() { return this.hasShares @@ -95,56 +149,13 @@ export default { }) : '' // disable the tooltip }, - // building the popover menu - menu() { - let menu = [ - { - href: this.addressbook.url, - icon: this.copyLoading ? 'icon-loading-small' : 'icon-public', - text: !this.copied - ? t('contacts', 'Copy link') - : this.copySuccess - ? t('contacts', 'Copied') - : t('contacts', 'Can not copy'), - action: this.copyLink - }, - { - href: this.addressbook.url + '?export', - icon: 'icon-download', - text: t('contacts', 'Download') - } - ] - - // check if addressbook is readonly - if (!this.addressbook.readOnly) { - menu.push({ - icon: this.renameLoading ? 'icon-loading-small' : 'icon-rename', - // check if editing name - input: this.editingName ? 'text' : null, - text: !this.editingName ? t('contacts', 'Rename') : '', - action: !this.editingName ? this.renameAddressbook : this.updateAddressbookName, - value: this.addressbook.displayName, - placeholder: this.addressbook.displayName - }, - { - text: this.enabled ? t('contacts', 'Enabled') : t('contacts', 'Disabled'), - icon: this.toggleEnabledLoading ? 'icon-loading-small' : null, - input: this.toggleEnabledLoading ? null : 'checkbox', - key: 'enableAddressbook', - model: this.enabled, - action: this.toggleAddressbookEnabled - }) - - // check to ensure last addressbook is not deleted. - if (this.$store.getters.getAddressbooks.length > 1) { - menu.push({ - icon: this.deleteAddressbookLoading ? 'icon-loading-small' : 'icon-delete', - text: t('contacts', 'Delete'), - action: this.confirmDeletion - }) - } + copyButtonText() { + if (this.copied) { + return this.copySuccess + ? t('contacts', 'Copied') + : t('contacts', 'Can not copy') } - return menu + return t('contacts', 'Copy link') } }, watch: { @@ -168,21 +179,19 @@ export default { toggleShare() { this.shareOpen = !this.shareOpen }, - toggleAddressbookEnabled() { + async toggleAddressbookEnabled() { // change to loading status this.toggleEnabledLoading = true - setTimeout(() => { - try { - this.$store.dispatch('toggleAddressbookEnabled', this.addressbook) - } catch (err) { - // error handling - console.error(err) - OC.Notification.showTemporary(t('contacts', 'Enabled toggle of addressbook was not successful.')) - } finally { - // stop loading status regardless of outcome - this.toggleEnabledLoading = false - } - }, 500) + try { + await this.$store.dispatch('toggleAddressbookEnabled', this.addressbook) + } catch (err) { + // error handling + console.error(err) + OC.Notification.showTemporary(t('contacts', 'Enabled toggle of addressbook was not successful.')) + } finally { + // stop loading status regardless of outcome + this.toggleEnabledLoading = false + } }, confirmDeletion() { @@ -194,73 +203,68 @@ export default { ) }, - deleteAddressbook(confirm) { + async deleteAddressbook(confirm) { if (confirm) { // change to loading status this.deleteAddressbookLoading = true - setTimeout(() => { - try { - this.$store.dispatch('deleteAddressbook', this.addressbook) - } catch (err) { - // error handling - console.error(err) - OC.Notification.showTemporary(t('contacts', 'Deletion of addressbook was not successful.')) - } finally { - // stop loading status regardless of outcome - this.deleteAddressbookLoading = false - } - }, 500) + try { + await this.$store.dispatch('deleteAddressbook', this.addressbook) + } catch (err) { + // error handling + console.error(err) + OC.Notification.showTemporary(t('contacts', 'Deletion of addressbook was not successful.')) + } finally { + // stop loading status regardless of outcome + this.deleteAddressbookLoading = false + } } }, renameAddressbook() { this.editingName = true }, - updateAddressbookName(e) { + async updateAddressbookName(e) { let addressbook = this.addressbook // New name for addressbook - inputed value from form - let newName = e.target[0].value + let newName = this.$refs.renameInput.$el.querySelector('input[type="text"]').value // change to loading status this.renameLoading = true - setTimeout(() => { - try { - this.$store.dispatch('renameAddressbook', { addressbook, newName }) - } catch (err) { - // error handling - console.error(err) - OC.Notification.showTemporary(t('contacts', 'Renaming of addressbook was not successful.')) - } finally { - this.editingName = false - // stop loading status regardless of outcome - this.renameLoading = false - // close popover menu - this.menuOpen = false - } - }, 500) + try { + await this.$store.dispatch('renameAddressbook', { addressbook, newName }) + } catch (err) { + // error handling + console.error(err) + OC.Notification.showTemporary(t('contacts', 'Renaming of addressbook was not successful.')) + } finally { + this.editingName = false + // stop loading status regardless of outcome + this.renameLoading = false + // close popover menu + this.menuOpen = false + } }, - copyLink(event) { + async copyLink(event) { // change to loading status this.copyLoading = true - event.stopPropagation() // copy link for addressbook to clipboard - this.$copyText(window.location.origin + this.addressbook.url) - .then(e => { - event.preventDefault() - this.copySuccess = true - this.copied = true - // Notify addressbook was copied - OC.Notification.showTemporary(t('contacts', 'Addressbook copied to clipboard')) - }, e => { + try { + await this.$copyText(window.location.origin + this.addressbook.url) + this.copySuccess = true + this.copied = true + // Notify addressbook was copied + OC.Notification.showTemporary(t('contacts', 'Addressbook copied to clipboard')) + } catch (error) { + this.copySuccess = false + this.copied = true + OC.Notification.showTemporary(t('contacts', 'Addressbook was not copied to clipboard.')) + } finally { + this.copyLoading = false + setTimeout(() => { + // stop loading status regardless of outcome + this.copied = false this.copySuccess = false - this.copied = true - OC.Notification.showTemporary(t('contacts', 'Addressbook was not copied to clipboard.')) - }).then(() => { - this.copyLoading = false - setTimeout(() => { - // stop loading status regardless of outcome - this.copied = false - }, 2000) - }) + }, 2000) + } } } } diff --git a/webpack.common.js b/webpack.common.js index da9cc0e9..af5d6759 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -9,7 +9,7 @@ module.exports = { path: path.resolve(__dirname, './js'), publicPath: '/js/', filename: 'contacts.js', - chunkFilename: 'chunks/[name].js' + chunkFilename: 'chunks/contacts.[name].[contenthash].js' }, module: { rules: [ |