cx 26.0.14 → 26.1.1
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.
- package/build/ui/VDOM.d.ts +1 -20
- package/build/ui/VDOM.js +1 -3
- package/build/ui/Widget.d.ts +1 -1
- package/build/ui/Widget.js +0 -5
- package/build/ui/app/startAppLoop.js +2 -10
- package/build/util/Component.js +5 -0
- package/build/util/test/createTestRenderer.d.ts +3 -1
- package/build/util/test/createTestRenderer.js +8 -2
- package/build/widgets/form/Checkbox.d.ts +0 -1
- package/build/widgets/form/Checkbox.js +1 -0
- package/build/widgets/form/ColorField.d.ts +0 -1
- package/build/widgets/form/ColorField.js +2 -2
- package/build/widgets/form/DateTimeField.d.ts +0 -2
- package/build/widgets/form/DateTimeField.js +1 -0
- package/build/widgets/form/DateTimePicker.d.ts +0 -2
- package/build/widgets/form/DateTimePicker.js +1 -0
- package/build/widgets/form/Radio.d.ts +0 -1
- package/build/widgets/form/Slider.js +9 -1
- package/build/widgets/form/Switch.d.ts +0 -1
- package/build/widgets/form/Switch.js +1 -1
- package/build/widgets/form/Wheel.d.ts +0 -1
- package/build/widgets/grid/Grid.d.ts +0 -2
- package/build/widgets/grid/GridCellEditor.js +3 -1
- package/build/widgets/icons/calendar.js +4 -3
- package/build/widgets/icons/check.js +2 -2
- package/build/widgets/icons/clear.js +2 -2
- package/build/widgets/icons/close.js +2 -2
- package/build/widgets/icons/cx.js +2 -2
- package/build/widgets/icons/drop-down.js +2 -2
- package/build/widgets/icons/file.js +2 -2
- package/build/widgets/icons/folder-open.js +2 -2
- package/build/widgets/icons/folder.js +2 -2
- package/build/widgets/icons/forward.js +2 -2
- package/build/widgets/icons/loading.js +2 -2
- package/build/widgets/icons/menu.js +2 -2
- package/build/widgets/icons/pixel-picker.js +2 -2
- package/build/widgets/icons/search.js +2 -2
- package/build/widgets/icons/sort-asc.js +2 -2
- package/build/widgets/icons/square.js +2 -2
- package/build/widgets/overlay/Overlay.d.ts +3 -0
- package/build/widgets/overlay/Overlay.js +3 -2
- package/dist/manifest.js +867 -867
- package/dist/ui.js +4 -18
- package/dist/util.js +4 -0
- package/dist/widgets.js +395 -319
- package/package.json +11 -8
- package/src/charts/Chart.ts +108 -108
- package/src/core.d.ts +182 -182
- package/src/data/Expression.spec.ts +229 -229
- package/src/data/Expression.ts +233 -233
- package/src/data/Grouper.ts +158 -158
- package/src/data/Selector.ts +10 -10
- package/src/data/StringTemplate.spec.ts +132 -132
- package/src/data/StructuredSelector.ts +146 -146
- package/src/data/ZoomIntoPropertyView.spec.ts +64 -64
- package/src/data/comparer.ts +78 -78
- package/src/data/computable.spec.ts +87 -87
- package/src/data/createStructuredSelector.ts +62 -62
- package/src/data/getAccessor.spec.ts +11 -11
- package/src/data/getAccessor.ts +74 -74
- package/src/data/getSelector.spec.ts +43 -43
- package/src/data/getSelector.ts +66 -66
- package/src/data/ops/filter.spec.ts +35 -35
- package/src/data/ops/filter.ts +9 -9
- package/src/data/ops/merge.ts +13 -13
- package/src/data/ops/removeTreeNodes.spec.ts +37 -37
- package/src/data/ops/updateArray.spec.ts +69 -69
- package/src/data/ops/updateArray.ts +31 -31
- package/src/data/test-types.ts +7 -7
- package/src/hooks/invokeCallback.spec.tsx +4 -4
- package/src/hooks/resolveCallback.spec.tsx +4 -4
- package/src/hooks/store.spec.tsx +15 -15
- package/src/hooks/useTrigger.spec.tsx +16 -10
- package/src/hooks/useTrigger.ts +26 -26
- package/src/index.scss +6 -6
- package/src/jsx-runtime.ts +79 -79
- package/src/svg/BoundedObject.ts +101 -101
- package/src/svg/util/Rect.ts +105 -105
- package/src/ui/CSS.ts +87 -87
- package/src/ui/CSSHelper.ts +17 -17
- package/src/ui/ContentResolver.spec.tsx +31 -29
- package/src/ui/Controller.spec.tsx +47 -39
- package/src/ui/Culture.ts +159 -159
- package/src/ui/Cx.spec.tsx +10 -8
- package/src/ui/DataProxy.spec.tsx +18 -18
- package/src/ui/Instance.ts +866 -866
- package/src/ui/IsolatedScope.spec.tsx +16 -9
- package/src/ui/Prop.ts +140 -140
- package/src/ui/PureContainer.spec.tsx +20 -18
- package/src/ui/RenderingContext.ts +99 -99
- package/src/ui/Repeater.spec.tsx +8 -6
- package/src/ui/Rescope.spec.tsx +13 -13
- package/src/ui/Restate.spec.tsx +31 -27
- package/src/ui/StructuredInstanceDataAccessor.ts +32 -32
- package/src/ui/VDOM.ts +1 -34
- package/src/ui/Widget.tsx +0 -7
- package/src/ui/adapter/TreeAdapter.spec.ts +76 -76
- package/src/ui/adapter/TreeAdapter.ts +185 -185
- package/src/ui/app/History.ts +133 -133
- package/src/ui/app/Url.spec.ts +50 -50
- package/src/ui/app/startAppLoop.tsx +5 -9
- package/src/ui/app/startHotAppLoop.ts +41 -41
- package/src/ui/createFunctionalComponent.spec.tsx +20 -18
- package/src/ui/layout/ContentPlaceholder.spec.tsx +46 -34
- package/src/ui/layout/FirstVisibleChildLayout.spec.tsx +31 -19
- package/src/ui/layout/FirstVisibleChildLayout.ts +60 -60
- package/src/ui/selection/PropertySelection.ts +87 -87
- package/src/util/Component.spec.ts +30 -0
- package/src/util/Component.ts +301 -296
- package/src/util/Console.ts +13 -13
- package/src/util/DOM.ts +88 -88
- package/src/util/hasKey.ts +18 -18
- package/src/util/index.ts +55 -55
- package/src/util/isArray.ts +3 -3
- package/src/util/isDefined.ts +3 -3
- package/src/util/isString.ts +3 -3
- package/src/util/test/createTestRenderer.tsx +9 -2
- package/src/widgets/AccessorBindings.spec.tsx +4 -4
- package/src/widgets/DocumentTitle.ts +95 -95
- package/src/widgets/HtmlElement.spec.tsx +6 -6
- package/src/widgets/ReactElementWrapper.spec.tsx +37 -37
- package/src/widgets/autoFocus.ts +9 -9
- package/src/widgets/cx.ts +63 -63
- package/src/widgets/form/Checkbox.tsx +0 -1
- package/src/widgets/form/ColorField.tsx +15 -12
- package/src/widgets/form/DateTimeField.tsx +0 -2
- package/src/widgets/form/DateTimePicker.tsx +0 -2
- package/src/widgets/form/Radio.tsx +0 -1
- package/src/widgets/form/Slider.tsx +12 -4
- package/src/widgets/form/Switch.tsx +2 -3
- package/src/widgets/form/ValidationGroup.spec.tsx +12 -12
- package/src/widgets/form/Wheel.tsx +0 -1
- package/src/widgets/grid/Grid.tsx +0 -1
- package/src/widgets/grid/GridCellEditor.tsx +7 -1
- package/src/widgets/icons/calendar.tsx +20 -15
- package/src/widgets/icons/check.tsx +2 -1
- package/src/widgets/icons/clear.tsx +2 -1
- package/src/widgets/icons/close.tsx +2 -2
- package/src/widgets/icons/cx.tsx +2 -1
- package/src/widgets/icons/drop-down.tsx +2 -1
- package/src/widgets/icons/file.tsx +2 -1
- package/src/widgets/icons/folder-open.tsx +2 -1
- package/src/widgets/icons/folder.tsx +2 -1
- package/src/widgets/icons/forward.tsx +2 -1
- package/src/widgets/icons/loading.tsx +2 -1
- package/src/widgets/icons/menu.tsx +2 -1
- package/src/widgets/icons/pixel-picker.tsx +2 -2
- package/src/widgets/icons/search.tsx +2 -1
- package/src/widgets/icons/sort-asc.tsx +2 -1
- package/src/widgets/icons/square.tsx +2 -1
- package/src/widgets/nav/Route.spec.tsx +2 -2
- package/src/widgets/overlay/Overlay.tsx +5 -1
- package/src/widgets/overlay/captureMouse.ts +195 -195
- package/src/widgets/overlay/createHotPromiseWindowFactory.ts +71 -71
- package/src/widgets/overlay/index.d.ts +11 -11
- package/src/widgets/overlay/tooltip-ops.ts +173 -173
- package/build/data/ArrayElementView.spec.d.ts +0 -1
- package/build/data/ArrayElementView.spec.js +0 -81
- package/build/data/Binding.spec.d.ts +0 -1
- package/build/data/Binding.spec.js +0 -61
- package/build/data/Expression.spec.d.ts +0 -1
- package/build/data/Expression.spec.js +0 -196
- package/build/data/Grouper.spec.d.ts +0 -1
- package/build/data/Grouper.spec.js +0 -48
- package/build/data/Ref.spec.d.ts +0 -1
- package/build/data/Ref.spec.js +0 -72
- package/build/data/Store.spec.d.ts +0 -1
- package/build/data/Store.spec.js +0 -19
- package/build/data/StoreRef.spec.d.ts +0 -1
- package/build/data/StoreRef.spec.js +0 -22
- package/build/data/StringTemplate.spec.d.ts +0 -1
- package/build/data/StringTemplate.spec.js +0 -112
- package/build/data/StructuredSelector.spec.d.ts +0 -1
- package/build/data/StructuredSelector.spec.js +0 -102
- package/build/data/View.spec.d.ts +0 -1
- package/build/data/View.spec.js +0 -44
- package/build/data/ZoomIntoPropertyView.spec.d.ts +0 -1
- package/build/data/ZoomIntoPropertyView.spec.js +0 -54
- package/build/data/comparer.spec.d.ts +0 -1
- package/build/data/comparer.spec.js +0 -50
- package/build/data/computable.spec.d.ts +0 -1
- package/build/data/computable.spec.js +0 -56
- package/build/data/createAccessorModelProxy.spec.d.ts +0 -1
- package/build/data/createAccessorModelProxy.spec.js +0 -30
- package/build/data/createStructuredSelector.spec.d.ts +0 -1
- package/build/data/createStructuredSelector.spec.js +0 -42
- package/build/data/diff/diffs.spec.d.ts +0 -1
- package/build/data/diff/diffs.spec.js +0 -45
- package/build/data/getAccessor.spec.d.ts +0 -1
- package/build/data/getAccessor.spec.js +0 -10
- package/build/data/getSelector.spec.d.ts +0 -1
- package/build/data/getSelector.spec.js +0 -36
- package/build/data/ops/append.spec.d.ts +0 -1
- package/build/data/ops/append.spec.js +0 -24
- package/build/data/ops/filter.spec.d.ts +0 -1
- package/build/data/ops/filter.spec.js +0 -25
- package/build/data/ops/findTreeNode.spec.d.ts +0 -1
- package/build/data/ops/findTreeNode.spec.js +0 -20
- package/build/data/ops/merge.spec.d.ts +0 -1
- package/build/data/ops/merge.spec.js +0 -23
- package/build/data/ops/removeTreeNodes.spec.d.ts +0 -1
- package/build/data/ops/removeTreeNodes.spec.js +0 -35
- package/build/data/ops/updateArray.spec.d.ts +0 -1
- package/build/data/ops/updateArray.spec.js +0 -33
- package/build/data/ops/updateTree.spec.d.ts +0 -1
- package/build/data/ops/updateTree.spec.js +0 -44
- package/build/hooks/invokeCallback.spec.d.ts +0 -1
- package/build/hooks/invokeCallback.spec.js +0 -44
- package/build/hooks/resolveCallback.spec.d.ts +0 -1
- package/build/hooks/resolveCallback.spec.js +0 -35
- package/build/hooks/store.spec.d.ts +0 -1
- package/build/hooks/store.spec.js +0 -48
- package/build/hooks/useTrigger.spec.d.ts +0 -1
- package/build/hooks/useTrigger.spec.js +0 -59
- package/build/ui/Controller.spec.d.ts +0 -1
- package/build/ui/Controller.spec.js +0 -247
- package/build/ui/Cx.spec.d.ts +0 -1
- package/build/ui/Cx.spec.js +0 -153
- package/build/ui/DataProxy.spec.d.ts +0 -1
- package/build/ui/DataProxy.spec.js +0 -208
- package/build/ui/IsolatedScope.spec.d.ts +0 -1
- package/build/ui/IsolatedScope.spec.js +0 -42
- package/build/ui/PureContainer.spec.d.ts +0 -1
- package/build/ui/PureContainer.spec.js +0 -149
- package/build/ui/Repeater.spec.d.ts +0 -1
- package/build/ui/Repeater.spec.js +0 -109
- package/build/ui/Rescope.spec.d.ts +0 -1
- package/build/ui/Rescope.spec.js +0 -134
- package/build/ui/Restate.spec.d.ts +0 -1
- package/build/ui/Restate.spec.js +0 -257
- package/build/ui/adapter/ArrayAdapter.spec.d.ts +0 -1
- package/build/ui/adapter/ArrayAdapter.spec.js +0 -44
- package/build/ui/adapter/TreeAdapter.spec.d.ts +0 -1
- package/build/ui/adapter/TreeAdapter.spec.js +0 -71
- package/build/ui/app/Url.spec.d.ts +0 -1
- package/build/ui/app/Url.spec.js +0 -43
- package/build/ui/createFunctionalComponent.spec.d.ts +0 -1
- package/build/ui/createFunctionalComponent.spec.js +0 -272
- package/build/ui/layout/ContentPlaceholder.spec.d.ts +0 -1
- package/build/ui/layout/ContentPlaceholder.spec.js +0 -333
- package/build/ui/layout/FirstVisibleChildLayout.spec.d.ts +0 -1
- package/build/ui/layout/FirstVisibleChildLayout.spec.js +0 -101
- package/build/util/Format.spec.d.ts +0 -1
- package/build/util/Format.spec.js +0 -58
- package/build/util/TraversalStack.spec.d.ts +0 -1
- package/build/util/TraversalStack.spec.js +0 -43
- package/build/util/date/upperBoundCheck.spec.d.ts +0 -1
- package/build/util/date/upperBoundCheck.spec.js +0 -22
- package/build/util/getSearchQueryPredicate.spec.d.ts +0 -1
- package/build/util/getSearchQueryPredicate.spec.js +0 -33
- package/build/util/isValidIdentifierName.spec.d.ts +0 -1
- package/build/util/isValidIdentifierName.spec.js +0 -28
- package/build/util/routeAppend.spec.d.ts +0 -1
- package/build/util/routeAppend.spec.js +0 -14
- package/build/widgets/AccessorBindings.spec.d.ts +0 -1
- package/build/widgets/AccessorBindings.spec.js +0 -40
- package/build/widgets/HtmlElement.spec.d.ts +0 -1
- package/build/widgets/HtmlElement.spec.js +0 -38
- package/build/widgets/form/ValidationGroup.spec.d.ts +0 -1
- package/build/widgets/form/ValidationGroup.spec.js +0 -62
- package/build/widgets/nav/Route.spec.d.ts +0 -1
- package/build/widgets/nav/Route.spec.js +0 -15
- package/dist/manifest.d.ts +0 -1443
package/src/ui/app/History.ts
CHANGED
|
@@ -1,133 +1,133 @@
|
|
|
1
|
-
import { Url } from "./Url";
|
|
2
|
-
import { batchUpdatesAndNotify } from "../batchUpdates";
|
|
3
|
-
import { SubscriberList } from "../../util/SubscriberList";
|
|
4
|
-
import { View } from "../../data/View";
|
|
5
|
-
|
|
6
|
-
interface Transition {
|
|
7
|
-
url: string;
|
|
8
|
-
state: any;
|
|
9
|
-
title: string | null;
|
|
10
|
-
replace: boolean;
|
|
11
|
-
completed?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type NavigateConfirmationCallback = (state: any) => boolean | Promise<boolean>;
|
|
15
|
-
|
|
16
|
-
let last = 0;
|
|
17
|
-
let next = 1;
|
|
18
|
-
let transitions: Record<number, Transition> = {};
|
|
19
|
-
let subscribers: SubscriberList | null = null;
|
|
20
|
-
let reload = false;
|
|
21
|
-
let navigateConfirmationCallback: NavigateConfirmationCallback | null = null;
|
|
22
|
-
let permanentNavigateConfirmation = false;
|
|
23
|
-
|
|
24
|
-
export class History {
|
|
25
|
-
static store: View;
|
|
26
|
-
static urlBinding: string;
|
|
27
|
-
static hashBinding?: string;
|
|
28
|
-
|
|
29
|
-
static connect(store: View, urlBinding: string, hashBinding?: string): void {
|
|
30
|
-
this.store = store;
|
|
31
|
-
this.urlBinding = urlBinding;
|
|
32
|
-
this.hashBinding = hashBinding;
|
|
33
|
-
this.updateStore();
|
|
34
|
-
window.onpopstate = () => {
|
|
35
|
-
this.updateStore();
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
static pushState(state: any, title: string | null, url: string): boolean {
|
|
40
|
-
return this.confirmAndNavigate(state, title, url);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
static replaceState(state: any, title: string | null, url: string): boolean {
|
|
44
|
-
return this.navigate(state, title, url, true);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
static reloadOnNextChange(): void {
|
|
48
|
-
reload = true;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
static addNavigateConfirmation(callback: NavigateConfirmationCallback, permanent = false): void {
|
|
52
|
-
navigateConfirmationCallback = callback;
|
|
53
|
-
permanentNavigateConfirmation = permanent;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
static confirm(continueCallback: () => boolean, state: any): boolean {
|
|
57
|
-
if (!navigateConfirmationCallback) return continueCallback();
|
|
58
|
-
|
|
59
|
-
let result = navigateConfirmationCallback(state);
|
|
60
|
-
Promise.resolve(result).then((value) => {
|
|
61
|
-
if (value) {
|
|
62
|
-
if (!permanentNavigateConfirmation) navigateConfirmationCallback = null;
|
|
63
|
-
continueCallback();
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
static confirmAndNavigate(state: any, title: string | null, url: string, replace?: boolean): boolean {
|
|
71
|
-
return this.confirm(() => this.navigate(state, title, url, replace), url);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
static navigate(state: any, title: string | null, url: string, replace = false): boolean {
|
|
75
|
-
url = Url.resolve(url);
|
|
76
|
-
|
|
77
|
-
if (!window.history.pushState || reload) {
|
|
78
|
-
window.location[replace ? "replace" : "assign"](url);
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
let transition: Transition | undefined;
|
|
83
|
-
let changed = false;
|
|
84
|
-
batchUpdatesAndNotify(
|
|
85
|
-
() => {
|
|
86
|
-
changed = this.updateStore(url);
|
|
87
|
-
if (changed)
|
|
88
|
-
transitions[++last] = transition = {
|
|
89
|
-
url,
|
|
90
|
-
state,
|
|
91
|
-
title,
|
|
92
|
-
replace,
|
|
93
|
-
};
|
|
94
|
-
},
|
|
95
|
-
() => {
|
|
96
|
-
if (transition) transition.completed = true;
|
|
97
|
-
|
|
98
|
-
//update history once the page is rendered and the title is set
|
|
99
|
-
while (transitions[next] && transitions[next].completed) {
|
|
100
|
-
let tr = transitions[next];
|
|
101
|
-
delete transitions[next];
|
|
102
|
-
next++;
|
|
103
|
-
if (tr.replace) {
|
|
104
|
-
window.history.replaceState(tr.state, tr.title ?? "", tr.url);
|
|
105
|
-
if (subscribers) subscribers.notify(tr.url, "replaceState");
|
|
106
|
-
} else {
|
|
107
|
-
window.history.pushState(tr.state, tr.title ?? "", tr.url);
|
|
108
|
-
if (subscribers) subscribers.notify(tr.url, "pushState");
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
return changed;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
static updateStore(href?: string): boolean {
|
|
118
|
-
let url = Url.unresolve(href || document.location.href);
|
|
119
|
-
let hash: string | null = null;
|
|
120
|
-
let hashIndex = url.indexOf("#");
|
|
121
|
-
if (hashIndex !== -1) {
|
|
122
|
-
hash = url.substring(hashIndex);
|
|
123
|
-
url = url.substring(0, hashIndex);
|
|
124
|
-
}
|
|
125
|
-
if (this.hashBinding) this.store.set(this.hashBinding, hash);
|
|
126
|
-
return this.store.set(this.urlBinding, url);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
static subscribe(callback: (url: string, op: string) => void): () => void {
|
|
130
|
-
if (!subscribers) subscribers = new SubscriberList();
|
|
131
|
-
return subscribers.subscribe(callback);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
1
|
+
import { Url } from "./Url";
|
|
2
|
+
import { batchUpdatesAndNotify } from "../batchUpdates";
|
|
3
|
+
import { SubscriberList } from "../../util/SubscriberList";
|
|
4
|
+
import { View } from "../../data/View";
|
|
5
|
+
|
|
6
|
+
interface Transition {
|
|
7
|
+
url: string;
|
|
8
|
+
state: any;
|
|
9
|
+
title: string | null;
|
|
10
|
+
replace: boolean;
|
|
11
|
+
completed?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type NavigateConfirmationCallback = (state: any) => boolean | Promise<boolean>;
|
|
15
|
+
|
|
16
|
+
let last = 0;
|
|
17
|
+
let next = 1;
|
|
18
|
+
let transitions: Record<number, Transition> = {};
|
|
19
|
+
let subscribers: SubscriberList | null = null;
|
|
20
|
+
let reload = false;
|
|
21
|
+
let navigateConfirmationCallback: NavigateConfirmationCallback | null = null;
|
|
22
|
+
let permanentNavigateConfirmation = false;
|
|
23
|
+
|
|
24
|
+
export class History {
|
|
25
|
+
static store: View;
|
|
26
|
+
static urlBinding: string;
|
|
27
|
+
static hashBinding?: string;
|
|
28
|
+
|
|
29
|
+
static connect(store: View, urlBinding: string, hashBinding?: string): void {
|
|
30
|
+
this.store = store;
|
|
31
|
+
this.urlBinding = urlBinding;
|
|
32
|
+
this.hashBinding = hashBinding;
|
|
33
|
+
this.updateStore();
|
|
34
|
+
window.onpopstate = () => {
|
|
35
|
+
this.updateStore();
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static pushState(state: any, title: string | null, url: string): boolean {
|
|
40
|
+
return this.confirmAndNavigate(state, title, url);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static replaceState(state: any, title: string | null, url: string): boolean {
|
|
44
|
+
return this.navigate(state, title, url, true);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static reloadOnNextChange(): void {
|
|
48
|
+
reload = true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static addNavigateConfirmation(callback: NavigateConfirmationCallback, permanent = false): void {
|
|
52
|
+
navigateConfirmationCallback = callback;
|
|
53
|
+
permanentNavigateConfirmation = permanent;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static confirm(continueCallback: () => boolean, state: any): boolean {
|
|
57
|
+
if (!navigateConfirmationCallback) return continueCallback();
|
|
58
|
+
|
|
59
|
+
let result = navigateConfirmationCallback(state);
|
|
60
|
+
Promise.resolve(result).then((value) => {
|
|
61
|
+
if (value) {
|
|
62
|
+
if (!permanentNavigateConfirmation) navigateConfirmationCallback = null;
|
|
63
|
+
continueCallback();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static confirmAndNavigate(state: any, title: string | null, url: string, replace?: boolean): boolean {
|
|
71
|
+
return this.confirm(() => this.navigate(state, title, url, replace), url);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static navigate(state: any, title: string | null, url: string, replace = false): boolean {
|
|
75
|
+
url = Url.resolve(url);
|
|
76
|
+
|
|
77
|
+
if (!window.history.pushState || reload) {
|
|
78
|
+
window.location[replace ? "replace" : "assign"](url);
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let transition: Transition | undefined;
|
|
83
|
+
let changed = false;
|
|
84
|
+
batchUpdatesAndNotify(
|
|
85
|
+
() => {
|
|
86
|
+
changed = this.updateStore(url);
|
|
87
|
+
if (changed)
|
|
88
|
+
transitions[++last] = transition = {
|
|
89
|
+
url,
|
|
90
|
+
state,
|
|
91
|
+
title,
|
|
92
|
+
replace,
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
() => {
|
|
96
|
+
if (transition) transition.completed = true;
|
|
97
|
+
|
|
98
|
+
//update history once the page is rendered and the title is set
|
|
99
|
+
while (transitions[next] && transitions[next].completed) {
|
|
100
|
+
let tr = transitions[next];
|
|
101
|
+
delete transitions[next];
|
|
102
|
+
next++;
|
|
103
|
+
if (tr.replace) {
|
|
104
|
+
window.history.replaceState(tr.state, tr.title ?? "", tr.url);
|
|
105
|
+
if (subscribers) subscribers.notify(tr.url, "replaceState");
|
|
106
|
+
} else {
|
|
107
|
+
window.history.pushState(tr.state, tr.title ?? "", tr.url);
|
|
108
|
+
if (subscribers) subscribers.notify(tr.url, "pushState");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return changed;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static updateStore(href?: string): boolean {
|
|
118
|
+
let url = Url.unresolve(href || document.location.href);
|
|
119
|
+
let hash: string | null = null;
|
|
120
|
+
let hashIndex = url.indexOf("#");
|
|
121
|
+
if (hashIndex !== -1) {
|
|
122
|
+
hash = url.substring(hashIndex);
|
|
123
|
+
url = url.substring(0, hashIndex);
|
|
124
|
+
}
|
|
125
|
+
if (this.hashBinding) this.store.set(this.hashBinding, hash);
|
|
126
|
+
return this.store.set(this.urlBinding, url);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static subscribe(callback: (url: string, op: string) => void): () => void {
|
|
130
|
+
if (!subscribers) subscribers = new SubscriberList();
|
|
131
|
+
return subscribers.subscribe(callback);
|
|
132
|
+
}
|
|
133
|
+
}
|
package/src/ui/app/Url.spec.ts
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import { Url } from "./Url";
|
|
2
|
-
import Route from "route-parser";
|
|
3
|
-
import assert from "assert";
|
|
4
|
-
describe("Url", function () {
|
|
5
|
-
describe(".unresolve", function () {
|
|
6
|
-
it("preserves query parameters", function () {
|
|
7
|
-
Url.absoluteBase = "https://cxjs.io/docs/";
|
|
8
|
-
assert.equal("~/?state=1", Url.unresolve("https://cxjs.io/docs/?state=1"));
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it("doesn't touch unresolved urls", function () {
|
|
12
|
-
assert.equal("~/test", Url.unresolve("~/test"));
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe(".getBaseFromScriptSrc", () => {
|
|
17
|
-
it("ignores query strings", function () {
|
|
18
|
-
assert.equal(Url.getBaseFromScriptSrc("/vendor.js?qs=1", "~/vendor.js"), "/");
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("allows wildcards", function () {
|
|
22
|
-
assert.equal(Url.getBaseFromScriptSrc("/vendor.123.js?qs=1", "~/vendor.*.js"), "/");
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("works for an application folder", function () {
|
|
26
|
-
assert.equal(Url.getBaseFromScriptSrc("/datasync/vendor.124c82.js", "~/vendor.*.js"), "/datasync/");
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe("Route", function () {
|
|
32
|
-
it("matches query param", function () {
|
|
33
|
-
let route = new Route("~/?state=:state");
|
|
34
|
-
let result = route.match("~/?state=1");
|
|
35
|
-
assert(result !== false);
|
|
36
|
-
assert.equal(result.state, "1");
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("matches routes with extra query params", function () {
|
|
40
|
-
let route = new Route("~/?state=:state");
|
|
41
|
-
let result = route.match("~/?state=1&more=2");
|
|
42
|
-
assert(result);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it.skip("matches query params in any order", function () {
|
|
46
|
-
let route = new Route("~/?a=:a&b=:b");
|
|
47
|
-
let result = route.match("~/?b=1&a=2");
|
|
48
|
-
assert(result);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
1
|
+
import { Url } from "./Url";
|
|
2
|
+
import Route from "route-parser";
|
|
3
|
+
import assert from "assert";
|
|
4
|
+
describe("Url", function () {
|
|
5
|
+
describe(".unresolve", function () {
|
|
6
|
+
it("preserves query parameters", function () {
|
|
7
|
+
Url.absoluteBase = "https://cxjs.io/docs/";
|
|
8
|
+
assert.equal("~/?state=1", Url.unresolve("https://cxjs.io/docs/?state=1"));
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("doesn't touch unresolved urls", function () {
|
|
12
|
+
assert.equal("~/test", Url.unresolve("~/test"));
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe(".getBaseFromScriptSrc", () => {
|
|
17
|
+
it("ignores query strings", function () {
|
|
18
|
+
assert.equal(Url.getBaseFromScriptSrc("/vendor.js?qs=1", "~/vendor.js"), "/");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("allows wildcards", function () {
|
|
22
|
+
assert.equal(Url.getBaseFromScriptSrc("/vendor.123.js?qs=1", "~/vendor.*.js"), "/");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("works for an application folder", function () {
|
|
26
|
+
assert.equal(Url.getBaseFromScriptSrc("/datasync/vendor.124c82.js", "~/vendor.*.js"), "/datasync/");
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("Route", function () {
|
|
32
|
+
it("matches query param", function () {
|
|
33
|
+
let route = new Route("~/?state=:state");
|
|
34
|
+
let result = route.match("~/?state=1");
|
|
35
|
+
assert(result !== false);
|
|
36
|
+
assert.equal(result.state, "1");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("matches routes with extra query params", function () {
|
|
40
|
+
let route = new Route("~/?state=:state");
|
|
41
|
+
let result = route.match("~/?state=1&more=2");
|
|
42
|
+
assert(result);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it.skip("matches query params in any order", function () {
|
|
46
|
+
let route = new Route("~/?a=:a&b=:b");
|
|
47
|
+
let result = route.match("~/?b=1&a=2");
|
|
48
|
+
assert(result);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** @jsxImportSource react */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import type { Root } from "cx-react";
|
|
4
|
+
import { Widget, VDOM } from "../Widget";
|
|
4
5
|
import { Store } from "../../data/Store";
|
|
5
6
|
import { Cx } from "../Cx";
|
|
6
7
|
import { Instance } from "../Instance";
|
|
@@ -44,11 +45,8 @@ export function startAppLoop(
|
|
|
44
45
|
/>
|
|
45
46
|
) as any;
|
|
46
47
|
|
|
47
|
-
let root
|
|
48
|
-
|
|
49
|
-
root = VDOM.DOM.createRoot(parentDOMElement);
|
|
50
|
-
root.render(content);
|
|
51
|
-
} else VDOM.DOM.render(content, parentDOMElement);
|
|
48
|
+
let root = VDOM.DOM.createRoot(parentDOMElement);
|
|
49
|
+
root.render(content);
|
|
52
50
|
|
|
53
51
|
let stopped = false;
|
|
54
52
|
|
|
@@ -66,10 +64,8 @@ export function startAppLoop(
|
|
|
66
64
|
};
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
function destroy(parentDOMElement: HTMLElement, options: StartAppLoopOptions, root:
|
|
67
|
+
function destroy(parentDOMElement: HTMLElement, options: StartAppLoopOptions, root: Root): void {
|
|
70
68
|
if (root) root.unmount();
|
|
71
|
-
else VDOM.DOM.unmountComponentAtNode(parentDOMElement);
|
|
72
|
-
|
|
73
69
|
if (options.removeParentDOMElement && parentDOMElement.parentNode)
|
|
74
70
|
parentDOMElement.parentNode.removeChild(parentDOMElement);
|
|
75
71
|
}
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import { startAppLoop, StartAppLoopOptions } from "./startAppLoop";
|
|
2
|
-
import { Widget, WidgetConfig } from "../Widget";
|
|
3
|
-
import { Store } from "../../data/Store";
|
|
4
|
-
import { Create } from "../../util/Component";
|
|
5
|
-
|
|
6
|
-
export interface HotModule {
|
|
7
|
-
hot?: {
|
|
8
|
-
accept: () => void;
|
|
9
|
-
dispose: (callback: (data: any) => void) => void;
|
|
10
|
-
data?: any;
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function startHotAppLoop(
|
|
15
|
-
appModule: HotModule,
|
|
16
|
-
element: HTMLElement,
|
|
17
|
-
store: Store,
|
|
18
|
-
widgets: Create<typeof Widget> | Create<typeof Widget>[],
|
|
19
|
-
options: StartAppLoopOptions = {},
|
|
20
|
-
): () => void {
|
|
21
|
-
let stop: (() => void) | undefined;
|
|
22
|
-
//webpack (HMR)
|
|
23
|
-
if (appModule.hot) {
|
|
24
|
-
// accept itself
|
|
25
|
-
appModule.hot.accept();
|
|
26
|
-
|
|
27
|
-
// remember data on dispose
|
|
28
|
-
appModule.hot.dispose(function (data: any) {
|
|
29
|
-
data.state = store.getData();
|
|
30
|
-
if (stop) stop();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
//apply data on hot replace
|
|
34
|
-
if (appModule.hot.data?.state) store.load(appModule.hot.data.state);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
Widget.resetCounter();
|
|
38
|
-
|
|
39
|
-
//app loop
|
|
40
|
-
return (stop = startAppLoop(element, store, widgets, options));
|
|
41
|
-
}
|
|
1
|
+
import { startAppLoop, StartAppLoopOptions } from "./startAppLoop";
|
|
2
|
+
import { Widget, WidgetConfig } from "../Widget";
|
|
3
|
+
import { Store } from "../../data/Store";
|
|
4
|
+
import { Create } from "../../util/Component";
|
|
5
|
+
|
|
6
|
+
export interface HotModule {
|
|
7
|
+
hot?: {
|
|
8
|
+
accept: () => void;
|
|
9
|
+
dispose: (callback: (data: any) => void) => void;
|
|
10
|
+
data?: any;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function startHotAppLoop(
|
|
15
|
+
appModule: HotModule,
|
|
16
|
+
element: HTMLElement,
|
|
17
|
+
store: Store,
|
|
18
|
+
widgets: Create<typeof Widget> | Create<typeof Widget>[],
|
|
19
|
+
options: StartAppLoopOptions = {},
|
|
20
|
+
): () => void {
|
|
21
|
+
let stop: (() => void) | undefined;
|
|
22
|
+
//webpack (HMR)
|
|
23
|
+
if (appModule.hot) {
|
|
24
|
+
// accept itself
|
|
25
|
+
appModule.hot.accept();
|
|
26
|
+
|
|
27
|
+
// remember data on dispose
|
|
28
|
+
appModule.hot.dispose(function (data: any) {
|
|
29
|
+
data.state = store.getData();
|
|
30
|
+
if (stop) stop();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
//apply data on hot replace
|
|
34
|
+
if (appModule.hot.data?.state) store.load(appModule.hot.data.state);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Widget.resetCounter();
|
|
38
|
+
|
|
39
|
+
//app loop
|
|
40
|
+
return (stop = startAppLoop(element, store, widgets, options));
|
|
41
|
+
}
|
|
@@ -2,7 +2,7 @@ import { Store } from "../data/Store";
|
|
|
2
2
|
import { createFunctionalComponent } from "./createFunctionalComponent";
|
|
3
3
|
import { bind } from "./bind";
|
|
4
4
|
import { expr } from "./expr";
|
|
5
|
-
import { createTestRenderer } from "../util/test/createTestRenderer";
|
|
5
|
+
import { createTestRenderer, act } from "../util/test/createTestRenderer";
|
|
6
6
|
|
|
7
7
|
import assert from "assert";
|
|
8
8
|
import { Rescope } from "./Rescope";
|
|
@@ -66,7 +66,7 @@ describe("createFunctionalComponent type safety", () => {
|
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
describe("createFunctionalComponent", () => {
|
|
69
|
-
it("allows spread", () => {
|
|
69
|
+
it("allows spread", async () => {
|
|
70
70
|
const SuperDiv = createFunctionalComponent(({ ...props }) => {
|
|
71
71
|
return (
|
|
72
72
|
<cx>
|
|
@@ -88,7 +88,7 @@ describe("createFunctionalComponent", () => {
|
|
|
88
88
|
|
|
89
89
|
let store = new Store();
|
|
90
90
|
|
|
91
|
-
const component = createTestRenderer(store, widget);
|
|
91
|
+
const component = await createTestRenderer(store, widget);
|
|
92
92
|
|
|
93
93
|
let tree = component.toJSON();
|
|
94
94
|
assert.deepEqual(tree, {
|
|
@@ -103,7 +103,7 @@ describe("createFunctionalComponent", () => {
|
|
|
103
103
|
});
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
it("visible and Rescope behave as expected", () => {
|
|
106
|
+
it("visible and Rescope behave as expected", async () => {
|
|
107
107
|
const RootRescope = createFunctionalComponent(({}) => {
|
|
108
108
|
return (
|
|
109
109
|
<cx>
|
|
@@ -128,7 +128,7 @@ describe("createFunctionalComponent", () => {
|
|
|
128
128
|
},
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
-
const component = createTestRenderer(store, widget);
|
|
131
|
+
const component = await createTestRenderer(store, widget);
|
|
132
132
|
|
|
133
133
|
let tree = component.toJSON();
|
|
134
134
|
assert.deepEqual(tree, {
|
|
@@ -138,7 +138,7 @@ describe("createFunctionalComponent", () => {
|
|
|
138
138
|
});
|
|
139
139
|
});
|
|
140
140
|
|
|
141
|
-
it("visible and multiple items behave as expected", () => {
|
|
141
|
+
it("visible and multiple items behave as expected", async () => {
|
|
142
142
|
const FComponent = createFunctionalComponent(({}) => {
|
|
143
143
|
return (
|
|
144
144
|
<cx>
|
|
@@ -157,7 +157,7 @@ describe("createFunctionalComponent", () => {
|
|
|
157
157
|
|
|
158
158
|
let store = new Store();
|
|
159
159
|
|
|
160
|
-
const component = createTestRenderer(store, widget);
|
|
160
|
+
const component = await createTestRenderer(store, widget);
|
|
161
161
|
|
|
162
162
|
let tree = component.toJSON();
|
|
163
163
|
assert.deepEqual(tree, [
|
|
@@ -174,7 +174,7 @@ describe("createFunctionalComponent", () => {
|
|
|
174
174
|
]);
|
|
175
175
|
});
|
|
176
176
|
|
|
177
|
-
it("respects inner layouts", () => {
|
|
177
|
+
it("respects inner layouts", async () => {
|
|
178
178
|
const FComponent = createFunctionalComponent(({}) => {
|
|
179
179
|
return (
|
|
180
180
|
<cx>
|
|
@@ -194,7 +194,7 @@ describe("createFunctionalComponent", () => {
|
|
|
194
194
|
|
|
195
195
|
let store = new Store();
|
|
196
196
|
|
|
197
|
-
const component = createTestRenderer(store, widget);
|
|
197
|
+
const component = await createTestRenderer(store, widget);
|
|
198
198
|
|
|
199
199
|
let tree = component.toJSON();
|
|
200
200
|
|
|
@@ -279,7 +279,7 @@ describe("createFunctionalComponent", () => {
|
|
|
279
279
|
});
|
|
280
280
|
});
|
|
281
281
|
|
|
282
|
-
it("can use refs for data bindings", () => {
|
|
282
|
+
it("can use refs for data bindings", async () => {
|
|
283
283
|
const X = createFunctionalComponent(({}) => {
|
|
284
284
|
let { ref } = useStoreMethods();
|
|
285
285
|
let x = ref("x", "OK");
|
|
@@ -298,7 +298,7 @@ describe("createFunctionalComponent", () => {
|
|
|
298
298
|
|
|
299
299
|
let store = new Store();
|
|
300
300
|
|
|
301
|
-
const component = createTestRenderer(store, widget);
|
|
301
|
+
const component = await createTestRenderer(store, widget);
|
|
302
302
|
|
|
303
303
|
let tree = component.toJSON();
|
|
304
304
|
assert.deepEqual(tree, {
|
|
@@ -308,7 +308,7 @@ describe("createFunctionalComponent", () => {
|
|
|
308
308
|
});
|
|
309
309
|
});
|
|
310
310
|
|
|
311
|
-
it("adds children at the right place", () => {
|
|
311
|
+
it("adds children at the right place", async () => {
|
|
312
312
|
const X = createFunctionalComponent(({ children }: { children: any }) => (
|
|
313
313
|
<cx>
|
|
314
314
|
<header />
|
|
@@ -327,7 +327,7 @@ describe("createFunctionalComponent", () => {
|
|
|
327
327
|
|
|
328
328
|
let store = new Store();
|
|
329
329
|
|
|
330
|
-
const component = createTestRenderer(store, widget);
|
|
330
|
+
const component = await createTestRenderer(store, widget);
|
|
331
331
|
|
|
332
332
|
let tree = component.toJSON();
|
|
333
333
|
|
|
@@ -356,7 +356,7 @@ describe("createFunctionalComponent", () => {
|
|
|
356
356
|
]);
|
|
357
357
|
});
|
|
358
358
|
|
|
359
|
-
it("works well with repeaters", () => {
|
|
359
|
+
it("works well with repeaters", async () => {
|
|
360
360
|
const X = createFunctionalComponent(({}) => {
|
|
361
361
|
let { ref } = useStoreMethods();
|
|
362
362
|
let text = ref("$record.text");
|
|
@@ -377,7 +377,7 @@ describe("createFunctionalComponent", () => {
|
|
|
377
377
|
|
|
378
378
|
let store = new Store({ data: { array: [{ text: "0" }, { text: "1" }, { text: "2" }] } });
|
|
379
379
|
|
|
380
|
-
const component = createTestRenderer(store, widget);
|
|
380
|
+
const component = await createTestRenderer(store, widget);
|
|
381
381
|
|
|
382
382
|
let tree = component.toJSON();
|
|
383
383
|
|
|
@@ -399,7 +399,9 @@ describe("createFunctionalComponent", () => {
|
|
|
399
399
|
},
|
|
400
400
|
]);
|
|
401
401
|
|
|
402
|
-
|
|
402
|
+
await act(async () => {
|
|
403
|
+
store.update("array", (array) => [array[0], { text: "10" }, array[2]]);
|
|
404
|
+
});
|
|
403
405
|
|
|
404
406
|
tree = component.toJSON();
|
|
405
407
|
|
|
@@ -422,7 +424,7 @@ describe("createFunctionalComponent", () => {
|
|
|
422
424
|
]);
|
|
423
425
|
});
|
|
424
426
|
|
|
425
|
-
it("can have its own layout", () => {
|
|
427
|
+
it("can have its own layout", async () => {
|
|
426
428
|
const X = createFunctionalComponent(() => (
|
|
427
429
|
<cx>
|
|
428
430
|
<div>1</div>
|
|
@@ -439,7 +441,7 @@ describe("createFunctionalComponent", () => {
|
|
|
439
441
|
|
|
440
442
|
let store = new Store();
|
|
441
443
|
|
|
442
|
-
const component = createTestRenderer(store, widget);
|
|
444
|
+
const component = await createTestRenderer(store, widget);
|
|
443
445
|
|
|
444
446
|
let tree = component.toJSON();
|
|
445
447
|
|