x4js 2.0.18 → 2.0.21

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 (201) hide show
  1. package/README.md +1 -0
  2. package/lib/cjs/x4.css +1 -1
  3. package/lib/cjs/x4.js +2 -2
  4. package/lib/esm/x4.css +1 -1
  5. package/lib/esm/x4.mjs +2 -2
  6. package/lib/styles/x4.css +1 -1
  7. package/lib/types/x4js.d.ts +92 -77
  8. package/package.json +1 -1
  9. package/src/components/boxes/boxes.ts +35 -3
  10. package/src/components/breadcrumb/breadcrumb.ts +4 -4
  11. package/src/components/btngroup/btngroup.ts +4 -4
  12. package/src/components/button/button.ts +2 -2
  13. package/src/components/calendar/calendar.ts +1 -1
  14. package/src/components/canvas/canvas.ts +2 -2
  15. package/src/components/checkbox/checkbox.ts +4 -4
  16. package/src/components/colorinput/colorinput.ts +3 -3
  17. package/src/components/combobox/combobox.module.scss +13 -0
  18. package/src/components/combobox/combobox.ts +10 -3
  19. package/src/components/dialog/dialog.ts +7 -7
  20. package/src/components/form/form.ts +5 -5
  21. package/src/components/gridview/gridview.ts +12 -9
  22. package/src/components/header/header.module.scss +2 -1
  23. package/src/components/header/header.ts +22 -10
  24. package/src/components/icon/icon.module.scss +1 -0
  25. package/src/components/icon/icon.ts +1 -1
  26. package/src/components/image/image.ts +3 -3
  27. package/src/components/input/input.ts +2 -2
  28. package/src/components/keyboard/keyboard.ts +5 -5
  29. package/src/components/label/label.module.scss +6 -1
  30. package/src/components/label/label.ts +1 -1
  31. package/src/components/listbox/listbox.module.scss +35 -31
  32. package/src/components/listbox/listbox.ts +53 -15
  33. package/src/components/messages/messages.ts +15 -1
  34. package/src/components/notification/notification.ts +8 -8
  35. package/src/components/popup/popup.ts +14 -3
  36. package/src/components/progress/progress.ts +1 -1
  37. package/src/components/propgrid/propgrid.ts +5 -3
  38. package/src/components/radio/radio.ts +2 -2
  39. package/src/components/rating/rating.ts +6 -6
  40. package/src/components/select/select.ts +1 -1
  41. package/src/components/sizers/sizer.ts +5 -5
  42. package/src/components/slider/slider.ts +3 -3
  43. package/src/components/switch/switch.ts +3 -3
  44. package/src/components/tabs/tabs.module.scss +2 -2
  45. package/src/components/tabs/tabs.ts +29 -5
  46. package/src/components/textarea/textarea.ts +1 -1
  47. package/src/components/textedit/textedit.ts +2 -2
  48. package/src/components/tickline/tickline.ts +1 -1
  49. package/src/components/tooltips/tooltips.ts +2 -2
  50. package/src/components/treeview/treeview.module.scss +9 -1
  51. package/src/components/treeview/treeview.ts +53 -14
  52. package/src/components/viewport/viewport.ts +1 -1
  53. package/src/core/component.ts +46 -9
  54. package/src/core/core_application.ts +3 -3
  55. package/src/core/core_data.ts +12 -12
  56. package/src/core/core_element.ts +1 -1
  57. package/src/core/core_react.ts +2 -2
  58. package/src/core/core_router.ts +2 -2
  59. package/src/core/core_state.ts +1 -1
  60. package/src/core/core_styles.ts +1 -1
  61. package/src/core/core_tools.ts +2 -0
  62. package/lib/src/components/base.scss +0 -25
  63. package/lib/src/components/boxes/boxes.module.scss +0 -54
  64. package/lib/src/components/boxes/boxes.ts +0 -370
  65. package/lib/src/components/breadcrumb/breadcrumb.scss +0 -56
  66. package/lib/src/components/breadcrumb/breadcrumb.ts +0 -93
  67. package/lib/src/components/breadcrumb/chevron-right.svg +0 -1
  68. package/lib/src/components/btngroup/btngroup.module.scss +0 -41
  69. package/lib/src/components/btngroup/btngroup.ts +0 -153
  70. package/lib/src/components/button/button.module.scss +0 -173
  71. package/lib/src/components/button/button.ts +0 -185
  72. package/lib/src/components/calendar/calendar-check-sharp-light.svg +0 -1
  73. package/lib/src/components/calendar/calendar.module.scss +0 -163
  74. package/lib/src/components/calendar/calendar.ts +0 -327
  75. package/lib/src/components/calendar/chevron-left-sharp-light.svg +0 -1
  76. package/lib/src/components/calendar/chevron-right-sharp-light.svg +0 -1
  77. package/lib/src/components/canvas/canvas.module.scss +0 -25
  78. package/lib/src/components/canvas/canvas.ts +0 -189
  79. package/lib/src/components/canvas/canvas_ex.ts +0 -276
  80. package/lib/src/components/checkbox/check.svg +0 -4
  81. package/lib/src/components/checkbox/checkbox.module.scss +0 -142
  82. package/lib/src/components/checkbox/checkbox.ts +0 -140
  83. package/lib/src/components/colorinput/colorinput.module.scss +0 -65
  84. package/lib/src/components/colorinput/colorinput.ts +0 -91
  85. package/lib/src/components/colorinput/crosshairs-simple-sharp-light.svg +0 -1
  86. package/lib/src/components/colorpicker/colorpicker.module.scss +0 -133
  87. package/lib/src/components/colorpicker/colorpicker.ts +0 -482
  88. package/lib/src/components/combobox/combobox.module.scss +0 -133
  89. package/lib/src/components/combobox/combobox.ts +0 -275
  90. package/lib/src/components/combobox/updown.svg +0 -4
  91. package/lib/src/components/components.ts +0 -42
  92. package/lib/src/components/dialog/dialog.module.scss +0 -104
  93. package/lib/src/components/dialog/dialog.ts +0 -229
  94. package/lib/src/components/dialog/xmark-sharp-light.svg +0 -1
  95. package/lib/src/components/filedrop/cloud-arrow-up.svg +0 -1
  96. package/lib/src/components/filedrop/filedrop.module.scss +0 -70
  97. package/lib/src/components/filedrop/filedrop.ts +0 -131
  98. package/lib/src/components/form/form.module.scss +0 -38
  99. package/lib/src/components/form/form.ts +0 -172
  100. package/lib/src/components/gridview/arrow-down-light.svg +0 -1
  101. package/lib/src/components/gridview/arrow-up-light.svg +0 -1
  102. package/lib/src/components/gridview/gridview.module.scss +0 -324
  103. package/lib/src/components/gridview/gridview.ts +0 -1175
  104. package/lib/src/components/header/header.module.scss +0 -40
  105. package/lib/src/components/header/header.ts +0 -130
  106. package/lib/src/components/icon/icon.module.scss +0 -31
  107. package/lib/src/components/icon/icon.ts +0 -137
  108. package/lib/src/components/image/image.module.scss +0 -28
  109. package/lib/src/components/image/image.ts +0 -168
  110. package/lib/src/components/input/input.module.scss +0 -74
  111. package/lib/src/components/input/input.ts +0 -422
  112. package/lib/src/components/keyboard/arrow-up.svg +0 -1
  113. package/lib/src/components/keyboard/delete-left.svg +0 -1
  114. package/lib/src/components/keyboard/eye-slash.svg +0 -1
  115. package/lib/src/components/keyboard/keyboard.module.scss +0 -134
  116. package/lib/src/components/keyboard/keyboard.ts +0 -526
  117. package/lib/src/components/label/label.module.scss +0 -76
  118. package/lib/src/components/label/label.ts +0 -97
  119. package/lib/src/components/link/link.ts +0 -81
  120. package/lib/src/components/listbox/listbox.module.scss +0 -161
  121. package/lib/src/components/listbox/listbox.ts +0 -539
  122. package/lib/src/components/menu/caret-right-solid.svg +0 -1
  123. package/lib/src/components/menu/menu.module.scss +0 -117
  124. package/lib/src/components/menu/menu.ts +0 -174
  125. package/lib/src/components/messages/circle-exclamation.svg +0 -1
  126. package/lib/src/components/messages/messages.module.scss +0 -92
  127. package/lib/src/components/messages/messages.ts +0 -215
  128. package/lib/src/components/messages/pen-field.svg +0 -1
  129. package/lib/src/components/normalize.scss +0 -391
  130. package/lib/src/components/notification/circle-check-solid.svg +0 -1
  131. package/lib/src/components/notification/circle-exclamation-solid.svg +0 -1
  132. package/lib/src/components/notification/circle-notch-light.svg +0 -1
  133. package/lib/src/components/notification/notification.module.scss +0 -84
  134. package/lib/src/components/notification/notification.ts +0 -107
  135. package/lib/src/components/notification/xmark-sharp-light.svg +0 -1
  136. package/lib/src/components/panel/panel.module.scss +0 -60
  137. package/lib/src/components/panel/panel.ts +0 -58
  138. package/lib/src/components/popup/popup.module.scss +0 -51
  139. package/lib/src/components/popup/popup.ts +0 -442
  140. package/lib/src/components/progress/progress.module.scss +0 -57
  141. package/lib/src/components/progress/progress.ts +0 -44
  142. package/lib/src/components/propgrid/folder-closed.svg +0 -1
  143. package/lib/src/components/propgrid/folder-open.svg +0 -1
  144. package/lib/src/components/propgrid/progrid.module.scss +0 -112
  145. package/lib/src/components/propgrid/propgrid.ts +0 -288
  146. package/lib/src/components/propgrid/updown.svg +0 -4
  147. package/lib/src/components/radio/radio.module.scss +0 -147
  148. package/lib/src/components/radio/radio.svg +0 -4
  149. package/lib/src/components/radio/radio.ts +0 -142
  150. package/lib/src/components/rating/rating.module.scss +0 -23
  151. package/lib/src/components/rating/rating.ts +0 -131
  152. package/lib/src/components/rating/star-sharp-light.svg +0 -1
  153. package/lib/src/components/rating/star-sharp-solid.svg +0 -1
  154. package/lib/src/components/select/select.module.scss +0 -9
  155. package/lib/src/components/select/select.ts +0 -134
  156. package/lib/src/components/shared.scss +0 -137
  157. package/lib/src/components/sizers/sizer.module.scss +0 -90
  158. package/lib/src/components/sizers/sizer.ts +0 -132
  159. package/lib/src/components/slider/slider.module.scss +0 -118
  160. package/lib/src/components/slider/slider.ts +0 -198
  161. package/lib/src/components/switch/switch.module.scss +0 -127
  162. package/lib/src/components/switch/switch.ts +0 -62
  163. package/lib/src/components/tabs/tabs.module.scss +0 -45
  164. package/lib/src/components/tabs/tabs.ts +0 -205
  165. package/lib/src/components/textarea/textarea.module.scss +0 -63
  166. package/lib/src/components/textarea/textarea.ts +0 -125
  167. package/lib/src/components/textedit/textedit.module.scss +0 -116
  168. package/lib/src/components/textedit/textedit.ts +0 -115
  169. package/lib/src/components/themes.scss +0 -88
  170. package/lib/src/components/tickline/tickline.module.scss +0 -26
  171. package/lib/src/components/tickline/tickline.ts +0 -82
  172. package/lib/src/components/tooltips/circle-info-sharp-light.svg +0 -1
  173. package/lib/src/components/tooltips/comments-question.svg +0 -1
  174. package/lib/src/components/tooltips/tooltips.scss +0 -72
  175. package/lib/src/components/tooltips/tooltips.ts +0 -109
  176. package/lib/src/components/treeview/chevron-down-light.svg +0 -1
  177. package/lib/src/components/treeview/treeview.module.scss +0 -185
  178. package/lib/src/components/treeview/treeview.ts +0 -445
  179. package/lib/src/components/viewport/viewport.module.scss +0 -32
  180. package/lib/src/components/viewport/viewport.ts +0 -41
  181. package/lib/src/core/component.ts +0 -1066
  182. package/lib/src/core/core_application.ts +0 -265
  183. package/lib/src/core/core_colors.ts +0 -250
  184. package/lib/src/core/core_data.ts +0 -1310
  185. package/lib/src/core/core_dom.ts +0 -471
  186. package/lib/src/core/core_dragdrop.ts +0 -201
  187. package/lib/src/core/core_element.ts +0 -115
  188. package/lib/src/core/core_events.ts +0 -177
  189. package/lib/src/core/core_i18n.ts +0 -393
  190. package/lib/src/core/core_react.ts +0 -79
  191. package/lib/src/core/core_router.ts +0 -237
  192. package/lib/src/core/core_state.ts +0 -62
  193. package/lib/src/core/core_styles.ts +0 -214
  194. package/lib/src/core/core_svg.ts +0 -712
  195. package/lib/src/core/core_tools.ts +0 -906
  196. package/lib/src/types/scss.d.ts +0 -4
  197. package/lib/src/types/svg.d.ts +0 -1
  198. package/lib/src/types/x4react.d.ts +0 -9
  199. package/lib/src/x4.scss +0 -19
  200. package/lib/src/x4.ts +0 -35
  201. package/lib/src/x4tsx.d.ts +0 -25
