@kwiz/common 1.0.78 → 1.0.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/.github/workflows/npm-publish.yml +24 -0
  2. package/.madgerc +2 -2
  3. package/LICENSE +21 -21
  4. package/fix-folder-imports.js +26 -26
  5. package/lib/cjs/helpers/sharepoint.js +5 -1
  6. package/lib/cjs/helpers/sharepoint.js.map +1 -1
  7. package/lib/cjs/helpers/typecheckers.js +5 -1
  8. package/lib/cjs/helpers/typecheckers.js.map +1 -1
  9. package/lib/cjs/types/libs/msal.types.js +26 -26
  10. package/lib/cjs/utils/sharepoint.rest/list.js +1 -1
  11. package/lib/cjs/utils/sharepoint.rest/list.js.map +1 -1
  12. package/lib/cjs/utils/sharepoint.rest/user.js +11 -11
  13. package/lib/esm/helpers/sharepoint.js +3 -0
  14. package/lib/esm/helpers/sharepoint.js.map +1 -1
  15. package/lib/esm/helpers/typecheckers.js +3 -0
  16. package/lib/esm/helpers/typecheckers.js.map +1 -1
  17. package/lib/esm/types/libs/msal.types.js +26 -26
  18. package/lib/esm/utils/sharepoint.rest/list.js +2 -2
  19. package/lib/esm/utils/sharepoint.rest/list.js.map +1 -1
  20. package/lib/esm/utils/sharepoint.rest/user.js +11 -11
  21. package/lib/types/helpers/sharepoint.d.ts +1 -0
  22. package/lib/types/helpers/typecheckers.d.ts +1 -0
  23. package/package.json +77 -77
  24. package/readme.md +17 -17
  25. package/src/_dependencies.ts +12 -12
  26. package/src/config.ts +17 -17
  27. package/src/helpers/Guid.ts +181 -181
  28. package/src/helpers/base64.ts +173 -173
  29. package/src/helpers/browser.test.js +13 -13
  30. package/src/helpers/browser.ts +1348 -1348
  31. package/src/helpers/browserinfo.ts +292 -292
  32. package/src/helpers/collections.base.test.js +25 -25
  33. package/src/helpers/collections.base.ts +437 -437
  34. package/src/helpers/collections.ts +107 -107
  35. package/src/helpers/color.ts +54 -54
  36. package/src/helpers/cookies.ts +59 -59
  37. package/src/helpers/date.test.js +119 -119
  38. package/src/helpers/date.ts +188 -188
  39. package/src/helpers/debug.ts +186 -186
  40. package/src/helpers/emails.ts +6 -6
  41. package/src/helpers/eval.ts +5 -5
  42. package/src/helpers/file.test.js +50 -50
  43. package/src/helpers/file.ts +58 -58
  44. package/src/helpers/flatted.ts +149 -149
  45. package/src/helpers/functions.ts +16 -16
  46. package/src/helpers/graph/calendar.types.ts +10 -10
  47. package/src/helpers/http.ts +69 -69
  48. package/src/helpers/images.ts +22 -22
  49. package/src/helpers/json.ts +38 -38
  50. package/src/helpers/md5.ts +189 -189
  51. package/src/helpers/objects.test.js +33 -33
  52. package/src/helpers/objects.ts +270 -270
  53. package/src/helpers/promises.test.js +37 -37
  54. package/src/helpers/promises.ts +165 -165
  55. package/src/helpers/random.ts +27 -27
  56. package/src/helpers/scheduler/scheduler.test.js +103 -103
  57. package/src/helpers/scheduler/scheduler.ts +131 -131
  58. package/src/helpers/sharepoint.ts +776 -772
  59. package/src/helpers/strings.test.js +101 -101
  60. package/src/helpers/strings.ts +317 -317
  61. package/src/helpers/typecheckers.test.js +34 -34
  62. package/src/helpers/typecheckers.ts +266 -262
  63. package/src/helpers/url.test.js +43 -43
  64. package/src/helpers/url.ts +207 -207
  65. package/src/helpers/urlhelper.ts +111 -111
  66. package/src/index.ts +6 -6
  67. package/src/types/auth.ts +54 -54
  68. package/src/types/common.types.ts +15 -15
  69. package/src/types/flatted.types.ts +59 -59
  70. package/src/types/globals.types.ts +6 -6
  71. package/src/types/graph/calendar.types.ts +80 -80
  72. package/src/types/knownscript.types.ts +18 -18
  73. package/src/types/libs/datajs.types.ts +28 -28
  74. package/src/types/libs/ics.types.ts +30 -30
  75. package/src/types/libs/msal.types.ts +49 -49
  76. package/src/types/locales.ts +124 -124
  77. package/src/types/localstoragecache.types.ts +8 -8
  78. package/src/types/location.types.ts +27 -27
  79. package/src/types/moment.ts +11 -11
  80. package/src/types/regex.types.ts +16 -16
  81. package/src/types/rest.types.ts +95 -95
  82. package/src/types/sharepoint.types.ts +1465 -1465
  83. package/src/types/sharepoint.utils.types.ts +287 -287
  84. package/src/utils/auth/common.ts +74 -74
  85. package/src/utils/auth/discovery.test.js +12 -12
  86. package/src/utils/auth/discovery.ts +132 -132
  87. package/src/utils/base64.ts +27 -27
  88. package/src/utils/consolelogger.ts +320 -320
  89. package/src/utils/date.ts +35 -35
  90. package/src/utils/emails.ts +24 -24
  91. package/src/utils/knownscript.ts +286 -286
  92. package/src/utils/localstoragecache.ts +441 -441
  93. package/src/utils/rest.ts +501 -501
  94. package/src/utils/script.ts +170 -170
  95. package/src/utils/sharepoint.rest/common.ts +154 -154
  96. package/src/utils/sharepoint.rest/date.ts +62 -62
  97. package/src/utils/sharepoint.rest/file.folder.ts +598 -598
  98. package/src/utils/sharepoint.rest/item.ts +547 -547
  99. package/src/utils/sharepoint.rest/list.ts +1388 -1388
  100. package/src/utils/sharepoint.rest/listutils/GetListItemsByCaml.ts +774 -774
  101. package/src/utils/sharepoint.rest/listutils/GetListItemsById.ts +275 -275
  102. package/src/utils/sharepoint.rest/listutils/common.ts +206 -206
  103. package/src/utils/sharepoint.rest/location.ts +141 -141
  104. package/src/utils/sharepoint.rest/navigation-links.ts +86 -86
  105. package/src/utils/sharepoint.rest/user-search.ts +252 -252
  106. package/src/utils/sharepoint.rest/user.ts +491 -491
  107. package/src/utils/sharepoint.rest/web.ts +1384 -1384
  108. package/src/utils/sod.ts +194 -194
  109. package/lib/cjs/helpers/_dependencies.js +0 -21
  110. package/lib/cjs/helpers/_dependencies.js.map +0 -1
  111. package/lib/cjs/utils/_dependencies.js +0 -24
  112. package/lib/cjs/utils/_dependencies.js.map +0 -1
  113. package/lib/esm/helpers/_dependencies.js +0 -3
  114. package/lib/esm/helpers/_dependencies.js.map +0 -1
  115. package/lib/esm/utils/_dependencies.js +0 -4
  116. package/lib/esm/utils/_dependencies.js.map +0 -1
  117. package/lib/types/helpers/_dependencies.d.ts +0 -2
  118. package/lib/types/utils/_dependencies.d.ts +0 -3
