diff --git a/package.json b/package.json index e6d0afff35..fce3b2a503 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "vue": "^2.5.16", "vue-click-outside": "^1.0.7", "vue-multiselect": "^2.1.0", - "vue2-datepicker": "^2.4.1" + "vue2-datepicker": "^2.4.1", + "nextcloud-axios": "^0.1.2" }, "engines": { "node": ">=10.0.0" diff --git a/src/components/Avatar/Avatar.vue b/src/components/Avatar/Avatar.vue new file mode 100644 index 0000000000..6d4678dc09 --- /dev/null +++ b/src/components/Avatar/Avatar.vue @@ -0,0 +1,176 @@ +<!-- + - @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> + - + - @author Julius Härtl <jus@bitgrid.net> + - + - @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-tooltip="displayName" v-click-outside="closeMenu" + :class="{ 'icon-loading': loading, 'unknown': unknown }" + :style="{width: size + 'px', height: size + 'px'}" + class="avatardiv popovermenu-wrapper" @click="toggleMenu"> + <img v-if="!loading && !unknown" :src="avatarUrlLoaded"> + <div v-if="unknown" class="unknown">?</div> + <div v-show="openedMenu" class="popovermenu"> + <popover-menu :is-open="openedMenu" :menu="menu" /> + </div> + </div> +</template> + +<script> + +/* global OC oc_userconfig */ + +import { VTooltip } from 'v-tooltip' +import { PopoverMenu } from '../PopoverMenu' +import ClickOutside from 'vue-click-outside' +import axios from 'nextcloud-axios' + +export default { + name: 'Avatar', + directives: { + tooltip: VTooltip, + ClickOutside: ClickOutside + }, + components: { + PopoverMenu + }, + props: { + url: { + type: String, + default: undefined + }, + user: { + type: String, + default: undefined + }, + displayName: { + type: String, + default: undefined + }, + size: { + type: Number, + default: 32 + } + }, + data() { + return { + actions: [], + avatarUrlLoaded: null, + unknown: false, + loading: true, + openedMenu: false + } + }, + computed: { + menu() { + return this.actions.map((item) => { + return { + href: item.hyperlink, + icon: item.icon, + text: item.title + } + }) + } + }, + mounted() { + let avatarUrl = OC.generateUrl( + '/avatar/{user}/{size}', + { + user: this.user, + size: Math.ceil(this.size * window.devicePixelRatio) + }) + if (this.user === OC.getCurrentUser().uid) { + avatarUrl += '?v=' + oc_userconfig.avatar.version + } + if (typeof this.url !== 'undefined') { + avatarUrl = this.url + } + + let img = new Image() + img.onload = () => { + this.avatarUrlLoaded = avatarUrl + this.loading = false + } + img.onerror = () => { + this.unknown = true + this.loading = false + } + img.src = avatarUrl + }, + methods: { + toggleMenu() { + if (this.user === OC.getCurrentUser().uid || this.unknown || this.url) { + return + } + this.openedMenu = !this.openedMenu + if (this.openedMenu) { + this.fetchContactsMenu() + } + }, + closeMenu() { + this.openedMenu = false + }, + fetchContactsMenu() { + axios.post(OC.generateUrl('contactsmenu/findOne'), 'shareType=0&shareWith=' + this.user).then((response) => { + this.actions = [response.data.topAction].concat(response.data.actions) + }).catch(() => { + this.openedMenu = false + }) + } + } +} +</script> + +<style scoped> + .avatardiv { + display: inline-block; + } + + .avatardiv.unknown { + background-color: var(--color-text-maxcontrast); + position: relative; + } + + .avatardiv > .unknown { + position: absolute; + color: var(--color-main-background); + width: 100%; + text-align: center; + font-size: 14pt; + display: block; + top: 18%; + left: 0; + } + + .avatardiv img { + width: 100%; + height: 100%; + } + + .popovermenu-wrapper { + position: relative; + display: inline-block; + } + + .popovermenu { + display: block; + margin: 0; + } +</style> diff --git a/src/components/Avatar/index.js b/src/components/Avatar/index.js new file mode 100644 index 0000000000..87d4bf91da --- /dev/null +++ b/src/components/Avatar/index.js @@ -0,0 +1,26 @@ +/** + * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @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/>. + * + */ + +import Avatar from './Avatar' + +export default Avatar +export { Avatar } diff --git a/src/components/PopoverMenu/PopoverMenuItem.vue b/src/components/PopoverMenu/PopoverMenuItem.vue index d70cfc4884..d70a78f051 100644 --- a/src/components/PopoverMenu/PopoverMenuItem.vue +++ b/src/components/PopoverMenu/PopoverMenuItem.vue @@ -26,7 +26,8 @@ <a v-if="item.href" :href="(item.href) ? item.href : '#' " :target="(item.target) ? item.target : '' " rel="noreferrer noopener" @click="action"> - <span :class="item.icon" /> + <span v-if="!iconIsUrl" :class="item.icon" /> + <img v-else :src="item.icon"> <span v-if="item.text">{{ item.text }}</span> <p v-else-if="item.longtext">{{ item.longtext }}</p> </a> @@ -100,6 +101,15 @@ export default { return this.item.key ? this.item.key : Math.round(Math.random() * 16 * 1000000).toString(16) + }, + iconIsUrl() { + try { + // eslint-disable-next-line no-new + new URL(this.item.icon) + return true + } catch (_) { + return false + } } }, methods: { diff --git a/src/components/index.js b/src/components/index.js index eb7857afdf..e00cd1adca 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -24,10 +24,12 @@ import AppNavigation from './AppNavigation' import PopoverMenu from './PopoverMenu' import DatetimePicker from './DatetimePicker' import Multiselect from './Multiselect' +import Avatar from './Avatar' export { AppNavigation, PopoverMenu, DatetimePicker, - Multiselect + Multiselect, + Avatar }