x4js 2.3.19 → 2.3.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.
- package/aicontext.md +48 -28
- 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/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 +7 -3
- 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/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 +34 -54
- package/src/core/core_pdf.ts +524 -8
- 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
|
@@ -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
|
|
|
@@ -284,15 +284,19 @@ export class Keyboard extends HBox<KeyboardProps>
|
|
|
284
284
|
|
|
285
285
|
this.hide( );
|
|
286
286
|
|
|
287
|
+
// a key: each contact, a finger or the mouse, the second tap of a quick double tap too
|
|
288
|
+
this.addDOMEvent( "pointerdown", (e) => {
|
|
289
|
+
this.handleKeyEvent( e );
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// the focus stays in the field
|
|
287
293
|
this.addDOMEvent( "mousedown", (e) => {
|
|
288
|
-
this.handleKeyEvent( e );
|
|
289
294
|
e.preventDefault( );
|
|
290
295
|
e.stopPropagation( );
|
|
291
296
|
});
|
|
292
297
|
|
|
293
|
-
//
|
|
298
|
+
// a double click or a double tap: its two pointerdown gave the two keys
|
|
294
299
|
this.addDOMEvent( "dblclick", (e) => {
|
|
295
|
-
this.handleKeyEvent( e );
|
|
296
300
|
e.preventDefault( );
|
|
297
301
|
e.stopPropagation( );
|
|
298
302
|
});
|
|
@@ -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
|
}
|
|
@@ -16,30 +16,31 @@
|
|
|
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
|
+
--spreadsheet-background: var( --background-primary );
|
|
20
21
|
--spreadsheet-border: var( --border );
|
|
21
22
|
|
|
22
|
-
--spreadsheet-header-cell-background:
|
|
23
|
-
--spreadsheet-header-cell-color:
|
|
24
|
-
--spreadsheet-header-cell-vline:
|
|
25
|
-
--spreadsheet-header-cell-border:
|
|
23
|
+
--spreadsheet-header-cell-background: var( --background-primary );
|
|
24
|
+
--spreadsheet-header-cell-color: var( --text-primary );
|
|
25
|
+
--spreadsheet-header-cell-vline: var( --border );
|
|
26
|
+
--spreadsheet-header-cell-border: var( --border );
|
|
26
27
|
|
|
27
28
|
--spreadsheet-check-background: var( --accent-background );
|
|
28
|
-
--spreadsheet-check-color:
|
|
29
|
-
--spreadsheet-check-background-hover:
|
|
29
|
+
--spreadsheet-check-color: var( --accent-color );
|
|
30
|
+
--spreadsheet-check-background-hover: var( --background-primary );
|
|
30
31
|
--spreadsheet-check-color-hover: var( --accent-background );
|
|
31
32
|
|
|
32
33
|
--spreadsheet-perc-background: var( --accent-background );
|
|
33
|
-
--spreadsheet-perc-color:
|
|
34
|
-
--spreadsheet-perc-background-hover:
|
|
34
|
+
--spreadsheet-perc-color: var( --accent-color );
|
|
35
|
+
--spreadsheet-perc-background-hover: var( --background-primary );
|
|
35
36
|
--spreadsheet-perc-color-hover: var( --accent-background );
|
|
36
37
|
|
|
37
|
-
--spreadsheet-cell-color:
|
|
38
|
-
--spreadsheet-cell-color-sel:
|
|
38
|
+
--spreadsheet-cell-color: var( --text-primary );
|
|
39
|
+
--spreadsheet-cell-color-sel: var( --accent-color );
|
|
39
40
|
--spreadsheet-cell-vline: var( --border );
|
|
40
41
|
|
|
41
|
-
--spreadsheet-row-background:
|
|
42
|
-
--spreadsheet-row-odd-background:
|
|
42
|
+
--spreadsheet-row-background: var( --background-primary );
|
|
43
|
+
--spreadsheet-row-odd-background: var( --background-primary );
|
|
43
44
|
--spreadsheet-row-border: var( --border );
|
|
44
45
|
|
|
45
46
|
--spreadsheet-row-background-hover: var( --background-secondary );
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
|
|
71
72
|
background-color: var( --spreadsheet-background );
|
|
72
73
|
border: 1px solid var( --spreadsheet-border );
|
|
74
|
+
color: var( --spreadsheet-cell-color );
|
|
73
75
|
|
|
74
76
|
.cell {
|
|
75
77
|
padding: 4px;
|
|
@@ -180,7 +182,7 @@
|
|
|
180
182
|
width: 100%;
|
|
181
183
|
border: 1px solid var( --border );
|
|
182
184
|
height: 8px;
|
|
183
|
-
background-color:
|
|
185
|
+
background-color: var( --spreadsheet-background );
|
|
184
186
|
overflow: hidden;
|
|
185
187
|
|
|
186
188
|
div {
|
|
@@ -234,7 +236,7 @@
|
|
|
234
236
|
display: inline-flex;
|
|
235
237
|
align-items: center;
|
|
236
238
|
|
|
237
|
-
color:
|
|
239
|
+
color: var( --spreadsheet-header-cell-color );
|
|
238
240
|
font-weight: 500;
|
|
239
241
|
justify-content: center;
|
|
240
242
|
|
|
@@ -307,7 +309,7 @@
|
|
|
307
309
|
width: var( --fixed-width );
|
|
308
310
|
bottom: 0;
|
|
309
311
|
|
|
310
|
-
background-color:
|
|
312
|
+
background-color: var( --spreadsheet-background );
|
|
311
313
|
z-index: 1;
|
|
312
314
|
|
|
313
315
|
.row {
|
|
@@ -27,6 +27,12 @@
|
|
|
27
27
|
flex-shrink: 0; // alone in a box, it keeps its height: the box does not crush it
|
|
28
28
|
resize: none; // no handle unless the prop resize asks for one
|
|
29
29
|
padding: 4px;
|
|
30
|
+
|
|
31
|
+
// never smaller than one character, its padding and border included (border-box):
|
|
32
|
+
// 10px = 2 x 4px of padding + 2 x 1px of border
|
|
33
|
+
min-height: calc( 1lh + 10px );
|
|
34
|
+
min-width: calc( 1ch + 10px );
|
|
35
|
+
|
|
30
36
|
outline: none;
|
|
31
37
|
font: inherit;
|
|
32
38
|
|
|
@@ -65,7 +71,8 @@
|
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
.x4simpletextarea {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
// its height of rows when the TextArea has none, the TextArea's height when it has one;
|
|
75
|
+
// a basis of 0 would leave it the height of its padding: a textarea scrolls, its min-height is 0
|
|
76
|
+
flex: 1 0 auto;
|
|
77
|
+
}
|
|
71
78
|
}
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { Component, ComponentProps } from '../../core/component';
|
|
18
|
+
import { class_ns } from '../../core/core_tools';
|
|
19
|
+
import { Box } from '../boxes/boxes';
|
|
18
20
|
|
|
19
21
|
import "./video.module.scss"
|
|
20
22
|
|
|
@@ -29,6 +31,7 @@ interface VideoProps extends ComponentProps {
|
|
|
29
31
|
*
|
|
30
32
|
*/
|
|
31
33
|
|
|
34
|
+
@class_ns( "x4" )
|
|
32
35
|
export class Video extends Box {
|
|
33
36
|
|
|
34
37
|
private _vplayer: HTMLVideoElement;
|
|
@@ -124,7 +127,18 @@ export class Video extends Box {
|
|
|
124
127
|
this.player.pause( );
|
|
125
128
|
}
|
|
126
129
|
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
/**
|
|
131
|
+
* @returns false when the playback could not start: the browser wants a click
|
|
132
|
+
* of the user first, or the source cannot be played
|
|
133
|
+
*/
|
|
134
|
+
|
|
135
|
+
async play( ): Promise<boolean> {
|
|
136
|
+
try {
|
|
137
|
+
await this.player.play( );
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
catch( e ) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
129
143
|
}
|
|
130
144
|
}
|
package/src/core/core_colors.ts
CHANGED
|
@@ -83,8 +83,6 @@ export class Color {
|
|
|
83
83
|
|
|
84
84
|
setValue(value: string): this {
|
|
85
85
|
|
|
86
|
-
this.invalid = false;
|
|
87
|
-
|
|
88
86
|
if( value.startsWith('#') ) {
|
|
89
87
|
if (value.length == 7 && /#[0-9a-fA-F]{6}/.test(value)) {
|
|
90
88
|
const hex = parseInt(value.slice(1), 16);
|
|
@@ -139,8 +137,10 @@ export class Color {
|
|
|
139
137
|
}
|
|
140
138
|
}
|
|
141
139
|
|
|
140
|
+
// red, to be seen, and marked as invalid
|
|
141
|
+
this.setRgb(255, 0, 0, 1);
|
|
142
142
|
this.invalid = true;
|
|
143
|
-
return this
|
|
143
|
+
return this;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
/**
|
|
@@ -205,23 +205,34 @@ export class Color {
|
|
|
205
205
|
* @param r - Red component (0-255).
|
|
206
206
|
* @param g - Green component (0-255).
|
|
207
207
|
* @param b - Blue component (0-255).
|
|
208
|
-
* @param a - Alpha component (0-1).
|
|
208
|
+
* @param a - Alpha component (0-1, default 1.0).
|
|
209
209
|
* @returns The current Color instance.
|
|
210
210
|
*/
|
|
211
|
-
setRgb(r: number, g: number, b: number, a
|
|
212
|
-
|
|
211
|
+
setRgb(r: number, g: number, b: number, a = 1.0): this {
|
|
212
|
+
// a new color: valid
|
|
213
|
+
this.invalid = false;
|
|
214
|
+
// rounded: hsv gives 123.999 for 124; "| 0" makes a NaN 0
|
|
215
|
+
const c = ( v: number ) => clamp( Math.round( v ) | 0, 0, 255 );
|
|
216
|
+
this.rgb = [c(r), c(g), c(b), clamp(a, 0, 1)];
|
|
213
217
|
return this;
|
|
214
218
|
}
|
|
215
219
|
|
|
216
220
|
/**
|
|
217
221
|
* Returns the CSS string representation of the color.
|
|
218
222
|
*
|
|
219
|
-
* @param withAlpha -
|
|
220
|
-
* @returns The CSS color string (e.g. "rgb(255,0,0)" or "rgba(255,0,0,0.
|
|
223
|
+
* @param withAlpha - false (default): never the alpha; true: the alpha when the color is not opaque.
|
|
224
|
+
* @returns The CSS color string (e.g. "rgb(255,0,0)" or "rgba(255,0,0,0.500)").
|
|
221
225
|
*/
|
|
222
|
-
toRgbString(withAlpha
|
|
226
|
+
toRgbString(withAlpha = false): string {
|
|
223
227
|
const _ = this.rgb;
|
|
224
|
-
|
|
228
|
+
const rgb = `${round(_[0])},${round(_[1])},${round(_[2])}`;
|
|
229
|
+
|
|
230
|
+
// an opaque color has no alpha to show
|
|
231
|
+
if( !withAlpha || _[3] >= 1 ) {
|
|
232
|
+
return `rgb(${rgb})`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return `rgba(${rgb},${_[3].toFixed(3)})`;
|
|
225
236
|
}
|
|
226
237
|
|
|
227
238
|
/**
|
|
@@ -175,12 +175,13 @@ class DragManager {
|
|
|
175
175
|
*/
|
|
176
176
|
|
|
177
177
|
private _startCheck() {
|
|
178
|
+
clearInterval( this.timer );
|
|
178
179
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
this._check( );
|
|
182
|
-
}
|
|
180
|
+
// the target is told at once (and the one that was left)
|
|
181
|
+
this._check( );
|
|
183
182
|
|
|
183
|
+
// then checked again: over the children of a target, dragleave and dragover come
|
|
184
|
+
// in turn; it is left when no dragover came back in between
|
|
184
185
|
this.timer = setInterval( () => this._check(), 300 );
|
|
185
186
|
}
|
|
186
187
|
|