@microsoft/mgt
Version:
The Microsoft Graph Toolkit
297 lines • 11 kB
JavaScript
/**
* -------------------------------------------------------------------------------------------
* 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 { Providers } from '../../Providers';
import { ProviderState } from '../../providers/IProvider';
import '../../styles/fabric-icon-font';
import { MgtBaseComponent } from '../baseComponent';
import '../mgt-person/mgt-person';
import { styles } from './mgt-login-css';
/**
* Web component button and flyout control to facilitate Microsoft identity platform authentication
*
* @export
* @class MgtLogin
* @extends {MgtBaseComponent}
*/
let MgtLogin = class MgtLogin extends MgtBaseComponent {
constructor() {
super();
this._openLeft = false;
/**
* determines if login menu popup should be showing
* @type {boolean}
*/
this._showMenu = false;
/**
* determines if login component is in loading state
* @type {boolean}
*/
this._loading = true;
Providers.onProviderUpdated(() => this.loadState());
this.loadState();
this.handleWindowClick = this.handleWindowClick.bind(this);
}
/**
* Array of styles to apply to the element. The styles should be defined
* using the `css` tag function.
*/
static get styles() {
return styles;
}
/**
* Invoked each time the custom element is appended into a document-connected element
*
* @memberof MgtLogin
*/
connectedCallback() {
super.connectedCallback();
window.addEventListener('click', this.handleWindowClick);
}
/**
* Invoked each time the custom element is disconnected from the document's DOM
*
* @memberof MgtLogin
*/
disconnectedCallback() {
window.removeEventListener('click', this.handleWindowClick);
super.disconnectedCallback();
}
/**
* Initiate login
*
* @returns {Promise<void>}
* @memberof MgtLogin
*/
login() {
return __awaiter(this, void 0, void 0, function* () {
if (this.userDetails) {
return;
}
const provider = Providers.globalProvider;
if (provider && provider.login) {
yield provider.login();
if (provider.state === ProviderState.SignedIn) {
this.fireCustomEvent('loginCompleted');
}
else {
this.fireCustomEvent('loginFailed');
}
yield this.loadState();
}
});
}
/**
*
* Initiate logout
* @returns {Promise<void>}
* @memberof MgtLogin
*/
logout() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.fireCustomEvent('logoutInitiated')) {
return;
}
const provider = Providers.globalProvider;
if (provider && provider.logout) {
yield provider.logout();
this.userDetails = null;
this._showMenu = false;
this.fireCustomEvent('logoutCompleted');
}
});
}
/**
* 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) {
if (changedProps.get('_showMenu') === false) {
// get popup bounds
const popup = this.renderRoot.querySelector('.popup');
if (popup && popup.animate) {
this._popupRect = popup.getBoundingClientRect();
// invert variables
const deltaX = this._loginButtonRect.left - this._popupRect.left;
const deltaY = this._loginButtonRect.top - this._popupRect.top;
const deltaW = this._loginButtonRect.width / this._popupRect.width;
const deltaH = this._loginButtonRect.height / this._popupRect.height;
// play back
popup.animate([
{
backgroundColor: '#eaeaea',
transform: `
translate(${deltaX}px, ${deltaY}px)
scale(${deltaW}, ${deltaH})
`,
transformOrigin: 'top left'
},
{
backgroundColor: 'white',
transform: 'none',
transformOrigin: 'top left'
}
], {
duration: 100,
easing: 'ease-in-out',
fill: 'both'
});
}
}
}
/**
* 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 content = this.userDetails ? this.renderLoggedIn() : this.renderLogIn();
return html `
<div class="root">
<button ?disabled="${this._loading}" class="login-button" =${this.onClick} role="button">
${content}
</button>
${this.renderMenu()}
</div>
`;
}
handleWindowClick(e) {
if (e.target === this) {
return;
}
// get popup bounds
const popup = this.renderRoot.querySelector('.popup');
if (popup) {
this._popupRect = popup.getBoundingClientRect();
this._showMenu = false;
}
}
renderLogIn() {
return html `
<i class="login-icon ms-Icon ms-Icon--Contact"></i>
<span aria-label="Sign In">
Sign In
</span>
`;
}
renderLoggedIn() {
if (this.userDetails) {
return html `
<mgt-person .personDetails=${this.userDetails} .personImage=${this._image} show-name />
`;
}
else {
return this.renderLogIn();
}
}
renderMenu() {
if (!this.userDetails) {
return;
}
const personComponent = html `
<mgt-person .personDetails=${this.userDetails} .personImage=${this._image} show-name show-email />
`;
return html `
<div class="popup ${this._openLeft ? 'open-left' : ''} ${this._showMenu ? 'show-menu' : ''}">
<div class="popup-content">
<div>
${personComponent}
</div>
<div class="popup-commands">
<ul>
<li>
<button class="popup-command" =${this.logout} aria-label="Sign Out">
Sign Out
</button>
</li>
</ul>
</div>
</div>
</div>
`;
}
loadState() {
return __awaiter(this, void 0, void 0, function* () {
const provider = Providers.globalProvider;
if (provider) {
this._loading = true;
if (provider.state === ProviderState.SignedIn) {
const batch = provider.graph.createBatch();
batch.get('me', 'me', ['user.read']);
batch.get('photo', 'me/photo/$value', ['user.read']);
const response = yield batch.execute();
this._image = response.photo;
this.userDetails = response.me;
}
else if (provider.state === ProviderState.SignedOut) {
this.userDetails = null;
}
else {
// Loading
this._showMenu = false;
return;
}
}
this._loading = false;
});
}
onClick(event) {
if (this.userDetails) {
// get login button bounds
const loginButton = this.renderRoot.querySelector('.login-button');
if (loginButton) {
this._loginButtonRect = loginButton.getBoundingClientRect();
const leftEdge = this._loginButtonRect.left;
const rightEdge = (window.innerWidth || document.documentElement.clientWidth) - this._loginButtonRect.right;
this._openLeft = rightEdge < leftEdge;
this._showMenu = !this._showMenu;
}
}
else {
if (this.fireCustomEvent('loginInitiated')) {
this.login();
}
}
}
};
__decorate([
property({
attribute: 'user-details',
type: Object
})
], MgtLogin.prototype, "userDetails", void 0);
__decorate([
property({ attribute: false })
], MgtLogin.prototype, "_showMenu", void 0);
__decorate([
property({ attribute: false })
], MgtLogin.prototype, "_loading", void 0);
MgtLogin = __decorate([
customElement('mgt-login')
], MgtLogin);
export { MgtLogin };
//# sourceMappingURL=mgt-login.js.map