Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix avatar errors, and migrate settings menu to Actions #1103

Merged
merged 1 commit into from
May 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion css/ContactDetailsAvatar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
6 changes: 3 additions & 3 deletions src/components/ContactDetails/ContactDetailsAvatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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()}`
Expand Down Expand Up @@ -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)
}
},
Expand Down
240 changes: 122 additions & 118 deletions src/components/Settings/SettingsAddressbook.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,74 @@
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" />
</li>
</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: {
Expand Down Expand Up @@ -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
Expand All @@ -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: {
Expand All @@ -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() {
Expand All @@ -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)
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down