x4js 1.5.23 → 1.5.25

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.
@@ -33,6 +33,7 @@ import { BaseComponent, BaseComponentEventMap, BaseComponentProps } from './base
33
33
  import { Component, flyWrap } from './component'
34
34
  import { Settings } from './settings'
35
35
  import { _tr } from './i18n'
36
+ import { Router } from 'x4js'
36
37
 
37
38
  const _x4_touch_time = Symbol( );
38
39
 
@@ -97,6 +98,8 @@ export class Application<P extends ApplicationProps = ApplicationProps, E extend
97
98
 
98
99
  private m_touch_time: number;
99
100
  private m_touch_count: number;
101
+
102
+ private m_router: Router;
100
103
 
101
104
  constructor( props : P ) {
102
105
  console.assert( Application.self===null, 'application is a singleton' );
@@ -112,8 +115,9 @@ export class Application<P extends ApplicationProps = ApplicationProps, E extend
112
115
 
113
116
  this.m_touch_time = 0;
114
117
  this.m_touch_count = 0;
118
+ this.m_router = null;
115
119
 
116
- (Application.self as any) = this;
120
+ x4app = (Application.self as any) = this;
117
121
 
118
122
  if( 'onload' in globalThis ) {
119
123
  globalThis.addEventListener( 'load', ( ) => {
@@ -129,6 +133,13 @@ export class Application<P extends ApplicationProps = ApplicationProps, E extend
129
133
  this.setTitle( '' );
130
134
  }
131
135
 
136
+ public get router( ) {
137
+ if( !this.m_router ) {
138
+ this.m_router = new Router( );
139
+ }
140
+ return this.m_router;
141
+ }
142
+
132
143
  public get app_name( ) {
133
144
  return this.m_app_name;
134
145
  }
@@ -247,5 +258,5 @@ export class Application<P extends ApplicationProps = ApplicationProps, E extend
247
258
  }
248
259
  };
249
260
 
250
-
261
+ export let x4app: Application;
251
262
 
@@ -174,6 +174,7 @@ interface CInternalProps {
174
174
  dom_events: any;
175
175
  classes: IMap<boolean>;
176
176
  uid: number;
177
+ created: boolean;
177
178
  inrender: boolean;
178
179
  }
179
180
 
@@ -891,6 +892,18 @@ export class Component<P extends CProps<CEventMap> = CProps<CEventMap>, E extend
891
892
 
892
893
  // notify descendants that we have been created (dom exists)
893
894
 
895
+ const notify = ( c: Component ) => {
896
+
897
+ if( !c.m_iprops.created ) {
898
+ if (c.dom && c.m_iprops.dom_events && c.m_iprops.dom_events.create) {
899
+ c.dom.dispatchEvent(new Event('create'));
900
+ }
901
+
902
+ c.componentCreated();
903
+ c.m_iprops.created = true;
904
+ }
905
+ }
906
+
894
907
  for (let mutation of mutations) {
895
908
 
896
909
  if (mutation.type == 'childList') {
@@ -902,24 +915,16 @@ export class Component<P extends CProps<CEventMap> = CProps<CEventMap>, E extend
902
915
 
903
916
  if (el) {
904
917
  el.enumChilds((c: Component) => {
905
-
906
- if (c.dom && c.m_iprops.dom_events && c.m_iprops.dom_events.create) {
907
- c.dom.dispatchEvent(new Event('create'));
908
- }
909
-
910
- c.componentCreated();
911
-
918
+ notify( c );
912
919
  }, true);
913
920
 
914
- if (el.m_iprops.dom_events && el.m_iprops.dom_events.create) {
915
- el.dom.dispatchEvent(new Event('create'));
916
- }
917
-
918
- el.componentCreated();
921
+ notify( el );
919
922
  }
920
923
  }
921
924
  }
922
925
  }
926
+
927
+
923
928
  }
924
929
 
925
930
  public dispose() {
@@ -953,6 +958,7 @@ export class Component<P extends CProps<CEventMap> = CProps<CEventMap>, E extend
953
958
  }
954
959
 
955
960
  this.componentDisposed();
961
+ this.m_iprops.created = false;
956
962
  // todo: pb on update this.removeAllListeners( null );
957
963
  }
958
964
 
@@ -39,7 +39,6 @@ export type FieldType = 'string' | 'int' | 'float' | 'date' | 'bool' | 'array' |
39
39
  export type DataIndex = Uint32Array;
40
40
 
41
41
  interface EvDataChange extends BasicEvent {
42
-
43
42
  type: string;
44
43
  id: any;
45
44
  }
