x4js 2.3.17 → 2.3.19
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/aicli.md +3 -3
- package/aicontext.md +211 -47
- package/cli/config.mjs +14 -7
- package/cli/copy-plugin.mjs +8 -0
- package/cli/create.mjs +8 -2
- package/cli/dev.mjs +4 -1
- package/cli/less-plugin.mjs +5 -1
- package/cli/main.mjs +15 -5
- package/cli/rawfile-plugin.mjs +23 -3
- package/cli/templates.mjs +5 -1
- package/package.json +1 -1
- package/src/components/calendar/calendar.module.scss +16 -1
- package/src/components/calendar/calendar.ts +52 -9
- package/src/components/checkbox/checkbox.ts +1 -0
- package/src/components/combobox/combobox.ts +51 -23
- package/src/components/dialog/dialog.ts +4 -1
- package/src/components/form/form.ts +9 -5
- package/src/components/gridview/gridview.ts +352 -176
- package/src/components/input/input.ts +63 -38
- package/src/components/keyboard/keyboard.module.scss +35 -4
- package/src/components/keyboard/keyboard.ts +295 -80
- package/src/components/listbox/listbox.ts +6 -1
- package/src/components/messages/messages.ts +12 -3
- package/src/components/popup/popup.ts +19 -20
- package/src/components/radio/radio.ts +8 -4
- package/src/components/rating/rating.ts +38 -48
- package/src/components/slider/slider.ts +38 -8
- package/src/components/spreadsheet/spreadsheet.ts +167 -132
- package/src/components/switch/switch.ts +2 -1
- package/src/components/tag/tag.ts +1 -2
- package/src/components/textarea/textarea.module.scss +6 -2
- package/src/components/textarea/textarea.ts +50 -11
- package/src/components/textedit/textedit.ts +12 -2
- package/src/core/component.ts +16 -9
- package/src/core/core_application.ts +8 -4
- package/src/core/core_clipboard.ts +239 -0
- package/src/core/core_data.ts +118 -49
- package/src/core/core_dom.ts +36 -6
- package/src/core/core_dragdrop.ts +11 -5
- package/src/core/core_element.ts +1 -1
- package/src/core/core_pdf.ts +696 -46
- package/src/core/core_router.ts +42 -44
- package/src/core/core_shortcuts.ts +1 -1
- package/src/core/core_state.ts +22 -5
- package/src/x4.d.ts +1 -0
- package/src/x4.ts +1 -0
|
@@ -15,22 +15,24 @@
|
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
17
|
import { EventCallback } from '../../core/core_events';
|
|
18
|
-
import { Component, ComponentEvent,
|
|
18
|
+
import { Component, ComponentEvent, ComponentProps, EvChange, EvFocus } from '../../core/component';
|
|
19
19
|
import { class_ns, formatIntlDate, IComponentInterface, IFormElement, isString } from '../../core/core_tools';
|
|
20
20
|
|
|
21
21
|
import "./input.module.scss"
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* @internal where to look for the radios of a group: the form that holds them,
|
|
26
|
+
* else the document
|
|
27
|
+
*/
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
const comp = componentFromDOM(el);
|
|
28
|
-
const ifx = comp.queryInterface( "tab-handler");
|
|
29
|
-
if( ifx ) {
|
|
30
|
-
return el;
|
|
31
|
-
}
|
|
29
|
+
export function getRadioOwner( el: Element ): ParentNode {
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
// two forms of a page can each have a group of the same name;
|
|
32
|
+
// a dialog has its form, its radios are in it
|
|
33
|
+
const form = el.closest( "form" );
|
|
34
|
+
if( form ) {
|
|
35
|
+
return form;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
return document;
|
|
@@ -222,7 +224,19 @@ export class Input extends Component<InputProps,InputEvents> {
|
|
|
222
224
|
if( props.autofocus===true ) {
|
|
223
225
|
this.setAttribute( "autofocus", true );
|
|
224
226
|
}
|
|
225
|
-
|
|
227
|
+
|
|
228
|
+
// every type but checkbox and radio (range and file ignore readonly)
|
|
229
|
+
if( props.type!="checkbox" && props.type!="radio" ) {
|
|
230
|
+
this.setAttribute( "required", props.required );
|
|
231
|
+
this.setAttribute( "readonly", props.readonly );
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// placeholder: shown by the browser on text, email, password and number only,
|
|
235
|
+
// not on date nor time (they show their own pattern)
|
|
236
|
+
if( props.type===undefined || props.type=="text" || props.type=="email" || props.type=="password" || props.type=="number" ) {
|
|
237
|
+
this.setAttribute( "placeholder", props.placeholder );
|
|
238
|
+
}
|
|
239
|
+
|
|
226
240
|
switch( props.type ) {
|
|
227
241
|
case "checkbox":
|
|
228
242
|
case "radio": {
|
|
@@ -244,9 +258,7 @@ export class Input extends Component<InputProps,InputEvents> {
|
|
|
244
258
|
|
|
245
259
|
case "number": {
|
|
246
260
|
const p = this.props as NumberProps;
|
|
247
|
-
|
|
248
|
-
this.setAttribute( "required", p.required );
|
|
249
|
-
this.setAttribute( "readonly", p.readonly );
|
|
261
|
+
|
|
250
262
|
this.setAttribute( "min", p.min );
|
|
251
263
|
this.setAttribute( "max", p.max );
|
|
252
264
|
this.setAttribute( "step", p.step );
|
|
@@ -256,20 +268,26 @@ export class Input extends Component<InputProps,InputEvents> {
|
|
|
256
268
|
this.addDOMEvent( "wheel", ( e: WheelEvent ) => {
|
|
257
269
|
if( this.hasFocus() ) { // only if has focus
|
|
258
270
|
e.preventDefault( );
|
|
259
|
-
let v = this.getNumValue();
|
|
260
|
-
const delta = e.deltaY < 0 ? 1 : -1;
|
|
261
|
-
v += (p.step ? p.step : 1) * delta;
|
|
262
|
-
this.setNumValue( v, -2 );
|
|
263
271
|
|
|
264
|
-
|
|
272
|
+
// the browser keeps the value between min and max, on the step,
|
|
273
|
+
// and starts from a valid one when the field is empty
|
|
274
|
+
const input = this.dom as HTMLInputElement;
|
|
275
|
+
if( e.deltaY < 0 ) {
|
|
276
|
+
input.stepUp( );
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
input.stepDown( );
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// the decimals of the step: 10.1 shown 10.10 for a step of 0.01
|
|
283
|
+
this.setNumValue( this.getNumValue( ), -2 );
|
|
284
|
+
this.dom.dispatchEvent(new Event('input'));
|
|
265
285
|
}
|
|
266
286
|
}, );
|
|
267
287
|
break;
|
|
268
288
|
}
|
|
269
289
|
|
|
270
290
|
case "date": {
|
|
271
|
-
this.setAttribute( "required", props.required );
|
|
272
|
-
|
|
273
291
|
let v = props.value;
|
|
274
292
|
if( v instanceof Date ) {
|
|
275
293
|
this.setAttribute( "value", formatIntlDate( v, "Y-M-D" ) );
|
|
@@ -295,7 +313,6 @@ export class Input extends Component<InputProps,InputEvents> {
|
|
|
295
313
|
}
|
|
296
314
|
|
|
297
315
|
case "time": {
|
|
298
|
-
this.setAttribute( "required", props.required );
|
|
299
316
|
if( props.value!==null && props.value!==undefined ) {
|
|
300
317
|
this.setAttribute( "value", props.value );
|
|
301
318
|
}
|
|
@@ -303,9 +320,6 @@ export class Input extends Component<InputProps,InputEvents> {
|
|
|
303
320
|
}
|
|
304
321
|
|
|
305
322
|
default: {
|
|
306
|
-
this.setAttribute( "required", props.required );
|
|
307
|
-
this.setAttribute( "readonly", props.readonly );
|
|
308
|
-
|
|
309
323
|
if( props.value!==null && props.value!==undefined ) {
|
|
310
324
|
this.setAttribute( "value", props.value );
|
|
311
325
|
}
|
|
@@ -314,10 +328,6 @@ export class Input extends Component<InputProps,InputEvents> {
|
|
|
314
328
|
this.setAttribute( "pattern", props.pattern );
|
|
315
329
|
}
|
|
316
330
|
|
|
317
|
-
if( props.placeholder!==null && props.placeholder!==undefined ) {
|
|
318
|
-
this.setAttribute( "placeholder", props.placeholder );
|
|
319
|
-
}
|
|
320
|
-
|
|
321
331
|
if( props.spellcheck===false ) {
|
|
322
332
|
this.setAttribute( "spellcheck", false );
|
|
323
333
|
}
|
|
@@ -417,14 +427,19 @@ export class Input extends Component<InputProps,InputEvents> {
|
|
|
417
427
|
}
|
|
418
428
|
|
|
419
429
|
if( ndec==-2 && this.props.type=='number' ) {
|
|
420
|
-
const
|
|
430
|
+
const step = (this.props as NumberProps).step;
|
|
431
|
+
|
|
432
|
+
// as many decimals as the step, 4 at most: the step in 1/10000 is an integer,
|
|
433
|
+
// each 0 on its right is a decimal less (0.25 → 2500 → 2, 2.5 → 25000 → 1, 2 → 0)
|
|
434
|
+
if( step!==undefined && step!=1 ) {
|
|
435
|
+
let n = Math.round( step * 10000 );
|
|
436
|
+
let decimals = 4;
|
|
437
|
+
while( n && n%10==0 && decimals ) {
|
|
438
|
+
n /= 10;
|
|
439
|
+
decimals--;
|
|
440
|
+
}
|
|
421
441
|
|
|
422
|
-
|
|
423
|
-
let ndec = -Math.floor(Math.log10(p.step ?? 1) );
|
|
424
|
-
return this.setValue( value.toFixed(ndec) );
|
|
425
|
-
}
|
|
426
|
-
else if( p.step>1 ) {
|
|
427
|
-
return this.setValue( value.toFixed() );
|
|
442
|
+
return this.setValue( value.toFixed( decimals ) );
|
|
428
443
|
}
|
|
429
444
|
}
|
|
430
445
|
else if( ndec>=0 ) {
|
|
@@ -506,9 +521,16 @@ export class Input extends Component<InputProps,InputEvents> {
|
|
|
506
521
|
override queryInterface<T extends IComponentInterface>( name: string ): T {
|
|
507
522
|
if( name=="form-element" ) {
|
|
508
523
|
const i: IFormElement = {
|
|
509
|
-
getRawValue: ( ): any => {
|
|
524
|
+
getRawValue: ( ): any => {
|
|
525
|
+
// checkbox without value, or a boolean one: a boolean; with one: the value when checked,
|
|
526
|
+
// null when not (as a <form>)
|
|
510
527
|
if( this.props.type=='checkbox' ) {
|
|
511
|
-
|
|
528
|
+
const value = this.props.value;
|
|
529
|
+
if( value===undefined || typeof value==="boolean" ) {
|
|
530
|
+
return this.getCheck( );
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return this.getCheck( ) ? value : null;
|
|
512
534
|
}
|
|
513
535
|
else if( this.props.type=='radio' ) {
|
|
514
536
|
const owner = getRadioOwner( this.dom );
|
|
@@ -523,8 +545,11 @@ export class Input extends Component<InputProps,InputEvents> {
|
|
|
523
545
|
}
|
|
524
546
|
},
|
|
525
547
|
setRawValue: ( v: any ) => {
|
|
548
|
+
// checkbox with a value (not a boolean): checked by that value (or true)
|
|
526
549
|
if( this.props.type=='checkbox' ) {
|
|
527
|
-
this.
|
|
550
|
+
const value = this.props.value;
|
|
551
|
+
const plain = value===undefined || typeof value==="boolean";
|
|
552
|
+
this.setCheck( plain ? !!v : ( v===value || v===true ) );
|
|
528
553
|
}
|
|
529
554
|
else if( this.props.type=='radio' ) {
|
|
530
555
|
if( this.props.value==v ) {
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
:root {
|
|
18
18
|
--keyboard-key-background: #33302d;
|
|
19
19
|
--keyboard-hilite-color: #5ba921;
|
|
20
|
+
--keyboard-key-color: #ffffff;
|
|
21
|
+
--keyboard-accents-color: #7cc7ff;
|
|
22
|
+
--keyboard-symbols-color: #f2c94c;
|
|
20
23
|
--keyboard-zoom: 100%;
|
|
21
24
|
}
|
|
22
25
|
|
|
@@ -62,7 +65,8 @@
|
|
|
62
65
|
width: 100%;
|
|
63
66
|
}
|
|
64
67
|
|
|
65
|
-
color
|
|
68
|
+
// the color of the page, for the keys of characters
|
|
69
|
+
color: var( --kb-page-color, var( --keyboard-key-color ) );
|
|
66
70
|
text-align: center;
|
|
67
71
|
|
|
68
72
|
background-color: var( --keyboard-key-background);
|
|
@@ -83,6 +87,29 @@
|
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
|
|
90
|
+
.accents {
|
|
91
|
+
--kb-page-color: var( --keyboard-accents-color );
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.symbols {
|
|
95
|
+
--kb-page-color: var( --keyboard-symbols-color );
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// the keys of commands keep their color, the keys that call a page have its one
|
|
99
|
+
.cnum,
|
|
100
|
+
.calpha,
|
|
101
|
+
.cspace {
|
|
102
|
+
color: var( --keyboard-key-color );
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.caccents {
|
|
106
|
+
color: var( --keyboard-accents-color );
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.csymbols {
|
|
110
|
+
color: var( --keyboard-symbols-color );
|
|
111
|
+
}
|
|
112
|
+
|
|
86
113
|
.cplace {
|
|
87
114
|
visibility: hidden;
|
|
88
115
|
}
|
|
@@ -109,8 +136,9 @@
|
|
|
109
136
|
|
|
110
137
|
// color: rgba(255,255,255,0.3);
|
|
111
138
|
|
|
112
|
-
.
|
|
113
|
-
.
|
|
139
|
+
.alpha,
|
|
140
|
+
.accents,
|
|
141
|
+
.symbols {
|
|
114
142
|
|
|
115
143
|
.cspace {
|
|
116
144
|
flex-basis: 689px;
|
|
@@ -128,7 +156,10 @@
|
|
|
128
156
|
flex-basis: 88px;
|
|
129
157
|
}
|
|
130
158
|
|
|
131
|
-
.cnum
|
|
159
|
+
.cnum,
|
|
160
|
+
.caccents,
|
|
161
|
+
.csymbols,
|
|
162
|
+
.calpha {
|
|
132
163
|
flex-basis: 88px;
|
|
133
164
|
}
|
|
134
165
|
}
|