@kwiz/common 1.0.110 → 1.0.112

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.
@@ -1401,57 +1401,83 @@ export function getCSSVariableValue(value: string, elm: HTMLElement = document.b
1401
1401
  }
1402
1402
 
1403
1403
  /**
1404
- * Converts an HTMLImageElement to base 64 and resizes the image to the exact dimensions of the HTMLImageElement
1404
+ * Converts an HTMLImageElement/SVGImageElement to base 64 and resizes the image to the exact dimensions of the element.
1405
+ * The following image types are supported: jpg, jpeg, gif, png, webp, bmp
1405
1406
  */
1406
- export function convertImageToBase64(imgEle: HTMLImageElement, quality: ImageSmoothingQuality = "medium") {
1407
+ export async function convertImageToBase64(imgEle: HTMLImageElement | SVGImageElement, quality: ImageSmoothingQuality = "medium"): Promise<string> {
1407
1408
  if (!isElement(imgEle)
1408
1409
  || (isNullOrEmptyString(imgEle.src) && isNullOrEmptyString(imgEle.getAttribute("xlink:href")))) {
1409
- return;
1410
+ return null;
1410
1411
  }
1411
1412
 
1412
- let xlinkHref = imgEle.getAttribute("xlink:href");
1413
- let useXlinkHref = !isNullOrEmptyString(xlinkHref);
1414
- let src = useXlinkHref ? xlinkHref : imgEle.src;
1413
+ return new Promise((resolve) => {
1414
+ let xlinkHref = imgEle.getAttribute("xlink:href");
1415
+ let useXlinkHref = !isNullOrEmptyString(xlinkHref);
1416
+ let src = useXlinkHref ? xlinkHref : imgEle.src;
1417
+
1418
+ let type = "image/png"
1419
+ if (!isDataUrl(src)) {
1420
+ let ext = getURLExtension(src);
1421
+ if (!isNullOrEmptyString(ext)) {
1422
+ ext = ext.toLowerCase();
1423
+ if (ext !== "png") {
1424
+ type = "image/jpeg";
1425
+ }
1426
+ }
1427
+ }
1428
+
1429
+ let height = 0;
1430
+ let width = 0;
1415
1431
 
1416
- let isCrossOrigin = !src.toLowerCase().startsWith(window.location.origin.toLowerCase());
1417
- let crossOriginImg: HTMLImageElement = null;
1432
+ if (imgEle instanceof SVGImageElement || useXlinkHref || imgEle.tagName === "image") {
1433
+ width = parseInt(imgEle.getAttribute("width"));
1434
+ height = parseInt(imgEle.getAttribute("height"));
1435
+ } else {
1436
+ width = imgEle.width;
1437
+ height = imgEle.height;
1438
+ }
1418
1439
 
1419
- if (isCrossOrigin === true) {
1420
- crossOriginImg = new Image();
1421
- crossOriginImg.crossOrigin = "use-credentials";
1422
- crossOriginImg.src = src;
1423
- }
1440
+ let canvas = document.createElement("canvas");
1441
+ canvas.height = height;
1442
+ canvas.width = width;
1424
1443
 
1425
- let canvas = document.createElement("canvas");
1426
- canvas.width = imgEle.width;
1427
- canvas.height = imgEle.height;
1444
+ let ctx = canvas.getContext("2d");
1445
+ ctx.imageSmoothingEnabled = true;
1446
+ ctx.imageSmoothingQuality = quality;
1428
1447
 
1429
- let ctx = canvas.getContext("2d");
1430
- ctx.imageSmoothingEnabled = true;
1431
- ctx.imageSmoothingQuality = quality;
1432
- ctx.drawImage(crossOriginImg || imgEle, 0, 0, imgEle.width, imgEle.height);
1448
+ let isCrossOrigin = !src.toLowerCase().startsWith(window.location.origin.toLowerCase());
1449
+ let crossOriginImg = new Image();
1433
1450
 
1434
- let type = "image/png"
1435
- if (!isDataUrl(src)) {
1436
- let ext = getURLExtension(src);
1437
- if (!isNullOrEmptyString(ext)) {
1438
- ext = ext.toLowerCase();
1439
- if (ext !== "png") {
1440
- type = "image/jpeg";
1451
+ crossOriginImg.onload = () => {
1452
+ let dataURL: string = null;
1453
+ try {
1454
+ ctx.drawImage(crossOriginImg, 0, 0, width, height);
1455
+ dataURL = canvas.toDataURL(type, quality === "high" ? 1 : quality === "medium" ? 0.75 : 0.5);
1456
+ } catch {
1457
+ dataURL = null;
1441
1458
  }
1442
- }
1443
- }
1444
1459
 
1445
- let dataURL: string = null;
1446
- try {
1447
- dataURL = canvas.toDataURL(type, quality === "high" ? 1 : quality === "medium" ? 0.75 : 0.5);
1448
- } catch {
1449
- dataURL = null;
1450
- }
1460
+ canvas = null;
1461
+ ctx = null;
1462
+ crossOriginImg = null;
1463
+
1464
+ resolve(dataURL);
1465
+ };
1451
1466
 
1452
- canvas = null;
1453
- ctx = null;
1454
- crossOriginImg = null;
1455
-
1456
- return dataURL;
1467
+ crossOriginImg.onerror = () => {
1468
+ canvas = null;
1469
+ ctx = null;
1470
+ crossOriginImg = null;
1471
+
1472
+ resolve(null);
1473
+ };
1474
+
1475
+ if (isCrossOrigin === true) {
1476
+ crossOriginImg.crossOrigin = "anonymous";
1477
+ } else {
1478
+ crossOriginImg.crossOrigin = "use-credentials";
1479
+ }
1480
+
1481
+ crossOriginImg.src = src;
1482
+ });
1457
1483
  }
@@ -79,6 +79,11 @@ export function DecodeFieldValuesAsTextKey(key: string): string {
79
79
  return key.replace(/_x005f_/g, "_").replace('OData__', '_');
80
80
  }
81
81
 
82
+ /** Replaces _ with _x005f_, except OData_ at the start */
83
+ export function EncodeFieldValuesAsTextKey(key: string): string {
84
+ return key.replace('OData_', '~').replace(/_/g, "_x005f_").replace('~', 'OData_');
85
+ }
86
+
82
87
  /** Gets REST FieldValuesAsText or FieldValuesForEdit and fix their column names so that you can get a field value by its internal name */
83
88
  export function DecodeFieldValuesAsText(FieldValuesAsText: IDictionary<string>) {
84
89
  return DecodeFieldValuesForEdit(FieldValuesAsText);
@@ -1,5 +1,5 @@
1
1
  import { jsonStringify } from "../../helpers/json";
2
- import { isNotEmptyArray, isNullOrEmptyString, isNullOrUndefined, isNumber, isNumeric, newGuid } from "../../helpers/typecheckers";
2
+ import { isNotEmptyArray, isNotEmptyString, isNullOrEmptyString, isNullOrUndefined, isNumber, isNumeric, isString, newGuid } from "../../helpers/typecheckers";
3
3
  import { encodeURIComponentEX, makeServerRelativeUrl, normalizeUrl } from "../../helpers/url";
4
4
  import { IDictionary } from "../../types/common.types";
5
5
  import { IRequestBody, IRestOptions, IRestResponseType, jsonTypes } from "../../types/rest.types";
@@ -176,7 +176,8 @@ async function _moderateFile(siteUrl: string, fileUrl: string, action: "publish"
176
176
  siteUrl = GetSiteUrl(siteUrl);
177
177
  let fileServerRelativeUrl = makeServerRelativeUrl(fileUrl, siteUrl);
178
178
  try {
179
- let publishUrl = `${GetRestBaseUrl(siteUrl)}/Web/getFileByServerRelativeUrl('${fileServerRelativeUrl}')/${action}('${comment}')`;
179
+ let hasComments = !isNullOrEmptyString(comment);
180
+ let publishUrl = `${GetRestBaseUrl(siteUrl)}/Web/getFileByServerRelativeUrl('${fileServerRelativeUrl}')/${action}${hasComments ? `(@a1)?@a1=%27${encodeURIComponentEX(comment, { singleQuoteMultiplier: 2 })}%27` : '()'}`;
180
181
  let publishResult = await GetJson<{ "odata.null": boolean }>(publishUrl, null, {
181
182
  method: "POST",
182
183
  jsonMetadata: jsonTypes.nometadata,
@@ -185,7 +186,7 @@ async function _moderateFile(siteUrl: string, fileUrl: string, action: "publish"
185
186
  return !isNullOrUndefined(publishResult) && publishResult["odata.null"] === true;
186
187
  } catch {
187
188
  }
188
- return null;
189
+ return false;
189
190
  }
190
191
 
191
192
  export function RecycleFile(siteUrl: string, fileServerRelativeUrl: string): Promise<boolean> {
@@ -257,29 +258,66 @@ export function GetFileSync<T>(siteUrl: string, fileServerRelativeUrl: string, r
257
258
  };
258
259
  }
259
260
 
261
+ /** @deprecated use GetFileEx */
260
262
  export function GetFile<T>(siteUrl: string, fileServerRelativeUrl: string, allowCache?: boolean, responseType?: IRestResponseType): Promise<{ Exists: boolean; Content?: T; }> {
263
+ return GetFileEx(siteUrl, fileServerRelativeUrl, { allowCache, responseType });
264
+ }
265
+
266
+ export async function GetFileEx<T>(siteUrl: string, fileServerRelativeUrl: string, options?: {
267
+ allowCache?: boolean; responseType?: IRestResponseType;
268
+ /** version #.# or version ID as number */
269
+ version?: string | number;
270
+ }): Promise<{ Exists: boolean; Content?: T; }> {
261
271
  siteUrl = GetSiteUrl(siteUrl);
262
272
 
263
- let options: IRestOptions = { ...(allowCache === true ? shortLocalCache : noLocalCache), forceCacheUpdate: allowCache !== true };
264
- if (!isNullOrUndefined(responseType)) {
265
- options.responseType = responseType;
273
+ let restOptions: IRestOptions = { ...(options?.allowCache === true ? shortLocalCache : noLocalCache), forceCacheUpdate: options?.allowCache !== true };
274
+ if (!isNullOrUndefined(options?.responseType)) {
275
+ restOptions.responseType = options?.responseType;
266
276
  }
267
277
 
268
- let fileRestUrl = GetFileRestUrl(siteUrl, fileServerRelativeUrl);
269
- if (!options.forceCacheUpdate && reloadCacheFileModifiedRecently(siteUrl, fileServerRelativeUrl)) {
270
- options.forceCacheUpdate = true;
278
+ let version = options?.version;
279
+ if (isNumber(version) && version > 0 || isNotEmptyString(version)) {
280
+ //get content of specific version
281
+ let fileSiteRelativeUrl = fileServerRelativeUrl.slice(siteUrl.length - 1);
282
+ let versionUrl = `${siteUrl}/_vti_history/${FileVersionToVersionId(options.version)}${fileSiteRelativeUrl}`;
283
+ try {
284
+ let versionContent = await GetJson<T>(versionUrl, undefined, restOptions);
285
+ return { Exists: isString(versionContent), Content: versionContent };
286
+ } catch (e) {
287
+ return { Exists: false };
288
+ }
271
289
  }
290
+ else {
291
+ let fileRestUrl = GetFileRestUrl(siteUrl, fileServerRelativeUrl);
292
+ if (!restOptions.forceCacheUpdate && reloadCacheFileModifiedRecently(siteUrl, fileServerRelativeUrl)) {
293
+ restOptions.forceCacheUpdate = true;
294
+ }
272
295
 
273
- return GetJson<T>(`${fileRestUrl}/$value`, null, options).then(r => {
274
- return {
275
- Exists: true,
276
- Content: r
277
- };
278
- }).catch<{ Exists: boolean; Content?: T; }>(() => {
279
- return {
280
- Exists: false
281
- };
282
- });
296
+ return GetJson<T>(`${fileRestUrl}/$value`, null, restOptions).then(r => {
297
+ return {
298
+ Exists: true,
299
+ Content: r
300
+ };
301
+ }).catch<{ Exists: boolean; Content?: T; }>(() => {
302
+ return {
303
+ Exists: false
304
+ };
305
+ });
306
+ }
307
+ }
308
+
309
+ /** version: 1.5 >> version ID for history */
310
+ export function FileVersionToVersionId(version: string | number) {
311
+ try {
312
+ if (isNumber(version)) return version;
313
+ const vSplit = version.split('.');
314
+ const major = parseInt(vSplit[0], 10);
315
+ const minor = parseInt(vSplit[1], 10);
316
+ let versionId = (major * 512) + minor;
317
+ return versionId;
318
+ }
319
+ catch (e) { }
320
+ return null;
283
321
  }
284
322
 
285
323
  var $reloadCacheFileModifiedRecentlyFlagged: string[] = [];
@@ -596,4 +634,4 @@ async function CopyOrMoveFile(siteUrl: string, currentServerRelativeUrl: string,
596
634
  // return UpdateItem(siteUrl, listIdOrTitle, itemId, {
597
635
  // FileLeafRef: newFileName "hello.txt" >> "hello.md" won't work.
598
636
  // });
599
- }
637
+ }