@@ -1,906 +0,0 @@
1
- /**
2
- * ___ ___ __
3
- * \ \/ / / _
4
- * \ / /_| |_
5
- * / \____ _|
6
- * /__/\__\ |_|
7
- *
8
- * @file core_tools.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
- import { _tr } from "./core_i18n.js";
18
-
19
- /**
20
- * @returns true if object is a string
21
- */
22
- export function isString(val: any): val is string {
23
- return typeof val === 'string';
24
- }
25
-
26
- /**
27
- * @returns true if object is a number
28
- */
29
-
30
- export function isNumber(v: any): v is number {
31
- return typeof v === 'number' && isFinite(v);
32
- }
33
-
34
- /**
35
- * @returns true if object is an array
36
- */
37
- export function isArray(val: any): val is any[] {
38
- return val instanceof Array;
39
- }
40
-
41
- /**
42
- * @returns true if object is a function
43
- */
44
-
45
- export function isFunction(val: any): val is Function {
46
- return val instanceof Function;
47
- }
48
-
49
- /**
50
- * generic constructor
51
- */
52
-
53
- export type Constructor<P> = {
54
- new(...params: any[]): P;
55
- };
56
-
57
-
58
- /**
59
- * a way to explain that the given string may be unsafe but must be treated a sstring
60
- * @example
61
- * label.setText( unsafehtml`<b>Bold</b> text` );
62
- * label.setText( new UnsafeHtml("<b>Bold</b> text`" ) );
63
- */
64
-
65
- export class UnsafeHtml extends String {
66
- constructor(value: string) {
67
- super(value);
68
- }
69
- }
70
-
71
- export function unsafeHtml(x: string): UnsafeHtml {
72
- return new UnsafeHtml(x);
73
- }
74
-
75
- export function unsafe(strings: TemplateStringsArray, ...values: any[]): UnsafeHtml {
76
- const result = strings.reduce((acc, str, i) => {
77
- return acc + str + (values[i] || '');
78
- }, '');
79
- return unsafeHtml(result);
80
- }
81
-
82
- /**
83
- *
84
- */
85
-
86
- export function clamp<T>(v: T, min: T, max: T): T {
87
- if (v < min) { return min; }
88
- if (v > max) { return max; }
89
- return v;
90
- }
91
-
92
-
93
- /**
94
- * generic Rectangle
95
- */
96
-
97
- export interface IRect {
98
- left: number;
99
- top: number;
100
- height: number;
101
- width: number;
102
- }
103
-
104
- /**
105
- *
106
- */
107
-
108
- export class Rect implements IRect {
109
- left: number;
110
- top: number;
111
- height: number;
112
- width: number;
113
-
114
- constructor();
115
- constructor(l: number, t: number, w: number, h: number);
116
- constructor(l: Rect);
117
- constructor(l?: number | IRect, t?: number, w?: number, h?: number) {
118
- if (l !== undefined) {
119
- if (isNumber(l)) {
120
- this.left = l;
121
- this.top = t;
122
- this.width = w;
123
- this.height = h;
124
- }
125
- else {
126
- Object.assign(this, l);
127
- }
128
- }
129
- }
130
-
131
- get right() {
132
- return this.left + this.width;
133
- }
134
-
135
- get bottom() {
136
- return this.top + this.height;
137
- }
138
-
139
- contains(pt: Point): boolean;
140
- contains(rc: Rect): boolean;
141
- contains(arg: any): boolean {
142
- if (arg instanceof Rect) {
143
- return arg.left >= this.left && arg.right <= this.right && arg.top >= this.top && arg.bottom <= this.bottom;
144
- }
145
- else {
146
- return arg.x >= this.left && arg.x < this.right && arg.y >= this.top && arg.y < this.bottom;
147
- }
148
- }
149
-
150
- touches(rc: Rect): boolean {
151
- if (this.left > rc.right || this.right < rc.left || this.top > rc.bottom || this.bottom < rc.top) {
152
- return false;
153
- }
154
-
155
- return true;
156
- }
157
-
158
- normalize(): this {
159
- let w = this.width,
160
- h = this.height;
161
-
162
- if (w < 0) {
163
- this.left += w;
164
- this.width = -w;
165
- }
166
-
167
- if (h < 0) {
168
- this.top += h;
169
- this.height = -h;
170
- }
171
-
172
- return this;
173
- }
174
- }
175
-
176
- /**
177
- * generic size
178
- */
179
-
180
- export interface Size {
181
- w: number;
182
- h: number;
183
- }
184
-
185
-
186
- /**
187
- * generic Point
188
- * TODO: IPoint
189
- */
190
-
191
- export interface Point {
192
- x: number;
193
- y: number;
194
- }
195
-
196
-
197
- /**
198
- * generic Size
199
- * TODO: ISize
200
- */
201
-
202
- export interface Size {
203
- w: number;
204
- h: number;
205
- }
206
-
207
- /**
208
- * center one rect inside another
209
- */
210
-
211
-
212
- export function centerRect(innerRect: IRect, outerRect: IRect, margin: number = 0): IRect {
213
-
214
- const owidth = outerRect.width - 2 * margin;
215
- const oheight = outerRect.height - 2 * margin;
216
-
217
- const ratio = innerRect.width / innerRect.height;
218
-
219
- let nwidth = owidth;
220
- let nheight = owidth / ratio;
221
-
222
- if (nheight > oheight) {
223
- nheight = oheight;
224
- nwidth = oheight * ratio;
225
- }
226
-
227
- const newLeft = outerRect.left + (outerRect.width - nwidth) / 2;
228
- const newTop = outerRect.top + (outerRect.height - nheight) / 2;
229
-
230
- return { left: newLeft, top: newTop, width: nwidth, height: nheight };
231
- }
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
- /**
247
- * @see queryInterface
248
- */
249
-
250
- export interface IComponentInterface {
251
- }
252
-
253
- // form-element
254
- export interface IFormElement extends IComponentInterface {
255
- getRawValue(): any;
256
- setRawValue(v: any): void;
257
- isValid(): boolean;
258
- }
259
-
260
- // tab-handler
261
- export interface ITabHandler extends IComponentInterface {
262
- focusNext(next: boolean): boolean; // return true to stop event
263
- }
264
-
265
- // tip-handler
266
- export interface ITipHandler extends IComponentInterface {
267
- getTip(): string;
268
- }
269
-
270
- /**
271
- *
272
- */
273
-
274
- interface Features {
275
- eyedropper: 1,
276
- }
277
-
278
- export function isFeatureAvailable(name: keyof Features): boolean {
279
- switch (name) {
280
- case "eyedropper": return "EyeDropper" in window;
281
- }
282
-
283
- return false;
284
- }
285
-
286
- export class Timer {
287
-
288
- protected _timers: Map<string, any>;
289
-
290
- /**
291
- *
292
- */
293
-
294
- setTimeout(name: string, time: number, callback: Function) {
295
- if (!this._timers) {
296
- this._timers = new Map();
297
- }
298
- else {
299
- this.clearTimeout(name);
300
- }
301
-
302
- const tm = setTimeout(callback, time);
303
- this._timers.set(name, tm);
304
-
305
- return tm;
306
- }
307
-
308
- clearTimeout(name: string) {
309
- if (this._timers && this._timers.has(name)) {
310
- clearTimeout(this._timers.get(name));
311
- this._timers.delete(name);
312
- }
313
- }
314
-
315
- /**
316
- *
317
- */
318
-
319
- setInterval(name: string, time: number, callback: Function) {
320
- if (!this._timers) {
321
- this._timers = new Map();
322
- }
323
- else {
324
- this.clearInterval(name);
325
- }
326
-
327
- const tm = setInterval(callback, time);
328
- this._timers.set(name, tm);
329
-
330
- return tm;
331
- }
332
-
333
- clearInterval(name: string) {
334
- if (this._timers && this._timers.has(name)) {
335
- clearInterval(this._timers.get(name));
336
- this._timers.delete(name);
337
- }
338
- }
339
-
340
- clearAllTimeouts() {
341
- this._timers?.forEach(t => {
342
- clearTimeout(t);
343
- });
344
-
345
- this._timers = null;
346
- }
347
- }
348
-
349
- /**
350
- *
351
- */
352
-
353
- export function asap(callback: () => void) {
354
- return requestAnimationFrame(callback);
355
- }
356
-
357
- export function oneshot(callback: () => void, ms = 0) {
358
- return setTimeout(callback, ms);
359
- }
360
-
361
-
362
- // :: STRING UTILS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
363
-
364
-
365
- /**
366
- * prepend 0 to a value to a given length
367
- * @param value
368
- * @param length
369
- */
370
-
371
- export function pad(what: any, size: number, ch: string = '0') {
372
-
373
- let value: string;
374
-
375
- if (!isString(what)) {
376
- value = '' + what;
377
- }
378
- else {
379
- value = what;
380
- }
381
-
382
- if (size > 0) {
383
- return value.padEnd(size, ch);
384
- }
385
- else {
386
- return value.padStart(-size, ch);
387
- }
388
- }
389
-
390
- /**
391
- * replace {0..9} by given arguments
392
- * @param format string
393
- * @param args
394
- *
395
- * @example ```ts
396
- *
397
- * console.log( sprintf( 'here is arg 1 {1} and arg 0 {0}', 'argument 0', 'argument 1' ) )
398
- */
399
-
400
- export function sprintf(format: string, ...args: any[]) {
401
- return format.replace(/{(\d+)}/g, function (match, index) {
402
- return typeof args[index] != 'undefined' ? args[index] : match;
403
- });
404
- }
405
-
406
- /**
407
- * inverse of camel case
408
- * theThingToCase -> the-thing-to-case
409
- * @param {String} str
410
- */
411
-
412
- export function pascalCase(string: string): string {
413
-
414
- let result = string;
415
-
416
- result = result.replace(/([a-z])([A-Z])/g, "$1 $2");
417
- result = result.toLowerCase();
418
- result = result.replace(/[^- a-z0-9]+/g, ' ');
419
-
420
- if (result.indexOf(' ') < 0) {
421
- return result;
422
- }
423
-
424
- result = result.trim();
425
- return result.replace(/ /g, '-');
426
- }
427
-
428
- export function camelCase(text: string) {
429
- let result = text.toLowerCase();
430
- result = result.replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => {
431
- return chr.toUpperCase();
432
- });
433
- return result;
434
- }
435
-
436
- // :: DATES ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
437
-
438
- let cur_locale: string = 'fr-FR';
439
-
440
- /**
441
- * change the current locale for misc translations (date...)
442
- * @param locale
443
- */
444
-
445
- export function _date_set_locale(locale: string) {
446
- cur_locale = locale;
447
- }
448
-
449
- /**
450
- *
451
- * @param date
452
- * @param options
453
- * @example
454
- * let date = new Date( );
455
- * let options = { day: 'numeric', month: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric' };
456
- * let text = date_format( date, options );
457
- */
458
-
459
- export function date_format(date: Date, options?: any): string {
460
- //return new Intl.DateTimeFormat(cur_locale, options).format( date );
461
- return formatIntlDate(date);
462
- }
463
-
464
- /**
465
- *
466
- * @param date
467
- * @param options
468
- */
469
-
470
- export function date_diff(date1: Date, date2: Date, options?: any): string {
471
-
472
- let dt = (date1.getTime() - date2.getTime()) / 1000;
473
-
474
- // seconds
475
- let sec = dt;
476
- if (sec < 60) {
477
- return sprintf(_tr.global.diff_date_seconds, Math.round(sec));
478
- }
479
-
480
- // minutes
481
- let min = Math.floor(sec / 60);
482
- if (min < 60) {
483
- return sprintf(_tr.global.diff_date_minutes, Math.round(min));
484
- }
485
-
486
- // hours
487
- let hrs = Math.floor(min / 60);
488
- return sprintf(_tr.global.diff_date_hours, hrs, min % 60);
489
- }
490
-
491
- export function date_to_sql(date: Date, withHours: boolean) {
492
-
493
- if (withHours) {
494
- return formatIntlDate(date, 'Y-M-D H:I:S');
495
- }
496
- else {
497
- return formatIntlDate(date, 'Y-M-D');
498
- }
499
- }
500
-
501
- /**
502
- * construct a date from an utc date time (sql format)
503
- * YYYY-MM-DD HH:MM:SS
504
- */
505
-
506
- export function date_sql_utc(date: string): Date {
507
- let result = new Date(date + ' GMT');
508
- return result;
509
- }
510
-
511
-
512
-
513
- /**
514
- * return a number that is a representation of the date
515
- * this number can be compared with another hash
516
- */
517
-
518
- export function date_hash(date: Date): number {
519
- return date.getFullYear() << 16 | date.getMonth() << 8 | date.getDate();
520
- }
521
-
522
- /**
523
- * return a copy of a date
524
- */
525
-
526
- export function date_clone(date: Date): Date {
527
- return new Date(date.getTime());
528
- }
529
-
530
- /**
531
- * return the week number of a date
532
- */
533
-
534
- export function date_calc_weeknum(date: Date): number {
535
- const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
536
- const pastDaysOfYear = (date.valueOf() - firstDayOfYear.valueOf()) / 86400000;
537
- return Math.floor((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7);
538
- }
539
-
540
-
541
-
542
- /**
543
- * parse a date according to the given format
544
- * @param value - string date to parse
545
- * @param fmts - format list - i18 tranlation by default
546
- * allowed format specifiers:
547
- * d: date (1 or 2 digits)
548
- * D: date (2 digits)
549
- * m: month (1 or 2 digits)
550
- * M: month (2 digits)
551
- * y: year (2 to 4 digits)
552
- * Y: year (2 digits)
553
- * YY: year (4 digits)
554
- * h: hours (1 or 2 digits)
555
- * H: hours (2 digits)
556
- * i: minutes (1 or 2 digits)
557
- * I: minutes (2 digits)
558
- * s: seconds (1 or 2 digits)
559
- * S: seconds (2 digits)
560
- * <space>: 1 or more spaces
561
- * any other char: <0 or more spaces><the char><0 or more spaces>
562
- * each specifiers is separated from other by a pipe (|)
563
- * more specific at first
564
- * @example
565
- * 'd/m/y|d m Y|dmy|y-m-d h:i:s|y-m-d|YY-M-D'
566
- */
567
-
568
- export function parseIntlDate(value: string, fmts: string = _tr.global.date_input_formats): Date {
569
-
570
- let formats = fmts.split('|');
571
- for (let fmatch of formats) {
572
-
573
- //review: could do that only once & keep result
574
- //review: add hours, minutes, seconds
575
-
576
- let smatch = '';
577
- for (let i = 0; i < fmatch.length; i++) {
578
- const c = fmatch[i];
579
-
580
- if (c == 'd') {
581
- smatch += '(?<day>\\d{1,2})';
582
- }
583
- else if (c == 'D') {
584
- smatch += '(?<day>\\d{2})';
585
- }
586
- else if (c == 'm') {
587
- smatch += '(?<month>\\d{1,2})';
588
- }
589
- else if (c == 'M') {
590
- smatch += '(?<month>\\d{2})';
591
- }
592
- else if (c == 'y') {
593
- smatch += '(?<year>\\d{1,4})';
594
- }
595
- else if (c == 'Y') {
596
- if (fmatch[i + 1] == 'Y') {
597
- smatch += '(?<year>\\d{4})';
598
- i++;
599
- }
600
- else {
601
- smatch += '(?<year>\\d{2})';
602
- }
603
- }
604
- else if (c == 'h') {
605
- smatch += '(?<hour>\\d{1,2})';
606
- }
607
- else if (c == 'H') {
608
- smatch += '(?<hour>\\d{2})';
609
- }
610
- else if (c == 'i') {
611
- smatch += '(?<min>\\d{1,2})';
612
- }
613
- else if (c == 'I') {
614
- smatch += '(?<min>\\d{2})';
615
- }
616
- else if (c == 's') {
617
- smatch += '(?<sec>\\d{1,2})';
618
- }
619
- else if (c == 'S') {
620
- smatch += '(?<sec>\\d{2})';
621
- }
622
- else if (c == ' ') {
623
- smatch += '\\s+';
624
- }
625
- else {
626
- smatch += '\\s*\\' + c + '\\s*';
627
- }
628
- }
629
-
630
- let rematch = new RegExp('^' + smatch + '$', 'm');
631
-
632
- let match = rematch.exec(value);
633
-
634
- if (match) {
635
- const now = new Date();
636
-
637
- let d = parseInt(match.groups.day ?? '1');
638
- let m = parseInt(match.groups.month ?? '1');
639
- let y = parseInt(match.groups.year ?? now.getFullYear() + '');
640
- let h = parseInt(match.groups.hour ?? '0');
641
- let i = parseInt(match.groups.min ?? '0');
642
- let s = parseInt(match.groups.sec ?? '0');
643
-
644
- if (y > 0 && y < 100) {
645
- y += 2000;
646
- }
647
-
648
- let result = new Date(y, m - 1, d, h, i, s, 0);
649
-
650
- // we test the vdate validity (without adjustments)
651
- // without this test, date ( 0, 0, 0) is accepted and transformed to 1969/11/31 (not fun)
652
- let ty = result.getFullYear(),
653
- tm = result.getMonth() + 1,
654
- td = result.getDate();
655
-
656
- if (ty != y || tm != m || td != d) {
657
- //debugger;
658
- return null;
659
- }
660
-
661
- return result;
662
- }
663
- }
664
-
665
- return null;
666
- }
667
-
668
- /**
669
- * format a date as string
670
- * @param date - date to format
671
- * @param fmt - format
672
- * format specifiers:
673
- * - d: date (no pad)
674
- * - D: 2 digits date padded with 0
675
- * - j: day of week short mode 'mon'
676
- * - J: day of week long mode 'monday'
677
- * - w: week number
678
- * - m: month (no pad)
679
- * - M: 2 digits month padded with 0
680
- * - o: month short mode 'jan'
681
- * - O: month long mode 'january'
682
- * - y or Y: year
683
- * - h: hour (24 format)
684
- * - H: 2 digits hour (24 format) padded with 0
685
- * - i: minutes
686
- * - I: 2 digits minutes padded with 0
687
- * - s: seconds
688
- * - S: 2 digits seconds padded with 0
689
- * - a: am or pm
690
- * - anything else is inserted
691
- * - if you need to insert some text, put it between {}
692
- *
693
- * @example
694
- *
695
- * 01/01/1970 11:25:00 with '{this is my demo date formatter: }H-i*M'
696
- * "this is my demo date formatter: 11-25*january"
697
- */
698
-
699
- export function formatIntlDate(date: Date, fmt: string = _tr.global.date_format) {
700
-
701
- if (!date) {
702
- return '';
703
- }
704
-
705
- let now = {
706
- year: date.getFullYear(),
707
- month: date.getMonth() + 1,
708
- day: date.getDate(),
709
- wday: date.getDay(),
710
- hours: date.getHours(),
711
- minutes: date.getMinutes(),
712
- seconds: date.getSeconds(),
713
- milli: date.getMilliseconds()
714
- };
715
-
716
-
717
- let result = '';
718
- let esc = 0;
719
-
720
- for (let c of fmt) {
721
-
722
- if (c == '{') {
723
- if (++esc == 1) {
724
- continue;
725
- }
726
- }
727
- else if (c == '}') {
728
- if (--esc == 0) {
729
- continue;
730
- }
731
- }
732
-
733
- if (esc) {
734
- result += c;
735
- continue;
736
- }
737
-
738
- if (c == 'd') {
739
- result += now.day;
740
- }
741
- else if (c == 'D') {
742
- result += pad(now.day, -2);
743
- }
744
- else if (c == 'j') { // day short
745
- result += _tr.global.day_short[now.wday];
746
- }
747
- else if (c == 'J') { // day long
748
- result += _tr.global.day_long[now.wday];
749
- }
750
- else if (c == 'w') { // week
751
- result += date_calc_weeknum(date);
752
- }
753
- else if (c == 'W') { // week
754
- result += pad(date_calc_weeknum(date), -2);
755
- }
756
- else if (c == 'm') {
757
- result += now.month;
758
- }
759
- else if (c == 'M') {
760
- result += pad(now.month, -2);
761
- }
762
- else if (c == 'o') { // month short
763
- result += _tr.global.month_short[now.month - 1];
764
- }
765
- else if (c == 'O') { // month long
766
- result += _tr.global.month_long[now.month - 1];
767
- }
768
- else if (c == 'y' || c == 'Y') {
769
- result += pad(now.year, -4);
770
- }
771
- else if (c == 'a' || c == 'A') {
772
- result += now.hours < 12 ? 'am' : 'pm';
773
- }
774
- else if (c == 'h') {
775
- result += now.hours;
776
- }
777
- else if (c == 'H') {
778
- result += pad(now.hours, -2);
779
- }
780
- else if (c == 'i') {
781
- result += now.minutes;
782
- }
783
- else if (c == 'I') {
784
- result += pad(now.minutes, -2);
785
- }
786
- else if (c == 's') {
787
- result += now.seconds;
788
- }
789
- else if (c == 'S') {
790
- result += pad(now.seconds, -2);
791
- }
792
- else if (c == 'l') {
793
- result += now.milli;
794
- }
795
- else if (c == 'L') {
796
- result += pad(now.milli, -3);
797
- }
798
- else {
799
- result += c;
800
- }
801
- }
802
-
803
- return result;
804
- }
805
-
806
- export function calcAge(birth: Date, ref?: Date) {
807
- if (ref === undefined) {
808
- ref = new Date();
809
- }
810
-
811
- if (!birth) {
812
- return 0;
813
- }
814
-
815
- let age = ref.getFullYear() - birth.getFullYear();
816
- if (ref.getMonth() < birth.getMonth() || (ref.getMonth() == birth.getMonth() && ref.getDate() < birth.getDate())) {
817
- age--;
818
- }
819
-
820
- return age;
821
- }
822
-
823
-
824
- // :: MISC ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
825
-
826
- export function beep() {
827
- const snd = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");
828
- snd.play();
829
- }
830
-
831
- let sb_width_cache = -1;
832
-
833
- /**
834
- * compute scrollbar size
835
- */
836
-
837
- export function getScrollbarSize() {
838
-
839
- if (sb_width_cache < 0) {
840
- let outerDiv = document.createElement('div');
841
- outerDiv.style.cssText = 'overflow:auto;position:absolute;top:0;width:100px;height:100px';
842
-
843
- let innerDiv = document.createElement('div');
844
- innerDiv.style.width = '200px';
845
- innerDiv.style.height = '200px';
846
-
847
- outerDiv.appendChild(innerDiv);
848
- document.body.appendChild(outerDiv);
849
-
850
- sb_width_cache = outerDiv.offsetWidth - outerDiv.clientWidth;
851
- document.body.removeChild(outerDiv);
852
- }
853
-
854
- return sb_width_cache;
855
- }
856
-
857
- /**
858
- *
859
- */
860
-
861
- export const x4_class_ns_sym = Symbol("class-ns");
862
- export function class_ns(ns: string) {
863
- return function (constructor: Function) {
864
- (constructor as any)[x4_class_ns_sym] = ns;
865
- }
866
- }
867
-
868
- /**
869
- *
870
- */
871
-
872
- export function setWaitCursor(wait: boolean) {
873
- document.body.style.cursor = wait ? "wait" : "default";
874
- }
875
-
876
- /**
877
- * return the focusable elements from a given node
878
- */
879
-
880
- export function getFocusableElements(root: Element) {
881
- const els = [
882
- 'button:not([tabindex="-1"]):not([disabled])',
883
- '[href]',
884
- 'input:not([disabled])',
885
- 'select:not([disabled])',
886
- 'textarea:not([disabled])',
887
- '[tabindex]:not([tabindex="-1"])'
888
- ]
889
-
890
- const focusable = Array.from(root.querySelectorAll(els.join(',')));
891
- return focusable.filter(x => (x as HTMLElement).offsetParent != null); // check visibility
892
- }
893
-
894
- /**
895
- *
896
- */
897
-
898
- export enum kbNav {
899
- first,
900
- prev,
901
- pgdn,
902
- pgup,
903
- next,
904
- last,
905
- }
906
-