x4js 2.0.13 → 2.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/.vscode/launch.json +14 -0
  2. package/README.md +5 -0
  3. package/{lib/src/demo → demo}/main.scss +3 -1
  4. package/{lib/src/demo/main.tsx → demo/main.ts} +37 -36
  5. package/demo/package.json +26 -0
  6. package/demo/scss.d.ts +4 -0
  7. package/demo/svg.d.ts +1 -0
  8. package/demo/tsconfig.json +14 -0
  9. package/lib/README.txt +5 -0
  10. package/lib/cjs/x4.css +1 -1
  11. package/lib/cjs/x4.js +2 -1
  12. package/lib/esm/x4.css +1 -1
  13. package/lib/esm/x4.mjs +2 -1
  14. package/lib/src/components/boxes/boxes.module.scss +17 -0
  15. package/lib/src/components/boxes/boxes.ts +258 -17
  16. package/lib/src/components/breadcrumb/breadcrumb.scss +56 -28
  17. package/lib/src/components/breadcrumb/breadcrumb.ts +93 -84
  18. package/lib/src/components/btngroup/btngroup.module.scss +12 -0
  19. package/lib/src/components/btngroup/btngroup.ts +41 -8
  20. package/lib/src/components/button/button.module.scss +23 -5
  21. package/lib/src/components/button/button.ts +72 -4
  22. package/lib/src/components/canvas/canvas.module.scss +25 -0
  23. package/lib/src/components/canvas/canvas.ts +189 -0
  24. package/lib/src/components/canvas/canvas_ex.ts +276 -0
  25. package/lib/src/components/checkbox/checkbox.ts +18 -4
  26. package/lib/src/components/combobox/combobox.module.scss +24 -15
  27. package/lib/src/components/combobox/combobox.ts +107 -24
  28. package/lib/src/components/components.ts +7 -0
  29. package/lib/src/components/dialog/dialog.module.scss +40 -7
  30. package/lib/src/components/dialog/dialog.ts +166 -31
  31. package/lib/src/components/filedrop/cloud-arrow-up.svg +1 -0
  32. package/lib/src/components/filedrop/filedrop.module.scss +70 -0
  33. package/lib/src/components/filedrop/filedrop.ts +131 -0
  34. package/lib/src/components/form/form.module.scss +4 -0
  35. package/lib/src/components/form/form.ts +137 -6
  36. package/lib/src/components/gridview/arrow-down-light.svg +1 -0
  37. package/lib/src/components/gridview/arrow-up-light.svg +1 -0
  38. package/lib/src/components/gridview/gridview.module.scss +324 -0
  39. package/lib/src/components/gridview/gridview.ts +1175 -0
  40. package/lib/src/components/icon/icon.module.scss +2 -1
  41. package/lib/src/components/icon/icon.ts +4 -3
  42. package/lib/src/components/image/image.module.scss +8 -1
  43. package/lib/src/components/image/image.ts +105 -6
  44. package/lib/src/components/input/input.module.scss +8 -3
  45. package/lib/src/components/input/input.ts +178 -31
  46. package/lib/src/components/keyboard/arrow-up.svg +1 -0
  47. package/lib/src/components/keyboard/delete-left.svg +1 -0
  48. package/lib/src/components/keyboard/eye-slash.svg +1 -0
  49. package/lib/src/components/keyboard/keyboard.module.scss +134 -0
  50. package/lib/src/components/keyboard/keyboard.ts +526 -0
  51. package/lib/src/components/label/label.module.scss +22 -4
  52. package/lib/src/components/label/label.ts +33 -0
  53. package/lib/src/components/link/link.ts +81 -78
  54. package/lib/src/components/listbox/listbox.module.scss +61 -3
  55. package/lib/src/components/listbox/listbox.ts +164 -56
  56. package/lib/src/components/menu/menu.module.scss +10 -1
  57. package/lib/src/components/menu/menu.ts +6 -3
  58. package/lib/src/components/messages/messages.module.scss +44 -0
  59. package/lib/src/components/messages/messages.ts +164 -18
  60. package/lib/src/components/messages/pen-field.svg +1 -0
  61. package/lib/src/components/normalize.scss +5 -0
  62. package/lib/src/components/notification/notification.module.scss +4 -2
  63. package/lib/src/components/notification/notification.ts +2 -4
  64. package/lib/src/components/panel/panel.module.scss +12 -0
  65. package/lib/src/components/popup/popup.module.scss +10 -2
  66. package/lib/src/components/popup/popup.ts +141 -95
  67. package/lib/src/components/propgrid/folder-closed.svg +1 -0
  68. package/lib/src/components/propgrid/folder-open.svg +1 -0
  69. package/lib/src/components/propgrid/progrid.module.scss +112 -0
  70. package/lib/src/components/propgrid/propgrid.ts +288 -0
  71. package/lib/src/components/propgrid/updown.svg +4 -0
  72. package/lib/src/components/radio/radio.module.scss +147 -0
  73. package/lib/src/components/radio/radio.svg +4 -0
  74. package/lib/src/components/radio/radio.ts +142 -0
  75. package/lib/src/components/select/select.module.scss +9 -0
  76. package/lib/src/components/select/select.ts +134 -0
  77. package/lib/src/components/shared.scss +47 -0
  78. package/lib/src/components/sizers/sizer.ts +10 -2
  79. package/lib/src/components/slider/slider.module.scss +77 -30
  80. package/lib/src/components/slider/slider.ts +72 -22
  81. package/lib/src/components/tabs/tabs.module.scss +1 -2
  82. package/lib/src/components/tabs/tabs.ts +49 -12
  83. package/lib/src/components/textarea/textarea.module.scss +6 -2
  84. package/lib/src/components/textarea/textarea.ts +73 -8
  85. package/lib/src/components/textedit/textedit.module.scss +3 -1
  86. package/lib/src/components/textedit/textedit.ts +47 -15
  87. package/lib/src/components/themes.scss +7 -0
  88. package/lib/src/components/tickline/tickline.module.scss +26 -0
  89. package/lib/src/components/tickline/tickline.ts +82 -0
  90. package/lib/src/components/tooltips/comments-question.svg +1 -0
  91. package/lib/src/components/tooltips/tooltips.scss +30 -9
  92. package/lib/src/components/tooltips/tooltips.ts +10 -5
  93. package/lib/src/components/treeview/treeview.module.scss +129 -60
  94. package/lib/src/components/treeview/treeview.ts +47 -12
  95. package/lib/src/components/viewport/viewport.module.scss +7 -0
  96. package/lib/src/core/component.ts +113 -40
  97. package/lib/src/core/core_application.ts +223 -2
  98. package/lib/src/core/core_colors.ts +2 -2
  99. package/lib/src/{components/grid/datastore.ts → core/core_data.ts} +264 -252
  100. package/lib/src/core/core_dragdrop.ts +3 -3
  101. package/lib/src/core/core_element.ts +18 -1
  102. package/lib/src/core/core_events.ts +28 -0
  103. package/lib/src/core/core_i18n.ts +19 -3
  104. package/lib/src/core/core_react.ts +79 -0
  105. package/lib/src/core/core_router.ts +25 -9
  106. package/lib/src/core/core_state.ts +62 -0
  107. package/lib/src/core/core_styles.ts +5 -5
  108. package/lib/src/core/core_svg.ts +174 -12
  109. package/lib/src/core/core_tools.ts +305 -87
  110. package/lib/src/x4tsx.d.ts +25 -0
  111. package/lib/styles/x4.css +1 -1
  112. package/lib/types/x4js.d.ts +828 -119
  113. package/package.json +4 -4
  114. package/scripts/build.mjs +378 -0
  115. package/scripts/prepack.mjs +346 -0
  116. package/src/components/base.scss +25 -0
  117. package/src/components/boxes/boxes.module.scss +54 -0
  118. package/src/components/boxes/boxes.ts +370 -0
  119. package/src/components/breadcrumb/breadcrumb.scss +56 -0
  120. package/src/components/breadcrumb/breadcrumb.ts +93 -0
  121. package/src/components/breadcrumb/chevron-right.svg +1 -0
  122. package/src/components/btngroup/btngroup.module.scss +41 -0
  123. package/src/components/btngroup/btngroup.ts +153 -0
  124. package/src/components/button/button.module.scss +173 -0
  125. package/src/components/button/button.ts +185 -0
  126. package/src/components/calendar/calendar-check-sharp-light.svg +1 -0
  127. package/src/components/calendar/calendar.module.scss +163 -0
  128. package/src/components/calendar/calendar.ts +327 -0
  129. package/src/components/calendar/chevron-left-sharp-light.svg +1 -0
  130. package/src/components/calendar/chevron-right-sharp-light.svg +1 -0
  131. package/src/components/canvas/canvas.module.scss +25 -0
  132. package/src/components/canvas/canvas.ts +189 -0
  133. package/src/components/canvas/canvas_ex.ts +276 -0
  134. package/src/components/checkbox/check.svg +4 -0
  135. package/src/components/checkbox/checkbox.module.scss +142 -0
  136. package/src/components/checkbox/checkbox.ts +140 -0
  137. package/src/components/colorinput/colorinput.module.scss +65 -0
  138. package/src/components/colorinput/colorinput.ts +91 -0
  139. package/src/components/colorinput/crosshairs-simple-sharp-light.svg +1 -0
  140. package/src/components/colorpicker/colorpicker.module.scss +133 -0
  141. package/src/components/colorpicker/colorpicker.ts +482 -0
  142. package/src/components/combobox/combobox.module.scss +133 -0
  143. package/src/components/combobox/combobox.ts +275 -0
  144. package/src/components/combobox/updown.svg +4 -0
  145. package/src/components/components.ts +41 -0
  146. package/src/components/dialog/dialog.module.scss +104 -0
  147. package/src/components/dialog/dialog.ts +229 -0
  148. package/src/components/dialog/xmark-sharp-light.svg +1 -0
  149. package/src/components/filedrop/cloud-arrow-up.svg +1 -0
  150. package/src/components/filedrop/filedrop.module.scss +70 -0
  151. package/src/components/filedrop/filedrop.ts +131 -0
  152. package/src/components/form/form.module.scss +38 -0
  153. package/src/components/form/form.ts +172 -0
  154. package/src/components/gridview/arrow-down-light.svg +1 -0
  155. package/src/components/gridview/arrow-up-light.svg +1 -0
  156. package/src/components/gridview/gridview.module.scss +324 -0
  157. package/src/components/gridview/gridview.ts +1175 -0
  158. package/src/components/header/header.module.scss +40 -0
  159. package/src/components/header/header.ts +130 -0
  160. package/src/components/icon/icon.module.scss +31 -0
  161. package/src/components/icon/icon.ts +137 -0
  162. package/src/components/image/image.module.scss +28 -0
  163. package/src/components/image/image.ts +168 -0
  164. package/src/components/input/input.module.scss +74 -0
  165. package/src/components/input/input.ts +422 -0
  166. package/src/components/keyboard/arrow-up.svg +1 -0
  167. package/src/components/keyboard/delete-left.svg +1 -0
  168. package/src/components/keyboard/eye-slash.svg +1 -0
  169. package/src/components/keyboard/keyboard.module.scss +134 -0
  170. package/src/components/keyboard/keyboard.ts +526 -0
  171. package/src/components/label/label.module.scss +76 -0
  172. package/src/components/label/label.ts +97 -0
  173. package/src/components/link/link.ts +81 -0
  174. package/src/components/listbox/listbox.module.scss +161 -0
  175. package/src/components/listbox/listbox.ts +539 -0
  176. package/src/components/menu/caret-right-solid.svg +1 -0
  177. package/src/components/menu/menu.module.scss +117 -0
  178. package/src/components/menu/menu.ts +174 -0
  179. package/src/components/messages/circle-exclamation.svg +1 -0
  180. package/src/components/messages/messages.module.scss +92 -0
  181. package/src/components/messages/messages.ts +215 -0
  182. package/src/components/messages/pen-field.svg +1 -0
  183. package/src/components/normalize.scss +391 -0
  184. package/src/components/notification/circle-check-solid.svg +1 -0
  185. package/src/components/notification/circle-exclamation-solid.svg +1 -0
  186. package/src/components/notification/circle-notch-light.svg +1 -0
  187. package/src/components/notification/notification.module.scss +84 -0
  188. package/src/components/notification/notification.ts +107 -0
  189. package/src/components/notification/xmark-sharp-light.svg +1 -0
  190. package/src/components/panel/panel.module.scss +60 -0
  191. package/src/components/panel/panel.ts +58 -0
  192. package/src/components/popup/popup.module.scss +51 -0
  193. package/src/components/popup/popup.ts +442 -0
  194. package/src/components/progress/progress.module.scss +57 -0
  195. package/src/components/progress/progress.ts +44 -0
  196. package/src/components/propgrid/folder-closed.svg +1 -0
  197. package/src/components/propgrid/folder-open.svg +1 -0
  198. package/src/components/propgrid/progrid.module.scss +112 -0
  199. package/src/components/propgrid/propgrid.ts +288 -0
  200. package/src/components/propgrid/updown.svg +4 -0
  201. package/src/components/radio/radio.module.scss +147 -0
  202. package/src/components/radio/radio.svg +4 -0
  203. package/src/components/radio/radio.ts +142 -0
  204. package/src/components/rating/rating.module.scss +23 -0
  205. package/src/components/rating/rating.ts +131 -0
  206. package/src/components/rating/star-sharp-light.svg +1 -0
  207. package/src/components/rating/star-sharp-solid.svg +1 -0
  208. package/src/components/select/select.module.scss +9 -0
  209. package/src/components/select/select.ts +134 -0
  210. package/src/components/shared.scss +137 -0
  211. package/src/components/sizers/sizer.module.scss +90 -0
  212. package/src/components/sizers/sizer.ts +132 -0
  213. package/src/components/slider/slider.module.scss +118 -0
  214. package/src/components/slider/slider.ts +198 -0
  215. package/src/components/switch/switch.module.scss +127 -0
  216. package/src/components/switch/switch.ts +62 -0
  217. package/src/components/tabs/tabs.module.scss +45 -0
  218. package/src/components/tabs/tabs.ts +205 -0
  219. package/src/components/textarea/textarea.module.scss +63 -0
  220. package/src/components/textarea/textarea.ts +125 -0
  221. package/src/components/textedit/textedit.module.scss +116 -0
  222. package/src/components/textedit/textedit.ts +115 -0
  223. package/src/components/themes.scss +88 -0
  224. package/src/components/tickline/tickline.module.scss +26 -0
  225. package/src/components/tickline/tickline.ts +82 -0
  226. package/src/components/tooltips/circle-info-sharp-light.svg +1 -0
  227. package/src/components/tooltips/comments-question.svg +1 -0
  228. package/src/components/tooltips/tooltips.scss +72 -0
  229. package/src/components/tooltips/tooltips.ts +109 -0
  230. package/src/components/treeview/chevron-down-light.svg +1 -0
  231. package/src/components/treeview/treeview.module.scss +185 -0
  232. package/src/components/treeview/treeview.ts +445 -0
  233. package/src/components/viewport/viewport.module.scss +32 -0
  234. package/src/components/viewport/viewport.ts +41 -0
  235. package/src/core/component.ts +1075 -0
  236. package/src/core/core_application.ts +265 -0
  237. package/src/core/core_colors.ts +250 -0
  238. package/src/core/core_data.ts +1310 -0
  239. package/src/core/core_dom.ts +471 -0
  240. package/src/core/core_dragdrop.ts +201 -0
  241. package/src/core/core_element.ts +115 -0
  242. package/src/core/core_events.ts +177 -0
  243. package/src/core/core_i18n.ts +393 -0
  244. package/src/core/core_react.ts +79 -0
  245. package/src/core/core_router.ts +237 -0
  246. package/src/core/core_state.ts +62 -0
  247. package/src/core/core_styles.ts +214 -0
  248. package/src/core/core_svg.ts +712 -0
  249. package/src/core/core_tools.ts +906 -0
  250. package/src/types/scss.d.ts +4 -0
  251. package/src/types/svg.d.ts +1 -0
  252. package/src/types/x4react.d.ts +9 -0
  253. package/src/x4.scss +19 -0
  254. package/src/x4tsx.d.ts +25 -0
  255. package/tsconfig.json +14 -0
  256. package/lib/src/components/grid/gridview.ts +0 -1108
  257. package/lib/src/components/grid/memdb.ts +0 -325
  258. /package/{lib/src/demo → demo}/assets/house-light.svg +0 -0
  259. /package/{lib/src/demo → demo}/assets/radio.svg +0 -0
  260. /package/{lib/src/demo → demo}/index.html +0 -0
