@brandup/ui-app 1.0.44 → 2.0.2

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 (39) hide show
  1. package/README.md +7 -4
  2. package/dist/cjs/app.js +397 -0
  3. package/dist/cjs/app.js.map +1 -0
  4. package/dist/cjs/builder.js +53 -0
  5. package/dist/cjs/builder.js.map +1 -0
  6. package/dist/cjs/constants.js +21 -0
  7. package/dist/cjs/constants.js.map +1 -0
  8. package/dist/cjs/ext.js +39 -0
  9. package/dist/cjs/ext.js.map +1 -0
  10. package/dist/cjs/helpers/url.js +206 -0
  11. package/dist/cjs/helpers/url.js.map +1 -0
  12. package/dist/cjs/index.js +11 -760
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/middlewares/hyperlink.js +75 -0
  15. package/dist/cjs/middlewares/hyperlink.js.map +1 -0
  16. package/dist/cjs/middlewares/invoker.js +55 -0
  17. package/dist/cjs/middlewares/invoker.js.map +1 -0
  18. package/dist/cjs/middlewares/state.js +86 -0
  19. package/dist/cjs/middlewares/state.js.map +1 -0
  20. package/dist/mjs/app.js +393 -0
  21. package/dist/mjs/app.js.map +1 -0
  22. package/dist/mjs/builder.js +51 -0
  23. package/dist/mjs/builder.js.map +1 -0
  24. package/dist/mjs/constants.js +17 -0
  25. package/dist/mjs/constants.js.map +1 -0
  26. package/dist/mjs/ext.js +37 -0
  27. package/dist/mjs/ext.js.map +1 -0
  28. package/dist/mjs/helpers/url.js +202 -0
  29. package/dist/mjs/helpers/url.js.map +1 -0
  30. package/dist/mjs/index.js +7 -759
  31. package/dist/mjs/index.js.map +1 -1
  32. package/dist/mjs/middlewares/hyperlink.js +70 -0
  33. package/dist/mjs/middlewares/hyperlink.js.map +1 -0
  34. package/dist/mjs/middlewares/invoker.js +53 -0
  35. package/dist/mjs/middlewares/invoker.js.map +1 -0
  36. package/dist/mjs/middlewares/state.js +81 -0
  37. package/dist/mjs/middlewares/state.js.map +1 -0
  38. package/dist/types.d.ts +155 -7
  39. package/package.json +11 -4