@@ -49,6 +48,8 @@ function EvDataChange( type: 'create' | 'update' | 'delete' | 'data' | 'change',
49
48
  }
50
49
 
51
50
 
51
+
52
+
52
53
  /**
53
54
  * fields definition
54
55
  * field with index=0 is record id
@@ -553,55 +554,55 @@ interface DataEventMap extends BaseComponentEventMap {
553
554
  change?: EvChange;
554
555
  }
555
556
 
557
+ type DataSolver = ( data: any ) => Record[];
558
+
556
559
  export interface DataProxyProps extends BaseComponentProps<DataEventMap> {
557
- type: 'local' | 'immediate' | 'ajax';
558
- path?: string;
559
- params?: any;
560
+ url: string;
561
+ params?: string[];
562
+ solver?: DataSolver;
560
563
  }
561
564
 
562
565
  export class DataProxy extends BaseComponent<DataProxyProps,DataEventMap> {
563
-
566
+
564
567
  constructor( props: DataProxyProps ) {
565
568
  super( props );
566
569
  }
567
570
 
568
- load( ) {
571
+ load( url?: string ) {
572
+ if( url ) {
573
+ this.m_props.url = url;
574
+ }
575
+
569
576
  this._refresh( );
570
577
  }
571
578
 
572
- save( data ) {
573
- if( this.m_props.type=='local' ) {
574
- console.assert( false ); // not imp
575
- /*
576
- const fs = require('fs');
577
- fs.writeFileSync( this.m_path, data );
578
- */
579
- }
580
- }
581
-
582
579
  private _refresh( delay: number = 0 ) {
583
580
 
584
- if( this.m_props.type=='local' ) {
585
- console.assert( false ); // not imp
586
- /*
587
- const fs = require('fs');
588
- fs.readFile( this.m_path, ( _, bdata ) => {;
589
- let data = JSON.parse(bdata);
590
- this.emit( 'dataready', data );
591
- } );
592
- */
581
+ const load = async ( ) => {
582
+
583
+ let url = this.m_props.url;
584
+ if( this.m_props.params ) {
585
+ url += '?' + this.m_props.params.join( '&' );
586
+ }
587
+
588
+ const r = await fetch( url );
589
+ if( r.ok ) {
590
+ const raw = await r.json( );
591
+
592
+ let json = raw;
593
+ if( this.m_props.solver ) {
594
+ json = this.m_props.solver( json );
595
+ }
596
+
597
+ this.emit( 'change', EvChange(json,raw) );
598
+ }
599
+ }
600
+
601
+ if( delay ) {
602
+ setTimeout( load, delay );
593
603
  }
594
604
  else {
595
- setTimeout( ( ) => {
596
- ajaxRequest( {
597
- url: this.m_props.path,
598
- method: 'GET',
599
- params: this.m_props.params,
600
- success: ( data ) => {
601
- this.emit( 'change', EvChange(data) );
602
- }
603
- });
604
- }, delay );
605
+ load( );
605
606
  }
606
607
  }
607
608
  }
@@ -650,7 +651,13 @@ export class DataStore extends EventSource<DataStoreEventMap> {
650
651
  this.setRawData( props.data );
651
652
  }
652
653
  else if( props.url ) {
653
- this.load( props.url );
654
+ this.m_proxy = new DataProxy( {
655
+ url: props.url,
656
+ solver: props.solver,
657
+ events: { change: (ev) => { this.setData( ev.value ); } }
658
+ });
659
+
660
+ this.m_proxy.load( );
654
661
  }
655
662
  }
656
663
 
