x4js 1.6.5 → 2.0.2

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.
Files changed (292) hide show
  1. package/README.md +3 -14
  2. package/lib/README.txt +3 -14
  3. package/lib/esm/x4.css +1 -0
  4. package/lib/esm/x4.js +1 -0
  5. package/lib/src/assets/house-light.svg +1 -0
  6. package/lib/src/assets/radio.svg +4 -0
  7. package/lib/src/components/base.scss +26 -0
  8. package/lib/src/components/boxes/boxes.module.scss +37 -0
  9. package/lib/src/components/boxes/boxes.ts +125 -0
  10. package/lib/src/components/btngroup/btngroup.module.scss +29 -0
  11. package/lib/src/components/btngroup/btngroup.ts +106 -0
  12. package/lib/src/components/button/button.module.scss +154 -0
  13. package/lib/src/components/button/button.ts +117 -0
  14. package/lib/src/components/calendar/calendar-check-sharp-light.svg +1 -0
  15. package/lib/src/components/calendar/calendar.module.scss +163 -0
  16. package/lib/src/{calendar.ts → components/calendar/calendar.ts} +81 -83
  17. package/lib/src/components/calendar/chevron-left-sharp-light.svg +1 -0
  18. package/lib/src/components/calendar/chevron-right-sharp-light.svg +1 -0
  19. package/lib/src/components/checkbox/check.svg +4 -0
  20. package/lib/src/components/checkbox/checkbox.module.scss +142 -0
  21. package/lib/src/components/checkbox/checkbox.ts +125 -0
  22. package/lib/src/components/colorinput/colorinput.module.scss +65 -0
  23. package/lib/src/components/colorinput/colorinput.ts +88 -0
  24. package/lib/src/components/colorinput/crosshairs-simple-sharp-light.svg +1 -0
  25. package/lib/src/components/colorpicker/colorpicker.module.scss +133 -0
  26. package/lib/src/components/colorpicker/colorpicker.ts +477 -0
  27. package/lib/src/components/combobox/combobox.module.scss +121 -0
  28. package/lib/src/components/combobox/combobox.ts +190 -0
  29. package/lib/src/components/combobox/updown.svg +4 -0
  30. package/lib/src/components/dialog/dialog.module.scss +71 -0
  31. package/lib/src/components/dialog/dialog.ts +91 -0
  32. package/lib/src/components/dialog/xmark-sharp-light.svg +1 -0
  33. package/lib/src/components/form/form.module.scss +34 -0
  34. package/lib/src/components/form/form.ts +36 -0
  35. package/lib/src/components/header/header.module.scss +40 -0
  36. package/lib/src/components/header/header.ts +124 -0
  37. package/lib/src/components/icon/icon.module.scss +30 -0
  38. package/lib/src/components/icon/icon.ts +134 -0
  39. package/lib/src/components/image/image.module.scss +21 -0
  40. package/lib/src/components/image/image.ts +67 -0
  41. package/lib/src/components/input/input.module.scss +69 -0
  42. package/lib/src/components/input/input.ts +274 -0
  43. package/lib/src/components/label/label.module.scss +52 -0
  44. package/lib/src/components/label/label.ts +55 -0
  45. package/lib/src/components/listbox/listbox.module.scss +103 -0
  46. package/lib/src/components/listbox/listbox.ts +427 -0
  47. package/lib/src/components/menu/caret-right-solid.svg +1 -0
  48. package/lib/src/components/menu/menu.module.scss +108 -0
  49. package/lib/src/components/menu/menu.ts +168 -0
  50. package/lib/src/components/messages/circle-exclamation.svg +1 -0
  51. package/lib/src/components/messages/messages.module.scss +47 -0
  52. package/lib/src/components/messages/messages.ts +64 -0
  53. package/lib/src/components/normalize.scss +386 -0
  54. package/lib/src/components/notification/circle-check-solid.svg +1 -0
  55. package/lib/src/components/notification/circle-exclamation-solid.svg +1 -0
  56. package/lib/src/components/notification/circle-notch-light.svg +1 -0
  57. package/lib/src/components/notification/notification.module.scss +82 -0
  58. package/lib/src/components/notification/notification.ts +108 -0
  59. package/lib/src/components/notification/xmark-sharp-light.svg +1 -0
  60. package/lib/src/components/panel/panel.module.scss +48 -0
  61. package/lib/src/components/panel/panel.ts +57 -0
  62. package/lib/src/components/popup/popup.module.scss +43 -0
  63. package/lib/src/components/popup/popup.ts +395 -0
  64. package/lib/src/components/progress/progress.module.scss +57 -0
  65. package/lib/src/components/progress/progress.ts +43 -0
  66. package/lib/src/components/rating/rating.module.scss +23 -0
  67. package/lib/src/components/rating/rating.ts +125 -0
  68. package/lib/src/components/rating/star-sharp-light.svg +1 -0
  69. package/lib/src/components/rating/star-sharp-solid.svg +1 -0
  70. package/lib/src/components/shared.scss +76 -0
  71. package/lib/src/components/sizers/sizer.module.scss +90 -0
  72. package/lib/src/components/sizers/sizer.ts +120 -0
  73. package/lib/src/components/slider/slider.module.scss +71 -0
  74. package/lib/src/components/slider/slider.ts +143 -0
  75. package/lib/src/components/switch/switch.module.scss +127 -0
  76. package/lib/src/components/switch/switch.ts +56 -0
  77. package/lib/src/components/tabs/tabs.module.scss +46 -0
  78. package/lib/src/components/tabs/tabs.ts +157 -0
  79. package/lib/src/components/textarea/textarea.module.scss +59 -0
  80. package/lib/src/components/textarea/textarea.ts +54 -0
  81. package/lib/src/components/textedit/textedit.module.scss +114 -0
  82. package/lib/src/components/textedit/textedit.ts +82 -0
  83. package/lib/src/components/themes.scss +77 -0
  84. package/lib/src/components/tooltips/circle-info-sharp-light.svg +1 -0
  85. package/lib/src/components/tooltips/tooltips.scss +51 -0
  86. package/lib/src/components/tooltips/tooltips.ts +103 -0
  87. package/lib/src/components/treeview/chevron-down-light.svg +1 -0
  88. package/lib/src/components/treeview/treeview.module.scss +116 -0
  89. package/lib/src/components/treeview/treeview.ts +403 -0
  90. package/lib/src/components/viewport/viewport.module.scss +25 -0
  91. package/lib/src/components/viewport/viewport.ts +38 -0
  92. package/lib/src/core/component.ts +979 -0
  93. package/lib/src/core/core_colors.ts +250 -0
  94. package/lib/src/{dom_events.ts → core/core_dom.ts} +195 -39
  95. package/lib/src/{drag_manager.ts → core/core_dragdrop.ts} +29 -44
  96. package/lib/src/core/core_element.ts +98 -0
  97. package/lib/src/core/core_events.ts +149 -0
  98. package/lib/src/{i18n.ts → core/core_i18n.ts} +43 -42
  99. package/lib/src/{router.ts → core/core_router.ts} +27 -40
  100. package/lib/src/core/core_styles.ts +215 -0
  101. package/lib/src/core/core_svg.ts +550 -0
  102. package/lib/src/core/core_tools.ts +673 -0
  103. package/lib/src/demo/assets/house-light.svg +1 -0
  104. package/lib/src/demo/assets/radio.svg +4 -0
  105. package/lib/src/demo/index.html +12 -0
  106. package/lib/src/demo/main.scss +21 -0
  107. package/lib/src/demo/main.tsx +323 -0
  108. package/lib/src/main.scss +21 -0
  109. package/lib/src/main.tsx +323 -0
  110. package/lib/src/x4.scss +19 -0
  111. package/lib/src/x4.ts +60 -0
  112. package/lib/types/x4.d.ts +26548 -0
  113. package/package.json +68 -59
  114. package/scripts/build.mjs +351 -0
  115. package/scripts/prepack.mjs +43 -0
  116. package/src/components/base.scss +26 -0
  117. package/src/components/boxes/boxes.module.scss +37 -0
  118. package/src/components/boxes/boxes.ts +125 -0
  119. package/src/components/btngroup/btngroup.module.scss +29 -0
  120. package/src/components/btngroup/btngroup.ts +106 -0
  121. package/src/components/button/button.module.scss +154 -0
  122. package/src/components/button/button.ts +117 -0
  123. package/src/components/calendar/calendar-check-sharp-light.svg +1 -0
  124. package/src/components/calendar/calendar.module.scss +163 -0
  125. package/src/components/calendar/calendar.ts +326 -0
  126. package/src/components/calendar/chevron-left-sharp-light.svg +1 -0
  127. package/src/components/calendar/chevron-right-sharp-light.svg +1 -0
  128. package/src/components/checkbox/check.svg +4 -0
  129. package/src/components/checkbox/checkbox.module.scss +142 -0
  130. package/src/components/checkbox/checkbox.ts +125 -0
  131. package/src/components/colorinput/colorinput.module.scss +65 -0
  132. package/src/components/colorinput/colorinput.ts +88 -0
  133. package/src/components/colorinput/crosshairs-simple-sharp-light.svg +1 -0
  134. package/src/components/colorpicker/colorpicker.module.scss +133 -0
  135. package/src/components/colorpicker/colorpicker.ts +477 -0
  136. package/src/components/combobox/combobox.module.scss +121 -0
  137. package/src/components/combobox/combobox.ts +190 -0
  138. package/src/components/combobox/updown.svg +4 -0
  139. package/src/components/dialog/dialog.module.scss +71 -0
  140. package/src/components/dialog/dialog.ts +91 -0
  141. package/src/components/dialog/xmark-sharp-light.svg +1 -0
  142. package/src/components/form/form.module.scss +34 -0
  143. package/src/components/form/form.ts +36 -0
  144. package/src/components/header/header.module.scss +40 -0
  145. package/src/components/header/header.ts +124 -0
  146. package/src/components/icon/icon.module.scss +30 -0
  147. package/src/components/icon/icon.ts +134 -0
  148. package/src/components/image/image.module.scss +21 -0
  149. package/src/components/image/image.ts +67 -0
  150. package/src/components/input/input.module.scss +69 -0
  151. package/src/components/input/input.ts +274 -0
  152. package/src/components/label/label.module.scss +52 -0
  153. package/src/components/label/label.ts +55 -0
  154. package/src/components/listbox/listbox.module.scss +103 -0
  155. package/src/components/listbox/listbox.ts +427 -0
  156. package/src/components/menu/caret-right-solid.svg +1 -0
  157. package/src/components/menu/menu.module.scss +108 -0
  158. package/src/components/menu/menu.ts +168 -0
  159. package/src/components/messages/circle-exclamation.svg +1 -0
  160. package/src/components/messages/messages.module.scss +47 -0
  161. package/src/components/messages/messages.ts +64 -0
  162. package/src/components/normalize.scss +386 -0
  163. package/src/components/notification/circle-check-solid.svg +1 -0
  164. package/src/components/notification/circle-exclamation-solid.svg +1 -0
  165. package/src/components/notification/circle-notch-light.svg +1 -0
  166. package/src/components/notification/notification.module.scss +82 -0
  167. package/src/components/notification/notification.ts +108 -0
  168. package/src/components/notification/xmark-sharp-light.svg +1 -0
  169. package/src/components/panel/panel.module.scss +48 -0
  170. package/src/components/panel/panel.ts +57 -0
  171. package/src/components/popup/popup.module.scss +43 -0
  172. package/src/components/popup/popup.ts +395 -0
  173. package/src/components/progress/progress.module.scss +57 -0
  174. package/src/components/progress/progress.ts +43 -0
  175. package/src/components/rating/rating.module.scss +23 -0
  176. package/src/components/rating/rating.ts +125 -0
  177. package/src/components/rating/star-sharp-light.svg +1 -0
  178. package/src/components/rating/star-sharp-solid.svg +1 -0
  179. package/src/components/shared.scss +76 -0
  180. package/src/components/sizers/sizer.module.scss +90 -0
  181. package/src/components/sizers/sizer.ts +120 -0
  182. package/src/components/slider/slider.module.scss +71 -0
  183. package/src/components/slider/slider.ts +143 -0
  184. package/src/components/switch/switch.module.scss +127 -0
  185. package/src/components/switch/switch.ts +56 -0
  186. package/src/components/tabs/tabs.module.scss +46 -0
  187. package/src/components/tabs/tabs.ts +157 -0
  188. package/src/components/textarea/textarea.module.scss +59 -0
  189. package/src/components/textarea/textarea.ts +54 -0
  190. package/src/components/textedit/textedit.module.scss +114 -0
  191. package/src/components/textedit/textedit.ts +82 -0
  192. package/src/components/themes.scss +77 -0
  193. package/src/components/tooltips/circle-info-sharp-light.svg +1 -0
  194. package/src/components/tooltips/tooltips.scss +51 -0
  195. package/src/components/tooltips/tooltips.ts +103 -0
  196. package/src/components/treeview/chevron-down-light.svg +1 -0
  197. package/src/components/treeview/treeview.module.scss +116 -0
  198. package/src/components/treeview/treeview.ts +403 -0
  199. package/src/components/viewport/viewport.module.scss +25 -0
  200. package/src/components/viewport/viewport.ts +38 -0
  201. package/src/core/component.ts +979 -0
  202. package/src/core/core_colors.ts +250 -0
  203. package/src/core/core_dom.ts +471 -0
  204. package/src/core/core_dragdrop.ts +201 -0
  205. package/src/core/core_element.ts +98 -0
  206. package/src/core/core_events.ts +149 -0
  207. package/src/core/core_i18n.ts +377 -0
  208. package/src/core/core_router.ts +221 -0
  209. package/src/core/core_styles.ts +215 -0
  210. package/src/core/core_svg.ts +550 -0
  211. package/src/core/core_tools.ts +673 -0
  212. package/src/demo/assets/house-light.svg +1 -0
  213. package/src/demo/assets/radio.svg +4 -0
  214. package/src/demo/index.html +12 -0
  215. package/src/demo/main.scss +21 -0
  216. package/src/demo/main.tsx +323 -0
  217. package/src/x4.scss +19 -0
  218. package/src/x4.ts +60 -0
  219. package/tsconfig.json +14 -0
  220. package/types/scss.d.ts +4 -0
  221. package/types/svg.d.ts +4 -0
  222. package/types/x4react.d.ts +9 -0
  223. package/lib/changelog.txt +0 -23
  224. package/lib/cjs/x4js.js +0 -39
  225. package/lib/cjs/x4js.js.map +0 -7
  226. package/lib/esm/x4js.mjs +0 -15972
  227. package/lib/esm/x4js.mjs.map +0 -7
  228. package/lib/licence.md +0 -21
  229. package/lib/src/MIT-license.md +0 -14
  230. package/lib/src/action.ts +0 -88
  231. package/lib/src/alpha.jpg +0 -0
  232. package/lib/src/app_sockets.ts +0 -81
  233. package/lib/src/application.ts +0 -262
  234. package/lib/src/autocomplete.ts +0 -232
  235. package/lib/src/base64.ts +0 -166
  236. package/lib/src/base_component.ts +0 -152
  237. package/lib/src/button.ts +0 -355
  238. package/lib/src/canvas.ts +0 -510
  239. package/lib/src/cardview.ts +0 -228
  240. package/lib/src/checkbox.ts +0 -188
  241. package/lib/src/color.ts +0 -752
  242. package/lib/src/colorpicker.ts +0 -1649
  243. package/lib/src/combobox.ts +0 -512
  244. package/lib/src/component.ts +0 -2367
  245. package/lib/src/copyright.txt +0 -27
  246. package/lib/src/datastore.ts +0 -1302
  247. package/lib/src/dialog.ts +0 -656
  248. package/lib/src/drawtext.ts +0 -355
  249. package/lib/src/fileupload.ts +0 -213
  250. package/lib/src/form.ts +0 -413
  251. package/lib/src/formatters.ts +0 -105
  252. package/lib/src/gridview.ts +0 -1185
  253. package/lib/src/icon.ts +0 -362
  254. package/lib/src/image.ts +0 -225
  255. package/lib/src/index.ts +0 -89
  256. package/lib/src/input.ts +0 -297
  257. package/lib/src/label.ts +0 -153
  258. package/lib/src/layout.ts +0 -442
  259. package/lib/src/link.ts +0 -86
  260. package/lib/src/listview.ts +0 -765
  261. package/lib/src/md5.ts +0 -438
  262. package/lib/src/menu.ts +0 -425
  263. package/lib/src/messagebox.ts +0 -224
  264. package/lib/src/panel.ts +0 -86
  265. package/lib/src/popup.ts +0 -494
  266. package/lib/src/property_editor.ts +0 -337
  267. package/lib/src/radiobtn.ts +0 -197
  268. package/lib/src/rating.ts +0 -135
  269. package/lib/src/request.ts +0 -300
  270. package/lib/src/settings.ts +0 -77
  271. package/lib/src/sidebarview.ts +0 -108
  272. package/lib/src/spreadsheet.ts +0 -1449
  273. package/lib/src/styles.ts +0 -343
  274. package/lib/src/svgcomponent.ts +0 -592
  275. package/lib/src/tabbar.ts +0 -151
  276. package/lib/src/tabview.ts +0 -110
  277. package/lib/src/textarea.ts +0 -235
  278. package/lib/src/textedit.ts +0 -533
  279. package/lib/src/toaster.ts +0 -80
  280. package/lib/src/tools.ts +0 -1473
  281. package/lib/src/tooltips.ts +0 -191
  282. package/lib/src/treeview.ts +0 -716
  283. package/lib/src/version.ts +0 -30
  284. package/lib/src/x4.less +0 -2242
  285. package/lib/src/x4dom.ts +0 -57
  286. package/lib/src/x4events.ts +0 -585
  287. package/lib/src/x4js.ts +0 -89
  288. package/lib/src/x4react.ts +0 -90
  289. package/lib/styles/x4.css +0 -1785
  290. package/lib/styles/x4.less +0 -2242
  291. package/lib/types/x4js.d.ts +0 -6728
  292. package/license.md +0 -21
