nexusframework 0.3.0-beta.73 → 0.3.0-beta.74

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 (60) hide show
  1. package/LICENSE.md +55 -55
  2. package/README.md +12 -12
  3. package/about/index.json +5 -5
  4. package/about/index.nhp +4 -4
  5. package/icon.png +0 -0
  6. package/index.d.ts +0 -2
  7. package/index.js +0 -0
  8. package/index.js.map +1 -1
  9. package/index.ts +101 -101
  10. package/indexOfSkeleton.nhp +133 -133
  11. package/legacySkeleton.nhp +22 -22
  12. package/loader/overlay.css +1 -1
  13. package/loader/overlay.html +25 -25
  14. package/loader/overlay.scss +152 -152
  15. package/package.json +102 -90
  16. package/scripts/es5/compat.js +100 -100
  17. package/scripts/es5/compat.min.js +1 -1
  18. package/scripts/es5/loader.js +0 -0
  19. package/scripts/es5/loader.js.map +0 -0
  20. package/scripts/es5/loader.min.js +1 -1
  21. package/scripts/es5/loader.min.js.map +0 -0
  22. package/scripts/es5/nexusframeworkclient.js +1224 -1224
  23. package/scripts/es5/nexusframeworkclient.js.map +0 -0
  24. package/scripts/es5/nexusframeworkclient.min.js +1 -1
  25. package/scripts/es5/nexusframeworkclient.min.js.map +0 -0
  26. package/scripts/es6/compat.js +64 -64
  27. package/scripts/es6/compat.min.js +1 -1
  28. package/scripts/es6/loader.js +0 -0
  29. package/scripts/es6/loader.js.map +0 -0
  30. package/scripts/es6/loader.min.js +1 -1
  31. package/scripts/es6/loader.min.js.map +0 -0
  32. package/scripts/es6/nexusframeworkclient.js +1146 -1146
  33. package/scripts/es6/nexusframeworkclient.js.map +0 -0
  34. package/scripts/es6/nexusframeworkclient.min.js +1 -1
  35. package/scripts/es6/nexusframeworkclient.min.js.map +0 -0
  36. package/scripts/index.d.ts +259 -259
  37. package/scripts/src/compat.ts +62 -62
  38. package/scripts/src/loader.ts +385 -385
  39. package/scripts/src/nexusframeworkclient.ts +1163 -1163
  40. package/scripts/tsconfig.json +11 -11
  41. package/src/cli.d.ts +1 -0
  42. package/src/cli.js +102 -102
  43. package/src/cli.js.map +1 -1
  44. package/src/cli.ts +101 -101
  45. package/src/compileScripts.d.ts +0 -0
  46. package/src/compileScripts.js +0 -0
  47. package/src/compileScripts.js.map +1 -1
  48. package/src/compileScripts.ts +153 -153
  49. package/src/nexusframework.d.ts +5 -5
  50. package/src/nexusframework.js +44 -37
  51. package/src/nexusframework.js.map +1 -1
  52. package/src/nexusframework.ts +3631 -3622
  53. package/templates/basic/package.json +3 -3
  54. package/templates/basic/www/skeleton.nhp +1 -1
  55. package/templates/bootstrap/package.json +2 -2
  56. package/templates/bootstrap/www/skeleton.nhp +1 -1
  57. package/templates/bootstrap-material-design/package.json +2 -2
  58. package/templates/bootstrap-material-design/www/skeleton.nhp +1 -1
  59. package/tsconfig.json +25 -22
  60. package/types.d.ts +612 -612
