x4js 2.3.20 → 2.3.22
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 +127 -32
- package/package.json +1 -1
- package/src/components/autocomplete/autocomplete.ts +3 -0
- package/src/components/boxes/boxes.ts +1 -1
- package/src/components/chart/chart.ts +12 -3
- package/src/components/colorinput/colorinput.module.scss +11 -2
- package/src/components/colorinput/colorinput.ts +37 -4
- package/src/components/colorpicker/colorpicker.module.scss +14 -2
- package/src/components/colorpicker/colorpicker.ts +57 -11
- package/src/components/components.ts +1 -0
- package/src/components/dialog/dialog.ts +16 -5
- package/src/components/form/form.ts +3 -4
- package/src/components/gridview/gridview.module.scss +18 -16
- package/src/components/gridview/gridview.ts +5 -0
- package/src/components/icon/icon.ts +34 -18
- package/src/components/keyboard/keyboard.ts +31 -5
- package/src/components/link/link.ts +18 -7
- package/src/components/messages/messages.ts +1 -1
- package/src/components/panel/panel.ts +3 -2
- package/src/components/settingsview/settingsview.module.scss +178 -0
- package/src/components/settingsview/settingsview.ts +289 -0
- package/src/components/spreadsheet/spreadsheet.module.scss +18 -16
- package/src/components/textarea/textarea.module.scss +10 -3
- package/src/components/video/video.ts +17 -3
- package/src/core/core_colors.ts +21 -10
- package/src/core/core_dragdrop.ts +5 -4
- package/src/core/core_i18n.ts +191 -54
- package/src/core/core_pdf.ts +15 -3
- package/src/core/core_shortcuts.ts +5 -1
- package/src/core/core_styles.ts +46 -25
- package/src/core/core_svg.ts +24 -16
- package/src/core/core_tools.ts +18 -9
|
@@ -30,6 +30,9 @@ export interface ColorPickerProps extends ComponentProps {
|
|
|
30
30
|
|
|
31
31
|
/** Adds a "no color" swatch: picking it fires `change` with a null color. */
|
|
32
32
|
nullable?: boolean;
|
|
33
|
+
|
|
34
|
+
/** false: the colors are opaque, there is no alpha slider (default true). */
|
|
35
|
+
alpha?: boolean;
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
interface HueChangeEvent extends ComponentEvent {
|
|
@@ -83,13 +86,17 @@ export class Saturation extends Box<BoxProps,CommonEvents> {
|
|
|
83
86
|
created: () => this.updateThumbMarker( ),
|
|
84
87
|
} );
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
// the color at start: its hue, and the thumb on its saturation and value
|
|
90
|
+
this.setColor( init );
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
mousedown( ev: PointerEvent ) {
|
|
90
94
|
this.mdown = true;
|
|
91
95
|
this.irect = this.getBoundingRect( );
|
|
92
96
|
this.setCapture( ev.pointerId );
|
|
97
|
+
|
|
98
|
+
// a click takes the point too, without a move
|
|
99
|
+
this.mousemove( ev );
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
mousemove( ev: PointerEvent ) {
|
|
@@ -213,6 +220,9 @@ class HueSlider extends Box<BoxProps,CommonEvents> {
|
|
|
213
220
|
this.mdown = true;
|
|
214
221
|
this.irect = this.getBoundingRect( );
|
|
215
222
|
this.setCapture( ev.pointerId );
|
|
223
|
+
|
|
224
|
+
// a click takes the point too, without a move
|
|
225
|
+
this.mousemove( ev );
|
|
216
226
|
}
|
|
217
227
|
|
|
218
228
|
mousemove( ev: PointerEvent ) {
|
|
@@ -286,14 +296,17 @@ class AlphaSlider extends Box<BoxProps,CommonEvents> {
|
|
|
286
296
|
pointerup: ( e ) => this._on_mouseup( e ),
|
|
287
297
|
} );
|
|
288
298
|
|
|
289
|
-
|
|
290
|
-
this.
|
|
299
|
+
// the color at start: its gradient, and the thumb on its alpha
|
|
300
|
+
this.setColor( init );
|
|
291
301
|
}
|
|
292
302
|
|
|
293
303
|
_on_mousedown( ev: PointerEvent ) {
|
|
294
304
|
this.mdown = true;
|
|
295
305
|
this.irect = this.getBoundingRect( );
|
|
296
306
|
this.setCapture( ev.pointerId );
|
|
307
|
+
|
|
308
|
+
// a click takes the point too, without a move
|
|
309
|
+
this._on_mousemove( ev );
|
|
297
310
|
}
|
|
298
311
|
|
|
299
312
|
_on_mousemove( ev: PointerEvent ) {
|
|
@@ -370,7 +383,10 @@ interface ColorPickerChangeEvents extends ComponentEvents {
|
|
|
370
383
|
}
|
|
371
384
|
|
|
372
385
|
/**
|
|
373
|
-
*
|
|
386
|
+
* @cssvar
|
|
387
|
+
* ```
|
|
388
|
+
* --colorpicker-none
|
|
389
|
+
* ```
|
|
374
390
|
*/
|
|
375
391
|
|
|
376
392
|
@class_ns( "x4" )
|
|
@@ -395,6 +411,11 @@ export class ColorPicker extends VBox<ColorPickerProps,ColorPickerChangeEvents>
|
|
|
395
411
|
this._base = new Color( props.color );
|
|
396
412
|
}
|
|
397
413
|
|
|
414
|
+
// no alpha: the color is opaque
|
|
415
|
+
if( props.alpha===false ) {
|
|
416
|
+
this._base.setAlpha( 1 );
|
|
417
|
+
}
|
|
418
|
+
|
|
398
419
|
const hsv = this._hsv = this._base.toHsv( );
|
|
399
420
|
|
|
400
421
|
this.setAttribute( "tabindex", 0 );
|
|
@@ -417,6 +438,8 @@ export class ColorPicker extends VBox<ColorPickerProps,ColorPickerChangeEvents>
|
|
|
417
438
|
this._swatches = new HBox( { cls: "swatches" } ),
|
|
418
439
|
]);
|
|
419
440
|
|
|
441
|
+
this._alpha.show( props.alpha!==false );
|
|
442
|
+
|
|
420
443
|
this._sat.on( "sat_change", ( ev ) => {
|
|
421
444
|
this._hsv.saturation = ev.saturation;
|
|
422
445
|
this._hsv.value = ev.value;
|
|
@@ -460,14 +483,21 @@ export class ColorPicker extends VBox<ColorPickerProps,ColorPickerChangeEvents>
|
|
|
460
483
|
private _changed( ) {
|
|
461
484
|
const hsv = this._hsv;
|
|
462
485
|
|
|
463
|
-
|
|
486
|
+
// no alpha: the hidden slider can still be moved by the keys, the color stays opaque
|
|
487
|
+
let alpha = hsv.alpha;
|
|
488
|
+
if( this.props.alpha===false ) {
|
|
489
|
+
alpha = 1;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
this._base.setHsv( hsv.hue, hsv.saturation, hsv.value, alpha );
|
|
464
493
|
this._refresh( );
|
|
465
494
|
this._notify( );
|
|
466
495
|
}
|
|
467
496
|
|
|
468
497
|
private _refresh( ) {
|
|
469
|
-
|
|
470
|
-
this._swatch.
|
|
498
|
+
// with its alpha: the swatch is drawn over checkers
|
|
499
|
+
this._swatch.setStyleValue( "backgroundColor", this._base.toRgbString( true ) );
|
|
500
|
+
this._swatch.setAttribute( "tooltip", this._base.toRgbString( true ) );
|
|
471
501
|
}
|
|
472
502
|
|
|
473
503
|
private _notify( ) {
|
|
@@ -499,8 +529,13 @@ export class ColorPicker extends VBox<ColorPickerProps,ColorPickerChangeEvents>
|
|
|
499
529
|
setColor( color: Color | string ) {
|
|
500
530
|
const rgb = ( color instanceof Color ? color : new Color( color ) ).toRgb( );
|
|
501
531
|
|
|
532
|
+
let alpha = rgb.alpha;
|
|
533
|
+
if( this.props.alpha===false ) {
|
|
534
|
+
alpha = 1;
|
|
535
|
+
}
|
|
536
|
+
|
|
502
537
|
// the color itself is kept as given: going through hsv could shift it
|
|
503
|
-
this._base.setRgb( rgb.red, rgb.green, rgb.blue,
|
|
538
|
+
this._base.setRgb( rgb.red, rgb.green, rgb.blue, alpha );
|
|
504
539
|
|
|
505
540
|
const hsv = this._base.toHsv( );
|
|
506
541
|
this._hsv.hue = hsv.hue;
|
|
@@ -538,14 +573,17 @@ export class ColorPicker extends VBox<ColorPickerProps,ColorPickerChangeEvents>
|
|
|
538
573
|
continue;
|
|
539
574
|
}
|
|
540
575
|
|
|
541
|
-
|
|
576
|
+
const item = new Component( {
|
|
542
577
|
cls: "item",
|
|
543
578
|
tooltip: color.toHexString( ),
|
|
544
|
-
style: { backgroundColor: color.toRgbString( ) },
|
|
545
579
|
dom_events: {
|
|
546
580
|
click: ( ) => this._pick( color ),
|
|
547
581
|
},
|
|
548
|
-
} )
|
|
582
|
+
} );
|
|
583
|
+
|
|
584
|
+
// as it is taken: opaque without alpha; the stylesheet draws it over checkers
|
|
585
|
+
item.setStyleVariable( "--swatch-color", color.toRgbString( this.props.alpha!==false ) );
|
|
586
|
+
items.push( item );
|
|
549
587
|
}
|
|
550
588
|
|
|
551
589
|
this._swatches.setContent( items );
|
|
@@ -593,6 +631,14 @@ export class ColorPicker extends VBox<ColorPickerProps,ColorPickerChangeEvents>
|
|
|
593
631
|
}
|
|
594
632
|
break;
|
|
595
633
|
}
|
|
634
|
+
|
|
635
|
+
default: {
|
|
636
|
+
// not for the picker: Tab, Escape... go on
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
596
639
|
}
|
|
640
|
+
|
|
641
|
+
// the arrows move the picker, not the page
|
|
642
|
+
ev.preventDefault( );
|
|
597
643
|
}
|
|
598
644
|
}
|
|
@@ -35,6 +35,7 @@ export * from "./propgrid/propgrid"
|
|
|
35
35
|
export * from "./radio/radio"
|
|
36
36
|
export * from "./rating/rating"
|
|
37
37
|
export * from "./select/select"
|
|
38
|
+
export * from "./settingsview/settingsview"
|
|
38
39
|
export * from "./sizers/sizer"
|
|
39
40
|
export * from "./slider/slider"
|
|
40
41
|
export * from "./spreadsheet/spreadsheet"
|
|
@@ -64,7 +64,8 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogEvents
|
|
|
64
64
|
private _title: Label;
|
|
65
65
|
|
|
66
66
|
constructor(props: P) {
|
|
67
|
-
|
|
67
|
+
// content is the content of its form
|
|
68
|
+
super({ tag: "dialog", modal: true, ...props, content: undefined });
|
|
68
69
|
|
|
69
70
|
this._ismodal = this.props.modal;
|
|
70
71
|
|
|
@@ -95,7 +96,7 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogEvents
|
|
|
95
96
|
}) : null,
|
|
96
97
|
]
|
|
97
98
|
}),
|
|
98
|
-
this.form = props.form ? props.form : new Form({}),
|
|
99
|
+
this.form = props.form ? props.form : new Form({ content: props.content }),
|
|
99
100
|
new BtnGroup({
|
|
100
101
|
id: "btnbar",
|
|
101
102
|
reverse: true,
|
|
@@ -133,9 +134,19 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogEvents
|
|
|
133
134
|
}
|
|
134
135
|
})
|
|
135
136
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* each time it opens: the focus on its first field
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
override show( show = true ): this {
|
|
144
|
+
super.show( show );
|
|
145
|
+
if( show ) {
|
|
146
|
+
asap( ( ) => this.focusNext( true ) );
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return this;
|
|
139
150
|
}
|
|
140
151
|
|
|
141
152
|
private focusNext( next: boolean) : boolean {
|
|
@@ -105,10 +105,9 @@ export class Form<P extends FormProps = FormProps> extends Box<P> {
|
|
|
105
105
|
*/
|
|
106
106
|
|
|
107
107
|
setAutoComplete( on = true ) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
} );
|
|
108
|
+
// on the <form>: its fields without an autocomplete of their own follow it,
|
|
109
|
+
// those added later too
|
|
110
|
+
this.setAttribute( "autocomplete", on ? "on" : "off" );
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
/**
|
|
@@ -16,31 +16,32 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
:root {
|
|
19
|
-
--
|
|
19
|
+
// from the theme: a dark theme (its scale --color-primary-* reversed) gives a dark grid
|
|
20
|
+
--gridview-background: var( --background-primary );
|
|
20
21
|
--gridview-border: var( --border );
|
|
21
22
|
|
|
22
|
-
--gridview-header-cell-background:
|
|
23
|
-
--gridview-header-cell-color:
|
|
24
|
-
--gridview-header-cell-vline:
|
|
25
|
-
--gridview-header-cell-border:
|
|
23
|
+
--gridview-header-cell-background: var( --background-primary );
|
|
24
|
+
--gridview-header-cell-color: var( --text-primary );
|
|
25
|
+
--gridview-header-cell-vline: var( --border );
|
|
26
|
+
--gridview-header-cell-border: var( --border );
|
|
26
27
|
|
|
27
28
|
--grid-check-background: var( --accent-background );
|
|
28
|
-
--grid-check-color:
|
|
29
|
-
--grid-check-background-hover:
|
|
29
|
+
--grid-check-color: var( --accent-color );
|
|
30
|
+
--grid-check-background-hover: var( --background-primary );
|
|
30
31
|
--grid-check-color-hover: var( --accent-background );
|
|
31
32
|
|
|
32
33
|
--grid-perc-background: var( --accent-background );
|
|
33
|
-
--grid-perc-color:
|
|
34
|
-
--grid-perc-background-hover:
|
|
34
|
+
--grid-perc-color: var( --accent-color );
|
|
35
|
+
--grid-perc-background-hover: var( --background-primary );
|
|
35
36
|
--grid-perc-color-hover: var( --accent-background );
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
--gridview-cell-color:
|
|
39
|
-
--gridview-cell-color-sel:
|
|
39
|
+
--gridview-cell-color: var( --text-primary );
|
|
40
|
+
--gridview-cell-color-sel: var( --accent-color );
|
|
40
41
|
--gridview-cell-vline: var( --border );
|
|
41
42
|
|
|
42
|
-
--gridview-row-background:
|
|
43
|
-
--gridview-row-odd-background:
|
|
43
|
+
--gridview-row-background: var( --background-primary );
|
|
44
|
+
--gridview-row-odd-background: var( --background-primary );
|
|
44
45
|
--gridview-row-border: var( --border );
|
|
45
46
|
|
|
46
47
|
--gridview-row-background-hover: var( --background-secondary );
|
|
@@ -71,6 +72,7 @@
|
|
|
71
72
|
|
|
72
73
|
background-color: var( --gridview-background );
|
|
73
74
|
border: 1px solid var( --gridview-border );
|
|
75
|
+
color: var( --gridview-cell-color );
|
|
74
76
|
|
|
75
77
|
.cell {
|
|
76
78
|
padding: 4px;
|
|
@@ -159,7 +161,7 @@
|
|
|
159
161
|
width: 100%;
|
|
160
162
|
border: 1px solid var( --border );
|
|
161
163
|
height: 8px;
|
|
162
|
-
background-color:
|
|
164
|
+
background-color: var( --gridview-background );
|
|
163
165
|
overflow: hidden;
|
|
164
166
|
|
|
165
167
|
div {
|
|
@@ -219,7 +221,7 @@
|
|
|
219
221
|
display: inline-flex;
|
|
220
222
|
align-items: center;
|
|
221
223
|
|
|
222
|
-
color:
|
|
224
|
+
color: var( --gridview-header-cell-color );
|
|
223
225
|
font-weight: 500;
|
|
224
226
|
justify-content: center;
|
|
225
227
|
|
|
@@ -320,7 +322,7 @@
|
|
|
320
322
|
width: var( --fixed-width );
|
|
321
323
|
bottom: 0;
|
|
322
324
|
|
|
323
|
-
background-color:
|
|
325
|
+
background-color: var( --gridview-background );
|
|
324
326
|
z-index: 1;
|
|
325
327
|
|
|
326
328
|
.row {
|
|
@@ -559,6 +559,11 @@ export class Gridview<P extends GridviewProps = GridviewProps, E extends Gridvie
|
|
|
559
559
|
|
|
560
560
|
private _scrollToIndex( index: number, block = 'nearest' ) {
|
|
561
561
|
|
|
562
|
+
// not built yet: nothing to scroll
|
|
563
|
+
if( !this._viewport ) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
|
|
562
567
|
// is it already visible ?
|
|
563
568
|
let rows = this.queryAll(`.row[data-row="${index}"]`);
|
|
564
569
|
if (rows.length) {
|
|
@@ -27,7 +27,7 @@ type solveCallback = (data:string)=>void;
|
|
|
27
27
|
|
|
28
28
|
class SvgLoader {
|
|
29
29
|
private cache: Map<string,string>;
|
|
30
|
-
private waiters: Map<string,solveCallback[]>;
|
|
30
|
+
private waiters: Map<string,{ resolve: solveCallback, reject: ( e: any ) => void }[]>;
|
|
31
31
|
|
|
32
32
|
constructor( ) {
|
|
33
33
|
this.cache = new Map( );
|
|
@@ -37,26 +37,35 @@ class SvgLoader {
|
|
|
37
37
|
async load( file: string ): Promise<string> {
|
|
38
38
|
|
|
39
39
|
if( this.cache.has(file) ) {
|
|
40
|
-
|
|
40
|
+
// null: the file was not found, it is not asked again
|
|
41
|
+
const svg = this.cache.get( file );
|
|
42
|
+
if( svg===null ) {
|
|
43
|
+
return Promise.reject( new Error( `file not found: ${file}` ) );
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return Promise.resolve( svg );
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
return new Promise( (resolve,reject) => {
|
|
50
|
+
// already asked: the same answer
|
|
44
51
|
if( this.waiters.has(file) ) {
|
|
45
|
-
this.waiters.get(file).push( resolve );
|
|
46
|
-
|
|
47
|
-
else {
|
|
48
|
-
this.waiters.set( file, [resolve] );
|
|
49
|
-
this._load( file )
|
|
50
|
-
.then( ( data: string ) => {
|
|
51
|
-
this.cache.set( file, data );
|
|
52
|
-
const ww = this.waiters.get( file );
|
|
53
|
-
ww.forEach( cb => cb(data ) );
|
|
54
|
-
})
|
|
55
|
-
.catch( e => {
|
|
56
|
-
this.cache.set( file, null );
|
|
57
|
-
reject( e );
|
|
58
|
-
} )
|
|
52
|
+
this.waiters.get(file).push( { resolve, reject } );
|
|
53
|
+
return;
|
|
59
54
|
}
|
|
55
|
+
|
|
56
|
+
this.waiters.set( file, [{ resolve, reject }] );
|
|
57
|
+
this._load( file )
|
|
58
|
+
.then( ( data: string ) => {
|
|
59
|
+
this.cache.set( file, data );
|
|
60
|
+
this.waiters.get( file ).forEach( w => w.resolve( data ) );
|
|
61
|
+
this.waiters.delete( file );
|
|
62
|
+
})
|
|
63
|
+
.catch( e => {
|
|
64
|
+
// kept as not found: it is not asked again
|
|
65
|
+
this.cache.set( file, null );
|
|
66
|
+
this.waiters.get( file ).forEach( w => w.reject( e ) );
|
|
67
|
+
this.waiters.delete( file );
|
|
68
|
+
} );
|
|
60
69
|
});
|
|
61
70
|
}
|
|
62
71
|
|
|
@@ -83,6 +92,8 @@ export interface IconProps extends ComponentProps {
|
|
|
83
92
|
/**
|
|
84
93
|
* Identifier for the icon.
|
|
85
94
|
* Can be a URL, a CSS variable (prefixed with `var:`), or inline SVG data.
|
|
95
|
+
* `var:home` (or `var:--home`) is the variable --home set on <html> by the code:
|
|
96
|
+
* document.documentElement.style.setProperty( "--home", svg ).
|
|
86
97
|
* @example
|
|
87
98
|
* // Using a CSS variable
|
|
88
99
|
* { iconId: "var:home" }
|
|
@@ -139,8 +150,13 @@ export class Icon extends Component<IconProps> {
|
|
|
139
150
|
if( iconId ) {
|
|
140
151
|
if( iconId.startsWith('var:') ) {
|
|
141
152
|
do {
|
|
142
|
-
|
|
143
|
-
|
|
153
|
+
// "var:home" or "var:--home": the variable --home, set on <html>
|
|
154
|
+
let name = iconId.substring( 4 );
|
|
155
|
+
if( !name.startsWith( "--" ) ) {
|
|
156
|
+
name = "--" + name;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
iconId = document.documentElement.style.getPropertyValue( name );
|
|
144
160
|
} while( iconId.startsWith('var:') );
|
|
145
161
|
}
|
|
146
162
|
|
|
@@ -239,6 +239,14 @@ function accentLabel( layout: KbLayout, upper: boolean ): string {
|
|
|
239
239
|
return ( upper ? upperKeys( label ) : label ).replace( " ", "" );
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/**
|
|
243
|
+
* the keys that draw the keyboard again: shift, 123, abc, accents, signs
|
|
244
|
+
*/
|
|
245
|
+
|
|
246
|
+
function redrawKey( key: number ) {
|
|
247
|
+
return key==4 || key==5 || key==8 || key==10 || key==11;
|
|
248
|
+
}
|
|
249
|
+
|
|
242
250
|
|
|
243
251
|
const RE_sel = /text|password|search|tel|url/i;
|
|
244
252
|
|
|
@@ -248,6 +256,12 @@ interface KeyboardProps extends BoxProps {
|
|
|
248
256
|
* "de-CH", "pl"... "fr-FR" when it is not given
|
|
249
257
|
*/
|
|
250
258
|
locale?: string;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* on a number or date field, the keyboard stays on the pad: no "abc" key
|
|
262
|
+
* back to the letters. The other fields keep all the keys.
|
|
263
|
+
*/
|
|
264
|
+
numpadOnly?: boolean;
|
|
251
265
|
}
|
|
252
266
|
|
|
253
267
|
/**
|
|
@@ -284,15 +298,20 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
284
298
|
|
|
285
299
|
this.hide( );
|
|
286
300
|
|
|
301
|
+
// a key: each contact, a finger or the mouse, the second tap of a quick double tap too.
|
|
302
|
+
// not the keys that draw the keyboard again, they act on the click
|
|
303
|
+
this.addDOMEvent( "pointerdown", (e) => {
|
|
304
|
+
this.handleKeyEvent( e );
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// the focus stays in the field
|
|
287
308
|
this.addDOMEvent( "mousedown", (e) => {
|
|
288
|
-
this.handleKeyEvent( e );
|
|
289
309
|
e.preventDefault( );
|
|
290
310
|
e.stopPropagation( );
|
|
291
311
|
});
|
|
292
312
|
|
|
293
|
-
//
|
|
313
|
+
// a double click or a double tap: its two pointerdown gave the two keys
|
|
294
314
|
this.addDOMEvent( "dblclick", (e) => {
|
|
295
|
-
this.handleKeyEvent( e );
|
|
296
315
|
e.preventDefault( );
|
|
297
316
|
e.stopPropagation( );
|
|
298
317
|
});
|
|
@@ -348,7 +367,7 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
348
367
|
target = target.parentNode as HTMLElement;
|
|
349
368
|
}
|
|
350
369
|
|
|
351
|
-
if( !key ) {
|
|
370
|
+
if( !key || redrawKey( key ) ) {
|
|
352
371
|
return;
|
|
353
372
|
}
|
|
354
373
|
|
|
@@ -627,6 +646,11 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
627
646
|
|
|
628
647
|
if( this.mode=="number" || this.mode=="date" ) {
|
|
629
648
|
lines = kb_pads[this.mode];
|
|
649
|
+
|
|
650
|
+
// no key back to the letters: its place stays empty
|
|
651
|
+
if( this.props.numpadOnly ) {
|
|
652
|
+
lines = lines.map( line => line.replace( "{8}", "{9}" ) );
|
|
653
|
+
}
|
|
630
654
|
}
|
|
631
655
|
else if( this.mode=="accents" ) {
|
|
632
656
|
lines = accentLines( layout, this.upper );
|
|
@@ -761,7 +785,9 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
761
785
|
icon,
|
|
762
786
|
autorepeat: repeat,
|
|
763
787
|
click: ( e ) => {
|
|
764
|
-
|
|
788
|
+
// the keys that draw the keyboard again act on the click: the mousedown
|
|
789
|
+
// that follows a pointerdown would go to a key no longer in the page
|
|
790
|
+
if( e.repeat || redrawKey( key ) ) {
|
|
765
791
|
this._handleKey( key )
|
|
766
792
|
}
|
|
767
793
|
}
|
|
@@ -56,11 +56,14 @@ export class Link extends Component<LinkProps,LinkEvents> {
|
|
|
56
56
|
|
|
57
57
|
this.mapPropEvents( props, "click" );
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
// content given: it is the link; else a label (icon and text)
|
|
60
|
+
if( props.content===undefined ) {
|
|
61
|
+
this.setContent( new Label( {
|
|
62
|
+
text: props.text,
|
|
63
|
+
icon: props.icon,
|
|
64
|
+
align: props.align,
|
|
65
|
+
} ) );
|
|
66
|
+
}
|
|
64
67
|
|
|
65
68
|
this.addDOMEvent('click', (e) => this._on_click(e));
|
|
66
69
|
}
|
|
@@ -71,7 +74,14 @@ export class Link extends Component<LinkProps,LinkEvents> {
|
|
|
71
74
|
*/
|
|
72
75
|
|
|
73
76
|
setText( text: string | UnsafeHtml ) {
|
|
74
|
-
|
|
77
|
+
// the text of the label: its icon and alignment stay
|
|
78
|
+
const label = this.query<Label>( ":scope > .x4label" );
|
|
79
|
+
if( label ) {
|
|
80
|
+
label.setText( text );
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.setContent( text );
|
|
84
|
+
}
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
/**
|
|
@@ -83,7 +93,8 @@ export class Link extends Component<LinkProps,LinkEvents> {
|
|
|
83
93
|
const xev: EvClick = {context: this.props.href };
|
|
84
94
|
this.fire('click', xev );
|
|
85
95
|
|
|
86
|
-
|
|
96
|
+
// the handler called ev.preventDefault( ): the link is not followed
|
|
97
|
+
if( xev.defaultPrevented ) {
|
|
87
98
|
ev.preventDefault();
|
|
88
99
|
ev.stopPropagation();
|
|
89
100
|
}
|
|
@@ -39,7 +39,7 @@ interface PanelProps extends ComponentProps {
|
|
|
39
39
|
@class_ns( "x4" )
|
|
40
40
|
export class Panel extends VBox<PanelProps> {
|
|
41
41
|
|
|
42
|
-
private _title:
|
|
42
|
+
private _title: Label;
|
|
43
43
|
private _body: Component;
|
|
44
44
|
|
|
45
45
|
constructor( props: PanelProps ) {
|
|
@@ -57,6 +57,7 @@ export class Panel extends VBox<PanelProps> {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
setTitle( title: string | UnsafeHtml ) {
|
|
60
|
-
|
|
60
|
+
// the text of the label: its icon stays
|
|
61
|
+
this._title.setText( title );
|
|
61
62
|
}
|
|
62
63
|
}
|