@olenbetong/appframe-core 2.0.3 → 2.1.0

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 (42) hide show
  1. package/dist/esm/af.common.js +115 -293
  2. package/dist/esm/af.common.legacy.js +119 -290
  3. package/dist/esm/af.common.legacy.min.js +1 -47
  4. package/dist/esm/af.common.legacy.min.js.map +4 -4
  5. package/dist/esm/af.common.min.js +1 -47
  6. package/dist/esm/af.common.min.js.map +4 -4
  7. package/dist/iife/af.common.js +118 -294
  8. package/dist/iife/af.common.legacy.js +122 -293
  9. package/dist/iife/af.common.legacy.min.js +1 -47
  10. package/dist/iife/af.common.legacy.min.js.map +4 -4
  11. package/dist/iife/af.common.min.js +1 -47
  12. package/dist/iife/af.common.min.js.map +4 -4
  13. package/es/SessionHandler.d.ts +2 -7
  14. package/es/SessionHandler.js +34 -135
  15. package/es/UserSession.d.ts +1 -2
  16. package/es/UserSession.js +1 -2
  17. package/es/downloadRequest.js +1 -4
  18. package/es/expose.d.ts +1 -1
  19. package/es/expose.js +4 -5
  20. package/es/getLocalizedString.d.ts +6 -7
  21. package/es/getLocalizedString.js +9 -82
  22. package/es/index.d.ts +3 -2
  23. package/es/index.js +4 -3
  24. package/es/localize.d.ts +14 -0
  25. package/es/localize.js +25 -0
  26. package/es/parseFunc.d.ts +1 -1
  27. package/es/parseFunc.js +1 -1
  28. package/es/requireNamespace.d.ts +1 -1
  29. package/es/requireNamespace.js +1 -7
  30. package/package.json +2 -2
  31. package/src/SessionHandler.ts +38 -156
  32. package/src/UserSession.ts +1 -2
  33. package/src/downloadRequest.ts +1 -4
  34. package/src/expose.ts +4 -5
  35. package/src/getLocalizedString.ts +22 -110
  36. package/src/index.ts +3 -2
  37. package/src/localize.ts +29 -0
  38. package/src/parseFunc.ts +1 -1
  39. package/src/requireNamespace.ts +1 -5
  40. package/es/warn.d.ts +0 -1
  41. package/es/warn.js +0 -4
  42. package/src/warn.ts +0 -4
@@ -1,10 +1,3 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
3
- var __publicField = (obj, key2, value) => {
4
- __defNormalProp(obj, typeof key2 !== "symbol" ? key2 + "" : key2, value);
5
- return value;
6
- };
7
-
8
1
  // src/errorHandler.ts
