UNPKG

@kwiz/common

Version:

KWIZ common utilities and helpers for M365 platform

679 lines 28.1 kB
import { FieldTypes, PrincipalType, SPBasePermissionKind } from "../types/sharepoint.types"; import { isElement, waitFor, waitForWindowObject } from "./browser"; import { firstOrNull, forEach } from "./collections.base"; import { deleteCookie, getCookie, setCookie } from "./cookies"; import { isValidEmail } from "./emails"; import { jsonParse } from "./json"; import { hasOwnProperty } from "./objects"; import { isValidDomainLogin, normalizeGuid } from "./strings"; import { isNotEmptyArray, isNullOrEmptyString, isNullOrNaN, isNullOrUndefined, isNumber, isNumeric, isString, isTypeofFullNameFunction, isTypeofFullNameNullOrUndefined, isTypeofFullNameUndefined, isUndefined, isValidGuid } from "./typecheckers"; import { makeServerRelativeUrl, normalizeUrl } from "./url"; export const KWIZ_CONTROLLER_FIELD_NAME = "kwizcomcontrollerfield"; const MODERN_EXPERIENCE_COOKIE_NAME = "splnu"; const MODERN_EXPERIENCE_TEMP_COOKIE_NAME = `${MODERN_EXPERIENCE_COOKIE_NAME}_kwizcom_original`; const MOBILE_EXPERIENCE_COOKIE_NAME = "mobile"; const MOBILE_EXPERIENCE_TEMP_COOKIE_NAME = `${MOBILE_EXPERIENCE_COOKIE_NAME}_kwizcom_original`; //const logger = ConsoleLogger.get("_modules/helpers/sharepoint"); export function IsClassicPage() { if (!isTypeofFullNameUndefined("_spClientSideComponentIds")) { //only modern pages have the _spClientSideComponentIds object created on the page inline, not a in script that //can be loaded return false; } if (!isTypeofFullNameUndefined("_spWebPartComponents") || !isTypeofFullNameUndefined("g_Workspace") || isTypeofFullNameFunction("$_global_ie55up") || !isTypeofFullNameUndefined("_spBodyOnLoadCalled")) { //_spWebPartComponents = inline global var that contains web part info //g_Workspace = inline global var that contains the worskpace element selector //$_global_ie55up = global function for IE polyfills on classic pages //_spBodyOnLoadCalled = inline global var return true; } if (!isTypeofFullNameNullOrUndefined("document.body.childNodes") && document.body.childNodes.length > 0) { //only classic pages have the s4-workspace element let s4workspaceEle = document.getElementById("s4-workspace"); if (isElement(s4workspaceEle)) { return true; } } return false; } export function restoreExperience() { var splnu_original = getCookie(MODERN_EXPERIENCE_TEMP_COOKIE_NAME); deleteCookie(MODERN_EXPERIENCE_TEMP_COOKIE_NAME); deleteCookie(MODERN_EXPERIENCE_COOKIE_NAME); if (isString(splnu_original)) { setCookie(MODERN_EXPERIENCE_COOKIE_NAME, splnu_original); } var mobile_original = getCookie(MOBILE_EXPERIENCE_TEMP_COOKIE_NAME); deleteCookie(MOBILE_EXPERIENCE_TEMP_COOKIE_NAME); deleteCookie(MOBILE_EXPERIENCE_COOKIE_NAME); if (isString(mobile_original)) { setCookie(MOBILE_EXPERIENCE_COOKIE_NAME, mobile_original, null, "/"); } } export function ensureClassicExperience(listId) { var splnu = getCookie(MODERN_EXPERIENCE_COOKIE_NAME); var mobile = getCookie(MOBILE_EXPERIENCE_COOKIE_NAME); if (isString(splnu)) { setCookie(MODERN_EXPERIENCE_TEMP_COOKIE_NAME, splnu); } if (isString(mobile)) { setCookie(MOBILE_EXPERIENCE_TEMP_COOKIE_NAME, splnu); } setCookie(MOBILE_EXPERIENCE_COOKIE_NAME, "0", null, "/"); switchToClassicExperience(listId); } export function setExperienceCookie(value, reload) { setCookie(MODERN_EXPERIENCE_COOKIE_NAME, value); if (reload === true) { window.location.reload(); } } export function switchToClassicExperience(listId, reload) { setExperienceCookie(listId ? `{${normalizeGuid(listId)}}` : "0", reload); } export function switchToModernExperience(reload) { setExperienceCookie("1", reload); } /** Gets field schema XML and converts it into JSON object */ export function SchemaXmlToJson(xml) { let result = { Attributes: {}, Customizations: {} }; try { if (!isNullOrEmptyString(xml !== null)) { //IE9+ supports this, we don't need to support IE8 anymore let SchemaXmlDoc = new DOMParser().parseFromString(xml, "text/xml"); let xField = SchemaXmlDoc.getElementsByTagName("Field")[0]; for (var i = 0; i < xField.attributes.length; i++) { result.Attributes[xField.attributes[i].name] = xField.attributes[i].value; } let properties = xField.querySelectorAll("Customization>ArrayOfProperty>Property"); if (properties && properties.length > 0) { properties.forEach(p => { let name = p.querySelector("Name"); let value = p.querySelector("Value"); if (name && value && !isNullOrEmptyString(name.textContent)) result.Customizations[name.textContent] = value.textContent; }); } } } catch (e) { } return result; } export function SchemaJsonToXml(json) { let doc = new Document(); let fieldElm = doc.createElement("Field"); forEach(json.Attributes, (name, value) => { fieldElm.setAttribute(name, value); }); if (Object.keys(json.Customizations).length) { let custElm = doc.createElement("Customization"); fieldElm.appendChild(custElm); let arrElm = doc.createElement("ArrayOfProperty"); custElm.appendChild(arrElm); forEach(json.Customizations, (name, value) => { let propElm = doc.createElement("Property"); arrElm.appendChild(propElm); let nameElm = doc.createElement("Name"); propElm.appendChild(nameElm); let valElm = doc.createElement("Value"); propElm.appendChild(valElm); nameElm.textContent = name; valElm.textContent = value; }); } if (isNotEmptyArray(json["Choices"])) { let choices = doc.createElement("CHOICES"); fieldElm.appendChild(choices); json["Choices"].forEach(c => { let choice = doc.createElement("CHOICE"); choice.textContent = c; choices.appendChild(choice); }); } return fieldElm.outerHTML; } export function NormalizeListName(list) { let Name = list.EntityTypeName; //get list name. if it is a list, it will be [Name]List so cut the list out. try { if (list.BaseType === 0 && Name.endsWith("List")) Name = Name.substr(0, Name.length - 4); //remove List } catch (e) { } return Name; } export class SPBasePermissions { constructor(EffectiveBasePermissions) { this.$High = 0; this.$Low = 0; this.initPropertiesFromJson(EffectiveBasePermissions); } set(perm) { if (perm === SPBasePermissionKind.FullMask) { this.$Low = 65535; this.$High = 32767; return; } if (!perm) { this.$Low = 0; this.$High = 0; return; } var $v_0 = perm; $v_0 = $v_0 - 1; var $v_1 = 1; if ($v_0 >= 0 && $v_0 < 32) { $v_1 = $v_1 << $v_0; this.$Low = this.$Low | $v_1; } else if ($v_0 >= 32 && $v_0 < 64) { $v_1 = $v_1 << $v_0 - 32; this.$High = this.$High | $v_1; } } clear(perm) { var $v_0 = perm; $v_0 = $v_0 - 1; var $v_1 = 1; if ($v_0 >= 0 && $v_0 < 32) { $v_1 = $v_1 << $v_0; $v_1 = ~$v_1; this.$Low = this.$Low & $v_1; } else if ($v_0 >= 32 && $v_0 < 64) { $v_1 = $v_1 << $v_0 - 32; $v_1 = ~$v_1; this.$High = this.$High & $v_1; } } clearAll() { this.$High = 0; this.$Low = 0; } has(perm) { if (!perm) { return true; } if (perm === SPBasePermissionKind.FullMask) { return (this.$High & 32767) === 32767 && this.$Low === 65535; } var $v_0 = perm; $v_0 = $v_0 - 1; var $v_1 = 1; if ($v_0 >= 0 && $v_0 < 32) { $v_1 = $v_1 << $v_0; return 0 !== (this.$Low & $v_1); } else if ($v_0 >= 32 && $v_0 < 64) { $v_1 = $v_1 << $v_0 - 32; return 0 !== (this.$High & $v_1); } return false; } hasAny(...requestedPerms) { return (requestedPerms || []).some((t) => { return this.has(t); }); } haAll(...requestedPerms) { return (requestedPerms || []).every((t) => { return this.has(t); }); } hasPermissions(requestedPerms) { return (this.$High & requestedPerms.High) === requestedPerms.High && (this.$Low & requestedPerms.Low) === requestedPerms.Low; } hasAnyPermissions(...requestedPerms) { return (requestedPerms || []).some((t) => { return this.hasPermissions(t); }); } hasAllPermissions(...requestedPerms) { return (requestedPerms || []).every((t) => { return this.hasPermissions(t); }); } initPropertiesFromJson(EffectiveBasePermissions) { this.$High = 0; this.$Low = 0; if (isNullOrUndefined(EffectiveBasePermissions)) return; if (!isNullOrNaN(EffectiveBasePermissions.High)) { this.$High = EffectiveBasePermissions.High; } if (!isNullOrNaN(EffectiveBasePermissions.Low)) { this.$Low = EffectiveBasePermissions.Low; } } } /** remove i:0#.f|membership| prefix from login */ export function CleanupUserClaimsLogin(login) { if (login.indexOf('|membership|') >= 0) return login.slice(login.lastIndexOf('|') + 1); else return login; } export function IsSPPeoplePickerControlFormEntity(entity) { let asType = entity; return !isNullOrUndefined(entity) && !isNullOrEmptyString(asType.Key) && (!isNullOrUndefined(asType.EntityData) || !isNullOrUndefined(asType.Resolved)); } export function getPrincipalTypeFromPickerEntity(entity) { if (entity.EntityType === "FormsRole" || entity.EntityType === "SecGroup" || entity.EntityData && entity.EntityData.PrincipalType === "SecurityGroup") { return PrincipalType.SecurityGroup; } if (entity.EntityType === "SPGroup" || entity.EntityData && (isNumeric(entity.EntityData.SPGroupID) || entity.EntityData.PrincipalType === "SharePointGroup")) { return PrincipalType.SharePointGroup; } if (entity.EntityType === "User" || entity.EntityType === "" && entity.EntityData && entity.EntityData.PrincipalType === "User") { if (entity.EntityData && isValidEmail(entity.EntityData.Email) || isString(entity.EntityData.SIPAddress)) { return PrincipalType.User; } var keyparts = entity.Key.split("|"); if (keyparts.length === 3 && isValidEmail(keyparts[keyparts.length - 1])) { //sharepoint online key for a user is in the form xxxx|membership|email; return PrincipalType.User; } else if (keyparts.length === 2 && isValidDomainLogin(keyparts[keyparts.length - 1])) { //sharepoint onpremise key for a user is in the form xxxx|domain\\user; return PrincipalType.User; } else { //SharePoint groups on saved classic forms item are shown with EntityType = User but dont have a SIPAddress/Email //and the key does not contain a valid domain login/email return PrincipalType.SharePointGroup; } } return PrincipalType.User; } /** rest object might put array values under ".results", this will place them at the property value directly */ export function NormalizeRestObject(o) { //extract collections such as choice field "choices" if (o) { Object.keys(o).forEach(key => { if (!isNullOrUndefined(o[key]) && hasOwnProperty(o[key], "results") && Array.isArray(o[key].results)) o[key] = o[key].results; }); } return o; } /** * Extends a field info into field info EX (adding SchemaJson) * @param field REST field data * @param allFields Optional - all list fields, used for discovering multi TaxonomyField's update hidden text field */ export function extendFieldInfo(field, allFields) { let fieldEx = field; fieldEx.Id = normalizeGuid(field.Id); if (field.InternalName === "ContentType") { fieldEx.Required = true; } else { switch (fieldEx.TypeAsString) { case "TaxonomyFieldTypeMulti": //find the hidden rich text for updates! { let taxonomyField = fieldEx; let textFieldId = normalizeGuid(taxonomyField.TextField); let related = isNotEmptyArray(allFields) ? firstOrNull(allFields, relatedField => relatedField.Id === textFieldId) : null; if (related !== null) taxonomyField.HiddenMultiValueFieldName = related.InternalName; } break; } } fieldEx.OutputTypeAsString = getFieldOutputType(fieldEx); if (isNullOrUndefined(fieldEx.SchemaJson)) { Object.defineProperty(fieldEx, 'SchemaJson', { get: function () { if (isUndefined(this._schemaJson)) { this._schemaJson = SchemaXmlToJson(this.SchemaXml); } return this._schemaJson; } }); } if (field.InternalName === KWIZ_CONTROLLER_FIELD_NAME) { //not hidden by SharePoint so its shown in views/forms but as far as our products concerned - should be treated as hidden field.Hidden = true; } return fieldEx; } export function extendFieldInfos(fields) { return fields.map(f => extendFieldInfo(f, fields)); } export function getFieldOutputType(field) { let outputType = field.TypeAsString; if (outputType === "Calculated") { switch (field.OutputType) { case FieldTypes.DateTime: outputType = "DateTime"; break; case FieldTypes.Boolean: outputType = "Boolean"; break; case FieldTypes.Currency: outputType = "Currency"; break; case FieldTypes.Number: outputType = "Number"; break; default: outputType = "Text"; break; } } return outputType; } export function isDocLib(list) { return list && list.BaseType === 1; } export function GetOrderByFromCaml(camlQuery) { let xmlDoc = new DOMParser().parseFromString(camlQuery, "text/xml"); let orderByElm = xmlDoc.querySelector("OrderBy"); let OrderBy = []; if (orderByElm) { let orderFieldsElms = orderByElm.querySelectorAll("FieldRef"); orderFieldsElms.forEach(f => { let name = f.getAttribute("Name"); let asc = f.getAttribute("Ascending") || ""; //Issue 1019 default value is true if ommitted - https://learn.microsoft.com/en-us/sharepoint/dev/schema/fieldref-element-query let IsAscending = asc.toUpperCase() !== "FALSE"; if (!isNullOrEmptyString(name)) OrderBy.push({ Name: name, IsAscending: IsAscending }); }); } return OrderBy; } export function RemoveOrderByFromCaml(camlQuery) { let xmlDoc = new DOMParser().parseFromString(camlQuery, "text/xml"); let orderByElm = xmlDoc.querySelector("OrderBy"); //let OrderBy: { Name: string; IsAscending: boolean; }[] = []; if (orderByElm) { orderByElm.remove(); return xmlDoc.documentElement.outerHTML; } return camlQuery; } export function EnsureViewFields(camlQuery, fields, forceCreateViewFields, removeAllOthers) { let xmlDoc = new DOMParser().parseFromString(camlQuery, "text/xml"); let viewElm = xmlDoc.querySelector("View"); if (!isNullOrUndefined(viewElm)) { let viewFieldsElm = viewElm.querySelector("ViewFields"); if (forceCreateViewFields && isNullOrUndefined(viewFieldsElm)) { viewFieldsElm = xmlDoc.createElement("ViewFields"); viewElm.appendChild(viewFieldsElm); } if (!isNullOrUndefined(viewFieldsElm)) { let viewFieldsElms = viewFieldsElm.querySelectorAll("FieldRef"); if (removeAllOthers) viewFieldsElms.forEach(e => e.remove()); let viewFields = removeAllOthers ? [] : Array.from(viewFieldsElms).map(viewFieldNode => { let name = viewFieldNode.getAttribute("Name"); return name.toLowerCase(); }); let changed = false; fields.forEach(f => { if (viewFields.indexOf(f.toLowerCase()) === -1) { let newViewFieldElm = xmlDoc.createElement("FieldRef"); newViewFieldElm.setAttribute("Name", f); viewFieldsElm.appendChild(newViewFieldElm); changed = true; } }); if (viewFieldsElm.querySelectorAll("FieldRef").length < 1 && !forceCreateViewFields) { //don't leave an empty object viewFieldsElm.remove(); changed = true; } if (changed) return xmlDoc.documentElement.outerHTML; } } return camlQuery; } /**If it is a thumbnail field - parse and return a typed value */ export function ParseThumbnalFieldValue(value, context) { if (!isNullOrEmptyString(value)) { try { let parsed = jsonParse(value); if (isNullOrUndefined(parsed)) { return null; } if (!isNullOrEmptyString(parsed.serverRelativeUrl)) { return parsed; } else if (!isNullOrEmptyString(parsed.fileName) && !isNullOrUndefined(context) && isNumber(context.itemId) && !isNullOrEmptyString(context.rootFolder)) { let { itemId, rootFolder } = context; parsed.serverRelativeUrl = `${makeServerRelativeUrl(rootFolder)}/Attachments/${itemId}/${parsed.fileName}`; return parsed; } } catch (e) { } } return null; } export function isTitleField(fieldName) { return fieldName === "Title" || fieldName === "LinkTitleNoMenu" || fieldName === "LinkTitle"; } /** we are on a list view page, not a web part page with possible multiple list views */ export function isSingleViewPage() { return !isNullOrUndefined(_spPageContextInfo) && isValidGuid(_spPageContextInfo.viewId); } /** * Splits the ViewFields of a CAML query into separate entries based on the batch size. * @param {string} camlQuery - The CAML query string. * @param {number} batchSize - The size of each batch (number of ViewFields per entry). */ export function splitViewFieldsByBatch(camlQuery, allListFieldsToLowerHash, batchSize) { let xmlDoc = new DOMParser().parseFromString(camlQuery, 'text/xml'); let viewNode = xmlDoc.querySelector("View, view"); let viewFieldsNode = viewNode && viewNode.querySelector("ViewFields, viewfields"); if (isNullOrUndefined(viewFieldsNode)) { return [camlQuery]; // No ViewFields element found, return the original query as is } let viewFieldNodes = Array.from(viewFieldsNode.children); let numberOfEntries = Math.ceil(viewFieldNodes.length / batchSize); let splitQueries = []; for (let i = 0; i < numberOfEntries; i++) { let startIndex = i * batchSize; let endIndex = startIndex + batchSize; let slicedViewFields = viewFieldNodes.slice(startIndex, endIndex); let clonedXmlDoc = xmlDoc.cloneNode(true); let clonedViewFieldsElement = clonedXmlDoc.getElementsByTagName('ViewFields')[0]; // Remove existing child nodes from cloned ViewFields while (clonedViewFieldsElement.firstChild) { clonedViewFieldsElement.removeChild(clonedViewFieldsElement.firstChild); } // Append sliced ViewFields to cloned ViewFields for (let slicedViewField of slicedViewFields) { clonedViewFieldsElement.appendChild(slicedViewField.cloneNode(true)); } let splitQuery = new XMLSerializer().serializeToString(clonedXmlDoc); splitQueries.push(splitQuery); } return splitQueries; } /** Size=S = 48×48 px, M = 72×72 px, L = 300×300 px */ export function UserPhoto(siteUrl, userName, size = "L") { return `${normalizeUrl(siteUrl)}/_layouts/15/userphoto.aspx?size=${size}&accountname=${encodeURIComponent(userName)}`; } export function IsFolderContentType(contentTypeId) { //item:0x0100 //file:0x0101 //folder:0x0120 //item in MS Lists:0x00 Issue 7121 return contentTypeId.startsWith("0x0120"); } export var PageContainerTypes; (function (PageContainerTypes) { PageContainerTypes[PageContainerTypes["M365SPFx"] = 0] = "M365SPFx"; PageContainerTypes[PageContainerTypes["M365OOBListForm"] = 1] = "M365OOBListForm"; PageContainerTypes[PageContainerTypes["SP2019SPFx"] = 2] = "SP2019SPFx"; PageContainerTypes[PageContainerTypes["SP2019ListForm"] = 3] = "SP2019ListForm"; })(PageContainerTypes || (PageContainerTypes = {})); export function GetModernPageContainers() { let mainContent = document.querySelector("section.mainContent"); if (mainContent) return { mainContent, commandBar: document.querySelector(".commandBarWrapper"), type: PageContainerTypes.M365SPFx }; mainContent = document.querySelector("div[class^=canvasWrapper]"); //document.querySelector("div.SPCanvas"); if (mainContent) return { mainContent, commandBar: document.querySelector(".commandBarWrapper"), type: PageContainerTypes.SP2019SPFx }; mainContent = document.querySelector(".flex-mainColumn"); if (mainContent) return { mainContent, commandBar: null, type: PageContainerTypes.M365OOBListForm }; mainContent = document.querySelector(".Files-mainColumn"); if (mainContent) return { mainContent, commandBar: null, type: PageContainerTypes.SP2019ListForm }; return { mainContent: null, commandBar: null, type: PageContainerTypes.SP2019ListForm }; } export function AddCamlQueryFragmentToViewQuery(viewXml, queryFragmentXml) { const combineWithExistingConditions = (doc, existingConditions, newConditionXml) => { const parser = new DOMParser(); const newConditionDoc = parser.parseFromString(newConditionXml, 'text/xml'); const newCondition = doc.importNode(newConditionDoc.documentElement, true); if (existingConditions.length === 0) { return newCondition; } else if (existingConditions.length === 1) { const andElement = doc.createElement("And"); andElement.appendChild(existingConditions[0]); andElement.appendChild(newCondition); return andElement; } else { const lastCondition = existingConditions.pop(); const andElement = doc.createElement("And"); andElement.appendChild(combineWithExistingConditions(doc, existingConditions, "")); andElement.appendChild(lastCondition); return andElement; } }; try { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(viewXml, 'text/xml'); const whereClause = xmlDoc.querySelector('Where') || xmlDoc.createElement('Where'); const existingConditions = Array.from(whereClause.children); const combinedCondition = combineWithExistingConditions(xmlDoc, existingConditions, queryFragmentXml); whereClause.textContent = ''; // Clear existing conditions whereClause.appendChild(combinedCondition); const query = xmlDoc.querySelector('Query') || xmlDoc.createElement('Query'); query.appendChild(whereClause); const view = xmlDoc.querySelector('View') || xmlDoc.createElement('View'); view.appendChild(query); const serializer = new XMLSerializer(); let modifiedCamlXml = serializer.serializeToString(xmlDoc); return modifiedCamlXml; } catch (error) { return viewXml; } } export function IsUserEntityValueType(value) { if (isNullOrUndefined(value) || isString(value)) { return false; } var asUserEntityValueType = value; var isEntityValueType = asUserEntityValueType.principalType === PrincipalType.SharePointGroup || asUserEntityValueType.principalType === PrincipalType.User || asUserEntityValueType.principalType === PrincipalType.SecurityGroup; return isEntityValueType; } export function IsMultiUserEntityValueType(value) { if (isNullOrUndefined(value) || isString(value) || !Array.isArray(value)) { return false; } return value.every((v) => { return IsUserEntityValueType(v); }); } export function IsUrlValueType(value) { if (isNullOrUndefined(value) || isString(value)) { return false; } let asType = value; return !isNullOrUndefined(asType.Url) && !isNullOrUndefined(asType.Description); } export function IsRetentionLabelValueType(value) { if (isNullOrUndefined(value) || isString(value)) { return false; } let asType = value; return isValidGuid(asType.TagId) && !isNullOrEmptyString(asType.TagName); } export function isHostedInTeams() { return window.location.pathname.toLowerCase().indexOf("teamshostedapp.aspx") >= 0; } export function isClassicAppIframe() { return window.location.search.toLowerCase().indexOf("sphosturl=") >= 0 && window.location.search.toLowerCase().indexOf("spappweburl=") >= 0; } export function isNumberFieldType(fieldInfo) { let targetColumnOutputType = getFieldOutputType(fieldInfo); return targetColumnOutputType === "Currency" || targetColumnOutputType === "Number" || targetColumnOutputType === "Counter" || targetColumnOutputType === "Integer"; } export async function isSharePointOnline() { let url = new URL(window.location.href); //Most cases are satisfied by this check. Very few customers have custom domains for SharePoint online. if (url.host.toLowerCase().endsWith(".sharepoint.com")) { return true; } let contextReady = await waitFor(() => { return !isTypeofFullNameUndefined("_spPageContextInfo"); }); if (contextReady) { return _spPageContextInfo.isSPO === true; } return false; } export function isSharePointOnlineSync() { let url = new URL(window.location.href); //Most cases are satisfied by this check. Very few customers have custom domains for SharePoint online. if (url.host.toLowerCase().endsWith(".sharepoint.com")) { return true; } if (!isTypeofFullNameUndefined("_spPageContextInfo")) { return _spPageContextInfo.isSPO === true; } return false; } export async function isAppWeb() { let contextReady = await waitFor(() => { return !isTypeofFullNameUndefined("_spPageContextInfo"); }); if (contextReady) { return _spPageContextInfo.isAppWeb === true; } return false; } export function isAppWebSync() { if (!isTypeofFullNameUndefined("_spPageContextInfo")) { return _spPageContextInfo.isAppWeb === true; } return false; } export async function isSPPageContextInfoReady() { return await waitForWindowObject("_spPageContextInfo"); } export function isSPPageContextInfoReadySync() { return !isTypeofFullNameNullOrUndefined("_spPageContextInfo"); } export function isExternalUser(loginName) { if (isNullOrEmptyString(loginName)) return false; return loginName.indexOf("#ext#@") >= 0; } //# sourceMappingURL=sharepoint.js.map