package/dist/mjs/index.js CHANGED
@@ -1,760 +1,8 @@
1
- import { UIElement } from '@brandup/ui';
2
- import { Guid } from '@brandup/ui-helpers';
3
-
4
- class MiddlewareInvoker {
5
- middleware;
6
- __next;
7
- constructor(middleware) {
8
- this.middleware = middleware;
9
- }
10
- next(middleware) {
11
- if (this.__next)
12
- this.__next.next(middleware);
13
- else
14
- this.__next = new MiddlewareInvoker(middleware);
15
- }
16
- invoke(method, context) {
17
- return this.__exec(method, context);
18
- }
19
- async __exec(method, context) {
20
- const nextFunc = () => this.__next ? this.__next.__exec(method, context) : Promise.resolve();
21
- context.abort.throwIfAborted();
22
- const methodFunc = this.middleware[method];
23
- if (typeof methodFunc === "function") {
24
- const methodResult = methodFunc.call(this.middleware, context, nextFunc);
25
- if (!methodResult || !(methodResult instanceof Promise))
26
- throw new Error(`Middleware "${this.middleware.name}" method "${method}" is not async.`);
27
- await methodResult;
28
- }
29
- else
30
- await nextFunc();
31
- }
32
- }
33
-
34
- const result = {
35
- LoadingElementClass: "loading",
36
- NavUrlClassName: "applink",
37
- FormClassName: "appform",
38
- NavUrlAttributeName: "data-nav-url",
39
- NavUrlReplaceAttributeName: "data-nav-replace",
40
- NavUrlScopeAttributeName: "data-nav-scope",
41
- NavIgnoreAttributeName: "data-nav-ignore",
42
- STATE_CLASS: {
43
- LOADING: "bp-state-loading",
44
- LOADED: "bp-state-loaded",
45
- READY: "bp-state-ready"
46
- }
47
- };
48
-
49
- var constants = /*#__PURE__*/Object.freeze({
50
- __proto__: null,
51
- default: result
52
- });
53
-
54
- const STATE_MIDDLEWARE_NAME = "app-state";
55
- const StateMiddlewareFactory = () => {
56
- let counter = 0;
57
- const begin = (context) => {
58
- const prev = counter++;
59
- if (prev === 0) {
60
- context.app.element?.classList.remove(result.STATE_CLASS.LOADED);
61
- context.app.element?.classList.add(result.STATE_CLASS.LOADING);
62
- }
63
- };
64
- const end = (context) => {
65
- counter--;
66
- if (counter <= 0) {
67
- counter = 0;
68
- context.app.element?.classList.add(result.STATE_CLASS.LOADED);
69
- context.app.element?.classList.remove(result.STATE_CLASS.LOADING);
70
- }
71
- };
72
- return {
73
- name: STATE_MIDDLEWARE_NAME,
74
- start: async (context, next) => {
75
- begin(context);
76
- try {
77
- await next();
78
- // on success the begin() is left open on purpose: the loading state
79
- // must persist through "loaded" and the first navigation, which closes
80
- // it (see the "first" branch in navigate). On error we close it here.
81
- }
82
- catch (reason) {
83
- end(context);
84
- throw reason;
85
- }
86
- },
87
- loaded: async (context, next) => {
88
- try {
89
- await next();
90
- context.app.element?.classList.add(result.STATE_CLASS.READY);
91
- }
92
- catch (reason) {
93
- end(context);
94
- throw reason;
95
- }
96
- },
97
- navigate: async (context, next) => {
98
- begin(context);
99
- try {
100
- await next();
101
- }
102
- finally {
103
- end(context); // close the begin() of this navigation
104
- // the first navigation also closes the loading opened by start(),
105
- // which intentionally leaves its begin() open until the page is rendered
106
- if (context.source == "first")
107
- end(context);
108
- }
109
- },
110
- submit: async (context, next) => {
111
- begin(context);
112
- try {
113
- await next();
114
- }
115
- finally {
116
- end(context);
117
- }
118
- },
119
- stop: async (_context, next) => {
120
- await next();
121
- }
122
- };
123
- };
124
-
125
- const HYPERLINK_MIDDLEWARE_NAME = "app-hyperlink";
126
- const HyperLinkMiddlewareFactory = () => {
127
- let onClick;
128
- return {
129
- name: HYPERLINK_MIDDLEWARE_NAME,
130
- start: async (context, next) => {
131
- await next();
132
- window.addEventListener("click", onClick = (e) => {
133
- let elem = e.target;
134
- let ignore = false;
135
- while (elem) {
136
- if (elem instanceof HTMLElement) {
137
- if (elem.hasAttribute(result.NavIgnoreAttributeName)) {
138
- ignore = true;
139
- break;
140
- }
141
- if (elem.classList.contains(result.NavUrlClassName) || elem.hasAttribute(result.NavUrlAttributeName))
142
- break;
143
- }
144
- if (elem === e.currentTarget)
145
- return;
146
- elem = elem.parentElement;
147
- }
148
- if (!elem || e.ctrlKey || e.metaKey || elem.getAttribute("target") === "_blank")
149
- return;
150
- e.preventDefault();
151
- e.stopPropagation();
152
- if (ignore)
153
- return;
154
- let url;
155
- if (elem.tagName === "A")
156
- url = elem.getAttribute("href");
157
- else if (elem.hasAttribute(result.NavUrlAttributeName))
158
- url = elem.getAttribute(result.NavUrlAttributeName);
159
- else
160
- throw "Not found url for navigation.";
161
- if (elem.classList.contains(result.LoadingElementClass))
162
- return;
163
- elem.classList.add(result.LoadingElementClass);
164
- context.app
165
- .nav({
166
- url,
167
- replace: elem.hasAttribute(result.NavUrlReplaceAttributeName),
168
- scope: elem.getAttribute(result.NavUrlScopeAttributeName),
169
- data: { clickElem: elem }
170
- })
171
- .catch(() => { })
172
- .finally(() => elem.classList.remove(result.LoadingElementClass));
173
- }, false);
174
- },
175
- stop: (_context, next) => {
176
- window.removeEventListener("click", onClick, false);
177
- return next();
178
- }
179
- };
180
- };
181
-
182
- const parseUrl = (basePath, url) => {
183
- const loc = window.location;
184
- let origin = loc.origin;
185
- let path;
186
- let query = null;
187
- let hash = null;
188
- let isExternal = false;
189
- if (basePath === '/')
190
- basePath = '';
191
- if (!url) {
192
- path = loc.pathname;
193
- if (loc.search)
194
- query = new URLSearchParams(loc.search);
195
- if (loc.hash)
196
- hash = loc.hash;
197
- }
198
- else {
199
- if (url.startsWith("#")) {
200
- path = loc.pathname;
201
- query = new URLSearchParams(loc.search);
202
- hash = url;
203
- }
204
- else if (url.startsWith("?")) {
205
- const hastIndex = url.lastIndexOf("#");
206
- if (hastIndex !== -1) {
207
- hash = url.substring(hastIndex);
208
- url = url.substring(0, hastIndex);
209
- }
210
- path = loc.pathname;
211
- query = new URLSearchParams(url);
212
- }
213
- else if (url.startsWith("http")) {
214
- const u = new URL(url);
215
- if (u.origin != origin) {
216
- origin = u.origin;
217
- isExternal = true;
218
- }
219
- path = u.pathname;
220
- query = u.searchParams;
221
- hash = u.hash || null;
222
- }
223
- else {
224
- const hastIndex = url.lastIndexOf("#");
225
- if (hastIndex !== -1) {
226
- hash = url.substring(hastIndex);
227
- url = url.substring(0, hastIndex);
228
- }
229
- const queryIndex = url.lastIndexOf("?");
230
- if (queryIndex !== -1) {
231
- query = new URLSearchParams(url.substring(queryIndex));
232
- url = url.substring(0, queryIndex);
233
- }
234
- path = url;
235
- if (!path.startsWith("/")) {
236
- let curPath = loc.pathname;
237
- if (curPath.endsWith("/"))
238
- curPath = curPath.substring(0, curPath.length - 1);
239
- path = curPath + "/" + path;
240
- }
241
- }
242
- }
243
- if (!path)
244
- path = '/';
245
- else if (path.length > 1 && path.endsWith('/'))
246
- path = path.substring(0, path.length - 1);
247
- path = path.toLowerCase();
248
- if (basePath) {
249
- if (path.startsWith(basePath.toLowerCase())) {
250
- path = path.substring(basePath.length);
251
- if (!path)
252
- path = '/';
253
- }
254
- else
255
- basePath = '';
256
- }
257
- if (!query)
258
- query = new URLSearchParams();
259
- if (hash === '#')
260
- hash = null;
261
- else if (hash)
262
- hash = hash.substring(1);
263
- var result = {
264
- full: '',
265
- url: '',
266
- relative: '',
267
- origin,
268
- basePath,
269
- path,
270
- query,
271
- hash,
272
- external: isExternal
273
- };
274
- rebuildUrl(result);
275
- return result;
276
- };
277
- /**
278
- * Add or replace query parameters.
279
- * @param url Source url for extending query.
280
- * @param query New or update parameters.
281
- */
282
- const extendQuery = (url, query) => {
283
- if (query instanceof URLSearchParams) {
284
- query.forEach((_v, k) => url.query.delete(k));
285
- query.forEach((v, k) => url.query.append(k, v));
286
- }
287
- else if (query instanceof FormData) {
288
- query.forEach((_v, k) => url.query.delete(k));
289
- query.forEach((v, k) => url.query.append(k, v.toString()));
290
- }
291
- else {
292
- for (const key in query) {
293
- const value = query[key];
294
- if (!Array.isArray(value)) {
295
- url.query.set(key, value);
296
- }
297
- else {
298
- url.query.delete(key);
299
- value.forEach(val => url.query.append(key, val));
300
- }
301
- }
302
- }
303
- rebuildUrl(url);
304
- };
305
- const rebuildUrl = (parsedUrl) => {
306
- let relativeUrl = parsedUrl.basePath + parsedUrl.path;
307
- if (relativeUrl.length > 1 && relativeUrl.endsWith('/'))
308
- relativeUrl = relativeUrl.substring(0, relativeUrl.length - 1);
309
- if (parsedUrl.query.size)
310
- relativeUrl += "?" + parsedUrl.query.toString();
311
- parsedUrl.url = parsedUrl.origin + relativeUrl;
312
- parsedUrl.relative = relativeUrl;
313
- parsedUrl.full = parsedUrl.hash ? `${parsedUrl.url}#${parsedUrl.hash}` : parsedUrl.url;
314
- };
315
- const buildUrl = (basePath, path, query, hash) => {
316
- let url = basePath;
317
- if (url == '/')
318
- url = '';
319
- if (path) {
320
- if (!path.startsWith("/"))
321
- path = '/' + path;
322
- url += path;
323
- }
324
- if (!url)
325
- url = '/';
326
- else if (url.endsWith('/'))
327
- url = url.substring(0, url.length - 1);
328
- if (query) {
329
- let params;
330
- if (query instanceof URLSearchParams)
331
- params = query;
332
- else if (query instanceof FormData) {
333
- params = new URLSearchParams();
334
- query.forEach((value, key) => params.append(key, value.toString()));
335
- }
336
- else {
337
- params = new URLSearchParams();
338
- for (const key in query) {
339
- const value = query[key];
340
- if (value === null || typeof value === "undefined")
341
- continue;
342
- if (Array.isArray(value))
343
- value.forEach(v => params.append(key, v));
344
- else
345
- params.append(key, value);
346
- }
347
- }
348
- if (params.size)
349
- url += "?" + params.toString();
350
- }
351
- if (hash) {
352
- if (!hash.startsWith("#"))
353
- hash = "#" + hash;
354
- if (hash != "#")
355
- url += hash;
356
- }
357
- return url;
358
- };
359
- var urlHelper = {
360
- parseUrl,
361
- extendQuery,
362
- buildUrl
363
- };
364
-
365
- var url = /*#__PURE__*/Object.freeze({
366
- __proto__: null,
367
- default: urlHelper
368
- });
369
-
370
- const APP_TYPENAME = "brandup-ui-app";
371
- const NAV_OVERIDE_ERROR = "NavigationOveride";
372
- /**
373
- * Base application class.
374
- */
375
- class Application extends UIElement {
376
- /** Application environment. */
377
- env;
378
- /** Application model. */
379
- model;
380
- /** Application middleware invoker. */
381
- invoker;
382
- __abort;
383
- __isInited;
384
- __isRuned;
385
- __middlewares = {};
386
- __globalSubmit;
387
- __execNav; // current navigation invoking
388
- __lastNav; // last success navigation
389
- constructor(env, model, ..._args) {
390
- super();
391
- this.env = env;
392
- this.model = model;
393
- const core = { name: "app-root" };
394
- this.invoker = new MiddlewareInvoker(core);
395
- this.__abort = new AbortController();
396
- }
397
- get typeName() { return APP_TYPENAME; }
398
- /** Current navigation context. */
399
- get current() { return this.__lastNav?.context; }
400
- /** Application destroy signal. */
401
- get abort() { return this.__abort.signal; }
402
- /** @internal */
403
- initialize(middlewares) {
404
- if (this.__isInited)
405
- throw new Error('Application already initialized.');
406
- this.__isInited = true;
407
- this.onInitialize();
408
- middlewares.forEach(middleware => {
409
- const name = middleware.name;
410
- if (this.__middlewares.hasOwnProperty(name))
411
- throw new Error(`Middleware "${name}" already registered.`);
412
- this.__middlewares[name] = middleware;
413
- this.invoker.next(middleware);
414
- });
415
- }
416
- /** Initialize application instance. */
417
- onInitialize() {
418
- this.invoker.next(StateMiddlewareFactory());
419
- this.invoker.next(HyperLinkMiddlewareFactory());
420
- }
421
- /** Begin run application. */
422
- onStarting() { return Promise.resolve(); }
423
- /** Complate run application. */
424
- onStared() { return Promise.resolve(); }
425
- /**
426
- * Get middleware by type.
427
- * @param type Type of middleware.
428
- * @returns Middleware instance.
429
- */
430
- middleware(name) {
431
- this.__abort.signal.throwIfAborted();
432
- const middleware = this.__middlewares[name];
433
- if (!middleware)
434
- throw new Error(`Middleware ${name} is not registered.`);
435
- return middleware;
436
- }
437
- /**
438
- * Run application.
439
- * @param contextData Run context data.
440
- * @param element HTMLElement of application. Default is document.body.
441
- * @returns Promise of runned result.
442
- */
443
- async run(contextData, element) {
444
- if (this.__abort.signal.aborted)
445
- throw new Error('Application is destroyed.');
446
- if (this.__isRuned)
447
- throw new Error('Application already run.');
448
- this.__isRuned = true;
449
- if (!contextData)
450
- contextData = {};
451
- element = element || document.body;
452
- this.setElement(element);
453
- const context = {
454
- abort: this.__abort.signal,
455
- app: this,
456
- data: contextData
457
- };
458
- try {
459
- await this.onStarting();
460
- await this.invoker.invoke("start", context);
461
- console.info("app start success");
462
- this.__abort.signal.throwIfAborted();
463
- await this.invoker.invoke("loaded", context);
464
- console.info("app load success");
465
- this.__abort.signal.throwIfAborted();
466
- window.addEventListener("popstate", (e) => this.__onPopState(context, e));
467
- element.addEventListener("submit", this.__globalSubmit = (e) => {
468
- const form = e.target;
469
- if (!form.classList.contains(result.FormClassName))
470
- return;
471
- e.preventDefault();
472
- this.__onSubmit({ form, button: e.submitter instanceof HTMLButtonElement ? e.submitter : null })
473
- .catch(() => { });
474
- }, false);
475
- await this.onStared();
476
- console.info("app runned");
477
- }
478
- catch (reason) {
479
- console.error(`app run error: ${reason}`);
480
- throw reason;
481
- }
482
- try {
483
- await this.nav({ data: context.data, abort: this.__abort.signal });
484
- }
485
- catch (reason) {
486
- if (reason === NAV_OVERIDE_ERROR) {
487
- console.info(`app run nav overided`);
488
- return context;
489
- }
490
- throw reason;
491
- }
492
- return context;
493
- }
494
- /**
495
- * Navigate application to url.
496
- * @param options Navigate options.
497
- * @returns Promise of navigated result.
498
- */
499
- async nav(options) {
500
- const opt = (!options || typeof options === "string") ? { url: options } : options;
501
- let { url = null, query, replace = false, scope = null, data = {}, abort } = opt;
502
- const navUrl = urlHelper.parseUrl(this.env.basePath, url);
503
- if (query)
504
- urlHelper.extendQuery(navUrl, query);
505
- let isFirst = !this.__lastNav && !this.__execNav;
506
- let action;
507
- if (isFirst)
508
- action = "first";
509
- else {
510
- const isChangedUrl = this.__lastNav?.context.url.toLowerCase() !== navUrl.url.toLowerCase();
511
- const hasHash = !!this.__lastNav?.context.hash || !!navUrl.hash;
512
- if (isChangedUrl)
513
- action = "url-change"; // если изменился url
514
- else
515
- action = hasHash ? "hash" : "url-no-change";
516
- }
517
- const base = this.__beginNav(abort);
518
- const context = {
519
- ...this.__createContext(base, navUrl, isFirst ? "first" : "nav", action, data, replace),
520
- scope
521
- };
522
- const currentNav = { method: "navigate", context, abort: base.navAbort, status: "work" };
523
- return await this.__execNavigate(currentNav, base.parentNav);
524
- }
525
- /**
526
- * Reload page with nav.
527
- */
528
- reload() {
529
- this.__abort.signal.throwIfAborted();
530
- return this.nav({ replace: true });
531
- }
532
- /**
533
- * Global reload page in browser.
534
- */
535
- restart() {
536
- this.__abort.signal.throwIfAborted();
537
- window.location.reload();
538
- }
539
- async destroy(contextData) {
540
- if (this.__abort.signal.aborted)
541
- return Promise.reject('Application already destroyed.');
542
- this.__abort.abort();
543
- console.info("app destroy begin");
544
- if (this.__execNav)
545
- this.__execNav.abort.abort();
546
- if (this.__lastNav)
547
- this.__lastNav.abort.abort();
548
- if (this.__globalSubmit)
549
- this.element?.removeEventListener("submit", this.__globalSubmit);
550
- const destroyAbort = new AbortController();
551
- const context = {
552
- abort: destroyAbort.signal,
553
- app: this,
554
- data: contextData || {}
555
- };
556
- try {
557
- await this.invoker.invoke("stop", context);
558
- console.info("app destroy success");
559
- return context;
560
- }
561
- catch (reason) {
562
- console.error(`app destroy error: ${reason}`);
563
- throw reason;
564
- }
565
- finally {
566
- super.destroy();
567
- }
568
- }
569
- /**
570
- * Generate url of application base url.
571
- * @param path Add optional path of base url.
572
- * @param query Add optional query params.
573
- * @param hash Add optional hash.
574
- * @returns Relative url with base path.
575
- */
576
- buildUrl(path, query, hash) {
577
- this.__abort.signal.throwIfAborted();
578
- return urlHelper.buildUrl(this.env.basePath, path, query, hash);
579
- }
580
- async __onSubmit(options) {
581
- const opt = options instanceof HTMLFormElement ? { form: options } : options;
582
- const { form, button = null, query, data = {} } = opt;
583
- if ((!button || !button.formNoValidate) && !form.checkValidity())
584
- throw new Error('Form is invalid.');
585
- let replace = form.hasAttribute(result.NavUrlReplaceAttributeName);
586
- let method = form.method;
587
- let enctype = form.enctype;
588
- let url = form.action;
589
- if (button) {
590
- if (button.hasAttribute("formmethod"))
591
- method = button.formMethod;
592
- if (button.hasAttribute("formenctype"))
593
- enctype = button.formEnctype;
594
- if (button.hasAttribute("formaction"))
595
- url = button.formAction;
596
- button.classList.add(result.LoadingElementClass);
597
- if (button.hasAttribute(result.NavUrlReplaceAttributeName))
598
- replace = true;
599
- }
600
- if (form.classList.contains(result.LoadingElementClass))
601
- throw new Error('Form already submitting.');
602
- form.classList.add(result.LoadingElementClass);
603
- method = method.toUpperCase();
604
- try {
605
- if (method === "GET")
606
- await this.nav({ url, query: new FormData(form), data: data, replace, abort: opt.abort });
607
- else {
608
- const navUrl = urlHelper.parseUrl(this.env.basePath, url);
609
- if (query)
610
- urlHelper.extendQuery(navUrl, query);
611
- const base = this.__beginNav(opt.abort);
612
- const context = {
613
- ...this.__createContext(base, navUrl, "submit", "submit", data, replace),
614
- form,
615
- button,
616
- method,
617
- enctype
618
- };
619
- const currentNav = { method: "submit", context, abort: base.navAbort, status: "work" };
620
- await this.__execNavigate(currentNav);
621
- }
622
- }
623
- finally {
624
- form.classList.remove(result.LoadingElementClass);
625
- if (button)
626
- button.classList.remove(result.LoadingElementClass);
627
- }
628
- }
629
- __onPopState(_context, event) {
630
- const popUrl = location.href;
631
- console.log(`popstate: ${popUrl}`, event.state);
632
- this.nav({ url: popUrl, data: { popstate: event.state } });
633
- }
634
- /** Detect parent (overriding) navigation and compose the abort signal shared by a new navigation. */
635
- __beginNav(abort) {
636
- let parentNav;
637
- if (this.__execNav && this.__execNav.status === "work") {
638
- parentNav = this.__execNav;
639
- parentNav.abort.abort(NAV_OVERIDE_ERROR);
640
- parentNav.context.overided = true;
641
- }
642
- const navAbort = new AbortController();
643
- const aborts = [this.__abort.signal, navAbort.signal];
644
- if (abort)
645
- aborts.push(abort);
646
- return { parentNav, navAbort, abort: AbortSignal.any(aborts) };
647
- }
648
- /** Build the navigation context fields shared by nav and submit. */
649
- __createContext(base, navUrl, source, action, data, replace) {
650
- const { parentNav, abort } = base;
651
- return {
652
- index: parentNav ? parentNav.context.index + 1 : 1,
653
- id: Guid.createGuid(),
654
- source,
655
- app: this,
656
- abort,
657
- current: this.__lastNav?.context,
658
- parent: parentNav?.context,
659
- overided: false,
660
- action,
661
- data,
662
- url: navUrl.url,
663
- origin: navUrl.origin,
664
- pathAndQuery: navUrl.relative,
665
- basePath: navUrl.basePath,
666
- path: navUrl.path,
667
- query: navUrl.query,
668
- hash: navUrl.hash,
669
- external: navUrl.external,
670
- replace,
671
- redirect: async (options) => {
672
- abort.throwIfAborted();
673
- const result = await this.nav(options);
674
- abort.throwIfAborted();
675
- return result;
676
- }
677
- };
678
- }
679
- async __execNavigate(nav, parent) {
680
- if (parent)
681
- parent.overide = nav;
682
- try {
683
- console.info(`${nav.method} begin`, nav.context);
684
- nav.context.abort.throwIfAborted();
685
- this.__execNav = nav;
686
- await this.invoker.invoke(nav.method, nav.context);
687
- this.__lastNav = nav;
688
- nav.status = "success";
689
- console.info(`${nav.method} ${nav.status} ${nav.context.url}`);
690
- return nav.context;
691
- }
692
- catch (reason) {
693
- if (reason?.name === "AbortError") {
694
- nav.status = "cancelled";
695
- console.warn(`${nav.method} ${nav.status} ${nav.context.url}`);
696
- }
697
- else if (reason === NAV_OVERIDE_ERROR) {
698
- if (!nav.context.overided || !nav.overide)
699
- throw new Error("Nav is not overided.");
700
- nav.status = "overided";
701
- console.warn(`${nav.method} ${nav.status} ${nav.context.url}`);
702
- return nav.overide.context; // return redirected navigation
703
- }
704
- else {
705
- nav.status = "error";
706
- console.error(`${nav.method} ${nav.status} ${nav.context.url}: ${reason}`);
707
- }
708
- throw reason;
709
- }
710
- }
711
- }
712
-
713
- class ApplicationBuilder {
714
- __model;
715
- __appType = (Application);
716
- __middlewares = [];
717
- constructor(model) {
718
- this.__model = model;
719
- }
720
- useApp(appType) {
721
- this.__appType = appType;
722
- return this;
723
- }
724
- useMiddleware(createFunc, ...params) {
725
- let midl = createFunc(...params);
726
- this.__middlewares.push(midl);
727
- return this;
728
- }
729
- build(env, ...args) {
730
- if (!env.basePath || env.basePath == '/')
731
- env.basePath = '';
732
- const app = new this.__appType(env, this.__model, ...args);
733
- app.initialize(this.__middlewares);
734
- return app;
735
- }
736
- }
737
-
738
- HTMLElement.prototype.navUrl = function (url) {
739
- if (this instanceof HTMLAnchorElement)
740
- this.href = url;
741
- else
742
- this.dataset.navUrl = url;
743
- this.classList.add(result.NavUrlClassName);
744
- return this;
745
- };
746
- HTMLElement.prototype.nav = function (app, path, query, hash) {
747
- const url = app.buildUrl(path, query, hash);
748
- return this.navUrl(url);
749
- };
750
- HTMLElement.prototype.navReplace = function () {
751
- this.setAttribute(result.NavUrlReplaceAttributeName, "");
752
- return this;
753
- };
754
- HTMLElement.prototype.navScope = function (scope) {
755
- this.setAttribute(result.NavUrlScopeAttributeName, scope);
756
- return this;
757
- };
758
-
759
- export { APP_TYPENAME, Application, ApplicationBuilder, constants as CONSTANTS, NAV_OVERIDE_ERROR, url as UrlHelper };
1
+ export { ApplicationBuilder } from './builder.js';
2
+ export { APP_TYPENAME, Application, NAV_OVERIDE_ERROR } from './app.js';
3
+ export { enableNavExtensions } from './ext.js';
4
+ import * as url from './helpers/url.js';
5
+ export { url as UrlHelper };
6
+ import * as constants from './constants.js';
7
+ export { constants as CONSTANTS };
760
8
  //# sourceMappingURL=index.js.map