x4js 2.3.25 → 2.3.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/aicontext.md +87 -13
- package/package.json +1 -1
- package/src/components/autocomplete/autocomplete.ts +3 -3
- package/src/components/boxes/boxes.module.scss +16 -2
- package/src/components/boxes/boxes.ts +24 -11
- package/src/components/breadcrumb/breadcrumb.ts +1 -2
- package/src/components/btngroup/btngroup.ts +2 -2
- package/src/components/button/button.ts +2 -2
- package/src/components/calendar/calendar.ts +5 -3
- package/src/components/canvas/canvas.ts +1 -2
- package/src/components/chart/chart.ts +4 -4
- package/src/components/checkbox/checkbox.ts +2 -2
- package/src/components/colorinput/colorinput.ts +3 -2
- package/src/components/colorpicker/colorpicker.ts +5 -5
- package/src/components/combobox/combobox.ts +3 -3
- package/src/components/components.ts +1 -0
- package/src/components/dialog/dialog.ts +2 -2
- package/src/components/dockingview/dockingview.ts +2 -3
- package/src/components/filedrop/filedrop.ts +3 -2
- package/src/components/form/form.ts +4 -3
- package/src/components/gauge/gauge.ts +2 -2
- package/src/components/gridview/gridview.module.scss +8 -5
- package/src/components/gridview/gridview.ts +11 -13
- package/src/components/header/header.ts +2 -2
- package/src/components/icon/icon.ts +1 -2
- package/src/components/image/image.ts +1 -2
- package/src/components/input/input.ts +3 -2
- package/src/components/keyboard/keyboard.ts +2 -2
- package/src/components/label/label.ts +3 -3
- package/src/components/link/link.ts +3 -2
- package/src/components/listbox/listbox.ts +33 -47
- package/src/components/menu/menu.ts +5 -4
- package/src/components/messages/messages.module.scss +29 -5
- package/src/components/messages/messages.ts +42 -50
- package/src/components/monaco/monaco.ts +1 -2
- package/src/components/notification/notification.ts +3 -2
- package/src/components/panel/panel.ts +2 -2
- package/src/components/popup/popup.ts +4 -4
- package/src/components/progress/progress.ts +1 -2
- package/src/components/propgrid/progrid.module.scss +2 -3
- package/src/components/propgrid/propgrid.ts +2 -2
- package/src/components/radio/radio.ts +1 -2
- package/src/components/rating/rating.ts +3 -3
- package/src/components/select/select.ts +2 -2
- package/src/components/settingsview/settingsview.module.scss +6 -5
- package/src/components/settingsview/settingsview.ts +3 -3
- package/src/components/sizers/sizer.ts +21 -29
- package/src/components/slider/slider.ts +2 -2
- package/src/components/spreadsheet/spreadsheet.ts +8 -10
- package/src/components/switch/switch.ts +2 -2
- package/src/components/tabs/tabs.ts +4 -4
- package/src/components/tag/tag.ts +2 -2
- package/src/components/textarea/textarea.ts +3 -3
- package/src/components/textedit/textedit.ts +2 -2
- package/src/components/themes.scss +2 -0
- package/src/components/tickline/tickline.ts +3 -3
- package/src/components/timeline/timeline.module.scss +147 -0
- package/src/components/timeline/timeline.ts +146 -0
- package/src/components/tooltips/tooltips.ts +2 -2
- package/src/components/treeview/treeview.ts +19 -25
- package/src/components/video/video.ts +1 -2
- package/src/components/viewport/viewport.ts +4 -3
- package/src/core/component.ts +46 -26
- package/src/core/core_application.ts +29 -1
- package/src/core/core_i18n.ts +39 -0
- package/src/core/core_shortcuts.ts +2 -1
- package/src/core/core_svg.ts +1 -0
- package/src/core/core_tools.ts +83 -24
package/src/core/component.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
|
-
import { isArray, UnsafeHtml, isNumber, Rect, Constructor
|
|
17
|
+
import { isArray, UnsafeHtml, isNumber, Rect, Constructor } from './core_tools';
|
|
18
18
|
import { CoreElement } from './core_element';
|
|
19
19
|
import { AriaAttributes, unitless } from './core_styles';
|
|
20
20
|
import { CoreEvent, EventMap } from './core_events';
|
|
@@ -31,17 +31,19 @@ const FRAGMENT = Symbol( "fragment" );
|
|
|
31
31
|
const RE_NUMBER = /^-?\d+(\.\d*)?$/;
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* the css classes of a component: the name of each class of its chain, in lower case, after
|
|
35
|
+
* the prefix that class declares itself (not the one of its parent):
|
|
35
36
|
*
|
|
36
37
|
* ```
|
|
37
|
-
* static
|
|
38
|
+
* static classPrefix = "<your prefix>";
|
|
38
39
|
* ```
|
|
39
|
-
*
|
|
40
|
-
*
|
|
40
|
+
*
|
|
41
|
+
* every component of x4 declares "x4" (x4button...); the classes of an application have
|
|
42
|
+
* none unless they declare one
|
|
41
43
|
*/
|
|
42
44
|
|
|
43
45
|
function genClassNames( x: any ): string[] {
|
|
44
|
-
|
|
46
|
+
|
|
45
47
|
let self = Object.getPrototypeOf(x);
|
|
46
48
|
if( self.constructor==Component ) {
|
|
47
49
|
return ["x4-comp","x4"];
|
|
@@ -50,8 +52,8 @@ function genClassNames( x: any ): string[] {
|
|
|
50
52
|
const classes = [];
|
|
51
53
|
while (self && self.constructor !== Component ) {
|
|
52
54
|
const clsname:string = self.constructor.name;
|
|
53
|
-
const
|
|
54
|
-
classes.push(
|
|
55
|
+
const prefix: string = Object.prototype.hasOwnProperty.call(self.constructor,"classPrefix") ? self.constructor.classPrefix : "";
|
|
56
|
+
classes.push( prefix+clsname.toLowerCase() );
|
|
55
57
|
self = Object.getPrototypeOf(self);
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -156,9 +158,9 @@ export interface ComponentEvents extends EventMap {
|
|
|
156
158
|
* ```
|
|
157
159
|
*/
|
|
158
160
|
|
|
159
|
-
@class_ns("x4")
|
|
160
161
|
export class Component<P extends ComponentProps = ComponentProps, E extends ComponentEvents = ComponentEvents>
|
|
161
162
|
extends CoreElement<E> {
|
|
163
|
+
static classPrefix = "x4";
|
|
162
164
|
|
|
163
165
|
/** The underlying DOM element of the component. */
|
|
164
166
|
readonly dom: Element;
|
|
@@ -907,19 +909,6 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
907
909
|
this.setAttribute( "disabled", !ena ? 'true' : null );
|
|
908
910
|
this.setAttribute( "inert", !ena ? 'true' : null );
|
|
909
911
|
|
|
910
|
-
/*
|
|
911
|
-
boxes are now fieldset, this is native
|
|
912
|
-
if( this.dom instanceof HTMLInputElement || this.dom instanceof HTMLButtonElement ) {
|
|
913
|
-
this.dom.disabled = !ena;
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
// propagate enable state to all input children
|
|
917
|
-
const nodes = this.enumChildComponents( true );
|
|
918
|
-
nodes.forEach( x => {
|
|
919
|
-
x.enable( ena );
|
|
920
|
-
});
|
|
921
|
-
*/
|
|
922
|
-
|
|
923
912
|
return this;
|
|
924
913
|
}
|
|
925
914
|
|
|
@@ -970,7 +959,24 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
970
959
|
*/
|
|
971
960
|
|
|
972
961
|
parentElement<T extends Component>( cls?: Constructor<T> ): T {
|
|
973
|
-
return Component.parentElement<T>( this.dom, cls );
|
|
962
|
+
return Component.parentElement<T>( this.dom, cls );
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* The nearest component whose element matches a css selector: this one, or one of its ancestors.
|
|
967
|
+
* @returns null when there is none
|
|
968
|
+
*/
|
|
969
|
+
|
|
970
|
+
closest<T extends Component = Component>( selector: string ): T {
|
|
971
|
+
return Component.closest<T>( this.dom, selector );
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* true when a node, or the element of a component, is the element of this one or inside it
|
|
976
|
+
*/
|
|
977
|
+
|
|
978
|
+
contains( other: Component | Node ): boolean {
|
|
979
|
+
return this.dom.contains( other instanceof Component ? other.dom : other );
|
|
974
980
|
}
|
|
975
981
|
|
|
976
982
|
/**
|
|
@@ -1003,10 +1009,22 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
1003
1009
|
|
|
1004
1010
|
dom = dom.parentElement;
|
|
1005
1011
|
}
|
|
1006
|
-
|
|
1012
|
+
|
|
1007
1013
|
return null;
|
|
1008
1014
|
}
|
|
1009
1015
|
|
|
1016
|
+
/**
|
|
1017
|
+
* The nearest component whose element matches a css selector: the one of dom, or one of its ancestors.
|
|
1018
|
+
* @returns null when there is none
|
|
1019
|
+
* @example
|
|
1020
|
+
* // in a click handler: the item hit, wherever the click is in it
|
|
1021
|
+
* const item = Component.closest( ev.target as Element, ".x4timeline > .item" );
|
|
1022
|
+
*/
|
|
1023
|
+
|
|
1024
|
+
static closest<T extends Component = Component>( dom: Element, selector: string ): T {
|
|
1025
|
+
return componentFromDOM<T>( dom.closest( selector ) );
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1010
1028
|
/**
|
|
1011
1029
|
* Returns the first child element as a Component instance.
|
|
1012
1030
|
* @returns The first child component, or `null` if none exists.
|
|
@@ -1294,8 +1312,9 @@ export function wrapDOM( el: HTMLElement ): Component {
|
|
|
1294
1312
|
* Automatically generates CSS class: `x4flex`.
|
|
1295
1313
|
*/
|
|
1296
1314
|
|
|
1297
|
-
@class_ns( "x4" )
|
|
1298
1315
|
export class Flex extends Component {
|
|
1316
|
+
static classPrefix = "x4";
|
|
1317
|
+
|
|
1299
1318
|
constructor( ) {
|
|
1300
1319
|
super({})
|
|
1301
1320
|
}
|
|
@@ -1311,8 +1330,9 @@ export class Flex extends Component {
|
|
|
1311
1330
|
* ```
|
|
1312
1331
|
*/
|
|
1313
1332
|
|
|
1314
|
-
@class_ns( "x4" )
|
|
1315
1333
|
export class Space extends Component {
|
|
1334
|
+
static classPrefix = "x4";
|
|
1335
|
+
|
|
1316
1336
|
constructor( width?: number|string, cls?: string ) {
|
|
1317
1337
|
super( { width, cls } )
|
|
1318
1338
|
}
|
|
@@ -19,6 +19,7 @@ import { CoreElement } from './core_element';
|
|
|
19
19
|
import { CoreEvent, EventMap } from './core_events';
|
|
20
20
|
import { asap, getFocusableElements, ITabHandler } from './core_tools';
|
|
21
21
|
import { Shortcuts, ShortcutCallback, ShortcutOptions } from './core_shortcuts';
|
|
22
|
+
import { _setLocale, getCurrentLocale, getCurrentCurrency } from './core_i18n';
|
|
22
23
|
|
|
23
24
|
const socket_sent = Symbol( 'socket' );
|
|
24
25
|
|
|
@@ -249,7 +250,34 @@ export class Application<E extends ApplicationEvents = ApplicationEvents> extend
|
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
/**
|
|
252
|
-
*
|
|
253
|
+
* Forces the locale of the formats of numbers, amounts and dates (formatNumber, formatMoney,
|
|
254
|
+
* formatDate, formatDateTime), and the currency of the amounts. Without it, the locale is the one of the language (`_tr.global.locale`: "fr-FR"
|
|
255
|
+
* for fr, "en-US" for en...) and the currency "EUR".
|
|
256
|
+
* A field of type number is shown by the browser, in its own locale, whatever this one.
|
|
257
|
+
* @param locale - "fr-CH", "en-GB"...; null: the one of the language again
|
|
258
|
+
* @param currency - "CHF", "USD"...; not given: the currency does not change
|
|
259
|
+
* @example
|
|
260
|
+
* Application.setLocale( "fr-CH", "CHF" );
|
|
261
|
+
*/
|
|
262
|
+
|
|
263
|
+
static setLocale( locale: string, currency?: string ) {
|
|
264
|
+
_setLocale( locale, currency );
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** The locale of the formats: the one forced by setLocale, else the one of the language. */
|
|
268
|
+
|
|
269
|
+
static getLocale( ): string {
|
|
270
|
+
return getCurrentLocale( );
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** The currency of the amounts: "EUR" unless setLocale gave another. */
|
|
274
|
+
|
|
275
|
+
static getCurrency( ): string {
|
|
276
|
+
return getCurrentCurrency( );
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
*
|
|
253
281
|
*/
|
|
254
282
|
|
|
255
283
|
private _setupKeyboard( ) {
|
package/src/core/core_i18n.ts
CHANGED
|
@@ -255,6 +255,41 @@ export function getCurrentLanguage( ): string {
|
|
|
255
255
|
return current.name;
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
// :: LOCALE ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
259
|
+
|
|
260
|
+
// the formats of numbers, amounts and dates: the locale of the language (_tr.global.locale),
|
|
261
|
+
// unless one is forced (Application.setLocale); the currency of the amounts
|
|
262
|
+
let forced_locale: string = null;
|
|
263
|
+
let currency = "EUR";
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @internal the locale forced (null: the one of the language), the currency when given
|
|
267
|
+
*/
|
|
268
|
+
|
|
269
|
+
export function _setLocale( locale: string, cur?: string ) {
|
|
270
|
+
forced_locale = locale || null;
|
|
271
|
+
if( cur ) {
|
|
272
|
+
currency = cur;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* the locale of the formats: the one forced by Application.setLocale, else the one of the
|
|
278
|
+
* language ("fr-FR" for fr)
|
|
279
|
+
*/
|
|
280
|
+
|
|
281
|
+
export function getCurrentLocale( ): string {
|
|
282
|
+
return forced_locale ?? _tr.global.locale ?? "fr-FR";
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* the currency of the amounts: "EUR" unless Application.setLocale gave another
|
|
287
|
+
*/
|
|
288
|
+
|
|
289
|
+
export function getCurrentCurrency( ): string {
|
|
290
|
+
return currency;
|
|
291
|
+
}
|
|
292
|
+
|
|
258
293
|
/**
|
|
259
294
|
*
|
|
260
295
|
*/
|
|
@@ -308,6 +343,7 @@ let fr = {
|
|
|
308
343
|
date_input_formats: 'd/m/y|d.m.y|d m y|d-m-y|dmy',
|
|
309
344
|
date_format: 'D/M/Y',
|
|
310
345
|
date_time_format: 'D/M/Y H:I:S',
|
|
346
|
+
locale: 'fr-FR', // the formats of numbers, amounts, dates (Intl)
|
|
311
347
|
|
|
312
348
|
day_short: [ 'dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam' ],
|
|
313
349
|
day_long: [ 'dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi' ],
|
|
@@ -385,6 +421,7 @@ let en = {
|
|
|
385
421
|
date_input_formats: 'm/d/y|m.d.y|m d y|m-d-y|mdy',
|
|
386
422
|
date_format: 'M/D/Y',
|
|
387
423
|
date_time_format: 'M/D/Y H:I:S',
|
|
424
|
+
locale: 'en-US', // the formats of numbers, amounts, dates (Intl)
|
|
388
425
|
|
|
389
426
|
day_short: [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ],
|
|
390
427
|
day_long: [ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' ],
|
|
@@ -462,6 +499,7 @@ let es = {
|
|
|
462
499
|
date_input_formats: 'd/m/y|d.m.y|d m y|d-m-y|dmy',
|
|
463
500
|
date_format: 'D/M/Y',
|
|
464
501
|
date_time_format: 'D/M/Y H:I:S',
|
|
502
|
+
locale: 'es-ES', // the formats of numbers, amounts, dates (Intl)
|
|
465
503
|
|
|
466
504
|
day_short: [ 'dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sáb' ],
|
|
467
505
|
day_long: [ 'domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado' ],
|
|
@@ -539,6 +577,7 @@ let de = {
|
|
|
539
577
|
date_input_formats: 'd.m.y|d/m/y|d m y|d-m-y|dmy',
|
|
540
578
|
date_format: 'D.M.Y',
|
|
541
579
|
date_time_format: 'D.M.Y H:I:S',
|
|
580
|
+
locale: 'de-DE', // the formats of numbers, amounts, dates (Intl)
|
|
542
581
|
|
|
543
582
|
day_short: [ 'So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa' ],
|
|
544
583
|
day_long: [ 'Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag' ],
|
|
@@ -51,7 +51,8 @@ interface Keys {
|
|
|
51
51
|
key: string;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
/** true on a Mac, an iPhone or an iPad: Mod is Cmd there */
|
|
55
|
+
export const isMac = /mac|iphone|ipad/i.test( navigator.platform ?? "" );
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
58
|
* "Shift+Mod+K" -> shift, ctrl (cmd on a Mac), k
|
package/src/core/core_svg.ts
CHANGED
|
@@ -1013,6 +1013,7 @@ export interface SvgProps extends ComponentProps {
|
|
|
1013
1013
|
*/
|
|
1014
1014
|
|
|
1015
1015
|
export class SvgComponent<P extends SvgProps = SvgProps, E extends ComponentEvents = ComponentEvents> extends Component<P,E> {
|
|
1016
|
+
static classPrefix = "x4";
|
|
1016
1017
|
|
|
1017
1018
|
/**
|
|
1018
1019
|
* Creates an instance of `SvgComponent`.
|
package/src/core/core_tools.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
|
-
import { _tr } from "./core_i18n.js";
|
|
17
|
+
import { _tr, _setLocale, getCurrentLocale, getCurrentCurrency } from "./core_i18n.js";
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
// todo: split into 2 files
|
|
@@ -528,33 +528,103 @@ export function camelCase(text: string) {
|
|
|
528
528
|
|
|
529
529
|
// :: DATES ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
530
530
|
|
|
531
|
-
let cur_locale: string = 'fr-FR';
|
|
532
|
-
|
|
533
531
|
/**
|
|
534
|
-
*
|
|
535
|
-
* @param locale
|
|
536
|
-
* TODO: ????
|
|
532
|
+
* forces the locale of the formats (see Application.setLocale)
|
|
533
|
+
* @param locale
|
|
537
534
|
*/
|
|
538
535
|
|
|
539
536
|
export function _date_set_locale(locale: string) {
|
|
540
|
-
|
|
537
|
+
_setLocale( locale );
|
|
541
538
|
}
|
|
542
539
|
|
|
543
540
|
/**
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
* @param
|
|
541
|
+
* a date as text: with options, the ones of Intl.DateTimeFormat in the current locale;
|
|
542
|
+
* without, the format of the language (_tr.global.date_format)
|
|
543
|
+
* @param date
|
|
544
|
+
* @param options
|
|
547
545
|
* @example
|
|
548
546
|
* let date = new Date( );
|
|
549
|
-
* let options = { day: 'numeric', month: '
|
|
547
|
+
* let options = { day: 'numeric', month: 'long', year: 'numeric' };
|
|
550
548
|
* let text = date_format( date, options );
|
|
551
549
|
*/
|
|
552
550
|
|
|
553
|
-
export function date_format(date: Date, options?:
|
|
554
|
-
|
|
551
|
+
export function date_format(date: Date, options?: Intl.DateTimeFormatOptions): string {
|
|
552
|
+
if( options ) {
|
|
553
|
+
return new Intl.DateTimeFormat( getCurrentLocale( ), options ).format( date );
|
|
554
|
+
}
|
|
555
|
+
|
|
555
556
|
return formatIntlDate(date);
|
|
556
557
|
}
|
|
557
558
|
|
|
559
|
+
// :: FORMATS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
560
|
+
|
|
561
|
+
// numbers, amounts and dates in the current locale (the one of the language, or the one
|
|
562
|
+
// Application.setLocale forced): the objects of Intl, made once by locale and options
|
|
563
|
+
const intl_formats = new Map<string, Intl.NumberFormat | Intl.DateTimeFormat>( );
|
|
564
|
+
|
|
565
|
+
function numberFormat( key: string, options: Intl.NumberFormatOptions ) {
|
|
566
|
+
const locale = getCurrentLocale( );
|
|
567
|
+
const id = locale + "|" + key;
|
|
568
|
+
let fmt = intl_formats.get( id ) as Intl.NumberFormat;
|
|
569
|
+
if( !fmt ) {
|
|
570
|
+
fmt = new Intl.NumberFormat( locale, options );
|
|
571
|
+
intl_formats.set( id, fmt );
|
|
572
|
+
}
|
|
573
|
+
return fmt;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function dateFormat( key: string, options: Intl.DateTimeFormatOptions ) {
|
|
577
|
+
const locale = getCurrentLocale( );
|
|
578
|
+
const id = locale + "|" + key;
|
|
579
|
+
let fmt = intl_formats.get( id ) as Intl.DateTimeFormat;
|
|
580
|
+
if( !fmt ) {
|
|
581
|
+
fmt = new Intl.DateTimeFormat( locale, options );
|
|
582
|
+
intl_formats.set( id, fmt );
|
|
583
|
+
}
|
|
584
|
+
return fmt;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* a number as text in the current locale: "1 234,5" in fr-FR, "1,234.5" in en-US
|
|
589
|
+
* @param value
|
|
590
|
+
* @param decimals - the most decimals shown (Intl: 3 when not given)
|
|
591
|
+
* @param grouping - the separator of thousands, true by default
|
|
592
|
+
*/
|
|
593
|
+
|
|
594
|
+
export function formatNumber( value: number, decimals?: number, grouping = true ): string {
|
|
595
|
+
const options: Intl.NumberFormatOptions = { useGrouping: grouping };
|
|
596
|
+
if( decimals!==undefined ) {
|
|
597
|
+
options.maximumFractionDigits = decimals;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return numberFormat( "n" + decimals + grouping, options ).format( value );
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* an amount as text in the current locale and currency: "1 234,50 €" in fr-FR
|
|
605
|
+
*/
|
|
606
|
+
|
|
607
|
+
export function formatMoney( value: number ): string {
|
|
608
|
+
const currency = getCurrentCurrency( );
|
|
609
|
+
return numberFormat( "m" + currency, { style: "currency", currency } ).format( value );
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* a date as text in the current locale: "22/10/2026" in fr-FR, "10/22/2026" in en-US
|
|
614
|
+
*/
|
|
615
|
+
|
|
616
|
+
export function formatDate( date: Date ): string {
|
|
617
|
+
return dateFormat( "d", { } ).format( date );
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* a date and its time (hours, minutes) as text in the current locale: "22/10/2026 14:05" in fr-FR
|
|
622
|
+
*/
|
|
623
|
+
|
|
624
|
+
export function formatDateTime( date: Date ): string {
|
|
625
|
+
return dateFormat( "dt", { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit" } ).format( date );
|
|
626
|
+
}
|
|
627
|
+
|
|
558
628
|
/**
|
|
559
629
|
* difference between 2 dates
|
|
560
630
|
* @return text
|
|
@@ -1002,17 +1072,6 @@ export function getSystemMetrics( part: "scrollbar" | "zoom" ) {
|
|
|
1002
1072
|
|
|
1003
1073
|
|
|
1004
1074
|
|
|
1005
|
-
/**
|
|
1006
|
-
*
|
|
1007
|
-
*/
|
|
1008
|
-
|
|
1009
|
-
export const x4_class_ns_sym = Symbol("class-ns");
|
|
1010
|
-
export function class_ns(ns: string) {
|
|
1011
|
-
return function (constructor: Function) {
|
|
1012
|
-
(constructor as any)[x4_class_ns_sym] = ns;
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
1075
|
/**
|
|
1017
1076
|
*
|
|
1018
1077
|
*/
|