@@ -1,1147 +1,1147 @@
1
- /// <reference path="../index.d.ts" />
2
- (function (window) {
3
- const BSON = new window['bson'];
4
- Object.defineProperties(window, {
5
- NexusFrameworkTransport: {
6
- configurable: true,
7
- set: function (instance) {
8
- Object.defineProperty(window, "NexusFrameworkTransport", {
9
- value: instance
10
- });
11
- },
12
- get: function () {
13
- var impl;
14
- if ("XMLHttpRequest" in window) {
15
- class NexusFrameworkXMLHttpRequestResponse {
16
- constructor(request, url, hadData, abResponse) {
17
- this._url = url;
18
- this.request = request;
19
- this.hadData = hadData;
20
- this.abResponse = abResponse;
21
- }
22
- get url() {
23
- return this.request.responseURL || this._url;
24
- }
25
- get code() {
26
- return this.request.status;
27
- }
28
- get contentLength() {
29
- return parseInt(this.request.getResponseHeader("content-length")) || this.request.responseText.length;
30
- }
31
- get contentFromJSON() {
32
- if (!this.parsedJson)
33
- this.parsedJson = JSON.parse(this.request.responseText);
34
- return this.parsedJson;
35
- }
36
- get contentFromBSON() {
37
- if (!this.parsedBson) {
38
- var response = this.request.response;
39
- if (typeof response === "string")
40
- response = Buffer.from(response, "utf8");
41
- else
42
- response = new Buffer(response);
43
- this.parsedBson = BSON.deserialize(response, { promoteValues: true });
44
- }
45
- return this.parsedBson;
46
- }
47
- get contentAsString() {
48
- return this.request.responseText;
49
- }
50
- get contentAsArrayBuffer() {
51
- return this.request.response;
52
- }
53
- get headers() {
54
- if (!this.processedHeaders) {
55
- const headers = this.processedHeaders = {};
56
- this.request.getAllResponseHeaders().split(/\r?\n/g).forEach(function (header) {
57
- const index = header.indexOf(":");
58
- var key, val;
59
- if (index > 0) {
60
- key = header.substring(0, index).trim().toLowerCase();
61
- val = header.substring(index + 1).trim();
62
- }
63
- else
64
- key = header.trim().toLowerCase();
65
- var list = headers[key];
66
- if (!list)
67
- list = headers[key] = [];
68
- if (val)
69
- list.push(val);
70
- });
71
- }
72
- return this.processedHeaders;
73
- }
74
- }
75
- const execute = function (method, url, data, cb, extraHeaders, progcb, wantsBinary) {
76
- const request = new XMLHttpRequest();
77
- var responseIsArrayBuffer;
78
- try {
79
- if (!wantsBinary)
80
- throw false;
81
- request.responseType = "arraybuffer";
82
- if (request.responseType !== "arraybuffer") {
83
- console.error("Could not request arraybuffer");
84
- throw false;
85
- }
86
- responseIsArrayBuffer = true;
87
- }
88
- catch (e) {
89
- responseIsArrayBuffer = false;
90
- }
91
- request.open(method, url, true);
92
- if (extraHeaders)
93
- Object.keys(extraHeaders).forEach(function (key) {
94
- request.setRequestHeader(key, extraHeaders[key]);
95
- });
96
- if (progcb)
97
- request.onprogress = function (ev) {
98
- if (ev.lengthComputable && ev.total)
99
- progcb(ev.loaded, ev.total);
100
- };
101
- request.onreadystatechange = function (e) {
102
- if (request.readyState === XMLHttpRequest.DONE)
103
- cb(new NexusFrameworkXMLHttpRequestResponse(request, url, !!data, responseIsArrayBuffer));
104
- };
105
- const type = data && data.type;
106
- if (type)
107
- switch (type) {
108
- case "":
109
- case "text/urlencoded":
110
- var dat = "";
111
- for (var entry of data.data) {
112
- if (dat)
113
- dat += "&";
114
- dat += encodeURIComponent(entry[0]);
115
- dat += "=";
116
- dat += encodeURIComponent(entry[1]);
117
- }
118
- request.setRequestHeader("Content-Type", "text/urlencoded");
119
- request.send(dat);
120
- break;
121
- case "text/json":
122
- request.setRequestHeader("Content-Type", "text/json");
123
- request.send(JSON.stringify(data.data));
124
- break;
125
- case "application/bson":
126
- request.setRequestHeader("Content-Type", "application/bson");
127
- request.send(BSON.serialize(data.data));
128
- break;
129
- case "multipart/form-data":
130
- request.send(data.data);
131
- break;
132
- default:
133
- request.send(data);
134
- }
135
- else
136
- request.send(data);
137
- };
138
- impl = {
139
- get: function (url, cb, extraHeaders, progcb, wantsBinary) {
140
- execute("GET", url, undefined, cb, extraHeaders, progcb, wantsBinary);
141
- },
142
- head: function (url, cb, extraHeaders, progcb, wantsBinary) {
143
- execute("HEAD", url, undefined, cb, extraHeaders, progcb, wantsBinary);
144
- },
145
- post: function (url, data, cb, extraHeaders, progcb, wantsBinary) {
146
- execute("POST", url, data, cb, extraHeaders, progcb, wantsBinary);
147
- },
148
- put: function (url, data, cb, extraHeaders, progcb, wantsBinary) {
149
- execute("PUT", url, data, cb, extraHeaders, progcb, wantsBinary);
150
- },
151
- execute,
152
- del: function (url, cb, extraHeaders, progcb, wantsBinary) {
153
- execute("DELETE", url, undefined, cb, extraHeaders, progcb, wantsBinary);
154
- }
155
- };
156
- }
157
- else
158
- throw new Error("No transport implementations");
159
- Object.defineProperty(window, "NexusFrameworkTransport", {
160
- value: impl
161
- });
162
- return impl;
163
- }
164
- },
165
- NexusFrameworkImpl: {
166
- configurable: true,
167
- set: function (instance) {
168
- Object.defineProperty(window, "NexusFrameworkImpl", {
169
- value: instance
170
- });
171
- },
172
- get: function () {
173
- const loader = window.NexusFrameworkLoader;
174
- const showError = loader.showError;
175
- const debug = /*function(...args: any[]){};*/ console.log.bind(console);
176
- const GA_ANALYTICS = {
177
- reportError: function (err, fatal) {
178
- if (window.ga)
179
- try {
180
- window.ga('send', 'exception', {
181
- 'exDescription': (err.stack || "" + err).replace(/\n/g, "\n\t"),
182
- 'exFatal': fatal
183
- });
184
- }
185
- catch (e) {
186
- console.warn(e);
187
- }
188
- },
189
- reportEvent: function (category, action, label, value) {
190
- if (window.ga)
191
- try {
192
- window.ga('send', 'event', category, action, label, value);
193
- }
194
- catch (e) {
195
- console.warn(e);
196
- }
197
- },
198
- reportPage: function (path) {
199
- if (window.ga)
200
- try {
201
- if (!path)
202
- path = location.pathname;
203
- window.ga('set', 'page', path);
204
- window.ga('send', 'pageview');
205
- }
206
- catch (e) {
207
- console.warn(e);
208
- }
209
- }
210
- };
211
- const r = document.createElement("a");
212
- const protocol = location.href.match(/^\w+:/)[0];
213
- const resolveUrl = function (url) {
214
- r.setAttribute("href", url);
215
- var href = r.href;
216
- if (/^\/\//.test(href))
217
- href = protocol + href;
218
- return href;
219
- };
220
- const convertResponse = function (res, url = location.href) {
221
- var storage;
222
- return (typeof res.data === "string") ? {
223
- url,
224
- code: res.code,
225
- contentAsString: res.data,
226
- get contentLength() {
227
- return parseInt(res.headers['content-length'] && res.headers['content-length'][0]) || res.data.length;
228
- },
229
- get contentAsArrayBuffer() {
230
- throw new Error("Not implemented");
231
- },
232
- get contentFromBSON() {
233
- if (!storage)
234
- storage = JSON.parse(res.data);
235
- return storage;
236
- },
237
- get contentFromJSON() {
238
- if (!storage)
239
- storage = JSON.parse(res.data);
240
- return storage;
241
- },
242
- headers: res.headers
243
- } : {
244
- url,
245
- code: res.code,
246
- get contentAsString() {
247
- if (!storage)
248
- storage = JSON.stringify(res.data);
249
- return storage;
250
- },
251
- get contentAsArrayBuffer() {
252
- throw new Error("Not implemented");
253
- },
254
- contentFromJSON: res.data,
255
- contentFromBSON: res.data,
256
- headers: res.headers,
257
- get contentLength() {
258
- var length = parseInt(res.headers['content-length'] && res.headers['content-length'][0]);
259
- if (length)
260
- return length;
261
- if (!storage)
262
- storage = JSON.stringify(res.data);
263
- return storage.length;
264
- }
265
- };
266
- };
267
- const loaderContainerRegex = /(^|\s)loader\-(progress|error)\-container(\s|$)/;
268
- class NexusFrameworkBase {
269
- constructor(url = "/", io) {
270
- this.activerid = 0;
271
- this.components = {};
272
- this.currentUserID = undefined;
273
- this.progressVisible = false;
274
- this.animationTiming = 500;
275
- this.requestPage = this.defaultRequestPage;
276
- this._listeners = {};
277
- url = resolveUrl(url);
278
- if (!/\/$/.test(url))
279
- url += "/";
280
- Object.defineProperties(this, {
281
- io: {
282
- value: io
283
- },
284
- url: {
285
- value: url
286
- }
287
- });
288
- this._analytics = GA_ANALYTICS;
289
- }
290
- resolveUrl(url) {
291
- if (/^\w+\:/.test(url))
292
- return url;
293
- return resolveUrl(this.url + url);
294
- }
295
- disableAll(root = document.body) {
296
- const focusable = root.querySelectorAll("a, input, select, textarea, iframe, button, *[focusable], *[tabindex]");
297
- for (var i = 0; i < focusable.length; i++) {
298
- const child = focusable[i];
299
- const tabindex = child.getAttribute("tabindex");
300
- if (tabindex == "-1")
301
- return;
302
- child.setAttribute("data-tabindex", tabindex ? tabindex : "");
303
- child.setAttribute("data-tabindex", "-1");
304
- }
305
- }
306
- enableAll(root = document.body) {
307
- const focusable = root.querySelectorAll("*[data-tabindex]");
308
- for (var i = 0; i < focusable.length; i++) {
309
- const child = focusable[i];
310
- child.setAttribute("tabindex", child.getAttribute("data-tabindex"));
311
- child.removeAttribute("data-tabindex");
312
- }
313
- }
314
- get analytics() {
315
- return this._analytics;
316
- }
317
- set analytics(value) {
318
- this._analytics = value ? value : GA_ANALYTICS;
319
- }
320
- reportError(err, fatal) {
321
- console[fatal ? "error" : "warn"](err.stack);
322
- if (this.errorreporter)
323
- this.errorreporter(err, fatal);
324
- }
325
- installErrorReporter(errorreporter) {
326
- this.errorreporter = errorreporter;
327
- }
328
- registerComponent(selector, impl) {
329
- if (impl) {
330
- this.components[selector] = impl;
331
- this.createComponents(document.head);
332
- this.createComponents(document.body);
333
- }
334
- else {
335
- delete this.components[selector];
336
- var destroy = (root) => {
337
- const elements = root.querySelectorAll(selector);
338
- if (!elements.length)
339
- return;
340
- for (var i = 0; i < elements.length; i++) {
341
- const element = elements[i];
342
- var components = element['__nf_cmapping__'];
343
- if (!components)
344
- components = element['__nf_cmapping__'] = {};
345
- const component = components[selector];
346
- if (component) {
347
- try {
348
- component.destroy();
349
- }
350
- catch (e) {
351
- this.reportError(e);
352
- }
353
- }
354
- }
355
- };
356
- destroy(document.head);
357
- destroy(document.body);
358
- }
359
- }
360
- unregisterComponent(selector, impl) {
361
- }
362
- createComponents(root) {
363
- Object.keys(this.components).forEach((selector) => {
364
- const elements = root.querySelectorAll(selector);
365
- if (!elements.length)
366
- return;
367
- for (var i = 0; i < elements.length; i++) {
368
- const element = elements[i];
369
- var components = element['__nf_cmapping__'];
370
- if (!components)
371
- components = element['__nf_cmapping__'] = {};
372
- if (components[selector])
373
- continue;
374
- const componentFactory = this.components[selector];
375
- try {
376
- (components[selector] = new componentFactory()).create(element);
377
- }
378
- catch (e) {
379
- this.reportError(e);
380
- }
381
- }
382
- });
383
- }
384
- destroyComponents(root) {
385
- Object.keys(this.components).forEach((selector) => {
386
- const elements = root.querySelectorAll(selector);
387
- if (!elements.length)
388
- return;
389
- for (var i = 0; i < elements.length; i++) {
390
- const element = elements[i];
391
- var components = element['__nf_cmapping__'];
392
- if (!components)
393
- components = element['__nf_cmapping__'] = {};
394
- const component = components[selector];
395
- if (component) {
396
- try {
397
- component.destroy();
398
- }
399
- catch (e) {
400
- this.reportError(e);
401
- }
402
- }
403
- }
404
- });
405
- }
406
- restoreComponents(root, state) {
407
- Object.keys(this.components).forEach((selector) => {
408
- const states = state[selector];
409
- if (!states)
410
- return;
411
- const elements = root.querySelectorAll(selector);
412
- if (!elements.length)
413
- return;
414
- for (var i = 0; i < elements.length; i++) {
415
- const element = elements[i];
416
- if (states.length) {
417
- const _state = states.shift();
418
- if (_state) {
419
- var components = element['__nf_cmapping__'];
420
- if (!components)
421
- components = element['__nf_cmapping__'] = {};
422
- var component = components[selector];
423
- if (!component) {
424
- const componentFactory = this.components[selector];
425
- try {
426
- (component = components[selector] = new componentFactory()).create(element);
427
- }
428
- catch (e) {
429
- this.reportError(e);
430
- console.warn(e);
431
- continue;
432
- }
433
- }
434
- try {
435
- component.restore(_state);
436
- }
437
- catch (e) {
438
- this.reportError(e);
439
- console.warn(e);
440
- }
441
- }
442
- }
443
- else
444
- break;
445
- }
446
- });
447
- }
448
- saveComponents(root) {
449
- var state = {};
450
- Object.keys(this.components).forEach((selector) => {
451
- const states = state[selector] = [];
452
- const elements = root.querySelectorAll(selector);
453
- if (!elements.length)
454
- return;
455
- for (var i = 0; i < elements.length; i++) {
456
- const element = elements[i];
457
- var components = element['__nf_cmapping__'];
458
- if (!components)
459
- components = element['__nf_cmapping__'] = {};
460
- var component = components[selector];
461
- if (!component) {
462
- const componentFactory = this.components[selector];
463
- try {
464
- (component = components[selector] = new componentFactory).create(element);
465
- }
466
- catch (e) {
467
- states.push(undefined);
468
- this.reportError(e);
469
- console.warn(e);
470
- continue;
471
- }
472
- }
473
- try {
474
- states.push(component.save());
475
- }
476
- catch (e) {
477
- states.push(undefined);
478
- this.reportError(e);
479
- console.warn(e);
480
- }
481
- }
482
- });
483
- return state;
484
- }
485
- initPageSystem(opts) {
486
- if (!loader)
487
- return console.error("The NexusFramework Loader is required for the dynamic Page System to work correctly.");
488
- if (!history.pushState || !history.replaceState)
489
- return console.warn("This browser is missing an essential feature required for the dynamic Page System.");
490
- if (this.pagesyshandler)
491
- return console.warn("Page System already initialized, ignoring additional requests to initialize.");
492
- opts = opts || {};
493
- const self = this;
494
- var pageStatesSize = 0;
495
- const pageStates = [];
496
- this.animationTiming = opts.animationTiming || 500;
497
- const pageStateCacheSize = opts.pageHistoryCacheSize || 25000000;
498
- const wrapCB = (cb) => {
499
- return (res) => {
500
- const user = res.headers['x-logged-user'];
501
- if (user)
502
- self.currentUserID = user[0];
503
- else
504
- self.currentUserID = undefined;
505
- debug("Current UID", self.currentUserID);
506
- cb(res);
507
- if (res.code === 200)
508
- setTimeout(() => {
509
- self._analytics.reportPage();
510
- });
511
- };
512
- };
513
- loader.showError = function (error) {
514
- const match = location.href.match(beforeHash);
515
- const baseurl = match && match[1] || location.href;
516
- const length = error.stack.length;
517
- const tooBig = pageStateCacheSize <= length;
518
- try {
519
- const cPageStates = pageStates.length;
520
- for (var i = 0; i < cPageStates; i++) {
521
- const state = pageStates[i];
522
- if (state.url === baseurl) {
523
- if (tooBig) {
524
- pageStates.splice(i, 1);
525
- pageStatesSize -= state.size;
526
- }
527
- else {
528
- state.data = { error };
529
- state.updated = +new Date;
530
- pageStatesSize += length - state.size;
531
- }
532
- throw true;
533
- }
534
- }
535
- if (tooBig)
536
- throw true;
537
- pageStates.push({
538
- url: baseurl,
539
- data: { error },
540
- updated: +new Date,
541
- size: length
542
- });
543
- pageStatesSize += length;
544
- }
545
- catch (e) {
546
- if (e !== true)
547
- throw e;
548
- }
549
- return showError(error);
550
- };
551
- const transportPageSystem = {
552
- requestPage(path, cb, post, rid) {
553
- if (self.pagesysprerequest && !self.pagesysprerequest(path)) {
554
- self.defaultRequestPage(path, post);
555
- return;
556
- }
557
- if (!opts.noprogress) {
558
- self.disableAll();
559
- loader.showProgress();
560
- }
561
- const url = self.resolveUrl(":pagesys/" + path);
562
- const _cb = opts.noprogress ? cb : function (res) {
563
- if (opts.noprogress)
564
- cb(res);
565
- else
566
- loader.showProgress(() => {
567
- cb(res);
568
- self.enableAll();
569
- });
570
- };
571
- if (post)
572
- window.NexusFrameworkTransport.post(url, post, wrapCB(_cb), undefined, undefined, true);
573
- else
574
- window.NexusFrameworkTransport.get(url, wrapCB(_cb), undefined, undefined, true);
575
- }
576
- };
577
- if (!opts.noio && this.io) {
578
- const io = this.io;
579
- this.pagesysimpl = {
580
- requestPage(path, cb, post, rid) {
581
- if (io.connected) {
582
- if (self.pagesysprerequest && !self.pagesysprerequest(path)) {
583
- self.defaultRequestPage(path, post);
584
- return;
585
- }
586
- if (!opts.noprogress) {
587
- self.disableAll();
588
- loader.showProgress();
589
- }
590
- const headers = {
591
- "referrer": location.href
592
- };
593
- var val = document.cookie;
594
- if (val)
595
- headers['cookie'] = val;
596
- io.emit("page", post ? "POST" : "GET", path, post, headers, function (res) {
597
- if (rid != self.activerid)
598
- return;
599
- const cookies = res.headers['set-cookie'];
600
- if (cookies) {
601
- cookies.forEach(function (cookie) {
602
- document.cookie = cookie;
603
- });
604
- }
605
- const _cb = opts.noprogress ? cb : function (res) {
606
- if (!opts.noprogress)
607
- cb(res);
608
- else
609
- loader.showProgress(() => {
610
- cb(res);
611
- self.enableAll();
612
- });
613
- };
614
- wrapCB(_cb)(convertResponse(res, self.resolveUrl(path)));
615
- });
616
- }
617
- else
618
- transportPageSystem.requestPage(path, cb, post, rid);
619
- }
620
- };
621
- }
622
- else
623
- this.pagesysimpl = transportPageSystem;
624
- var base = document.getElementsByTagName("base");
625
- base = base && base[0];
626
- this.pagesysprerequest = opts.prerequest;
627
- this.pagesyshandler = opts.handler || ((res, pageReady) => {
628
- try {
629
- const contentType = res.headers['content-type'][0];
630
- if (!/\/html(;.+)?$/.test(contentType.toLowerCase())) {
631
- throw new Error("Content type is not html");
632
- }
633
- }
634
- catch (e) { }
635
- const content = res.contentAsString;
636
- const bodyindex = content.indexOf("<body");
637
- if (bodyindex == -1)
638
- throw new Error("Could not find start of body tag");
639
- const endbodyindex = content.indexOf("</body>") || content.indexOf("</ body>");
640
- if (endbodyindex == -1)
641
- throw new Error("Could not find end of body tag");
642
- const title = content.match(/<title>([^<]+)<\/\s*title>/);
643
- document.title = title && title[1] || "Title Not Set";
644
- const mockhtml = document.createElement("html");
645
- mockhtml.innerHTML = content.substring(bodyindex, endbodyindex) + "</body>";
646
- var loaderScript;
647
- var childs = mockhtml.children;
648
- const toAdd = [];
649
- for (var i = 0; i < childs.length; i++) {
650
- const child = childs[i];
651
- switch (child.nodeName.toUpperCase()) {
652
- case "HEAD":
653
- break;
654
- case "BODY":
655
- i = -1;
656
- childs = child.children;
657
- break;
658
- case "SCRIPT":
659
- const match = child.innerHTML.match(/^NexusFrameworkLoader\.load\((.+)\);?$/);
660
- if (match)
661
- loaderScript = JSON.parse(match[1]);
662
- break;
663
- default:
664
- if (loaderContainerRegex.test(child.className))
665
- break;
666
- toAdd.push(child);
667
- }
668
- }
669
- if (!toAdd.length)
670
- throw new Error("Nothing found in response to add to page");
671
- if (!loaderScript)
672
- throw new Error("NexusFrameworkLoader script not found...");
673
- childs = document.body.children;
674
- for (var i = childs.length - 1; i >= 0; i--) {
675
- const child = childs[i];
676
- switch (child.nodeName.toUpperCase()) {
677
- case "LINK":
678
- case "SCRIPT":
679
- break;
680
- default:
681
- if (loaderContainerRegex.test(child.className))
682
- break;
683
- document.body.removeChild(child);
684
- }
685
- }
686
- const fragment = document.createDocumentFragment();
687
- toAdd.forEach((el) => {
688
- fragment.appendChild(el);
689
- this.createComponents(el);
690
- });
691
- document.body.appendChild(fragment);
692
- loader.load(loaderScript, function () {
693
- self.progressVisible = true;
694
- loader.resetProgress();
695
- pageReady();
696
- });
697
- return true;
698
- });
699
- var forwardPopState;
700
- const beforeHash = /^([^#]+)(#.*)?$/;
701
- var chash = location.href.match(beforeHash)[1];
702
- const startsWith = new RegExp("^" + this.url.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "(.*)$", "i");
703
- class AnchorElementComponent {
704
- constructor() {
705
- this.handler = (e) => {
706
- if (this.element.hasAttribute("data-nopagesys") || this.element.hasAttribute("data-nodynamic"))
707
- return;
708
- const href = this.element.getAttribute("href");
709
- if (!href || !href.length)
710
- return;
711
- var url = this.element.href;
712
- const bhash = url.match(beforeHash);
713
- if (bhash[2] && chash === bhash[1])
714
- return;
715
- if (startsWith.test(url))
716
- try {
717
- const match = url.match(/^(.+)#.*$/);
718
- if (match)
719
- url = match[1];
720
- self.requestPage(url.substring(self.url.length));
721
- try {
722
- e.stopPropagation();
723
- }
724
- catch (e) { }
725
- try {
726
- e.preventDefault();
727
- }
728
- catch (e) { }
729
- }
730
- catch (e) {
731
- console.warn(e);
732
- }
733
- else
734
- debug("Navigating", url);
735
- };
736
- }
737
- create(element) {
738
- element.addEventListener("click", this.handler);
739
- this.element = element;
740
- }
741
- destroy() {
742
- this.element.removeEventListener("click", this.handler);
743
- }
744
- restore(data) { }
745
- save() { }
746
- }
747
- class FormElementComponent {
748
- constructor() {
749
- this.handler = (e) => {
750
- if (this.element.hasAttribute("data-nopagesys") || this.element.hasAttribute("data-nodynamic"))
751
- return;
752
- const method = this.element.getAttribute("method") || "get";
753
- const enctype = this.element.getAttribute("enctype") || "text/urlencoded";
754
- const action = this.element.getAttribute("action") || "";
755
- var url = resolveUrl(action);
756
- if (startsWith.test(url)) {
757
- try {
758
- const match = url.match(/^(.+)#.*$/);
759
- if (match)
760
- url = match[1];
761
- const formData = new FormData(this.element);
762
- loader.showProgress(undefined, "Submitting Form", "Your form data is being processed");
763
- if (method.trim().toLowerCase() === "post")
764
- self.requestPage(url.substring(self.url.length), { type: enctype, data: formData });
765
- else {
766
- var first = true;
767
- var reqUrl = url.substring(self.url.length) + "?";
768
- for (var entry of formData) {
769
- if (first)
770
- first = false;
771
- else
772
- reqUrl += "&";
773
- reqUrl += encodeURIComponent(entry[0]);
774
- reqUrl += "=";
775
- reqUrl += encodeURIComponent(entry[1]);
776
- }
777
- self.requestPage(reqUrl);
778
- }
779
- try {
780
- e.stopPropagation();
781
- }
782
- catch (e) { }
783
- try {
784
- e.preventDefault();
785
- }
786
- catch (e) { }
787
- Array.prototype.forEach.call(this.element.querySelectorAll("a, input, select, textarea, iframe, button, *[name]"), function (el) {
788
- el.setAttribute("disabled", "disabled");
789
- el.className += " disabled";
790
- });
791
- Array.prototype.forEach.call(this.element.querySelectorAll("button:not([type]), button[type=submit]"), function (button) {
792
- button.innerHTML = "Processing Request";
793
- });
794
- Array.prototype.forEach.call(this.element.querySelectorAll("input[type=submit]"), function (input) {
795
- input.value = "Processing Request";
796
- });
797
- return;
798
- }
799
- catch (e) {
800
- debug(e);
801
- }
802
- }
803
- debug("Submitting", url);
804
- };
805
- }
806
- create(element) {
807
- element.addEventListener("submit", this.handler);
808
- this.element = element;
809
- }
810
- destroy() {
811
- this.element.removeEventListener("submit", this.handler);
812
- }
813
- restore(data) { }
814
- save() { }
815
- }
816
- const requestPage = this.requestPage = (path, post, replace = false) => {
817
- const match = path.match(/\.([^\/]+)([\?#].*)?$/);
818
- if (match && match[0] !== "htm" && match[0] !== "html") {
819
- this.defaultRequestPage(path, post);
820
- debug("Ignoring navigation", path, match);
821
- }
822
- else {
823
- debug("requestPage", path);
824
- const rid = ++self.activerid;
825
- const baseurl = this.resolveUrl(path);
826
- const fullurl = baseurl + (match && match[2] || "");
827
- if (replace)
828
- history.replaceState(!!post, "Loading...", fullurl);
829
- else {
830
- history.pushState(!!post, "Loading...", fullurl);
831
- chash = fullurl.match(beforeHash)[1];
832
- window.scrollTo(0, 0);
833
- }
834
- loader.resetError();
835
- loader.resetProgress();
836
- this.pagesysimpl.requestPage(path, (res) => {
837
- try {
838
- if (rid !== self.activerid)
839
- return;
840
- if (!res.code) {
841
- loader.showProgress(undefined, "Connection Issue", "Check your network and try again");
842
- document.title = "Connection Issue";
843
- history.replaceState(res.hadData, "Connection Issue", fullurl);
844
- setTimeout(function () {
845
- if (rid !== self.activerid)
846
- return;
847
- requestPage(path, post, true);
848
- }, 900000);
849
- return;
850
- }
851
- else if (res.code === 502 || res.code === 503) {
852
- loader.showProgress(undefined, "Scheduled Maintenance", "Sorry but this website is undergoing scheduled maintenance");
853
- document.title = "Scheduled Maintenance";
854
- history.replaceState(res.hadData, "Scheduled Maintenance", fullurl);
855
- setTimeout(function () {
856
- if (rid !== self.activerid)
857
- return;
858
- requestPage(path, post, true);
859
- }, 900000);
860
- return;
861
- }
862
- const location = res.headers['x-location'] || res.headers['location'];
863
- if (location) {
864
- const url = resolveUrl(location[0]);
865
- if (startsWith.test(url)) {
866
- this.requestPage(url.substring(this.url.length), undefined, true);
867
- return;
868
- }
869
- console.warn("Requested redirect to external url:", url);
870
- window.location.href = url;
871
- return;
872
- }
873
- const contentDisposition = res.headers['content-disposition'];
874
- if (contentDisposition && contentDisposition[0].toLowerCase() == "attachment")
875
- throw new Error("Attachment disposition");
876
- this.pagesyshandler(res, function () {
877
- if (rid !== self.activerid)
878
- return;
879
- try {
880
- const title = document.title;
881
- const length = res.contentLength;
882
- const tooBig = pageStateCacheSize <= length;
883
- const stateData = tooBig ? undefined : {
884
- title: title,
885
- user: self.currentUserID,
886
- scroll: [window.scrollX, window.scrollY],
887
- body: self.saveComponents(document.body),
888
- basehref: base ? base['href'] : undefined,
889
- response: res
890
- };
891
- var i;
892
- const cPageStates = pageStates.length;
893
- try {
894
- for (i = 0; i < cPageStates; i++) {
895
- const state = pageStates[i];
896
- if (state.url === baseurl) {
897
- if (tooBig) {
898
- pageStates.splice(i, 1);
899
- pageStatesSize -= state.size;
900
- }
901
- else {
902
- state.data = stateData;
903
- state.updated = +new Date;
904
- pageStatesSize += length - state.size;
905
- }
906
- throw true;
907
- }
908
- }
909
- if (!tooBig) {
910
- pageStates.push({
911
- url: baseurl,
912
- data: stateData,
913
- updated: +new Date,
914
- size: length
915
- });
916
- pageStatesSize += length;
917
- throw true;
918
- }
919
- else
920
- debug("Response too big to store", baseurl, length);
921
- }
922
- catch (e) {
923
- if (e === true) {
924
- const over = pageStatesSize - pageStateCacheSize;
925
- if (over > 0) {
926
- pageStates.sort(function (a, b) {
927
- return a.updated - b.updated;
928
- });
929
- var found = 0;
930
- for (i = 0; i < cPageStates; i++) {
931
- found += pageStates[i].size;
932
- if (found >= over)
933
- break;
934
- }
935
- i++;
936
- pageStates.splice(0, i);
937
- debug("Trimmed", i, "items...");
938
- }
939
- }
940
- else
941
- throw e;
942
- }
943
- history.replaceState(res.hadData, document.title, fullurl);
944
- self.emit("page", baseurl, path);
945
- }
946
- catch (e) {
947
- debug(e);
948
- if (replace)
949
- window.location.reload(true);
950
- else
951
- try {
952
- chash = undefined;
953
- forwardPopState = [path, post];
954
- debug("Going backwards");
955
- history.go(-1);
956
- }
957
- catch (e) { }
958
- }
959
- });
960
- }
961
- catch (e) {
962
- debug(e);
963
- if (replace)
964
- window.location.reload(true);
965
- else
966
- try {
967
- chash = undefined;
968
- forwardPopState = [path, post];
969
- debug("Going backwards");
970
- history.go(-1);
971
- }
972
- catch (e) { }
973
- }
974
- }, post, rid);
975
- }
976
- };
977
- this.registerComponent("a", AnchorElementComponent);
978
- this.registerComponent("form", FormElementComponent);
979
- window.addEventListener('popstate', (e) => {
980
- try {
981
- var state;
982
- const bhash = location.href.match(beforeHash);
983
- const cStates = pageStates.length;
984
- const baseurl = bhash[1];
985
- for (var i = 0; i < cStates; i++) {
986
- const _state = pageStates[i];
987
- if (_state.url === baseurl) {
988
- state = _state;
989
- break;
990
- }
991
- }
992
- const hasState = !!state;
993
- const rid = ++self.activerid;
994
- const error = hasState && state.data.error;
995
- if (error) {
996
- showError(error);
997
- return;
998
- }
999
- if (forwardPopState) {
1000
- debug("forwardPopState", forwardPopState);
1001
- const forward = forwardPopState;
1002
- setTimeout(() => {
1003
- if (rid === self.activerid)
1004
- self.defaultRequestPage(forward[0], forward[1]);
1005
- });
1006
- forwardPopState = undefined;
1007
- return;
1008
- }
1009
- if (chash === baseurl) {
1010
- debug("Only hash has changed...", baseurl);
1011
- return;
1012
- }
1013
- chash = bhash[1];
1014
- if (e.state)
1015
- alert("You submitted data to this page, which cannot be re-sent. Because of this, what you're viewing may not be the same now.");
1016
- if (!hasState)
1017
- throw new Error("No state for: " + baseurl + ", reloading...");
1018
- if (state.data.user != self.currentUserID)
1019
- throw new Error("User has changed since state was created, reloading...");
1020
- document.title = state.data.title;
1021
- loader.resetProgress();
1022
- loader.resetError();
1023
- self.pagesyshandler(state.data.response, function (err) {
1024
- if (rid !== self.activerid)
1025
- return;
1026
- try {
1027
- if (err)
1028
- throw err;
1029
- if (state.data.body)
1030
- self.restoreComponents(document.body, state.data.body);
1031
- if (state.data.scroll)
1032
- window.scrollTo.apply(window, state.data.scroll);
1033
- debug("Used stored page state!", state);
1034
- }
1035
- catch (err) {
1036
- debug(err);
1037
- var url = location.href;
1038
- if (startsWith.test(url)) {
1039
- try {
1040
- if (/reloading\.\.\.$/.test(err.message)) {
1041
- self.requestPage(url.substring(self.url.length), undefined, true);
1042
- return;
1043
- }
1044
- console.error("Unknown error occured, actually navigating to page...");
1045
- }
1046
- catch (e) {
1047
- console.error(e);
1048
- }
1049
- }
1050
- location.reload(true);
1051
- }
1052
- });
1053
- }
1054
- catch (err) {
1055
- debug(err);
1056
- var url = location.href;
1057
- if (startsWith.test(url)) {
1058
- try {
1059
- if (/reloading\.\.\.$/.test(err.message)) {
1060
- self.requestPage(url.substring(self.url.length), undefined, true);
1061
- return;
1062
- }
1063
- console.error("Unknown error occured, actually navigating to page...");
1064
- }
1065
- catch (e) {
1066
- console.error(e);
1067
- }
1068
- }
1069
- location.reload(true);
1070
- }
1071
- });
1072
- return true;
1073
- }
1074
- get currentUser() {
1075
- return this.currentUserID;
1076
- }
1077
- defaultRequestPage(path, post) {
1078
- if (post)
1079
- throw new Error("Posting is not supported without an initialized page system, yet");
1080
- else
1081
- location.href = this.resolveUrl(path);
1082
- }
1083
- on(event, cb) {
1084
- var listeners = this._listeners[event];
1085
- if (listeners)
1086
- listeners.push(cb);
1087
- else
1088
- this._listeners[event] = listeners = [cb];
1089
- }
1090
- off(event, cb) {
1091
- var index;
1092
- var listeners = this._listeners[event];
1093
- if (listeners && (index = listeners.indexOf(cb)) > -1)
1094
- listeners.splice(index, 1);
1095
- }
1096
- emit(event, ...args) {
1097
- const self = this;
1098
- const listeners = this._listeners[event];
1099
- if (listeners)
1100
- listeners.forEach(function (cb) {
1101
- cb.apply(self, args);
1102
- });
1103
- }
1104
- }
1105
- var impl;
1106
- if (window.io)
1107
- impl = class NexusFrameworkWithIO extends NexusFrameworkBase {
1108
- constructor(url) {
1109
- super(url, window.io({
1110
- path: "/:io"
1111
- }));
1112
- const io = this.io;
1113
- io.on("connect", function () {
1114
- io.emit("init", loader.requestedResources());
1115
- });
1116
- }
1117
- };
1118
- else
1119
- impl = class NexusFrameworkNoIO extends NexusFrameworkBase {
1120
- constructor(url) {
1121
- super(url);
1122
- }
1123
- };
1124
- Object.defineProperty(window, "NexusFrameworkImpl", {
1125
- value: impl
1126
- });
1127
- return impl;
1128
- }
1129
- },
1130
- NexusFrameworkClient: {
1131
- configurable: true,
1132
- set: function (instance) {
1133
- Object.defineProperty(window, "NexusFrameworkClient", {
1134
- value: instance
1135
- });
1136
- },
1137
- get: function () {
1138
- const instance = new window.NexusFrameworkImpl();
1139
- Object.defineProperty(window, "NexusFrameworkClient", {
1140
- value: instance
1141
- });
1142
- return instance;
1143
- }
1144
- }
1145
- });
1146
- })(window);
1
+ /// <reference path="../index.d.ts" />
2
+ (function (window) {
3
+ const BSON = new window['bson'];
4
+ Object.defineProperties(window, {
5
+ NexusFrameworkTransport: {
6
+ configurable: true,
7
+ set: function (instance) {
8
+ Object.defineProperty(window, "NexusFrameworkTransport", {
9
+ value: instance
10
+ });
11
+ },
12
+ get: function () {
13
+ var impl;
14
+ if ("XMLHttpRequest" in window) {
15
+ class NexusFrameworkXMLHttpRequestResponse {
16
+ constructor(request, url, hadData, abResponse) {
17
+ this._url = url;
18
+ this.request = request;
19
+ this.hadData = hadData;
20
+ this.abResponse = abResponse;
21
+ }
22
+ get url() {
23
+ return this.request.responseURL || this._url;
24
+ }
25
+ get code() {
26
+ return this.request.status;
27
+ }
28
+ get contentLength() {
29
+ return parseInt(this.request.getResponseHeader("content-length")) || this.request.responseText.length;
30
+ }
31
+ get contentFromJSON() {
32
+ if (!this.parsedJson)
33
+ this.parsedJson = JSON.parse(this.request.responseText);
34
+ return this.parsedJson;
35
+ }
36
+ get contentFromBSON() {
37
+ if (!this.parsedBson) {
38
+ var response = this.request.response;
39
+ if (typeof response === "string")
40
+ response = Buffer.from(response, "utf8");
41
+ else
42
+ response = new Buffer(response);
43
+ this.parsedBson = BSON.deserialize(response, { promoteValues: true });
44
+ }
45
+ return this.parsedBson;
46
+ }
47
+ get contentAsString() {
48
+ return this.request.responseText;
49
+ }
50
+ get contentAsArrayBuffer() {
51
+ return this.request.response;
52
+ }
53
+ get headers() {
54
+ if (!this.processedHeaders) {
55
+ const headers = this.processedHeaders = {};
56
+ this.request.getAllResponseHeaders().split(/\r?\n/g).forEach(function (header) {
57
+ const index = header.indexOf(":");
58
+ var key, val;
59
+ if (index > 0) {
60
+ key = header.substring(0, index).trim().toLowerCase();
61
+ val = header.substring(index + 1).trim();
62
+ }
63
+ else
64
+ key = header.trim().toLowerCase();
65
+ var list = headers[key];
66
+ if (!list)
67
+ list = headers[key] = [];
68
+ if (val)
69
+ list.push(val);
70
+ });
71
+ }
72
+ return this.processedHeaders;
73
+ }
74
+ }
75
+ const execute = function (method, url, data, cb, extraHeaders, progcb, wantsBinary) {
76
+ const request = new XMLHttpRequest();
77
+ var responseIsArrayBuffer;
78
+ try {
79
+ if (!wantsBinary)
80
+ throw false;
81
+ request.responseType = "arraybuffer";
82
+ if (request.responseType !== "arraybuffer") {
83
+ console.error("Could not request arraybuffer");
84
+ throw false;
85
+ }
86
+ responseIsArrayBuffer = true;
87
+ }
88
+ catch (e) {
89
+ responseIsArrayBuffer = false;
90
+ }
91
+ request.open(method, url, true);
92
+ if (extraHeaders)
93
+ Object.keys(extraHeaders).forEach(function (key) {
94
+ request.setRequestHeader(key, extraHeaders[key]);
95
+ });
96
+ if (progcb)
97
+ request.onprogress = function (ev) {
98
+ if (ev.lengthComputable && ev.total)
99
+ progcb(ev.loaded, ev.total);
100
+ };
101
+ request.onreadystatechange = function (e) {
102
+ if (request.readyState === XMLHttpRequest.DONE)
103
+ cb(new NexusFrameworkXMLHttpRequestResponse(request, url, !!data, responseIsArrayBuffer));
104
+ };
105
+ const type = data && data.type;
106
+ if (type)
107
+ switch (type) {
108
+ case "":
109
+ case "text/urlencoded":
110
+ var dat = "";
111
+ for (var entry of data.data) {
112
+ if (dat)
113
+ dat += "&";
114
+ dat += encodeURIComponent(entry[0]);
115
+ dat += "=";
116
+ dat += encodeURIComponent(entry[1]);
117
+ }
118
+ request.setRequestHeader("Content-Type", "text/urlencoded");
119
+ request.send(dat);
120
+ break;
121
+ case "text/json":
122
+ request.setRequestHeader("Content-Type", "text/json");
123
+ request.send(JSON.stringify(data.data));
124
+ break;
125
+ case "application/bson":
126
+ request.setRequestHeader("Content-Type", "application/bson");
127
+ request.send(BSON.serialize(data.data));
128
+ break;
129
+ case "multipart/form-data":
130
+ request.send(data.data);
131
+ break;
132
+ default:
133
+ request.send(data);
134
+ }
135
+ else
136
+ request.send(data);
137
+ };
138
+ impl = {
139
+ get: function (url, cb, extraHeaders, progcb, wantsBinary) {
140
+ execute("GET", url, undefined, cb, extraHeaders, progcb, wantsBinary);
141
+ },
142
+ head: function (url, cb, extraHeaders, progcb, wantsBinary) {
143
+ execute("HEAD", url, undefined, cb, extraHeaders, progcb, wantsBinary);
144
+ },
145
+ post: function (url, data, cb, extraHeaders, progcb, wantsBinary) {
146
+ execute("POST", url, data, cb, extraHeaders, progcb, wantsBinary);
147
+ },
148
+ put: function (url, data, cb, extraHeaders, progcb, wantsBinary) {
149
+ execute("PUT", url, data, cb, extraHeaders, progcb, wantsBinary);
150
+ },
151
+ execute,
152
+ del: function (url, cb, extraHeaders, progcb, wantsBinary) {
153
+ execute("DELETE", url, undefined, cb, extraHeaders, progcb, wantsBinary);
154
+ }
155
+ };
156
+ }
157
+ else
158
+ throw new Error("No transport implementations");
159
+ Object.defineProperty(window, "NexusFrameworkTransport", {
160
+ value: impl
161
+ });
162
+ return impl;
163
+ }
164
+ },
165
+ NexusFrameworkImpl: {
166
+ configurable: true,
167
+ set: function (instance) {
168
+ Object.defineProperty(window, "NexusFrameworkImpl", {
169
+ value: instance
170
+ });
171
+ },
172
+ get: function () {
173
+ const loader = window.NexusFrameworkLoader;
174
+ const showError = loader.showError;
175
+ const debug = /*function(...args: any[]){};*/ console.log.bind(console);
176
+ const GA_ANALYTICS = {
177
+ reportError: function (err, fatal) {
178
+ if (window.ga)
179
+ try {
180
+ window.ga('send', 'exception', {
181
+ 'exDescription': (err.stack || "" + err).replace(/\n/g, "\n\t"),
182
+ 'exFatal': fatal
183
+ });
184
+ }
185
+ catch (e) {
186
+ console.warn(e);
187
+ }
188
+ },
189
+ reportEvent: function (category, action, label, value) {
190
+ if (window.ga)
191
+ try {
192
+ window.ga('send', 'event', category, action, label, value);
193
+ }
194
+ catch (e) {
195
+ console.warn(e);
196
+ }
197
+ },
198
+ reportPage: function (path) {
199
+ if (window.ga)
200
+ try {
201
+ if (!path)
202
+ path = location.pathname;
203
+ window.ga('set', 'page', path);
204
+ window.ga('send', 'pageview');
205
+ }
206
+ catch (e) {
207
+ console.warn(e);
208
+ }
209
+ }
210
+ };
211
+ const r = document.createElement("a");
212
+ const protocol = location.href.match(/^\w+:/)[0];
213
+ const resolveUrl = function (url) {
214
+ r.setAttribute("href", url);
215
+ var href = r.href;
216
+ if (/^\/\//.test(href))
217
+ href = protocol + href;
218
+ return href;
219
+ };
220
+ const convertResponse = function (res, url = location.href) {
221
+ var storage;
222
+ return (typeof res.data === "string") ? {
223
+ url,
224
+ code: res.code,
225
+ contentAsString: res.data,
226
+ get contentLength() {
227
+ return parseInt(res.headers['content-length'] && res.headers['content-length'][0]) || res.data.length;
228
+ },
229
+ get contentAsArrayBuffer() {
230
+ throw new Error("Not implemented");
231
+ },
232
+ get contentFromBSON() {
233
+ if (!storage)
234
+ storage = JSON.parse(res.data);
235
+ return storage;
236
+ },
237
+ get contentFromJSON() {
238
+ if (!storage)
239
+ storage = JSON.parse(res.data);
240
+ return storage;
241
+ },
242
+ headers: res.headers
243
+ } : {
244
+ url,
245
+ code: res.code,
246
+ get contentAsString() {
247
+ if (!storage)
248
+ storage = JSON.stringify(res.data);
249
+ return storage;
250
+ },
251
+ get contentAsArrayBuffer() {
252
+ throw new Error("Not implemented");
253
+ },
254
+ contentFromJSON: res.data,
255
+ contentFromBSON: res.data,
256
+ headers: res.headers,
257
+ get contentLength() {
258
+ var length = parseInt(res.headers['content-length'] && res.headers['content-length'][0]);
259
+ if (length)
260
+ return length;
261
+ if (!storage)
262
+ storage = JSON.stringify(res.data);
263
+ return storage.length;
264
+ }
265
+ };
266
+ };
267
+ const loaderContainerRegex = /(^|\s)loader\-(progress|error)\-container(\s|$)/;
268
+ class NexusFrameworkBase {
269
+ constructor(url = "/", io) {
270
+ this.activerid = 0;
271
+ this.components = {};
272
+ this.currentUserID = undefined;
273
+ this.progressVisible = false;
274
+ this.animationTiming = 500;
275
+ this.requestPage = this.defaultRequestPage;
276
+ this._listeners = {};
277
+ url = resolveUrl(url);
278
+ if (!/\/$/.test(url))
279
+ url += "/";
280
+ Object.defineProperties(this, {
281
+ io: {
282
+ value: io
283
+ },
284
+ url: {
285
+ value: url
286
+ }
287
+ });
288
+ this._analytics = GA_ANALYTICS;
289
+ }
290
+ resolveUrl(url) {
291
+ if (/^\w+\:/.test(url))
292
+ return url;
293
+ return resolveUrl(this.url + url);
294
+ }
295
+ disableAll(root = document.body) {
296
+ const focusable = root.querySelectorAll("a, input, select, textarea, iframe, button, *[focusable], *[tabindex]");
297
+ for (var i = 0; i < focusable.length; i++) {
298
+ const child = focusable[i];
299
+ const tabindex = child.getAttribute("tabindex");
300
+ if (tabindex == "-1")
301
+ return;
302
+ child.setAttribute("data-tabindex", tabindex ? tabindex : "");
303
+ child.setAttribute("data-tabindex", "-1");
304
+ }
305
+ }
306
+ enableAll(root = document.body) {
307
+ const focusable = root.querySelectorAll("*[data-tabindex]");
308
+ for (var i = 0; i < focusable.length; i++) {
309
+ const child = focusable[i];
310
+ child.setAttribute("tabindex", child.getAttribute("data-tabindex"));
311
+ child.removeAttribute("data-tabindex");
312
+ }
313
+ }
314
+ get analytics() {
315
+ return this._analytics;
316
+ }
317
+ set analytics(value) {
318
+ this._analytics = value ? value : GA_ANALYTICS;
319
+ }
320
+ reportError(err, fatal) {
321
+ console[fatal ? "error" : "warn"](err.stack);
322
+ if (this.errorreporter)
323
+ this.errorreporter(err, fatal);
324
+ }
325
+ installErrorReporter(errorreporter) {
326
+ this.errorreporter = errorreporter;
327
+ }
328
+ registerComponent(selector, impl) {
329
+ if (impl) {
330
+ this.components[selector] = impl;
331
+ this.createComponents(document.head);
332
+ this.createComponents(document.body);
333
+ }
334
+ else {
335
+ delete this.components[selector];
336
+ var destroy = (root) => {
337
+ const elements = root.querySelectorAll(selector);
338
+ if (!elements.length)
339
+ return;
340
+ for (var i = 0; i < elements.length; i++) {
341
+ const element = elements[i];
342
+ var components = element['__nf_cmapping__'];
343
+ if (!components)
344
+ components = element['__nf_cmapping__'] = {};
345
+ const component = components[selector];
346
+ if (component) {
347
+ try {
348
+ component.destroy();
349
+ }
350
+ catch (e) {
351
+ this.reportError(e);
352
+ }
353
+ }
354
+ }
355
+ };
356
+ destroy(document.head);
357
+ destroy(document.body);
358
+ }
359
+ }
360
+ unregisterComponent(selector, impl) {
361
+ }
362
+ createComponents(root) {
363
+ Object.keys(this.components).forEach((selector) => {
364
+ const elements = root.querySelectorAll(selector);
365
+ if (!elements.length)
366
+ return;
367
+ for (var i = 0; i < elements.length; i++) {
368
+ const element = elements[i];
369
+ var components = element['__nf_cmapping__'];
370
+ if (!components)
371
+ components = element['__nf_cmapping__'] = {};
372
+ if (components[selector])
373
+ continue;
374
+ const componentFactory = this.components[selector];
375
+ try {
376
+ (components[selector] = new componentFactory()).create(element);
377
+ }
378
+ catch (e) {
379
+ this.reportError(e);
380
+ }
381
+ }
382
+ });
383
+ }
384
+ destroyComponents(root) {
385
+ Object.keys(this.components).forEach((selector) => {
386
+ const elements = root.querySelectorAll(selector);
387
+ if (!elements.length)
388
+ return;
389
+ for (var i = 0; i < elements.length; i++) {
390
+ const element = elements[i];
391
+ var components = element['__nf_cmapping__'];
392
+ if (!components)
393
+ components = element['__nf_cmapping__'] = {};
394
+ const component = components[selector];
395
+ if (component) {
396
+ try {
397
+ component.destroy();
398
+ }
399
+ catch (e) {
400
+ this.reportError(e);
401
+ }
402
+ }
403
+ }
404
+ });
405
+ }
406
+ restoreComponents(root, state) {
407
+ Object.keys(this.components).forEach((selector) => {
408
+ const states = state[selector];
409
+ if (!states)
410
+ return;
411
+ const elements = root.querySelectorAll(selector);
412
+ if (!elements.length)
413
+ return;
414
+ for (var i = 0; i < elements.length; i++) {
415
+ const element = elements[i];
416
+ if (states.length) {
417
+ const _state = states.shift();
418
+ if (_state) {
419
+ var components = element['__nf_cmapping__'];
420
+ if (!components)
421
+ components = element['__nf_cmapping__'] = {};
422
+ var component = components[selector];
423
+ if (!component) {
424
+ const componentFactory = this.components[selector];
425
+ try {
426
+ (component = components[selector] = new componentFactory()).create(element);
427
+ }
428
+ catch (e) {
429
+ this.reportError(e);
430
+ console.warn(e);
431
+ continue;
432
+ }
433
+ }
434
+ try {
435
+ component.restore(_state);
436
+ }
437
+ catch (e) {
438
+ this.reportError(e);
439
+ console.warn(e);
440
+ }
441
+ }
442
+ }
443
+ else
444
+ break;
445
+ }
446
+ });
447
+ }
448
+ saveComponents(root) {
449
+ var state = {};
450
+ Object.keys(this.components).forEach((selector) => {
451
+ const states = state[selector] = [];
452
+ const elements = root.querySelectorAll(selector);
453
+ if (!elements.length)
454
+ return;
455
+ for (var i = 0; i < elements.length; i++) {
456
+ const element = elements[i];
457
+ var components = element['__nf_cmapping__'];
458
+ if (!components)
459
+ components = element['__nf_cmapping__'] = {};
460
+ var component = components[selector];
461
+ if (!component) {
462
+ const componentFactory = this.components[selector];
463
+ try {
464
+ (component = components[selector] = new componentFactory).create(element);
465
+ }
466
+ catch (e) {
467
+ states.push(undefined);
468
+ this.reportError(e);
469
+ console.warn(e);
470
+ continue;
471
+ }
472
+ }
473
+ try {
474
+ states.push(component.save());
475
+ }
476
+ catch (e) {
477
+ states.push(undefined);
478
+ this.reportError(e);
479
+ console.warn(e);
480
+ }
481
+ }
482
+ });
483
+ return state;
484
+ }
485
+ initPageSystem(opts) {
486
+ if (!loader)
487
+ return console.error("The NexusFramework Loader is required for the dynamic Page System to work correctly.");
488
+ if (!history.pushState || !history.replaceState)
489
+ return console.warn("This browser is missing an essential feature required for the dynamic Page System.");
490
+ if (this.pagesyshandler)
491
+ return console.warn("Page System already initialized, ignoring additional requests to initialize.");
492
+ opts = opts || {};
493
+ const self = this;
494
+ var pageStatesSize = 0;
495
+ const pageStates = [];
496
+ this.animationTiming = opts.animationTiming || 500;
497
+ const pageStateCacheSize = opts.pageHistoryCacheSize || 25000000;
498
+ const wrapCB = (cb) => {
499
+ return (res) => {
500
+ const user = res.headers['x-logged-user'];
501
+ if (user)
502
+ self.currentUserID = user[0];
503
+ else
504
+ self.currentUserID = undefined;
505
+ debug("Current UID", self.currentUserID);
506
+ cb(res);
507
+ if (res.code === 200)
508
+ setTimeout(() => {
509
+ self._analytics.reportPage();
510
+ });
511
+ };
512
+ };
513
+ loader.showError = function (error) {
514
+ const match = location.href.match(beforeHash);
515
+ const baseurl = match && match[1] || location.href;
516
+ const length = error.stack.length;
517
+ const tooBig = pageStateCacheSize <= length;
518
+ try {
519
+ const cPageStates = pageStates.length;
520
+ for (var i = 0; i < cPageStates; i++) {
521
+ const state = pageStates[i];
522
+ if (state.url === baseurl) {
523
+ if (tooBig) {
524
+ pageStates.splice(i, 1);
525
+ pageStatesSize -= state.size;
526
+ }
527
+ else {
528
+ state.data = { error };
529
+ state.updated = +new Date;
530
+ pageStatesSize += length - state.size;
531
+ }
532
+ throw true;
533
+ }
534
+ }
535
+ if (tooBig)
536
+ throw true;
537
+ pageStates.push({
538
+ url: baseurl,
539
+ data: { error },
540
+ updated: +new Date,
541
+ size: length
542
+ });
543
+ pageStatesSize += length;
544
+ }
545
+ catch (e) {
546
+ if (e !== true)
547
+ throw e;
548
+ }
549
+ return showError(error);
550
+ };
551
+ const transportPageSystem = {
552
+ requestPage(path, cb, post, rid) {
553
+ if (self.pagesysprerequest && !self.pagesysprerequest(path)) {
554
+ self.defaultRequestPage(path, post);
555
+ return;
556
+ }
557
+ if (!opts.noprogress) {
558
+ self.disableAll();
559
+ loader.showProgress();
560
+ }
561
+ const url = self.resolveUrl(":pagesys/" + path);
562
+ const _cb = opts.noprogress ? cb : function (res) {
563
+ if (opts.noprogress)
564
+ cb(res);
565
+ else
566
+ loader.showProgress(() => {
567
+ cb(res);
568
+ self.enableAll();
569
+ });
570
+ };
571
+ if (post)
572
+ window.NexusFrameworkTransport.post(url, post, wrapCB(_cb), undefined, undefined, true);
573
+ else
574
+ window.NexusFrameworkTransport.get(url, wrapCB(_cb), undefined, undefined, true);
575
+ }
576
+ };
577
+ if (!opts.noio && this.io) {
578
+ const io = this.io;
579
+ this.pagesysimpl = {
580
+ requestPage(path, cb, post, rid) {
581
+ if (io.connected) {
582
+ if (self.pagesysprerequest && !self.pagesysprerequest(path)) {
583
+ self.defaultRequestPage(path, post);
584
+ return;
585
+ }
586
+ if (!opts.noprogress) {
587
+ self.disableAll();
588
+ loader.showProgress();
589
+ }
590
+ const headers = {
591
+ "referrer": location.href
592
+ };
593
+ var val = document.cookie;
594
+ if (val)
595
+ headers['cookie'] = val;
596
+ io.emit("page", post ? "POST" : "GET", path, post, headers, function (res) {
597
+ if (rid != self.activerid)
598
+ return;
599
+ const cookies = res.headers['set-cookie'];
600
+ if (cookies) {
601
+ cookies.forEach(function (cookie) {
602
+ document.cookie = cookie;
603
+ });
604
+ }
605
+ const _cb = opts.noprogress ? cb : function (res) {
606
+ if (!opts.noprogress)
607
+ cb(res);
608
+ else
609
+ loader.showProgress(() => {
610
+ cb(res);
611
+ self.enableAll();
612
+ });
613
+ };
614
+ wrapCB(_cb)(convertResponse(res, self.resolveUrl(path)));
615
+ });
616
+ }
617
+ else
618
+ transportPageSystem.requestPage(path, cb, post, rid);
619
+ }
620
+ };
621
+ }
622
+ else
623
+ this.pagesysimpl = transportPageSystem;
624
+ var base = document.getElementsByTagName("base");
625
+ base = base && base[0];
626
+ this.pagesysprerequest = opts.prerequest;
627
+ this.pagesyshandler = opts.handler || ((res, pageReady) => {
628
+ try {
629
+ const contentType = res.headers['content-type'][0];
630
+ if (!/\/html(;.+)?$/.test(contentType.toLowerCase())) {
631
+ throw new Error("Content type is not html");
632
+ }
633
+ }
634
+ catch (e) { }
635
+ const content = res.contentAsString;
636
+ const bodyindex = content.indexOf("<body");
637
+ if (bodyindex == -1)
638
+ throw new Error("Could not find start of body tag");
639
+ const endbodyindex = content.indexOf("</body>") || content.indexOf("</ body>");
640
+ if (endbodyindex == -1)
641
+ throw new Error("Could not find end of body tag");
642
+ const title = content.match(/<title>([^<]+)<\/\s*title>/);
643
+ document.title = title && title[1] || "Title Not Set";
644
+ const mockhtml = document.createElement("html");
645
+ mockhtml.innerHTML = content.substring(bodyindex, endbodyindex) + "</body>";
646
+ var loaderScript;
647
+ var childs = mockhtml.children;
648
+ const toAdd = [];
649
+ for (var i = 0; i < childs.length; i++) {
650
+ const child = childs[i];
651
+ switch (child.nodeName.toUpperCase()) {
652
+ case "HEAD":
653
+ break;
654
+ case "BODY":
655
+ i = -1;
656
+ childs = child.children;
657
+ break;
658
+ case "SCRIPT":
659
+ const match = child.innerHTML.match(/^NexusFrameworkLoader\.load\((.+)\);?$/);
660
+ if (match)
661
+ loaderScript = JSON.parse(match[1]);
662
+ break;
663
+ default:
664
+ if (loaderContainerRegex.test(child.className))
665
+ break;
666
+ toAdd.push(child);
667
+ }
668
+ }
669
+ if (!toAdd.length)
670
+ throw new Error("Nothing found in response to add to page");
671
+ if (!loaderScript)
672
+ throw new Error("NexusFrameworkLoader script not found...");
673
+ childs = document.body.children;
674
+ for (var i = childs.length - 1; i >= 0; i--) {
675
+ const child = childs[i];
676
+ switch (child.nodeName.toUpperCase()) {
677
+ case "LINK":
678
+ case "SCRIPT":
679
+ break;
680
+ default:
681
+ if (loaderContainerRegex.test(child.className))
682
+ break;
683
+ document.body.removeChild(child);
684
+ }
685
+ }
686
+ const fragment = document.createDocumentFragment();
687
+ toAdd.forEach((el) => {
688
+ fragment.appendChild(el);
689
+ this.createComponents(el);
690
+ });
691
+ document.body.appendChild(fragment);
692
+ loader.load(loaderScript, function () {
693
+ self.progressVisible = true;
694
+ loader.resetProgress();
695
+ pageReady();
696
+ });
697
+ return true;
698
+ });
699
+ var forwardPopState;
700
+ const beforeHash = /^([^#]+)(#.*)?$/;
701
+ var chash = location.href.match(beforeHash)[1];
702
+ const startsWith = new RegExp("^" + this.url.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "(.*)$", "i");
703
+ class AnchorElementComponent {
704
+ constructor() {
705
+ this.handler = (e) => {
706
+ if (this.element.hasAttribute("data-nopagesys") || this.element.hasAttribute("data-nodynamic"))
707
+ return;
708
+ const href = this.element.getAttribute("href");
709
+ if (!href || !href.length)
710
+ return;
711
+ var url = this.element.href;
712
+ const bhash = url.match(beforeHash);
713
+ if (bhash[2] && chash === bhash[1])
714
+ return;
715
+ if (startsWith.test(url))
716
+ try {
717
+ const match = url.match(/^(.+)#.*$/);
718
+ if (match)
719
+ url = match[1];
720
+ self.requestPage(url.substring(self.url.length));
721
+ try {
722
+ e.stopPropagation();
723
+ }
724
+ catch (e) { }
725
+ try {
726
+ e.preventDefault();
727
+ }
728
+ catch (e) { }
729
+ }
730
+ catch (e) {
731
+ console.warn(e);
732
+ }
733
+ else
734
+ debug("Navigating", url);
735
+ };
736
+ }
737
+ create(element) {
738
+ element.addEventListener("click", this.handler);
739
+ this.element = element;
740
+ }
741
+ destroy() {
742
+ this.element.removeEventListener("click", this.handler);
743
+ }
744
+ restore(data) { }
745
+ save() { }
746
+ }
747
+ class FormElementComponent {
748
+ constructor() {
749
+ this.handler = (e) => {
750
+ if (this.element.hasAttribute("data-nopagesys") || this.element.hasAttribute("data-nodynamic"))
751
+ return;
752
+ const method = this.element.getAttribute("method") || "get";
753
+ const enctype = this.element.getAttribute("enctype") || "text/urlencoded";
754
+ const action = this.element.getAttribute("action") || "";
755
+ var url = resolveUrl(action);
756
+ if (startsWith.test(url)) {
757
+ try {
758
+ const match = url.match(/^(.+)#.*$/);
759
+ if (match)
760
+ url = match[1];
761
+ const formData = new FormData(this.element);
762
+ loader.showProgress(undefined, "Submitting Form", "Your form data is being processed");
763
+ if (method.trim().toLowerCase() === "post")
764
+ self.requestPage(url.substring(self.url.length), { type: enctype, data: formData });
765
+ else {
766
+ var first = true;
767
+ var reqUrl = url.substring(self.url.length) + "?";
768
+ for (var entry of formData) {
769
+ if (first)
770
+ first = false;
771
+ else
772
+ reqUrl += "&";
773
+ reqUrl += encodeURIComponent(entry[0]);
774
+ reqUrl += "=";
775
+ reqUrl += encodeURIComponent(entry[1]);
776
+ }
777
+ self.requestPage(reqUrl);
778
+ }
779
+ try {
780
+ e.stopPropagation();
781
+ }
782
+ catch (e) { }
783
+ try {
784
+ e.preventDefault();
785
+ }
786
+ catch (e) { }
787
+ Array.prototype.forEach.call(this.element.querySelectorAll("a, input, select, textarea, iframe, button, *[name]"), function (el) {
788
+ el.setAttribute("disabled", "disabled");
789
+ el.className += " disabled";
790
+ });
791
+ Array.prototype.forEach.call(this.element.querySelectorAll("button:not([type]), button[type=submit]"), function (button) {
792
+ button.innerHTML = "Processing Request";
793
+ });
794
+ Array.prototype.forEach.call(this.element.querySelectorAll("input[type=submit]"), function (input) {
795
+ input.value = "Processing Request";
796
+ });
797
+ return;
798
+ }
799
+ catch (e) {
800
+ debug(e);
801
+ }
802
+ }
803
+ debug("Submitting", url);
804
+ };
805
+ }
806
+ create(element) {
807
+ element.addEventListener("submit", this.handler);
808
+ this.element = element;
809
+ }
810
+ destroy() {
811
+ this.element.removeEventListener("submit", this.handler);
812
+ }
813
+ restore(data) { }
814
+ save() { }
815
+ }
816
+ const requestPage = this.requestPage = (path, post, replace = false) => {
817
+ const match = path.match(/\.([^\/]+)([\?#].*)?$/);
818
+ if (match && match[0] !== "htm" && match[0] !== "html") {
819
+ this.defaultRequestPage(path, post);
820
+ debug("Ignoring navigation", path, match);
821
+ }
822
+ else {
823
+ debug("requestPage", path);
824
+ const rid = ++self.activerid;
825
+ const baseurl = this.resolveUrl(path);
826
+ const fullurl = baseurl + (match && match[2] || "");
827
+ if (replace)
828
+ history.replaceState(!!post, "Loading...", fullurl);
829
+ else {
830
+ history.pushState(!!post, "Loading...", fullurl);
831
+ chash = fullurl.match(beforeHash)[1];
832
+ window.scrollTo(0, 0);
833
+ }
834
+ loader.resetError();
835
+ loader.resetProgress();
836
+ this.pagesysimpl.requestPage(path, (res) => {
837
+ try {
838
+ if (rid !== self.activerid)
839
+ return;
840
+ if (!res.code) {
841
+ loader.showProgress(undefined, "Connection Issue", "Check your network and try again");
842
+ document.title = "Connection Issue";
843
+ history.replaceState(res.hadData, "Connection Issue", fullurl);
844
+ setTimeout(function () {
845
+ if (rid !== self.activerid)
846
+ return;
847
+ requestPage(path, post, true);
848
+ }, 900000);
849
+ return;
850
+ }
851
+ else if (res.code === 502 || res.code === 503) {
852
+ loader.showProgress(undefined, "Scheduled Maintenance", "Sorry but this website is undergoing scheduled maintenance");
853
+ document.title = "Scheduled Maintenance";
854
+ history.replaceState(res.hadData, "Scheduled Maintenance", fullurl);
855
+ setTimeout(function () {
856
+ if (rid !== self.activerid)
857
+ return;
858
+ requestPage(path, post, true);
859
+ }, 900000);
860
+ return;
861
+ }
862
+ const location = res.headers['x-location'] || res.headers['location'];
863
+ if (location) {
864
+ const url = resolveUrl(location[0]);
865
+ if (startsWith.test(url)) {
866
+ this.requestPage(url.substring(this.url.length), undefined, true);
867
+ return;
868
+ }
869
+ console.warn("Requested redirect to external url:", url);
870
+ window.location.href = url;
871
+ return;
872
+ }
873
+ const contentDisposition = res.headers['content-disposition'];
874
+ if (contentDisposition && contentDisposition[0].toLowerCase() == "attachment")
875
+ throw new Error("Attachment disposition");
876
+ this.pagesyshandler(res, function () {
877
+ if (rid !== self.activerid)
878
+ return;
879
+ try {
880
+ const title = document.title;
881
+ const length = res.contentLength;
882
+ const tooBig = pageStateCacheSize <= length;
883
+ const stateData = tooBig ? undefined : {
884
+ title: title,
885
+ user: self.currentUserID,
886
+ scroll: [window.scrollX, window.scrollY],
887
+ body: self.saveComponents(document.body),
888
+ basehref: base ? base['href'] : undefined,
889
+ response: res
890
+ };
891
+ var i;
892
+ const cPageStates = pageStates.length;
893
+ try {
894
+ for (i = 0; i < cPageStates; i++) {
895
+ const state = pageStates[i];
896
+ if (state.url === baseurl) {
897
+ if (tooBig) {
898
+ pageStates.splice(i, 1);
899
+ pageStatesSize -= state.size;
900
+ }
901
+ else {
902
+ state.data = stateData;
903
+ state.updated = +new Date;
904
+ pageStatesSize += length - state.size;
905
+ }
906
+ throw true;
907
+ }
908
+ }
909
+ if (!tooBig) {
910
+ pageStates.push({
911
+ url: baseurl,
912
+ data: stateData,
913
+ updated: +new Date,
914
+ size: length
915
+ });
916
+ pageStatesSize += length;
917
+ throw true;
918
+ }
919
+ else
920
+ debug("Response too big to store", baseurl, length);
921
+ }
922
+ catch (e) {
923
+ if (e === true) {
924
+ const over = pageStatesSize - pageStateCacheSize;
925
+ if (over > 0) {
926
+ pageStates.sort(function (a, b) {
927
+ return a.updated - b.updated;
928
+ });
929
+ var found = 0;
930
+ for (i = 0; i < cPageStates; i++) {
931
+ found += pageStates[i].size;
932
+ if (found >= over)
933
+ break;
934
+ }
935
+ i++;
936
+ pageStates.splice(0, i);
937
+ debug("Trimmed", i, "items...");
938
+ }
939
+ }
940
+ else
941
+ throw e;
942
+ }
943
+ history.replaceState(res.hadData, document.title, fullurl);
944
+ self.emit("page", baseurl, path);
945
+ }
946
+ catch (e) {
947
+ debug(e);
948
+ if (replace)
949
+ window.location.reload(true);
950
+ else
951
+ try {
952
+ chash = undefined;
953
+ forwardPopState = [path, post];
954
+ debug("Going backwards");
955
+ history.go(-1);
956
+ }
957
+ catch (e) { }
958
+ }
959
+ });
960
+ }
961
+ catch (e) {
962
+ debug(e);
963
+ if (replace)
964
+ window.location.reload(true);
965
+ else
966
+ try {
967
+ chash = undefined;
968
+ forwardPopState = [path, post];
969
+ debug("Going backwards");
970
+ history.go(-1);
971
+ }
972
+ catch (e) { }
973
+ }
974
+ }, post, rid);
975
+ }
976
+ };
977
+ this.registerComponent("a", AnchorElementComponent);
978
+ this.registerComponent("form", FormElementComponent);
979
+ window.addEventListener('popstate', (e) => {
980
+ try {
981
+ var state;
982
+ const bhash = location.href.match(beforeHash);
983
+ const cStates = pageStates.length;
984
+ const baseurl = bhash[1];
985
+ for (var i = 0; i < cStates; i++) {
986
+ const _state = pageStates[i];
987
+ if (_state.url === baseurl) {
988
+ state = _state;
989
+ break;
990
+ }
991
+ }
992
+ const hasState = !!state;
993
+ const rid = ++self.activerid;
994
+ const error = hasState && state.data.error;
995
+ if (error) {
996
+ showError(error);
997
+ return;
998
+ }
999
+ if (forwardPopState) {
1000
+ debug("forwardPopState", forwardPopState);
1001
+ const forward = forwardPopState;
1002
+ setTimeout(() => {
1003
+ if (rid === self.activerid)
1004
+ self.defaultRequestPage(forward[0], forward[1]);
1005
+ });
1006
+ forwardPopState = undefined;
1007
+ return;
1008
+ }
1009
+ if (chash === baseurl) {
1010
+ debug("Only hash has changed...", baseurl);
1011
+ return;
1012
+ }
1013
+ chash = bhash[1];
1014
+ if (e.state)
1015
+ alert("You submitted data to this page, which cannot be re-sent. Because of this, what you're viewing may not be the same now.");
1016
+ if (!hasState)
1017
+ throw new Error("No state for: " + baseurl + ", reloading...");
1018
+ if (state.data.user != self.currentUserID)
1019
+ throw new Error("User has changed since state was created, reloading...");
1020
+ document.title = state.data.title;
1021
+ loader.resetProgress();
1022
+ loader.resetError();
1023
+ self.pagesyshandler(state.data.response, function (err) {
1024
+ if (rid !== self.activerid)
1025
+ return;
1026
+ try {
1027
+ if (err)
1028
+ throw err;
1029
+ if (state.data.body)
1030
+ self.restoreComponents(document.body, state.data.body);
1031
+ if (state.data.scroll)
1032
+ window.scrollTo.apply(window, state.data.scroll);
1033
+ debug("Used stored page state!", state);
1034
+ }
1035
+ catch (err) {
1036
+ debug(err);
1037
+ var url = location.href;
1038
+ if (startsWith.test(url)) {
1039
+ try {
1040
+ if (/reloading\.\.\.$/.test(err.message)) {
1041
+ self.requestPage(url.substring(self.url.length), undefined, true);
1042
+ return;
1043
+ }
1044
+ console.error("Unknown error occured, actually navigating to page...");
1045
+ }
1046
+ catch (e) {
1047
+ console.error(e);
1048
+ }
1049
+ }
1050
+ location.reload(true);
1051
+ }
1052
+ });
1053
+ }
1054
+ catch (err) {
1055
+ debug(err);
1056
+ var url = location.href;
1057
+ if (startsWith.test(url)) {
1058
+ try {
1059
+ if (/reloading\.\.\.$/.test(err.message)) {
1060
+ self.requestPage(url.substring(self.url.length), undefined, true);
1061
+ return;
1062
+ }
1063
+ console.error("Unknown error occured, actually navigating to page...");
1064
+ }
1065
+ catch (e) {
1066
+ console.error(e);
1067
+ }
1068
+ }
1069
+ location.reload(true);
1070
+ }
1071
+ });
1072
+ return true;
1073
+ }
1074
+ get currentUser() {
1075
+ return this.currentUserID;
1076
+ }
1077
+ defaultRequestPage(path, post) {
1078
+ if (post)
1079
+ throw new Error("Posting is not supported without an initialized page system, yet");
1080
+ else
1081
+ location.href = this.resolveUrl(path);
1082
+ }
1083
+ on(event, cb) {
1084
+ var listeners = this._listeners[event];
1085
+ if (listeners)
1086
+ listeners.push(cb);
1087
+ else
1088
+ this._listeners[event] = listeners = [cb];
1089
+ }
1090
+ off(event, cb) {
1091
+ var index;
1092
+ var listeners = this._listeners[event];
1093
+ if (listeners && (index = listeners.indexOf(cb)) > -1)
1094
+ listeners.splice(index, 1);
1095
+ }
1096
+ emit(event, ...args) {
1097
+ const self = this;
1098
+ const listeners = this._listeners[event];
1099
+ if (listeners)
1100
+ listeners.forEach(function (cb) {
1101
+ cb.apply(self, args);
1102
+ });
1103
+ }
1104
+ }
1105
+ var impl;
1106
+ if (window.io)
1107
+ impl = class NexusFrameworkWithIO extends NexusFrameworkBase {
1108
+ constructor(url) {
1109
+ super(url, window.io({
1110
+ path: "/:io"
1111
+ }));
1112
+ const io = this.io;
1113
+ io.on("connect", function () {
1114
+ io.emit("init", loader.requestedResources());
1115
+ });
1116
+ }
1117
+ };
1118
+ else
1119
+ impl = class NexusFrameworkNoIO extends NexusFrameworkBase {
1120
+ constructor(url) {
1121
+ super(url);
1122
+ }
1123
+ };
1124
+ Object.defineProperty(window, "NexusFrameworkImpl", {
1125
+ value: impl
1126
+ });
1127
+ return impl;
1128
+ }
1129
+ },
1130
+ NexusFrameworkClient: {
1131
+ configurable: true,
1132
+ set: function (instance) {
1133
+ Object.defineProperty(window, "NexusFrameworkClient", {
1134
+ value: instance
1135
+ });
1136
+ },
1137
+ get: function () {
1138
+ const instance = new window.NexusFrameworkImpl();
1139
+ Object.defineProperty(window, "NexusFrameworkClient", {
1140
+ value: instance
1141
+ });
1142
+ return instance;
1143
+ }
1144
+ }
1145
+ });
1146
+ })(window);
1147
1147
  //# sourceMappingURL=nexusframeworkclient.js.map