UNPKG

@microsoft/mgt

Version:
455 lines • 17.2 kB
/** * ------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. * See License in the project root for license information. * ------------------------------------------------------------------------------------------- */ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { customElement, html, property } from 'lit-element'; import { classMap } from 'lit-html/directives/class-map'; import { Providers } from '../../Providers'; import { ProviderState } from '../../providers/IProvider'; import '../../styles/fabric-icon-font'; import { getEmailFromGraphEntity } from '../../utils/GraphHelpers'; import '../sub-components/mgt-flyout/mgt-flyout'; import { MgtTemplatedComponent } from '../templatedComponent'; import { PersonCardInteraction } from './../PersonCardInteraction'; import { styles } from './mgt-person-css'; /** * The person component is used to display a person or contact by using their photo, name, and/or email address. * * @export * @class MgtPerson * @extends {MgtTemplatedComponent} */ let MgtPerson = class MgtPerson extends MgtTemplatedComponent { constructor() { super(); /** * Sets how the person-card is invoked * Set to PersonCardInteraction.none to not show the card * * @type {PersonCardInteraction} * @memberof MgtPerson */ this.personCardInteraction = PersonCardInteraction.none; this.isPersonCardVisible = false; this.personCardShouldRender = false; this.handleWindowClick = this.handleWindowClick.bind(this); } /** * Array of styles to apply to the element. The styles should be defined * user the `css` tag function. */ static get styles() { return styles; } /** * Synchronizes property values when attributes change. * * @param {*} name * @param {*} oldValue * @param {*} newValue * @memberof MgtPerson */ attributeChangedCallback(name, oldval, newval) { super.attributeChangedCallback(name, oldval, newval); if ((name === 'person-query' || name === 'user-id') && oldval !== newval) { this.personDetails = null; this.loadData(); } } /** * Invoked when the element is first updated. Implement to perform one time * work on the element after update. * * Setting properties inside this method will trigger the element to update * again after this update cycle completes. * * * @param _changedProperties Map of changed properties with old values */ firstUpdated() { Providers.onProviderUpdated(() => this.loadData()); this.loadData(); } /** * Invoked each time the custom element is appended into a document-connected element * * @memberof MgtPerson */ connectedCallback() { super.connectedCallback(); window.addEventListener('click', this.handleWindowClick); } /** * Invoked each time the custom element is disconnected from the document's DOM * * @memberof MgtPerson */ disconnectedCallback() { window.removeEventListener('click', this.handleWindowClick); super.disconnectedCallback(); } /** * Invoked on each update to perform rendering tasks. This method must return * a lit-html TemplateResult. Setting properties inside this method will *not* * trigger the element to update. */ render() { const image = this.getImage(); const person = this.renderTemplate('default', { person: this.personDetails, personImage: image }) || html ` <div class="person-root"> ${this.renderImage(image)} ${this.renderDetails()} </div> `; return html ` <div class="root" @click=${this.handleMouseClick} @mouseenter=${this.handleMouseEnter} @mouseleave=${this.handleMouseLeave} > ${this.renderFlyout(person)} </div> `; } /** * Invoked whenever the element is updated. Implement to perform * post-updating tasks via DOM APIs, for example, focusing an element. * * Setting properties inside this method will trigger the element to update * again after this update cycle completes. * * * @param changedProperties Map of changed properties with old values */ updated(changedProps) { super.updated(changedProps); const initials = this.renderRoot.querySelector('.initials-text'); if (initials && initials.parentNode && initials.parentNode.getBoundingClientRect) { const parent = initials.parentNode; const height = parent.getBoundingClientRect().height; initials.style.fontSize = `${height * 0.5}px`; } } handleWindowClick(e) { if (this.isPersonCardVisible && e.target !== this) { this.hidePersonCard(); } } loadData() { return __awaiter(this, void 0, void 0, function* () { const provider = Providers.globalProvider; if (!provider || provider.state === ProviderState.Loading) { return; } if (provider.state === ProviderState.SignedOut) { this.personDetails = null; return; } // personDetails.personImage is a toolkit injected property to pass image between components // an optimization to avoid fetching the image when unnecessary if (this.personDetails) { // in some cases we might only have name or email, but need to find the image // use @ for the image value to search for an image if (this.personImage && this.personImage === '@' && !this.personDetails.personImage) { this.loadImage(); } return; } if (this.userId || (this.personQuery && this.personQuery === 'me')) { const batch = provider.graph.createBatch(); if (this.userId) { batch.get('user', `/users/${this.userId}`, ['user.readbasic.all']); batch.get('photo', `users/${this.userId}/photo/$value`, ['user.readbasic.all']); } else { batch.get('user', 'me', ['user.read']); batch.get('photo', 'me/photo/$value', ['user.read']); } const response = yield batch.execute(); this.personDetails = response.user; this.personImage = response.photo; this.personDetails.personImage = response.photo; } else if (!this.personDetails && this.personQuery) { const people = yield provider.graph.findPerson(this.personQuery); if (people && people.length > 0) { const person = people[0]; this.personDetails = person; this.loadImage(); } } }); } loadImage() { return __awaiter(this, void 0, void 0, function* () { const provider = Providers.globalProvider; const person = this.personDetails; let image; if (person.userPrincipalName) { const userPrincipalName = person.userPrincipalName; image = yield provider.graph.getUserPhoto(userPrincipalName); } else { const email = getEmailFromGraphEntity(person); if (email) { // try to find a user by e-mail const users = yield provider.graph.findUserByEmail(email); if (users && users.length) { if (users[0].personType && users[0].personType.subclass === 'OrganizationUser') { image = yield provider.graph.getUserPhoto(users[0].scoredEmailAddresses[0].address); } else { const contactId = users[0].id; image = yield provider.graph.getContactPhoto(contactId); } } } } if (image) { this.personImage = image; this.personDetails.personImage = image; } this.requestUpdate(); }); } handleMouseClick(e) { if (this.personCardInteraction !== PersonCardInteraction.none && !this.isPersonCardVisible) { this.showPersonCard(); } } handleMouseEnter(e) { clearTimeout(this._mouseEnterTimeout); clearTimeout(this._mouseLeaveTimeout); if (this.personCardInteraction !== PersonCardInteraction.hover) { return; } this._mouseEnterTimeout = setTimeout(this.showPersonCard.bind(this), 500); } handleMouseLeave(e) { clearTimeout(this._mouseEnterTimeout); clearTimeout(this._mouseLeaveTimeout); this._mouseLeaveTimeout = setTimeout(this.hidePersonCard.bind(this), 500); } showPersonCard() { if (!this.personCardShouldRender) { this.personCardShouldRender = true; } this.isPersonCardVisible = true; } hidePersonCard() { this.isPersonCardVisible = false; const personCard = (this.querySelector('mgt-person-card') || this.renderRoot.querySelector('mgt-person-card')); if (personCard) { personCard.isExpanded = false; } } getImage() { if (this.personImage && this.personImage !== '@') { return this.personImage; } else if (this.personDetails && this.personDetails.personImage) { return this.personDetails.personImage; } return null; } renderFlyout(anchor) { if (this.personCardInteraction === PersonCardInteraction.none) { return anchor; } const image = this.getImage(); const flyout = this.personCardShouldRender ? html ` <div slot="flyout" class="flyout"> ${this.renderTemplate('person-card', { person: this.personDetails, personImage: image }) || html ` <mgt-person-card .personDetails=${this.personDetails} .personImage=${image}> </mgt-person-card> `} </div> ` : null; return html ` <mgt-flyout .isOpen=${this.isPersonCardVisible}> ${anchor} ${flyout} </mgt-flyout> `; } renderDetails() { if (this.showEmail || this.showName) { const isLarge = this.showEmail && this.showName; const detailsClasses = { Details: true, small: !isLarge }; return html ` <span class="${classMap(detailsClasses)}"> ${this.renderNameAndEmail()} </span> `; } return null; } renderImage(image) { if (this.personDetails) { const title = this.personCardInteraction === PersonCardInteraction.none ? this.personDetails.displayName : ''; const isLarge = this.showEmail && this.showName; const imageClasses = { initials: !image, 'row-span-2': isLarge, small: !isLarge, 'user-avatar': true }; let imageHtml; if (image) { imageHtml = html ` <img alt=${title} src=${image} /> `; } else { const initials = this.getInitials(); imageHtml = html ` <span class="initials-text" aria-label="${initials}"> ${initials} </span> `; } return html ` <div class=${classMap(imageClasses)} title=${title} aria-label=${title}> ${imageHtml} </div> `; } return this.renderEmptyImage(); } renderEmptyImage() { const isLarge = this.showEmail && this.showName; const imageClasses = { 'avatar-icon': true, 'ms-Icon': true, 'ms-Icon--Contact': true, 'row-span-2': isLarge, small: !isLarge }; return html ` <i class=${classMap(imageClasses)}></i> `; } renderNameAndEmail() { if (!this.personDetails || (!this.showEmail && !this.showName)) { return; } const nameView = this.showName ? html ` <div class="user-name" aria-label="${this.personDetails.displayName}">${this.personDetails.displayName}</div> ` : null; let emailView; if (this.showEmail) { const email = getEmailFromGraphEntity(this.personDetails); emailView = html ` <div class="user-email" aria-label="${email}">${email}</div> `; } return html ` ${nameView} ${emailView} `; } getInitials() { if (!this.personDetails) { return ''; } let initials = ''; if (this.personDetails.givenName) { initials += this.personDetails.givenName[0].toUpperCase(); } if (this.personDetails.surname) { initials += this.personDetails.surname[0].toUpperCase(); } if (!initials && this.personDetails.displayName) { const name = this.personDetails.displayName.split(' '); for (let i = 0; i < 2 && i < name.length; i++) { if (name[i][0].match(/[a-z]/i)) { // check if letter initials += name[i][0].toUpperCase(); } } } return initials; } }; __decorate([ property({ attribute: 'person-query' }) ], MgtPerson.prototype, "personQuery", void 0); __decorate([ property({ attribute: 'user-id' }) ], MgtPerson.prototype, "userId", void 0); __decorate([ property({ attribute: 'show-name', type: Boolean }) ], MgtPerson.prototype, "showName", void 0); __decorate([ property({ attribute: 'show-email', type: Boolean }) ], MgtPerson.prototype, "showEmail", void 0); __decorate([ property({ attribute: 'person-details', type: Object }) ], MgtPerson.prototype, "personDetails", void 0); __decorate([ property({ attribute: 'person-image', reflect: true, type: String }) ], MgtPerson.prototype, "personImage", void 0); __decorate([ property({ attribute: 'person-card', converter: (value, type) => { value = value.toLowerCase(); if (typeof PersonCardInteraction[value] === 'undefined') { return PersonCardInteraction.none; } else { return PersonCardInteraction[value]; } } }) ], MgtPerson.prototype, "personCardInteraction", void 0); __decorate([ property({ attribute: false }) ], MgtPerson.prototype, "isPersonCardVisible", void 0); __decorate([ property({ attribute: false }) ], MgtPerson.prototype, "personCardShouldRender", void 0); MgtPerson = __decorate([ customElement('mgt-person') ], MgtPerson); export { MgtPerson }; //# sourceMappingURL=mgt-person.js.map