@@ -0,0 +1,1175 @@
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|
7
+ *
8
+ * @file gridview.ts
9
+ * @author Etienne Cochard
10
+ *
11
+ * @copyright (c) 2024 R-libre ingenierie
12
+ *
13
+ * Use of this source code is governed by an MIT-style license
14
+ * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
+ **/
16
+
17
+
18
+ import { Component, ComponentContent, ComponentEvents, ComponentProps, EvClick, EvContextMenu, EvDblClick, EvSelectionChange, componentFromDOM } from '../../core/component';
19
+ import { class_ns, isNumber, isString, setWaitCursor } from '../../core/core_tools';
20
+ import { DataModel, DataStore, DataView, DataRecord, DataFieldValue, EvViewChange } from '../../core/core_data';
21
+ import { EventCallback } from '../../core/core_events';
22
+ import { kbNav } from '../../core/core_tools';
23
+
24
+ import { Icon } from '../icon/icon';
25
+ import { Image } from '../image/image'
26
+ import { Box } from '../boxes/boxes';
27
+ import { CSizer } from '../sizers/sizer'
28
+ import { Viewport } from '../viewport/viewport';
29
+ import { SimpleText } from '../label/label';
30
+
31
+ import check_icon from "../checkbox/check.svg";
32
+ import "./gridview.module.scss"
33
+
34
+ export type CellRenderer = (rec: DataRecord) => Component;
35
+ export type CellClassifier = (data: any, rec: DataRecord, col: string ) => string; // return the cell computed class
36
+
37
+ type ColType = "number" | "money" | "checkbox" | "date" | "string" | "image" | "percent" | "icon";
38
+
39
+ const SCROLL_LIMIT = 200;
40
+
41
+
42
+ /**
43
+ *
44
+ */
45
+
46
+ interface GridColumn {
47
+ id: any;
48
+ title: string;
49
+ width: number;
50
+ fixed?: boolean;
51
+ flex?: number;
52
+ align?: 'left' | 'center' | 'right';
53
+ header_align?: 'left' | 'center' | 'right';
54
+ renderer?: CellRenderer; // for "renderer" type
55
+ formatter?: (input: any) => string; // for "custom" type
56
+ type?: ColType;
57
+ cls?: string;
58
+ sortable?: boolean;
59
+ footer_val?: string;
60
+ classifier?: CellClassifier;
61
+ }
62
+
63
+ interface GridColumnEx extends GridColumn {
64
+ sens?: "up" | "dn";
65
+ }
66
+
67
+ export interface GridviewEvents extends ComponentEvents {
68
+ click?: EvClick;
69
+ dblClick?: EvDblClick;
70
+ contextMenu?: EvContextMenu;
71
+ selectionChange?: EvSelectionChange;
72
+ }
73
+
74
+ export interface GridviewProps extends ComponentProps {
75
+ footer?: boolean;
76
+ store: DataStore;
77
+ columns: GridColumn[];
78
+
79
+ click?: EventCallback<EvClick>;
80
+ dblClick?: EventCallback<EvDblClick>;
81
+ contextMenu?: EventCallback<EvContextMenu>;
82
+ selectionChange?: EventCallback<EvSelectionChange>;
83
+ }
84
+
85
+ /**
86
+ * we can handle
87
+ * 4_095 cols and (1_048_575-1)/2 rows (this is a chrome limitation max pixels of scrollbars )
88
+ */
89
+
90
+ /**
91
+ *
92
+ */
93
+
94
+ @class_ns("x4")
95
+ export class Gridview<P extends GridviewProps = GridviewProps, E extends GridviewEvents = GridviewEvents> extends Component<P,E> {
96
+
97
+ private _dataview: DataView;
98
+ private _datamodel: DataModel;
99
+
100
+ private _columns: GridColumnEx[];
101
+
102
+ private _lock: number;
103
+ private _dirty: number;
104
+
105
+ private _row_height: number;
106
+
107
+ private _left: number;
108
+ private _top: number;
109
+
110
+ private _body: Component;
111
+ private _viewport: Component;
112
+
113
+ private _fheader: Box; // fixed col header
114
+ private _hheader: Box; // col header
115
+ private _vheader: Box; // vertical row header
116
+ private _ffooter: Box; // fixed footer
117
+ private _footer: Box; // footer
118
+
119
+ private _vis_rows: Map<number, { h: Component, r: Component }>;
120
+ private _start: number;
121
+ private _end: number;
122
+
123
+ private _selection: Set<number>;
124
+ private _num_fmt = new Intl.NumberFormat('fr-FR');
125
+ private _mny_fmt = new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' });
126
+ private _dte_fmt = new Intl.DateTimeFormat('fr-FR', {});
127
+
128
+ private _has_fixed: boolean;
129
+ private _has_footer: boolean;
130
+
131
+ constructor(props: P) {
132
+ super(props);
133
+
134
+ this._lock = 0;
135
+ this._dirty = 0;
136
+
137
+ this._row_height = 32;
138
+
139
+ this._left = 0;
140
+ this._top = 0;
141
+
142
+ this._vis_rows = new Map();
143
+ this._selection = new Set();
144
+ this._has_fixed = false;
145
+ this._has_footer = props.footer;
146
+
147
+ this._columns = props.columns.map(x => x);
148
+
149
+ this.mapPropEvents( props, "click", "dblClick", "contextMenu", "selectionChange" );
150
+
151
+ this.lock(true);
152
+ this.setAttribute("tabindex", 0);
153
+
154
+ this.addDOMEvent("created", () => {
155
+ this._init();
156
+ this._dirty = 1;
157
+ this.lock(false);
158
+ });
159
+
160
+ this.addDOMEvent("resized", () => {
161
+ this._updateFlexs( );
162
+ this._computeFullSize( );
163
+ this._update( true );
164
+ });
165
+
166
+ this.addDOMEvent( "keydown", (e) => {
167
+ this._on_key( e );
168
+ })
169
+
170
+ if (props.store) {
171
+ this.setStore(props.store);
172
+ }
173
+
174
+ }
175
+
176
+ /**
177
+ *
178
+ */
179
+
180
+ private _on_key( ev: KeyboardEvent ) {
181
+ if( this.isDisabled() ) {
182
+ return;
183
+ }
184
+
185
+ switch( ev.key ) {
186
+ case "ArrowDown": {
187
+ this.navigate( kbNav.next );
188
+ break;
189
+ }
190
+
191
+ case "ArrowUp": {
192
+ this.navigate( kbNav.prev );
193
+ break;
194
+ }
195
+
196
+ case "Home": {
197
+ this.navigate( kbNav.first );
198
+ break;
199
+ }
200
+
201
+ case "End": {
202
+ this.navigate( kbNav.last );
203
+ break;
204
+ }
205
+
206
+ case "PageDown": {
207
+ this.navigate( kbNav.pgdn );
208
+ break;
209
+ }
210
+
211
+ case "PageUp": {
212
+ this.navigate( kbNav.pgup );
213
+ break;
214
+ }
215
+
216
+ default:
217
+ return;
218
+ }
219
+
220
+ ev.preventDefault( );
221
+ ev.stopPropagation( );
222
+ }
223
+
224
+ /**
225
+ *
226
+ */
227
+
228
+ navigate( sens: kbNav ) {
229
+ if( !this._selection.size ) {
230
+ if( sens==kbNav.next || sens==kbNav.pgdn ) {
231
+ sens = kbNav.first;
232
+ }
233
+ else {
234
+ sens = kbNav.last;
235
+ }
236
+ }
237
+
238
+ if( sens==kbNav.first || sens==kbNav.last ) {
239
+ let nel = sens==kbNav.first ? 0 : this._dataview.getCount()-1;
240
+ this._clearSelection();
241
+ this._addSelection( nel );
242
+ this._scrollToIndex( nel );
243
+ return true;
244
+ }
245
+ else if( sens==kbNav.prev || sens==kbNav.next ) {
246
+ const fsel = this._selection.values().next().value;
247
+ let nel = sens==kbNav.next ? fsel+1 : fsel-1;
248
+ if( nel>=0 && nel<this._dataview.getCount() ) {
249
+ this._clearSelection();
250
+ this._addSelection( nel );
251
+ this._scrollToIndex( nel );
252
+ return true;
253
+ }
254
+ }
255
+ else if( sens==kbNav.pgdn || sens==kbNav.pgup ) {
256
+ const pgh = this._vis_rows.size;
257
+
258
+ const fsel = this._selection.values().next().value;
259
+
260
+ let sby = sens==kbNav.pgdn ? pgh : -pgh;
261
+ let nel = fsel+sby;
262
+
263
+ if( nel<0 ) {
264
+ nel = 0;
265
+ }
266
+ else if( nel>=this._dataview.getCount() ) {
267
+ nel = this._dataview.getCount()-1;
268
+ }
269
+
270
+ if( nel!=fsel ) {
271
+ this._clearSelection();
272
+ this._addSelection( nel );
273
+
274
+ if (this._dataview.getCount() < SCROLL_LIMIT) {
275
+ sby *= this._row_height;
276
+ }
277
+
278
+ this._viewport.dom.scrollBy( 0, sby );
279
+
280
+ return true;
281
+ }
282
+ }
283
+
284
+ return false;
285
+ }
286
+
287
+ /**
288
+ *
289
+ */
290
+
291
+ private _scrollToIndex( index: number, block = 'nearest' ) {
292
+
293
+ // is it already visible ?
294
+ let rows = this.queryAll(`.row[data-row="${index}"]`);
295
+ if (rows.length) {
296
+ rows.forEach( row => {
297
+ row.scrollIntoView({ block: block as any } );
298
+ } );
299
+ }
300
+ // nope, refill
301
+ else {
302
+ let top = index;
303
+ if (this._dataview.getCount() < SCROLL_LIMIT) {
304
+ top *= this._row_height;
305
+ }
306
+
307
+ this._viewport.dom.scrollTo( 0, top );
308
+ }
309
+ }
310
+
311
+ /**
312
+ *
313
+ */
314
+
315
+ setStore(store: DataStore) {
316
+
317
+ const on_change = (ev: EvViewChange) => {
318
+ if( !this._viewport ) {
319
+ // not created
320
+ return;
321
+ }
322
+
323
+ if (ev.change_type == 'change') {
324
+ this._selection.clear();
325
+ }
326
+
327
+ this._updateFlexs( );
328
+ this._computeFullSize();
329
+ this._update(true);
330
+ }
331
+
332
+ // unlink previous observer
333
+ if (this._dataview) {
334
+ this._dataview.off('view_change', on_change);
335
+ }
336
+
337
+ if (store) {
338
+ this._dataview = new DataView({ store: store });
339
+ this._datamodel = store.getModel();
340
+ this._dataview.on('view_change', on_change);
341
+ }
342
+ else {
343
+ this._dataview = null;
344
+ this._datamodel = null;
345
+ }
346
+ }
347
+
348
+ getView( ): DataView {
349
+ return this._dataview;
350
+ }
351
+
352
+ /**
353
+ *
354
+ */
355
+
356
+ lock(lock: boolean) {
357
+ if (lock) {
358
+ this._lock++;
359
+ }
360
+ else {
361
+ if (--this._lock == 0 && this._dirty) {
362
+ this._update( true );
363
+ }
364
+ }
365
+ }
366
+
367
+ private _getColCount() {
368
+ return this._columns.length;
369
+ }
370
+
371
+ private _getCol(index: number) {
372
+ return this._columns[index];
373
+ }
374
+
375
+ /**
376
+ *
377
+ */
378
+
379
+ private _buildColHeader(fixed: boolean) {
380
+ // row header
381
+ const els: Component[] = [];
382
+
383
+ const count = this._getColCount();
384
+ for (let col = 0; col < count; col++) {
385
+ const cdata = this._getCol(col);
386
+ if ((!!cdata.fixed) != fixed) {
387
+ continue;
388
+ }
389
+
390
+ const sizer = new CSizer("right");
391
+
392
+ sizer.on("stop", ( ) => {
393
+ this._updateFlexs( );
394
+ })
395
+
396
+ sizer.on("resize", (ev) => {
397
+ cdata.width = ev.size;
398
+ cdata.flex = 0;
399
+
400
+ const cols = this.queryAll(`[data-col="${col}"]`)
401
+ cols.forEach(c => {
402
+ c.setStyleValue("width", ev.size + "px");
403
+ });
404
+
405
+ const rh = header.getBoundingRect();
406
+
407
+ if (!fixed) {
408
+ this._body.setStyleValue("width", rh.width + "px");
409
+ }
410
+ else {
411
+ this.setStyleVariable("--fixed-width", rh.width + "px");
412
+ }
413
+ })
414
+
415
+ const cell = new Component({
416
+ cls: `cell`,
417
+ attrs: { "data-col": col },
418
+ style: { width: cdata.width ? cdata.width + "px" : undefined },
419
+ content: [
420
+ new SimpleText({ text: cdata.title, align: cdata.header_align ?? "left" }),
421
+ new Component({ cls: "sorter" }),
422
+ sizer
423
+ ]
424
+ });
425
+
426
+ cell.addDOMEvent("touchend", () => {
427
+ const last = cell.getInternalData("touchend");
428
+ const now = Date.now();
429
+ const delta = last ? now - last : 0;
430
+ if (delta > 30 && delta < 300) {
431
+ this._sortCol(col);
432
+ }
433
+ else {
434
+ cell.setInternalData("touchend", now);
435
+ }
436
+ })
437
+
438
+ cell.addDOMEvent("dblclick", () => {
439
+ this._sortCol(col);
440
+ });
441
+
442
+ els.push(cell);
443
+ }
444
+
445
+ if (fixed && els.length == 0) {
446
+ return null;
447
+ }
448
+
449
+ const header = new Box({ cls: "col-header", content: els });
450
+ header.setClass("fixed", fixed);
451
+
452
+ return header;
453
+ }
454
+
455
+ /**
456
+ *
457
+ */
458
+
459
+ private _buildColFooter(fixed: boolean) {
460
+ // row header
461
+ const els: Component[] = [];
462
+
463
+ const count = this._getColCount();
464
+ for (let col = 0; col < count; col++) {
465
+ const cdata = this._getCol(col);
466
+ if ((!!cdata.fixed) != fixed) {
467
+ continue;
468
+ }
469
+
470
+ const cell = new Component({
471
+ cls: `cell`,
472
+ attrs: { "data-col": col },
473
+ style: { width: cdata.width ? cdata.width + "px" : undefined },
474
+ content: [
475
+ new SimpleText({ text: cdata.footer_val }),
476
+ ]
477
+ });
478
+
479
+ cell.addDOMEvent("dblclick", () => {
480
+ this._sortCol(col);
481
+ });
482
+
483
+ els.push(cell);
484
+ }
485
+
486
+ if (fixed && els.length == 0) {
487
+ return null;
488
+ }
489
+
490
+ const header = new Box({ cls: "col-footer", content: els });
491
+ header.setClass("fixed", fixed);
492
+
493
+ return header;
494
+ }
495
+
496
+ /**
497
+ *
498
+ */
499
+
500
+ private _sortCol(col: number, ascending?: boolean ) {
501
+
502
+ setWaitCursor(true);
503
+
504
+ // to allow cursor
505
+ this.setTimeout("sort", 50, () => {
506
+ let asc = true;
507
+
508
+ // already sorted ?
509
+ const scol = this.query(`.col-header [data-col="${col}"`);
510
+
511
+ if( ascending===undefined ) {
512
+ if (scol.hasClass("sorted")) {
513
+ if (scol.hasClass("desc")) {
514
+ asc = true;
515
+ }
516
+ else {
517
+ asc = false;
518
+ }
519
+ }
520
+ else {
521
+ const sorted = this.queryAll(".sorted");
522
+ sorted.forEach(x => x.removeClass("sorted asc desc"));
523
+ }
524
+ }
525
+ else {
526
+ asc = ascending;
527
+ }
528
+
529
+ scol.setClass("sorted");
530
+ scol.setClass("desc", !asc);
531
+
532
+ const cdata = this._getCol(col);
533
+
534
+ let num = false;
535
+ switch (cdata.type) {
536
+ case "checkbox":
537
+ case "money":
538
+ case "number":
539
+ case "percent": {
540
+ num = true;
541
+ }
542
+ }
543
+
544
+ this._dataview.sort([{
545
+ field: cdata.id,
546
+ ascending: asc,
547
+ numeric: num
548
+ }]);
549
+
550
+ this._update(true);
551
+
552
+ setWaitCursor(false);
553
+ });
554
+ }
555
+
556
+ /**
557
+ *
558
+ */
559
+
560
+ sortCol( colIdx: any, ascending: boolean ) {
561
+
562
+ const idx = this._columns.findIndex( x => x.id === colIdx );
563
+ if( idx>=0 ) {
564
+ this._sortCol( idx, ascending );
565
+ }
566
+ }
567
+
568
+ /**
569
+ *
570
+ */
571
+
572
+ private _renderCell(rec: DataRecord, column: GridColumnEx, extra_cls: string[] ): ComponentContent {
573
+
574
+ const col = column.id;
575
+ const type = column.type;
576
+
577
+ let data = this._datamodel.getRaw(col, rec);
578
+ if (data === undefined || data === null) {
579
+ return null;
580
+ }
581
+
582
+ let cls = "";
583
+ if( column.classifier ) {
584
+ extra_cls.push( column.classifier( data, rec, col ) );
585
+ }
586
+
587
+ if (data instanceof Function) {
588
+ return data(rec, col);
589
+ }
590
+
591
+ if( column.formatter ) {
592
+ return column.formatter( data );
593
+ }
594
+
595
+ switch (type) {
596
+ case "checkbox": {
597
+ if (data) {
598
+ return new Icon({ cls: "cell-check" + cls, iconId: check_icon });
599
+ }
600
+
601
+ return undefined;
602
+ }
603
+
604
+ case "image": {
605
+ if (isString(data)) {
606
+ return new Image({ cls, src: data, fit: "scale-down" });
607
+ }
608
+
609
+ return undefined;
610
+ }
611
+
612
+ case "number": {
613
+ if (!isNumber(data)) {
614
+ return "NaN";
615
+ }
616
+
617
+ data = this._num_fmt.format(data as number);
618
+ break;
619
+ }
620
+
621
+ case "money": {
622
+ if (!isNumber(data)) {
623
+ return "NaN";
624
+ }
625
+
626
+ data = this._mny_fmt.format(data as number);
627
+ break;
628
+ }
629
+
630
+ case "percent": {
631
+ return new Box({
632
+ cls: "percent" + cls,
633
+ content: new Component({ cls: "bar", width: data + "%" })
634
+ });
635
+ }
636
+
637
+ case "icon": {
638
+ return new Icon({ cls, iconId: data + "" });
639
+ }
640
+
641
+ case "date": {
642
+ data = this._dte_fmt.format(data as Date);
643
+ break;
644
+ }
645
+
646
+ default: {
647
+ data = data + "";
648
+ break;
649
+ }
650
+ }
651
+
652
+ return new Component({ tag: "span", cls, content: data });
653
+ }
654
+
655
+ /**
656
+ *
657
+ */
658
+
659
+ private _buildRow(rowid: number, rec: DataRecord, top: number) {
660
+
661
+ const els: Component[] = [];
662
+ const count = this._getColCount();
663
+
664
+ for (let col = 0; col < count; col++) {
665
+ const cdata = this._getCol(col);
666
+ if (cdata.fixed) {
667
+ continue;
668
+ }
669
+
670
+ const extra: string[] = []
671
+ const content = this._renderCell(rec, cdata, extra );
672
+
673
+ let align = "start";
674
+ switch (cdata.align) {
675
+ default: align = "start"; break;
676
+ case "center": align = "center"; break;
677
+ case "right": align = "end"; break;
678
+ }
679
+
680
+ const el = new Component({
681
+ cls: "cell",
682
+ style: { width: cdata?.width ? cdata.width + "px" : undefined, justifyContent: align },
683
+ content
684
+ });
685
+
686
+ if( extra.length ) {
687
+ el.addClass( extra.join(' ') );
688
+ }
689
+
690
+ if (cdata.type) {
691
+ el.addClass(cdata.type);
692
+ }
693
+
694
+ el.setData("col", col + "");
695
+ el.setData("row", rowid + "")
696
+
697
+ els.push(el);
698
+ }
699
+
700
+ const rowel = new Box({ cls: "row", style: { top: top.toFixed(2) + "px" }, content: els });
701
+ rowel.setData("row", rowid + "");
702
+
703
+ if (this._selection.has(rowid)) {
704
+ rowel.addClass("selected");
705
+ }
706
+
707
+ return rowel;
708
+ }
709
+
710
+ /**
711
+ *
712
+ */
713
+
714
+ private _buildRowHeader(rowid: number, rec: DataRecord, top: number) {
715
+
716
+ const cols: Component[] = [];
717
+ const count = this._getColCount();
718
+
719
+ for (let col = 0; col < count; col++) {
720
+ const cdata = this._getCol(col);
721
+ if (!cdata?.fixed) {
722
+ continue;
723
+ }
724
+
725
+ const content = this._renderCell(rec, cdata.id, [cdata.type] );
726
+
727
+ let align = "start";
728
+ switch (cdata.align) {
729
+ default: align = "start"; break;
730
+ case "center": align = "center"; break;
731
+ case "right": align = "end"; break;
732
+ }
733
+
734
+ const el = new Component({
735
+ cls: "cell",
736
+ style: { width: cdata?.width ? cdata.width + "px" : undefined, justifyContent: align },
737
+ content
738
+ });
739
+
740
+ if (cdata.type) {
741
+ el.addClass(cdata.type);
742
+ }
743
+
744
+ el.setData("col", col + "");
745
+ el.setData("row", rowid + "")
746
+
747
+ cols.push(el);
748
+ }
749
+
750
+ const rowel = new Box({ cls: "row", style: { top: top + "px" }, content: cols });
751
+ rowel.setData("row", rowid + "");
752
+
753
+ if (this._selection.has(rowid)) {
754
+ rowel.addClass("selected");
755
+ }
756
+
757
+ return rowel;
758
+ }
759
+
760
+ /**
761
+ *
762
+ */
763
+
764
+ private _updateFlexs( ) {
765
+ let maxw = 0;
766
+ let flexc = 0;
767
+
768
+ const ccount = this._getColCount();
769
+
770
+ for (let x = 0; x < ccount; x++) {
771
+ const cdata = this._getCol(x);
772
+
773
+ if( !cdata.fixed && cdata.flex ) {
774
+ flexc += cdata.flex;
775
+ }
776
+ else {
777
+ maxw += cdata.width;
778
+ }
779
+ }
780
+
781
+ if( flexc ) {
782
+ const width = this._viewport.dom.clientWidth;
783
+ const delta = width - maxw;
784
+ const fw = delta / flexc;
785
+
786
+ for (let col = 0; col < ccount; col++) {
787
+ const cdata = this._getCol(col);
788
+ if( !cdata.fixed && cdata.flex ) {
789
+ cdata.width = Math.max( cdata.flex*fw, 32 );
790
+
791
+ const cols = this.queryAll(`[data-col="${col}"]`)
792
+ cols.forEach(c => {
793
+ c.setStyleValue("width", cdata.width + "px");
794
+ });
795
+ }
796
+ }
797
+ }
798
+ }
799
+
800
+ /**
801
+ *
802
+ */
803
+
804
+ private _computeFullSize() {
805
+
806
+ let maxw = 0;
807
+ let maxfw = 0;
808
+
809
+ const ccount = this._getColCount();
810
+
811
+ for (let x = 0; x < ccount; x++) {
812
+ const cdata = this._getCol(x);
813
+ let w = 0;
814
+
815
+ if (cdata.fixed) {
816
+ this._has_fixed = true;
817
+ }
818
+
819
+ if ( cdata.width) {
820
+ w += cdata.width;
821
+ }
822
+
823
+ if (cdata.fixed) {
824
+ maxfw += w;
825
+ }
826
+ else {
827
+ maxw += w;
828
+ }
829
+ }
830
+
831
+ const maxr = this._dataview.getCount();
832
+ let maxh = maxr;
833
+
834
+ if (maxr < SCROLL_LIMIT) {
835
+ maxh *= this._row_height;
836
+ }
837
+ else {
838
+ const height = this._body.dom.parentElement.clientHeight;
839
+ const npage = height / this._row_height;
840
+ maxh = maxr - Math.floor(npage) + npage * this._row_height;
841
+ }
842
+
843
+ this.setStyleVariable("--fixed-width", maxfw + "px");
844
+ this._body.setStyleValue("height", maxh + "px");
845
+ this._body.setStyleValue("width", maxw + "px");
846
+ this._vheader.setStyleValue("height", maxh + "px");
847
+ }
848
+
849
+ /**
850
+ *
851
+ */
852
+
853
+ private _init() {
854
+ this._body = new Component({ cls: "body" });
855
+
856
+ this._viewport = new Viewport({ content: this._body });
857
+
858
+ if (!this._has_footer) {
859
+ this.setStyleVariable("--footer-height", "0");
860
+ }
861
+
862
+ // SCROLL
863
+ this._viewport.addDOMEvent( "scroll", (ev) => {
864
+ // sync horz & vert elements
865
+ this._left = this._viewport.dom.scrollLeft;
866
+ this.setStyleVariable("--left", -this._left + "px");
867
+
868
+ this._top = this._viewport.dom.scrollTop;
869
+ this.setStyleVariable("--top", -this._top + "px");
870
+
871
+ //this.setTimeout( "update", 0, ( ) => this._update( ) );
872
+ this._update()
873
+ });
874
+
875
+ // WHEEL
876
+ this.addDOMEvent("wheel", (ev: WheelEvent) => {
877
+ if (ev.deltaY && this._dataview.getCount() >= SCROLL_LIMIT) {
878
+ this._viewport.dom.scrollBy(0, ev.deltaY < 0 ? -1 : 1);
879
+ ev.stopPropagation();
880
+ ev.preventDefault();
881
+ }
882
+
883
+ if (this._has_fixed && ev.deltaY) {
884
+ // wheel on fixed part
885
+ // fixed part do not have scrollbar, so we need to handle it by hand
886
+ let t = ev.target as Node;
887
+ while (t != this.dom) {
888
+ if (t == this._vheader.dom) {
889
+ this._viewport.dom.scrollBy(0, ev.deltaY < 0 ? -this._row_height : this._row_height);
890
+ ev.stopPropagation();
891
+ ev.preventDefault();
892
+ break;
893
+ }
894
+
895
+ t = t.parentNode;
896
+ }
897
+ }
898
+ })
899
+
900
+ const targetRow = ( e: MouseEvent ) => {
901
+ let el = Component.parentElement(e.target as HTMLElement, Component);
902
+ while (el && !el.hasClass("row")) {
903
+ el = el.parentElement();
904
+ }
905
+
906
+ if (el) {
907
+ return el.getIntData("row");
908
+ }
909
+
910
+ return undefined;
911
+ }
912
+
913
+
914
+ // CLICK
915
+ this.addDOMEvent("click", (e) => {
916
+ const row = targetRow( e );
917
+ if (row!==undefined ) {
918
+ //TODO: multiselection
919
+ if( !this._selection.has(row) ) {
920
+ this._clearSelection();
921
+ this._addSelection(row);
922
+ }
923
+ }
924
+ });
925
+
926
+ // DBLCLICK
927
+ this.addDOMEvent("dblclick", (e) => {
928
+ const row = targetRow( e );
929
+ if (row!==undefined ) {
930
+ //TODO: multiselection
931
+ if( !this._selection.has(row) ) {
932
+ this._clearSelection();
933
+ this._addSelection(row);
934
+ }
935
+
936
+ this._on_dblclk( e, row );
937
+
938
+ const rec = this._dataview.getByIndex( row );
939
+ this.fire( "dblClick", { context: rec } );
940
+ }
941
+ });
942
+
943
+ // CONTEXT
944
+ this.addDOMEvent("contextmenu", (e) => {
945
+ const row = targetRow( e );
946
+ if (row!==undefined ) {
947
+ //TODO: multiselection
948
+ if( !this._selection.has(row) ) {
949
+ this._clearSelection();
950
+ this._addSelection(row);
951
+ }
952
+
953
+ const rec = this._dataview.getByIndex( row );
954
+ this.fire( "contextMenu", { uievent: e, context: rec } );
955
+ }
956
+
957
+ e.preventDefault( );
958
+ e.stopPropagation( );
959
+ });
960
+
961
+ // MOUSE OVER
962
+ this.addDOMEvent("mouseover", (e) => {
963
+
964
+ if (!this._has_fixed) {
965
+ return;
966
+ }
967
+
968
+ let el = Component.parentElement(e.target as HTMLElement, Component);
969
+ while (el && !el.hasClass("row")) {
970
+ el = el.parentElement();
971
+ }
972
+
973
+ if (el) {
974
+ const data = el.getData("row");
975
+
976
+ this.queryAll(".hover").forEach(x => x.removeClass("hover"));
977
+
978
+ if (data) {
979
+ const rows = this.queryAll(`.row[data-row="${data}"]`);
980
+ rows.forEach(x => x.addClass("hover"));
981
+ }
982
+ }
983
+ });
984
+
985
+ // MOUSE LEAVE
986
+ this.addDOMEvent("mouseleave", (e) => {
987
+
988
+ if (!this._has_fixed) {
989
+ return;
990
+ }
991
+
992
+ this.queryAll(".hover").forEach(x => x.removeClass("hover"));
993
+ });
994
+
995
+ this._updateFlexs( );
996
+
997
+ this._fheader = this._buildColHeader(true);
998
+ this._hheader = this._buildColHeader(false);
999
+ this._vheader = new Box({ cls: "row-header" })
1000
+
1001
+ if (this._has_footer) {
1002
+ this._ffooter = this._buildColFooter(true);
1003
+ this._footer = this._buildColFooter(false);
1004
+ }
1005
+
1006
+ this.setContent([this._viewport, this._fheader, this._hheader, this._ffooter, this._footer, this._vheader]);
1007
+
1008
+ // compute misc variables
1009
+ {
1010
+ const rh = this.getStyleVariable("--row-height");
1011
+ this._row_height = parseInt(rh);
1012
+ }
1013
+
1014
+ this._computeFullSize();
1015
+ }
1016
+
1017
+ /**
1018
+ *
1019
+ */
1020
+
1021
+ protected _on_dblclk( e: UIEvent, row: number ) {
1022
+
1023
+ }
1024
+
1025
+ /**
1026
+ *
1027
+ */
1028
+
1029
+ private _update(force = false) {
1030
+
1031
+ if (!this._lock) {
1032
+ const rc = this.getBoundingRect();
1033
+
1034
+ // rows
1035
+ const rowc = this._dataview.getCount();
1036
+ const mul = rowc < SCROLL_LIMIT ? this._row_height : 1;
1037
+
1038
+ const start = Math.floor(this._top / mul);
1039
+ const end = start + Math.ceil(rc.height / this._row_height);
1040
+ const hasFixed = this._has_fixed;
1041
+
1042
+ if (this._start != start || this._end != end || force) {
1043
+
1044
+ const rows: Component[] = [];
1045
+ const headers: Component[] = [];
1046
+
1047
+ if (force) {
1048
+ this._vis_rows.clear();
1049
+ }
1050
+
1051
+ let newvis: typeof this._vis_rows = new Map();
1052
+
1053
+ let y = start * mul;
1054
+
1055
+ for (let row = start; row < end && row < rowc; row++, y += this._row_height) {
1056
+
1057
+ let el = this._vis_rows.get(row);
1058
+ const rec = this._dataview.getByIndex(row);
1059
+
1060
+ if (hasFixed) {
1061
+ if (!el) {
1062
+ el = {
1063
+ h: this._buildRowHeader(row, rec, y),
1064
+ r: this._buildRow(row, rec, y),
1065
+ };
1066
+ }
1067
+ else {
1068
+ el.h.setStyleValue("top", y + "px");
1069
+ el.r.setStyleValue("top", y + "px");
1070
+ }
1071
+
1072
+ headers.push(el.h);
1073
+ }
1074
+ else {
1075
+ if (!el) {
1076
+ el = { h: null, r: this._buildRow(row, rec, y), };
1077
+ }
1078
+ else {
1079
+ el.r.setStyleValue("top", y + "px");
1080
+ }
1081
+ }
1082
+
1083
+ rows.push(el.r);
1084
+ newvis.set(row, el);
1085
+ }
1086
+
1087
+ if (hasFixed) {
1088
+ headers.push(new Component({ cls: "cell-out", style: { top: y + "px" } }));
1089
+ }
1090
+
1091
+ this._vis_rows = newvis;
1092
+ this._start = start;
1093
+ this._end = end;
1094
+
1095
+ this._body.setContent(rows);
1096
+
1097
+ if (hasFixed) {
1098
+ this._vheader.removeClass("@hidden");
1099
+ this._vheader.setContent(headers);
1100
+ }
1101
+ else {
1102
+ this._vheader.addClass("@hidden");
1103
+ }
1104
+ }
1105
+ }
1106
+ }
1107
+ /**
1108
+ *
1109
+ */
1110
+
1111
+ private _clearSelection() {
1112
+ for (const ref of this._selection.keys()) {
1113
+ const els = this.queryAll(`.row[data-row="${ref}"]`)
1114
+ els.forEach(el => {
1115
+ el.removeClass("selected");
1116
+ })
1117
+ }
1118
+
1119
+ this._selection.clear();
1120
+ }
1121
+
1122
+ /**
1123
+ *
1124
+ */
1125
+
1126
+ private _addSelection(rowid: number) {
1127
+ this._selection.add(rowid)
1128
+
1129
+ const els = this.queryAll(`.row[data-row="${rowid}"]`)
1130
+ els.forEach(el => {
1131
+ el.addClass("selected");
1132
+ });
1133
+
1134
+ const rec = this._dataview.getByIndex( rowid );
1135
+ this.fire("selectionChange", { selection: rec, empty: false } );
1136
+ }
1137
+
1138
+ /**
1139
+ *
1140
+ */
1141
+
1142
+ getSelection( ) {
1143
+ if( this._selection.size==0 ) {
1144
+ return null;
1145
+ }
1146
+
1147
+ const ids = [...this._selection.values() ];
1148
+ return ids.map( id => this._dataview.getByIndex(id) );
1149
+ }
1150
+
1151
+ /**
1152
+ *
1153
+ */
1154
+
1155
+ getFirstSel( ) {
1156
+ if( this._selection.size==0 ) {
1157
+ return null;
1158
+ }
1159
+
1160
+ const id = this._selection.values().next().value;
1161
+ return this._dataview.getByIndex( id );
1162
+ }
1163
+
1164
+ /**
1165
+ *
1166
+ */
1167
+
1168
+ selectItem( id: any ) {
1169
+ const index = this._dataview.indexOfId( id );
1170
+ if( index>=0 ) {
1171
+ this._addSelection( index );
1172
+ }
1173
+ }
1174
+ }
1175
+