x4js 2.3.24 → 2.3.26
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 +101 -17
- package/aiguide.md +64 -15
- package/package.json +1 -1
- package/src/components/assets/icons.ts +2 -0
- package/src/components/autocomplete/autocomplete.ts +2 -2
- 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 +7 -2
- package/src/components/calendar/calendar.ts +4 -2
- package/src/components/canvas/canvas.ts +1 -2
- package/src/components/chart/chart.ts +3 -3
- 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/dialog/dialog.ts +8 -2
- package/src/components/dockingview/dockingview.ts +1 -2
- package/src/components/filedrop/filedrop.ts +3 -2
- package/src/components/form/form.module.scss +2 -1
- package/src/components/form/form.ts +7 -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.module.scss +59 -2
- package/src/components/listbox/listbox.ts +133 -23
- package/src/components/menu/menu.ts +5 -4
- package/src/components/messages/messages.module.scss +95 -3
- package/src/components/messages/messages.ts +113 -27
- package/src/components/notification/notification.ts +6 -6
- package/src/components/panel/panel.ts +2 -2
- package/src/components/popup/popup.ts +17 -2
- package/src/components/progress/progress.ts +1 -2
- package/src/components/propgrid/progrid.module.scss +2 -3
- package/src/components/propgrid/propgrid.ts +32 -38
- package/src/components/radio/radio.ts +1 -2
- package/src/components/rating/rating.ts +2 -2
- 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/tooltips/tooltips.ts +11 -2
- package/src/components/treeview/treeview.ts +3 -3
- package/src/components/video/video.ts +1 -2
- package/src/components/viewport/viewport.ts +4 -3
- package/src/core/component.ts +15 -24
- package/src/core/core_application.ts +36 -3
- package/src/core/core_events.ts +14 -2
- package/src/core/core_i18n.ts +67 -0
- package/src/core/core_svg.ts +1 -0
- package/src/core/core_tools.ts +83 -24
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// :: MESSAGEBOX ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
3
3
|
|
|
4
4
|
import { _tr } from '../../core/core_i18n';
|
|
5
|
-
import { asap,
|
|
5
|
+
import { asap, sprintf, unsafeHtml, UnsafeHtml } from '../../core/core_tools';
|
|
6
6
|
|
|
7
7
|
import { HBox, VBox } from '../boxes/boxes';
|
|
8
8
|
import { Icon } from '../icon/icon';
|
|
@@ -11,10 +11,10 @@ import { Dialog, DialogProps } from "../dialog/dialog"
|
|
|
11
11
|
import { Form } from '../form/form';
|
|
12
12
|
import { BtnGroupItem } from '../btngroup/btngroup';
|
|
13
13
|
import { Input } from '../input/input';
|
|
14
|
-
import { SimpleTextArea } from '../textarea/textarea';
|
|
15
14
|
import { Button } from '../button/button';
|
|
16
15
|
import { Component } from '../../core/component';
|
|
17
16
|
import { Progress } from '../components.js';
|
|
17
|
+
import icons from '../assets/icons';
|
|
18
18
|
|
|
19
19
|
import "./messages.module.scss";
|
|
20
20
|
|
|
@@ -38,14 +38,22 @@ export interface MessageBoxProps extends DialogProps {
|
|
|
38
38
|
* --msgbox-icon-color
|
|
39
39
|
* --msgbox-question-icon-color
|
|
40
40
|
* --msgbox-log-background
|
|
41
|
+
* --msgbox-log-border
|
|
42
|
+
* --msgbox-log-border-focus
|
|
43
|
+
* --msgbox-log-error-color
|
|
44
|
+
* --msgbox-log-error-background
|
|
45
|
+
* --msgbox-log-warning-color
|
|
46
|
+
* --msgbox-log-warning-background
|
|
47
|
+
* --msgbox-log-scrollbar
|
|
41
48
|
* ```
|
|
42
49
|
* --msgbox-caption-* and --msgbox-icon-color are the ones of an error; a question, an InputBox
|
|
43
50
|
* and a PromptBox have the title bar of a Dialog and their icon in --msgbox-question-icon-color
|
|
44
51
|
*/
|
|
45
52
|
|
|
46
|
-
@class_ns( "x4" )
|
|
47
53
|
export class MessageBox extends Dialog<DialogProps>
|
|
48
54
|
{
|
|
55
|
+
static classPrefix = "x4";
|
|
56
|
+
|
|
49
57
|
constructor(props: DialogProps) {
|
|
50
58
|
super(props);
|
|
51
59
|
}
|
|
@@ -134,9 +142,10 @@ interface InputOptions {
|
|
|
134
142
|
trim?: boolean;
|
|
135
143
|
}
|
|
136
144
|
|
|
137
|
-
@class_ns( "x4" )
|
|
138
145
|
export class InputBox extends Dialog<DialogProps>
|
|
139
146
|
{
|
|
147
|
+
static classPrefix = "x4";
|
|
148
|
+
|
|
140
149
|
constructor(props: DialogProps) {
|
|
141
150
|
super(props);
|
|
142
151
|
}
|
|
@@ -203,9 +212,10 @@ export class InputBox extends Dialog<DialogProps>
|
|
|
203
212
|
// :: PROMPT ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
204
213
|
|
|
205
214
|
|
|
206
|
-
@class_ns( "x4" )
|
|
207
215
|
export class PromptBox extends Dialog<DialogProps>
|
|
208
216
|
{
|
|
217
|
+
static classPrefix = "x4";
|
|
218
|
+
|
|
209
219
|
constructor(props: DialogProps) {
|
|
210
220
|
super(props);
|
|
211
221
|
}
|
|
@@ -279,15 +289,21 @@ export class PromptBox extends Dialog<DialogProps>
|
|
|
279
289
|
|
|
280
290
|
/**
|
|
281
291
|
* a modal box that follows a long task: a title, a bar, and the lines of what is done
|
|
282
|
-
* in a
|
|
283
|
-
*
|
|
284
|
-
*
|
|
292
|
+
* in a <pre>, in a fixed font, a <div> each: a string is text, an UnsafeHtml is html. An
|
|
293
|
+
* error, a warning are coloured on all their width, a bar on their left. addSection puts
|
|
294
|
+
* the lines that follow in a section that folds. Ctrl+A selects the lines.
|
|
295
|
+
* done( ) shows its button OK: after an error or a warning it waits for it, their counts
|
|
296
|
+
* on the left of the bar; else it closes the box after 5s, the seconds left in the button.
|
|
285
297
|
*/
|
|
286
298
|
|
|
287
|
-
@class_ns( "x4" )
|
|
288
299
|
export class ProgressionBox extends Dialog {
|
|
300
|
+
static classPrefix = "x4";
|
|
301
|
+
|
|
302
|
+
// an error or a warning: done( ) waits for OK
|
|
303
|
+
private _errors = 0;
|
|
304
|
+
private _warnings = 0;
|
|
289
305
|
|
|
290
|
-
|
|
306
|
+
private _section: Component; // the last section (a <details>): the lines go in it
|
|
291
307
|
|
|
292
308
|
constructor( title: string ) {
|
|
293
309
|
super( {
|
|
@@ -303,13 +319,15 @@ export class ProgressionBox extends Dialog {
|
|
|
303
319
|
new VBox( { flex: 1, cls: "right", content: [
|
|
304
320
|
new SimpleText( { id: "title", text: title } ),
|
|
305
321
|
new Progress( { id:"prog", min: 0, max: 100, value: 0 } ),
|
|
306
|
-
new
|
|
322
|
+
new Component( { tag: "pre", id: "sub-text", attrs: { tabindex: 0 }, dom_events: {
|
|
323
|
+
keydown: ( ev ) => this._on_log_key( ev ),
|
|
324
|
+
} } ),
|
|
307
325
|
]})
|
|
308
326
|
]
|
|
309
327
|
}),
|
|
310
328
|
]
|
|
311
329
|
}),
|
|
312
|
-
buttons: [ "ok.outline.default" ]
|
|
330
|
+
buttons: [ new Label( { id: "alerts", text: "" } ), "-", "ok.outline.default" ]
|
|
313
331
|
});
|
|
314
332
|
|
|
315
333
|
this.query("#btnbar").show( false );
|
|
@@ -328,50 +346,118 @@ export class ProgressionBox extends Dialog {
|
|
|
328
346
|
this.query<Progress>( "#prog").setValue( perc );
|
|
329
347
|
}
|
|
330
348
|
|
|
331
|
-
/** a line at the end: done( ) then waits for the button OK */
|
|
349
|
+
/** a line at the end, with the icon of an error: done( ) then waits for the button OK */
|
|
332
350
|
|
|
333
351
|
addError( text: string | UnsafeHtml, perc: number ) {
|
|
334
|
-
this._addLine( text );
|
|
352
|
+
this._addLine( text, "error" );
|
|
353
|
+
this.query<Progress>( "#prog").setValue( perc );
|
|
354
|
+
this.addClass( "error" ); // the title bar in red, as the one of an error of MessageBox
|
|
355
|
+
|
|
356
|
+
this._errors++;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** a line at the end, with the icon of a warning: done( ) then waits for the button OK */
|
|
360
|
+
|
|
361
|
+
addWarning( text: string | UnsafeHtml, perc: number ) {
|
|
362
|
+
this._addLine( text, "warning" );
|
|
335
363
|
this.query<Progress>( "#prog").setValue( perc );
|
|
336
364
|
|
|
337
|
-
this
|
|
365
|
+
this._warnings++;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* a section at the end, open: the lines that follow go in it. A click on its title folds
|
|
370
|
+
* it; its title has the icon of the worst of its lines (an error, a warning)
|
|
371
|
+
*/
|
|
372
|
+
|
|
373
|
+
addSection( title: string | UnsafeHtml, perc: number ) {
|
|
374
|
+
const summary = new Component( { tag: "summary", content: new Component( { tag: "span", cls: "alert" } ) } );
|
|
375
|
+
summary.appendContent( title );
|
|
376
|
+
|
|
377
|
+
this._section = new Component( { tag: "details", attrs: { open: true }, content: summary } );
|
|
378
|
+
|
|
379
|
+
const log = this.query( "#sub-text" );
|
|
380
|
+
log.appendContent( this._section );
|
|
381
|
+
log.dom.scrollTop = log.dom.scrollHeight;
|
|
382
|
+
this.query<Progress>( "#prog").setValue( perc );
|
|
338
383
|
}
|
|
339
384
|
|
|
340
385
|
/** the text in place of all the lines */
|
|
341
386
|
|
|
342
387
|
setText( text: string | UnsafeHtml, perc: number ) {
|
|
343
|
-
this.
|
|
388
|
+
this._section = null;
|
|
389
|
+
this.query( "#sub-text" ).setContent( text );
|
|
344
390
|
this.query<Progress>( "#prog").setValue( perc );
|
|
345
391
|
}
|
|
346
392
|
|
|
347
393
|
/** as at the start: no line, no error, no button OK */
|
|
348
394
|
|
|
349
395
|
clear( ) {
|
|
350
|
-
this
|
|
396
|
+
this._errors = 0;
|
|
397
|
+
this._warnings = 0;
|
|
351
398
|
this.clearInterval( "close" );
|
|
352
399
|
this.query( "#btnbar" ).show( false );
|
|
353
|
-
this.
|
|
400
|
+
this.removeClass( "error" );
|
|
401
|
+
this.query<Label>( "#alerts" ).setText( "" );
|
|
402
|
+
this.query<Label>( "#alerts" ).setIcon( null );
|
|
403
|
+
this._section = null;
|
|
404
|
+
this.query( "#sub-text" ).clearContent( );
|
|
354
405
|
}
|
|
355
406
|
|
|
356
|
-
// the line after the others, the last one shown
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
407
|
+
// the line after the others (in the last section), the last one shown: a <div>, of the
|
|
408
|
+
// class of its kind for an error, a warning
|
|
409
|
+
private _addLine( text: string | UnsafeHtml, kind?: "error" | "warning" ) {
|
|
410
|
+
const log = this.query( "#sub-text" );
|
|
411
|
+
const target = this._section ?? log;
|
|
412
|
+
|
|
413
|
+
target.appendContent( new Component( { cls: kind ? "line " + kind : "line", content: text } ) );
|
|
414
|
+
|
|
415
|
+
// the title of the section: the icon of the worst, in its colour
|
|
416
|
+
const alert = this._section?.query( ".alert" );
|
|
417
|
+
if( kind && alert && !alert.hasClass( "error" ) ) {
|
|
418
|
+
alert.setClass( "warning", kind=="warning" );
|
|
419
|
+
alert.setClass( "error", kind=="error" );
|
|
420
|
+
alert.setContent( unsafeHtml( kind=="error" ? icons.danger : icons.warning ) );
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
log.dom.scrollTop = log.dom.scrollHeight;
|
|
424
|
+
}
|
|
360
425
|
|
|
361
|
-
|
|
362
|
-
|
|
426
|
+
// Ctrl+A: the lines only, not the whole page
|
|
427
|
+
private _on_log_key( ev: KeyboardEvent ) {
|
|
428
|
+
if( ( ev.ctrlKey || ev.metaKey ) && ev.key.toLowerCase( )=="a" ) {
|
|
429
|
+
document.getSelection( ).selectAllChildren( ev.currentTarget as HTMLElement );
|
|
430
|
+
ev.preventDefault( );
|
|
431
|
+
}
|
|
363
432
|
}
|
|
364
433
|
|
|
365
434
|
/**
|
|
366
|
-
* the task is over: the button OK is shown. After an error it waits for
|
|
367
|
-
*
|
|
435
|
+
* the task is over: the button OK is shown. After an error or a warning it waits for
|
|
436
|
+
* a click, their counts on the left of the bar ("2 errors / 1 warning"); without one it counts the
|
|
437
|
+
* seconds left, "OK (5s)", and closes the box at 0
|
|
368
438
|
*/
|
|
369
439
|
|
|
370
440
|
done( ) {
|
|
371
441
|
const ok = this.query<Button>( "#ok" );
|
|
372
442
|
this.query( "#btnbar" ).show( true );
|
|
373
443
|
|
|
374
|
-
if( this
|
|
444
|
+
if( this._errors || this._warnings ) {
|
|
445
|
+
const tr = _tr.global.progression;
|
|
446
|
+
const counts = [];
|
|
447
|
+
if( this._errors ) {
|
|
448
|
+
counts.push( sprintf( this._errors>1 ? tr.errors : tr.error, this._errors ) );
|
|
449
|
+
}
|
|
450
|
+
if( this._warnings ) {
|
|
451
|
+
counts.push( sprintf( this._warnings>1 ? tr.warnings : tr.warning, this._warnings ) );
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// on the left, the icon of the worst
|
|
455
|
+
const alerts = this.query<Label>( "#alerts" );
|
|
456
|
+
alerts.setText( counts.join( " / " ) );
|
|
457
|
+
alerts.setIcon( this._errors ? icons.danger : icons.warning );
|
|
458
|
+
alerts.setClass( "error", this._errors>0 );
|
|
459
|
+
alerts.setClass( "warning", this._errors==0 );
|
|
460
|
+
|
|
375
461
|
ok.setText( _tr.global.ok );
|
|
376
462
|
return;
|
|
377
463
|
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
17
|
import { ComponentProps } from '../../core/component';
|
|
18
|
-
import { asap,
|
|
18
|
+
import { asap, Rect, UnsafeHtml } from '../../core/core_tools';
|
|
19
19
|
|
|
20
20
|
import { Popup } from '../popup/popup';
|
|
21
21
|
import { HBox, VBox } from '../boxes/boxes';
|
|
@@ -61,18 +61,18 @@ interface NotificationProps extends ComponentProps {
|
|
|
61
61
|
* ```
|
|
62
62
|
*/
|
|
63
63
|
|
|
64
|
-
@class_ns( "x4" )
|
|
65
64
|
export class Notification extends Popup {
|
|
65
|
+
static classPrefix = "x4";
|
|
66
|
+
|
|
66
67
|
private static list = new Set<Notification>( );
|
|
67
68
|
|
|
68
69
|
constructor( props: NotificationProps ) {
|
|
69
|
-
super(
|
|
70
|
+
super( props );
|
|
70
71
|
|
|
71
72
|
let icon = props.iconId;
|
|
72
73
|
if( !icon ) {
|
|
73
74
|
if( props.loading ) {
|
|
74
75
|
icon = icons.loading;
|
|
75
|
-
this.addClass( "")
|
|
76
76
|
}
|
|
77
77
|
else if( props.mode=="danger" ) {
|
|
78
78
|
icon = icons.danger;
|
|
@@ -84,10 +84,10 @@ export class Notification extends Popup {
|
|
|
84
84
|
|
|
85
85
|
this.addClass( props.mode );
|
|
86
86
|
|
|
87
|
+
// the icon of loading turns (x4rotate, base.scss)
|
|
87
88
|
const _icon = new Icon( { iconId: icon } );
|
|
88
89
|
if( props.loading ) {
|
|
89
|
-
_icon.addClass( "
|
|
90
|
-
//this.props.modal = true;
|
|
90
|
+
_icon.addClass( "x4rotate" );
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
this.setContent( new HBox( {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
17
|
import { Component, ComponentContent, ComponentProps } from '../../core/component';
|
|
18
|
-
import { UnsafeHtml, Constructor
|
|
18
|
+
import { UnsafeHtml, Constructor } from '../../core/core_tools';
|
|
19
19
|
|
|
20
20
|
import { VBox } from '../boxes/boxes';
|
|
21
21
|
import { Label } from '../label/label';
|
|
@@ -37,8 +37,8 @@ interface PanelProps extends ComponentProps {
|
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
|
-
@class_ns( "x4" )
|
|
41
40
|
export class Panel extends VBox<PanelProps> {
|
|
41
|
+
static classPrefix = "x4";
|
|
42
42
|
|
|
43
43
|
private _title: Label;
|
|
44
44
|
private _body: Component;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { Component, ComponentEvent, ComponentEvents, ComponentProps, componentFromDOM, makeUniqueComponentId } from "../../core/component"
|
|
18
18
|
|
|
19
19
|
import { CSizer } from '../sizers/sizer';
|
|
20
|
-
import { Rect, Point,
|
|
20
|
+
import { Rect, Point, asap } from '../../core/core_tools';
|
|
21
21
|
import { Box } from '../boxes/boxes'
|
|
22
22
|
|
|
23
23
|
import "./popup.module.scss"
|
|
@@ -70,11 +70,12 @@ function dismissLast( e: UIEvent ) {
|
|
|
70
70
|
* ```
|
|
71
71
|
*/
|
|
72
72
|
|
|
73
|
-
@class_ns( "x4" )
|
|
74
73
|
export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = PopupEvents> extends Box<P,E> {
|
|
74
|
+
static classPrefix = "x4";
|
|
75
75
|
|
|
76
76
|
private _isshown = false;
|
|
77
77
|
protected _ismodal = false;
|
|
78
|
+
private _prevFocus: HTMLElement; // modal: the element that had the focus when it opened
|
|
78
79
|
|
|
79
80
|
constructor( props: P ) {
|
|
80
81
|
super( props );
|
|
@@ -220,6 +221,11 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
|
|
|
220
221
|
return;
|
|
221
222
|
}
|
|
222
223
|
|
|
224
|
+
// modal: the focus goes back to the element that had it when it opened, unless the
|
|
225
|
+
// user put it elsewhere (read before the popup leaves the page and its focus with it)
|
|
226
|
+
const active = document.activeElement;
|
|
227
|
+
const giveBack = this._ismodal && this._prevFocus && ( !active || active===document.body || this.dom.contains( active ) );
|
|
228
|
+
|
|
223
229
|
this.__hide( );
|
|
224
230
|
this.__remove( );
|
|
225
231
|
|
|
@@ -255,6 +261,11 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
|
|
|
255
261
|
}
|
|
256
262
|
}
|
|
257
263
|
|
|
264
|
+
if( giveBack && this._prevFocus.isConnected ) {
|
|
265
|
+
this._prevFocus.focus( );
|
|
266
|
+
}
|
|
267
|
+
this._prevFocus = null;
|
|
268
|
+
|
|
258
269
|
this._isshown = false;
|
|
259
270
|
this.fire( "closed", {} );
|
|
260
271
|
}
|
|
@@ -272,6 +283,10 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
|
|
|
272
283
|
this.__append( );
|
|
273
284
|
|
|
274
285
|
if( this._ismodal ) {
|
|
286
|
+
// given back the focus when it closes; <body>: nothing had it
|
|
287
|
+
const active = document.activeElement as HTMLElement;
|
|
288
|
+
this._prevFocus = active && active!==document.body ? active : null;
|
|
289
|
+
|
|
275
290
|
modal_stack.push( this );
|
|
276
291
|
this._showModalMask( );
|
|
277
292
|
}
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
* that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
|
-
import { class_ns } from '../../core/core_tools';
|
|
18
17
|
import { Component, ComponentProps } from '../../core/component';
|
|
19
18
|
|
|
20
19
|
import "./progress.module.scss";
|
|
@@ -33,8 +32,8 @@ interface ProgressProps extends ComponentProps {
|
|
|
33
32
|
* ```
|
|
34
33
|
*/
|
|
35
34
|
|
|
36
|
-
@class_ns( "x4" )
|
|
37
35
|
export class Progress extends Component<ProgressProps> {
|
|
36
|
+
static classPrefix = "x4";
|
|
38
37
|
|
|
39
38
|
private _bar: Component;
|
|
40
39
|
|
|
@@ -117,9 +117,8 @@
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
// A row has no box of its own: its two cells go straight on the columns
|
|
120
|
-
// of the grid, which is how all the titles get the same width.
|
|
121
|
-
//
|
|
122
|
-
// and bottom line, is carried by its cells.
|
|
120
|
+
// of the grid, which is how all the titles get the same width. What a row
|
|
121
|
+
// looked like, background and bottom line, is carried by its cells.
|
|
123
122
|
.row {
|
|
124
123
|
display: contents;
|
|
125
124
|
|
|
@@ -21,7 +21,7 @@ import { HBox, VBox } from "../boxes/boxes"
|
|
|
21
21
|
import { Input } from "../input/input"
|
|
22
22
|
import { ListboxID, ListItem } from "../listbox/listbox"
|
|
23
23
|
import { Label, SimpleText } from "../label/label"
|
|
24
|
-
import { asap,
|
|
24
|
+
import { asap, isFunction, isNumber } from '../../core/core_tools';
|
|
25
25
|
import { Icon, ScrollView } from '../components'
|
|
26
26
|
import { ColorInput } from '../colorinput/colorinput'
|
|
27
27
|
import { EvColorChange } from '../colorpicker/colorpicker'
|
|
@@ -84,12 +84,15 @@ export interface PropertyProps extends ComponentProps {
|
|
|
84
84
|
* ```
|
|
85
85
|
*/
|
|
86
86
|
|
|
87
|
-
@class_ns( "x4" )
|
|
88
87
|
export class PropertyGrid extends VBox {
|
|
88
|
+
static classPrefix = "x4";
|
|
89
89
|
|
|
90
90
|
private root: Component;
|
|
91
91
|
private groups: PropertyGroup[];
|
|
92
92
|
|
|
93
|
+
// the editor of each property, by its name: no id, a name is not unique in a page
|
|
94
|
+
private editors = new Map<string, Component>( );
|
|
95
|
+
|
|
93
96
|
constructor(props: PropertyProps) {
|
|
94
97
|
super(props);
|
|
95
98
|
|
|
@@ -118,6 +121,8 @@ export class PropertyGrid extends VBox {
|
|
|
118
121
|
|
|
119
122
|
setItems( _grps: PropertyGroup[] ) {
|
|
120
123
|
|
|
124
|
+
this.editors.clear( );
|
|
125
|
+
|
|
121
126
|
if( !_grps || _grps.length==0 ) {
|
|
122
127
|
this.root.clearContent( );
|
|
123
128
|
return;
|
|
@@ -218,7 +223,6 @@ export class PropertyGrid extends VBox {
|
|
|
218
223
|
if (item.type === 'boolean') {
|
|
219
224
|
editor = new Input({
|
|
220
225
|
type: "checkbox",
|
|
221
|
-
id: item.name,
|
|
222
226
|
//name: item.name,
|
|
223
227
|
checked: value as boolean,
|
|
224
228
|
dom_events: {
|
|
@@ -232,7 +236,6 @@ export class PropertyGrid extends VBox {
|
|
|
232
236
|
else if (item.type === 'options') {
|
|
233
237
|
editor = new Select( {
|
|
234
238
|
value: value as ListboxID,
|
|
235
|
-
id: item.name,
|
|
236
239
|
items: item.options,
|
|
237
240
|
//name: item.name,
|
|
238
241
|
change: ( e: EvChange ) => {
|
|
@@ -243,20 +246,23 @@ export class PropertyGrid extends VBox {
|
|
|
243
246
|
else if (item.type === 'password') {
|
|
244
247
|
editor = new Input({
|
|
245
248
|
type: 'password',
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
value: String(value),
|
|
249
|
+
//name: item.name,
|
|
250
|
+
value: String(value),
|
|
249
251
|
focus: ( e: EvFocus ) => {
|
|
250
252
|
if( e.focus_out ) {
|
|
251
253
|
item.callback?.( item.name, (editor as Input).getValue() );
|
|
252
254
|
}
|
|
255
|
+
},
|
|
256
|
+
change: ( ) => {
|
|
257
|
+
if( item.live ) {
|
|
258
|
+
item.callback?.( item.name, (editor as Input).getValue() );
|
|
259
|
+
}
|
|
253
260
|
}
|
|
254
261
|
});
|
|
255
262
|
}
|
|
256
263
|
else if (item.type === 'number') {
|
|
257
264
|
editor = new Input({
|
|
258
265
|
type: 'number',
|
|
259
|
-
id: item.name,
|
|
260
266
|
//name: item.name,
|
|
261
267
|
value: String(value),
|
|
262
268
|
step: item.step,
|
|
@@ -276,7 +282,6 @@ export class PropertyGrid extends VBox {
|
|
|
276
282
|
}
|
|
277
283
|
else if (item.type === 'color') {
|
|
278
284
|
editor = new ColorInput({
|
|
279
|
-
id: item.name,
|
|
280
285
|
color: value as string,
|
|
281
286
|
format: "hex",
|
|
282
287
|
picker: true,
|
|
@@ -289,14 +294,12 @@ export class PropertyGrid extends VBox {
|
|
|
289
294
|
}
|
|
290
295
|
else if (item.type === 'label') {
|
|
291
296
|
editor = new Label({
|
|
292
|
-
id: item.name,
|
|
293
297
|
text: value as string,
|
|
294
298
|
});
|
|
295
299
|
}
|
|
296
300
|
else if (item.type === 'button') {
|
|
297
301
|
use_hdr = false;
|
|
298
302
|
editor = new Button({
|
|
299
|
-
id: item.name,
|
|
300
303
|
cls: "button",
|
|
301
304
|
label: value as string,
|
|
302
305
|
click: ( ) => {
|
|
@@ -307,7 +310,6 @@ export class PropertyGrid extends VBox {
|
|
|
307
310
|
else {
|
|
308
311
|
editor = new Input({
|
|
309
312
|
type: 'text',
|
|
310
|
-
id: item.name,
|
|
311
313
|
//name: item.name,
|
|
312
314
|
value: value as string,
|
|
313
315
|
focus: ( e: EvFocus ) => {
|
|
@@ -315,8 +317,17 @@ export class PropertyGrid extends VBox {
|
|
|
315
317
|
item.callback?.( item.name, (editor as Input).getValue() );
|
|
316
318
|
}
|
|
317
319
|
},
|
|
320
|
+
change: ( ) => {
|
|
321
|
+
if( item.live ) {
|
|
322
|
+
item.callback?.( item.name, (editor as Input).getValue() );
|
|
323
|
+
}
|
|
324
|
+
}
|
|
318
325
|
})
|
|
319
326
|
}
|
|
327
|
+
|
|
328
|
+
if( item.name ) {
|
|
329
|
+
this.editors.set( item.name, editor );
|
|
330
|
+
}
|
|
320
331
|
|
|
321
332
|
let cls = 'row';
|
|
322
333
|
if( item.cls ) {
|
|
@@ -340,7 +351,7 @@ export class PropertyGrid extends VBox {
|
|
|
340
351
|
cls,
|
|
341
352
|
content: [
|
|
342
353
|
use_hdr ? new Component({ cls: 'cell hdr', content: item.title ?? item.name, tooltip: item.desc }) : null,
|
|
343
|
-
new HBox({ cls: 'cell', tag: "label",
|
|
354
|
+
new HBox({ cls: 'cell', tag: "label", content }),
|
|
344
355
|
]
|
|
345
356
|
});
|
|
346
357
|
}
|
|
@@ -352,45 +363,28 @@ export class PropertyGrid extends VBox {
|
|
|
352
363
|
setPropValue( name: string, value: any ) {
|
|
353
364
|
const all = this.groups.flatMap( x => [ ...x.items ] ) ;
|
|
354
365
|
const item = all.find( x => x.name==name );
|
|
355
|
-
|
|
366
|
+
const editor = this.editors.get( name );
|
|
367
|
+
if( !item || !editor ) {
|
|
356
368
|
return;
|
|
357
369
|
}
|
|
358
370
|
|
|
359
371
|
if (item.type === 'boolean') {
|
|
360
|
-
|
|
361
|
-
if( editor ) {
|
|
362
|
-
editor.setCheck( value as boolean );
|
|
363
|
-
}
|
|
372
|
+
(editor as Input).setCheck( value as boolean );
|
|
364
373
|
}
|
|
365
374
|
else if (item.type === 'options') {
|
|
366
|
-
|
|
367
|
-
if( editor ) {
|
|
368
|
-
editor.setValue( value as string );
|
|
369
|
-
}
|
|
375
|
+
(editor as Select).setValue( value as string );
|
|
370
376
|
}
|
|
371
377
|
else if (item.type === 'number') {
|
|
372
|
-
|
|
373
|
-
if( editor ) {
|
|
374
|
-
editor.setNumValue( value as number, -2 );
|
|
375
|
-
}
|
|
378
|
+
(editor as Input).setNumValue( value as number, -2 );
|
|
376
379
|
}
|
|
377
380
|
else if (item.type === 'color') {
|
|
378
|
-
|
|
379
|
-
if( editor ) {
|
|
380
|
-
editor.setColor( value as string );
|
|
381
|
-
}
|
|
381
|
+
(editor as ColorInput).setColor( value as string );
|
|
382
382
|
}
|
|
383
383
|
else if (item.type === 'label') {
|
|
384
|
-
|
|
385
|
-
if( label ) {
|
|
386
|
-
label.setText( value );
|
|
387
|
-
}
|
|
384
|
+
(editor as Label).setText( value );
|
|
388
385
|
}
|
|
389
386
|
else {
|
|
390
|
-
|
|
391
|
-
if( editor ) {
|
|
392
|
-
editor.setValue( value as string );
|
|
393
|
-
}
|
|
387
|
+
(editor as Input).setValue( value as string );
|
|
394
388
|
}
|
|
395
389
|
}
|
|
396
390
|
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
17
|
import { Component, ComponentEvents, ComponentProps, EvChange, makeUniqueComponentId } from '../../core/component';
|
|
18
|
-
import { class_ns } from '../../core/core_tools';
|
|
19
18
|
import { EventCallback } from '../../core/core_events';
|
|
20
19
|
|
|
21
20
|
import { Label } from '../label/label';
|
|
@@ -57,8 +56,8 @@ interface RadioProps extends ComponentProps {
|
|
|
57
56
|
* ```
|
|
58
57
|
*/
|
|
59
58
|
|
|
60
|
-
@class_ns( "x4" )
|
|
61
59
|
export class Radio extends Component<RadioProps,RadioEvents> {
|
|
60
|
+
static classPrefix = "x4";
|
|
62
61
|
|
|
63
62
|
private _check: HBox;
|
|
64
63
|
private _input: Input;
|
|
@@ -18,7 +18,7 @@ import { Component, ComponentEvents, ComponentProps, EvChange } from '../../core
|
|
|
18
18
|
import { EventCallback } from '../../core/core_events';
|
|
19
19
|
import { HBox } from '../boxes/boxes';
|
|
20
20
|
import { Icon } from '../icon/icon';
|
|
21
|
-
import {
|
|
21
|
+
import { IComponentInterface, IFormElement } from '../../core/core_tools';
|
|
22
22
|
|
|
23
23
|
import icons from "../assets/icons"
|
|
24
24
|
|
|
@@ -49,8 +49,8 @@ export interface RatingProps extends ComponentProps {
|
|
|
49
49
|
* ```
|
|
50
50
|
*/
|
|
51
51
|
|
|
52
|
-
@class_ns( "x4" )
|
|
53
52
|
export class Rating extends HBox<RatingProps,RatingEventMap> {
|
|
53
|
+
static classPrefix = "x4";
|
|
54
54
|
|
|
55
55
|
private m_els: Component[];
|
|
56
56
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import { EventCallback } from '../../core/core_events';
|
|
19
19
|
import { Component, ComponentEvents, ComponentProps, EvChange, EvFocus } from '../../core/component';
|
|
20
|
-
import {
|
|
20
|
+
import { IComponentInterface, IFormElement, isArray } from '../../core/core_tools';
|
|
21
21
|
|
|
22
22
|
import { ListboxID, ListItem } from '../components';
|
|
23
23
|
|
|
@@ -57,8 +57,8 @@ interface SelectEvents extends ComponentEvents {
|
|
|
57
57
|
* ```
|
|
58
58
|
*/
|
|
59
59
|
|
|
60
|
-
@class_ns( "x4" )
|
|
61
60
|
export class Select extends Component<SelectProps,SelectEvents> {
|
|
61
|
+
static classPrefix = "x4";
|
|
62
62
|
|
|
63
63
|
private _items: ListItem[];
|
|
64
64
|
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
|
|
17
17
|
:root {
|
|
18
18
|
--settingsview-toc-width: 210px;
|
|
19
|
-
--settingsview-section-background: var( --
|
|
20
|
-
--settingsview-section-title-background:
|
|
19
|
+
--settingsview-section-background: var( --background-primary );
|
|
20
|
+
--settingsview-section-title-background: transparent;
|
|
21
|
+
--settingsview-section-title-color: var( --accent-background );
|
|
21
22
|
--settingsview-hover-background: var( --color-primary-a20 );
|
|
22
23
|
--settingsview-marker: var( --accent-background );
|
|
23
24
|
}
|
|
@@ -92,13 +93,13 @@
|
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
// a section:
|
|
96
|
+
// a section: no frame, its title in the accent colour on a line
|
|
96
97
|
.section {
|
|
97
98
|
flex-shrink: 0;
|
|
98
99
|
width: 100%;
|
|
99
100
|
max-width: 900px;
|
|
100
101
|
padding: 0 8px 10px;
|
|
101
|
-
border:
|
|
102
|
+
border: none;
|
|
102
103
|
background: var( --settingsview-section-background );
|
|
103
104
|
overflow: hidden;
|
|
104
105
|
scroll-margin-top: 20px; // brought to the top: below the padding of the view
|
|
@@ -115,7 +116,7 @@
|
|
|
115
116
|
background: var( --settingsview-section-title-background );
|
|
116
117
|
font-size: 1.1rem;
|
|
117
118
|
font-weight: 600;
|
|
118
|
-
--label-color: var( --
|
|
119
|
+
--label-color: var( --settingsview-section-title-color );
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
> .description {
|