uicore-ts 1.1.362 → 1.1.363

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.
@@ -8,7 +8,15 @@ export interface UIRouteComponent<T = any> {
8
8
  name: string;
9
9
  parameters: UIRouteParameters<T>;
10
10
  }
11
+ export interface UIRouteChangeDescriptor {
12
+ currentRoute: UIRoute;
13
+ targetRoute: UIRoute;
14
+ forcefully: boolean;
15
+ replacesCurrentRouteInHistory: boolean;
16
+ }
17
+ export type UIRouteShouldApplyRouteChangeCallbackFunction = (routeChangeDescriptor: UIRouteChangeDescriptor) => boolean | Promise<boolean>;
11
18
  export declare class UIRoute extends Array<UIRouteComponent> {
19
+ static ShouldApplyRouteChange?: UIRouteShouldApplyRouteChangeCallbackFunction;
12
20
  constructor(hash?: string);
13
21
  static get currentRoute(): UIRoute;
14
22
  /**
@@ -19,13 +27,29 @@ export declare class UIRoute extends Array<UIRouteComponent> {
19
27
  * "tap the already-active tab to reset to root" feature in TopBarView).
20
28
  * Defaults to `false`.
21
29
  */
22
- apply(forcefully?: boolean): void;
30
+ apply(forcefully?: boolean): boolean | Promise<boolean>;
31
+ /**
32
+ * Applies this route without consulting `UIRoute.routeApplicationShouldProceed`.
33
+ * Use this only for route changes that are internal bookkeeping or that already
34
+ * passed a higher-level confirmation flow.
35
+ */
36
+ applyWithoutRouteApplicationCheck(forcefully?: boolean): boolean;
23
37
  /**
24
38
  * @param forcefully When `true`, replaces the current history entry with
25
39
  * this route even when the route is identical to the current URL hash.
26
40
  * Defaults to `false`.
27
41
  */
28
- applyByReplacingCurrentRouteInHistory(forcefully?: boolean): void;
42
+ applyByReplacingCurrentRouteInHistory(forcefully?: boolean): boolean | Promise<boolean>;
43
+ /**
44
+ * Replaces the current history entry without consulting
45
+ * `UIRoute.routeApplicationShouldProceed`.
46
+ */
47
+ applyByReplacingCurrentRouteInHistoryWithoutRouteApplicationCheck(forcefully?: boolean): boolean;
48
+ _applyRouteAfterRouteApplicationCheck(forcefully: boolean, replacesCurrentRouteInHistory: boolean): boolean | Promise<boolean>;
49
+ _applyRouteIfAllowed(routeApplicationShouldProceed: boolean, forcefully: boolean, replacesCurrentRouteInHistory: boolean): boolean;
50
+ _applyRouteWithoutRouteApplicationCheck(forcefully: boolean, replacesCurrentRouteInHistory: boolean): boolean;
51
+ _needsRouteApplication(forcefully: boolean): boolean;
52
+ _routeApplication(forcefully: boolean, replacesCurrentRouteInHistory: boolean): UIRouteChangeDescriptor;
29
53
  copy(): UIRoute;
30
54
  routeByRemovingComponentsOtherThanOnesNamed(componentNames: string[]): UIRoute;
31
55
  routeByRemovingComponentNamed(componentName: string): UIRoute;
@@ -35,7 +59,7 @@ export declare class UIRoute extends Array<UIRouteComponent> {
35
59
  [P in keyof T["ParameterIdentifierName"]]: string;
36
60
  }>, extendParameters?: boolean): UIRoute;
37
61
  routeWithComponent(name: string, parameters: UIRouteParameters, extendParameters?: boolean): UIRoute;
38
- navigateBySettingComponent(name: string, parameters: UIRouteParameters, extendParameters?: boolean): void;
62
+ navigateBySettingComponent(name: string, parameters: UIRouteParameters, extendParameters?: boolean): boolean | Promise<boolean>;
39
63
  componentWithViewController<T extends typeof UIViewController>(viewController: T): UIRouteComponent<{
40
64
  [P in ValueOf<T["ParameterIdentifierName"]>]: string;
41
65
  }> | undefined;
@@ -59,18 +59,69 @@ class UIRoute extends Array {
59
59
  return new UIRoute(window.location.hash);
60
60
  }
