UNPKG

@aappddeevv/dynamics-client-ui

Version:

## What is it? A library to help you create great dynamics applications.

356 lines 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const R = require("ramda"); tslib_1.__exportStar(require("./getXrmP"), exports); const BuildSettings_1 = require("BuildSettings"); /** * Get a URL parameter from `search` or `document.loction.search` by * default. This is useful for obtaining the "data" parameter from the URL * that is passed in from a form if you set the WebResource url properties. * Sometimes the API does not seem to work, but this seems to always work. */ function getURLParameter(name, search = document.location.search) { search = search || ""; const r = new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec(search); const r2 = ["", ""]; return decodeURIComponent((r || r2)[1].replace(/\+/g, "%20")) || null; } exports.getURLParameter = getURLParameter; /** Generate a unique id with an optional prefix. */ function generateId(prefix = "") { return `${prefix}-${uuidv4()}`; } exports.generateId = generateId; const dec2hex = []; for (let i = 0; i <= 15; i++) { dec2hex[i] = i.toString(16); } const UUID = () => { let uuid = ""; for (let i = 1; i <= 36; i++) { if (i === 9 || i === 14 || i === 19 || i === 24) { uuid += "-"; } else if (i === 15) { uuid += 4; } else if (i === 20) { uuid += dec2hex[(Math.random() * 4 | 0 + 8)]; } else { uuid += dec2hex[(Math.random() * 15 | 0)]; } } return uuid; }; /** Probably need something multi-browser friendly here. */ //export function uuidv4(): string { // return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => // (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) // ) //} function uuidv4() { return UUID(); } exports.uuidv4 = uuidv4; /** Internal to this module. ... */ function cleanId(id) { if (typeof id === "undefined" || id === null) throw Error(`Unable to clean nil id ${id}`); return id.toString().replace(/[{}]/g, "").toLowerCase(); } /** Uses internal API. */ function isUci(xrm) { if (xrm.Internal && xrm.Internal.isUci) return xrm.Internal.isUci(); return false; } exports.isUci = isUci; let _isElectron = false; const userAgent = navigator.userAgent.toLowerCase(); if (userAgent.indexOf(" electron/") > -1) { _isElectron = true; } /** Return true if we are running inside electron. */ function isElectron() { return _isElectron; } exports.isElectron = isElectron; /** * Checks the form context to see if there is an entity id. If not, * it's probably a new form. */ function hasEntityId(xrm) { if (!xrm) return false; const id = entityIdOrNull(xrm); if (id) return true; return false; } exports.hasEntityId = hasEntityId; /** Return the entity id on the page context or null. Braces removed. */ function entityIdOrNull(xrm) { if (!xrm) return null; const e = eaccess(xrm); if (e) return cleanId(e.getId()); return null; } exports.entityIdOrNull = entityIdOrNull; const eaccess = R.pathOr(null, ["Page", "data", "entity"]); /** * After a save event, run actionToTake if ready returns ture. Uses polling. * Once actionToTake is run, the polling is removed. An exception thrown in * in ready is considered a false return. * @param xrm Xrm to attach to Xrm.Page.data.entity.addOnSave/removeOnSave * @param ready Return true if the condition to run actionToTake has been met. * @param actionToTake The action to take. * @param pollInterval The interval to poll that ready is true after the save has occurred. * @return A cancellable thunk. */ function runAfterSave(xrm, ready, actionToTake, pollInterval = 500) { let cancellable = null; const onSaveHandler = (ctx) => { const keepChecking = () => { try { const fire = ready(xrm); if (fire) { xrm.Page.data.entity.removeOnSave(onSaveHandler); clearInterval(cancellable); actionToTake(xrm); } } catch (e) { // do nothing console.log("Ready check failed", e); } }; cancellable = setInterval(keepChecking, pollInterval); }; xrm.Page.data.entity.addOnSave(onSaveHandler); return () => xrm.Page.data.entity.removeOnSave(onSaveHandler); } exports.runAfterSave = runAfterSave; /** Render a null, which in react means no rendering. */ exports.RenderNothing = () => null; /** Do nothing. */ function noop() { } exports.noop = noop; /** * If cb is a function, return it, otherwise noop. * @param cb Callback */ function callbackOrNoop(cb) { return typeof cb === "function" ? cb : noop; } exports.callbackOrNoop = callbackOrNoop; /** * If arg is an array, return the first element if it exists, * otherwise, return other. */ function firstOrElse(arg, other) { arg = Array.isArray(arg) ? arg[0] : arg; if (R.isNil(arg) && other) return other; else return arg; } exports.firstOrElse = firstOrElse; /** Find the first undefined array element or return undefined. */ function firstUndefined(...args) { if (!Array.isArray(args)) return undefined; return args.find(a => typeof a !== "undefined"); } exports.firstUndefined = firstUndefined; /** * Execute fns with the same args in order until * `event.preventDefault()` is called. This is really * just a takeWhile and map where "event" is mutable state. */ function composeEventHandlers(...fns) { return (event, ...args) => { fns.some(fn => { fn && fn(event, ...args); return event.defaultPrevented; }); }; } exports.composeEventHandlers = composeEventHandlers; /** Per downshift, (p)react. */ function isDOMElement(el) { if (el) { if (el.nodeName) return typeof el.nodeName === "string"; else return (typeof el.type === "string" || typeof el.type === "function"); } return false; } exports.isDOMElement = isDOMElement; /** Return true if its a number. */ function isNumber(thing) { // eslint-disable-next-line no-self-compare return thing === thing && typeof thing === "number"; } exports.isNumber = isNumber; /** * Get props for (p)react. */ function getElementProps(element) { return element.props || element.attributes; } exports.getElementProps = getElementProps; /** * Return the parent's Xrm from window.parent.Xrm or window.Xrm. * No check to see if Xrm.Page.data is present as that is deprecated. * This is a strict value check, no async. * * @see getXrmForEntity */ function getXrm() { return window.parent.Xrm || window.Xrm; } exports.getXrm = getXrm; /** * Return the global context from GetGlobalContext(), then * Xrm.Utility.getGlobalContext() then Xrm.Page.context. * Throws Error if not found. * * @see https://msdn.microsoft.com/pt-pt/library/af74d417-1359-4eaa-9f87-5b33a8852e83(v=crm.7) */ function getGlobalContext() { var errorMessage = "Context is not available."; if (typeof GetGlobalContext !== "undefined") { return GetGlobalContext(); } else { if (typeof Xrm !== "undefined") { if (typeof Xrm.Utility !== "undefined" && typeof Xrm.Utility.getGlobalContext !== "undefined") { return Xrm.Utility.getGlobalContext(); } // Try this... return Xrm.Page.context; } else { throw new Error(errorMessage); } } } exports.getGlobalContext = getGlobalContext; /** * Walk the window chain looking for Xrm with Xrm.Page.data attribute being * non-null. Return null if not found. It will walk the window hierarchy * as well as test some well known locations of Xrm. * * @see getXrm */ function getXrmForEntity() { const window = walkParents({ select: (w) => R.pathOr(false, ["Xrm", "Page", "data"], w) }); if (window) return window.Xrm; const maybeXrm = getXrm(); if (R.pathOr(false, ["Page", "data"], maybeXrm)) return maybeXrm; return null; } exports.getXrmForEntity = getXrmForEntity; /** * Run a thunk up the window chain. Return the last window visited if it meets * select criteria (if provided) or if select returns true for a particular * window. Return null otherwise. Thunk is usually used for logging. */ function walkParents({ thunk, select, max }) { max = max || 10; let current = window; // this window while (current && max > 0 && !select(current)) { if (thunk) thunk(current); max = max - 1; if (current.parent === current) current = null; else current = current.parent; } if (select(current)) return current; return null; } exports.walkParents = walkParents; /** * Try to get entityid, userid, entity name, entity type code (number) from a * variety of places including the Xrm values and the URL parameters in the * document that the function is called from. Varibles that are found are * returned but if something is not found it is not returned. If its a new * entity, obviously, the entityid will not be present. Return an object with * {userId, entityId, entityName, entityTypeCode}. Note that entityTypeCode * is specific to an organization so do not use it if you can avoid it. * * Should typecode be number or string? */ function getEntityInfo(xrm) { const x = xrm || getXrmForEntity(); const context = R.pathOr(null, ["Page", "context"], x); const entity = R.pathOr(null, ["Page", "data", "entity"], x); const etn = getURLParameter("etn"); const typename = getURLParameter("typename"); const etc = context ? parseInt(context.getQueryStringParameters().etc) : null; const eid = (entity && entity.getId()) || getURLParameter("id") || null; const uid = (context && context.getUserId()) || null; const ename = entity ? entity.getEntityName() : (etn ? etn : (typename ? typename : null)); const tcode = etc; const rval = Object.assign({}, (uid ? { userId: cleanId(uid) } : {}), (eid ? { entityId: cleanId(eid) } : {}), (ename ? { entityName: ename } : {}), (tcode ? { entityTypeCode: tcode } : {})); return rval; } exports.getEntityInfo = getEntityInfo; /** * Access page context to return form type. * @deprecated Use XRM members directly. */ function getFormType(xrm) { const v = xrm.Page.ui.getFormType(); // check range??? return v; } exports.getFormType = getFormType; /** If create form, checks formtype and whether there is an id. */ function isCreateForm(xrm) { return getFormType(xrm) === 1 /* Create */ || !eaccess(xrm).getId(); } exports.isCreateForm = isCreateForm; /** * Load scripts programmatically. The script is evaluated once loaded by the browser/host. */ function loadScripts(scripts, callback, targetDoc = document) { const loader = (src, handler) => { if (BuildSettings_1.DEBUG) console.log("Programmatically loading: " + src); const script = targetDoc.createElement("script"); script.src = src; script.onload = () => { // remove onload handler?? handler(); }; const head = targetDoc.getElementsByTagName("head")[0]; (head || targetDoc.body).appendChild(script); }; // Run on each script... (function run() { if (scripts.length > 0) { loader(scripts.shift(), run); } else if (callback) callback(); })(); } exports.loadScripts = loadScripts; //# sourceMappingURL=Utils.js.map