UNPKG

@nextcloud/vue

Version:
573 lines (572 loc) 20.3 kB
require('../assets/NcMentionBubble-C6t8od-_.css'); require('../assets/NcAvatar-5N7xP8zN.css'); "use strict"; const NcActions = require("./NcActions-gOMT5VzC.cjs"); const Components_NcActionLink = require("../Components/NcActionLink.cjs"); const Components_NcActionRouter = require("../Components/NcActionRouter.cjs"); const Components_NcActionText = require("../Components/NcActionText.cjs"); const Components_NcButton = require("../Components/NcButton.cjs"); const NcIconSvgWrapper = require("./NcIconSvgWrapper-Cb4bAwV6.cjs"); const Components_NcLoadingIcon = require("../Components/NcLoadingIcon.cjs"); const NcUserStatusIcon = require("./NcUserStatusIcon-FtKzp5sl.cjs"); const usernameToColor = require("./usernameToColor-u2MH9nY7.cjs"); const getAvatarUrl = require("./getAvatarUrl-6z9qRNH-.cjs"); require("../Composables/useIsFullscreen.cjs"); require("../Composables/useIsMobile.cjs"); ;/* empty css */ const _pluginVue2_normalizer = require("./_plugin-vue2_normalizer-V0q-tHlQ.cjs"); require("linkify-string"); require("escape-html"); require("striptags"); require("vue"); const auth = require("@nextcloud/auth"); const axios = require("@nextcloud/axios"); const capabilities = require("@nextcloud/capabilities"); const router = require("@nextcloud/router"); const _l10n = require("./_l10n-Ci9_UR5q.cjs"); const autolink = require("./autolink-BAgL31EZ.cjs"); const DotsHorizontal = require("./DotsHorizontal-DQfnwpao.cjs"); const eventBus = require("@nextcloud/event-bus"); const browserStorage$1 = require("@nextcloud/browser-storage"); const components = require("@vueuse/components"); const _interopDefault = (e) => e && e.__esModule ? e : { default: e }; const axios__default = /* @__PURE__ */ _interopDefault(axios); const userStatus = { data() { return { hasStatus: false, userStatus: { status: null, message: null, icon: null } }; }, methods: { /** * Fetches the user-status from the server * * @param {string} userId UserId of the user to fetch the status for * * @return {Promise<void>} */ async fetchUserStatus(userId) { var _a, _b; if (!userId) { return; } const capabilities$1 = capabilities.getCapabilities(); if (!Object.prototype.hasOwnProperty.call(capabilities$1, "user_status") || !capabilities$1.user_status.enabled) { return; } if (!auth.getCurrentUser()) { return; } try { const { data } = await axios__default.default.get(router.generateOcsUrl("apps/user_status/api/v1/statuses/{userId}", { userId })); const { status, message, icon } = data.ocs.data; this.userStatus.status = status; this.userStatus.message = message || ""; this.userStatus.icon = icon || ""; this.hasStatus = true; } catch (e) { if (e.response.status === 404 && ((_b = (_a = e.response.data.ocs) == null ? void 0 : _a.data) == null ? void 0 : _b.length) === 0) { return; } console.error(e); } } } }; _l10n.register(_l10n.t10); const browserStorage = browserStorage$1.getBuilder("nextcloud").persist().build(); function getUserHasAvatar(userId) { const flag = browserStorage.getItem("user-has-avatar." + userId); if (typeof flag === "string") { return Boolean(flag); } return null; } function setUserHasAvatar(userId, flag) { if (userId) { browserStorage.setItem("user-has-avatar." + userId, flag); } } const _sfc_main = { name: "NcAvatar", directives: { ClickOutside: components.vOnClickOutside }, components: { DotsHorizontal: DotsHorizontal.DotsHorizontal, NcActions: NcActions.NcActions, NcButton: Components_NcButton, NcIconSvgWrapper: NcIconSvgWrapper.NcIconSvgWrapper, NcLoadingIcon: Components_NcLoadingIcon, NcUserStatusIcon: NcUserStatusIcon.NcUserStatusIcon }, mixins: [userStatus], props: { /** * Set a custom url to the avatar image * either the url, user or displayName property must be defined */ url: { type: String, default: void 0 }, /** * Set a css icon-class for an icon to be used instead of the avatar. */ iconClass: { type: String, default: void 0 }, /** * Set the user id to fetch the avatar * either the url, user or displayName property must be defined */ user: { type: String, default: void 0 }, /** * Whether or not to display the user-status */ showUserStatus: { type: Boolean, default: true }, /** * Whether or not to the status-icon should be used instead of online/away */ showUserStatusCompact: { type: Boolean, default: true }, /** * When the user status was preloaded via another source it can be handed in with this property to save the request. * If this property is not set the status will be fetched automatically. * If a preloaded no-status is available provide this object with properties "status", "icon" and "message" set to null. */ preloadedUserStatus: { type: Object, default: void 0 }, /** * Is the user a guest user (then we have to user a different endpoint) */ isGuest: { type: Boolean, default: false }, /** * Set a display name that will be rendered as a tooltip * either the url, user or displayName property must be defined * specify just the displayname to generate a placeholder avatar without * trying to fetch the avatar based on the user id */ displayName: { type: String, default: void 0 }, /** * Set a size in px for the rendered avatar */ size: { type: Number, default: 32 }, /** * Placeholder avatars will be automatically generated when this is set to true */ allowPlaceholder: { type: Boolean, default: true }, /** * Disable the tooltip */ disableTooltip: { type: Boolean, default: false }, /** * Disable the menu */ disableMenu: { type: Boolean, default: false }, /** * Declares a custom tooltip when not null * Fallback will be the displayName * * requires disableTooltip not to be set to true */ tooltipMessage: { type: String, default: null }, /** * Declares username is not a user's name, when true. * Prevents loading user's avatar from server and forces generating colored initials, * i.e. if the user is a group */ isNoUser: { type: Boolean, default: false }, /** * Selector for the popover menu container */ menuContainer: { type: [String, Object, Element, Boolean], default: "body" } }, data() { return { avatarUrlLoaded: null, avatarSrcSetLoaded: null, userDoesNotExist: false, isAvatarLoaded: false, isMenuLoaded: false, contactsMenuLoading: false, contactsMenuActions: [], contactsMenuOpenState: false }; }, computed: { avatarAriaLabel() { var _a, _b; if (!this.hasMenu) { return; } if (this.canDisplayUserStatus || this.showUserStatusIconOnAvatar) { return _l10n.t("Avatar of {displayName}, {status}", { displayName: (_a = this.displayName) != null ? _a : this.user, status: NcUserStatusIcon.getUserStatusText(this.userStatus.status) }); } return _l10n.t("Avatar of {displayName}", { displayName: (_b = this.displayName) != null ? _b : this.user }); }, canDisplayUserStatus() { return this.showUserStatus && this.hasStatus && ["online", "away", "busy", "dnd"].includes(this.userStatus.status); }, showUserStatusIconOnAvatar() { return this.showUserStatus && this.showUserStatusCompact && this.hasStatus && this.userStatus.status !== "dnd" && this.userStatus.icon; }, /** * The user identifier, either the display name if set or the user property * If both properties are not set an empty string is returned */ userIdentifier() { if (this.isDisplayNameDefined) { return this.displayName; } if (this.isUserDefined) { return this.user; } return ""; }, isUserDefined() { return typeof this.user !== "undefined"; }, isDisplayNameDefined() { return typeof this.displayName !== "undefined"; }, isUrlDefined() { return typeof this.url !== "undefined"; }, hasMenu() { var _a; if (this.disableMenu) { return false; } if (this.isMenuLoaded) { return this.menu.length > 0; } return !(this.user === ((_a = auth.getCurrentUser()) == null ? void 0 : _a.uid) || this.userDoesNotExist || this.url); }, /** * True if initials should be shown as the user icon fallback */ showInitials() { return this.allowPlaceholder && this.userDoesNotExist && !(this.iconClass || this.$slots.icon); }, avatarStyle() { const style = { "--size": this.size + "px", lineHeight: this.size + "px", fontSize: Math.round(this.size * 0.45) + "px" }; return style; }, initialsWrapperStyle() { const { r, g, b } = usernameToColor.usernameToColor(this.userIdentifier); return { backgroundColor: "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", 0.1)") }; }, initialsStyle() { const { r, g, b } = usernameToColor.usernameToColor(this.userIdentifier); return { color: "rgb(".concat(r, ", ").concat(g, ", ").concat(b, ")") }; }, tooltip() { if (this.disableTooltip) { return false; } if (this.tooltipMessage) { return this.tooltipMessage; } return this.displayName; }, /** * Get the (max. two) initials of the user as uppcase string */ initials() { let initials = "?"; if (this.showInitials) { const user = this.userIdentifier.trim(); if (user === "") { return initials; } const filteredChars = user.match(/[\p{L}\p{N}\s]/gu); if (filteredChars == null) { return initials; } const filtered = filteredChars.join(""); const idx = filtered.lastIndexOf(" "); initials = String.fromCodePoint(filtered.codePointAt(0)); if (idx !== -1) { initials = initials.concat(String.fromCodePoint(filtered.codePointAt(idx + 1))); } } return initials.toLocaleUpperCase(); }, menu() { const actions = this.contactsMenuActions.map((item) => { const route = autolink.getRoute(this.$router, item.hyperlink); return { ncActionComponent: route ? Components_NcActionRouter : Components_NcActionLink, ncActionComponentProps: route ? { to: route, icon: item.icon } : { href: item.hyperlink, icon: item.icon }, text: item.title }; }); function escape(html) { const text = document.createTextNode(html); const p = document.createElement("p"); p.appendChild(text); return p.innerHTML; } if (this.showUserStatus && (this.userStatus.icon || this.userStatus.message)) { const emojiIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <text x="50%" y="50%" text-anchor="middle" style="dominant-baseline: central; font-size: 85%">'.concat(escape(this.userStatus.icon), "</text>\n </svg>"); return [{ ncActionComponent: Components_NcActionText, ncActionComponentProps: {}, iconSvg: this.userStatus.icon ? emojiIcon : void 0, text: "".concat(this.userStatus.message) }].concat(actions); } return actions; } }, watch: { url() { this.userDoesNotExist = false; this.loadAvatarUrl(); }, user() { this.userDoesNotExist = false; this.isMenuLoaded = false; this.loadAvatarUrl(); } }, mounted() { this.loadAvatarUrl(); eventBus.subscribe("settings:avatar:updated", this.loadAvatarUrl); eventBus.subscribe("settings:display-name:updated", this.loadAvatarUrl); if (this.showUserStatus && this.user && !this.isNoUser) { if (!this.preloadedUserStatus) { this.fetchUserStatus(this.user); } else { this.userStatus.status = this.preloadedUserStatus.status || ""; this.userStatus.message = this.preloadedUserStatus.message || ""; this.userStatus.icon = this.preloadedUserStatus.icon || ""; this.hasStatus = this.preloadedUserStatus.status !== null; } eventBus.subscribe("user_status:status.updated", this.handleUserStatusUpdated); } }, beforeDestroy() { eventBus.unsubscribe("settings:avatar:updated", this.loadAvatarUrl); eventBus.unsubscribe("settings:display-name:updated", this.loadAvatarUrl); if (this.showUserStatus && this.user && !this.isNoUser) { eventBus.unsubscribe("user_status:status.updated", this.handleUserStatusUpdated); } }, methods: { t: _l10n.t, handleUserStatusUpdated(state) { if (this.user === state.userId) { this.userStatus = { status: state.status, icon: state.icon, message: state.message }; } }, /** * Toggle the popover menu on click or enter * @param {KeyboardEvent|MouseEvent} event the UI event */ async toggleMenu(event) { if (event.type === "keydown" && event.key !== "Enter") { return; } if (!this.contactsMenuOpenState) { await this.fetchContactsMenu(); } this.contactsMenuOpenState = !this.contactsMenuOpenState; }, closeMenu() { this.contactsMenuOpenState = false; }, async fetchContactsMenu() { this.contactsMenuLoading = true; try { const user = encodeURIComponent(this.user); const { data } = await axios__default.default.post(router.generateUrl("contactsmenu/findOne"), "shareType=0&shareWith=".concat(user)); this.contactsMenuActions = data.topAction ? [data.topAction].concat(data.actions) : data.actions; } catch (e) { this.contactsMenuOpenState = false; } this.contactsMenuLoading = false; this.isMenuLoaded = true; }, /** * Handle avatar loading if user or url defined */ loadAvatarUrl() { this.isAvatarLoaded = false; if (!this.isUrlDefined && (!this.isUserDefined || this.isNoUser)) { this.isAvatarLoaded = true; this.userDoesNotExist = true; return; } if (this.isUrlDefined) { this.updateImageIfValid(this.url); return; } if (this.size <= 64) { const avatarUrl = this.avatarUrlGenerator(this.user, 64); const srcset = [ avatarUrl + " 1x", this.avatarUrlGenerator(this.user, 512) + " 8x" ].join(", "); this.updateImageIfValid(avatarUrl, srcset); } else { const avatarUrl = this.avatarUrlGenerator(this.user, 512); this.updateImageIfValid(avatarUrl); } }, /** * Generate an avatar url from the server's avatar endpoint * * @param {string} user the user id * @param {number} size the desired size * @return {string} */ avatarUrlGenerator(user, size) { var _a; let avatarUrl = getAvatarUrl.getAvatarUrl(user, size, this.isGuest); if (user === ((_a = auth.getCurrentUser()) == null ? void 0 : _a.uid) && typeof oc_userconfig !== "undefined") { avatarUrl += "?v=" + oc_userconfig.avatar.version; } return avatarUrl; }, /** * Check if the provided url is valid and update Avatar if so * * @param {string} url the avatar url * @param {Array} srcset the avatar srcset */ updateImageIfValid(url, srcset = null) { const userHasAvatar = getUserHasAvatar(this.user); if (this.isUserDefined && typeof userHasAvatar === "boolean") { this.isAvatarLoaded = true; this.avatarUrlLoaded = url; if (srcset) { this.avatarSrcSetLoaded = srcset; } if (userHasAvatar === false) { this.userDoesNotExist = true; } return; } const img = new Image(); img.onload = () => { this.avatarUrlLoaded = url; if (srcset) { this.avatarSrcSetLoaded = srcset; } this.isAvatarLoaded = true; setUserHasAvatar(this.user, true); }; img.onerror = () => { console.debug("Invalid avatar url", url); this.avatarUrlLoaded = null; this.avatarSrcSetLoaded = null; this.userDoesNotExist = true; this.isAvatarLoaded = false; setUserHasAvatar(this.user, false); }; if (srcset) { img.srcset = srcset; } img.src = url; } } }; var _sfc_render = function render() { var _vm = this, _c = _vm._self._c; return _c("span", { directives: [{ name: "click-outside", rawName: "v-click-outside", value: _vm.closeMenu, expression: "closeMenu" }], ref: "main", staticClass: "avatardiv popovermenu-wrapper", class: { "avatardiv--unknown": _vm.userDoesNotExist, "avatardiv--with-menu": _vm.hasMenu, "avatardiv--with-menu-loading": _vm.contactsMenuLoading }, style: _vm.avatarStyle }, [_vm._t("icon", function() { return [_vm.iconClass ? _c("span", { staticClass: "avatar-class-icon", class: _vm.iconClass }) : _vm.isAvatarLoaded && !_vm.userDoesNotExist ? _c("img", { attrs: { "src": _vm.avatarUrlLoaded, "srcset": _vm.avatarSrcSetLoaded, "alt": "" } }) : _vm._e()]; }), _vm.hasMenu && _vm.menu.length === 0 ? _c("NcButton", { staticClass: "action-item action-item__menutoggle", attrs: { "type": "tertiary-no-background", "aria-label": _vm.avatarAriaLabel, "title": _vm.tooltip }, on: { "click": _vm.toggleMenu }, scopedSlots: _vm._u([{ key: "icon", fn: function() { return [_vm.contactsMenuLoading ? _c("NcLoadingIcon") : _c("DotsHorizontal", { attrs: { "size": 20 } })]; }, proxy: true }], null, false, 2617833509) }) : _vm.hasMenu ? _c("NcActions", { attrs: { "force-menu": "", "manual-open": "", "type": "tertiary-no-background", "container": _vm.menuContainer, "open": _vm.contactsMenuOpenState, "aria-label": _vm.avatarAriaLabel, "title": _vm.tooltip }, on: { "update:open": function($event) { _vm.contactsMenuOpenState = $event; }, "click": _vm.toggleMenu }, scopedSlots: _vm._u([_vm.contactsMenuLoading ? { key: "icon", fn: function() { return [_c("NcLoadingIcon")]; }, proxy: true } : null], null, true) }, _vm._l(_vm.menu, function(item, key) { return _c(item.ncActionComponent, _vm._b({ key, tag: "component", scopedSlots: _vm._u([item.iconSvg ? { key: "icon", fn: function() { return [_c("NcIconSvgWrapper", { attrs: { "svg": item.iconSvg } })]; }, proxy: true } : null], null, true) }, "component", item.ncActionComponentProps, false), [_vm._v(" " + _vm._s(item.text) + " ")]); }), 1) : _vm._e(), _vm.showUserStatusIconOnAvatar ? _c("span", { staticClass: "avatardiv__user-status avatardiv__user-status--icon" }, [_vm._v(" " + _vm._s(_vm.userStatus.icon) + " ")]) : _vm.canDisplayUserStatus ? _c("NcUserStatusIcon", { staticClass: "avatardiv__user-status", attrs: { "status": _vm.userStatus.status, "aria-hidden": String(_vm.hasMenu) } }) : _vm._e(), _vm.showInitials ? _c("span", { staticClass: "avatardiv__initials-wrapper", style: _vm.initialsWrapperStyle }, [_c("span", { staticClass: "avatardiv__initials", style: _vm.initialsStyle }, [_vm._v(" " + _vm._s(_vm.initials) + " ")])]) : _vm._e()], 2); }; var _sfc_staticRenderFns = []; var __component__ = /* @__PURE__ */ _pluginVue2_normalizer.normalizeComponent( _sfc_main, _sfc_render, _sfc_staticRenderFns, false, null, "e7e86f59" ); const NcAvatar = __component__.exports; exports.NcAvatar = NcAvatar; exports.userStatus = userStatus;