61
61
  apply(forcefully = import_UIObject.NO) {
62
- const stringRepresentation = this.stringRepresentation;
63
- if (!forcefully && new UIRoute(window.location.hash).stringRepresentation == stringRepresentation) {
64
- return;
65
- }
66
- window.location.hash = stringRepresentation;
62
+ return this._applyRouteAfterRouteApplicationCheck(forcefully, import_UIObject.NO);
63
+ }
64
+ applyWithoutRouteApplicationCheck(forcefully = import_UIObject.NO) {
65
+ return this._applyRouteWithoutRouteApplicationCheck(forcefully, import_UIObject.NO);
67
66
  }
68
67
  applyByReplacingCurrentRouteInHistory(forcefully = import_UIObject.NO) {
69
- const stringRepresentation = this.stringRepresentation;
70
- if (!forcefully && new UIRoute(window.location.hash).stringRepresentation == stringRepresentation) {
71
- return;
68
+ return this._applyRouteAfterRouteApplicationCheck(forcefully, import_UIObject.YES);
69
+ }
70
+ applyByReplacingCurrentRouteInHistoryWithoutRouteApplicationCheck(forcefully = import_UIObject.NO) {
71
+ return this._applyRouteWithoutRouteApplicationCheck(forcefully, import_UIObject.YES);
72
+ }
73
+ _applyRouteAfterRouteApplicationCheck(forcefully, replacesCurrentRouteInHistory) {
74
+ if (!this._needsRouteApplication(forcefully)) {
75
+ return import_UIObject.NO;
76
+ }
77
+ const routeApplicationShouldProceed = UIRoute.ShouldApplyRouteChange;
78
+ if (!routeApplicationShouldProceed) {
79
+ return this._applyRouteWithoutRouteApplicationCheck(forcefully, replacesCurrentRouteInHistory);
80
+ }
81
+ const shouldProceed = routeApplicationShouldProceed(
82
+ this._routeApplication(forcefully, replacesCurrentRouteInHistory)
83
+ );
84
+ if (shouldProceed instanceof Promise) {
85
+ return shouldProceed.then((routeApplicationShouldProceed2) => {
86
+ return this._applyRouteIfAllowed(
87
+ routeApplicationShouldProceed2,
88
+ forcefully,
89
+ replacesCurrentRouteInHistory
90
+ );
91
+ });
72
92
  }
73
- window.location.replace(this.linkRepresentation);
93
+ return this._applyRouteIfAllowed(shouldProceed, forcefully, replacesCurrentRouteInHistory);
94
+ }
95
+ _applyRouteIfAllowed(routeApplicationShouldProceed, forcefully, replacesCurrentRouteInHistory) {
96
+ if (!routeApplicationShouldProceed) {
97
+ return import_UIObject.NO;
98
+ }
99
+ return this._applyRouteWithoutRouteApplicationCheck(forcefully, replacesCurrentRouteInHistory);
100
+ }
101
+ _applyRouteWithoutRouteApplicationCheck(forcefully, replacesCurrentRouteInHistory) {
102
+ if (!this._needsRouteApplication(forcefully)) {
103
+ return import_UIObject.NO;
104
+ }
105
+ if (replacesCurrentRouteInHistory) {
106
+ window.location.replace(this.linkRepresentation);
107
+ } else {
108
+ window.location.hash = this.stringRepresentation;
109
+ }
110
+ return import_UIObject.YES;
111
+ }
112
+ _needsRouteApplication(forcefully) {
113
+ if (!forcefully && new UIRoute(window.location.hash).stringRepresentation == this.stringRepresentation) {
114
+ return import_UIObject.NO;
115
+ }
116
+ return import_UIObject.YES;
117
+ }
118
+ _routeApplication(forcefully, replacesCurrentRouteInHistory) {
119
+ return {
120
+ currentRoute: UIRoute.currentRoute,
121
+ targetRoute: this.copy(),
122
+ forcefully,
123
+ replacesCurrentRouteInHistory
124
+ };
74
125
  }
75
126
  copy() {
76
127
  const result = new UIRoute(this.stringRepresentation);
@@ -148,7 +199,7 @@ class UIRoute extends Array {
148
199
  return result;
149
200
  }
150
201
  navigateBySettingComponent(name, parameters, extendParameters = import_UIObject.NO) {
151
- this.routeWithComponent(name, parameters, extendParameters).apply();
202
+ return this.routeWithComponent(name, parameters, extendParameters).apply();
152
203
  }
153
204
  componentWithViewController(viewController) {
154
205
  return this.componentWithName(viewController.routeComponentName);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../scripts/UIRoute.ts"],
4
- "sourcesContent": ["import { IS_NIL, IS_NOT, NO, ValueOf } from \"./UIObject\"\nimport { UIViewController } from \"./UIViewController\"\n\n\nexport type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];\n\nexport type UIRouteParameters<T = any> = {\n \n [key: string]: string;\n \n} | T;\n\n\nexport interface UIRouteComponent<T = any> {\n \n name: string;\n parameters: UIRouteParameters<T>;\n \n}\n\n\nexport class UIRoute extends Array<UIRouteComponent> {\n \n constructor(hash?: string) {\n \n super()\n \n if (!hash || !hash.startsWith) {\n \n return\n \n }\n \n if (hash.startsWith(\"#\")) {\n hash = hash.slice(1)\n }\n \n hash = decodeURIComponent(hash)\n \n const components = hash.split(\"]\")\n components.forEach(component => {\n \n const componentName = component.split(\"[\")[0]\n const parameters: Record<string, string> = {}\n \n if (!componentName) {\n return\n }\n \n const parametersString = component.split(\"[\")[1] || \"\"\n const parameterPairStrings = parametersString.split(\",\") || []\n \n parameterPairStrings.forEach(pairString => {\n \n const keyAndValueArray = pairString.split(\":\")\n const key = decodeURIComponent(keyAndValueArray[0])\n const value = decodeURIComponent(keyAndValueArray[1])\n \n if (key) {\n parameters[key] = value\n }\n \n })\n \n \n this.push({\n name: componentName,\n parameters: parameters\n })\n \n })\n \n \n }\n \n \n static get currentRoute() {\n \n return new UIRoute(window.location.hash)\n \n }\n \n \n /**\n * @param forcefully When `true`, applies the route even if its string\n * representation is identical to the current URL hash, causing the browser\n * to fire a `hashchange` event and re-run the full `handleRoute` flow.\n * Use this only when you explicitly need re-entrant navigation (e.g. the\n * \"tap the already-active tab to reset to root\" feature in TopBarView).\n * Defaults to `false`.\n */\n apply(forcefully = NO) {\n \n const stringRepresentation = this.stringRepresentation\n if (!forcefully && new UIRoute(window.location.hash).stringRepresentation == stringRepresentation) {\n return\n }\n \n window.location.hash = stringRepresentation\n \n }\n \n \n /**\n * @param forcefully When `true`, replaces the current history entry with\n * this route even when the route is identical to the current URL hash.\n * Defaults to `false`.\n */\n applyByReplacingCurrentRouteInHistory(forcefully = NO) {\n \n const stringRepresentation = this.stringRepresentation\n if (!forcefully && new UIRoute(window.location.hash).stringRepresentation == stringRepresentation) {\n return\n }\n \n window.location.replace(this.linkRepresentation)\n \n }\n \n \n override copy() {\n const result = new UIRoute(this.stringRepresentation)\n return result\n }\n \n \n routeByRemovingComponentsOtherThanOnesNamed(componentNames: string[]) {\n const result = this.copy()\n const indexesToRemove: number[] = []\n result.forEach(function (component, index, array) {\n if (!componentNames.contains(component.name)) {\n indexesToRemove.push(index)\n }\n })\n indexesToRemove.forEach(function (indexToRemove, index, array) {\n result.removeElementAtIndex(indexToRemove)\n })\n return result\n }\n \n \n routeByRemovingComponentNamed(componentName: string) {\n const result = this.copy()\n const componentIndex = result.findIndex(function (component, index) {\n return (component.name == componentName)\n })\n if (componentIndex != -1) {\n result.splice(componentIndex, 1)\n }\n return result\n }\n \n \n routeByRemovingParameterInComponent(componentName: string, parameterName: string, removeComponentIfEmpty = NO) {\n let result = this.copy()\n let parameters = result.componentWithName(componentName)?.parameters ?? {}\n delete parameters[parameterName]\n result = result.routeWithComponent(componentName, parameters)\n if (removeComponentIfEmpty && Object.keys(parameters).length == 0) {\n result = result.routeByRemovingComponentNamed(componentName)\n }\n return result\n }\n \n routeBySettingParameterInComponent(componentName: string, parameterName: string, valueToSet: string) {\n let result = this.copy()\n if (IS_NIL(valueToSet) || IS_NIL(parameterName)) {\n return result\n }\n let parameters = result.componentWithName(componentName)?.parameters\n if (IS_NOT(parameters)) {\n parameters = {}\n }\n parameters[parameterName] = valueToSet\n result = result.routeWithComponent(componentName, parameters)\n return result\n }\n \n \n routeWithViewControllerComponent<T extends typeof UIViewController>(\n viewController: T,\n parameters: UIRouteParameters<{ [P in keyof T[\"ParameterIdentifierName\"]]: string }>,\n extendParameters: boolean = NO\n ) {\n \n return this.routeWithComponent(viewController.routeComponentName, parameters, extendParameters)\n \n }\n \n routeWithComponent(name: string, parameters: UIRouteParameters, extendParameters: boolean = NO) {\n \n const result = this.copy()\n let component = result.componentWithName(name)\n if (IS_NOT(component)) {\n component = {\n name: name,\n parameters: {}\n }\n result.push(component)\n }\n \n if (IS_NOT(parameters)) {\n \n parameters = {}\n \n }\n \n if (extendParameters) {\n component.parameters = Object.assign(component.parameters, parameters)\n }\n else {\n component.parameters = parameters\n }\n \n return result\n \n }\n \n navigateBySettingComponent(name: string, parameters: UIRouteParameters, extendParameters: boolean = NO) {\n \n this.routeWithComponent(name, parameters, extendParameters).apply()\n \n }\n \n \n componentWithViewController<T extends typeof UIViewController>(viewController: T): UIRouteComponent<{ [P in ValueOf<T[\"ParameterIdentifierName\"]>]: string }> | undefined {\n \n return this.componentWithName(viewController.routeComponentName)\n \n }\n \n componentWithName(name: string): UIRouteComponent | undefined {\n let result\n this.forEach(function (component, index, self) {\n if (component.name == name) {\n result = component\n }\n })\n return result\n }\n \n \n get linkRepresentation() {\n return \"#\" + this.stringRepresentation\n }\n \n \n get stringRepresentation() {\n \n let result = \"\"\n this.forEach(function (component, index, self) {\n result = result + component.name\n const parameters = component.parameters\n result = result + \"[\"\n Object.keys(parameters).forEach(function (key, index, keys) {\n if (index) {\n result = result + \",\"\n }\n result = result + encodeURIComponent(key) + \":\" + encodeURIComponent(parameters[key])\n })\n result = result + \"]\"\n })\n \n return result\n \n }\n \n \n}\n"],
5
- "mappings": "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",
6
- "names": ["index"]
4
+ "sourcesContent": ["import { IS_NIL, IS_NOT, NO, ValueOf, YES } from \"./UIObject\"\nimport { UIViewController } from \"./UIViewController\"\n\n\nexport type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];\n\nexport type UIRouteParameters<T = any> = {\n \n [key: string]: string;\n \n} | T;\n\n\nexport interface UIRouteComponent<T = any> {\n \n name: string;\n parameters: UIRouteParameters<T>;\n \n}\n\n\nexport interface UIRouteChangeDescriptor {\n \n currentRoute: UIRoute;\n targetRoute: UIRoute;\n forcefully: boolean;\n replacesCurrentRouteInHistory: boolean;\n \n}\n\n\nexport type UIRouteShouldApplyRouteChangeCallbackFunction = (\n routeChangeDescriptor: UIRouteChangeDescriptor\n) => boolean | Promise<boolean>;\n\n\nexport class UIRoute extends Array<UIRouteComponent> {\n \n static ShouldApplyRouteChange?: UIRouteShouldApplyRouteChangeCallbackFunction\n \n constructor(hash?: string) {\n \n super()\n \n if (!hash || !hash.startsWith) {\n \n return\n \n }\n \n if (hash.startsWith(\"#\")) {\n hash = hash.slice(1)\n }\n \n hash = decodeURIComponent(hash)\n \n const components = hash.split(\"]\")\n components.forEach(component => {\n \n const componentName = component.split(\"[\")[0]\n const parameters: Record<string, string> = {}\n \n if (!componentName) {\n return\n }\n \n const parametersString = component.split(\"[\")[1] || \"\"\n const parameterPairStrings = parametersString.split(\",\") || []\n \n parameterPairStrings.forEach(pairString => {\n \n const keyAndValueArray = pairString.split(\":\")\n const key = decodeURIComponent(keyAndValueArray[0])\n const value = decodeURIComponent(keyAndValueArray[1])\n \n if (key) {\n parameters[key] = value\n }\n \n })\n \n \n this.push({\n name: componentName,\n parameters: parameters\n })\n \n })\n \n \n }\n \n \n static get currentRoute() {\n \n return new UIRoute(window.location.hash)\n \n }\n \n \n /**\n * @param forcefully When `true`, applies the route even if its string\n * representation is identical to the current URL hash, causing the browser\n * to fire a `hashchange` event and re-run the full `handleRoute` flow.\n * Use this only when you explicitly need re-entrant navigation (e.g. the\n * \"tap the already-active tab to reset to root\" feature in TopBarView).\n * Defaults to `false`.\n */\n apply(forcefully = NO): boolean | Promise<boolean> {\n \n return this._applyRouteAfterRouteApplicationCheck(forcefully, NO)\n \n }\n \n \n /**\n * Applies this route without consulting `UIRoute.routeApplicationShouldProceed`.\n * Use this only for route changes that are internal bookkeeping or that already\n * passed a higher-level confirmation flow.\n */\n applyWithoutRouteApplicationCheck(forcefully = NO): boolean {\n \n return this._applyRouteWithoutRouteApplicationCheck(forcefully, NO)\n \n }\n \n \n /**\n * @param forcefully When `true`, replaces the current history entry with\n * this route even when the route is identical to the current URL hash.\n * Defaults to `false`.\n */\n applyByReplacingCurrentRouteInHistory(forcefully = NO): boolean | Promise<boolean> {\n \n return this._applyRouteAfterRouteApplicationCheck(forcefully, YES)\n \n }\n \n \n /**\n * Replaces the current history entry without consulting\n * `UIRoute.routeApplicationShouldProceed`.\n */\n applyByReplacingCurrentRouteInHistoryWithoutRouteApplicationCheck(forcefully = NO): boolean {\n \n return this._applyRouteWithoutRouteApplicationCheck(forcefully, YES)\n \n }\n \n \n _applyRouteAfterRouteApplicationCheck(\n forcefully: boolean,\n replacesCurrentRouteInHistory: boolean\n ): boolean | Promise<boolean> {\n \n if (!this._needsRouteApplication(forcefully)) {\n return NO\n }\n \n const routeApplicationShouldProceed = UIRoute.ShouldApplyRouteChange\n if (!routeApplicationShouldProceed) {\n return this._applyRouteWithoutRouteApplicationCheck(forcefully, replacesCurrentRouteInHistory)\n }\n \n const shouldProceed = routeApplicationShouldProceed(\n this._routeApplication(forcefully, replacesCurrentRouteInHistory)\n )\n \n if (shouldProceed instanceof Promise) {\n return shouldProceed.then(routeApplicationShouldProceed => {\n return this._applyRouteIfAllowed(\n routeApplicationShouldProceed,\n forcefully,\n replacesCurrentRouteInHistory\n )\n })\n }\n \n return this._applyRouteIfAllowed(shouldProceed, forcefully, replacesCurrentRouteInHistory)\n \n }\n \n \n _applyRouteIfAllowed(\n routeApplicationShouldProceed: boolean,\n forcefully: boolean,\n replacesCurrentRouteInHistory: boolean\n ): boolean {\n \n if (!routeApplicationShouldProceed) {\n return NO\n }\n \n return this._applyRouteWithoutRouteApplicationCheck(forcefully, replacesCurrentRouteInHistory)\n \n }\n \n \n _applyRouteWithoutRouteApplicationCheck(\n forcefully: boolean,\n replacesCurrentRouteInHistory: boolean\n ): boolean {\n \n if (!this._needsRouteApplication(forcefully)) {\n return NO\n }\n \n if (replacesCurrentRouteInHistory) {\n window.location.replace(this.linkRepresentation)\n }\n else {\n window.location.hash = this.stringRepresentation\n }\n \n return YES\n \n }\n \n \n _needsRouteApplication(forcefully: boolean): boolean {\n \n if (!forcefully && new UIRoute(window.location.hash).stringRepresentation == this.stringRepresentation) {\n return NO\n }\n \n return YES\n \n }\n \n \n _routeApplication(forcefully: boolean, replacesCurrentRouteInHistory: boolean): UIRouteChangeDescriptor {\n \n return {\n currentRoute: UIRoute.currentRoute,\n targetRoute: this.copy(),\n forcefully: forcefully,\n replacesCurrentRouteInHistory: replacesCurrentRouteInHistory\n }\n \n }\n \n \n override copy() {\n const result = new UIRoute(this.stringRepresentation)\n return result\n }\n \n \n routeByRemovingComponentsOtherThanOnesNamed(componentNames: string[]) {\n const result = this.copy()\n const indexesToRemove: number[] = []\n result.forEach(function (component, index, array) {\n if (!componentNames.contains(component.name)) {\n indexesToRemove.push(index)\n }\n })\n indexesToRemove.forEach(function (indexToRemove, index, array) {\n result.removeElementAtIndex(indexToRemove)\n })\n return result\n }\n \n \n routeByRemovingComponentNamed(componentName: string) {\n const result = this.copy()\n const componentIndex = result.findIndex(function (component, index) {\n return (component.name == componentName)\n })\n if (componentIndex != -1) {\n result.splice(componentIndex, 1)\n }\n return result\n }\n \n \n routeByRemovingParameterInComponent(componentName: string, parameterName: string, removeComponentIfEmpty = NO) {\n let result = this.copy()\n let parameters = result.componentWithName(componentName)?.parameters ?? {}\n delete parameters[parameterName]\n result = result.routeWithComponent(componentName, parameters)\n if (removeComponentIfEmpty && Object.keys(parameters).length == 0) {\n result = result.routeByRemovingComponentNamed(componentName)\n }\n return result\n }\n \n routeBySettingParameterInComponent(componentName: string, parameterName: string, valueToSet: string) {\n let result = this.copy()\n if (IS_NIL(valueToSet) || IS_NIL(parameterName)) {\n return result\n }\n let parameters = result.componentWithName(componentName)?.parameters\n if (IS_NOT(parameters)) {\n parameters = {}\n }\n parameters[parameterName] = valueToSet\n result = result.routeWithComponent(componentName, parameters)\n return result\n }\n \n \n routeWithViewControllerComponent<T extends typeof UIViewController>(\n viewController: T,\n parameters: UIRouteParameters<{ [P in keyof T[\"ParameterIdentifierName\"]]: string }>,\n extendParameters: boolean = NO\n ) {\n \n return this.routeWithComponent(viewController.routeComponentName, parameters, extendParameters)\n \n }\n \n routeWithComponent(name: string, parameters: UIRouteParameters, extendParameters: boolean = NO) {\n \n const result = this.copy()\n let component = result.componentWithName(name)\n if (IS_NOT(component)) {\n component = {\n name: name,\n parameters: {}\n }\n result.push(component)\n }\n \n if (IS_NOT(parameters)) {\n \n parameters = {}\n \n }\n \n if (extendParameters) {\n component.parameters = Object.assign(component.parameters, parameters)\n }\n else {\n component.parameters = parameters\n }\n \n return result\n \n }\n \n navigateBySettingComponent(name: string, parameters: UIRouteParameters, extendParameters: boolean = NO) {\n \n return this.routeWithComponent(name, parameters, extendParameters).apply()\n \n }\n \n \n componentWithViewController<T extends typeof UIViewController>(viewController: T): UIRouteComponent<{ [P in ValueOf<T[\"ParameterIdentifierName\"]>]: string }> | undefined {\n \n return this.componentWithName(viewController.routeComponentName)\n \n }\n \n componentWithName(name: string): UIRouteComponent | undefined {\n let result\n this.forEach(function (component, index, self) {\n if (component.name == name) {\n result = component\n }\n })\n return result\n }\n \n \n get linkRepresentation() {\n return \"#\" + this.stringRepresentation\n }\n \n \n get stringRepresentation() {\n \n let result = \"\"\n this.forEach(function (component, index, self) {\n result = result + component.name\n const parameters = component.parameters\n result = result + \"[\"\n Object.keys(parameters).forEach(function (key, index, keys) {\n if (index) {\n result = result + \",\"\n }\n result = result + encodeURIComponent(key) + \":\" + encodeURIComponent(parameters[key])\n })\n result = result + \"]\"\n })\n \n return result\n \n }\n \n \n}\n"],
5
+ "mappings": "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",
6
+ "names": ["routeApplicationShouldProceed", "index"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uicore-ts",
3
- "version": "1.1.362",
3
+ "version": "1.1.363",
4
4
  "description": "UICore is a library to build native-like user interfaces using pure Typescript. No HTML is needed at all. Components are described as TS classes and all user interactions are handled explicitly. This library is strongly inspired by the UIKit framework that is used in IOS. In addition, UICore has tools to handle URL based routing, array sorting and filtering and adds a number of other utilities for convenience.",
5
5
  "main": "compiledScripts/index.js",
6
6
  "types": "compiledScripts/index.d.ts",
@@ -1,4 +1,4 @@
1
- import { IS_NIL, IS_NOT, NO, ValueOf } from "./UIObject"
1
+ import { IS_NIL, IS_NOT, NO, ValueOf, YES } from "./UIObject"
2
2
  import { UIViewController } from "./UIViewController"
3
3
 
4
4
 
@@ -19,8 +19,25 @@ export interface UIRouteComponent<T = any> {
19
19
  }
20
20
 
21
21
 
22
+ export interface UIRouteChangeDescriptor {
23
+
24
+ currentRoute: UIRoute;
25
+ targetRoute: UIRoute;
26
+ forcefully: boolean;
27
+ replacesCurrentRouteInHistory: boolean;
28
+
29
+ }
30
+
31
+
32
+ export type UIRouteShouldApplyRouteChangeCallbackFunction = (
33
+ routeChangeDescriptor: UIRouteChangeDescriptor
34
+ ) => boolean | Promise<boolean>;
35
+
36
+
22
37
  export class UIRoute extends Array<UIRouteComponent> {
23
38
 
39
+ static ShouldApplyRouteChange?: UIRouteShouldApplyRouteChangeCallbackFunction
40
+
24
41
  constructor(hash?: string) {
25
42
 
26
43
  super()
@@ -89,14 +106,21 @@ export class UIRoute extends Array<UIRouteComponent> {
89
106
  * "tap the already-active tab to reset to root" feature in TopBarView).
90
107
  * Defaults to `false`.
91
108
  */
92
- apply(forcefully = NO) {
109
+ apply(forcefully = NO): boolean | Promise<boolean> {
93
110
 
94
- const stringRepresentation = this.stringRepresentation
95
- if (!forcefully && new UIRoute(window.location.hash).stringRepresentation == stringRepresentation) {
96
- return
97
- }
111
+ return this._applyRouteAfterRouteApplicationCheck(forcefully, NO)
112
+
113
+ }
114
+
115
+
116
+ /**
117
+ * Applies this route without consulting `UIRoute.routeApplicationShouldProceed`.
118
+ * Use this only for route changes that are internal bookkeeping or that already
119
+ * passed a higher-level confirmation flow.
120
+ */
121
+ applyWithoutRouteApplicationCheck(forcefully = NO): boolean {
98
122
 
99
- window.location.hash = stringRepresentation
123
+ return this._applyRouteWithoutRouteApplicationCheck(forcefully, NO)
100
124
 
101
125
  }
102
126
 
@@ -106,14 +130,112 @@ export class UIRoute extends Array<UIRouteComponent> {
106
130
  * this route even when the route is identical to the current URL hash.
107
131
  * Defaults to `false`.
108
132
  */
109
- applyByReplacingCurrentRouteInHistory(forcefully = NO) {
133
+ applyByReplacingCurrentRouteInHistory(forcefully = NO): boolean | Promise<boolean> {
110
134
 
111
- const stringRepresentation = this.stringRepresentation
112
- if (!forcefully && new UIRoute(window.location.hash).stringRepresentation == stringRepresentation) {
113
- return
135
+ return this._applyRouteAfterRouteApplicationCheck(forcefully, YES)
136
+
137
+ }
138
+
139
+
140
+ /**
141
+ * Replaces the current history entry without consulting
142
+ * `UIRoute.routeApplicationShouldProceed`.
143
+ */
144
+ applyByReplacingCurrentRouteInHistoryWithoutRouteApplicationCheck(forcefully = NO): boolean {
145
+
146
+ return this._applyRouteWithoutRouteApplicationCheck(forcefully, YES)
147
+
148
+ }
149
+
150
+
151
+ _applyRouteAfterRouteApplicationCheck(
152
+ forcefully: boolean,
153
+ replacesCurrentRouteInHistory: boolean
154
+ ): boolean | Promise<boolean> {
155
+
156
+ if (!this._needsRouteApplication(forcefully)) {
157
+ return NO
158
+ }
159
+
160
+ const routeApplicationShouldProceed = UIRoute.ShouldApplyRouteChange
161
+ if (!routeApplicationShouldProceed) {
162
+ return this._applyRouteWithoutRouteApplicationCheck(forcefully, replacesCurrentRouteInHistory)
163
+ }
164
+
165
+ const shouldProceed = routeApplicationShouldProceed(
166
+ this._routeApplication(forcefully, replacesCurrentRouteInHistory)
167
+ )
168
+
169
+ if (shouldProceed instanceof Promise) {
170
+ return shouldProceed.then(routeApplicationShouldProceed => {
171
+ return this._applyRouteIfAllowed(
172
+ routeApplicationShouldProceed,
173
+ forcefully,
174
+ replacesCurrentRouteInHistory
175
+ )
176
+ })
177
+ }
178
+
179
+ return this._applyRouteIfAllowed(shouldProceed, forcefully, replacesCurrentRouteInHistory)
180
+
181
+ }
182
+
183
+
184
+ _applyRouteIfAllowed(
185
+ routeApplicationShouldProceed: boolean,
186
+ forcefully: boolean,
187
+ replacesCurrentRouteInHistory: boolean
188
+ ): boolean {
189
+
190
+ if (!routeApplicationShouldProceed) {
191
+ return NO
114
192
  }
115
193
 
116
- window.location.replace(this.linkRepresentation)
194
+ return this._applyRouteWithoutRouteApplicationCheck(forcefully, replacesCurrentRouteInHistory)
195
+
196
+ }
197
+
198
+
199
+ _applyRouteWithoutRouteApplicationCheck(
200
+ forcefully: boolean,
201
+ replacesCurrentRouteInHistory: boolean
202
+ ): boolean {
203
+
204
+ if (!this._needsRouteApplication(forcefully)) {
205
+ return NO
206
+ }
207
+
208
+ if (replacesCurrentRouteInHistory) {
209
+ window.location.replace(this.linkRepresentation)
210
+ }
211
+ else {
212
+ window.location.hash = this.stringRepresentation
213
+ }
214
+
215
+ return YES
216
+
217
+ }
218
+
219
+
220
+ _needsRouteApplication(forcefully: boolean): boolean {
221
+
222
+ if (!forcefully && new UIRoute(window.location.hash).stringRepresentation == this.stringRepresentation) {
223
+ return NO
224
+ }
225
+
226
+ return YES
227
+
228
+ }
229
+
230
+
231
+ _routeApplication(forcefully: boolean, replacesCurrentRouteInHistory: boolean): UIRouteChangeDescriptor {
232
+
233
+ return {
234
+ currentRoute: UIRoute.currentRoute,
235
+ targetRoute: this.copy(),
236
+ forcefully: forcefully,
237
+ replacesCurrentRouteInHistory: replacesCurrentRouteInHistory
238
+ }
117
239
 
118
240
  }
119
241
 
@@ -218,7 +340,7 @@ export class UIRoute extends Array<UIRouteComponent> {
218
340
 
219
341
  navigateBySettingComponent(name: string, parameters: UIRouteParameters, extendParameters: boolean = NO) {
220
342
 
221
- this.routeWithComponent(name, parameters, extendParameters).apply()
343
+ return this.routeWithComponent(name, parameters, extendParameters).apply()
222
344
 
223
345
  }
224
346