9
2
  window.addEventListener("error", (event) => {
10
3
  try {
@@ -46,259 +39,42 @@ function mitt_default(n) {
46
39
  } };
47
40
  }
48
41
 
49
- // src/has.ts
50
- function has(obj, key2) {
51
- return Object.prototype.hasOwnProperty.call(obj, key2);
52
- }
53
-
54
- // src/getLocalizedString.ts
55
- async function getLocalizedStringAsync(text) {
56
- try {
57
- let response = await fetch(`/api/user/localize/new/${af.article.id}`, {
58
- body: JSON.stringify({ text }),
59
- headers: {
60
- Accept: "application/json; */*",
61
- "Content-Type": "application/json",
62
- "X-Requested-With": "XMLHttpRequest"
63
- },
64
- method: "POST"
65
- });
66
- if (response.ok) {
67
- return await response.json();
68
- }
69
- } catch (error) {
70
- }
71
- return text;
72
- }
73
- function afGetLocalizedString(string, wait) {
74
- if (typeof string === "string" && string.trim().length === 0) {
75
- return string;
76
- }
77
- if (string === void 0 || string === "" || string === null) {
78
- return;
79
- }
80
- if (af?.article?.i18n !== void 0) {
81
- if (!has(af.article.i18n, string)) {
82
- af.article.i18n[string] = string;
83
- let promise = getLocalizedStringAsync(string).then((text) => {
84
- af.article.i18n[string] = text;
85
- return text;
86
- });
87
- if (wait) {
88
- return promise;
89
- }
90
- }
91
- return af.article.i18n[string];
92
- } else {
93
- return string;
94
- }
95
- }
96
- var key = "__UNLOCALIZED_STRINGS__";
97
- var localizeSet = window[key] || /* @__PURE__ */ new Set();
98
- if (!window[key]) {
99
- window[key] = localizeSet;
100
- }
101
- function handleReadyStateChange() {
102
- if (document.readyState !== "loading") {
103
- addDeveloperUtils();
104
- document.removeEventListener("readystatechange", handleReadyStateChange);
105
- }
106
- }
107
- if (document.readyState !== "loading") {
108
- addDeveloperUtils();
109
- } else {
110
- document.addEventListener("readystatechange", handleReadyStateChange);
111
- }
112
- function isDeveloper() {
113
- const { af: af2 } = window;
114
- return af2 && af2.userSession && af2.userSession.isDeveloper;
115
- }
116
- function addDeveloperUtils() {
117
- if (isDeveloper()) {
118
- if (typeof window.__doNothingWithStrings === "function") {
119
- const addedStrings = window.__doNothingWithStrings();
120
- for (let string of Object.keys(addedStrings)) {
121
- localizeSet.add(string);
122
- }
123
- }
124
- if (!window[key]) {
125
- window[key] = localizeSet;
126
- }
127
- if (!window.__getUnlocalizedStrings) {
128
- window.__getUnlocalizedStrings = function(forCustomRoute) {
129
- const strings = [];
130
- for (let string of localizeSet) {
131
- if (string) {
132
- const escaped = string.replace(/'/g, "\\'");
133
- if (forCustomRoute) {
134
- const localized = afGetLocalizedString(string).replaceAll(/'/g, "\\'");
135
- strings.push(`'${escaped}': '${localized}',`);
136
- } else {
137
- strings.push(
138
- `s['${escaped}'] = @Html(@context.AddLocalizableString("${string.replaceAll('"', '\\"')}"));`
139
- );
140
- }
141
- }
142
- }
143
- if (forCustomRoute) {
144
- return `// Localization hack, since it AddLocalizableString doesn't work properly when custom routes is used
145
- if (af.userSession.uiculture === 'nb-NO') {
146
- const strings = {
147
- ${strings.join("\n ")}
148
- };
149
- af.article.i18n = af.article.i18n || {};
150
- Object.assign(af.article.i18n, strings);
151
- }`;
152
- }
153
- return `<script type="text/javascript">
154
- function __doNothingWithStrings() {
155
- @{
156
- var context = @Appframe.Web.Context.RequestContext.Current;
157
- }
158
- let s = {};
159
- ${strings.join("\n")}
160
- return s;
161
- }
162
- <\/script>`;
163
- };
164
- }
165
- }
166
- }
167
- function getLocalizedString(string) {
168
- const localized = afGetLocalizedString(string);
169
- if (localized === string && !localizeSet.has(string)) {
170
- localizeSet.add(string);
171
- }
172
- return localized;
173
- }
174
-
175
42
  // src/SessionHandler.ts
176
- var _SessionHandler = class {
43
+ var SessionHandler = class {
177
44
  eventHandler = mitt_default();
178
- showingDialog = false;
179
- dialog = null;
180
- expired(callback) {
181
- af.userSession = af.userSession || {
182
- login: null
183
- };
184
- if (typeof callback !== "function") {
185
- throw new TypeError("Parameter pCallback passed to the expired function must be a function!");
186
- }
187
- const once = () => {
188
- this.detachEvent("onAuthenticated", once);
189
- callback();
190
- };
191
- this.attachEvent("onAuthenticated", once);
192
- if (this.showingDialog !== true) {
193
- this.showingDialog = true;
194
- const contentContainer = document.createElement("div");
195
- contentContainer.className = "session-expired-container";
196
- contentContainer.innerHTML = `
197
- <div class="session-expired-log-in" style="margin-top: 20px;">
198
- <div class="row">
199
- <div class="sessionExpired">
200
- <h4 class="message">Frakoblet - tidsavbrudd</h4>
201
- <div class="form-group">
202
- <label for="username">${getLocalizedString("Username")}</label>
203
- <input type="text" class="form-control" id="username" autofocus>
204
- </div>
205
- <div class="form-group">
206
- <label for="password">${getLocalizedString("Password")}</label>
207
- <input type="password" autocomplete="password" class="form-control" id="password" >
208
- </div>
209
- <div class="form-group">
210
- <div>
211
- <button type="submit" class="btn btn-default sign-in">
212
- ${getLocalizedString("Log in")}
213
- </button>
214
- </div>
215
- </div>
216
- </div>
217
- </div>
218
- <div class="row">
219
- <div class="" style="display:none; margin: 0px 30px;">
220
- <div class="alert alert-warning" role="alert" style="margin-top:10px;"></div>
221
- </div>
222
- </div>
223
- </div>
224
- `;
225
- const message = af.userSession.login ? _SessionHandler.messages.relog : _SessionHandler.messages.login;
226
- const messageElem = contentContainer.querySelector(".message");
227
- const statusElem = contentContainer.querySelector(".alert-warning");
228
- const userElem = contentContainer.querySelector("input[type=text]");
229
- const signInElem = contentContainer.querySelector(".sign-in");
230
- const passwordElem = contentContainer.querySelector("input[type=password]");
231
- if (messageElem !== null && userElem !== null && statusElem !== null && userElem !== null && signInElem !== null && passwordElem !== null) {
232
- messageElem.innerText = getLocalizedString(message);
233
- userElem.value = af.userSession.login || "";
234
- userElem.disabled = !!af.userSession.login;
235
- userElem.readOnly = !!af.userSession.login;
236
- document.body.appendChild(contentContainer);
237
- const doLogin = async () => {
238
- passwordElem.disabled = true;
239
- const request = new Request("/login", {
240
- body: JSON.stringify({
241
- username: userElem.value,
242
- password: passwordElem.value,
243
- remember: false
244
- }),
245
- headers: {
246
- Accept: "application/json",
247
- "Content-Type": "application/json; charset=utf-8",
248
- "X-Requested-With": "XMLHttpRequest"
249
- },
250
- method: "POST"
251
- });
252
- try {
253
- const response = await fetch(request);
254
- const json = await response.json();
255
- if (json.success) {
256
- document.body.removeChild(contentContainer);
257
- this.showingDialog = false;
258
- this.eventHandler.emit("onAuthenticated");
259
- if (statusElem.parentNode) {
260
- statusElem.parentNode.style.display = "none";
261
- }
262
- } else {
263
- throw new Error(json.error);
264
- }
265
- } catch (err) {
266
- if (err && typeof err === "object") {
267
- let error = err;
268
- passwordElem.disabled = false;
269
- passwordElem.classList.toggle("invalid", true);
270
- passwordElem.value = "";
271
- passwordElem.focus();
272
- statusElem.innerText = error.message ? error.message : String(error);
273
- if (statusElem.parentNode) {
274
- statusElem.parentNode.style.display = "initial";
275
- }
276
- }
277
- }
278
- };
279
- signInElem.addEventListener("click", doLogin);
280
- passwordElem.addEventListener("keyup", (evt) => {
281
- if (evt.key === "Enter") {
282
- doLogin();
283
- }
284
- });
285
- passwordElem.addEventListener("change", (evt) => {
286
- if (evt.key === "Enter") {
287
- doLogin();
288
- }
289
- });
290
- userElem.addEventListener("keyup", (evt) => {
291
- if (evt.key === "Enter") {
292
- doLogin();
293
- }
294
- });
295
- userElem.addEventListener("change", (evt) => {
296
- if (evt.key === "Enter") {
297
- doLogin();
298
- }
299
- });
300
- passwordElem.focus();
45
+ authenticated() {
46
+ this.eventHandler.emit("onAuthenticated");
47
+ }
48
+ async expired(callback, type) {
49
+ let authPromise = new Promise((resolve) => {
50
+ let eventHandler = () => {
51
+ this.eventHandler.off("onAuthenticated", eventHandler);
52
+ callback?.();
53
+ resolve();
54
+ };
55
+ this.eventHandler.on("onAuthenticated", eventHandler);
56
+ });
57
+ let dialog = document.querySelector("dialog.session-expired-dialog");
58
+ if (!dialog) {
59
+ dialog = document.createElement("dialog");
60
+ dialog.className = "session-expired-dialog";
61
+ dialog.style.display = "flex";
62
+ dialog.style.padding = "0";
63
+ dialog.style.left = "50%";
64
+ dialog.style.transform = "translateX(-50%)";
65
+ let link = "/login?ReturnUrl=%2fapi/sessionexpired/remove";
66
+ if (type !== "RequireTwoFactor") {
67
+ await fetch("/logout", { method: "POST" });
68
+ } else {
69
+ link = "/login?RequireTwoFactor=1&ReturnUrl=%2fapi/sessionexpired/remove";
301
70
  }
71
+ dialog.innerHTML = `<iframe sandbox="allow-same-origin allow-scripts allow-modals allow-top-navigation-by-user-activation allow-forms" src="${link}" style="border:0;width:min(500px,100vw);height:min(700px, 100vh);"></iframe>`;
72
+ document.body.append(dialog);
73
+ dialog.showModal();
74
+ await authPromise;
75
+ dialog.remove();
76
+ } else {
77
+ await authPromise;
302
78
  }
303
79
  }
304
80
  attachEvent(eventName, handler) {
@@ -308,11 +84,6 @@ var _SessionHandler = class {
308
84
  return this.eventHandler.off(eventName, handler);
309
85
  }
310
86
  };
311
- var SessionHandler = _SessionHandler;
312
- __publicField(SessionHandler, "messages", {
313
- login: "Log in",
314
- relog: "Session expired - log in"
315
- });
316
87
 
317
88
  // src/UserSession.ts
318
89
  var UserSession = class extends SessionHandler {
@@ -335,7 +106,6 @@ var UserSession = class extends SessionHandler {
335
106
  shortDateFormat = "dd.MM.yyyy";
336
107
  culture = "en-GB";
337
108
  uiculture = "en-GB";
338
- expired = () => null;
339
109
  constructor(userData) {
340
110
  super();
341
111
  this.formats = {};
@@ -406,7 +176,6 @@ async function downloadRequest(request, { fileName, signal, onProgress }) {
406
176
  });
407
177
  response = new Response(stream);
408
178
  } catch (error) {
409
- console.warn("Failed to replace response stream to log download progress.");
410
179
  }
411
180
  const blob = await response.blob();
412
181
  reportProgress({ bytesReceived, status: "downloaded" });
@@ -421,6 +190,11 @@ async function downloadRequest(request, { fileName, signal, onProgress }) {
421
190
  }
422
191
  }
423
192
 
193
+ // src/has.ts
194
+ function has(obj, key) {
195
+ return Object.prototype.hasOwnProperty.call(obj, key);
196
+ }
197
+
424
198
  // src/parseFunc.ts
425
199
  var funcRegex = /^function(?:\s+([a-zA-Z$_][a-zA-Z0-9$_]*))?\s*\(((?:(?:\s*[a-zA-Z$_][a-zA-Z0-9$_]*)(?:\s*,\s*[a-zA-Z$_][a-zA-Z0-9$_]*)*)?)\s*\)\s*\{((?:.|\n|\r)*)\}$/;
426
200
  function parseFunc(func) {
@@ -449,19 +223,10 @@ function requireNamespace(root, namespace) {
449
223
  current = current[namespace[i]] = current[namespace[i]] || new Namespace_default();
450
224
  }
451
225
  return current;
452
- } else {
453
- throw new TypeError("Invalid type of parameter 'namespace'");
454
226
  }
455
- } else {
456
- throw new TypeError("Invalid type of parameter 'root'");
457
227
  }
458
228
  }
459
229
 
460
- // src/warn.ts
461
- function warn(message, fallbackToAlert) {
462
- console.warn(message);
463
- }
464
-
465
230
  // src/expose.ts
466
231
  function expose(name, value) {
467
232
  if (arguments.length !== 2) {
@@ -497,37 +262,93 @@ function expose(name, value) {
497
262
  throw new TypeError("Invalid typeof parameter 'name', or unable to parse pValue!");
498
263
  }
499
264
  if (has(namespace, keyName)) {
500
- warn([name, keyName].join(".") + " is already defined!");
265
+ console.warn([name, keyName].join(".") + " is already defined!");
501
266
  } else {
502
267
  namespace[keyName] = value;
503
268
  }
504
269
  }
505
270
  }
506
271
 
272
+ // src/getLocalizedString.ts
273
+ async function fetchLocalizedString(text) {
274
+ try {
275
+ let response = await fetch(`/api/user/localize/new/${af.article.id}`, {
276
+ body: JSON.stringify({ text }),
277
+ headers: {
278
+ Accept: "application/json; */*",
279
+ "Content-Type": "application/json",
280
+ "X-Requested-With": "XMLHttpRequest"
281
+ },
282
+ method: "POST"
283
+ });
284
+ if (response.ok) {
285
+ return await response.json();
286
+ }
287
+ } catch (error) {
288
+ }
289
+ return text;
290
+ }
291
+ function getLocalizedString(string, wait) {
292
+ if (typeof string === "string" && string.trim().length === 0) {
293
+ return string;
294
+ }
295
+ if (string === void 0 || string === "" || string === null) {
296
+ return;
297
+ }
298
+ if (af?.article?.i18n !== void 0) {
299
+ if (!has(af.article.i18n, string)) {
300
+ af.article.i18n[string] = string;
301
+ let promise = fetchLocalizedString(string).then((text) => {
302
+ af.article.i18n[string] = text;
303
+ return text;
304
+ });
305
+ if (wait) {
306
+ return promise;
307
+ }
308
+ }
309
+ return af.article.i18n[string];
310
+ } else {
311
+ return string;
312
+ }
313
+ }
314
+
315
+ // src/localize.ts
316
+ function localize(stringParts, ...args) {
317
+ if (!Array.isArray(stringParts) || stringParts?.length || stringParts.length !== args.length + 1) {
318
+ throw TypeError("Method 'localize' must be used as a tag function");
319
+ }
320
+ let stringToLocalize = stringParts.map((s, i) => i === stringParts.length - 1 ? s : `${s}$${i}`).join("");
321
+ let localized = getLocalizedString(stringToLocalize);
322
+ args.forEach((arg, index) => {
323
+ localized = localized.replace("$" + index, arg);
324
+ });
325
+ return localized;
326
+ }
327
+
507
328
  // src/localStorage.ts
508
- function getLocalKey(key2) {
509
- return [af?.article?.id || "", "common", key2].join(".");
329
+ function getLocalKey(key) {
330
+ return [af?.article?.id || "", "common", key].join(".");
510
331
  }
511
332
  var LocalStorage = class {
512
333
  isPersisted() {
513
334
  return true;
514
335
  }
515
- getLocalStorageKey(key2, global) {
516
- return global ? ["common", key2].join(".") : getLocalKey(key2);
336
+ getLocalStorageKey(key, global) {
337
+ return global ? ["common", key].join(".") : getLocalKey(key);
517
338
  }
518
- get(key2, defaultValue, global) {
519
- const lsKey = this.getLocalStorageKey(key2, global);
339
+ get(key, defaultValue, global) {
340
+ const lsKey = this.getLocalStorageKey(key, global);
520
341
  const value = localStorage.getItem(lsKey);
521
342
  return value !== null ? JSON.parse(value) : defaultValue;
522
343
  }
523
- set(key2, value, global) {
344
+ set(key, value, global) {
524
345
  localStorage.setItem(
525
- this.getLocalStorageKey(key2, global),
346
+ this.getLocalStorageKey(key, global),
526
347
  JSON.stringify(value)
527
348
  );
528
349
  }
529
- remove(key2, global) {
530
- const lsKey = this.getLocalStorageKey(key2, global);
350
+ remove(key, global) {
351
+ const lsKey = this.getLocalStorageKey(key, global);
531
352
  if (localStorage.getItem(lsKey) !== null) {
532
353
  localStorage.removeItem(lsKey);
533
354
  return true;
@@ -537,9 +358,9 @@ var LocalStorage = class {
537
358
  }
538
359
  clear() {
539
360
  const baseKey = getLocalKey("");
540
- for (let key2 in localStorage) {
541
- if (key2.slice(0, baseKey.length) === baseKey) {
542
- localStorage.removeItem(key2);
361
+ for (let key in localStorage) {
362
+ if (key.slice(0, baseKey.length) === baseKey) {
363
+ localStorage.removeItem(key);
543
364
  }
544
365
  }
545
366
  }
@@ -554,8 +375,8 @@ function getKey(article) {
554
375
  function getSettings(setting, article) {
555
376
  if (!af?.userSession)
556
377
  return null;
557
- const key2 = getKey(article);
558
- const settings = JSON.parse(localStorage.getItem(key2) || "{}");
378
+ const key = getKey(article);
379
+ const settings = JSON.parse(localStorage.getItem(key) || "{}");
559
380
  if (setting) {
560
381
  return settings[setting] || null;
561
382
  }
@@ -564,18 +385,18 @@ function getSettings(setting, article) {
564
385
  function saveSettings(setting, value, article) {
565
386
  if (!af?.userSession)
566
387
  return;
567
- const key2 = getKey(article);
568
- let userSettings = JSON.parse(localStorage.getItem(key2) || "{}");
388
+ const key = getKey(article);
389
+ let userSettings = JSON.parse(localStorage.getItem(key) || "{}");
569
390
  if (typeof value !== "undefined") {
570
391
  userSettings[setting] = value;
571
392
  } else {
572
393
  userSettings = setting;
573
394
  }
574
- localStorage.setItem(key2, JSON.stringify(userSettings));
395
+ localStorage.setItem(key, JSON.stringify(userSettings));
575
396
  }
576
397
 
577
398
  // src/index.ts
578
- var version = "2.0.3";
399
+ var version = "2.1.0";
579
400
  export {
580
401
  SessionHandler,
581
402
  UserSession,
@@ -586,6 +407,7 @@ export {
586
407
  getSettings,
587
408
  has,
588
409
  localStorage_default as localStorage,
410
+ localize,
589
411
  mitt_default as mitt,
590
412
  saveSettings,
591
413
  version