@microsoft/teams-js
Version:
Microsoft Client SDK for building app for Microsoft teams
1,247 lines (1,241 loc) • 55.4 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("microsoftTeams", [], factory);
else if(typeof exports === 'object')
exports["microsoftTeams"] = factory();
else
root["microsoftTeams"] = factory();
})(window, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(__webpack_require__(1));
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
t[p[i]] = s[p[i]];
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var version = "1.4.1";
var validOrigins = [
"https://teams.microsoft.com",
"https://teams.microsoft.us",
"https://int.teams.microsoft.com",
"https://devspaces.skype.com",
"https://ssauth.skype.com",
"http://dev.local",
"http://dev.local:8080",
"https://msft.spoppe.com",
"https://*.sharepoint.com",
"https://*.sharepoint-df.com",
"https://*.sharepointonline.com",
"https://outlook.office.com",
"https://outlook-sdf.office.com"
];
// This will return a reg expression a given url
function generateRegExpFromUrl(url) {
var urlRegExpPart = "^";
var urlParts = url.split(".");
for (var j = 0; j < urlParts.length; j++) {
urlRegExpPart += (j > 0 ? "[.]" : "") + urlParts[j].replace("*", "[^/^.]+");
}
urlRegExpPart += "$";
return urlRegExpPart;
}
// This will return a reg expression for list of url
function generateRegExpFromUrls(urls) {
var urlRegExp = "";
for (var i = 0; i < urls.length; i++) {
urlRegExp += (i === 0 ? "" : "|") + generateRegExpFromUrl(urls[i]);
}
return new RegExp(urlRegExp);
}
var validOriginRegExp = generateRegExpFromUrls(validOrigins);
var handlers = {};
// Ensure these declarations stay in sync with the framework.
var frameContexts = {
settings: "settings",
content: "content",
authentication: "authentication",
remove: "remove",
task: "task"
};
/**
* Namespace to interact with the menu-specific part of the SDK.
* This object is used to show View Configuration, Action Menu and Navigation Bar Menu.
*
* @private
* Hide from docs until feature is complete
*/
var menus;
(function (menus) {
/**
* Represents information about menu item for Action Menu and Navigation Bar Menu.
*/
var MenuItem = /** @class */ (function () {
function MenuItem() {
/**
* State of the menu item
*/
this.enabled = true;
}
return MenuItem;
}());
menus.MenuItem = MenuItem;
/**
* Represents information about type of list to display in Navigation Bar Menu.
*/
var MenuListType;
(function (MenuListType) {
MenuListType["dropDown"] = "dropDown";
MenuListType["popOver"] = "popOver";
})(MenuListType = menus.MenuListType || (menus.MenuListType = {}));
var navBarMenuItemPressHandler;
handlers["navBarMenuItemPress"] = handleNavBarMenuItemPress;
var actionMenuItemPressHandler;
handlers["actionMenuItemPress"] = handleActionMenuItemPress;
var viewConfigItemPressHandler;
handlers["setModuleView"] = handleViewConfigItemPress;
/**
* Registers list of view configurations and it's handler.
* Handler is responsible for listening selection of View Configuration.
* @param viewConfig List of view configurations. Minimum 1 value is required.
* @param handler The handler to invoke when the user selects view configuration.
*/
function setUpViews(viewConfig, handler) {
ensureInitialized();
viewConfigItemPressHandler = handler;
sendMessageRequest(parentWindow, "setUpViews", [viewConfig]);
}
menus.setUpViews = setUpViews;
function handleViewConfigItemPress(id) {
if (!viewConfigItemPressHandler || !viewConfigItemPressHandler(id)) {
ensureInitialized();
sendMessageRequest(parentWindow, "viewConfigItemPress", [id]);
}
}
/**
* Used to set menu items on the Navigation Bar. If icon is available, icon will be shown, otherwise title will be shown.
* @param items List of MenuItems for Navigation Bar Menu.
* @param handler The handler to invoke when the user selects menu item.
*/
function setNavBarMenu(items, handler) {
ensureInitialized();
navBarMenuItemPressHandler = handler;
sendMessageRequest(parentWindow, "setNavBarMenu", [items]);
}
menus.setNavBarMenu = setNavBarMenu;
function handleNavBarMenuItemPress(id) {
if (!navBarMenuItemPressHandler || !navBarMenuItemPressHandler(id)) {
ensureInitialized();
sendMessageRequest(parentWindow, "handleNavBarMenuItemPress", [id]);
}
}
/**
* Used to show Action Menu.
* @param params Parameters for Menu Parameters
* @param handler The handler to invoke when the user selects menu item.
*/
function showActionMenu(params, handler) {
ensureInitialized();
actionMenuItemPressHandler = handler;
sendMessageRequest(parentWindow, "showActionMenu", [params]);
}
menus.showActionMenu = showActionMenu;
function handleActionMenuItemPress(id) {
if (!actionMenuItemPressHandler || !actionMenuItemPressHandler(id)) {
ensureInitialized();
sendMessageRequest(parentWindow, "handleActionMenuItemPress", [id]);
}
}
})(menus = exports.menus || (exports.menus = {}));
// This indicates whether initialize was called (started).
// It does not indicate whether initialization is complete. That can be inferred by whether parentOrigin is set.
var initializeCalled = false;
var isFramelessWindow = false;
var currentWindow;
var parentWindow;
var parentOrigin;
var parentMessageQueue = [];
var childWindow;
var childOrigin;
var childMessageQueue = [];
var nextMessageId = 0;
var callbacks = {};
var frameContext;
var hostClientType;
var printCapabilityEnabled = false;
var themeChangeHandler;
handlers["themeChange"] = handleThemeChange;
var fullScreenChangeHandler;
handlers["fullScreenChange"] = handleFullScreenChange;
var backButtonPressHandler;
handlers["backButtonPress"] = handleBackButtonPress;
var beforeUnloadHandler;
handlers["beforeUnload"] = handleBeforeUnload;
var changeSettingsHandler;
handlers["changeSettings"] = handleChangeSettings;
/**
* Initializes the library. This must be called before any other SDK calls
* but after the frame is loaded successfully.
*/
function initialize(hostWindow) {
if (hostWindow === void 0) { hostWindow = window; }
if (initializeCalled) {
// Independent components might not know whether the SDK is initialized so might call it to be safe.
// Just no-op if that happens to make it easier to use.
return;
}
initializeCalled = true;
// Undocumented field used to mock the window for unit tests
currentWindow = hostWindow;
// Listen for messages post to our window
var messageListener = function (evt) { return processMessage(evt); };
// If we are in an iframe, our parent window is the one hosting us (i.e., window.parent); otherwise,
// it's the window that opened us (i.e., window.opener)
parentWindow =
currentWindow.parent !== currentWindow.self
? currentWindow.parent
: currentWindow.opener;
if (!parentWindow) {
isFramelessWindow = true;
window.onNativeMessage = handleParentMessage;
}
else {
// For iFrame scenario, add listener to listen 'message'
currentWindow.addEventListener("message", messageListener, false);
}
try {
// Send the initialized message to any origin, because at this point we most likely don't know the origin
// of the parent window, and this message contains no data that could pose a security risk.
parentOrigin = "*";
var messageId = sendMessageRequest(parentWindow, "initialize", [version]);
callbacks[messageId] = function (context, clientType) {
frameContext = context;
hostClientType = clientType;
};
}
finally {
parentOrigin = null;
}
// Undocumented function used to clear state between unit tests
this._uninitialize = function () {
if (frameContext) {
registerOnThemeChangeHandler(null);
registerFullScreenHandler(null);
registerBackButtonHandler(null);
registerBeforeUnloadHandler(null);
}
if (frameContext === frameContexts.settings) {
settings.registerOnSaveHandler(null);
}
if (frameContext === frameContexts.remove) {
settings.registerOnRemoveHandler(null);
}
if (!isFramelessWindow) {
currentWindow.removeEventListener("message", messageListener, false);
}
initializeCalled = false;
parentWindow = null;
parentOrigin = null;
parentMessageQueue = [];
childWindow = null;
childOrigin = null;
childMessageQueue = [];
nextMessageId = 0;
callbacks = {};
frameContext = null;
hostClientType = null;
isFramelessWindow = false;
};
}
exports.initialize = initialize;
/**
* Initializes the library. This must be called before any other SDK calls
* but after the frame is loaded successfully.
*/
function _uninitialize() { }
exports._uninitialize = _uninitialize;
/**
* Enable print capability to support printing page using Ctrl+P and cmd+P
*/
function enablePrintCapability() {
if (!printCapabilityEnabled) {
printCapabilityEnabled = true;
ensureInitialized();
// adding ctrl+P and cmd+P handler
document.addEventListener("keydown", function (event) {
if ((event.ctrlKey || event.metaKey) && event.keyCode === 80) {
print();
event.cancelBubble = true;
event.preventDefault();
event.stopImmediatePropagation();
}
});
}
}
exports.enablePrintCapability = enablePrintCapability;
/**
* default print handler
*/
function print() {
window.print();
}
exports.print = print;
/**
* Retrieves the current context the frame is running in.
* @param callback The callback to invoke when the {@link Context} object is retrieved.
*/
function getContext(callback) {
ensureInitialized();
var messageId = sendMessageRequest(parentWindow, "getContext");
callbacks[messageId] = callback;
}
exports.getContext = getContext;
/**
* Registers a handler for theme changes.
* Only one handler can be registered at a time. A subsequent registration replaces an existing registration.
* @param handler The handler to invoke when the user changes their theme.
*/
function registerOnThemeChangeHandler(handler) {
ensureInitialized();
themeChangeHandler = handler;
handler &&
sendMessageRequest(parentWindow, "registerHandler", ["themeChange"]);
}
exports.registerOnThemeChangeHandler = registerOnThemeChangeHandler;
function handleThemeChange(theme) {
if (themeChangeHandler) {
themeChangeHandler(theme);
}
if (childWindow) {
sendMessageRequest(childWindow, "themeChange", [theme]);
}
}
/**
* Registers a handler for changes from or to full-screen view for a tab.
* Only one handler can be registered at a time. A subsequent registration replaces an existing registration.
* @param handler The handler to invoke when the user toggles full-screen view for a tab.
*/
function registerFullScreenHandler(handler) {
ensureInitialized();
fullScreenChangeHandler = handler;
handler &&
sendMessageRequest(parentWindow, "registerHandler", ["fullScreen"]);
}
exports.registerFullScreenHandler = registerFullScreenHandler;
function handleFullScreenChange(isFullScreen) {
if (fullScreenChangeHandler) {
fullScreenChangeHandler(isFullScreen);
}
}
/**
* Registers a handler for user presses of the Team client's back button. Experiences that maintain an internal
* navigation stack should use this handler to navigate the user back within their frame. If an app finds
* that after running its back button handler it cannot handle the event it should call the navigateBack
* method to ask the Teams client to handle it instead.
* @param handler The handler to invoke when the user presses their Team client's back button.
*/
function registerBackButtonHandler(handler) {
ensureInitialized();
backButtonPressHandler = handler;
handler &&
sendMessageRequest(parentWindow, "registerHandler", ["backButton"]);
}
exports.registerBackButtonHandler = registerBackButtonHandler;
function handleBackButtonPress() {
if (!backButtonPressHandler || !backButtonPressHandler()) {
navigateBack();
}
}
/**
* Navigates back in the Teams client. See registerBackButtonHandler for more information on when
* it's appropriate to use this method.
*/
function navigateBack() {
ensureInitialized();
var messageId = sendMessageRequest(parentWindow, "navigateBack", []);
callbacks[messageId] = function (success) {
if (!success) {
throw new Error("Back navigation is not supported in the current client or context.");
}
};
}
exports.navigateBack = navigateBack;
/**
* Registers a handler to be called before the page is unloaded.
* @param handler The handler to invoke before the page is unloaded. If this handler returns true the page should
* invoke the readyToUnload function provided to it once it's ready to be unloaded.
*/
function registerBeforeUnloadHandler(handler) {
ensureInitialized();
beforeUnloadHandler = handler;
handler &&
sendMessageRequest(parentWindow, "registerHandler", ["beforeUnload"]);
}
exports.registerBeforeUnloadHandler = registerBeforeUnloadHandler;
function handleBeforeUnload() {
var readyToUnload = function () {
sendMessageRequest(parentWindow, "readyToUnload", []);
};
if (!beforeUnloadHandler || !beforeUnloadHandler(readyToUnload)) {
readyToUnload();
}
}
/**
* Registers a handler for when the user reconfigurated tab
* @param handler The handler to invoke when the user click on Settings.
*/
function registerChangeSettingsHandler(handler) {
ensureInitialized(frameContexts.content);
changeSettingsHandler = handler;
handler && sendMessageRequest(parentWindow, "registerHandler", ["changeSettings"]);
}
exports.registerChangeSettingsHandler = registerChangeSettingsHandler;
function handleChangeSettings() {
if (changeSettingsHandler) {
changeSettingsHandler();
}
}
/**
* Navigates the frame to a new cross-domain URL. The domain of this URL must match at least one of the
* valid domains specified in the validDomains block of the manifest; otherwise, an exception will be
* thrown. This function needs to be used only when navigating the frame to a URL in a different domain
* than the current one in a way that keeps the app informed of the change and allows the SDK to
* continue working.
* @param url The URL to navigate the frame to.
*/
function navigateCrossDomain(url) {
ensureInitialized(frameContexts.content, frameContexts.settings, frameContexts.remove, frameContexts.task);
var messageId = sendMessageRequest(parentWindow, "navigateCrossDomain", [
url
]);
callbacks[messageId] = function (success) {
if (!success) {
throw new Error("Cross-origin navigation is only supported for URLs matching the pattern registered in the manifest.");
}
};
}
exports.navigateCrossDomain = navigateCrossDomain;
/**
* Allows an app to retrieve for this user tabs that are owned by this app.
* If no TabInstanceParameters are passed, the app defaults to favorite teams and favorite channels.
* @param callback The callback to invoke when the {@link TabInstanceParameters} object is retrieved.
* @param tabInstanceParameters OPTIONAL Flags that specify whether to scope call to favorite teams or channels.
*/
function getTabInstances(callback, tabInstanceParameters) {
ensureInitialized();
var messageId = sendMessageRequest(parentWindow, "getTabInstances", [
tabInstanceParameters
]);
callbacks[messageId] = callback;
}
exports.getTabInstances = getTabInstances;
/**
* @private
* Hide from docs
* ------
* Allows an app to retrieve information of all user joined teams
* @param callback The callback to invoke when the {@link TeamInstanceParameters} object is retrieved.
* @param teamInstanceParameters OPTIONAL Flags that specify whether to scope call to favorite teams
*/
function getUserJoinedTeams(callback, teamInstanceParameters) {
ensureInitialized();
var messageId = sendMessageRequest(parentWindow, "getUserJoinedTeams", [
teamInstanceParameters
]);
callbacks[messageId] = callback;
}
exports.getUserJoinedTeams = getUserJoinedTeams;
/**
* Allows an app to retrieve the most recently used tabs for this user.
* @param callback The callback to invoke when the {@link TabInformation} object is retrieved.
* @param tabInstanceParameters OPTIONAL Ignored, kept for future use
*/
function getMruTabInstances(callback, tabInstanceParameters) {
ensureInitialized();
var messageId = sendMessageRequest(parentWindow, "getMruTabInstances", [
tabInstanceParameters
]);
callbacks[messageId] = callback;
}
exports.getMruTabInstances = getMruTabInstances;
/**
* Shares a deep link that a user can use to navigate back to a specific state in this page.
* @param deepLinkParameters ID and label for the link and fallback URL.
*/
function shareDeepLink(deepLinkParameters) {
ensureInitialized(frameContexts.content);
sendMessageRequest(parentWindow, "shareDeepLink", [
deepLinkParameters.subEntityId,
deepLinkParameters.subEntityLabel,
deepLinkParameters.subEntityWebUrl
]);
}
exports.shareDeepLink = shareDeepLink;
/**
* @private
* Hide from docs.
* ------
* Opens a client-friendly preview of the specified file.
* @param file The file to preview.
*/
function openFilePreview(filePreviewParameters) {
ensureInitialized(frameContexts.content);
var params = [
filePreviewParameters.entityId,
filePreviewParameters.title,
filePreviewParameters.description,
filePreviewParameters.type,
filePreviewParameters.objectUrl,
filePreviewParameters.downloadUrl,
filePreviewParameters.webPreviewUrl,
filePreviewParameters.webEditUrl,
filePreviewParameters.baseUrl,
filePreviewParameters.editFile,
filePreviewParameters.subEntityId
];
sendMessageRequest(parentWindow, "openFilePreview", params);
}
exports.openFilePreview = openFilePreview;
/**
* @private
* Hide from docs.
* ------
* display notification API.
* @param message Notification message.
* @param notificationType Notification type
*/
function showNotification(showNotificationParameters) {
ensureInitialized(frameContexts.content);
var params = [
showNotificationParameters.message,
showNotificationParameters.notificationType
];
sendMessageRequest(parentWindow, "showNotification", params);
}
exports.showNotification = showNotification;
/**
* @private
* Hide from docs.
* ------
* execute deep link API.
* @param deepLink deep link.
*/
function executeDeepLink(deepLink) {
ensureInitialized(frameContexts.content);
var messageId = sendMessageRequest(parentWindow, "executeDeepLink", [
deepLink
]);
callbacks[messageId] = function (success, result) {
if (!success) {
throw new Error(result);
}
};
}
exports.executeDeepLink = executeDeepLink;
/**
* @private
* Hide from docs.
* ------
* Upload a custom App manifest directly to both team and personal scopes.
* This method works just for the first party Apps.
*/
function uploadCustomApp(manifestBlob) {
ensureInitialized();
var messageId = sendMessageRequest(parentWindow, "uploadCustomApp", [
manifestBlob
]);
callbacks[messageId] = function (success, result) {
if (!success) {
throw new Error(result);
}
};
}
exports.uploadCustomApp = uploadCustomApp;
/**
* Navigates the Microsoft Teams app to the specified tab instance.
* @param tabInstance The tab instance to navigate to.
*/
function navigateToTab(tabInstance) {
ensureInitialized();
var messageId = sendMessageRequest(parentWindow, "navigateToTab", [
tabInstance
]);
callbacks[messageId] = function (success) {
if (!success) {
throw new Error("Invalid internalTabInstanceId and/or channelId were/was provided");
}
};
}
exports.navigateToTab = navigateToTab;
/**
* Namespace to interact with the settings-specific part of the SDK.
* This object is usable only on the settings frame.
*/
var settings;
(function (settings) {
var saveHandler;
var removeHandler;
handlers["settings.save"] = handleSave;
handlers["settings.remove"] = handleRemove;
/**
* Sets the validity state for the settings.
* The initial value is false, so the user cannot save the settings until this is called with true.
* @param validityState Indicates whether the save or remove button is enabled for the user.
*/
function setValidityState(validityState) {
ensureInitialized(frameContexts.settings, frameContexts.remove);
sendMessageRequest(parentWindow, "settings.setValidityState", [
validityState
]);
}
settings.setValidityState = setValidityState;
/**
* Gets the settings for the current instance.
* @param callback The callback to invoke when the {@link Settings} object is retrieved.
*/
function getSettings(callback) {
ensureInitialized(frameContexts.content, frameContexts.settings, frameContexts.remove);
var messageId = sendMessageRequest(parentWindow, "settings.getSettings");
callbacks[messageId] = callback;
}
settings.getSettings = getSettings;
/**
* Sets the settings for the current instance.
* This is an asynchronous operation; calls to getSettings are not guaranteed to reflect the changed state.
* @param settings The desired settings for this instance.
*/
function setSettings(instanceSettings) {
ensureInitialized(frameContexts.content, frameContexts.settings);
var messageId = sendMessageRequest(parentWindow, "settings.setSettings", [
instanceSettings
]);
callbacks[messageId] = function (success, result) {
if (!success) {
throw new Error(result);
}
};
}
settings.setSettings = setSettings;
/**
* Registers a handler for when the user attempts to save the settings. This handler should be used
* to create or update the underlying resource powering the content.
* The object passed to the handler must be used to notify whether to proceed with the save.
* Only one handler can be registered at a time. A subsequent registration replaces an existing registration.
* @param handler The handler to invoke when the user selects the save button.
*/
function registerOnSaveHandler(handler) {
ensureInitialized(frameContexts.settings);
saveHandler = handler;
handler && sendMessageRequest(parentWindow, "registerHandler", ["save"]);
}
settings.registerOnSaveHandler = registerOnSaveHandler;
/**
* Registers a handler for user attempts to remove content. This handler should be used
* to remove the underlying resource powering the content.
* The object passed to the handler must be used to indicate whether to proceed with the removal.
* Only one handler may be registered at a time. Subsequent registrations will override the first.
* @param handler The handler to invoke when the user selects the remove button.
*/
function registerOnRemoveHandler(handler) {
ensureInitialized(frameContexts.remove);
removeHandler = handler;
handler && sendMessageRequest(parentWindow, "registerHandler", ["remove"]);
}
settings.registerOnRemoveHandler = registerOnRemoveHandler;
function handleSave(result) {
var saveEvent = new SaveEventImpl(result);
if (saveHandler) {
saveHandler(saveEvent);
}
else {
// If no handler is registered, we assume success.
saveEvent.notifySuccess();
}
}
/**
* @private
* Hide from docs, since this class is not directly used.
*/
var SaveEventImpl = /** @class */ (function () {
function SaveEventImpl(result) {
this.notified = false;
this.result = result ? result : {};
}
SaveEventImpl.prototype.notifySuccess = function () {
this.ensureNotNotified();
sendMessageRequest(parentWindow, "settings.save.success");
this.notified = true;
};
SaveEventImpl.prototype.notifyFailure = function (reason) {
this.ensureNotNotified();
sendMessageRequest(parentWindow, "settings.save.failure", [reason]);
this.notified = true;
};
SaveEventImpl.prototype.ensureNotNotified = function () {
if (this.notified) {
throw new Error("The SaveEvent may only notify success or failure once.");
}
};
return SaveEventImpl;
}());
function handleRemove() {
var removeEvent = new RemoveEventImpl();
if (removeHandler) {
removeHandler(removeEvent);
}
else {
// If no handler is registered, we assume success.
removeEvent.notifySuccess();
}
}
/**
* @private
* Hide from docs, since this class is not directly used.
*/
var RemoveEventImpl = /** @class */ (function () {
function RemoveEventImpl() {
this.notified = false;
}
RemoveEventImpl.prototype.notifySuccess = function () {
this.ensureNotNotified();
sendMessageRequest(parentWindow, "settings.remove.success");
this.notified = true;
};
RemoveEventImpl.prototype.notifyFailure = function (reason) {
this.ensureNotNotified();
sendMessageRequest(parentWindow, "settings.remove.failure", [reason]);
this.notified = true;
};
RemoveEventImpl.prototype.ensureNotNotified = function () {
if (this.notified) {
throw new Error("The removeEvent may only notify success or failure once.");
}
};
return RemoveEventImpl;
}());
})(settings = exports.settings || (exports.settings = {}));
/**
* Namespace to interact with the authentication-specific part of the SDK.
* This object is used for starting or completing authentication flows.
*/
var authentication;
(function (authentication) {
var authParams;
var authWindowMonitor;
handlers["authentication.authenticate.success"] = handleSuccess;
handlers["authentication.authenticate.failure"] = handleFailure;
/**
* Registers the authentication handlers
* @param authenticateParameters A set of values that configure the authentication pop-up.
*/
function registerAuthenticationHandlers(authenticateParameters) {
authParams = authenticateParameters;
}
authentication.registerAuthenticationHandlers = registerAuthenticationHandlers;
/**
* Initiates an authentication request, which opens a new window with the specified settings.
*/
function authenticate(authenticateParameters) {
var authenticateParams = authenticateParameters !== undefined
? authenticateParameters
: authParams;
ensureInitialized(frameContexts.content, frameContexts.settings, frameContexts.remove, frameContexts.task);
if (hostClientType === "desktop" /* desktop */ ||
hostClientType === "android" /* android */ ||
hostClientType === "ios" /* ios */) {
// Convert any relative URLs into absolute URLs before sending them over to the parent window.
var link = document.createElement("a");
link.href = authenticateParams.url;
// Ask the parent window to open an authentication window with the parameters provided by the caller.
var messageId = sendMessageRequest(parentWindow, "authentication.authenticate", [link.href, authenticateParams.width, authenticateParams.height]);
callbacks[messageId] = function (success, response) {
if (success) {
authenticateParams.successCallback(response);
}
else {
authenticateParams.failureCallback(response);
}
};
}
else {
// Open an authentication window with the parameters provided by the caller.
openAuthenticationWindow(authenticateParams);
}
}
authentication.authenticate = authenticate;
/**
* @private
* Hide from docs.
* ------
* Requests an Azure AD token to be issued on behalf of the app. The token is acquired from the cache
* if it is not expired. Otherwise a request is sent to Azure AD to obtain a new token.
* @param authTokenRequest A set of values that configure the token request.
*/
function getAuthToken(authTokenRequest) {
ensureInitialized();
var messageId = sendMessageRequest(parentWindow, "authentication.getAuthToken", [authTokenRequest.resources]);
callbacks[messageId] = function (success, result) {
if (success) {
authTokenRequest.successCallback(result);
}
else {
authTokenRequest.failureCallback(result);
}
};
}
authentication.getAuthToken = getAuthToken;
/**
* @private
* Hide from docs.
* ------
* Requests the decoded Azure AD user identity on behalf of the app.
*/
function getUser(userRequest) {
ensureInitialized();
var messageId = sendMessageRequest(parentWindow, "authentication.getUser");
callbacks[messageId] = function (success, result) {
if (success) {
userRequest.successCallback(result);
}
else {
userRequest.failureCallback(result);
}
};
}
authentication.getUser = getUser;
function closeAuthenticationWindow() {
// Stop monitoring the authentication window
stopAuthenticationWindowMonitor();
// Try to close the authentication window and clear all properties associated with it
try {
if (childWindow) {
childWindow.close();
}
}
finally {
childWindow = null;
childOrigin = null;
}
}
function openAuthenticationWindow(authenticateParameters) {
authParams = authenticateParameters;
// Close the previously opened window if we have one
closeAuthenticationWindow();
// Start with a sensible default size
var width = authParams.width || 600;
var height = authParams.height || 400;
// Ensure that the new window is always smaller than our app's window so that it never fully covers up our app
width = Math.min(width, currentWindow.outerWidth - 400);
height = Math.min(height, currentWindow.outerHeight - 200);
// Convert any relative URLs into absolute URLs before sending them over to the parent window
var link = document.createElement("a");
link.href = authParams.url;
// We are running in the browser, so we need to center the new window ourselves
var left = typeof currentWindow.screenLeft !== "undefined"
? currentWindow.screenLeft
: currentWindow.screenX;
var top = typeof currentWindow.screenTop !== "undefined"
? currentWindow.screenTop
: currentWindow.screenY;
left += currentWindow.outerWidth / 2 - width / 2;
top += currentWindow.outerHeight / 2 - height / 2;
// Open a child window with a desired set of standard browser features
childWindow = currentWindow.open(link.href, "_blank", "toolbar=no, location=yes, status=no, menubar=no, scrollbars=yes, top=" +
top +
", left=" +
left +
", width=" +
width +
", height=" +
height);
if (childWindow) {
// Start monitoring the authentication window so that we can detect if it gets closed before the flow completes
startAuthenticationWindowMonitor();
}
else {
// If we failed to open the window, fail the authentication flow
handleFailure("FailedToOpenWindow");
}
}
function stopAuthenticationWindowMonitor() {
if (authWindowMonitor) {
clearInterval(authWindowMonitor);
authWindowMonitor = 0;
}
delete handlers["initialize"];
delete handlers["navigateCrossDomain"];
}
function startAuthenticationWindowMonitor() {
// Stop the previous window monitor if one is running
stopAuthenticationWindowMonitor();
// Create an interval loop that
// - Notifies the caller of failure if it detects that the authentication window is closed
// - Keeps pinging the authentication window while it is open to re-establish
// contact with any pages along the authentication flow that need to communicate
// with us
authWindowMonitor = currentWindow.setInterval(function () {
if (!childWindow || childWindow.closed) {
handleFailure("CancelledByUser");
}
else {
var savedChildOrigin = childOrigin;
try {
childOrigin = "*";
sendMessageRequest(childWindow, "ping");
}
finally {
childOrigin = savedChildOrigin;
}
}
}, 100);
// Set up an initialize-message handler that gives the authentication window its frame context
handlers["initialize"] = function () {
return [frameContexts.authentication, hostClientType];
};
// Set up a navigateCrossDomain message handler that blocks cross-domain re-navigation attempts
// in the authentication window. We could at some point choose to implement this method via a call to
// authenticationWindow.location.href = url; however, we would first need to figure out how to
// validate the URL against the tab's list of valid domains.
handlers["navigateCrossDomain"] = function (url) {
return false;
};
}
/**
* Notifies the frame that initiated this authentication request that the request was successful.
* This function is usable only on the authentication window.
* This call causes the authentication window to be closed.
* @param result Specifies a result for the authentication. If specified, the frame that initiated the authentication pop-up receives this value in its callback.
* @param callbackUrl Specifies the url to redirect back to if the client is Win32 Outlook.
*/
function notifySuccess(result, callbackUrl) {
redirectIfWin32Outlook(callbackUrl, "result", result);
ensureInitialized(frameContexts.authentication);
sendMessageRequest(parentWindow, "authentication.authenticate.success", [
result
]);
// Wait for the message to be sent before closing the window
waitForMessageQueue(parentWindow, function () {
return setTimeout(function () { return currentWindow.close(); }, 200);
});
}
authentication.notifySuccess = notifySuccess;
/**
* Notifies the frame that initiated this authentication request that the request failed.
* This function is usable only on the authentication window.
* This call causes the authentication window to be closed.
* @param result Specifies a result for the authentication. If specified, the frame that initiated the authentication pop-up receives this value in its callback.
* @param callbackUrl Specifies the url to redirect back to if the client is Win32 Outlook.
*/
function notifyFailure(reason, callbackUrl) {
redirectIfWin32Outlook(callbackUrl, "reason", reason);
ensureInitialized(frameContexts.authentication);
sendMessageRequest(parentWindow, "authentication.authenticate.failure", [
reason
]);
// Wait for the message to be sent before closing the window
waitForMessageQueue(parentWindow, function () {
return setTimeout(function () { return currentWindow.close(); }, 200);
});
}
authentication.notifyFailure = notifyFailure;
function handleSuccess(result) {
try {
if (authParams && authParams.successCallback) {
authParams.successCallback(result);
}
}
finally {
authParams = null;
closeAuthenticationWindow();
}
}
function handleFailure(reason) {
try {
if (authParams && authParams.failureCallback) {
authParams.failureCallback(reason);
}
}
finally {
authParams = null;
closeAuthenticationWindow();
}
}
/**
* Validates that the callbackUrl param is a valid connector url, appends the result/reason and authSuccess/authFailure as URL fragments and redirects the window
* @param callbackUrl - the connectors url to redirect to
* @param key - "result" in case of success and "reason" in case of failure
* @param value - the value of the passed result/reason parameter
*/
function redirectIfWin32Outlook(callbackUrl, key, value) {
if (callbackUrl) {
var link = document.createElement("a");
link.href = decodeURIComponent(callbackUrl);
if (link.host &&
link.host !== window.location.host &&
link.host === "outlook.office.com" &&
link.search.indexOf("client_type=Win32_Outlook") > -1) {
if (key && key === "result") {
if (value) {
link.href = updateUrlParameter(link.href, "result", value);
}
currentWindow.location.assign(updateUrlParameter(link.href, "authSuccess", ""));
}
if (key && key === "reason") {
if (value) {
link.href = updateUrlParameter(link.href, "reason", value);
}
currentWindow.location.assign(updateUrlParameter(link.href, "authFailure", ""));
}
}
}
}
/**
* Appends either result or reason as a fragment to the 'callbackUrl'
* @param uri - the url to modify
* @param key - the fragment key
* @param value - the fragment value
*/
function updateUrlParameter(uri, key, value) {
var i = uri.indexOf("#");
var hash = i === -1 ? "#" : uri.substr(i);
hash = hash + "&" + key + (value !== "" ? "=" + value : "");
uri = i === -1 ? uri : uri.substr(0, i);
return uri + hash;
}
})(authentication = exports.authentication || (exports.authentication = {}));
function ensureInitialized() {
var expectedFrameContexts = [];
for (var _i = 0; _i < arguments.length; _i++) {
expectedFrameContexts[_i] = arguments[_i];
}
if (!initializeCalled) {
throw new Error("The library has not yet been initialized");
}
if (frameContext &&
expectedFrameContexts &&
expectedFrameContexts.length > 0) {
var found = false;
for (var i = 0; i < expectedFrameContexts.length; i++) {
if (expectedFrameContexts[i] === frameContext) {
found = true;
break;
}
}
if (!found) {
throw new Error("This call is not allowed in the '" + frameContext + "' context");
}
}
}
function processMessage(evt) {
// Process only if we received a valid message
if (!evt || !evt.data || typeof evt.data !== "object") {
return;
}
// Process only if the message is coming from a different window and a valid origin
var messageSource = evt.source || evt.originalEvent.source;
var messageOrigin = evt.origin || evt.originalEvent.origin;
if (messageSource === currentWindow ||
(messageOrigin !== currentWindow.location.origin &&
!validOriginRegExp.test(messageOrigin.toLowerCase()))) {
return;
}
// Update our parent and child relationships based on this message
updateRelationships(messageSource, messageOrigin);
// Handle the message
if (messageSource === parentWindow) {
handleParentMessage(evt);
}
else if (messageSource === childWindow) {
handleChildMessage(evt);
}
}
function updateRelationships(messageSource, messageOrigin) {
// Determine whether the source of the message is our parent or child and update our
// window and origin pointer accordingly
if (!parentWindow || messageSource === parentWindow) {
parentWindow = messageSource;
parentOrigin = messageOrigin;
}
else if (!childWindow || messageSource === childWindow) {
childWindow = messageSource;
childOrigin = messageOrigin;
}
// Clean up pointers to closed parent and child windows
if (parentWindow && parentWindow.closed) {
parentWindow = null;
parentOrigin = null;
}
if (childWindow && childWindow.closed) {
childWindow = null;
childOrigin = null;
}
// If we have any messages in our queue, send them now
flushMessageQueue(parentWindow);
flushMessageQueue(childWindow);
}
function handleParentMessage(evt) {
if ("id" in evt.data) {
// Call any associated callbacks
var message = evt.data;
var callback = callbacks[message.id];
if (callback) {
callback.apply(null, message.args);
// Remove the callback to ensure that the callback is called only once and to free up memory.
delete callbacks[message.id];
}
}
else if ("func" in evt.data) {
// Delegate the request to the proper handler
var message = evt.data;
var handler = handlers[message.func];
if (handler) {
// We don't expect any handler to respond at this point
handler.apply(this, message.args);
}
}
}
function handleChildMessage(evt) {
if ("id" in evt.data && "func" in evt.data) {
// Try to delegate the request to the proper handler
var message_1 = evt.data;
var handler = handlers[message_1.func];
if (handler) {
var result = handler.apply(this, message_1.args);
if (result) {
sendMessageResponse(childWindow, message_1.id, Array.isArray(result) ? result : [result]);
}
}
else {
// Proxy to parent
var messageId = sendMessageRequest(parentWindow, message_1.func, message_1.args);
// tslint:disable-next-line:no-any
callbacks[messageId] = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (childWindow) {
sendMessageResponse(childWindow, message_1.id, args);
}
};
}
}
}
function getTargetMessageQueue(targetWindow) {
return targetWindow === parentWindow
? parentMessageQueue
: targetWindow === childWindow
? childMessageQueue
: [];
}
function getTargetOrigin(targetWindow) {
return targetWindow === parentWindow
? parentOrigin
: targetWindow === childWindow
? childOrigin
: null;
}
function flushMessa