x4js 1.5.17 → 1.5.20
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/{README.md → README.txt} +0 -0
- package/lib/cjs/index.js +39 -103
- package/lib/cjs/index.js.map +7 -0
- package/lib/esm/index.mjs +39 -87
- package/lib/esm/index.mjs.map +7 -0
- package/lib/{license.md → licence.md} +0 -0
- package/lib/src/MIT-license.md +14 -0
- package/lib/{types/action.d.ts → src/action.ts} +64 -33
- package/lib/src/alpha.jpg +0 -0
- package/lib/src/app_sockets.ts +81 -0
- package/lib/src/application.ts +251 -0
- package/lib/src/autocomplete.ts +197 -0
- package/lib/src/base64.ts +166 -0
- package/lib/src/base_component.ts +152 -0
- package/lib/src/button.ts +355 -0
- package/lib/src/calendar.ts +328 -0
- package/lib/src/canvas.ts +505 -0
- package/lib/src/cardview.ts +227 -0
- package/lib/src/checkbox.ts +188 -0
- package/lib/src/color.ts +752 -0
- package/lib/src/colorpicker.ts +1639 -0
- package/lib/src/combobox.ts +465 -0
- package/lib/src/component.ts +2329 -0
- package/lib/{esm/dom_events.js → src/copyright.txt} +27 -29
- package/lib/src/datastore.ts +1322 -0
- package/lib/src/dialog.ts +656 -0
- package/lib/src/dom_events.ts +315 -0
- package/lib/src/drag_manager.ts +199 -0
- package/lib/src/drawtext.ts +355 -0
- package/lib/src/fileupload.ts +213 -0
- package/lib/src/form.ts +375 -0
- package/lib/src/formatters.ts +105 -0
- package/lib/src/gridview.ts +1185 -0
- package/lib/src/i18n.ts +346 -0
- package/lib/src/icon.ts +335 -0
- package/lib/src/image.ts +204 -0
- package/lib/src/index.ts +89 -0
- package/lib/src/input.ts +249 -0
- package/lib/src/label.ts +128 -0
- package/lib/src/layout.ts +430 -0
- package/lib/src/link.ts +86 -0
- package/lib/src/listview.ts +765 -0
- package/lib/{esm/md5.js → src/md5.ts} +438 -403
- package/lib/src/menu.ts +425 -0
- package/lib/src/messagebox.ts +224 -0
- package/lib/src/panel.ts +86 -0
- package/lib/src/popup.ts +494 -0
- package/lib/src/property_editor.ts +337 -0
- package/lib/src/radiobtn.ts +197 -0
- package/lib/src/rating.ts +135 -0
- package/lib/src/request.ts +300 -0
- package/lib/src/router.ts +185 -0
- package/lib/src/settings.ts +77 -0
- package/lib/src/sidebarview.ts +103 -0
- package/lib/src/spreadsheet.ts +1449 -0
- package/lib/src/styles.ts +343 -0
- package/lib/src/svgcomponent.ts +577 -0
- package/lib/src/tabbar.ts +151 -0
- package/lib/src/tabview.ts +110 -0
- package/lib/src/textarea.ts +235 -0
- package/lib/src/textedit.ts +544 -0
- package/lib/src/toaster.ts +80 -0
- package/lib/src/tools.ts +1473 -0
- package/lib/src/tooltips.ts +191 -0
- package/lib/src/treeview.ts +716 -0
- package/lib/{esm/version.js → src/version.ts} +30 -29
- package/lib/{styles → src}/x4.less +0 -0
- package/lib/src/x4dom.ts +57 -0
- package/lib/src/x4events.ts +585 -0
- package/lib/src/x4react.ts +90 -0
- package/package.json +52 -49
- package/lib/cjs/action.js +0 -58
- package/lib/cjs/app_sockets.js +0 -74
- package/lib/cjs/application.js +0 -182
- package/lib/cjs/autocomplete.js +0 -155
- package/lib/cjs/base_component.js +0 -124
- package/lib/cjs/button.js +0 -263
- package/lib/cjs/calendar.js +0 -254
- package/lib/cjs/canvas.js +0 -361
- package/lib/cjs/cardview.js +0 -161
- package/lib/cjs/checkbox.js +0 -139
- package/lib/cjs/color.js +0 -591
- package/lib/cjs/colorpicker.js +0 -1468
- package/lib/cjs/combobox.js +0 -349
- package/lib/cjs/component.js +0 -1719
- package/lib/cjs/datastore.js +0 -985
- package/lib/cjs/dialog.js +0 -478
- package/lib/cjs/dom_events.js +0 -30
- package/lib/cjs/drag_manager.js +0 -145
- package/lib/cjs/drawtext.js +0 -276
- package/lib/cjs/fileupload.js +0 -167
- package/lib/cjs/form.js +0 -304
- package/lib/cjs/formatters.js +0 -90
- package/lib/cjs/gridview.js +0 -881
- package/lib/cjs/i18n.js +0 -266
- package/lib/cjs/icon.js +0 -272
- package/lib/cjs/image.js +0 -157
- package/lib/cjs/input.js +0 -174
- package/lib/cjs/label.js +0 -95
- package/lib/cjs/layout.js +0 -322
- package/lib/cjs/link.js +0 -64
- package/lib/cjs/listview.js +0 -546
- package/lib/cjs/md5.js +0 -403
- package/lib/cjs/menu.js +0 -301
- package/lib/cjs/messagebox.js +0 -177
- package/lib/cjs/panel.js +0 -68
- package/lib/cjs/popup.js +0 -383
- package/lib/cjs/property_editor.js +0 -252
- package/lib/cjs/radiobtn.js +0 -140
- package/lib/cjs/rating.js +0 -102
- package/lib/cjs/request.js +0 -246
- package/lib/cjs/router.js +0 -139
- package/lib/cjs/settings.js +0 -69
- package/lib/cjs/sidebarview.js +0 -82
- package/lib/cjs/spreadsheet.js +0 -1084
- package/lib/cjs/styles.js +0 -275
- package/lib/cjs/svgcomponent.js +0 -447
- package/lib/cjs/tabbar.js +0 -111
- package/lib/cjs/tabview.js +0 -85
- package/lib/cjs/textarea.js +0 -165
- package/lib/cjs/textedit.js +0 -415
- package/lib/cjs/toaster.js +0 -64
- package/lib/cjs/tools.js +0 -1197
- package/lib/cjs/tooltips.js +0 -157
- package/lib/cjs/treeview.js +0 -535
- package/lib/cjs/version.js +0 -32
- package/lib/cjs/x4dom.js +0 -32
- package/lib/cjs/x4events.js +0 -384
- package/lib/cjs/x4react.js +0 -72
- package/lib/esm/action.js +0 -53
- package/lib/esm/app_sockets.js +0 -70
- package/lib/esm/application.js +0 -184
- package/lib/esm/autocomplete.js +0 -155
- package/lib/esm/base_component.js +0 -107
- package/lib/esm/button.js +0 -257
- package/lib/esm/calendar.js +0 -249
- package/lib/esm/canvas.js +0 -358
- package/lib/esm/cardview.js +0 -159
- package/lib/esm/checkbox.js +0 -134
- package/lib/esm/color.js +0 -588
- package/lib/esm/colorpicker.js +0 -1475
- package/lib/esm/combobox.js +0 -351
- package/lib/esm/component.js +0 -1711
- package/lib/esm/datastore.js +0 -990
- package/lib/esm/dialog.js +0 -490
- package/lib/esm/drag_manager.js +0 -147
- package/lib/esm/drawtext.js +0 -271
- package/lib/esm/fileupload.js +0 -163
- package/lib/esm/form.js +0 -304
- package/lib/esm/formatters.js +0 -81
- package/lib/esm/gridview.js +0 -889
- package/lib/esm/i18n.js +0 -257
- package/lib/esm/icon.js +0 -261
- package/lib/esm/image.js +0 -154
- package/lib/esm/input.js +0 -182
- package/lib/esm/label.js +0 -90
- package/lib/esm/layout.js +0 -310
- package/lib/esm/link.js +0 -59
- package/lib/esm/listview.js +0 -534
- package/lib/esm/menu.js +0 -300
- package/lib/esm/messagebox.js +0 -161
- package/lib/esm/panel.js +0 -65
- package/lib/esm/popup.js +0 -379
- package/lib/esm/property_editor.js +0 -251
- package/lib/esm/radiobtn.js +0 -136
- package/lib/esm/rating.js +0 -97
- package/lib/esm/request.js +0 -224
- package/lib/esm/router.js +0 -136
- package/lib/esm/settings.js +0 -66
- package/lib/esm/sidebarview.js +0 -79
- package/lib/esm/spreadsheet.js +0 -1097
- package/lib/esm/styles.js +0 -270
- package/lib/esm/svgcomponent.js +0 -450
- package/lib/esm/tabbar.js +0 -107
- package/lib/esm/tabview.js +0 -83
- package/lib/esm/textarea.js +0 -160
- package/lib/esm/textedit.js +0 -412
- package/lib/esm/toaster.js +0 -62
- package/lib/esm/tools.js +0 -1158
- package/lib/esm/tooltips.js +0 -153
- package/lib/esm/treeview.js +0 -527
- package/lib/esm/x4dom.js +0 -29
- package/lib/esm/x4events.js +0 -376
- package/lib/esm/x4react.js +0 -71
- package/lib/types/app_sockets.d.ts +0 -29
- package/lib/types/application.d.ts +0 -104
- package/lib/types/autocomplete.d.ts +0 -58
- package/lib/types/base_component.d.ts +0 -88
- package/lib/types/button.d.ts +0 -151
- package/lib/types/calendar.d.ts +0 -82
- package/lib/types/canvas.d.ts +0 -92
- package/lib/types/cardview.d.ts +0 -87
- package/lib/types/checkbox.d.ts +0 -77
- package/lib/types/color.d.ts +0 -148
- package/lib/types/colorpicker.d.ts +0 -107
- package/lib/types/combobox.d.ts +0 -107
- package/lib/types/component.d.ts +0 -601
- package/lib/types/datastore.d.ts +0 -396
- package/lib/types/dialog.d.ts +0 -175
- package/lib/types/dom_events.d.ts +0 -302
- package/lib/types/drag_manager.d.ts +0 -54
- package/lib/types/drawtext.d.ts +0 -48
- package/lib/types/fileupload.d.ts +0 -64
- package/lib/types/form.d.ts +0 -133
- package/lib/types/formatters.d.ts +0 -35
- package/lib/types/gridview.d.ts +0 -175
- package/lib/types/i18n.d.ts +0 -73
- package/lib/types/icon.d.ts +0 -64
- package/lib/types/image.d.ts +0 -55
- package/lib/types/index.d.ts +0 -84
- package/lib/types/input.d.ts +0 -91
- package/lib/types/label.d.ts +0 -58
- package/lib/types/layout.d.ts +0 -87
- package/lib/types/link.d.ts +0 -50
- package/lib/types/listview.d.ts +0 -178
- package/lib/types/md5.d.ts +0 -61
- package/lib/types/menu.d.ts +0 -130
- package/lib/types/messagebox.d.ts +0 -69
- package/lib/types/panel.d.ts +0 -47
- package/lib/types/popup.d.ts +0 -75
- package/lib/types/property_editor.d.ts +0 -71
- package/lib/types/radiobtn.d.ts +0 -73
- package/lib/types/rating.d.ts +0 -53
- package/lib/types/request.d.ts +0 -52
- package/lib/types/router.d.ts +0 -42
- package/lib/types/settings.d.ts +0 -37
- package/lib/types/sidebarview.d.ts +0 -49
- package/lib/types/spreadsheet.d.ts +0 -222
- package/lib/types/styles.d.ts +0 -85
- package/lib/types/svgcomponent.d.ts +0 -215
- package/lib/types/tabbar.d.ts +0 -58
- package/lib/types/tabview.d.ts +0 -49
- package/lib/types/textarea.d.ts +0 -77
- package/lib/types/textedit.d.ts +0 -123
- package/lib/types/toaster.d.ts +0 -42
- package/lib/types/tools.d.ts +0 -394
- package/lib/types/tooltips.d.ts +0 -46
- package/lib/types/treeview.d.ts +0 -144
- package/lib/types/version.d.ts +0 -29
- package/lib/types/x4dom.d.ts +0 -49
- package/lib/types/x4events.d.ts +0 -269
- package/lib/types/x4react.d.ts +0 -41
package/lib/esm/datastore.js
DELETED
|
@@ -1,990 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ___ ___ __
|
|
3
|
-
* \ \/ / / _
|
|
4
|
-
* \ / /_| |_
|
|
5
|
-
* / \____ _|
|
|
6
|
-
* /__/\__\ |_|
|
|
7
|
-
*
|
|
8
|
-
* @file datastore.ts
|
|
9
|
-
* @author Etienne Cochard
|
|
10
|
-
*
|
|
11
|
-
* Copyright (c) 2019-2022 R-libre ingenierie
|
|
12
|
-
*
|
|
13
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
15
|
-
* in the Software without restriction, including without limitation the rights
|
|
16
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
17
|
-
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
18
|
-
* subject to the following conditions:
|
|
19
|
-
* The above copyright notice and this permission notice shall be included in all copies
|
|
20
|
-
* or substantial portions of the Software.
|
|
21
|
-
*
|
|
22
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
23
|
-
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
24
|
-
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
25
|
-
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
26
|
-
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
27
|
-
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
|
-
**/
|
|
29
|
-
import { ajaxRequest } from './request';
|
|
30
|
-
import { isArray, isString } from './tools';
|
|
31
|
-
import { BasicEvent, EvChange, EventSource } from './x4events';
|
|
32
|
-
import { BaseComponent } from './base_component';
|
|
33
|
-
function EvDataChange(type, id) {
|
|
34
|
-
return BasicEvent({ type, id });
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
*
|
|
38
|
-
*/
|
|
39
|
-
class MetaInfos {
|
|
40
|
-
name;
|
|
41
|
-
id; // field name holding 'id' record info
|
|
42
|
-
fields; // field list
|
|
43
|
-
constructor(name) {
|
|
44
|
-
this.name = name;
|
|
45
|
-
this.id = undefined;
|
|
46
|
-
this.fields = [];
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
const metaFields = Symbol('metaField');
|
|
50
|
-
function _getMetas(obj, create = true) {
|
|
51
|
-
let ctor = obj.constructor;
|
|
52
|
-
let mfld = ctor.hasOwnProperty(metaFields) ? ctor[metaFields] : undefined;
|
|
53
|
-
if (mfld === undefined) {
|
|
54
|
-
if (!create) {
|
|
55
|
-
console.assert(mfld !== undefined);
|
|
56
|
-
}
|
|
57
|
-
// construct our metas
|
|
58
|
-
mfld = new MetaInfos(ctor.name);
|
|
59
|
-
// merge with parent class metas
|
|
60
|
-
let pctor = Object.getPrototypeOf(ctor);
|
|
61
|
-
if (pctor != Record) {
|
|
62
|
-
let pmetas = pctor[metaFields];
|
|
63
|
-
mfld.fields = [...pmetas.fields, ...mfld.fields];
|
|
64
|
-
console.assert(mfld.id === undefined, 'cannot define mutiple record id');
|
|
65
|
-
if (!mfld.id) {
|
|
66
|
-
mfld.id = pmetas.id;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
obj.constructor[metaFields] = mfld;
|
|
70
|
-
}
|
|
71
|
-
return mfld;
|
|
72
|
-
}
|
|
73
|
-
export var data;
|
|
74
|
-
(function (data_1) {
|
|
75
|
-
/**
|
|
76
|
-
* define a record id
|
|
77
|
-
* @example
|
|
78
|
-
* \@data_id()
|
|
79
|
-
* id: string; // this field is the record id
|
|
80
|
-
**/
|
|
81
|
-
function id() {
|
|
82
|
-
return (ownerCls, fldName) => {
|
|
83
|
-
let metas = _getMetas(ownerCls);
|
|
84
|
-
metas.fields.push({
|
|
85
|
-
name: fldName,
|
|
86
|
-
type: 'any',
|
|
87
|
-
required: true,
|
|
88
|
-
});
|
|
89
|
-
metas.id = fldName;
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
data_1.id = id;
|
|
93
|
-
/**
|
|
94
|
-
* @ignore
|
|
95
|
-
*/
|
|
96
|
-
function field(data) {
|
|
97
|
-
return (ownerCls, fldName) => {
|
|
98
|
-
let metas = _getMetas(ownerCls);
|
|
99
|
-
metas.fields.push({
|
|
100
|
-
name: fldName,
|
|
101
|
-
...data
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
data_1.field = field;
|
|
106
|
-
/**
|
|
107
|
-
* following member is a string field
|
|
108
|
-
* @example
|
|
109
|
-
* \@data_string()
|
|
110
|
-
* my_field: string; // this field will be seen as a string
|
|
111
|
-
*/
|
|
112
|
-
function string(props) {
|
|
113
|
-
return field({ ...props, type: 'string' });
|
|
114
|
-
}
|
|
115
|
-
data_1.string = string;
|
|
116
|
-
/**
|
|
117
|
-
* following member is an integer field
|
|
118
|
-
* @example
|
|
119
|
-
* \@data_string()
|
|
120
|
-
* my_field: number; // this field will be seen as an integer
|
|
121
|
-
*/
|
|
122
|
-
function int(props) {
|
|
123
|
-
return field({ ...props, type: 'int' });
|
|
124
|
-
}
|
|
125
|
-
data_1.int = int;
|
|
126
|
-
/**
|
|
127
|
-
* following member is a float field
|
|
128
|
-
* @example
|
|
129
|
-
* \@data_float()
|
|
130
|
-
* my_field: number; // this field will be seen as a float
|
|
131
|
-
*/
|
|
132
|
-
function float(props) {
|
|
133
|
-
return field({ ...props, type: 'float' });
|
|
134
|
-
}
|
|
135
|
-
data_1.float = float;
|
|
136
|
-
/**
|
|
137
|
-
* following member is a boolean field
|
|
138
|
-
* @example
|
|
139
|
-
* \@data_bool()
|
|
140
|
-
* my_field: boolean; // this field will be seen as a boolean
|
|
141
|
-
*/
|
|
142
|
-
function bool(props) {
|
|
143
|
-
return field({ ...props, type: 'bool' });
|
|
144
|
-
}
|
|
145
|
-
data_1.bool = bool;
|
|
146
|
-
/**
|
|
147
|
-
* following member is a date field
|
|
148
|
-
* @example
|
|
149
|
-
* \@data_date()
|
|
150
|
-
* my_field: date; // this field will be seen as a date
|
|
151
|
-
*/
|
|
152
|
-
function date(props) {
|
|
153
|
-
return field({ ...props, type: 'date' });
|
|
154
|
-
}
|
|
155
|
-
data_1.date = date;
|
|
156
|
-
/**
|
|
157
|
-
* following member is a calculated field
|
|
158
|
-
* @example
|
|
159
|
-
* \@data_calc( )
|
|
160
|
-
* get my_field(): string => {
|
|
161
|
-
* return 'hello';
|
|
162
|
-
* };
|
|
163
|
-
*/
|
|
164
|
-
function calc(props) {
|
|
165
|
-
return field({ ...props, type: 'calc' });
|
|
166
|
-
}
|
|
167
|
-
data_1.calc = calc;
|
|
168
|
-
/**
|
|
169
|
-
* following member is a record array
|
|
170
|
-
* @example
|
|
171
|
-
* \@data_array( )
|
|
172
|
-
* my_field(): TypedRecord[];
|
|
173
|
-
*/
|
|
174
|
-
function array(ctor, props) {
|
|
175
|
-
return data.field({ ...props, type: 'array', model: new ctor() });
|
|
176
|
-
}
|
|
177
|
-
data_1.array = array;
|
|
178
|
-
})(data || (data = {}));
|
|
179
|
-
/**
|
|
180
|
-
* record model
|
|
181
|
-
*/
|
|
182
|
-
export class Record {
|
|
183
|
-
constructor(data, id) {
|
|
184
|
-
if (data !== undefined) {
|
|
185
|
-
this.unSerialize(data, id);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
clone(source) {
|
|
189
|
-
let rec = new this.constructor();
|
|
190
|
-
if (source) {
|
|
191
|
-
rec.unSerialize(source);
|
|
192
|
-
}
|
|
193
|
-
return rec;
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* get the record unique identifier
|
|
197
|
-
* by default the return value is the first field
|
|
198
|
-
* @return unique identifier
|
|
199
|
-
*/
|
|
200
|
-
getID() {
|
|
201
|
-
let metas = _getMetas(this, false);
|
|
202
|
-
return this[metas.id];
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* MUST IMPLEMENT
|
|
206
|
-
* @returns fields descriptors
|
|
207
|
-
*/
|
|
208
|
-
getFields() {
|
|
209
|
-
let metas = _getMetas(this, false);
|
|
210
|
-
return metas.fields;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
*
|
|
214
|
-
*/
|
|
215
|
-
validate() {
|
|
216
|
-
let errs = null;
|
|
217
|
-
let fields = this.getFields();
|
|
218
|
-
fields.forEach((fi) => {
|
|
219
|
-
if (fi.required && !this.getField(fi.name)) {
|
|
220
|
-
if (errs) {
|
|
221
|
-
errs = [];
|
|
222
|
-
}
|
|
223
|
-
errs.push(new Error(`field ${fi.name} is required.`));
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
return errs;
|
|
227
|
-
}
|
|
228
|
-
//mapAnyFields() {
|
|
229
|
-
// this.getFields = ( ) => {
|
|
230
|
-
// return Object.keys( this ).map( (name) => {
|
|
231
|
-
// return <FieldInfo>{ name };
|
|
232
|
-
// });
|
|
233
|
-
// }
|
|
234
|
-
//}
|
|
235
|
-
getFieldIndex(name) {
|
|
236
|
-
let fields = this.getFields();
|
|
237
|
-
return fields.findIndex((fd) => fd.name == name);
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* default serializer
|
|
241
|
-
* @returns an object with known record values
|
|
242
|
-
*/
|
|
243
|
-
serialize() {
|
|
244
|
-
let rec = {};
|
|
245
|
-
this.getFields().forEach((f) => {
|
|
246
|
-
if (f.calc === undefined) {
|
|
247
|
-
rec[f.name] = rec[f.name];
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
return rec;
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* default unserializer
|
|
254
|
-
* @param data - input data
|
|
255
|
-
* @returns a new Record
|
|
256
|
-
*/
|
|
257
|
-
unSerialize(data, id) {
|
|
258
|
-
let fields = this.getFields();
|
|
259
|
-
fields.forEach((sf) => {
|
|
260
|
-
let value = data[sf.name];
|
|
261
|
-
if (value !== undefined) {
|
|
262
|
-
this[sf.name] = this._convertField(sf, value);
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
if (id !== undefined) {
|
|
266
|
-
this[fields[0].name] = id;
|
|
267
|
-
}
|
|
268
|
-
else {
|
|
269
|
-
console.assert(this.getID() !== undefined); // store do not have ID field
|
|
270
|
-
}
|
|
271
|
-
return this;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* field conversion
|
|
275
|
-
* @param field - field descriptor
|
|
276
|
-
* @param input - value to convert
|
|
277
|
-
* @returns the field value in it's original form
|
|
278
|
-
*/
|
|
279
|
-
_convertField(field, input) {
|
|
280
|
-
//TODO: boolean
|
|
281
|
-
switch (field.type) {
|
|
282
|
-
case 'float': {
|
|
283
|
-
let ffv = typeof (input) === 'number' ? input : parseFloat(input);
|
|
284
|
-
if (field.prec !== undefined) {
|
|
285
|
-
let mul = Math.pow(10, field.prec);
|
|
286
|
-
ffv = Math.round(ffv * mul) / mul;
|
|
287
|
-
}
|
|
288
|
-
return ffv;
|
|
289
|
-
}
|
|
290
|
-
case 'int': {
|
|
291
|
-
return typeof (input) === 'number' ? input : parseInt(input);
|
|
292
|
-
}
|
|
293
|
-
case 'date': {
|
|
294
|
-
return isString(input) ? new Date(input) : input;
|
|
295
|
-
}
|
|
296
|
-
case 'array': {
|
|
297
|
-
let result = [];
|
|
298
|
-
if (field.model) {
|
|
299
|
-
input.forEach((v) => {
|
|
300
|
-
result.push(field.model.clone(v));
|
|
301
|
-
});
|
|
302
|
-
return result;
|
|
303
|
-
}
|
|
304
|
-
break;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return input;
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* get raw value of a field
|
|
311
|
-
* @param name - field name or field index
|
|
312
|
-
*/
|
|
313
|
-
getRaw(name) {
|
|
314
|
-
let idx;
|
|
315
|
-
let fields = this.getFields();
|
|
316
|
-
if (typeof (name) === 'string') {
|
|
317
|
-
idx = fields.findIndex(fi => fi.name == name);
|
|
318
|
-
if (idx < 0) {
|
|
319
|
-
console.assert(false, 'unknown field: ' + name);
|
|
320
|
-
return undefined;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
else if (name >= 0 && name < fields.length) {
|
|
324
|
-
idx = name;
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
console.assert(false, 'bad field name: ' + name);
|
|
328
|
-
return undefined;
|
|
329
|
-
}
|
|
330
|
-
let fld = fields[idx];
|
|
331
|
-
if (fld.calc !== undefined) {
|
|
332
|
-
return fld.calc(this);
|
|
333
|
-
}
|
|
334
|
-
return this[fld.name];
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
*
|
|
338
|
-
* @param name
|
|
339
|
-
* @param data
|
|
340
|
-
*/
|
|
341
|
-
setRaw(name, data) {
|
|
342
|
-
this[name] = data;
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* get field value (as string)
|
|
346
|
-
* @param name - field name
|
|
347
|
-
* @example
|
|
348
|
-
* let value = record.get('field1');
|
|
349
|
-
*/
|
|
350
|
-
getField(name) {
|
|
351
|
-
let v = this.getRaw(name);
|
|
352
|
-
return (v === undefined || v === null) ? '' : '' + v;
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* set field value
|
|
356
|
-
* @param name - field name
|
|
357
|
-
* @param value - value to set
|
|
358
|
-
* @example
|
|
359
|
-
* record.set( 'field1', 7 );
|
|
360
|
-
*/
|
|
361
|
-
setField(name, value) {
|
|
362
|
-
let fields = this.getFields();
|
|
363
|
-
let idx = fields.findIndex(fi => fi.name == name);
|
|
364
|
-
if (idx < 0) {
|
|
365
|
-
console.assert(false, 'unknown field: ' + name);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
let fld = fields[idx];
|
|
369
|
-
if (fld.calc !== undefined) {
|
|
370
|
-
console.assert(false, 'cannot set calc field: ' + name);
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
this.setRaw(fld.name, value);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
/**
|
|
377
|
-
* by default, the field id is rhe first member or the record
|
|
378
|
-
*/
|
|
379
|
-
export class AutoRecord extends Record {
|
|
380
|
-
m_data;
|
|
381
|
-
m_fid;
|
|
382
|
-
constructor(data) {
|
|
383
|
-
super();
|
|
384
|
-
this.m_data = data;
|
|
385
|
-
}
|
|
386
|
-
getID() {
|
|
387
|
-
if (!this.m_fid) {
|
|
388
|
-
let fnames = Object.keys(this.m_data);
|
|
389
|
-
this.m_fid = fnames[0];
|
|
390
|
-
}
|
|
391
|
-
return this.m_data[this.m_fid];
|
|
392
|
-
}
|
|
393
|
-
getFields() {
|
|
394
|
-
let fnames = Object.keys(this.m_data);
|
|
395
|
-
let fields = fnames.map((n) => {
|
|
396
|
-
return {
|
|
397
|
-
name: n
|
|
398
|
-
};
|
|
399
|
-
});
|
|
400
|
-
return fields;
|
|
401
|
-
}
|
|
402
|
-
getRaw(name) {
|
|
403
|
-
return this.m_data[name];
|
|
404
|
-
}
|
|
405
|
-
setRaw(name, data) {
|
|
406
|
-
this.m_data[name] = data;
|
|
407
|
-
}
|
|
408
|
-
clone(data) {
|
|
409
|
-
return new AutoRecord({ ...data });
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
export class DataProxy extends BaseComponent {
|
|
413
|
-
constructor(props) {
|
|
414
|
-
super(props);
|
|
415
|
-
}
|
|
416
|
-
load() {
|
|
417
|
-
this._refresh();
|
|
418
|
-
}
|
|
419
|
-
save(data) {
|
|
420
|
-
if (this.m_props.type == 'local') {
|
|
421
|
-
console.assert(false); // not imp
|
|
422
|
-
/*
|
|
423
|
-
const fs = require('fs');
|
|
424
|
-
fs.writeFileSync( this.m_path, data );
|
|
425
|
-
*/
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
_refresh(delay = 0) {
|
|
429
|
-
if (this.m_props.type == 'local') {
|
|
430
|
-
console.assert(false); // not imp
|
|
431
|
-
/*
|
|
432
|
-
const fs = require('fs');
|
|
433
|
-
fs.readFile( this.m_path, ( _, bdata ) => {;
|
|
434
|
-
let data = JSON.parse(bdata);
|
|
435
|
-
this.emit( 'dataready', data );
|
|
436
|
-
} );
|
|
437
|
-
*/
|
|
438
|
-
}
|
|
439
|
-
else {
|
|
440
|
-
setTimeout(() => {
|
|
441
|
-
ajaxRequest({
|
|
442
|
-
url: this.m_props.path,
|
|
443
|
-
method: 'GET',
|
|
444
|
-
params: this.m_props.params,
|
|
445
|
-
success: (data) => {
|
|
446
|
-
this.emit('change', EvChange(data));
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
}, delay);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
/**
|
|
454
|
-
*
|
|
455
|
-
*/
|
|
456
|
-
export class DataStore extends EventSource {
|
|
457
|
-
m_model;
|
|
458
|
-
m_fields;
|
|
459
|
-
m_records;
|
|
460
|
-
m_proxy;
|
|
461
|
-
m_rec_index;
|
|
462
|
-
constructor(props) {
|
|
463
|
-
super();
|
|
464
|
-
this.m_fields = undefined;
|
|
465
|
-
this.m_records = [];
|
|
466
|
-
this.m_rec_index = null;
|
|
467
|
-
this.m_model = props.model;
|
|
468
|
-
this.m_fields = props.model.getFields();
|
|
469
|
-
if (props.data) {
|
|
470
|
-
this.setRawData(props.data);
|
|
471
|
-
}
|
|
472
|
-
else if (props.url) {
|
|
473
|
-
this.load(props.url);
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
/**
|
|
477
|
-
*
|
|
478
|
-
* @param records
|
|
479
|
-
*/
|
|
480
|
-
load(url) {
|
|
481
|
-
//todo: that
|
|
482
|
-
if (url.substr(0, 7) === 'file://') {
|
|
483
|
-
this.m_proxy = new DataProxy({
|
|
484
|
-
type: 'local',
|
|
485
|
-
path: url.substr(7),
|
|
486
|
-
events: { change: (ev) => { this.setData(ev.value); } }
|
|
487
|
-
});
|
|
488
|
-
this.m_proxy.load();
|
|
489
|
-
}
|
|
490
|
-
else {
|
|
491
|
-
this.m_proxy = new DataProxy({
|
|
492
|
-
type: 'ajax',
|
|
493
|
-
path: url,
|
|
494
|
-
events: { change: (ev) => { this.setData(ev.value); } }
|
|
495
|
-
});
|
|
496
|
-
this.m_proxy.load();
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
reload() {
|
|
500
|
-
this.m_proxy.load();
|
|
501
|
-
}
|
|
502
|
-
/**
|
|
503
|
-
* convert raw objects to real records from model
|
|
504
|
-
* @param records
|
|
505
|
-
*/
|
|
506
|
-
setData(records) {
|
|
507
|
-
let realRecords = [];
|
|
508
|
-
records.forEach((rec) => {
|
|
509
|
-
realRecords.push(this.m_model.clone(rec));
|
|
510
|
-
});
|
|
511
|
-
this.setRawData(realRecords);
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* just set the records
|
|
515
|
-
* @param records - must be of the same type as model
|
|
516
|
-
*/
|
|
517
|
-
setRawData(records) {
|
|
518
|
-
this.m_records = records;
|
|
519
|
-
this._rebuildIndex();
|
|
520
|
-
this.emit('data_change', EvDataChange('change'));
|
|
521
|
-
}
|
|
522
|
-
_rebuildIndex() {
|
|
523
|
-
this.m_rec_index = null; // null to signal that we have to run on records instead of index
|
|
524
|
-
this.m_rec_index = this.createIndex(null); // prepare index (remove deleted)
|
|
525
|
-
this.m_rec_index = this.sortIndex(this.m_rec_index, null); // sort by id
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
*
|
|
529
|
-
*/
|
|
530
|
-
update(rec) {
|
|
531
|
-
let id = rec.getID();
|
|
532
|
-
let index = this.indexOfId(id);
|
|
533
|
-
if (index < 0) {
|
|
534
|
-
return false;
|
|
535
|
-
}
|
|
536
|
-
this.m_records[this.m_rec_index[index]] = rec;
|
|
537
|
-
this.emit('data_change', EvDataChange('update', id));
|
|
538
|
-
return true;
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
*
|
|
542
|
-
* @param data
|
|
543
|
-
*/
|
|
544
|
-
append(rec) {
|
|
545
|
-
if (!(rec instanceof Record)) {
|
|
546
|
-
let nrec = this.m_model.clone();
|
|
547
|
-
rec = nrec.unSerialize(rec);
|
|
548
|
-
}
|
|
549
|
-
console.assert(rec.getID());
|
|
550
|
-
this.m_records.push(rec);
|
|
551
|
-
this._rebuildIndex();
|
|
552
|
-
this.emit('data_change', EvDataChange('create', rec.getID()));
|
|
553
|
-
}
|
|
554
|
-
/**
|
|
555
|
-
*
|
|
556
|
-
*/
|
|
557
|
-
getMaxId() {
|
|
558
|
-
let maxID = undefined;
|
|
559
|
-
this.m_records.forEach((r) => {
|
|
560
|
-
let rid = r.getID();
|
|
561
|
-
if (maxID === undefined || maxID < rid) {
|
|
562
|
-
maxID = rid;
|
|
563
|
-
}
|
|
564
|
-
});
|
|
565
|
-
return maxID;
|
|
566
|
-
}
|
|
567
|
-
/**
|
|
568
|
-
*
|
|
569
|
-
* @param id
|
|
570
|
-
*/
|
|
571
|
-
delete(id) {
|
|
572
|
-
let idx = this.indexOfId(id);
|
|
573
|
-
if (idx < 0) {
|
|
574
|
-
return false;
|
|
575
|
-
}
|
|
576
|
-
idx = this.m_rec_index[idx];
|
|
577
|
-
// mark as deleted
|
|
578
|
-
this.m_records.splice(idx, 1);
|
|
579
|
-
this._rebuildIndex();
|
|
580
|
-
this.emit('data_change', EvDataChange('delete', id));
|
|
581
|
-
return true;
|
|
582
|
-
}
|
|
583
|
-
/**
|
|
584
|
-
* return the number of records
|
|
585
|
-
*/
|
|
586
|
-
get count() {
|
|
587
|
-
return this.m_rec_index ? this.m_rec_index.length : this.m_records.length;
|
|
588
|
-
}
|
|
589
|
-
/**
|
|
590
|
-
* return the fields
|
|
591
|
-
*/
|
|
592
|
-
get fields() {
|
|
593
|
-
return this.m_fields;
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* find the index of the element with the given id
|
|
597
|
-
*/
|
|
598
|
-
indexOfId(id) {
|
|
599
|
-
//if( this.count<10 ) {
|
|
600
|
-
// this.forEach( (rec) => rec.getID() == id );
|
|
601
|
-
//}
|
|
602
|
-
for (let lim = this.count, base = 0; lim != 0; lim >>= 1) {
|
|
603
|
-
let p = base + (lim >> 1); // int conversion
|
|
604
|
-
let idx = this.m_rec_index[p];
|
|
605
|
-
let rid = this.m_records[idx].getID();
|
|
606
|
-
if (rid == id) {
|
|
607
|
-
return p;
|
|
608
|
-
}
|
|
609
|
-
if (rid < id) {
|
|
610
|
-
base = p + 1;
|
|
611
|
-
lim--;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
return -1;
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* return the record by it's id
|
|
618
|
-
* @returns record or null
|
|
619
|
-
*/
|
|
620
|
-
getById(id) {
|
|
621
|
-
let idx = this.indexOfId(id);
|
|
622
|
-
if (idx < 0) {
|
|
623
|
-
return null;
|
|
624
|
-
}
|
|
625
|
-
idx = this.m_rec_index[idx];
|
|
626
|
-
return this.m_records[idx];
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* return a record by it's index
|
|
630
|
-
* @returns record or null
|
|
631
|
-
*/
|
|
632
|
-
getByIndex(index) {
|
|
633
|
-
let idx = this.m_rec_index[index];
|
|
634
|
-
return this._getRecord(idx);
|
|
635
|
-
}
|
|
636
|
-
_getRecord(index) {
|
|
637
|
-
return this.m_records[index] ?? null;
|
|
638
|
-
}
|
|
639
|
-
moveTo(other) {
|
|
640
|
-
other.setRawData(this.m_records);
|
|
641
|
-
}
|
|
642
|
-
/**
|
|
643
|
-
* create a new view on the DataStore
|
|
644
|
-
* @param opts
|
|
645
|
-
*/
|
|
646
|
-
createView(opts) {
|
|
647
|
-
let eopts = { ...opts, store: this };
|
|
648
|
-
return new DataView(eopts);
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
*
|
|
652
|
-
*/
|
|
653
|
-
createIndex(filter) {
|
|
654
|
-
if (filter && filter.op === 'empty-result') {
|
|
655
|
-
return new Uint32Array(0);
|
|
656
|
-
}
|
|
657
|
-
let index = new Uint32Array(this.m_records.length);
|
|
658
|
-
let iidx = 0;
|
|
659
|
-
if (!filter) {
|
|
660
|
-
// reset filter
|
|
661
|
-
this.forEach((rec, idx) => {
|
|
662
|
-
index[iidx++] = idx;
|
|
663
|
-
});
|
|
664
|
-
}
|
|
665
|
-
else {
|
|
666
|
-
if (typeof (filter.op) === 'function') {
|
|
667
|
-
let fn = filter.op;
|
|
668
|
-
// scan all records and append only interesting ones
|
|
669
|
-
this.forEach((rec, idx) => {
|
|
670
|
-
// skip deleted
|
|
671
|
-
if (!rec) {
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
if (fn(rec)) {
|
|
675
|
-
index[iidx++] = idx;
|
|
676
|
-
}
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
680
|
-
let filterFld = this.m_model.getFieldIndex(filter.field); // field index to filter on
|
|
681
|
-
if (filterFld < 0) {
|
|
682
|
-
// unknown filter field, nothing inside
|
|
683
|
-
console.assert(false, 'unknown field name in filter');
|
|
684
|
-
return new Uint32Array(0);
|
|
685
|
-
}
|
|
686
|
-
let filterValue = filter.value;
|
|
687
|
-
if (isString(filterValue) && !filter.caseSensitive) {
|
|
688
|
-
filterValue = filterValue.toUpperCase();
|
|
689
|
-
}
|
|
690
|
-
function _lt(recval) {
|
|
691
|
-
return recval < filterValue;
|
|
692
|
-
}
|
|
693
|
-
function _le(recval) {
|
|
694
|
-
return recval <= filterValue;
|
|
695
|
-
}
|
|
696
|
-
function _eq(recval) {
|
|
697
|
-
return recval == filterValue;
|
|
698
|
-
}
|
|
699
|
-
function _neq(recval) {
|
|
700
|
-
return recval != filterValue;
|
|
701
|
-
}
|
|
702
|
-
function _ge(recval) {
|
|
703
|
-
return recval >= filterValue;
|
|
704
|
-
}
|
|
705
|
-
function _gt(recval) {
|
|
706
|
-
return recval > filterValue;
|
|
707
|
-
}
|
|
708
|
-
function _re(recval) {
|
|
709
|
-
filterRe.lastIndex = -1;
|
|
710
|
-
return filterRe.test(recval);
|
|
711
|
-
}
|
|
712
|
-
let filterFn; // filter fn
|
|
713
|
-
let filterRe; // if fielter is regexp
|
|
714
|
-
if (filterValue instanceof RegExp) {
|
|
715
|
-
filterRe = filterValue;
|
|
716
|
-
filterFn = _re;
|
|
717
|
-
}
|
|
718
|
-
else {
|
|
719
|
-
switch (filter.op) {
|
|
720
|
-
case '<': {
|
|
721
|
-
filterFn = _lt;
|
|
722
|
-
break;
|
|
723
|
-
}
|
|
724
|
-
case '<=': {
|
|
725
|
-
filterFn = _le;
|
|
726
|
-
break;
|
|
727
|
-
}
|
|
728
|
-
case '=': {
|
|
729
|
-
filterFn = _eq;
|
|
730
|
-
break;
|
|
731
|
-
}
|
|
732
|
-
case '>=': {
|
|
733
|
-
filterFn = _ge;
|
|
734
|
-
break;
|
|
735
|
-
}
|
|
736
|
-
case '>': {
|
|
737
|
-
filterFn = _gt;
|
|
738
|
-
break;
|
|
739
|
-
}
|
|
740
|
-
case '<>': {
|
|
741
|
-
filterFn = _neq;
|
|
742
|
-
break;
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
// scan all records and append only interesting ones
|
|
747
|
-
this.forEach((rec, idx) => {
|
|
748
|
-
// skip deleted
|
|
749
|
-
if (!rec) {
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
let field = rec.getRaw(filterFld);
|
|
753
|
-
if (field === null || field === undefined) {
|
|
754
|
-
field = '';
|
|
755
|
-
}
|
|
756
|
-
else {
|
|
757
|
-
field = '' + field;
|
|
758
|
-
if (!filter.caseSensitive) {
|
|
759
|
-
field = field.toUpperCase();
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
let keep = filterFn(field);
|
|
763
|
-
if (keep) {
|
|
764
|
-
index[iidx++] = idx;
|
|
765
|
-
}
|
|
766
|
-
;
|
|
767
|
-
});
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
return index.slice(0, iidx);
|
|
771
|
-
}
|
|
772
|
-
sortIndex(index, sort) {
|
|
773
|
-
let bads = 0; // unknown fields
|
|
774
|
-
let fidxs = []; // fields indexes
|
|
775
|
-
// if no fields are given, reset sort by id
|
|
776
|
-
if (sort === null) {
|
|
777
|
-
fidxs.push({ fidx: 0, asc: true });
|
|
778
|
-
}
|
|
779
|
-
else {
|
|
780
|
-
fidxs = sort.map((si) => {
|
|
781
|
-
let fi = this.m_model.getFieldIndex(si.field);
|
|
782
|
-
if (fi == -1) {
|
|
783
|
-
console.assert(false, 'unknown field name in sort');
|
|
784
|
-
bads++;
|
|
785
|
-
}
|
|
786
|
-
return { fidx: fi, asc: si.ascending };
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
// unknown field or nothing to sort on ??
|
|
790
|
-
if (bads || fidxs.length == 0) {
|
|
791
|
-
return index;
|
|
792
|
-
}
|
|
793
|
-
// sort only by one field : optimize it
|
|
794
|
-
if (fidxs.length == 1) {
|
|
795
|
-
let field = fidxs[0].fidx;
|
|
796
|
-
index.sort((ia, ib) => {
|
|
797
|
-
let va = this.getByIndex(ia).getRaw(field) ?? '';
|
|
798
|
-
let vb = this.getByIndex(ib).getRaw(field) ?? '';
|
|
799
|
-
if (va > vb) {
|
|
800
|
-
return 1;
|
|
801
|
-
}
|
|
802
|
-
if (va < vb) {
|
|
803
|
-
return -1;
|
|
804
|
-
}
|
|
805
|
-
return 0;
|
|
806
|
-
});
|
|
807
|
-
// just reverse if
|
|
808
|
-
if (!fidxs[0].asc) {
|
|
809
|
-
index.reverse();
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
else {
|
|
813
|
-
index.sort((ia, ib) => {
|
|
814
|
-
for (let fi = 0; fi < fidxs.length; fi++) {
|
|
815
|
-
let fidx = fidxs[fi].fidx;
|
|
816
|
-
let mul = fidxs[fi].asc ? 1 : -1;
|
|
817
|
-
let va = this.getByIndex(ia).getRaw(fidx) ?? '';
|
|
818
|
-
let vb = this.getByIndex(ib).getRaw(fidx) ?? '';
|
|
819
|
-
if (va > vb) {
|
|
820
|
-
return mul;
|
|
821
|
-
}
|
|
822
|
-
if (va < vb) {
|
|
823
|
-
return -mul;
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
return 0;
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
return index;
|
|
830
|
-
}
|
|
831
|
-
/**
|
|
832
|
-
*
|
|
833
|
-
*/
|
|
834
|
-
forEach(cb) {
|
|
835
|
-
if (this.m_rec_index) {
|
|
836
|
-
this.m_rec_index.some((ri, index) => {
|
|
837
|
-
if (cb(this.m_records[ri], index)) {
|
|
838
|
-
return index;
|
|
839
|
-
}
|
|
840
|
-
});
|
|
841
|
-
}
|
|
842
|
-
else {
|
|
843
|
-
this.m_records.some((rec, index) => {
|
|
844
|
-
if (rec) {
|
|
845
|
-
if (cb(rec, index)) {
|
|
846
|
-
return index;
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
});
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
export() {
|
|
853
|
-
return this.m_records;
|
|
854
|
-
}
|
|
855
|
-
changed() {
|
|
856
|
-
this.emit('data_change', EvDataChange('change'));
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
export function EvViewChange(action) {
|
|
860
|
-
return BasicEvent({ action });
|
|
861
|
-
}
|
|
862
|
-
/**
|
|
863
|
-
* Dataview allow different views of the DataStore.
|
|
864
|
-
* You can sort the columns & filter data
|
|
865
|
-
* You can have multiple views for a single DataStore
|
|
866
|
-
*/
|
|
867
|
-
export class DataView extends BaseComponent {
|
|
868
|
-
m_index;
|
|
869
|
-
m_store;
|
|
870
|
-
m_sort;
|
|
871
|
-
m_filter;
|
|
872
|
-
constructor(props) {
|
|
873
|
-
super(props);
|
|
874
|
-
this.m_store = props.store;
|
|
875
|
-
this.m_index = null;
|
|
876
|
-
this.m_filter = null;
|
|
877
|
-
this.m_sort = null;
|
|
878
|
-
this.filter(props.filter);
|
|
879
|
-
if (props.order) {
|
|
880
|
-
if (isString(props.order)) {
|
|
881
|
-
this.sort([{ field: props.order, ascending: true }]);
|
|
882
|
-
}
|
|
883
|
-
else if (isArray(props.order)) {
|
|
884
|
-
this.sort(props.order);
|
|
885
|
-
}
|
|
886
|
-
else {
|
|
887
|
-
this.sort([props.order]);
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
else {
|
|
891
|
-
this.sort(null);
|
|
892
|
-
}
|
|
893
|
-
this.m_store.on('data_change', (e) => this._storeChange(e));
|
|
894
|
-
}
|
|
895
|
-
_storeChange(ev) {
|
|
896
|
-
this._filter(this.m_filter, ev.type != 'change');
|
|
897
|
-
this._sort(this.m_sort, ev.type != 'change');
|
|
898
|
-
this.emit('view_change', EvViewChange('change'));
|
|
899
|
-
}
|
|
900
|
-
/**
|
|
901
|
-
*
|
|
902
|
-
* @param filter
|
|
903
|
-
*/
|
|
904
|
-
filter(filter) {
|
|
905
|
-
this.m_index = null; // null to signal that we have to run on records instead of index
|
|
906
|
-
return this._filter(filter, true);
|
|
907
|
-
}
|
|
908
|
-
_filter(filter, notify) {
|
|
909
|
-
this.m_index = this.m_store.createIndex(filter);
|
|
910
|
-
this.m_filter = filter;
|
|
911
|
-
// need to sort again:
|
|
912
|
-
if (this.m_sort) {
|
|
913
|
-
this.sort(this.m_sort);
|
|
914
|
-
}
|
|
915
|
-
if (notify) {
|
|
916
|
-
this.emit('view_change', EvViewChange('filter'));
|
|
917
|
-
}
|
|
918
|
-
return this.m_index.length;
|
|
919
|
-
}
|
|
920
|
-
/**
|
|
921
|
-
*
|
|
922
|
-
* @param columns
|
|
923
|
-
* @param ascending
|
|
924
|
-
*/
|
|
925
|
-
sort(props) {
|
|
926
|
-
this._sort(props, true);
|
|
927
|
-
}
|
|
928
|
-
_sort(props, notify) {
|
|
929
|
-
this.m_index = this.m_store.sortIndex(this.m_index, props);
|
|
930
|
-
this.m_sort = props;
|
|
931
|
-
if (notify) {
|
|
932
|
-
this.emit('view_change', EvViewChange('sort'));
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
/**
|
|
936
|
-
*
|
|
937
|
-
*/
|
|
938
|
-
get store() {
|
|
939
|
-
return this.m_store;
|
|
940
|
-
}
|
|
941
|
-
/**
|
|
942
|
-
*
|
|
943
|
-
*/
|
|
944
|
-
get count() {
|
|
945
|
-
return this.m_index.length;
|
|
946
|
-
}
|
|
947
|
-
/**
|
|
948
|
-
*
|
|
949
|
-
* @param id
|
|
950
|
-
*/
|
|
951
|
-
indexOfId(id) {
|
|
952
|
-
let ridx = this.m_store.indexOfId(id);
|
|
953
|
-
return this.m_index.findIndex((rid) => rid === ridx);
|
|
954
|
-
}
|
|
955
|
-
/**
|
|
956
|
-
*
|
|
957
|
-
* @param index
|
|
958
|
-
*/
|
|
959
|
-
getByIndex(index) {
|
|
960
|
-
if (index >= 0 && index < this.m_index.length) {
|
|
961
|
-
let rid = this.m_index[index];
|
|
962
|
-
return this.m_store.getByIndex(rid);
|
|
963
|
-
}
|
|
964
|
-
return null;
|
|
965
|
-
}
|
|
966
|
-
/**
|
|
967
|
-
*
|
|
968
|
-
* @param id
|
|
969
|
-
*/
|
|
970
|
-
getById(id) {
|
|
971
|
-
return this.m_store.getById(id);
|
|
972
|
-
}
|
|
973
|
-
changed() {
|
|
974
|
-
this.emit('view_change', EvViewChange('change'));
|
|
975
|
-
}
|
|
976
|
-
/**
|
|
977
|
-
*
|
|
978
|
-
*/
|
|
979
|
-
forEach(cb) {
|
|
980
|
-
debugger;
|
|
981
|
-
this.m_index.some((index) => {
|
|
982
|
-
let rec = this.m_store.getByIndex(index);
|
|
983
|
-
if (rec) {
|
|
984
|
-
if (cb(rec, index)) {
|
|
985
|
-
return index;
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
});
|
|
989
|
-
}
|
|
990
|
-
}
|