@@ -1,1302 +0,0 @@
1
- /**
2
- * ___ ___ __
3
- * \ \/ / / _
4
- * \ / /_| |_
5
- * / \____ _|
6
- * /__/\__\ |_|
7
- *
8
- * @file datastore.ts
9
- * @author Etienne Cochard
10
- *
11
- * Copyright (c) 2019-2023 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
-
30
- import { ajaxRequest } from './request';
31
- import { isArray, isString } from './tools';
32
- import { BasicEvent, EvChange, EvSource, EventMap, } from './x4events';
33
- import { BaseComponent, BaseComponentEventMap, BaseComponentProps } from './base_component';
34
-
35
- export type ChangeCallback = (type: string, id?: any) => void;
36
- export type CalcCallback = () => string;
37
-
38
- export type FieldType = 'string' | 'int' | 'float' | 'date' | 'bool' | 'array' | 'object' | 'any' | 'calc';
39
- export type DataIndex = Uint32Array;
40
-
41
- export interface EvDataChange extends BasicEvent {
42
- type: string;
43
- id: any;
44
- }
45
-
46
- export function EvDataChange( type: 'create' | 'update' | 'delete' | 'data' | 'change', id?: any ) {
47
- return BasicEvent<EvDataChange>( { type, id } );
48
- }
49
-
50
-
51
-
52
-
53
- /**
54
- * fields definition
55
- * field with index=0 is record id
56
- */
57
-
58
- export interface MetaData {
59
- type?: FieldType;
60
- prec?: number;
61
- required?: boolean;
62
- calc?: (rec: Record) => any;
63
- model?: Record; // in case of array of subtypes, the model
64
- }
65
-
66
- export interface FieldInfo extends MetaData {
67
- name: string;
68
- }
69
-
70
- /**
71
- *
72
- */
73
-
74
- class MetaInfos {
75
- name: string;
76
- id: string; // field name holding 'id' record info
77
- fields: FieldInfo[]; // field list
78
-
79
- constructor( name: string ) {
80
- this.name = name;
81
- this.id = undefined;
82
- this.fields = [];
83
- }
84
- }
85
-
86
- const metaFields = Symbol( 'metaField' );
87
-
88
- function _getMetas( obj: object, create = true ) : MetaInfos {
89
-
90
- let ctor = obj.constructor;
91
- let mfld = ctor.hasOwnProperty(metaFields) ? ctor[metaFields] : undefined;
92
-
93
- if( mfld===undefined ) {
94
- if( !create ) {
95
- console.assert( mfld!==undefined );
96
- }
97
-
98
- // construct our metas
99
- mfld = new MetaInfos( ctor.name );
100
-
101
- // merge with parent class metas
102
- let pctor = Object.getPrototypeOf(ctor);
103
- if( pctor!=Record ) {
104
- let pmetas = pctor[metaFields];
105
- mfld.fields = [...pmetas.fields, ...mfld.fields ]
106
-
107
- console.assert( mfld.id===undefined, 'cannot define mutiple record id' );
108
- if( !mfld.id ) {
109
- mfld.id = pmetas.id;
110
- }
111
- }
112
-
113
- obj.constructor[metaFields] = mfld;
114
- }
115
-
116
- return mfld;
117
- }
118
-
119
- export namespace data {
120
-
121
- /**
122
- * define a record id
123
- * @example
124
- * \@data_id()
125
- * id: string; // this field is the record id
126
- **/
127
-
128
- export function id( ) {
129
- return ( ownerCls, fldName ) => {
130
- let metas = _getMetas( ownerCls );
131
- metas.fields.push( {
132
- name: fldName,
133
- type: 'any',
134
- required: true,
135
- });
136
-
137
- metas.id = fldName;
138
- }
139
- }
140
-
141
- /**
142
- * @ignore
143
- */
144
-
145
- export function field( data: MetaData ) {
146
-
147
- return ( ownerCls, fldName ) => {
148
- let metas = _getMetas( ownerCls );
149
- metas.fields.push( {
150
- name: fldName,
151
- ...data
152
- } );
153
- }
154
- }
155
-
156
- /**
157
- * following member is a string field
158
- * @example
159
- * \@data_string()
160
- * my_field: string; // this field will be seen as a string
161
- */
162
-
163
- export function string( props?: MetaData ) {
164
- return field( { ...props, type: 'string' } );
165
- }
166
-
167
- /**
168
- * following member is an integer field
169
- * @example
170
- * \@data_string()
171
- * my_field: number; // this field will be seen as an integer
172
- */
173
-
174
- export function int( props?: MetaData ) {
175
- return field( { ...props, type: 'int' } );
176
- }
177
-
178
- /**
179
- * following member is a float field
180
- * @example
181
- * \@data_float()
182
- * my_field: number; // this field will be seen as a float
183
- */
184
-
185
- export function float( props?: MetaData ) {
186
- return field( { ...props, type: 'float' } );
187
- }
188
-
189
- /**
190
- * following member is a boolean field
191
- * @example
192
- * \@data_bool()
193
- * my_field: boolean; // this field will be seen as a boolean
194
- */
195
-
196
- export function bool( props?: MetaData ) {
197
- return field( { ...props, type: 'bool' } );
198
- }
199
-
200
- /**
201
- * following member is a date field
202
- * @example
203
- * \@data_date()
204
- * my_field: date; // this field will be seen as a date
205
- */
206
-
207
- export function date( props?: MetaData ) {
208
- return field( { ...props, type: 'date' } );
209
- }
210
-
211
- /**
212
- * following member is a calculated field
213
- * @example
214
- * \@data_calc( )
215
- * get my_field(): string => {
216
- * return 'hello';
217
- * };
218
- */
219
-
220
- export function calc( props?: MetaData ) {
221
- return field( { ...props, type: 'calc'} )
222
- }
223
-
224
-
225
-
226
- /**
227
- *
228
- */
229
-
230
- interface RecordConstructor {
231
- new ( data?: any, id?: any ): Record;
232
- }
233
-
234
- /**
235
- * following member is a record array
236
- * @example
237
- * \@data_array( )
238
- * my_field(): TypedRecord[];
239
- */
240
-
241
- export function array( ctor: RecordConstructor, props?: MetaData ) {
242
- return data.field( { ...props, type: 'array', model: ctor ? new ctor() : null } )
243
- }
244
-
245
- }
246
-
247
-
248
-
249
-
250
- /**
251
- * record model
252
- */
253
-
254
- export class Record {
255
-
256
- constructor( data?: any, id?: any ) {
257
-
258
- if( data!==undefined ) {
259
- this.unSerialize( data, id );
260
- }
261
- }
262
-
263
- clone( source?: any ) {
264
- let rec = new (this.constructor as any)( );
265
- if( source ) {
266
- rec.unSerialize( source );
267
- }
268
- return rec;
269
- }
270
-
271
- /**
272
- * get the record unique identifier
273
- * by default the return value is the first field
274
- * @return unique identifier
275
- */
276
-
277
- getID(): any {
278
- let metas = _getMetas( this, false );
279
- return this[metas.id];
280
- }
281
-
282
- /**
283
- * MUST IMPLEMENT
284
- * @returns fields descriptors
285
- */
286
-
287
- getFields(): FieldInfo[] {
288
- let metas = _getMetas( this, false );
289
- return metas.fields;
290
- }
291
-
292
- /**
293
- *
294
- */
295
-
296
- validate( ) : Error[] {
297
-
298
- let errs: Error[] = null;
299
-
300
- let fields = this.getFields( );
301
- fields.forEach( (fi) => {
302
- if( fi.required && !this.getField(fi.name) ) {
303
- if( errs ) {
304
- errs = [];
305
- }
306
-
307
- errs.push( new Error( `field ${fi.name} is required.` ) );
308
- }
309
- })
310
-
311
- return errs;
312
- }
313
-
314
- //mapAnyFields() {
315
- // this.getFields = ( ) => {
316
- // return Object.keys( this ).map( (name) => {
317
- // return <FieldInfo>{ name };
318
- // });
319
- // }
320
- //}
321
-
322
- getFieldIndex( name: string ) : number {
323
- let fields = this.getFields( );
324
- return fields.findIndex( (fd) => fd.name == name );
325
- }
326
-
327
- /**
328
- * default serializer
329
- * @returns an object with known record values
330
- */
331
-
332
- serialize(): any {
333
- let rec = {};
334
-
335
- this.getFields().forEach((f) => {
336
- if( f.calc === undefined ) {
337
- rec[f.name] = rec[f.name];
338
- }
339
- });
340
-
341
- return rec;
342
- }
343
-
344
- /**
345
- * default unserializer
346
- * @param data - input data
347
- * @returns a new Record
348
- */
349
-
350
- unSerialize(data: any, id?: any) : Record {
351
-
352
- let fields = this.getFields();
353
-
354
- fields.forEach( (sf) => {
355
- let value = data[sf.name];
356
- if (value !== undefined) {
357
- this[sf.name] = this._convertField( sf, value );
358
- }
359
- });
360
-
361
- if( id!==undefined ) {
362
- this[fields[0].name] = id;
363
- }
364
- else {
365
- console.assert( this.getID()!==undefined ); // store do not have ID field
366
- }
367
-
368
- return this;
369
- }
370
-
371
- /**
372
- * field conversion
373
- * @param field - field descriptor
374
- * @param input - value to convert
375
- * @returns the field value in it's original form
376
- */
377
-
378
- protected _convertField( field: FieldInfo, input: any ) : any {
379
-
380
- //TODO: boolean
381
-
382
- switch( field.type ) {
383
- case 'float': {
384
- let ffv: number = typeof (input) === 'number' ? input : parseFloat(input);
385
-
386
- if (field.prec !== undefined) {
387
- let mul = Math.pow(10, field.prec);
388
- ffv = Math.round(ffv * mul) / mul;
389
- }
390
-
391
- return ffv;
392
- }
393
-
394
- case 'int': {
395
- return typeof (input) === 'number' ? input : parseInt(input);
396
- }
397
-
398
- case 'date': {
399
- return isString(input) ? new Date(input) : input;
400
- }
401
-
402
- case 'array': {
403
- let result = [];
404
-
405
- if( field.model ) {
406
- input.forEach( ( v ) => {
407
- result.push( field.model.clone( v ) );
408
- })
409
-
410
- return result;
411
- }
412
- break;
413
- }
414
- }
415
-
416
- return input;
417
- }
418
-
419
- /**
420
- * get raw value of a field
421
- * @param name - field name or field index
422
- */
423
-
424
- getRaw( name: string | number ) : any {
425
-
426
- let idx;
427
- let fields = this.getFields( );
428
-
429
- if( typeof(name) === 'string' ) {
430
- idx = fields.findIndex( fi => fi.name == name );
431
- if( idx < 0 ) {
432
- console.assert( false, 'unknown field: '+name);
433
- return undefined;
434
- }
435
- }
436
- else if( name<fields.length ) {
437
- if( name<0 ) {
438
- return undefined
439
- }
440
-
441
- idx = name;
442
- }
443
- else {
444
- console.assert( false, 'bad field name: '+name);
445
- return undefined;
446
- }
447
-
448
- let fld = fields[idx];
449
- if( fld.calc!==undefined ) {
450
- return fld.calc( this );
451
- }
452
-
453
- return this[fld.name];
454
- }
455
-
456
- /**
457
- *
458
- * @param name
459
- * @param data
460
- */
461
-
462
- setRaw( name: string, data: string ) {
463
- this[name] = data;
464
- }
465
-
466
- /**
467
- * get field value (as string)
468
- * @param name - field name
469
- * @example
470
- * let value = record.get('field1');
471
- */
472
-
473
- getField( name: string ): string {
474
- let v = this.getRaw( name );
475
- return (v===undefined || v===null) ? '' : ''+v;
476
- }
477
-
478
- /**
479
- * set field value
480
- * @param name - field name
481
- * @param value - value to set
482
- * @example
483
- * record.set( 'field1', 7 );
484
- */
485
-
486
- setField(name: string, value: any) {
487
- let fields = this.getFields( );
488
- let idx = fields.findIndex( fi => fi.name == name );
489
-
490
- if( idx < 0 ) {
491
- console.assert( false, 'unknown field: '+name);
492
- return;
493
- }
494
-
495
- let fld = fields[idx];
496
- if( fld.calc!==undefined ) {
497
- console.assert( false, 'cannot set calc field: '+name);
498
- return;
499
- }
500
-
501
- this.setRaw( fld.name, value );
502
- }
503
- }
504
-
505
- /**
506
- * by default, the field id is rhe first member or the record
507
- */
508
-
509
- export class AutoRecord extends Record {
510
-
511
- private m_data;
512
- private m_fid: string;
513
-
514
- constructor( data: any ) {
515
- super( );
516
-
517
- this.m_data = data;
518
- }
519
-
520
- getID( ) {
521
- if( !this.m_fid ) {
522
- let fnames = Object.keys( this.m_data );
523
- this.m_fid = fnames[0];
524
- }
525
-
526
- return this.m_data[this.m_fid];
527
- }
528
-
529
- getFields( ) : FieldInfo[] {
530
- let fnames = Object.keys( this.m_data );
531
- let fields: FieldInfo[] = fnames.map( (n) => {
532
- return {
533
- name: n
534
- };
535
- })
536
-
537
- return fields;
538
- }
539
-
540
- getRaw( name: string ) : string {
541
- return this.m_data[name];
542
- }
543
-
544
- setRaw( name: string, data: string ) {
545
- this.m_data[name] = data;
546
- }
547
-
548
- clone( data ) {
549
- return new AutoRecord( {...data} );
550
- }
551
- }
552
-
553
- /**
554
- *
555
- */
556
-
557
- interface DataEventMap extends BaseComponentEventMap {
558
- change?: EvChange;
559
- }
560
-
561
- type DataSolver = ( data: any ) => Record[];
562
-
563
- export interface DataProxyProps extends BaseComponentProps<DataEventMap> {
564
- url: string;
565
- params?: string[];
566
- solver?: DataSolver;
567
- }
568
-
569
- export class DataProxy extends BaseComponent<DataProxyProps,DataEventMap> {
570
-
571
- constructor( props: DataProxyProps ) {
572
- super( props );
573
- }
574
-
575
- async load( url?: string ) {
576
- if( url ) {
577
- this.m_props.url = url;
578
- }
579
- else {
580
- url = this.m_props.url;
581
- }
582
-
583
- if( this.m_props.params ) {
584
- url += '?' + this.m_props.params.join( '&' );
585
- }
586
-
587
- const r = await fetch( url );
588
- if( r.ok ) {
589
- const raw = await r.json( );
590
-
591
- let json = raw;
592
- if( this.m_props.solver ) {
593
- json = this.m_props.solver( json );
594
- }
595
-
596
- this.emit( 'change', EvChange(json,raw) );
597
- }
598
- }
599
- }
600
-
601
-
602
- /**
603
- *
604
- */
605
-
606
- interface DataStoreProps<T extends Record> extends BaseComponentProps<DataStoreEventMap> {
607
- model: T;
608
- data?: T[];
609
- url?: string;
610
- autoload?: false;
611
- }
612
-
613
-
614
- interface DataStoreEventMap extends EventMap {
615
- data_change: EvDataChange;
616
- }
617
-
618
-
619
-
620
- /**
621
- *
622
- */
623
-
624
- export class DataStore<T extends Record = Record> extends EvSource<DataStoreEventMap> {
625
-
626
- protected m_model: T;
627
- protected m_fields: FieldInfo[];
628
- protected m_records: T[];
629
-
630
- protected m_proxy: DataProxy;
631
- protected m_rec_index: DataIndex;
632
-
633
- constructor(props: DataStoreProps<T> ) {
634
- super( );
635
-
636
- this.m_fields = undefined;
637
- this.m_records = [];
638
- this.m_rec_index = null;
639
- this.m_model = props.model;
640
- this.m_fields = props.model.getFields();
641
-
642
- if (props.data) {
643
- this.setRawData( props.data );
644
- }
645
- else if( props.url ) {
646
- this.m_proxy = new DataProxy( {
647
- url: props.url,
648
- solver: props.solver,
649
- events: { change: (ev) => { this.setData( ev.value ); } }
650
- });
651
-
652
- if( props.autoload!=false ) {
653
- this.m_proxy.load( );
654
- }
655
- }
656
- }
657
-
658
- /**
659
- *
660
- * @param records
661
- */
662
-
663
- async load( url?: string ) {
664
- return this.m_proxy.load( url );
665
- }
666
-
667
- async reload( ) {
668
- return this.m_proxy.load( );
669
- }
670
-
671
- /**
672
- * convert raw objects to real records from model
673
- * @param records
674
- */
675
-
676
- public setData( records: any[] ) {
677
-
678
- let realRecords: T[] = [];
679
-
680
- records.forEach( (rec) => {
681
- realRecords.push( this.m_model.clone(rec) );
682
- });
683
-
684
- this.setRawData( realRecords );
685
- }
686
-
687
- /**
688
- * just set the records
689
- * @param records - must be of the same type as model
690
- */
691
-
692
- public setRawData(records: T[]) {
693
-
694
- this.m_records = records;
695
- this._rebuildIndex( );
696
- this.emit( 'data_change', EvDataChange( 'change' ) );
697
- }
698
-
699
-
700
- private _rebuildIndex( ) {
701
- this.m_rec_index = null; // null to signal that we have to run on records instead of index
702
- this.m_rec_index = this.createIndex( null ); // prepare index (remove deleted)
703
- this.m_rec_index = this.sortIndex( this.m_rec_index, null ); // sort by id
704
- }
705
-
706
- /**
707
- *
708
- */
709
-
710
- public update( rec: T ) {
711
- let id = rec.getID();
712
- let index = this.indexOfId(id);
713
- if (index < 0) {
714
- return false;
715
- }
716
-
717
- this.m_records[this.m_rec_index[index]] = rec;
718
- this.emit( 'data_change', EvDataChange( 'update', id ) );
719
- return true;
720
- }
721
-
722
- /**
723
- *
724
- * @param data
725
- */
726
-
727
- public append( rec: T | any ) {
728
-
729
- if( !(rec instanceof Record) ) {
730
- let nrec = this.m_model.clone( );
731
- rec = nrec.unSerialize( rec );
732
- }
733
-
734
- console.assert( rec.getID() );
735
-
736
- this.m_records.push( rec );
737
- this._rebuildIndex( );
738
- this.emit( 'data_change', EvDataChange( 'create', rec.getID() ) );
739
- }
740
-
741
- /**
742
- *
743
- */
744
-
745
- getMaxId( ) {
746
- let maxID = undefined;
747
- this.m_records.forEach( (r) => {
748
- let rid = r.getID( );
749
- if( maxID===undefined || maxID<rid ) {
750
- maxID = rid;
751
- }
752
- });
753
-
754
- return maxID;
755
- }
756
-
757
- /**
758
- *
759
- * @param id
760
- */
761
-
762
- public delete(id: any): boolean {
763
-
764
- let idx = this.indexOfId( id );
765
- if( idx<0 ) {
766
- return false;
767
- }
768
-
769
- idx = this.m_rec_index[idx];
770
-
771
- // mark as deleted
772
- this.m_records.splice( idx, 1 );
773
- this._rebuildIndex( );
774
- this.emit( 'data_change', EvDataChange( 'delete', id ) );
775
- return true;
776
- }
777
-
778
- /**
779
- * return the number of records
780
- */
781
-
782
- get count( ) : number {
783
- return this.m_rec_index ? this.m_rec_index.length : this.m_records.length;
784
- }
785
-
786
- /**
787
- * return the fields
788
- */
789
-
790
- get fields( ) : FieldInfo [] {
791
- return this.m_fields;
792
- }
793
-
794
- /**
795
- * find the index of the element with the given id
796
- */
797
-
798
- public indexOfId(id: any ): number {
799
-
800
- //if( this.count<10 ) {
801
- // this.forEach( (rec) => rec.getID() == id );
802
- //}
803
-
804
- for( let lim = this.count, base = 0; lim != 0; lim >>= 1 ) {
805
-
806
- let p = base + (lim >> 1); // int conversion
807
- let idx = this.m_rec_index[p];
808
- let rid = this.m_records[idx].getID( );
809
-
810
- if( rid==id ) {
811
- return p;
812
- }
813
-
814
- if( rid<id ) {
815
- base = p+1;
816
- lim--;
817
- }
818
- }
819
-
820
- return -1;
821
- }
822
-
823
- /**
824
- * return the record by it's id
825
- * @returns record or null
826
- */
827
-
828
- public getById(id: any): T {
829
- let idx = this.indexOfId( id );
830
- if( idx<0 ) {
831
- return null;
832
- }
833
-
834
- idx = this.m_rec_index[idx];
835
- return this.m_records[idx];
836
- }
837
-
838
- /**
839
- * return a record by it's index
840
- * @returns record or null
841
- */
842
-
843
- public getByIndex( index: number ): T {
844
- let idx = this.m_rec_index[index];
845
- return this._getRecord( idx );
846
- }
847
-
848
- private _getRecord( index: number ) : T {
849
- return this.m_records[index] ?? null;
850
- }
851
-
852
- public moveTo( other: DataStore<T> ) {
853
- other.setRawData( this.m_records );
854
- }
855
-
856
- /**
857
- * create a new view on the DataStore
858
- * @param opts
859
- */
860
-
861
- createView( opts?: DataViewProps<T> ) : DataView<T> {
862
- let eopts = { ...opts, store: this };
863
- return new DataView( eopts );
864
- }
865
-
866
- /**
867
- *
868
- */
869
-
870
- createIndex( filter: FilterInfo ) : DataIndex {
871
-
872
- if( filter && filter.op==='empty-result' ) {
873
- return new Uint32Array(0);
874
- }
875
-
876
- let index = new Uint32Array( this.m_records.length );
877
- let iidx = 0;
878
-
879
- if( !filter ) {
880
- // reset filter
881
- this.forEach( (rec, idx) => {
882
- index[iidx++] = idx;
883
- } );
884
- }
885
- else {
886
- if( typeof(filter.op)==='function' ) {
887
-
888
- let fn = <FilterFunc>filter.op;
889
-
890
- // scan all records and append only interesting ones
891
- this.forEach( (rec, idx) => {
892
-
893
- // skip deleted
894
- if( !rec ) {
895
- return;
896
- }
897
-
898
- if( fn(rec) ) {
899
- index[iidx++] = idx;
900
- }
901
- } );
902
- }
903
- else {
904
- let filterFld = this.m_model.getFieldIndex( filter.field ); // field index to filter on
905
- if( filterFld<0 ) {
906
- // unknown filter field, nothing inside
907
- console.assert( false, 'unknown field name in filter' )
908
- return new Uint32Array(0);
909
- }
910
-
911
- let filterValue = filter.value;
912
- if( isString(filterValue) && !filter.caseSensitive ) {
913
- filterValue = filterValue.toUpperCase( );
914
- }
915
-
916
- function _lt( recval: string ) : boolean {
917
- return recval < filterValue;
918
- }
919
-
920
- function _le( recval: string ) : boolean {
921
- return recval <= filterValue;
922
- }
923
-
924
- function _eq( recval: string ) : boolean {
925
- return recval == filterValue;
926
- }
927
-
928
- function _neq( recval: string ) : boolean {
929
- return recval != filterValue;
930
- }
931
-
932
- function _ge( recval: string ) : boolean {
933
- return recval >= filterValue;
934
- }
935
-
936
- function _gt( recval: string ) : boolean {
937
- return recval > filterValue;
938
- }
939
-
940
- function _re( recval: string ) : boolean {
941
- filterRe.lastIndex = -1;
942
- return filterRe.test( recval );
943
- }
944
-
945
- let filterFn; // filter fn
946
- let filterRe; // if fielter is regexp
947
- if( filterValue instanceof RegExp ) {
948
- filterRe = filterValue;
949
- filterFn = _re;
950
- }
951
- else {
952
- switch( filter.op ) {
953
- case '<': { filterFn = _lt; break; }
954
- case '<=': { filterFn = _le; break; }
955
- case '=': { filterFn = _eq; break; }
956
- case '>=': { filterFn = _ge; break; }
957
- case '>': { filterFn = _gt; break; }
958
- case '<>': { filterFn = _neq; break; }
959
- }
960
- }
961
-
962
- // scan all records and append only interesting ones
963
- this.forEach( (rec, idx) => {
964
-
965
- // skip deleted
966
- if( !rec ) {
967
- return;
968
- }
969
-
970
- let field = rec.getRaw( filterFld );
971
- if( field===null || field===undefined ) {
972
- field = '';
973
- }
974
- else {
975
- field = ''+field;
976
- if( !filter.caseSensitive ) {
977
- field = field.toUpperCase( );
978
- }
979
- }
980
-
981
- let keep = filterFn( field );
982
- if( keep ) {
983
- index[iidx++] = idx;
984
- };
985
- });
986
- }
987
- }
988
-
989
- return index.slice( 0, iidx );
990
- }
991
-
992
- sortIndex( index: DataIndex, sort: SortProp[] ) {
993
-
994
- interface sort_info {
995
- fidx: number,
996
- asc: boolean
997
- }
998
-
999
- let bads = 0; // unknown fields
1000
- let fidxs: sort_info[] = []; // fields indexes
1001
-
1002
- // if no fields are given, reset sort by id
1003
- if ( sort===null ) {
1004
- fidxs.push( { fidx: 0, asc: true } );
1005
- }
1006
- else {
1007
- fidxs = sort.map( (si) => {
1008
-
1009
- let fi = this.m_model.getFieldIndex( si.field );
1010
- if (fi == -1) {
1011
- console.assert( false, 'unknown field name in sort' )
1012
- bads++;
1013
- }
1014
-
1015
- return { fidx: fi, asc: si.ascending };
1016
- });
1017
- }
1018
-
1019
- // unknown field or nothing to sort on ??
1020
- if( bads || fidxs.length==0 ) {
1021
- return index;
1022
- }
1023
-
1024
- // sort only by one field : optimize it
1025
- if( fidxs.length==1 ) {
1026
-
1027
- let field = fidxs[0].fidx;
1028
- index.sort( ( ia, ib ) => {
1029
-
1030
- let va = this.getByIndex(ia).getRaw( field ) ?? '';
1031
- let vb = this.getByIndex(ib).getRaw( field ) ?? '';
1032
- if (va > vb) { return 1; }
1033
- if (va < vb) { return -1; }
1034
- return 0;
1035
- } );
1036
-
1037
- // just reverse if
1038
- if( !fidxs[0].asc ) {
1039
- index.reverse( );
1040
- }
1041
- }
1042
- else {
1043
- index.sort( ( ia, ib ) => {
1044
-
1045
- for( let fi=0; fi<fidxs.length; fi++ ) {
1046
-
1047
- let fidx = fidxs[fi].fidx;
1048
- let mul = fidxs[fi].asc ? 1 : -1;
1049
-
1050
- let va = this.getByIndex(ia).getRaw( fidx ) ?? '';
1051
- let vb = this.getByIndex(ib).getRaw( fidx ) ?? '';
1052
- if (va > vb) { return mul; }
1053
- if (va < vb) { return -mul; }
1054
- }
1055
-
1056
- return 0;
1057
- } );
1058
- }
1059
-
1060
- return index
1061
- }
1062
-
1063
- /**
1064
- *
1065
- */
1066
-
1067
- forEach( cb: ( rec:T, index: number ) => any ) {
1068
-
1069
- if( this.m_rec_index ) {
1070
- this.m_rec_index.some( (ri,index) => {
1071
- if( cb( this.m_records[ri], index ) ) {
1072
- return index;
1073
- }
1074
- });
1075
- }
1076
- else {
1077
- this.m_records.some( ( rec, index ) => {
1078
- if( rec ) {
1079
- if( cb( rec, index ) ) {
1080
- return index;
1081
- }
1082
- }
1083
- } );
1084
- }
1085
- }
1086
-
1087
- export( ) {
1088
- return this.m_records;
1089
- }
1090
-
1091
- changed( ) {
1092
- this.emit( 'data_change', EvDataChange('change') );
1093
- }
1094
- }
1095
-
1096
-
1097
- // :: VIEWS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1098
-
1099
- export interface EvViewChange extends BasicEvent {
1100
- action: string;
1101
- }
1102
-
1103
- export function EvViewChange( action: 'filter' | 'sort' | 'change' ) {
1104
- return BasicEvent<EvViewChange>( { action } );
1105
- }
1106
-
1107
- interface DataViewEventMap extends BaseComponentEventMap {
1108
- view_change: EvViewChange;
1109
- }
1110
-
1111
- interface DataViewProps<T extends Record> extends BaseComponentProps<DataViewEventMap> {
1112
- store?: DataStore<T>;
1113
- filter?: FilterInfo;
1114
- order?: string | SortProp[] | SortProp;
1115
- }
1116
-
1117
- export type FilterFunc = ( rec: Record ) => boolean;
1118
-
1119
- export interface FilterInfo {
1120
- op: '<' | '<=' | '=' | '>=' | '>' | '<>' | 'empty-result' | FilterFunc, // emptydb mean return an empty result always
1121
- field?: string;
1122
- value?: string | RegExp; // if regexp then operator is =
1123
- caseSensitive?: boolean;
1124
- }
1125
-
1126
-
1127
- export interface SortProp {
1128
- field: string; //
1129
- ascending: boolean; //
1130
- }
1131
-
1132
-
1133
-
1134
- /**
1135
- * Dataview allow different views of the DataStore.
1136
- * You can sort the columns & filter data
1137
- * You can have multiple views for a single DataStore
1138
- */
1139
-
1140
- export class DataView<T extends Record = Record> extends BaseComponent<DataViewProps<T>,DataViewEventMap>
1141
- {
1142
- protected m_index: DataIndex;
1143
- protected m_store: DataStore<T>;
1144
-
1145
- protected m_sort: SortProp[];
1146
- protected m_filter: FilterInfo;
1147
-
1148
- constructor( props: DataViewProps<T> ) {
1149
- super( props );
1150
-
1151
- this.m_store = props.store;
1152
- this.m_index = null;
1153
- this.m_filter = null;
1154
- this.m_sort = null;
1155
-
1156
- this.filter( props.filter );
1157
-
1158
- if( props.order ) {
1159
- if( isString(props.order) ) {
1160
- this.sort( [ { field: props.order, ascending: true } ] );
1161
- }
1162
- else if( isArray(props.order) ) {
1163
- this.sort( props.order );
1164
- }
1165
- else {
1166
- this.sort( [props.order] );
1167
- }
1168
- }
1169
- else {
1170
- this.sort( null );
1171
- }
1172
-
1173
- this.m_store.on( 'data_change', ( e ) => this._storeChange(e) );
1174
- }
1175
-
1176
- private _storeChange( ev: EvDataChange ) {
1177
-
1178
- this._filter( this.m_filter, ev.type!='change' );
1179
- this._sort( this.m_sort, ev.type!='change' );
1180
-
1181
- this.emit( 'view_change', EvViewChange( 'change' ) );
1182
- }
1183
-
1184
- /**
1185
- *
1186
- * @param filter
1187
- */
1188
-
1189
- public filter( filter?: FilterInfo ) : number {
1190
-
1191
- this.m_index = null; // null to signal that we have to run on records instead of index
1192
- return this._filter( filter, true );
1193
- }
1194
-
1195
- private _filter( filter: FilterInfo, notify: boolean) : number {
1196
-
1197
- this.m_index = this.m_store.createIndex( filter );
1198
- this.m_filter = filter;
1199
-
1200
- // need to sort again:
1201
- if( this.m_sort ) {
1202
- this.sort( this.m_sort );
1203
- }
1204
-
1205
- if( notify ) {
1206
- this.emit( 'view_change', EvViewChange( 'filter' ) );
1207
- }
1208
-
1209
- return this.m_index.length;
1210
- }
1211
-
1212
- /**
1213
- *
1214
- * @param columns
1215
- * @param ascending
1216
- */
1217
-
1218
- public sort( props: SortProp[] ) {
1219
- this._sort( props, true );
1220
- }
1221
-
1222
- private _sort( props: SortProp[], notify: boolean ) {
1223
- this.m_index = this.m_store.sortIndex( this.m_index, props );
1224
- this.m_sort = props;
1225
-
1226
- if( notify ) {
1227
- this.emit( 'view_change', EvViewChange( 'sort' ) );
1228
- }
1229
- }
1230
-
1231
- /**
1232
- *
1233
- */
1234
-
1235
- get store ( ) {
1236
- return this.m_store;
1237
- }
1238
-
1239
- /**
1240
- *
1241
- */
1242
-
1243
- public get count() {
1244
- return this.m_index.length;
1245
- }
1246
-
1247
- /**
1248
- *
1249
- * @param id
1250
- */
1251
-
1252
- public indexOfId(id): number {
1253
- let ridx = this.m_store.indexOfId( id );
1254
- return this.m_index.findIndex( (rid) => rid === ridx );
1255
- }
1256
-
1257
- /**
1258
- *
1259
- * @param index
1260
- */
1261
-
1262
- public getByIndex(index: number): T {
1263
-
1264
- if (index >= 0 && index < this.m_index.length) {
1265
- let rid = this.m_index[index];
1266
- return this.m_store.getByIndex( rid );
1267
- }
1268
-
1269
- return null;
1270
- }
1271
-
1272
- /**
1273
- *
1274
- * @param id
1275
- */
1276
-
1277
- public getById( id: any): T {
1278
- return this.m_store.getById( id );
1279
- }
1280
-
1281
- changed( ) {
1282
- this.emit( 'view_change', EvViewChange('change') );
1283
- }
1284
-
1285
- /**
1286
- *
1287
- */
1288
-
1289
- forEach( cb: ( rec:T, index: number ) => any ) {
1290
- this.m_index.some( ( index ) => {
1291
- let rec = this.m_store.getByIndex( index );
1292
- if( rec ) {
1293
- if( cb( rec, index ) ) {
1294
- return index;
1295
- }
1296
- }
1297
- } );
1298
- }
1299
- }
1300
-
1301
-
1302
-