x4js 1.4.14 → 1.4.15
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/lib/component.d.ts +0 -1
- package/lib/component.js +7 -2
- package/lib/layout.js +7 -0
- package/lib/listview.d.ts +2 -2
- package/lib/router.d.ts +10 -2
- package/lib/router.js +98 -18
- package/lib/tabbar.d.ts +3 -1
- package/lib/tabbar.js +31 -12
- package/lib/x4_events.d.ts +8 -0
- package/lib/x4_events.js +5 -1
- package/package.json +1 -1
- package/src/component.ts +8 -2
- package/src/layout.ts +9 -0
- package/src/listview.ts +2 -2
- package/src/router.ts +134 -22
- package/src/tabbar.ts +36 -13
- package/src/x4_events.ts +13 -0
package/lib/component.d.ts
CHANGED
|
@@ -107,7 +107,6 @@ export declare class Component<P extends CProps<BaseComponentEventMap> = CProps<
|
|
|
107
107
|
private static __privateEvents;
|
|
108
108
|
private static __sizeObserver;
|
|
109
109
|
private static __createObserver;
|
|
110
|
-
private static __intersectionObserver;
|
|
111
110
|
private static __capture;
|
|
112
111
|
private static __capture_mask;
|
|
113
112
|
private static __css;
|
package/lib/component.js
CHANGED
|
@@ -89,7 +89,7 @@ class Component extends base_component_1.BaseComponent {
|
|
|
89
89
|
static __privateEvents = {};
|
|
90
90
|
static __sizeObserver; // resize observer
|
|
91
91
|
static __createObserver; // creation observer
|
|
92
|
-
static __intersectionObserver;
|
|
92
|
+
//private static __intersectionObserver: IntersectionObserver; // visibility observer
|
|
93
93
|
static __capture = null;
|
|
94
94
|
static __capture_mask = null;
|
|
95
95
|
static __css = null;
|
|
@@ -101,6 +101,10 @@ class Component extends base_component_1.BaseComponent {
|
|
|
101
101
|
uid: Component.__comp_guid++,
|
|
102
102
|
inrender: false,
|
|
103
103
|
};
|
|
104
|
+
// prepare iprops
|
|
105
|
+
if (this.m_props.cls) {
|
|
106
|
+
this.addClass(this.m_props.cls);
|
|
107
|
+
}
|
|
104
108
|
}
|
|
105
109
|
/**
|
|
106
110
|
*
|
|
@@ -1042,7 +1046,8 @@ class Component extends base_component_1.BaseComponent {
|
|
|
1042
1046
|
this.addClass('@' + (0, tools_1.pascalCase)(clsname));
|
|
1043
1047
|
me = Object.getPrototypeOf(me);
|
|
1044
1048
|
}
|
|
1045
|
-
|
|
1049
|
+
//done in ctor now
|
|
1050
|
+
//this.addClass(this.m_props.cls);
|
|
1046
1051
|
}
|
|
1047
1052
|
/**
|
|
1048
1053
|
* prepend the system class name prefix on a name if needed (if class starts with @)
|
package/lib/layout.js
CHANGED
|
@@ -278,10 +278,17 @@ exports.ScrollView = ScrollView;
|
|
|
278
278
|
// https://medium.com/@andybarefoot/a-masonry-style-layout-using-css-grid-8c663d355ebb
|
|
279
279
|
class Masonry extends component_1.Container {
|
|
280
280
|
constructor(props) {
|
|
281
|
+
const items = props.items;
|
|
282
|
+
props.items = undefined;
|
|
281
283
|
super(props);
|
|
282
284
|
this.setDomEvent('sizechange', () => {
|
|
283
285
|
this.resizeAllItems();
|
|
284
286
|
});
|
|
287
|
+
if (items) {
|
|
288
|
+
items.forEach(i => {
|
|
289
|
+
this.addItem(i);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
285
292
|
}
|
|
286
293
|
resizeItem(item) {
|
|
287
294
|
const style = this.getComputedStyle();
|
package/lib/listview.d.ts
CHANGED
|
@@ -83,7 +83,7 @@ export interface ListViewProps<E extends ListViewEventMap = ListViewEventMap> ex
|
|
|
83
83
|
/**
|
|
84
84
|
* Standard listview class
|
|
85
85
|
*/
|
|
86
|
-
export declare class ListView
|
|
86
|
+
export declare class ListView extends VLayout<ListViewProps, ListViewEventMap> {
|
|
87
87
|
protected m_selection: {
|
|
88
88
|
item: ListViewItem;
|
|
89
89
|
citem: Component;
|
|
@@ -94,7 +94,7 @@ export declare class ListView<T extends ListViewProps = ListViewProps, E extends
|
|
|
94
94
|
protected m_topIndex: number;
|
|
95
95
|
protected m_itemHeight: number;
|
|
96
96
|
protected m_cache: Map<number, Component>;
|
|
97
|
-
constructor(props:
|
|
97
|
+
constructor(props: ListViewProps);
|
|
98
98
|
componentCreated(): void;
|
|
99
99
|
render(props: ListViewProps): void;
|
|
100
100
|
/**
|
package/lib/router.d.ts
CHANGED
|
@@ -26,9 +26,17 @@
|
|
|
26
26
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
|
-
|
|
29
|
+
import { EventSource, EvError, EventMap } from "./x4_events";
|
|
30
|
+
declare type RouteHandler = (params: any, path: string) => void;
|
|
31
|
+
interface RouterEventMap extends EventMap {
|
|
32
|
+
error: EvError;
|
|
33
|
+
}
|
|
34
|
+
export declare class Router extends EventSource<RouterEventMap> {
|
|
30
35
|
private routes;
|
|
31
36
|
constructor();
|
|
32
|
-
get(uri:
|
|
37
|
+
get(uri: string | RegExp, handler: RouteHandler): void;
|
|
33
38
|
init(): void;
|
|
39
|
+
navigate(uri: string, notify?: boolean): void;
|
|
40
|
+
private _find;
|
|
34
41
|
}
|
|
42
|
+
export {};
|
package/lib/router.js
CHANGED
|
@@ -29,31 +29,111 @@
|
|
|
29
29
|
**/
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
31
|
exports.Router = void 0;
|
|
32
|
-
|
|
32
|
+
const x4_events_1 = require("./x4_events");
|
|
33
|
+
function parseRoute(str, loose = false) {
|
|
34
|
+
if (str instanceof RegExp) {
|
|
35
|
+
return {
|
|
36
|
+
keys: null,
|
|
37
|
+
pattern: str
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const arr = str.split('/');
|
|
41
|
+
let keys = [];
|
|
42
|
+
let pattern = '';
|
|
43
|
+
if (arr[0] == '') {
|
|
44
|
+
arr.shift();
|
|
45
|
+
}
|
|
46
|
+
for (const tmp of arr) {
|
|
47
|
+
const c = tmp[0];
|
|
48
|
+
if (c === '*') {
|
|
49
|
+
keys.push('wild');
|
|
50
|
+
pattern += '/(.*)';
|
|
51
|
+
}
|
|
52
|
+
else if (c === ':') {
|
|
53
|
+
const o = tmp.indexOf('?', 1);
|
|
54
|
+
const ext = tmp.indexOf('.', 1);
|
|
55
|
+
keys.push(tmp.substring(1, o >= 0 ? o : ext >= 0 ? ext : tmp.length));
|
|
56
|
+
pattern += o < 0 && ext < 0 ? '(?:/([^/]+?))?' : '/([^/]+?)';
|
|
57
|
+
if (ext >= 0) {
|
|
58
|
+
pattern += (o >= 0 ? '?' : '') + '\\' + tmp.substring(ext);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
pattern += '/' + tmp;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
keys,
|
|
67
|
+
pattern: new RegExp(`^${pattern}${loose ? '(?=$|\/)' : '\/?$'}`, 'i')
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
class Router extends x4_events_1.EventSource {
|
|
33
71
|
routes;
|
|
34
72
|
constructor() {
|
|
73
|
+
super();
|
|
35
74
|
this.routes = [];
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
this.routes.push({
|
|
45
|
-
uri,
|
|
46
|
-
callback
|
|
75
|
+
window.addEventListener('popstate', (event) => {
|
|
76
|
+
const url = document.location.pathname;
|
|
77
|
+
const found = this._find(url);
|
|
78
|
+
found.handlers.forEach(h => {
|
|
79
|
+
h(found.params, url);
|
|
80
|
+
});
|
|
47
81
|
});
|
|
48
82
|
}
|
|
83
|
+
get(uri, handler) {
|
|
84
|
+
let { keys, pattern } = parseRoute(uri);
|
|
85
|
+
this.routes.push({ keys, pattern, handler });
|
|
86
|
+
}
|
|
49
87
|
init() {
|
|
50
|
-
this.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
88
|
+
this.navigate(window.location.pathname);
|
|
89
|
+
}
|
|
90
|
+
navigate(uri, notify = true) {
|
|
91
|
+
const found = this._find(uri);
|
|
92
|
+
if (!found || found.handlers.length == 0) {
|
|
93
|
+
//window.history.pushState({}, '', 'error')
|
|
94
|
+
console.log('route not found: ' + uri);
|
|
95
|
+
this.signal("error", (0, x4_events_1.EvError)(404, "route not found"));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
window.history.pushState({}, '', uri);
|
|
99
|
+
if (notify) {
|
|
100
|
+
found.handlers.forEach(h => {
|
|
101
|
+
h(found.params, uri);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
_find(url) {
|
|
106
|
+
let matches = [];
|
|
107
|
+
let params = {};
|
|
108
|
+
let handlers = [];
|
|
109
|
+
for (const tmp of this.routes) {
|
|
110
|
+
if (!tmp.keys) {
|
|
111
|
+
matches = tmp.pattern.exec(url);
|
|
112
|
+
if (!matches) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (matches['groups']) {
|
|
116
|
+
for (const k in matches['groups']) {
|
|
117
|
+
params[k] = matches['groups'][k];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
handlers = [...handlers, tmp.handler];
|
|
55
121
|
}
|
|
56
|
-
|
|
122
|
+
else if (tmp.keys.length > 0) {
|
|
123
|
+
matches = tmp.pattern.exec(url);
|
|
124
|
+
if (matches === null) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
for (let j = 0; j < tmp.keys.length;) {
|
|
128
|
+
params[tmp.keys[j]] = matches[++j];
|
|
129
|
+
}
|
|
130
|
+
handlers = [...handlers, tmp.handler];
|
|
131
|
+
}
|
|
132
|
+
else if (tmp.pattern.test(url)) {
|
|
133
|
+
handlers = [...handlers, tmp.handler];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { params, handlers };
|
|
57
137
|
}
|
|
58
138
|
}
|
|
59
139
|
exports.Router = Router;
|
package/lib/tabbar.d.ts
CHANGED
|
@@ -48,9 +48,11 @@ export declare class TabBar extends Container<TabBarProps, TabBarEventMap> {
|
|
|
48
48
|
private m_pages;
|
|
49
49
|
private m_curPage;
|
|
50
50
|
constructor(props: TabBarProps);
|
|
51
|
+
componentCreated(): void;
|
|
51
52
|
addPage(page: ITabPage): void;
|
|
52
53
|
render(): void;
|
|
53
|
-
select(id: string): void;
|
|
54
|
+
select(id: string | null, notify?: boolean): void;
|
|
54
55
|
private _select;
|
|
56
|
+
get selection(): Component<CProps<import("./base_component").BaseComponentEventMap>, import("./base_component").BaseComponentEventMap>;
|
|
55
57
|
}
|
|
56
58
|
export {};
|
package/lib/tabbar.js
CHANGED
|
@@ -47,8 +47,10 @@ class TabBar extends component_1.Container {
|
|
|
47
47
|
this.addClass('@hlayout');
|
|
48
48
|
}
|
|
49
49
|
this.m_props.pages?.forEach(p => this.addPage(p));
|
|
50
|
+
}
|
|
51
|
+
componentCreated() {
|
|
50
52
|
if (this.m_props.default) {
|
|
51
|
-
this.select(this.m_props.default);
|
|
53
|
+
this.select(this.m_props.default, true);
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
addPage(page) {
|
|
@@ -58,28 +60,45 @@ class TabBar extends component_1.Container {
|
|
|
58
60
|
render() {
|
|
59
61
|
let buttons = [];
|
|
60
62
|
this.m_pages.forEach(p => {
|
|
61
|
-
p.btn = new button_1.Button({ cls: p === this.m_curPage ? 'selected' : '', text: p.title, icon: p.icon, click: () => this._select(p) });
|
|
63
|
+
p.btn = new button_1.Button({ cls: p === this.m_curPage ? 'selected' : '', text: p.title, icon: p.icon, click: () => this._select(p, true) });
|
|
62
64
|
buttons.push(p.btn);
|
|
63
65
|
});
|
|
64
66
|
this.setContent(buttons);
|
|
65
67
|
}
|
|
66
|
-
select(id) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
select(id, notify = false) {
|
|
69
|
+
if (!id) {
|
|
70
|
+
this._select(null, notify);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
let page = this.m_pages.find(x => x.id === id);
|
|
74
|
+
if (page) {
|
|
75
|
+
this._select(page, notify);
|
|
76
|
+
}
|
|
70
77
|
}
|
|
71
78
|
}
|
|
72
|
-
_select(p) {
|
|
73
|
-
if (this.
|
|
79
|
+
_select(p, notify) {
|
|
80
|
+
if (this.m_curPage == p) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (this.dom && this.m_curPage) {
|
|
74
84
|
this.m_curPage.btn.removeClass('selected');
|
|
75
|
-
this.m_curPage.page
|
|
85
|
+
if (this.m_curPage.page) {
|
|
86
|
+
this.m_curPage.page.hide();
|
|
87
|
+
}
|
|
76
88
|
}
|
|
77
89
|
this.m_curPage = p;
|
|
78
|
-
|
|
79
|
-
|
|
90
|
+
if (notify) {
|
|
91
|
+
this.signal('change', (0, x4_events_1.EvChange)(p ? p.id : null));
|
|
92
|
+
}
|
|
93
|
+
if (this.dom && this.m_curPage) {
|
|
80
94
|
this.m_curPage.btn.addClass('selected');
|
|
81
|
-
this.m_curPage.page
|
|
95
|
+
if (this.m_curPage.page) {
|
|
96
|
+
this.m_curPage.page.show();
|
|
97
|
+
}
|
|
82
98
|
}
|
|
83
99
|
}
|
|
100
|
+
get selection() {
|
|
101
|
+
return this.m_curPage?.page;
|
|
102
|
+
}
|
|
84
103
|
}
|
|
85
104
|
exports.TabBar = TabBar;
|
package/lib/x4_events.d.ts
CHANGED
|
@@ -106,6 +106,14 @@ export interface EvDrag extends BasicEvent {
|
|
|
106
106
|
data: any;
|
|
107
107
|
}
|
|
108
108
|
export declare function EvDrag(element: unknown, data: any, ctx: any): EvDrag;
|
|
109
|
+
/**
|
|
110
|
+
* Errors
|
|
111
|
+
*/
|
|
112
|
+
export interface EvError extends BasicEvent {
|
|
113
|
+
code: number;
|
|
114
|
+
message: string;
|
|
115
|
+
}
|
|
116
|
+
export declare function EvError(code: number, message: string): EvError;
|
|
109
117
|
/**
|
|
110
118
|
* this Base interface is used to describe available events & their types
|
|
111
119
|
*
|
package/lib/x4_events.js
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
29
29
|
**/
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
-
exports.EventSource = exports.EvDrag = exports.EvMessage = exports.EvTimer = exports.EvContextMenu = exports.EvSelectionChange = exports.EvChange = exports.EvClick = exports.BasicEvent = void 0;
|
|
31
|
+
exports.EventSource = exports.EvError = exports.EvDrag = exports.EvMessage = exports.EvTimer = exports.EvContextMenu = exports.EvSelectionChange = exports.EvChange = exports.EvClick = exports.BasicEvent = void 0;
|
|
32
32
|
// default stopPropagation implementation for Events
|
|
33
33
|
const stopPropagation = function () {
|
|
34
34
|
this.propagationStopped = true;
|
|
@@ -81,6 +81,10 @@ function EvDrag(element, data, ctx) {
|
|
|
81
81
|
return BasicEvent({ element, data, context: ctx });
|
|
82
82
|
}
|
|
83
83
|
exports.EvDrag = EvDrag;
|
|
84
|
+
function EvError(code, message) {
|
|
85
|
+
return BasicEvent({ code, message });
|
|
86
|
+
}
|
|
87
|
+
exports.EvError = EvError;
|
|
84
88
|
/**
|
|
85
89
|
* Event emitter class
|
|
86
90
|
* this class allow you to emit and handle events
|
package/package.json
CHANGED
package/src/component.ts
CHANGED
|
@@ -188,7 +188,7 @@ export class Component<P extends CProps<BaseComponentEventMap> = CProps<BaseComp
|
|
|
188
188
|
private static __privateEvents: any = {};
|
|
189
189
|
private static __sizeObserver: ResizeObserver; // resize observer
|
|
190
190
|
private static __createObserver: MutationObserver; // creation observer
|
|
191
|
-
private static __intersectionObserver: IntersectionObserver; // visibility observer
|
|
191
|
+
//private static __intersectionObserver: IntersectionObserver; // visibility observer
|
|
192
192
|
|
|
193
193
|
private static __capture: ICaptureInfo = null;
|
|
194
194
|
private static __capture_mask = null;
|
|
@@ -202,6 +202,11 @@ export class Component<P extends CProps<BaseComponentEventMap> = CProps<BaseComp
|
|
|
202
202
|
dom_events: {},
|
|
203
203
|
uid: Component.__comp_guid++,
|
|
204
204
|
inrender: false,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// prepare iprops
|
|
208
|
+
if( this.m_props.cls ) {
|
|
209
|
+
this.addClass( this.m_props.cls );
|
|
205
210
|
}
|
|
206
211
|
}
|
|
207
212
|
|
|
@@ -1389,7 +1394,8 @@ export class Component<P extends CProps<BaseComponentEventMap> = CProps<BaseComp
|
|
|
1389
1394
|
me = Object.getPrototypeOf(me);
|
|
1390
1395
|
}
|
|
1391
1396
|
|
|
1392
|
-
|
|
1397
|
+
//done in ctor now
|
|
1398
|
+
//this.addClass(this.m_props.cls);
|
|
1393
1399
|
}
|
|
1394
1400
|
|
|
1395
1401
|
/**
|
package/src/layout.ts
CHANGED
|
@@ -378,11 +378,20 @@ export class ScrollView extends Component<ScrollViewProps> {
|
|
|
378
378
|
export class Masonry extends Container {
|
|
379
379
|
|
|
380
380
|
constructor(props) {
|
|
381
|
+
const items = props.items;
|
|
382
|
+
props.items = undefined;
|
|
383
|
+
|
|
381
384
|
super(props);
|
|
382
385
|
|
|
383
386
|
this.setDomEvent('sizechange', () => {
|
|
384
387
|
this.resizeAllItems( );
|
|
385
388
|
});
|
|
389
|
+
|
|
390
|
+
if( items ) {
|
|
391
|
+
items.forEach( i => {
|
|
392
|
+
this.addItem( i );
|
|
393
|
+
});
|
|
394
|
+
}
|
|
386
395
|
}
|
|
387
396
|
|
|
388
397
|
resizeItem(item: Component) {
|
package/src/listview.ts
CHANGED
|
@@ -100,7 +100,7 @@ export interface ListViewProps<E extends ListViewEventMap = ListViewEventMap> ex
|
|
|
100
100
|
* Standard listview class
|
|
101
101
|
*/
|
|
102
102
|
|
|
103
|
-
export class ListView
|
|
103
|
+
export class ListView extends VLayout<ListViewProps,ListViewEventMap> {
|
|
104
104
|
|
|
105
105
|
protected m_selection: {
|
|
106
106
|
item: ListViewItem;
|
|
@@ -117,7 +117,7 @@ export class ListView<T extends ListViewProps = ListViewProps, E extends ListVie
|
|
|
117
117
|
|
|
118
118
|
protected m_cache: Map<number, Component>; // recycling elements
|
|
119
119
|
|
|
120
|
-
constructor(props:
|
|
120
|
+
constructor(props: ListViewProps) {
|
|
121
121
|
super(props);
|
|
122
122
|
|
|
123
123
|
this.setDomEvent('keydown', (e) => this._handleKey(e));
|
package/src/router.ts
CHANGED
|
@@ -27,45 +27,157 @@
|
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
import { EventSource, EvError, EventMap } from "./x4_events"
|
|
31
|
+
|
|
32
|
+
type RouteHandler = ( params: any, path: string ) => void;
|
|
33
|
+
|
|
34
|
+
interface Segment {
|
|
35
|
+
keys: string[],
|
|
36
|
+
pattern: RegExp;
|
|
37
|
+
}
|
|
31
38
|
|
|
32
39
|
interface Route {
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
keys: string[],
|
|
41
|
+
pattern: RegExp;
|
|
42
|
+
handler: RouteHandler;
|
|
35
43
|
}
|
|
36
44
|
|
|
37
|
-
|
|
45
|
+
function parseRoute(str: string | RegExp, loose = false): Segment {
|
|
38
46
|
|
|
39
|
-
|
|
47
|
+
if (str instanceof RegExp) {
|
|
48
|
+
return {
|
|
49
|
+
keys: null,
|
|
50
|
+
pattern: str
|
|
51
|
+
};
|
|
52
|
+
}
|
|
40
53
|
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
const arr = str.split('/');
|
|
55
|
+
|
|
56
|
+
let keys = [];
|
|
57
|
+
let pattern = '';
|
|
58
|
+
|
|
59
|
+
if( arr[0]=='' ) {
|
|
60
|
+
arr.shift();
|
|
43
61
|
}
|
|
44
62
|
|
|
45
|
-
|
|
63
|
+
for (const tmp of arr) {
|
|
64
|
+
const c = tmp[0];
|
|
46
65
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
66
|
+
if (c === '*') {
|
|
67
|
+
keys.push('wild');
|
|
68
|
+
pattern += '/(.*)';
|
|
69
|
+
}
|
|
70
|
+
else if (c === ':') {
|
|
71
|
+
const o = tmp.indexOf('?', 1);
|
|
72
|
+
const ext = tmp.indexOf('.', 1);
|
|
73
|
+
|
|
74
|
+
keys.push(tmp.substring(1, o >= 0 ? o : ext >= 0 ? ext : tmp.length));
|
|
75
|
+
pattern += o < 0 && ext < 0 ? '(?:/([^/]+?))?' : '/([^/]+?)';
|
|
76
|
+
if (ext >= 0) {
|
|
77
|
+
pattern += (o >= 0 ? '?' : '') + '\\' + tmp.substring(ext);
|
|
51
78
|
}
|
|
52
|
-
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
pattern += '/' + tmp;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
keys,
|
|
87
|
+
pattern: new RegExp( `^${pattern}${loose ? '(?=$|\/)' : '\/?$'}`, 'i' )
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface RouterEventMap extends EventMap {
|
|
92
|
+
error: EvError;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export class Router extends EventSource< RouterEventMap > {
|
|
96
|
+
|
|
97
|
+
private routes: Route[];
|
|
53
98
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
99
|
+
constructor() {
|
|
100
|
+
super( );
|
|
101
|
+
|
|
102
|
+
this.routes = [];
|
|
103
|
+
|
|
104
|
+
window.addEventListener('popstate', (event) => {
|
|
105
|
+
const url = document.location.pathname;
|
|
106
|
+
const found = this._find(url);
|
|
107
|
+
|
|
108
|
+
found.handlers.forEach(h => {
|
|
109
|
+
h(found.params,url);
|
|
110
|
+
});
|
|
57
111
|
});
|
|
58
112
|
}
|
|
59
113
|
|
|
114
|
+
get(uri: string | RegExp, handler: RouteHandler ) {
|
|
115
|
+
let { keys, pattern } = parseRoute(uri);
|
|
116
|
+
this.routes.push({ keys, pattern, handler });
|
|
117
|
+
}
|
|
118
|
+
|
|
60
119
|
init() {
|
|
61
|
-
this.
|
|
120
|
+
this.navigate( window.location.pathname );
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
navigate( uri: string, notify = true ) {
|
|
124
|
+
|
|
125
|
+
const found = this._find( uri );
|
|
62
126
|
|
|
63
|
-
|
|
64
|
-
|
|
127
|
+
if( !found || found.handlers.length==0 ) {
|
|
128
|
+
//window.history.pushState({}, '', 'error')
|
|
129
|
+
console.log( 'route not found: '+uri );
|
|
130
|
+
this.signal( "error", EvError( 404, "route not found" ) );
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
65
133
|
|
|
66
|
-
|
|
67
|
-
|
|
134
|
+
window.history.pushState({}, '', uri )
|
|
135
|
+
|
|
136
|
+
if( notify ) {
|
|
137
|
+
found.handlers.forEach( h => {
|
|
138
|
+
h( found.params, uri );
|
|
139
|
+
} );
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private _find( url: string ): { params: any, handlers: RouteHandler[] } {
|
|
144
|
+
|
|
145
|
+
let matches = [];
|
|
146
|
+
let params = {};
|
|
147
|
+
let handlers = [];
|
|
148
|
+
|
|
149
|
+
for (const tmp of this.routes ) {
|
|
150
|
+
if (!tmp.keys ) {
|
|
151
|
+
matches = tmp.pattern.exec(url);
|
|
152
|
+
if (!matches) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (matches['groups']) {
|
|
157
|
+
for (const k in matches['groups']) {
|
|
158
|
+
params[k] = matches['groups'][k];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
handlers = [...handlers, tmp.handler];
|
|
163
|
+
}
|
|
164
|
+
else if (tmp.keys.length > 0) {
|
|
165
|
+
matches = tmp.pattern.exec(url);
|
|
166
|
+
if (matches === null) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for ( let j = 0; j < tmp.keys.length;) {
|
|
171
|
+
params[tmp.keys[j]] = matches[++j];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
handlers = [...handlers, tmp.handler];
|
|
175
|
+
}
|
|
176
|
+
else if (tmp.pattern.test(url)) {
|
|
177
|
+
handlers = [...handlers, tmp.handler];
|
|
68
178
|
}
|
|
69
|
-
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return { params, handlers };
|
|
70
182
|
}
|
|
71
183
|
}
|
package/src/tabbar.ts
CHANGED
|
@@ -75,9 +75,12 @@ export class TabBar extends Container<TabBarProps,TabBarEventMap> {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
this.m_props.pages?.forEach( p => this.addPage(p) );
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
componentCreated(): void {
|
|
78
81
|
if( this.m_props.default ) {
|
|
79
|
-
this.select( this.m_props.default );
|
|
80
|
-
}
|
|
82
|
+
this.select( this.m_props.default, true );
|
|
83
|
+
}
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
addPage( page: ITabPage ) {
|
|
@@ -88,33 +91,53 @@ export class TabBar extends Container<TabBarProps,TabBarEventMap> {
|
|
|
88
91
|
render( ) {
|
|
89
92
|
let buttons = [];
|
|
90
93
|
this.m_pages.forEach( p => {
|
|
91
|
-
p.btn = new Button( { cls: p===this.m_curPage ? 'selected' : '', text: p.title, icon: p.icon, click: () => this._select(p) } );
|
|
94
|
+
p.btn = new Button( { cls: p===this.m_curPage ? 'selected' : '', text: p.title, icon: p.icon, click: () => this._select(p,true) } );
|
|
92
95
|
buttons.push( p.btn );
|
|
93
96
|
});
|
|
94
97
|
|
|
95
98
|
this.setContent( buttons );
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
select( id: string ) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
select( id: string | null, notify = false ) {
|
|
102
|
+
if( !id ) {
|
|
103
|
+
this._select( null, notify );
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
let page = this.m_pages.find( x => x.id===id );
|
|
107
|
+
if( page ) {
|
|
108
|
+
this._select( page, notify );
|
|
109
|
+
}
|
|
102
110
|
}
|
|
103
111
|
}
|
|
104
112
|
|
|
105
|
-
private _select( p: TabPage ) {
|
|
113
|
+
private _select( p: TabPage, notify: boolean ) {
|
|
106
114
|
|
|
107
|
-
if( this.
|
|
115
|
+
if( this.m_curPage==p ) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if( this.dom && this.m_curPage ) {
|
|
108
120
|
this.m_curPage.btn.removeClass( 'selected' );
|
|
109
|
-
this.m_curPage.page
|
|
121
|
+
if( this.m_curPage.page ) {
|
|
122
|
+
this.m_curPage.page.hide( );
|
|
123
|
+
}
|
|
110
124
|
}
|
|
111
125
|
|
|
112
126
|
this.m_curPage = p;
|
|
113
|
-
this.signal( 'change', EvChange(p ? p.id : null) );
|
|
114
127
|
|
|
115
|
-
if(
|
|
128
|
+
if( notify ) {
|
|
129
|
+
this.signal( 'change', EvChange(p ? p.id : null) );
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if( this.dom && this.m_curPage ) {
|
|
116
133
|
this.m_curPage.btn.addClass( 'selected' );
|
|
117
|
-
this.m_curPage.page
|
|
134
|
+
if( this.m_curPage.page ) {
|
|
135
|
+
this.m_curPage.page.show( );
|
|
136
|
+
}
|
|
118
137
|
}
|
|
119
138
|
}
|
|
139
|
+
|
|
140
|
+
get selection( ) {
|
|
141
|
+
return this.m_curPage?.page;
|
|
142
|
+
}
|
|
120
143
|
}
|
package/src/x4_events.ts
CHANGED
|
@@ -168,6 +168,19 @@ export function EvDrag(element: unknown, data: any, ctx: any ) {
|
|
|
168
168
|
return BasicEvent<EvDrag>({ element, data, context: ctx });
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Errors
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
export interface EvError extends BasicEvent {
|
|
176
|
+
code: number;
|
|
177
|
+
message: string;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function EvError( code: number, message: string ) : EvError {
|
|
181
|
+
return BasicEvent<EvError>( {code, message} );
|
|
182
|
+
}
|
|
183
|
+
|
|
171
184
|
|
|
172
185
|
/**
|
|
173
186
|
* this Base interface is used to describe available events & their types
|