@@ -1,773 +1,777 @@
1
- import { IDictionary } from "../types/common.types";
2
- import { FieldTypeAsString, FieldTypes, IFieldCalculatedInfo, IFieldInfo, IFieldInfoEX, IFieldJsonSchema, IFieldTaxonomyInfo, PrincipalType, RententionLabelFieldValueType, SPBasePermissionKind, ThumbnailValueType, UrlValueType } from "../types/sharepoint.types";
3
- import { UserEntityValueType } from "../types/sharepoint.utils.types";
4
- import { waitFor, waitForWindowObject } from "./browser";
5
- import { firstOrNull, forEach } from "./collections.base";
6
- import { deleteCookie, getCookie, setCookie } from "./cookies";
7
- import { isValidEmail } from "./emails";
8
- import { jsonParse } from "./json";
9
- import { hasOwnProperty } from "./objects";
10
- import { isValidDomainLogin, normalizeGuid } from "./strings";
11
- import { isNotEmptyArray, isNullOrEmptyString, isNullOrNaN, isNullOrUndefined, isNumber, isNumeric, isString, isTypeofFullNameNullOrUndefined, isTypeofFullNameUndefined, isUndefined, isValidGuid } from "./typecheckers";
12
- import { makeServerRelativeUrl, normalizeUrl } from "./url";
13
-
14
- export const KWIZ_CONTROLLER_FIELD_NAME = "kwizcomcontrollerfield";
15
- const MODERN_EXPERIENCE_COOKIE_NAME = "splnu";
16
- const MODERN_EXPERIENCE_TEMP_COOKIE_NAME = `${MODERN_EXPERIENCE_COOKIE_NAME}_kwizcom_original`;
17
- const MOBILE_EXPERIENCE_COOKIE_NAME = "mobile";
18
- const MOBILE_EXPERIENCE_TEMP_COOKIE_NAME = `${MOBILE_EXPERIENCE_COOKIE_NAME}_kwizcom_original`;
19
-
20
- //const logger = ConsoleLogger.get("_modules/helpers/sharepoint");
21
- export function IsClassicPage() {
22
- //on premises has g_spribbon but no g_Workspace
23
- //can't use g_spribbon because it gets created whenever you load the init.js script
24
- if (!isUndefined(window)
25
- && window.document
26
- && document.body
27
- && document.body.childNodes.length
28
- && document.body.childNodes) {
29
- //only classic pages have the s4-workspace element, so try this first because it is the most reliable
30
- return !!document.getElementById("s4-workspace");
31
- } else if (!isUndefined((<any>window)._spWebPartComponents)) {
32
- //only classic pages have the _spWebPartComponents object created on the page inline, not in a script that
33
- //can be loaded
34
- return true;
35
- } else if (!isUndefined((<any>window)._spClientSideComponentIds)) {
36
- //only modern pages have the _spClientSideComponentIds object created on the page inline, not a in script that
37
- //can be loaded
38
- return false;
39
- } else if (!isUndefined((<any>window).g_Workspace)) {
40
- //online has g_Workspace
41
- return true;
42
- } else {
43
- return false;
44
- }
45
- }
46
-
47
- export function restoreExperience() {
48
- var splnu_original = getCookie(MODERN_EXPERIENCE_TEMP_COOKIE_NAME);
49
- deleteCookie(MODERN_EXPERIENCE_TEMP_COOKIE_NAME);
50
- deleteCookie(MODERN_EXPERIENCE_COOKIE_NAME);
51
-
52
- if (isString(splnu_original)) {
53
- setCookie(MODERN_EXPERIENCE_COOKIE_NAME, splnu_original);
54
- }
55
-
56
- var mobile_original = getCookie(MOBILE_EXPERIENCE_TEMP_COOKIE_NAME);
57
- deleteCookie(MOBILE_EXPERIENCE_TEMP_COOKIE_NAME);
58
- deleteCookie(MOBILE_EXPERIENCE_COOKIE_NAME);
59
-
60
- if (isString(mobile_original)) {
61
- setCookie(MOBILE_EXPERIENCE_COOKIE_NAME, mobile_original, null, "/");
62
- }
63
- }
64
-
65
- export function ensureClassicExperience(listId: string) {
66
- var splnu = getCookie(MODERN_EXPERIENCE_COOKIE_NAME);
67
- var mobile = getCookie(MOBILE_EXPERIENCE_COOKIE_NAME);
68
- if (isString(splnu)) {
69
- setCookie(MODERN_EXPERIENCE_TEMP_COOKIE_NAME, splnu);
70
- }
71
- if (isString(mobile)) {
72
- setCookie(MOBILE_EXPERIENCE_TEMP_COOKIE_NAME, splnu);
73
- }
74
- setCookie(MOBILE_EXPERIENCE_COOKIE_NAME, "0", null, "/");
75
- switchToClassicExperience(listId);
76
- }
77
-
78
- export function setExperienceCookie(value: string, reload?: boolean) {
79
- setCookie(MODERN_EXPERIENCE_COOKIE_NAME, value);
80
- if (reload === true) {
81
- window.location.reload();
82
- }
83
- }
84
-
85
- export function switchToClassicExperience(listId: string, reload?: boolean) {
86
- setExperienceCookie(listId ? `{${normalizeGuid(listId)}}` : "0", reload);
87
- }
88
-
89
- export function switchToModernExperience(reload?: boolean) {
90
- setExperienceCookie("1", reload);
91
- }
92
-
93
- /** Gets field schema XML and converts it into JSON object */
94
- export function SchemaXmlToJson(xml: string): IFieldJsonSchema {
95
- let result: IFieldJsonSchema = { Attributes: {}, Customizations: {} };
96
- try {
97
- if (!isNullOrEmptyString(xml !== null)) {
98
- //IE9+ supports this, we don't need to support IE8 anymore
99
- let SchemaXmlDoc: Document = new DOMParser().parseFromString(xml, "text/xml");
100
- let xField = SchemaXmlDoc.getElementsByTagName("Field")[0];
101
- for (var i = 0; i < xField.attributes.length; i++) {
102
- result.Attributes[xField.attributes[i].name] = xField.attributes[i].value;
103
- }
104
-
105
- let properties = xField.querySelectorAll("Customization>ArrayOfProperty>Property");
106
- if (properties && properties.length > 0) {
107
- properties.forEach(p => {
108
- let name = p.querySelector("Name");
109
- let value = p.querySelector("Value");
110
- if (name && value && !isNullOrEmptyString(name.textContent))
111
- result.Customizations[name.textContent] = value.textContent;
112
- });
113
- }
114
- }
115
- } catch (e) { }
116
- return result;
117
- }
118
- export function SchemaJsonToXml(json: IFieldJsonSchema): string {
119
- let doc = new Document();
120
- let fieldElm = doc.createElement("Field");
121
- forEach(json.Attributes, (name, value) => {
122
- fieldElm.setAttribute(name, value);
123
- });
124
- if (Object.keys(json.Customizations).length) {
125
- let custElm = doc.createElement("Customization");
126
- fieldElm.appendChild(custElm);
127
- let arrElm = doc.createElement("ArrayOfProperty");
128
- custElm.appendChild(arrElm);
129
- forEach(json.Customizations, (name, value) => {
130
- let propElm = doc.createElement("Property");
131
- arrElm.appendChild(propElm);
132
-
133
- let nameElm = doc.createElement("Name");
134
- propElm.appendChild(nameElm);
135
- let valElm = doc.createElement("Value");
136
- propElm.appendChild(valElm);
137
- nameElm.innerText = name;
138
- valElm.innerText = value;
139
- });
140
- }
141
- return fieldElm.outerHTML;
142
- }
143
-
144
- export function NormalizeListName(list: { EntityTypeName: string; BaseType: number; }): string {
145
- let Name = list.EntityTypeName;//get list name. if it is a list, it will be [Name]List so cut the list out.
146
- try {
147
- if (list.BaseType === 0 && Name.endsWith("List"))
148
- Name = Name.substr(0, Name.length - 4);//remove List
149
- } catch (e) { }
150
- return Name;
151
- }
152
-
153
- export class SPBasePermissions {
154
- private $High = 0;
155
- private $Low = 0;
156
- public constructor(EffectiveBasePermissions: { High: number; Low: number; }) {
157
- this.initPropertiesFromJson(EffectiveBasePermissions);
158
- }
159
- public set(perm: SPBasePermissionKind) {
160
- if (perm === SPBasePermissionKind.FullMask) {
161
- this.$Low = 65535;
162
- this.$High = 32767;
163
- return;
164
- }
165
-
166
- if (!perm) {
167
- this.$Low = 0;
168
- this.$High = 0;
169
- return;
170
- }
171
- var $v_0 = perm;
172
-
173
- $v_0 = $v_0 - 1;
174
- var $v_1 = 1;
175
-
176
- if ($v_0 >= 0 && $v_0 < 32) {
177
- $v_1 = $v_1 << $v_0;
178
- this.$Low = this.$Low | $v_1;
179
- }
180
- else if ($v_0 >= 32 && $v_0 < 64) {
181
- $v_1 = $v_1 << $v_0 - 32;
182
- this.$High = this.$High | $v_1;
183
- }
184
- }
185
- public clear(perm) {
186
- var $v_0 = perm;
187
-
188
- $v_0 = $v_0 - 1;
189
- var $v_1 = 1;
190
-
191
- if ($v_0 >= 0 && $v_0 < 32) {
192
- $v_1 = $v_1 << $v_0;
193
- $v_1 = ~$v_1;
194
- this.$Low = this.$Low & $v_1;
195
- }
196
- else if ($v_0 >= 32 && $v_0 < 64) {
197
- $v_1 = $v_1 << $v_0 - 32;
198
- $v_1 = ~$v_1;
199
- this.$High = this.$High & $v_1;
200
- }
201
- }
202
- public clearAll() {
203
- this.$High = 0;
204
- this.$Low = 0;
205
- }
206
- public has(perm: SPBasePermissionKind) {
207
- if (!perm) {
208
- return true;
209
- }
210
- if (perm === SPBasePermissionKind.FullMask) {
211
- return (this.$High & 32767) === 32767 && this.$Low === 65535;
212
- }
213
- var $v_0 = perm;
214
-
215
- $v_0 = $v_0 - 1;
216
- var $v_1 = 1;
217
-
218
- if ($v_0 >= 0 && $v_0 < 32) {
219
- $v_1 = $v_1 << $v_0;
220
- return 0 !== (this.$Low & $v_1);
221
- }
222
- else if ($v_0 >= 32 && $v_0 < 64) {
223
- $v_1 = $v_1 << $v_0 - 32;
224
- return 0 !== (this.$High & $v_1);
225
- }
226
- return false;
227
- }
228
- public hasAny(...requestedPerms: SPBasePermissionKind[]) {
229
- return (requestedPerms || []).some((t) => {
230
- return this.has(t);
231
- });
232
- }
233
- public haAll(...requestedPerms: SPBasePermissionKind[]) {
234
- return (requestedPerms || []).every((t) => {
235
- return this.has(t);
236
- });
237
- }
238
- public hasPermissions(requestedPerms: { High: number; Low: number; }) {
239
- return (this.$High & requestedPerms.High) === requestedPerms.High && (this.$Low & requestedPerms.Low) === requestedPerms.Low;
240
- }
241
- public hasAnyPermissions(...requestedPerms: { High: number; Low: number; }[]) {
242
- return (requestedPerms || []).some((t) => {
243
- return this.hasPermissions(t);
244
- });
245
- }
246
- public hasAllPermissions(...requestedPerms: { High: number; Low: number; }[]) {
247
- return (requestedPerms || []).every((t) => {
248
- return this.hasPermissions(t);
249
- });
250
- }
251
- public initPropertiesFromJson(EffectiveBasePermissions: { High: number; Low: number; }) {
252
- this.$High = 0;
253
- this.$Low = 0;
254
- if (isNullOrUndefined(EffectiveBasePermissions)) return;
255
-
256
- if (!isNullOrNaN(EffectiveBasePermissions.High)) {
257
- this.$High = EffectiveBasePermissions.High;
258
- }
259
- if (!isNullOrNaN(EffectiveBasePermissions.Low)) {
260
- this.$Low = EffectiveBasePermissions.Low;
261
- }
262
- }
263
- }
264
-
265
- export interface ISPPeoplePickerControlFormEntity {
266
- /** ie: i:0#.f|membership|user@kwizcom.com */
267
- Key: string;
268
- EntityType: "FormsRole" | "SecGroup" | "SPGroup";
269
- EntityData?: {
270
- SPGroupID?: string;
271
- PrincipalType?: "User" | "SecurityGroup" | "SharePointGroup";
272
- /** string of number "8" */
273
- SPUserID?: string;
274
- SIPAddress?: string;
275
- Email?: string;
276
- };
277
- Resolved?: boolean;
278
- }
279
-
280
- /** remove i:0#.f|membership| prefix from login */
281
- export function CleanupUserClaimsLogin(login: string) {
282
- if (login.indexOf('|membership|') >= 0)
283
- return login.slice(login.lastIndexOf('|') + 1);
284
- else return login;
285
- }
286
-
287
- export function IsSPPeoplePickerControlFormEntity(entity: any): entity is ISPPeoplePickerControlFormEntity {
288
- let asType = entity as ISPPeoplePickerControlFormEntity;
289
- return !isNullOrUndefined(entity)
290
- && !isNullOrEmptyString(asType.Key)
291
- && (!isNullOrUndefined(asType.EntityData) || !isNullOrUndefined(asType.Resolved));
292
- }
293
-
294
- export function getPrincipalTypeFromPickerEntity(entity: ISPPeoplePickerControlFormEntity): PrincipalType.SecurityGroup | PrincipalType.SharePointGroup | PrincipalType.User {
295
- if (entity.EntityType === "FormsRole"
296
- || entity.EntityType === "SecGroup"
297
- || entity.EntityData && entity.EntityData.PrincipalType === "SecurityGroup") {
298
- return PrincipalType.SecurityGroup;
299
- }
300
-
301
- if (entity.EntityType === "SPGroup"
302
- || entity.EntityData && (isNumeric(entity.EntityData.SPGroupID) || entity.EntityData.PrincipalType === "SharePointGroup")) {
303
- return PrincipalType.SharePointGroup;
304
- }
305
-
306
- if (entity.EntityType === "User" || entity.EntityType === "" && entity.EntityData && entity.EntityData.PrincipalType === "User") {
307
- if (entity.EntityData && isValidEmail(entity.EntityData.Email) || isString(entity.EntityData.SIPAddress)) {
308
- return PrincipalType.User;
309
- }
310
-
311
- var keyparts = entity.Key.split("|");
312
- if (keyparts.length === 3 && isValidEmail(keyparts[keyparts.length - 1])) {
313
- //sharepoint online key for a user is in the form xxxx|membership|email;
314
- return PrincipalType.User;
315
- } else if (keyparts.length === 2 && isValidDomainLogin(keyparts[keyparts.length - 1])) {
316
- //sharepoint onpremise key for a user is in the form xxxx|domain\\user;
317
- return PrincipalType.User;
318
- } else {
319
- //SharePoint groups on saved classic forms item are shown with EntityType = User but dont have a SIPAddress/Email
320
- //and the key does not contain a valid domain login/email
321
- return PrincipalType.SharePointGroup;
322
- }
323
- }
324
-
325
- return PrincipalType.User;
326
- }
327
-
328
- /** rest object might put array values under ".results", this will place them at the property value directly */
329
- export function NormalizeRestObject<T>(o: T): T {
330
- //extract collections such as choice field "choices"
331
- if (o) {
332
- Object.keys(o as any).forEach(key => {
333
- if (!isNullOrUndefined(o[key]) && hasOwnProperty(o[key], "results") && Array.isArray(o[key].results))
334
- o[key] = o[key].results;
335
- });
336
- }
337
- return o;
338
- }
339
-
340
- /**
341
- * Extends a field info into field info EX (adding SchemaJson)
342
- * @param field REST field data
343
- * @param allFields Optional - all list fields, used for discovering multi TaxonomyField's update hidden text field
344
- */
345
- export function extendFieldInfo(field: IFieldInfo, allFields?: IFieldInfo[]): IFieldInfoEX {
346
- let fieldEx = field as IFieldInfoEX;
347
- fieldEx.Id = normalizeGuid(field.Id);
348
-
349
- if (field.InternalName === "ContentType") {
350
- fieldEx.Required = true;
351
- }
352
- else {
353
- switch (fieldEx.TypeAsString) {
354
- case "TaxonomyFieldTypeMulti"://find the hidden rich text for updates!
355
- {
356
- let taxonomyField = (fieldEx as IFieldTaxonomyInfo);
357
- let textFieldId = normalizeGuid(taxonomyField.TextField);
358
- let related = isNotEmptyArray(allFields) ? firstOrNull(allFields, relatedField => relatedField.Id === textFieldId) : null;
359
- if (related !== null)
360
- taxonomyField.HiddenMultiValueFieldName = related.InternalName;
361
- }
362
- break;
363
- }
364
- }
365
-
366
- fieldEx.OutputTypeAsString = getFieldOutputType(fieldEx);
367
-
368
- if (isNullOrUndefined(fieldEx.SchemaJson)) {
369
- Object.defineProperty(fieldEx, 'SchemaJson', {
370
- get: function () {
371
- if (isUndefined(this._schemaJson)) {
372
- this._schemaJson = SchemaXmlToJson(this.SchemaXml);
373
- }
374
- return this._schemaJson;
375
- }
376
- });
377
- }
378
-
379
- if (field.InternalName === KWIZ_CONTROLLER_FIELD_NAME) {
380
- //not hidden by SharePoint so its shown in views/forms but as far as our products concerned - should be treated as hidden
381
- field.Hidden = true;
382
- }
383
-
384
- return fieldEx;
385
- }
386
-
387
- export function getFieldOutputType(field: IFieldInfo) {
388
- let outputType = field.TypeAsString;
389
-
390
- if (outputType === "Calculated") {
391
- switch ((field as IFieldCalculatedInfo).OutputType) {
392
- case FieldTypes.DateTime:
393
- outputType = "DateTime";
394
- break;
395
- case FieldTypes.Boolean:
396
- outputType = "Boolean";
397
- break;
398
- case FieldTypes.Currency:
399
- outputType = "Currency";
400
- break;
401
- case FieldTypes.Number:
402
- outputType = "Number";
403
- break;
404
- default:
405
- outputType = "Text";
406
- break;
407
- }
408
- }
409
-
410
- return outputType as FieldTypeAsString;
411
- }
412
-
413
- export function isDocLib(list?: { BaseType: number; }): boolean {
414
- return list && list.BaseType === 1;
415
- }
416
-
417
- export function GetOrderByFromCaml(camlQuery: string): { Name: string; IsAscending: boolean; }[] {
418
- let xmlDoc = new DOMParser().parseFromString(camlQuery, "text/xml");
419
-
420
- let orderByElm = xmlDoc.querySelector("OrderBy");
421
- let OrderBy: { Name: string; IsAscending: boolean; }[] = [];
422
- if (orderByElm) {
423
- let orderFieldsElms = orderByElm.querySelectorAll("FieldRef");
424
- orderFieldsElms.forEach(f => {
425
- let name = f.getAttribute("Name");
426
- let asc = f.getAttribute("Ascending") || "";
427
- //Issue 1019 default value is true if ommitted - https://learn.microsoft.com/en-us/sharepoint/dev/schema/fieldref-element-query
428
- let IsAscending = asc.toUpperCase() !== "FALSE";
429
- if (!isNullOrEmptyString(name))
430
- OrderBy.push({ Name: name, IsAscending: IsAscending });
431
- });
432
- }
433
-
434
- return OrderBy;
435
- }
436
-
437
- export function RemoveOrderByFromCaml(camlQuery: string): string {
438
- let xmlDoc = new DOMParser().parseFromString(camlQuery, "text/xml");
439
-
440
- let orderByElm = xmlDoc.querySelector("OrderBy");
441
- //let OrderBy: { Name: string; IsAscending: boolean; }[] = [];
442
- if (orderByElm) {
443
- orderByElm.remove();
444
- return xmlDoc.documentElement.outerHTML;
445
- }
446
-
447
- return camlQuery;
448
- }
449
-
450
- export function EnsureViewFields(camlQuery: string, fields: string[], forceCreateViewFields: boolean, removeAllOthers?: boolean) {
451
- let xmlDoc = new DOMParser().parseFromString(camlQuery, "text/xml");
452
- let viewElm = xmlDoc.querySelector("View");
453
- if (!isNullOrUndefined(viewElm)) {
454
- let viewFieldsElm = viewElm.querySelector("ViewFields");
455
-
456
- if (forceCreateViewFields && isNullOrUndefined(viewFieldsElm)) {
457
- viewFieldsElm = xmlDoc.createElement("ViewFields");
458
- viewElm.appendChild(viewFieldsElm);
459
- }
460
-
461
- if (!isNullOrUndefined(viewFieldsElm)) {
462
- let viewFieldsElms = viewFieldsElm.querySelectorAll("FieldRef");
463
-
464
- if (removeAllOthers)
465
- viewFieldsElms.forEach(e => e.remove());
466
-
467
- let viewFields = removeAllOthers ? [] : Array.from(viewFieldsElms).map(viewFieldNode => {
468
- let name = viewFieldNode.getAttribute("Name");
469
- return name.toLowerCase();
470
- });
471
-
472
- let changed = false;
473
- fields.forEach(f => {
474
- if (viewFields.indexOf(f.toLowerCase()) === -1) {
475
- let newViewFieldElm = xmlDoc.createElement("FieldRef");
476
- newViewFieldElm.setAttribute("Name", f);
477
- viewFieldsElm.appendChild(newViewFieldElm);
478
- changed = true;
479
- }
480
- });
481
-
482
- if (viewFieldsElm.querySelectorAll("FieldRef").length < 1 && !forceCreateViewFields) {
483
- //don't leave an empty object
484
- viewFieldsElm.remove();
485
- changed = true;
486
- }
487
-
488
- if (changed) return xmlDoc.documentElement.outerHTML;
489
- }
490
- }
491
-
492
- return camlQuery;
493
- }
494
-
495
- /**If it is a thumbnail field - parse and return a typed value */
496
- export function ParseThumbnalFieldValue(value?: string, context?: {
497
- itemId: number;
498
- rootFolder: string;
499
- }): ThumbnailValueType {
500
- if (!isNullOrEmptyString(value)) {
501
- try {
502
- let parsed = jsonParse<ThumbnailValueType>(value);
503
-
504
- if (isNullOrUndefined(parsed)) {
505
- return null;
506
- }
507
-
508
- if (!isNullOrEmptyString(parsed.serverRelativeUrl)) {
509
- return parsed;
510
- } else if (!isNullOrEmptyString(parsed.fileName)
511
- && !isNullOrUndefined(context)
512
- && isNumber(context.itemId)
513
- && !isNullOrEmptyString(context.rootFolder)) {
514
- let { itemId, rootFolder } = context;
515
- parsed.serverRelativeUrl = `${makeServerRelativeUrl(rootFolder)}/Attachments/${itemId}/${parsed.fileName}`
516
- return parsed;
517
- }
518
- } catch (e) {
519
- }
520
- }
521
- return null;
522
- }
523
-
524
- export function isTitleField(fieldName: string) {
525
- return fieldName === "Title" || fieldName === "LinkTitleNoMenu" || fieldName === "LinkTitle";
526
- }
527
-
528
- /** we are on a list view page, not a web part page with possible multiple list views */
529
- export function isSingleViewPage() {
530
- return !isNullOrUndefined(_spPageContextInfo) && isValidGuid(_spPageContextInfo.viewId);
531
- }
532
-
533
- /**
534
- * Splits the ViewFields of a CAML query into separate entries based on the batch size.
535
- * @param {string} camlQuery - The CAML query string.
536
- * @param {number} batchSize - The size of each batch (number of ViewFields per entry).
537
- */
538
- export function splitViewFieldsByBatch(camlQuery: string, allListFieldsToLowerHash: IDictionary<IFieldInfoEX>, batchSize: number): string[] {
539
- let xmlDoc = new DOMParser().parseFromString(camlQuery, 'text/xml');
540
- let viewNode = xmlDoc.querySelector("View, view");
541
- let viewFieldsNode = viewNode && viewNode.querySelector("ViewFields, viewfields");
542
-
543
- if (isNullOrUndefined(viewFieldsNode)) {
544
- return [camlQuery]; // No ViewFields element found, return the original query as is
545
- }
546
-
547
- let viewFieldNodes = Array.from(viewFieldsNode.children);
548
- let numberOfEntries = Math.ceil(viewFieldNodes.length / batchSize);
549
-
550
- let splitQueries: string[] = [];
551
- for (let i = 0; i < numberOfEntries; i++) {
552
- let startIndex = i * batchSize;
553
- let endIndex = startIndex + batchSize;
554
- let slicedViewFields = viewFieldNodes.slice(startIndex, endIndex);
555
-
556
- let clonedXmlDoc = xmlDoc.cloneNode(true) as XMLDocument;
557
- let clonedViewFieldsElement = clonedXmlDoc.getElementsByTagName('ViewFields')[0];
558
-
559
- // Remove existing child nodes from cloned ViewFields
560
- while (clonedViewFieldsElement.firstChild) {
561
- clonedViewFieldsElement.removeChild(clonedViewFieldsElement.firstChild);
562
- }
563
-
564
- // Append sliced ViewFields to cloned ViewFields
565
- for (let slicedViewField of slicedViewFields) {
566
- clonedViewFieldsElement.appendChild(slicedViewField.cloneNode(true));
567
- }
568
-
569
- let splitQuery = new XMLSerializer().serializeToString(clonedXmlDoc);
570
- splitQueries.push(splitQuery);
571
- }
572
-
573
- return splitQueries;
574
- }
575
-
576
- /** Size=S = 48×48 px, M = 72×72 px, L = 300×300 px */
577
- export function UserPhoto(siteUrl: string, userName: string, size: "S" | "M" | "L" = "L") {
578
- return `${normalizeUrl(siteUrl)}/_layouts/15/userphoto.aspx?size=${size}&accountname=${encodeURIComponent(userName)}`;
579
- }
580
-
581
- export function IsFolderContentType(contentTypeId: string) {
582
- //item:0x0100
583
- //file:0x0101
584
- //folder:0x0120
585
- //item in MS Lists:0x00 Issue 7121
586
- return contentTypeId.startsWith("0x0120");
587
- }
588
-
589
- export enum PageContainerTypes {
590
- M365SPFx, M365OOBListForm,
591
- SP2019SPFx, SP2019ListForm
592
- }
593
- export function GetModernPageContainers() {
594
- let mainContent: HTMLElement = document.querySelector("section.mainContent");
595
- if (mainContent)
596
- return { mainContent, commandBar: document.querySelector(".commandBarWrapper") as HTMLElement, type: PageContainerTypes.M365SPFx };
597
-
598
- mainContent = document.querySelector("div[class^=canvasWrapper]");//document.querySelector("div.SPCanvas");
599
- if (mainContent)
600
- return { mainContent, commandBar: document.querySelector(".commandBarWrapper") as HTMLElement, type: PageContainerTypes.SP2019SPFx };
601
-
602
- mainContent = document.querySelector(".flex-mainColumn");
603
- if (mainContent)
604
- return { mainContent, commandBar: null, type: PageContainerTypes.M365OOBListForm };
605
-
606
- mainContent = document.querySelector(".Files-mainColumn");
607
- if (mainContent)
608
- return { mainContent, commandBar: null, type: PageContainerTypes.SP2019ListForm };
609
-
610
- return { mainContent: null, commandBar: null, type: PageContainerTypes.SP2019ListForm };
611
- }
612
-
613
- export function AddCamlQueryFragmentToViewQuery(viewXml: string, queryFragmentXml: string): string {
614
-
615
- const combineWithExistingConditions = (doc: XMLDocument, existingConditions: Element[], newConditionXml: string): Element => {
616
- const parser = new DOMParser();
617
- const newConditionDoc = parser.parseFromString(newConditionXml, 'text/xml');
618
- const newCondition = doc.importNode(newConditionDoc.documentElement, true);
619
-
620
- if (existingConditions.length === 0) {
621
- return newCondition;
622
- } else if (existingConditions.length === 1) {
623
- const andElement = doc.createElement("And");
624
- andElement.appendChild(existingConditions[0]);
625
- andElement.appendChild(newCondition);
626
- return andElement;
627
- } else {
628
- const lastCondition = existingConditions.pop();
629
- const andElement = doc.createElement("And");
630
- andElement.appendChild(combineWithExistingConditions(doc, existingConditions, ""));
631
- andElement.appendChild(lastCondition);
632
- return andElement;
633
- }
634
- }
635
- try {
636
- const parser = new DOMParser();
637
- const xmlDoc = parser.parseFromString(viewXml, 'text/xml');
638
- const whereClause = xmlDoc.querySelector('Where') || xmlDoc.createElement('Where');
639
- const existingConditions = Array.from(whereClause.children);
640
-
641
- const combinedCondition = combineWithExistingConditions(xmlDoc, existingConditions, queryFragmentXml);
642
- whereClause.textContent = ''; // Clear existing conditions
643
- whereClause.appendChild(combinedCondition);
644
-
645
- const query = xmlDoc.querySelector('Query') || xmlDoc.createElement('Query');
646
- query.appendChild(whereClause);
647
-
648
- const view = xmlDoc.querySelector('View') || xmlDoc.createElement('View');
649
- view.appendChild(query);
650
-
651
- const serializer = new XMLSerializer();
652
- let modifiedCamlXml = serializer.serializeToString(xmlDoc);
653
-
654
- return modifiedCamlXml;
655
- } catch (error) {
656
- return viewXml;
657
- }
658
- }
659
-
660
- export function IsUserEntityValueType(value: any): value is UserEntityValueType {
661
- if (isNullOrUndefined(value) || isString(value)) {
662
- return false;
663
- }
664
- var asUserEntityValueType = value as UserEntityValueType;
665
- var isEntityValueType =
666
- asUserEntityValueType.principalType === PrincipalType.SharePointGroup
667
- || asUserEntityValueType.principalType === PrincipalType.User
668
- || asUserEntityValueType.principalType === PrincipalType.SecurityGroup;
669
-
670
- return isEntityValueType;
671
- }
672
-
673
- export function IsMultiUserEntityValueType(value: any[]): value is UserEntityValueType[] {
674
- if (isNullOrUndefined(value) || isString(value) || !Array.isArray(value)) {
675
- return false;
676
- }
677
-
678
- return value.every((v) => {
679
- return IsUserEntityValueType(v);
680
- });
681
- }
682
-
683
- export function IsUrlValueType(value: any): value is UrlValueType {
684
- if (isNullOrUndefined(value) || isString(value)) {
685
- return false;
686
- }
687
- let asType = value as UrlValueType;
688
- return !isNullOrUndefined(asType.Url) && !isNullOrUndefined(asType.Description);
689
- }
690
-
691
- export function IsRetentionLabelValueType(value: any): value is RententionLabelFieldValueType {
692
- if (isNullOrUndefined(value) || isString(value)) {
693
- return false;
694
- }
695
- let asType = value as RententionLabelFieldValueType;
696
- return isValidGuid(asType.TagId) && !isNullOrEmptyString(asType.TagName);
697
- }
698
-
699
- export function isHostedInTeams() {
700
- return window.location.pathname.toLowerCase().indexOf("teamshostedapp.aspx") >= 0;
701
- }
702
- export function isClassicAppIframe() {
703
- return window.location.search.toLowerCase().indexOf("sphosturl=") >= 0 &&
704
- window.location.search.toLowerCase().indexOf("spappweburl=") >= 0;
705
- }
706
-
707
- export function isNumberFieldType(fieldInfo: IFieldInfoEX) {
708
- let targetColumnOutputType = getFieldOutputType(fieldInfo);
709
- return targetColumnOutputType === "Currency"
710
- || targetColumnOutputType === "Number"
711
- || targetColumnOutputType === "Counter"
712
- || targetColumnOutputType === "Integer";
713
- }
714
-
715
- export async function isSharePointOnline() {
716
- let url = new URL(window.location.href);
717
- //Most cases are satisfied by this check. Very few customers have custom domains for SharePoint online.
718
- if (url.host.toLowerCase().endsWith(".sharepoint.com")) {
719
- return true;
720
- }
721
-
722
- let contextReady = await waitFor(() => {
723
- return !isTypeofFullNameUndefined("_spPageContextInfo");
724
- });
725
-
726
- if (contextReady) {
727
- return _spPageContextInfo.isSPO === true;
728
- }
729
-
730
- return false;
731
- }
732
-
733
- export function isSharePointOnlineSync() {
734
- let url = new URL(window.location.href);
735
- //Most cases are satisfied by this check. Very few customers have custom domains for SharePoint online.
736
- if (url.host.toLowerCase().endsWith(".sharepoint.com")) {
737
- return true;
738
- }
739
-
740
- if (!isTypeofFullNameUndefined("_spPageContextInfo")) {
741
- return _spPageContextInfo.isSPO === true;
742
- }
743
-
744
- return false;
745
- }
746
-
747
- export async function isAppWeb() {
748
- let contextReady = await waitFor(() => {
749
- return !isTypeofFullNameUndefined("_spPageContextInfo");
750
- });
751
-
752
- if (contextReady) {
753
- return _spPageContextInfo.isAppWeb === true;
754
- }
755
-
756
- return false;
757
- }
758
-
759
- export function isAppWebSync() {
760
- if (!isTypeofFullNameUndefined("_spPageContextInfo")) {
761
- return _spPageContextInfo.isAppWeb === true;
762
- }
763
-
764
- return false;
765
- }
766
-
767
- export async function isSPPageContextInfoReady() {
768
- return await waitForWindowObject("_spPageContextInfo");
769
- }
770
-
771
- export function isSPPageContextInfoReadySync() {
772
- return !isTypeofFullNameNullOrUndefined("_spPageContextInfo");
1
+ import { IDictionary } from "../types/common.types";
2
+ import { FieldTypeAsString, FieldTypes, IFieldCalculatedInfo, IFieldInfo, IFieldInfoEX, IFieldJsonSchema, IFieldTaxonomyInfo, PrincipalType, RententionLabelFieldValueType, SPBasePermissionKind, ThumbnailValueType, UrlValueType } from "../types/sharepoint.types";
3
+ import { UserEntityValueType } from "../types/sharepoint.utils.types";
4
+ import { waitFor, waitForWindowObject } from "./browser";
5
+ import { firstOrNull, forEach } from "./collections.base";
6
+ import { deleteCookie, getCookie, setCookie } from "./cookies";
7
+ import { isValidEmail } from "./emails";
8
+ import { jsonParse } from "./json";
9
+ import { hasOwnProperty } from "./objects";
10
+ import { isValidDomainLogin, normalizeGuid } from "./strings";
11
+ import { isNotEmptyArray, isNullOrEmptyString, isNullOrNaN, isNullOrUndefined, isNumber, isNumeric, isString, isTypeofFullNameNullOrUndefined, isTypeofFullNameUndefined, isUndefined, isValidGuid } from "./typecheckers";
12
+ import { makeServerRelativeUrl, normalizeUrl } from "./url";
13
+
14
+ export const KWIZ_CONTROLLER_FIELD_NAME = "kwizcomcontrollerfield";
15
+ const MODERN_EXPERIENCE_COOKIE_NAME = "splnu";
16
+ const MODERN_EXPERIENCE_TEMP_COOKIE_NAME = `${MODERN_EXPERIENCE_COOKIE_NAME}_kwizcom_original`;
17
+ const MOBILE_EXPERIENCE_COOKIE_NAME = "mobile";
18
+ const MOBILE_EXPERIENCE_TEMP_COOKIE_NAME = `${MOBILE_EXPERIENCE_COOKIE_NAME}_kwizcom_original`;
19
+
20
+ //const logger = ConsoleLogger.get("_modules/helpers/sharepoint");
21
+ export function IsClassicPage() {
22
+ //on premises has g_spribbon but no g_Workspace
23
+ //can't use g_spribbon because it gets created whenever you load the init.js script
24
+ if (!isUndefined(window)
25
+ && window.document
26
+ && document.body
27
+ && document.body.childNodes.length
28
+ && document.body.childNodes) {
29
+ //only classic pages have the s4-workspace element, so try this first because it is the most reliable
30
+ return !!document.getElementById("s4-workspace");
31
+ } else if (!isUndefined((<any>window)._spWebPartComponents)) {
32
+ //only classic pages have the _spWebPartComponents object created on the page inline, not in a script that
33
+ //can be loaded
34
+ return true;
35
+ } else if (!isUndefined((<any>window)._spClientSideComponentIds)) {
36
+ //only modern pages have the _spClientSideComponentIds object created on the page inline, not a in script that
37
+ //can be loaded
38
+ return false;
39
+ } else if (!isUndefined((<any>window).g_Workspace)) {
40
+ //online has g_Workspace
41
+ return true;
42
+ } else {
43
+ return false;
44
+ }
45
+ }
46
+
47
+ export function restoreExperience() {
48
+ var splnu_original = getCookie(MODERN_EXPERIENCE_TEMP_COOKIE_NAME);
49
+ deleteCookie(MODERN_EXPERIENCE_TEMP_COOKIE_NAME);
50
+ deleteCookie(MODERN_EXPERIENCE_COOKIE_NAME);
51
+
52
+ if (isString(splnu_original)) {
53
+ setCookie(MODERN_EXPERIENCE_COOKIE_NAME, splnu_original);
54
+ }
55
+
56
+ var mobile_original = getCookie(MOBILE_EXPERIENCE_TEMP_COOKIE_NAME);
57
+ deleteCookie(MOBILE_EXPERIENCE_TEMP_COOKIE_NAME);
58
+ deleteCookie(MOBILE_EXPERIENCE_COOKIE_NAME);
59
+
60
+ if (isString(mobile_original)) {
61
+ setCookie(MOBILE_EXPERIENCE_COOKIE_NAME, mobile_original, null, "/");
62
+ }
63
+ }
64
+
65
+ export function ensureClassicExperience(listId: string) {
66
+ var splnu = getCookie(MODERN_EXPERIENCE_COOKIE_NAME);
67
+ var mobile = getCookie(MOBILE_EXPERIENCE_COOKIE_NAME);
68
+ if (isString(splnu)) {
69
+ setCookie(MODERN_EXPERIENCE_TEMP_COOKIE_NAME, splnu);
70
+ }
71
+ if (isString(mobile)) {
72
+ setCookie(MOBILE_EXPERIENCE_TEMP_COOKIE_NAME, splnu);
73
+ }
74
+ setCookie(MOBILE_EXPERIENCE_COOKIE_NAME, "0", null, "/");
75
+ switchToClassicExperience(listId);
76
+ }
77
+
78
+ export function setExperienceCookie(value: string, reload?: boolean) {
79
+ setCookie(MODERN_EXPERIENCE_COOKIE_NAME, value);
80
+ if (reload === true) {
81
+ window.location.reload();
82
+ }
83
+ }
84
+
85
+ export function switchToClassicExperience(listId: string, reload?: boolean) {
86
+ setExperienceCookie(listId ? `{${normalizeGuid(listId)}}` : "0", reload);
87
+ }
88
+
89
+ export function switchToModernExperience(reload?: boolean) {
90
+ setExperienceCookie("1", reload);
91
+ }
92
+
93
+ /** Gets field schema XML and converts it into JSON object */
94
+ export function SchemaXmlToJson(xml: string): IFieldJsonSchema {
95
+ let result: IFieldJsonSchema = { Attributes: {}, Customizations: {} };
96
+ try {
97
+ if (!isNullOrEmptyString(xml !== null)) {
98
+ //IE9+ supports this, we don't need to support IE8 anymore
99
+ let SchemaXmlDoc: Document = new DOMParser().parseFromString(xml, "text/xml");
100
+ let xField = SchemaXmlDoc.getElementsByTagName("Field")[0];
101
+ for (var i = 0; i < xField.attributes.length; i++) {
102
+ result.Attributes[xField.attributes[i].name] = xField.attributes[i].value;
103
+ }
104
+
105
+ let properties = xField.querySelectorAll("Customization>ArrayOfProperty>Property");
106
+ if (properties && properties.length > 0) {
107
+ properties.forEach(p => {
108
+ let name = p.querySelector("Name");
109
+ let value = p.querySelector("Value");
110
+ if (name && value && !isNullOrEmptyString(name.textContent))
111
+ result.Customizations[name.textContent] = value.textContent;
112
+ });
113
+ }
114
+ }
115
+ } catch (e) { }
116
+ return result;
117
+ }
118
+ export function SchemaJsonToXml(json: IFieldJsonSchema): string {
119
+ let doc = new Document();
120
+ let fieldElm = doc.createElement("Field");
121
+ forEach(json.Attributes, (name, value) => {
122
+ fieldElm.setAttribute(name, value);
123
+ });
124
+ if (Object.keys(json.Customizations).length) {
125
+ let custElm = doc.createElement("Customization");
126
+ fieldElm.appendChild(custElm);
127
+ let arrElm = doc.createElement("ArrayOfProperty");
128
+ custElm.appendChild(arrElm);
129
+ forEach(json.Customizations, (name, value) => {
130
+ let propElm = doc.createElement("Property");
131
+ arrElm.appendChild(propElm);
132
+
133
+ let nameElm = doc.createElement("Name");
134
+ propElm.appendChild(nameElm);
135
+ let valElm = doc.createElement("Value");
136
+ propElm.appendChild(valElm);
137
+ nameElm.innerText = name;
138
+ valElm.innerText = value;
139
+ });
140
+ }
141
+ return fieldElm.outerHTML;
142
+ }
143
+
144
+ export function NormalizeListName(list: { EntityTypeName: string; BaseType: number; }): string {
145
+ let Name = list.EntityTypeName;//get list name. if it is a list, it will be [Name]List so cut the list out.
146
+ try {
147
+ if (list.BaseType === 0 && Name.endsWith("List"))
148
+ Name = Name.substr(0, Name.length - 4);//remove List
149
+ } catch (e) { }
150
+ return Name;
151
+ }
152
+
153
+ export class SPBasePermissions {
154
+ private $High = 0;
155
+ private $Low = 0;
156
+ public constructor(EffectiveBasePermissions: { High: number; Low: number; }) {
157
+ this.initPropertiesFromJson(EffectiveBasePermissions);
158
+ }
159
+ public set(perm: SPBasePermissionKind) {
160
+ if (perm === SPBasePermissionKind.FullMask) {
161
+ this.$Low = 65535;
162
+ this.$High = 32767;
163
+ return;
164
+ }
165
+
166
+ if (!perm) {
167
+ this.$Low = 0;
168
+ this.$High = 0;
169
+ return;
170
+ }
171
+ var $v_0 = perm;
172
+
173
+ $v_0 = $v_0 - 1;
174
+ var $v_1 = 1;
175
+
176
+ if ($v_0 >= 0 && $v_0 < 32) {
177
+ $v_1 = $v_1 << $v_0;
178
+ this.$Low = this.$Low | $v_1;
179
+ }
180
+ else if ($v_0 >= 32 && $v_0 < 64) {
181
+ $v_1 = $v_1 << $v_0 - 32;
182
+ this.$High = this.$High | $v_1;
183
+ }
184
+ }
185
+ public clear(perm) {
186
+ var $v_0 = perm;
187
+
188
+ $v_0 = $v_0 - 1;
189
+ var $v_1 = 1;
190
+
191
+ if ($v_0 >= 0 && $v_0 < 32) {
192
+ $v_1 = $v_1 << $v_0;
193
+ $v_1 = ~$v_1;
194
+ this.$Low = this.$Low & $v_1;
195
+ }
196
+ else if ($v_0 >= 32 && $v_0 < 64) {
197
+ $v_1 = $v_1 << $v_0 - 32;
198
+ $v_1 = ~$v_1;
199
+ this.$High = this.$High & $v_1;
200
+ }
201
+ }
202
+ public clearAll() {
203
+ this.$High = 0;
204
+ this.$Low = 0;
205
+ }
206
+ public has(perm: SPBasePermissionKind) {
207
+ if (!perm) {
208
+ return true;
209
+ }
210
+ if (perm === SPBasePermissionKind.FullMask) {
211
+ return (this.$High & 32767) === 32767 && this.$Low === 65535;
212
+ }
213
+ var $v_0 = perm;
214
+
215
+ $v_0 = $v_0 - 1;
216
+ var $v_1 = 1;
217
+
218
+ if ($v_0 >= 0 && $v_0 < 32) {
219
+ $v_1 = $v_1 << $v_0;
220
+ return 0 !== (this.$Low & $v_1);
221
+ }
222
+ else if ($v_0 >= 32 && $v_0 < 64) {
223
+ $v_1 = $v_1 << $v_0 - 32;
224
+ return 0 !== (this.$High & $v_1);
225
+ }
226
+ return false;
227
+ }
228
+ public hasAny(...requestedPerms: SPBasePermissionKind[]) {
229
+ return (requestedPerms || []).some((t) => {
230
+ return this.has(t);
231
+ });
232
+ }
233
+ public haAll(...requestedPerms: SPBasePermissionKind[]) {
234
+ return (requestedPerms || []).every((t) => {
235
+ return this.has(t);
236
+ });
237
+ }
238
+ public hasPermissions(requestedPerms: { High: number; Low: number; }) {
239
+ return (this.$High & requestedPerms.High) === requestedPerms.High && (this.$Low & requestedPerms.Low) === requestedPerms.Low;
240
+ }
241
+ public hasAnyPermissions(...requestedPerms: { High: number; Low: number; }[]) {
242
+ return (requestedPerms || []).some((t) => {
243
+ return this.hasPermissions(t);
244
+ });
245
+ }
246
+ public hasAllPermissions(...requestedPerms: { High: number; Low: number; }[]) {
247
+ return (requestedPerms || []).every((t) => {
248
+ return this.hasPermissions(t);
249
+ });
250
+ }
251
+ public initPropertiesFromJson(EffectiveBasePermissions: { High: number; Low: number; }) {
252
+ this.$High = 0;
253
+ this.$Low = 0;
254
+ if (isNullOrUndefined(EffectiveBasePermissions)) return;
255
+
256
+ if (!isNullOrNaN(EffectiveBasePermissions.High)) {
257
+ this.$High = EffectiveBasePermissions.High;
258
+ }
259
+ if (!isNullOrNaN(EffectiveBasePermissions.Low)) {
260
+ this.$Low = EffectiveBasePermissions.Low;
261
+ }
262
+ }
263
+ }
264
+
265
+ export interface ISPPeoplePickerControlFormEntity {
266
+ /** ie: i:0#.f|membership|user@kwizcom.com */
267
+ Key: string;
268
+ EntityType: "FormsRole" | "SecGroup" | "SPGroup";
269
+ EntityData?: {
270
+ SPGroupID?: string;
271
+ PrincipalType?: "User" | "SecurityGroup" | "SharePointGroup";
272
+ /** string of number "8" */
273
+ SPUserID?: string;
274
+ SIPAddress?: string;
275
+ Email?: string;
276
+ };
277
+ Resolved?: boolean;
278
+ }
279
+
280
+ /** remove i:0#.f|membership| prefix from login */
281
+ export function CleanupUserClaimsLogin(login: string) {
282
+ if (login.indexOf('|membership|') >= 0)
283
+ return login.slice(login.lastIndexOf('|') + 1);
284
+ else return login;
285
+ }
286
+
287
+ export function IsSPPeoplePickerControlFormEntity(entity: any): entity is ISPPeoplePickerControlFormEntity {
288
+ let asType = entity as ISPPeoplePickerControlFormEntity;
289
+ return !isNullOrUndefined(entity)
290
+ && !isNullOrEmptyString(asType.Key)
291
+ && (!isNullOrUndefined(asType.EntityData) || !isNullOrUndefined(asType.Resolved));
292
+ }
293
+
294
+ export function getPrincipalTypeFromPickerEntity(entity: ISPPeoplePickerControlFormEntity): PrincipalType.SecurityGroup | PrincipalType.SharePointGroup | PrincipalType.User {
295
+ if (entity.EntityType === "FormsRole"
296
+ || entity.EntityType === "SecGroup"
297
+ || entity.EntityData && entity.EntityData.PrincipalType === "SecurityGroup") {
298
+ return PrincipalType.SecurityGroup;
299
+ }
300
+
301
+ if (entity.EntityType === "SPGroup"
302
+ || entity.EntityData && (isNumeric(entity.EntityData.SPGroupID) || entity.EntityData.PrincipalType === "SharePointGroup")) {
303
+ return PrincipalType.SharePointGroup;
304
+ }
305
+
306
+ if (entity.EntityType === "User" || entity.EntityType === "" && entity.EntityData && entity.EntityData.PrincipalType === "User") {
307
+ if (entity.EntityData && isValidEmail(entity.EntityData.Email) || isString(entity.EntityData.SIPAddress)) {
308
+ return PrincipalType.User;
309
+ }
310
+
311
+ var keyparts = entity.Key.split("|");
312
+ if (keyparts.length === 3 && isValidEmail(keyparts[keyparts.length - 1])) {
313
+ //sharepoint online key for a user is in the form xxxx|membership|email;
314
+ return PrincipalType.User;
315
+ } else if (keyparts.length === 2 && isValidDomainLogin(keyparts[keyparts.length - 1])) {
316
+ //sharepoint onpremise key for a user is in the form xxxx|domain\\user;
317
+ return PrincipalType.User;
318
+ } else {
319
+ //SharePoint groups on saved classic forms item are shown with EntityType = User but dont have a SIPAddress/Email
320
+ //and the key does not contain a valid domain login/email
321
+ return PrincipalType.SharePointGroup;
322
+ }
323
+ }
324
+
325
+ return PrincipalType.User;
326
+ }
327
+
328
+ /** rest object might put array values under ".results", this will place them at the property value directly */
329
+ export function NormalizeRestObject<T>(o: T): T {
330
+ //extract collections such as choice field "choices"
331
+ if (o) {
332
+ Object.keys(o as any).forEach(key => {
333
+ if (!isNullOrUndefined(o[key]) && hasOwnProperty(o[key], "results") && Array.isArray(o[key].results))
334
+ o[key] = o[key].results;
335
+ });
336
+ }
337
+ return o;
338
+ }
339
+
340
+ /**
341
+ * Extends a field info into field info EX (adding SchemaJson)
342
+ * @param field REST field data
343
+ * @param allFields Optional - all list fields, used for discovering multi TaxonomyField's update hidden text field
344
+ */
345
+ export function extendFieldInfo(field: IFieldInfo, allFields?: IFieldInfo[]): IFieldInfoEX {
346
+ let fieldEx = field as IFieldInfoEX;
347
+ fieldEx.Id = normalizeGuid(field.Id);
348
+
349
+ if (field.InternalName === "ContentType") {
350
+ fieldEx.Required = true;
351
+ }
352
+ else {
353
+ switch (fieldEx.TypeAsString) {
354
+ case "TaxonomyFieldTypeMulti"://find the hidden rich text for updates!
355
+ {
356
+ let taxonomyField = (fieldEx as IFieldTaxonomyInfo);
357
+ let textFieldId = normalizeGuid(taxonomyField.TextField);
358
+ let related = isNotEmptyArray(allFields) ? firstOrNull(allFields, relatedField => relatedField.Id === textFieldId) : null;
359
+ if (related !== null)
360
+ taxonomyField.HiddenMultiValueFieldName = related.InternalName;
361
+ }
362
+ break;
363
+ }
364
+ }
365
+
366
+ fieldEx.OutputTypeAsString = getFieldOutputType(fieldEx);
367
+
368
+ if (isNullOrUndefined(fieldEx.SchemaJson)) {
369
+ Object.defineProperty(fieldEx, 'SchemaJson', {
370
+ get: function () {
371
+ if (isUndefined(this._schemaJson)) {
372
+ this._schemaJson = SchemaXmlToJson(this.SchemaXml);
373
+ }
374
+ return this._schemaJson;
375
+ }
376
+ });
377
+ }
378
+
379
+ if (field.InternalName === KWIZ_CONTROLLER_FIELD_NAME) {
380
+ //not hidden by SharePoint so its shown in views/forms but as far as our products concerned - should be treated as hidden
381
+ field.Hidden = true;
382
+ }
383
+
384
+ return fieldEx;
385
+ }
386
+
387
+ export function extendFieldInfos(fields: IFieldInfo[]) {
388
+ return fields.map(f => extendFieldInfo(f, fields));
389
+ }
390
+
391
+ export function getFieldOutputType(field: IFieldInfo) {
392
+ let outputType = field.TypeAsString;
393
+
394
+ if (outputType === "Calculated") {
395
+ switch ((field as IFieldCalculatedInfo).OutputType) {
396
+ case FieldTypes.DateTime:
397
+ outputType = "DateTime";
398
+ break;
399
+ case FieldTypes.Boolean:
400
+ outputType = "Boolean";
401
+ break;
402
+ case FieldTypes.Currency:
403
+ outputType = "Currency";
404
+ break;
405
+ case FieldTypes.Number:
406
+ outputType = "Number";
407
+ break;
408
+ default:
409
+ outputType = "Text";
410
+ break;
411
+ }
412
+ }
413
+
414
+ return outputType as FieldTypeAsString;
415
+ }
416
+
417
+ export function isDocLib(list?: { BaseType: number; }): boolean {
418
+ return list && list.BaseType === 1;
419
+ }
420
+
421
+ export function GetOrderByFromCaml(camlQuery: string): { Name: string; IsAscending: boolean; }[] {
422
+ let xmlDoc = new DOMParser().parseFromString(camlQuery, "text/xml");
423
+
424
+ let orderByElm = xmlDoc.querySelector("OrderBy");
425
+ let OrderBy: { Name: string; IsAscending: boolean; }[] = [];
426
+ if (orderByElm) {
427
+ let orderFieldsElms = orderByElm.querySelectorAll("FieldRef");
428
+ orderFieldsElms.forEach(f => {
429
+ let name = f.getAttribute("Name");
430
+ let asc = f.getAttribute("Ascending") || "";
431
+ //Issue 1019 default value is true if ommitted - https://learn.microsoft.com/en-us/sharepoint/dev/schema/fieldref-element-query
432
+ let IsAscending = asc.toUpperCase() !== "FALSE";
433
+ if (!isNullOrEmptyString(name))
434
+ OrderBy.push({ Name: name, IsAscending: IsAscending });
435
+ });
436
+ }
437
+
438
+ return OrderBy;
439
+ }
440
+
441
+ export function RemoveOrderByFromCaml(camlQuery: string): string {
442
+ let xmlDoc = new DOMParser().parseFromString(camlQuery, "text/xml");
443
+
444
+ let orderByElm = xmlDoc.querySelector("OrderBy");
445
+ //let OrderBy: { Name: string; IsAscending: boolean; }[] = [];
446
+ if (orderByElm) {
447
+ orderByElm.remove();
448
+ return xmlDoc.documentElement.outerHTML;
449
+ }
450
+
451
+ return camlQuery;
452
+ }
453
+
454
+ export function EnsureViewFields(camlQuery: string, fields: string[], forceCreateViewFields: boolean, removeAllOthers?: boolean) {
455
+ let xmlDoc = new DOMParser().parseFromString(camlQuery, "text/xml");
456
+ let viewElm = xmlDoc.querySelector("View");
457
+ if (!isNullOrUndefined(viewElm)) {
458
+ let viewFieldsElm = viewElm.querySelector("ViewFields");
459
+
460
+ if (forceCreateViewFields && isNullOrUndefined(viewFieldsElm)) {
461
+ viewFieldsElm = xmlDoc.createElement("ViewFields");
462
+ viewElm.appendChild(viewFieldsElm);
463
+ }
464
+
465
+ if (!isNullOrUndefined(viewFieldsElm)) {
466
+ let viewFieldsElms = viewFieldsElm.querySelectorAll("FieldRef");
467
+
468
+ if (removeAllOthers)
469
+ viewFieldsElms.forEach(e => e.remove());
470
+
471
+ let viewFields = removeAllOthers ? [] : Array.from(viewFieldsElms).map(viewFieldNode => {
472
+ let name = viewFieldNode.getAttribute("Name");
473
+ return name.toLowerCase();
474
+ });
475
+
476
+ let changed = false;
477
+ fields.forEach(f => {
478
+ if (viewFields.indexOf(f.toLowerCase()) === -1) {
479
+ let newViewFieldElm = xmlDoc.createElement("FieldRef");
480
+ newViewFieldElm.setAttribute("Name", f);
481
+ viewFieldsElm.appendChild(newViewFieldElm);
482
+ changed = true;
483
+ }
484
+ });
485
+
486
+ if (viewFieldsElm.querySelectorAll("FieldRef").length < 1 && !forceCreateViewFields) {
487
+ //don't leave an empty object
488
+ viewFieldsElm.remove();
489
+ changed = true;
490
+ }
491
+
492
+ if (changed) return xmlDoc.documentElement.outerHTML;
493
+ }
494
+ }
495
+
496
+ return camlQuery;
497
+ }
498
+
499
+ /**If it is a thumbnail field - parse and return a typed value */
500
+ export function ParseThumbnalFieldValue(value?: string, context?: {
501
+ itemId: number;
502
+ rootFolder: string;
503
+ }): ThumbnailValueType {
504
+ if (!isNullOrEmptyString(value)) {
505
+ try {
506
+ let parsed = jsonParse<ThumbnailValueType>(value);
507
+
508
+ if (isNullOrUndefined(parsed)) {
509
+ return null;
510
+ }
511
+
512
+ if (!isNullOrEmptyString(parsed.serverRelativeUrl)) {
513
+ return parsed;
514
+ } else if (!isNullOrEmptyString(parsed.fileName)
515
+ && !isNullOrUndefined(context)
516
+ && isNumber(context.itemId)
517
+ && !isNullOrEmptyString(context.rootFolder)) {
518
+ let { itemId, rootFolder } = context;
519
+ parsed.serverRelativeUrl = `${makeServerRelativeUrl(rootFolder)}/Attachments/${itemId}/${parsed.fileName}`
520
+ return parsed;
521
+ }
522
+ } catch (e) {
523
+ }
524
+ }
525
+ return null;
526
+ }
527
+
528
+ export function isTitleField(fieldName: string) {
529
+ return fieldName === "Title" || fieldName === "LinkTitleNoMenu" || fieldName === "LinkTitle";
530
+ }
531
+
532
+ /** we are on a list view page, not a web part page with possible multiple list views */
533
+ export function isSingleViewPage() {
534
+ return !isNullOrUndefined(_spPageContextInfo) && isValidGuid(_spPageContextInfo.viewId);
535
+ }
536
+
537
+ /**
538
+ * Splits the ViewFields of a CAML query into separate entries based on the batch size.
539
+ * @param {string} camlQuery - The CAML query string.
540
+ * @param {number} batchSize - The size of each batch (number of ViewFields per entry).
541
+ */
542
+ export function splitViewFieldsByBatch(camlQuery: string, allListFieldsToLowerHash: IDictionary<IFieldInfoEX>, batchSize: number): string[] {
543
+ let xmlDoc = new DOMParser().parseFromString(camlQuery, 'text/xml');
544
+ let viewNode = xmlDoc.querySelector("View, view");
545
+ let viewFieldsNode = viewNode && viewNode.querySelector("ViewFields, viewfields");
546
+
547
+ if (isNullOrUndefined(viewFieldsNode)) {
548
+ return [camlQuery]; // No ViewFields element found, return the original query as is
549
+ }
550
+
551
+ let viewFieldNodes = Array.from(viewFieldsNode.children);
552
+ let numberOfEntries = Math.ceil(viewFieldNodes.length / batchSize);
553
+
554
+ let splitQueries: string[] = [];
555
+ for (let i = 0; i < numberOfEntries; i++) {
556
+ let startIndex = i * batchSize;
557
+ let endIndex = startIndex + batchSize;
558
+ let slicedViewFields = viewFieldNodes.slice(startIndex, endIndex);
559
+
560
+ let clonedXmlDoc = xmlDoc.cloneNode(true) as XMLDocument;
561
+ let clonedViewFieldsElement = clonedXmlDoc.getElementsByTagName('ViewFields')[0];
562
+
563
+ // Remove existing child nodes from cloned ViewFields
564
+ while (clonedViewFieldsElement.firstChild) {
565
+ clonedViewFieldsElement.removeChild(clonedViewFieldsElement.firstChild);
566
+ }
567
+
568
+ // Append sliced ViewFields to cloned ViewFields
569
+ for (let slicedViewField of slicedViewFields) {
570
+ clonedViewFieldsElement.appendChild(slicedViewField.cloneNode(true));
571
+ }
572
+
573
+ let splitQuery = new XMLSerializer().serializeToString(clonedXmlDoc);
574
+ splitQueries.push(splitQuery);
575
+ }
576
+
577
+ return splitQueries;
578
+ }
579
+
580
+ /** Size=S = 48×48 px, M = 72×72 px, L = 300×300 px */
581
+ export function UserPhoto(siteUrl: string, userName: string, size: "S" | "M" | "L" = "L") {
582
+ return `${normalizeUrl(siteUrl)}/_layouts/15/userphoto.aspx?size=${size}&accountname=${encodeURIComponent(userName)}`;
583
+ }
584
+
585
+ export function IsFolderContentType(contentTypeId: string) {
586
+ //item:0x0100
587
+ //file:0x0101
588
+ //folder:0x0120
589
+ //item in MS Lists:0x00 Issue 7121
590
+ return contentTypeId.startsWith("0x0120");
591
+ }
592
+
593
+ export enum PageContainerTypes {
594
+ M365SPFx, M365OOBListForm,
595
+ SP2019SPFx, SP2019ListForm
596
+ }
597
+ export function GetModernPageContainers() {
598
+ let mainContent: HTMLElement = document.querySelector("section.mainContent");
599
+ if (mainContent)
600
+ return { mainContent, commandBar: document.querySelector(".commandBarWrapper") as HTMLElement, type: PageContainerTypes.M365SPFx };
601
+
602
+ mainContent = document.querySelector("div[class^=canvasWrapper]");//document.querySelector("div.SPCanvas");
603
+ if (mainContent)
604
+ return { mainContent, commandBar: document.querySelector(".commandBarWrapper") as HTMLElement, type: PageContainerTypes.SP2019SPFx };
605
+
606
+ mainContent = document.querySelector(".flex-mainColumn");
607
+ if (mainContent)
608
+ return { mainContent, commandBar: null, type: PageContainerTypes.M365OOBListForm };
609
+
610
+ mainContent = document.querySelector(".Files-mainColumn");
611
+ if (mainContent)
612
+ return { mainContent, commandBar: null, type: PageContainerTypes.SP2019ListForm };
613
+
614
+ return { mainContent: null, commandBar: null, type: PageContainerTypes.SP2019ListForm };
615
+ }
616
+
617
+ export function AddCamlQueryFragmentToViewQuery(viewXml: string, queryFragmentXml: string): string {
618
+
619
+ const combineWithExistingConditions = (doc: XMLDocument, existingConditions: Element[], newConditionXml: string): Element => {
620
+ const parser = new DOMParser();
621
+ const newConditionDoc = parser.parseFromString(newConditionXml, 'text/xml');
622
+ const newCondition = doc.importNode(newConditionDoc.documentElement, true);
623
+
624
+ if (existingConditions.length === 0) {
625
+ return newCondition;
626
+ } else if (existingConditions.length === 1) {
627
+ const andElement = doc.createElement("And");
628
+ andElement.appendChild(existingConditions[0]);
629
+ andElement.appendChild(newCondition);
630
+ return andElement;
631
+ } else {
632
+ const lastCondition = existingConditions.pop();
633
+ const andElement = doc.createElement("And");
634
+ andElement.appendChild(combineWithExistingConditions(doc, existingConditions, ""));
635
+ andElement.appendChild(lastCondition);
636
+ return andElement;
637
+ }
638
+ }
639
+ try {
640
+ const parser = new DOMParser();
641
+ const xmlDoc = parser.parseFromString(viewXml, 'text/xml');
642
+ const whereClause = xmlDoc.querySelector('Where') || xmlDoc.createElement('Where');
643
+ const existingConditions = Array.from(whereClause.children);
644
+
645
+ const combinedCondition = combineWithExistingConditions(xmlDoc, existingConditions, queryFragmentXml);
646
+ whereClause.textContent = ''; // Clear existing conditions
647
+ whereClause.appendChild(combinedCondition);
648
+
649
+ const query = xmlDoc.querySelector('Query') || xmlDoc.createElement('Query');
650
+ query.appendChild(whereClause);
651
+
652
+ const view = xmlDoc.querySelector('View') || xmlDoc.createElement('View');
653
+ view.appendChild(query);
654
+
655
+ const serializer = new XMLSerializer();
656
+ let modifiedCamlXml = serializer.serializeToString(xmlDoc);
657
+
658
+ return modifiedCamlXml;
659
+ } catch (error) {
660
+ return viewXml;
661
+ }
662
+ }
663
+
664
+ export function IsUserEntityValueType(value: any): value is UserEntityValueType {
665
+ if (isNullOrUndefined(value) || isString(value)) {
666
+ return false;
667
+ }
668
+ var asUserEntityValueType = value as UserEntityValueType;
669
+ var isEntityValueType =
670
+ asUserEntityValueType.principalType === PrincipalType.SharePointGroup
671
+ || asUserEntityValueType.principalType === PrincipalType.User
672
+ || asUserEntityValueType.principalType === PrincipalType.SecurityGroup;
673
+
674
+ return isEntityValueType;
675
+ }
676
+
677
+ export function IsMultiUserEntityValueType(value: any[]): value is UserEntityValueType[] {
678
+ if (isNullOrUndefined(value) || isString(value) || !Array.isArray(value)) {
679
+ return false;
680
+ }
681
+
682
+ return value.every((v) => {
683
+ return IsUserEntityValueType(v);
684
+ });
685
+ }
686
+
687
+ export function IsUrlValueType(value: any): value is UrlValueType {
688
+ if (isNullOrUndefined(value) || isString(value)) {
689
+ return false;
690
+ }
691
+ let asType = value as UrlValueType;
692
+ return !isNullOrUndefined(asType.Url) && !isNullOrUndefined(asType.Description);
693
+ }
694
+
695
+ export function IsRetentionLabelValueType(value: any): value is RententionLabelFieldValueType {
696
+ if (isNullOrUndefined(value) || isString(value)) {
697
+ return false;
698
+ }
699
+ let asType = value as RententionLabelFieldValueType;
700
+ return isValidGuid(asType.TagId) && !isNullOrEmptyString(asType.TagName);
701
+ }
702
+
703
+ export function isHostedInTeams() {
704
+ return window.location.pathname.toLowerCase().indexOf("teamshostedapp.aspx") >= 0;
705
+ }
706
+ export function isClassicAppIframe() {
707
+ return window.location.search.toLowerCase().indexOf("sphosturl=") >= 0 &&
708
+ window.location.search.toLowerCase().indexOf("spappweburl=") >= 0;
709
+ }
710
+
711
+ export function isNumberFieldType(fieldInfo: IFieldInfoEX) {
712
+ let targetColumnOutputType = getFieldOutputType(fieldInfo);
713
+ return targetColumnOutputType === "Currency"
714
+ || targetColumnOutputType === "Number"
715
+ || targetColumnOutputType === "Counter"
716
+ || targetColumnOutputType === "Integer";
717
+ }
718
+
719
+ export async function isSharePointOnline() {
720
+ let url = new URL(window.location.href);
721
+ //Most cases are satisfied by this check. Very few customers have custom domains for SharePoint online.
722
+ if (url.host.toLowerCase().endsWith(".sharepoint.com")) {
723
+ return true;
724
+ }
725
+
726
+ let contextReady = await waitFor(() => {
727
+ return !isTypeofFullNameUndefined("_spPageContextInfo");
728
+ });
729
+
730
+ if (contextReady) {
731
+ return _spPageContextInfo.isSPO === true;
732
+ }
733
+
734
+ return false;
735
+ }
736
+
737
+ export function isSharePointOnlineSync() {
738
+ let url = new URL(window.location.href);
739
+ //Most cases are satisfied by this check. Very few customers have custom domains for SharePoint online.
740
+ if (url.host.toLowerCase().endsWith(".sharepoint.com")) {
741
+ return true;
742
+ }
743
+
744
+ if (!isTypeofFullNameUndefined("_spPageContextInfo")) {
745
+ return _spPageContextInfo.isSPO === true;
746
+ }
747
+
748
+ return false;
749
+ }
750
+
751
+ export async function isAppWeb() {
752
+ let contextReady = await waitFor(() => {
753
+ return !isTypeofFullNameUndefined("_spPageContextInfo");
754
+ });
755
+
756
+ if (contextReady) {
757
+ return _spPageContextInfo.isAppWeb === true;
758
+ }
759
+
760
+ return false;
761
+ }
762
+
763
+ export function isAppWebSync() {
764
+ if (!isTypeofFullNameUndefined("_spPageContextInfo")) {
765
+ return _spPageContextInfo.isAppWeb === true;
766
+ }
767
+
768
+ return false;
769
+ }
770
+
771
+ export async function isSPPageContextInfoReady() {
772
+ return await waitForWindowObject("_spPageContextInfo");
773
+ }
774
+
775
+ export function isSPPageContextInfoReadySync() {
776
+ return !isTypeofFullNameNullOrUndefined("_spPageContextInfo");
773
777
  }