@@ -659,27 +666,8 @@ export class DataStore extends EventSource<DataStoreEventMap> {
659
666
  * @param records
660
667
  */
661
668
 
662
- load( url: string ) {
663
-
664
- //todo: that
665
- if( url.substr(0,7)==='file://' ) {
666
- this.m_proxy = new DataProxy( {
667
- type: 'local',
668
- path: url.substr( 7 ),
669
- events: { change: (ev) => { this.setData( ev.value ); } }
670
- });
671
-
672
- this.m_proxy.load( );
673
- }
674
- else {
675
- this.m_proxy = new DataProxy( {
676
- type: 'ajax',
677
- path: url,
678
- events: { change: (ev) => { this.setData( ev.value ); } }
679
- });
680
-
681
- this.m_proxy.load( );
682
- }
669
+ load( url?: string ) {
670
+ this.m_proxy.load( url );
683
671
  }
684
672
 
685
673
  reload( ) {
@@ -34,7 +34,12 @@ import { Point } from './tools';
34
34
 
35
35
  const x_drag_cb = Symbol( 'x-drag-cb' );
36
36
 
37
- type DropCallback = ( command: 'enter' | 'leave' | 'drag' | 'drop', el: Component, point: Point ) => void;
37
+ interface DropInfo {
38
+ pt: Point;
39
+ data: DataTransfer;
40
+ }
41
+
42
+ type DropCallback = ( command: 'enter' | 'leave' | 'drag' | 'drop', el: Component, infos: DropInfo ) => void;
38
43
  type FilterCallback = ( el: Component ) => boolean;
39
44
 
40
45
  /**
@@ -91,10 +96,10 @@ class DragManager {
91
96
  *
92
97
  */
93
98
 
94
- registerDropTarget(el: Component, cb: DropCallback, filterCB: FilterCallback ) {
99
+ registerDropTarget(el: Component, cb: DropCallback, filterCB?: FilterCallback ) {
95
100
 
96
101
  const dragEnter = (ev: DragEvent) => {
97
- if( !filterCB(this.dragSource) ) {
102
+ if( filterCB && !filterCB(this.dragSource) ) {
98
103
  console.log( 'reject ', el );
99
104
  ev.dataTransfer.dropEffect = 'none';
100
105
  return;
@@ -108,7 +113,7 @@ class DragManager {
108
113
  const dragOver = (ev: DragEvent) => {
109
114
  //console.log( "dragover", ev.target );
110
115
 
111
- if( !filterCB(this.dragSource) ) {
116
+ if( filterCB && !filterCB(this.dragSource) ) {
112
117
  console.log( 'reject ', el );
113
118
  ev.dataTransfer.dropEffect = 'none';
114
119
  return;
@@ -122,7 +127,12 @@ class DragManager {
122
127
  }
123
128
 
124
129
  if( this.dropTarget ) {
125
- cb( 'drag', this.dragSource, {x:ev.pageX,y:ev.pageY} );
130
+ const infos = {
131
+ pt: new Point( ev.pageX, ev.pageY ),
132
+ data: ev.dataTransfer,
133
+ }
134
+
135
+ cb( 'drag', this.dragSource, infos );
126
136
  }
127
137
 
128
138
  ev.dataTransfer.dropEffect = 'copy';
@@ -135,10 +145,17 @@ class DragManager {
135
145
  };
136
146
 
137
147
  const drop = (ev: DragEvent) => {
138
- cb('drop', this.dragSource, {x:ev.pageX,y:ev.pageY} );
148
+ const infos = {
149
+ pt: new Point( ev.pageX, ev.pageY ),
150
+ data: ev.dataTransfer,
151
+ }
152
+
153
+ cb('drop', this.dragSource, infos );
139
154
 
140
155
  this.dropTarget = null;
141
156
  el.removeClass('drop-over');
157
+
158
+ ev.preventDefault();
142
159
  }
143
160
 
144
161
  el.setDomEvent('dragenter', dragEnter);
package/lib/src/layout.ts CHANGED
@@ -153,7 +153,8 @@ interface CellData {
153
153
  width?: number;
154
154
  height?: number;
155
155
  cls?: string;
156
- item: ComponentContent;
156
+ item?: ComponentContent;
157
+ data?: any;
157
158
  }
158
159
 
159
160
  export class TableLayout extends Container<TableLayoutProps> {
@@ -204,6 +205,17 @@ export class TableLayout extends Container<TableLayoutProps> {
204
205
  this._setCell(row, col, cell, true);
205
206
  }
206
207
 
208
+ setCellData(row: number, col: number, data: any ) {
209
+ let cell = this._getCell(row, col);
210
+ cell.data = data;
211
+ this._setCell(row, col, cell, true);
212
+ }
213
+
214
+ getCellData(row: number, col: number ) {
215
+ let cell = this._getCell(row, col, false);
216
+ return cell?.data;
217
+ }
218
+
207
219
  merge(row: number, col: number, rowCount: number, colCount: number) {
208
220
  let cell = this._getCell(row, col);
209
221
  cell.rowSpan = rowCount;
package/lib/src/router.ts CHANGED
@@ -93,18 +93,46 @@ function parseRoute(str: string | RegExp, loose = false): Segment {
93
93
  interface RouterEventMap extends EventMap {
94
94
  error: EvError;
95
95
  }
96
-
96
+
97
+
98
+ /**
99
+ * micro router
100
+ *
101
+ * ```
102
+ * const router = new Router( );
103
+ *
104
+ * router.get( "/detail/:id", ( params: any ) => {
105
+ * this._showDetail( detail );
106
+ * } );
107
+ *
108
+ * router.get( "/:id", ( params: any ) => {
109
+ * if( params.id==0 )
110
+ * router.navigate( '/home' );
111
+ * }
112
+ * });
113
+ *
114
+ * router.on( "error", ( ) => {
115
+ * router.navigate( '/home' );
116
+ * })
117
+ *
118
+ * router.init( );
119
+ * ```
120
+ */
121
+
122
+
97
123
  export class Router extends EventSource< RouterEventMap > {
98
124
 
99
- private routes: Route[];
125
+ private m_routes: Route[];
126
+ private m_useHash: boolean;
100
127
 
101
- constructor() {
128
+ constructor( useHash = true ) {
102
129
  super( );
103
130
 
104
- this.routes = [];
131
+ this.m_routes = [];
132
+ this.m_useHash = useHash;
105
133
 
106
134
  window.addEventListener('popstate', (event) => {
107
- const url = x4document.location.pathname;
135
+ const url = this._getLocation( );
108
136
  const found = this._find(url);
109
137
 
110
138
  found.handlers.forEach(h => {
@@ -115,15 +143,23 @@ export class Router extends EventSource< RouterEventMap > {
115
143
 
116
144
  get(uri: string | RegExp, handler: RouteHandler ) {
117
145
  let { keys, pattern } = parseRoute(uri);
118
- this.routes.push({ keys, pattern, handler });
146
+ this.m_routes.push({ keys, pattern, handler });
119
147
  }
120
148
 
121
149
  init() {
122
- this.navigate( window.location.pathname );
150
+ this.navigate( this._getLocation() );
151
+ }
152
+
153
+ private _getLocation( ) {
154
+ return this.m_useHash ? '/'+x4document.location.hash.substring(1) : x4document.location.pathname;
123
155
  }
124
156
 
125
157
  navigate( uri: string, notify = true ) {
126
158
 
159
+ if( !uri.startsWith('/') ) {
160
+ uri = '/'+uri;
161
+ }
162
+
127
163
  const found = this._find( uri );
128
164
 
129
165
  if( !found || found.handlers.length==0 ) {
@@ -133,7 +169,16 @@ export class Router extends EventSource< RouterEventMap > {
133
169
  return;
134
170
  }
135
171
 
136
- window.history.pushState({}, '', uri )
172
+ if( this.m_useHash ) {
173
+ while( uri.startsWith('/') ) {
174
+ uri = uri.substring( 1 );
175
+ }
176
+
177
+ window.history.pushState({}, '', '#'+uri );
178
+ }
179
+ else {
180
+ window.history.pushState({}, '', uri );
181
+ }
137
182
 
138
183
  if( notify ) {
139
184
  found.handlers.forEach( h => {
@@ -148,7 +193,7 @@ export class Router extends EventSource< RouterEventMap > {
148
193
  let params = {};
149
194
  let handlers = [];
150
195
 
151
- for (const tmp of this.routes ) {
196
+ for (const tmp of this.m_routes ) {
152
197
  if (!tmp.keys ) {
153
198
  matches = tmp.pattern.exec(url);
154
199
  if (!matches) {
@@ -27,4 +27,4 @@
27
27
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
28
  **/
29
29
 
30
- export const x4js_version = "1.5.23";
30
+ export const x4js_version = "1.5.25";
@@ -30,6 +30,7 @@ import { EvMessage } from './x4events';
30
30
  import { BaseComponent, BaseComponentEventMap, BaseComponentProps } from './base_component';
31
31
  import { Component } from './component';
32
32
  import { Settings } from './settings';
33
+ import { Router } from 'x4js';
33
34
  interface ApplicationEventMap extends BaseComponentEventMap {
34
35
  message: EvMessage;
35
36
  global: EvMessage;
@@ -77,8 +78,10 @@ export declare class Application<P extends ApplicationProps = ApplicationProps,
77
78
  private m_user_data;
78
79
  private m_touch_time;
79
80
  private m_touch_count;
81
+ private m_router;
80
82
  constructor(props: P);
81
83
  ApplicationCreated(): void;
84
+ get router(): Router;
82
85
  get app_name(): string;
83
86
  get app_uid(): string;
84
87
  get app_version(): string;
@@ -101,4 +104,5 @@ export declare class Application<P extends ApplicationProps = ApplicationProps,
101
104
  enterModal(enter: boolean): void;
102
105
  enableTouchDblClick(): void;
103
106
  }
107
+ export declare let x4app: Application;
104
108
  export {};
@@ -208,15 +208,15 @@ export declare class AutoRecord extends Record {
208
208
  interface DataEventMap extends BaseComponentEventMap {
209
209
  change?: EvChange;
210
210
  }
211
+ type DataSolver = (data: any) => Record[];
211
212
  export interface DataProxyProps extends BaseComponentProps<DataEventMap> {
212
- type: 'local' | 'immediate' | 'ajax';
213
- path?: string;
214
- params?: any;
213
+ url: string;
214
+ params?: string[];
215
+ solver?: DataSolver;
215
216
  }
216
217
  export declare class DataProxy extends BaseComponent<DataProxyProps, DataEventMap> {
217
218
  constructor(props: DataProxyProps);
218
- load(): void;
219
- save(data: any): void;
219
+ load(url?: string): void;
220
220
  private _refresh;
221
221
  }
222
222
  /**
@@ -244,7 +244,7 @@ export declare class DataStore extends EventSource<DataStoreEventMap> {
244
244
  *
245
245
  * @param records
246
246
  */
247
- load(url: string): void;
247
+ load(url?: string): void;
248
248
  reload(): void;
249
249
  /**
250
250
  * convert raw objects to real records from model
@@ -28,7 +28,11 @@
28
28
  **/
29
29
  import { Component } from './component';
30
30
  import { Point } from './tools';
31
- type DropCallback = (command: 'enter' | 'leave' | 'drag' | 'drop', el: Component, point: Point) => void;
31
+ interface DropInfo {
32
+ pt: Point;
33
+ data: DataTransfer;
34
+ }
35
+ type DropCallback = (command: 'enter' | 'leave' | 'drag' | 'drop', el: Component, infos: DropInfo) => void;
32
36
  type FilterCallback = (el: Component) => boolean;
33
37
  /**
34
38
  *
@@ -46,7 +50,7 @@ declare class DragManager {
46
50
  /**
47
51
  *
48
52
  */
49
- registerDropTarget(el: Component, cb: DropCallback, filterCB: FilterCallback): void;
53
+ registerDropTarget(el: Component, cb: DropCallback, filterCB?: FilterCallback): void;
50
54
  _startCheck(): void;
51
55
  _check(): void;
52
56
  }
@@ -63,6 +63,8 @@ export declare class TableLayout extends Container<TableLayoutProps> {
63
63
  private _getCell;
64
64
  private _setCell;
65
65
  setCell(row: number, col: number, item: ComponentContent): void;
66
+ setCellData(row: number, col: number, data: any): void;
67
+ getCellData(row: number, col: number): any;
66
68
  merge(row: number, col: number, rowCount: number, colCount: number): void;
67
69
  setCellWidth(row: number, col: number, width?: number): void;
68
70
  setCellHeight(row: number, col: number, height?: number): void;
@@ -31,11 +31,36 @@ type RouteHandler = (params: any, path: string) => void;
31
31
  interface RouterEventMap extends EventMap {
32
32
  error: EvError;
33
33
  }
34
+ /**
35
+ * micro router
36
+ *
37
+ * ```
38
+ * const router = new Router( );
39
+ *
40
+ * router.get( "/detail/:id", ( params: any ) => {
41
+ * this._showDetail( detail );
42
+ * } );
43
+ *
44
+ * router.get( "/:id", ( params: any ) => {
45
+ * if( params.id==0 )
46
+ * router.navigate( '/home' );
47
+ * }
48
+ * });
49
+ *
50
+ * router.on( "error", ( ) => {
51
+ * router.navigate( '/home' );
52
+ * })
53
+ *
54
+ * router.init( );
55
+ * ```
56
+ */
34
57
  export declare class Router extends EventSource<RouterEventMap> {
35
- private routes;
36
- constructor();
58
+ private m_routes;
59
+ private m_useHash;
60
+ constructor(useHash?: boolean);
37
61
  get(uri: string | RegExp, handler: RouteHandler): void;
38
62
  init(): void;
63
+ private _getLocation;
39
64
  navigate(uri: string, notify?: boolean): void;
40
65
  private _find;
41
66
  }
@@ -26,4 +26,4 @@
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
- export declare const x4js_version = "1.5.23";
29
+ export declare const x4js_version = "1.5.25";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x4js",
3
- "version": "1.5.23",
3
+ "version": "1.5.25",
4
4
  "description": "X4js core files",
5
5
  "main": "lib/cjs/index.js",
6
6
  "types": "lib/types/index.d.ts",