x4js 2.2.49 → 2.2.50
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/README.md +4 -3
- package/package.json +1 -1
- package/src/components/boxes/boxes.module.scss +1 -0
- package/src/components/btngroup/btngroup.module.scss +1 -1
- package/src/components/colorpicker/colorpicker.ts +2 -2
- package/src/components/dialog/dialog.ts +1 -1
- package/src/components/input/input.module.scss +5 -0
- package/src/components/listbox/listbox.ts +8 -8
- package/src/components/notification/notification.ts +6 -0
- package/src/components/popup/popup.module.scss +1 -0
- package/src/components/popup/popup.ts +55 -32
- package/src/components/propgrid/progrid.module.scss +11 -5
- package/src/components/propgrid/propgrid.ts +29 -14
- package/src/components/sizers/sizer.ts +23 -8
- package/src/components/tabs/tabs.ts +6 -6
- package/src/components/tooltips/tooltips.ts +2 -2
- package/src/components/treeview/treeview.ts +2 -0
- package/src/core/component.ts +37 -38
- package/src/core/core_application.ts +15 -0
- package/src/core/core_dom.ts +49 -31
- package/src/core/core_element.ts +133 -31
- package/src/core/core_pdf.ts +1 -0
package/README.md
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
**A TypeScript framework for people who build applications, not markup.**
|
|
3
3
|
|
|
4
4
|
## Home page
|
|
5
|
-
see [home](https://x4js.org)
|
|
5
|
+
see [X4 home page](https://x4js.org)
|
|
6
6
|
|
|
7
7
|
## API Documentation
|
|
8
|
-
see [
|
|
9
|
-
|
|
8
|
+
see [GitHib](https://rlibre.github.io/x4/index.html)
|
|
9
|
+
|
|
10
|
+
see [AI context](./aicontext.md)
|
|
10
11
|
|
|
11
12
|
---
|
|
12
13
|
|
package/package.json
CHANGED
|
@@ -163,7 +163,7 @@ export class Saturation extends Box<BoxProps,CommonEvents> {
|
|
|
163
163
|
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
|
-
*
|
|
166
|
+
* @internal
|
|
167
167
|
*/
|
|
168
168
|
|
|
169
169
|
@class_ns( "x4" )
|
|
@@ -240,7 +240,7 @@ class HueSlider extends Box<BoxProps,CommonEvents> {
|
|
|
240
240
|
|
|
241
241
|
|
|
242
242
|
/**
|
|
243
|
-
*
|
|
243
|
+
* @internal
|
|
244
244
|
*/
|
|
245
245
|
|
|
246
246
|
@class_ns( "x4" )
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
17
|
:root {
|
|
18
|
+
--input-background: rgba(255, 255, 255, 0.6);
|
|
19
|
+
--input-color: black;
|
|
20
|
+
|
|
18
21
|
--input-sel-background: var( --accent-background );
|
|
19
22
|
--input-sel-color: var( --accent-color );
|
|
20
23
|
--input-placeholder: var( --disabled-background );
|
|
@@ -28,6 +31,8 @@ input.x4input {
|
|
|
28
31
|
outline: none;
|
|
29
32
|
|
|
30
33
|
border: none;
|
|
34
|
+
background-color: var( --input-background );
|
|
35
|
+
color: var( --input-color );
|
|
31
36
|
|
|
32
37
|
&::selection {
|
|
33
38
|
background-color: var( --input-sel-background );
|
|
@@ -498,30 +498,30 @@ export class Listbox extends Component<ListboxProps,ListboxEvents> {
|
|
|
498
498
|
|
|
499
499
|
defaultRenderer( item: ListItem ): Component {
|
|
500
500
|
|
|
501
|
-
const mk_col = (
|
|
502
|
-
const c = item.sub_cols[index];
|
|
501
|
+
const mk_col = ( c: any, index: number ) => {
|
|
503
502
|
if( c===undefined || c===null ) {
|
|
504
503
|
return null;
|
|
505
504
|
}
|
|
506
505
|
|
|
507
506
|
if( c instanceof Component ) {
|
|
507
|
+
c.addClass( "column" );
|
|
508
508
|
return c;
|
|
509
509
|
}
|
|
510
510
|
|
|
511
511
|
return new SimpleText( { cls: `column ref-c${index+2}`, text: c } )
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
-
|
|
514
|
+
const content = [
|
|
515
|
+
new Label( { cls: `column ref-c1`, icon: item.iconId, text: item.text } ),
|
|
516
|
+
];
|
|
517
|
+
|
|
515
518
|
if( item.sub_cols ) {
|
|
516
|
-
|
|
519
|
+
content.push( ...(item.sub_cols.map( mk_col )) );
|
|
517
520
|
}
|
|
518
521
|
|
|
519
522
|
return new HBox( {
|
|
520
523
|
cls: item.cls,
|
|
521
|
-
content
|
|
522
|
-
new Label( { cls: `column ref-c1`, icon: item.iconId, text: item.text } ),
|
|
523
|
-
...cols,
|
|
524
|
-
],
|
|
524
|
+
content
|
|
525
525
|
} )
|
|
526
526
|
}
|
|
527
527
|
|
|
@@ -42,6 +42,12 @@ interface NotificationProps extends ComponentProps {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
+
*
|
|
46
|
+
* @example:
|
|
47
|
+
* const not = new Notification( { title: "Yooo", text: "You win !", mode: "danger" })
|
|
48
|
+
* not.display( 3000 )
|
|
49
|
+
*
|
|
50
|
+
*
|
|
45
51
|
* @cssvar
|
|
46
52
|
* ```
|
|
47
53
|
* --notification-border
|
|
@@ -22,6 +22,7 @@ import { Box } from '../boxes/boxes'
|
|
|
22
22
|
|
|
23
23
|
import "./popup.module.scss"
|
|
24
24
|
import { getGlobalZoom, getScrollbarSize } from '../../core/core_tools.js';
|
|
25
|
+
import { Application } from '../../core/core_application.js';
|
|
25
26
|
|
|
26
27
|
export interface PopupEvents extends ComponentEvents {
|
|
27
28
|
closed: ComponentEvent;
|
|
@@ -66,6 +67,7 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
// wait for element to create it's childs
|
|
70
|
+
// > setContent is in ctor
|
|
69
71
|
asap( ( ) => {
|
|
70
72
|
if( this.props.movable===true || (this.props.sizable && this.props.movable===undefined) ) {
|
|
71
73
|
const movers = this.queryAll( ".caption-element" );
|
|
@@ -136,13 +138,31 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEvents = Po
|
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
/**
|
|
139
|
-
*
|
|
141
|
+
* stupid parameter
|
|
140
142
|
*/
|
|
141
143
|
|
|
142
|
-
displayCenter(
|
|
143
|
-
//this.displayNear( new Rect( window.innerWidth/2, window.innerHeight/2, 0, 0 ), "center middle" );
|
|
144
|
-
this.setClass( 'center', center );
|
|
144
|
+
displayCenter( ) {
|
|
145
145
|
this._do_show( ); // to compute size
|
|
146
|
+
|
|
147
|
+
const fixpos = ( ) => {
|
|
148
|
+
console.log( "fixpos" );
|
|
149
|
+
|
|
150
|
+
const orc = this.getBoundingRect( );
|
|
151
|
+
this.setStyle( {
|
|
152
|
+
left: ((window.innerWidth - orc.width) / 2) +'px',
|
|
153
|
+
top: ((window.innerHeight - orc.height) / 2) +'px',
|
|
154
|
+
} );
|
|
155
|
+
|
|
156
|
+
console.log( orc );
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
asap( fixpos );
|
|
160
|
+
|
|
161
|
+
const tkn = Application.instance( ).on( "resize", () => {
|
|
162
|
+
asap( fixpos );
|
|
163
|
+
} )
|
|
164
|
+
|
|
165
|
+
this.addCleanup( tkn.off );
|
|
146
166
|
}
|
|
147
167
|
|
|
148
168
|
/**
|
|
@@ -411,51 +431,54 @@ class CMover {
|
|
|
411
431
|
|
|
412
432
|
this.self = ref ? true : false;
|
|
413
433
|
|
|
414
|
-
|
|
434
|
+
const mouseDown = ( e: PointerEvent ) => {
|
|
415
435
|
if( this.self && e.target!=x.dom ) {
|
|
416
436
|
return;
|
|
417
437
|
}
|
|
418
438
|
|
|
419
439
|
x.setCapture( e.pointerId );
|
|
420
440
|
|
|
421
|
-
|
|
441
|
+
if( !ref ) {
|
|
442
|
+
ref = componentFromDOM( x.dom.parentElement );
|
|
443
|
+
}
|
|
422
444
|
|
|
445
|
+
this.ref = ref;
|
|
423
446
|
this.delta = {x:0,y:0};
|
|
424
|
-
const rc =
|
|
447
|
+
const rc = ref.getBoundingRect();
|
|
425
448
|
|
|
426
449
|
this.delta.x = e.pageX-rc.left;
|
|
427
450
|
this.delta.y = e.pageY-rc.top;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
x.addDOMEvent( "pointerup", ( e: PointerEvent ) => {
|
|
431
|
-
x.releaseCapture( e.pointerId );
|
|
432
|
-
this.ref = null;
|
|
433
|
-
});
|
|
451
|
+
}
|
|
434
452
|
|
|
435
|
-
|
|
436
|
-
this.
|
|
437
|
-
|
|
438
|
-
|
|
453
|
+
const mouseMove = ( e: PointerEvent ) => {
|
|
454
|
+
if( !this.delta ) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
439
457
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
458
|
+
const ref = this.ref
|
|
459
|
+
const pt = { x: e.pageX-this.delta.x, y: e.pageY-this.delta.y };
|
|
460
|
+
const rc = ref.getBoundingRect( );
|
|
461
|
+
|
|
462
|
+
ref.setStyle( {
|
|
463
|
+
top: pt.y+"",
|
|
464
|
+
left: pt.x+"",
|
|
465
|
+
} );
|
|
466
|
+
|
|
467
|
+
e.preventDefault( );
|
|
468
|
+
e.stopPropagation( );
|
|
443
469
|
}
|
|
444
470
|
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
};
|
|
471
|
+
const mouseUp = ( e: PointerEvent ) => {
|
|
472
|
+
x.releaseCapture( e.pointerId );
|
|
473
|
+
this.delta = null;
|
|
474
|
+
}
|
|
450
475
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
} );
|
|
455
|
-
|
|
456
|
-
e.preventDefault( );
|
|
457
|
-
e.stopPropagation( );
|
|
476
|
+
x.addDOMEvent( "pointerdown", mouseDown );
|
|
477
|
+
x.addDOMEvent( "pointerup", mouseUp );
|
|
478
|
+
x.addDOMEvent( "pointermove", mouseMove );
|
|
458
479
|
}
|
|
480
|
+
|
|
481
|
+
|
|
459
482
|
}
|
|
460
483
|
|
|
461
484
|
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
:root {
|
|
8
8
|
--propertygrid-background: white;
|
|
9
|
+
--propertygrid-gadget-background: white;
|
|
10
|
+
--propertygrid-gadget-color: black;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
.x4propertygrid {
|
|
@@ -92,10 +94,6 @@
|
|
|
92
94
|
flex-basis: 10px;
|
|
93
95
|
padding: 4px;
|
|
94
96
|
|
|
95
|
-
&>* {
|
|
96
|
-
width: 100%;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
97
|
input {
|
|
100
98
|
background: rgba(255,255,255,0.6);
|
|
101
99
|
}
|
|
@@ -110,8 +108,16 @@
|
|
|
110
108
|
padding-left: 34px;
|
|
111
109
|
}
|
|
112
110
|
|
|
113
|
-
.cell:has(.
|
|
111
|
+
.cell:has(.button) {
|
|
114
112
|
padding: 4px 40px;
|
|
115
113
|
}
|
|
114
|
+
|
|
115
|
+
.gadget {
|
|
116
|
+
&.x4button {
|
|
117
|
+
--button-background: var( --propertygrid-gadget-background );
|
|
118
|
+
--button-color: var( --propertygrid-gadget-color );
|
|
119
|
+
padding: 5px;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
116
122
|
}
|
|
117
123
|
}
|
|
@@ -44,6 +44,7 @@ export interface PropertyValue {
|
|
|
44
44
|
step?: number; // for numbers
|
|
45
45
|
min?: number;
|
|
46
46
|
max?: number;
|
|
47
|
+
gadgets?: Component[];
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
export interface PropertyGroup {
|
|
@@ -246,6 +247,7 @@ export class PropertyGrid extends VBox {
|
|
|
246
247
|
use_hdr = false;
|
|
247
248
|
editor = new Button({
|
|
248
249
|
id: item.name,
|
|
250
|
+
cls: "button",
|
|
249
251
|
label: value as string,
|
|
250
252
|
click: ( ) => {
|
|
251
253
|
item.callback?.( item.name, '' );
|
|
@@ -253,17 +255,17 @@ export class PropertyGrid extends VBox {
|
|
|
253
255
|
});
|
|
254
256
|
}
|
|
255
257
|
else {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
258
|
+
editor = new Input({
|
|
259
|
+
type: 'text',
|
|
260
|
+
id: item.name,
|
|
261
|
+
name: item.name,
|
|
262
|
+
value: value as string,
|
|
263
|
+
focus: ( e: EvFocus ) => {
|
|
264
|
+
if( e.focus_out ) {
|
|
265
|
+
item.callback?.( item.name, (editor as Input).getValue() );
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
})
|
|
267
269
|
}
|
|
268
270
|
|
|
269
271
|
let cls = 'row';
|
|
@@ -271,12 +273,25 @@ export class PropertyGrid extends VBox {
|
|
|
271
273
|
cls += ' ' + item.cls;
|
|
272
274
|
}
|
|
273
275
|
|
|
276
|
+
editor.addClass( "x4flex" );
|
|
277
|
+
|
|
278
|
+
const content: Component[] = [
|
|
279
|
+
editor
|
|
280
|
+
]
|
|
281
|
+
|
|
282
|
+
if( item.gadgets ) {
|
|
283
|
+
item.gadgets.forEach( g => {
|
|
284
|
+
g.addClass( "gadget" );
|
|
285
|
+
content.push( g );
|
|
286
|
+
} );
|
|
287
|
+
}
|
|
288
|
+
|
|
274
289
|
return new HBox({
|
|
275
290
|
cls,
|
|
276
291
|
content: [
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
292
|
+
use_hdr ? new Component({ cls: 'cell hdr', content: item.title ?? item.name, tooltip: item.desc }) : null,
|
|
293
|
+
new HBox({ cls: 'cell', tag: "label", attrs: { "labelFor": item.name }, content }),
|
|
294
|
+
]
|
|
280
295
|
});
|
|
281
296
|
}
|
|
282
297
|
|
|
@@ -24,7 +24,9 @@ import "./sizer.module.scss"
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
export interface EvSizeChange extends ComponentEvent {
|
|
27
|
-
size: number;
|
|
27
|
+
size: number; // compat
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
interface CSizerEvent extends ComponentEvents {
|
|
@@ -111,28 +113,41 @@ export class CSizer extends Component<ComponentProps,CSizerEvent> {
|
|
|
111
113
|
let nr: any = {};
|
|
112
114
|
let horz = true;
|
|
113
115
|
|
|
116
|
+
//const center = this._ref.hasClass("center");
|
|
117
|
+
//if( center ) {
|
|
118
|
+
// const orc = this._ref.getBoundingRect( );
|
|
119
|
+
// this._ref.removeClass("center");
|
|
120
|
+
//
|
|
121
|
+
// nr.left = orc.left;
|
|
122
|
+
// nr.top = orc.top;
|
|
123
|
+
//}
|
|
124
|
+
|
|
114
125
|
if( this._type.includes("top") ) {
|
|
115
126
|
nr.top = pt.y,
|
|
116
127
|
nr.height = (rc.top+rc.height)-pt.y;
|
|
117
128
|
horz = false;
|
|
118
129
|
}
|
|
119
|
-
|
|
130
|
+
|
|
131
|
+
if( this._type=="vsize-next" ) {
|
|
120
132
|
nr.height = (rc.top+rc.height)-pt.y;
|
|
121
133
|
horz = false;
|
|
122
134
|
}
|
|
123
|
-
|
|
124
|
-
|
|
135
|
+
|
|
136
|
+
if( this._type.includes("bottom") || this._type=='vsize-prev' ) {
|
|
125
137
|
nr.height = (pt.y-rc.top);
|
|
126
138
|
horz = false;
|
|
127
139
|
}
|
|
128
|
-
|
|
140
|
+
|
|
141
|
+
if( this._type.includes("left") ) {
|
|
129
142
|
nr.left = pt.x;
|
|
130
143
|
nr.width = ((rc.left+rc.width)-pt.x);
|
|
131
144
|
}
|
|
132
|
-
|
|
145
|
+
|
|
146
|
+
if( this._type=="hsize-next" ) {
|
|
133
147
|
nr.width = ((rc.left+rc.width)-pt.x);
|
|
134
148
|
}
|
|
135
|
-
|
|
149
|
+
|
|
150
|
+
if( this._type.includes("right") || this._type=='hsize-prev' ) {
|
|
136
151
|
nr.width = (pt.x-rc.left);
|
|
137
152
|
}
|
|
138
153
|
|
|
@@ -140,7 +155,7 @@ export class CSizer extends Component<ComponentProps,CSizerEvent> {
|
|
|
140
155
|
//this._ref.setStyleValue( "flexGrow", 0 );
|
|
141
156
|
|
|
142
157
|
const nrc = this._ref.getBoundingRect( );
|
|
143
|
-
this.fire( "resize", { size: horz ? nrc.width : nrc.height })
|
|
158
|
+
this.fire( "resize", { size: horz ? nrc.width : nrc.height, width: nrc.width, height: nrc.height })
|
|
144
159
|
|
|
145
160
|
e.preventDefault( );
|
|
146
161
|
e.stopPropagation( );
|
|
@@ -75,12 +75,7 @@ interface TablistEvents extends ComponentEvents {
|
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
77
|
* bar containing buttons
|
|
78
|
-
*
|
|
79
|
-
* @cssvar
|
|
80
|
-
* ```
|
|
81
|
-
* --tab-border-selected
|
|
82
|
-
* --tab-border-hover
|
|
83
|
-
* ```
|
|
78
|
+
* @internal
|
|
84
79
|
*/
|
|
85
80
|
|
|
86
81
|
@class_ns( "x4" )
|
|
@@ -147,6 +142,11 @@ interface TabsProps extends Omit<ComponentProps,"content"> {
|
|
|
147
142
|
|
|
148
143
|
/**
|
|
149
144
|
*
|
|
145
|
+
* @cssvar
|
|
146
|
+
* ```
|
|
147
|
+
* --tab-border-selected
|
|
148
|
+
* --tab-border-hover
|
|
149
|
+
* ```
|
|
150
150
|
*/
|
|
151
151
|
|
|
152
152
|
@class_ns( "x4" )
|
|
@@ -75,7 +75,7 @@ function showTT( text: string, rc: Rect, pt: Point ) {
|
|
|
75
75
|
tooltip = new Tooltip( { } );
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
timer.setTimeout(
|
|
78
|
+
timer.setTimeout( "update", 300, ( ) => {
|
|
79
79
|
tooltip.setText( unsafeHtml(text) );
|
|
80
80
|
|
|
81
81
|
let y = mouse_pos.y;
|
|
@@ -90,7 +90,7 @@ function showTT( text: string, rc: Rect, pt: Point ) {
|
|
|
90
90
|
|
|
91
91
|
function closeTT( ) {
|
|
92
92
|
tooltip.show( false );
|
|
93
|
-
timer.clearTimeout(
|
|
93
|
+
timer.clearTimeout( "update" );
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/**
|
|
@@ -488,8 +488,10 @@ export class Treeview extends Component<TreeviewProps,TreeviewEvents> {
|
|
|
488
488
|
this._selitem = undefined;
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
+
if( this._selection ) {
|
|
491
492
|
this._selection = undefined;
|
|
492
493
|
this.fire( "selectionChange", { selection: [], empty: true } );
|
|
494
|
+
}
|
|
493
495
|
}
|
|
494
496
|
|
|
495
497
|
/**
|
package/src/core/component.ts
CHANGED
|
@@ -14,11 +14,11 @@
|
|
|
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, class_ns, x4_class_ns_sym
|
|
17
|
+
import { isArray, UnsafeHtml, isNumber, Rect, Constructor, class_ns, x4_class_ns_sym } 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';
|
|
21
|
-
import { addEvent, DOMEventHandler, GlobalDOMEvents } from './core_dom';
|
|
21
|
+
import { addEvent, DOMEventHandler, GlobalDOMEvents, COMPONENT } from './core_dom';
|
|
22
22
|
import { Application, EvMessage } from './core_application';
|
|
23
23
|
import { makeState } from './core_state.js';
|
|
24
24
|
|
|
@@ -30,7 +30,6 @@ type ComponentAttributes = Record<string,string|number|boolean>;
|
|
|
30
30
|
type CreateComponentCallBack = ( attrs: Record<string,string> ) => ComponentContent;
|
|
31
31
|
|
|
32
32
|
const FRAGMENT = Symbol( "fragment" );
|
|
33
|
-
const COMPONENT = Symbol( "component" );
|
|
34
33
|
|
|
35
34
|
const RE_NUMBER = /^-?\d+(\.\d*)?$/;
|
|
36
35
|
|
|
@@ -152,7 +151,7 @@ export interface ComponentEvents extends EventMap {
|
|
|
152
151
|
* ```
|
|
153
152
|
*/
|
|
154
153
|
|
|
155
|
-
@class_ns(
|
|
154
|
+
@class_ns("x4")
|
|
156
155
|
export class Component<P extends ComponentProps = ComponentProps, E extends ComponentEvents = ComponentEvents>
|
|
157
156
|
extends CoreElement<E> {
|
|
158
157
|
|
|
@@ -166,16 +165,16 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
166
165
|
|
|
167
166
|
#store: Map<string|symbol,any>;
|
|
168
167
|
#pstate: any;
|
|
169
|
-
|
|
170
|
-
constructor(
|
|
168
|
+
|
|
169
|
+
constructor(props: P) {
|
|
171
170
|
super( );
|
|
172
171
|
|
|
173
172
|
this.props = props; // copy ?
|
|
174
173
|
|
|
175
174
|
if( props.existingDOM ) {
|
|
176
175
|
this.dom = props.existingDOM;
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
179
178
|
if( props.ns ) {
|
|
180
179
|
this.dom = document.createElementNS( props.ns, props.tag ?? "div" );
|
|
181
180
|
}
|
|
@@ -242,8 +241,8 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
242
241
|
this.addDOMEvent( "created", ( ) => {
|
|
243
242
|
this.enable( false );
|
|
244
243
|
} );
|
|
244
|
+
}
|
|
245
245
|
}
|
|
246
|
-
}
|
|
247
246
|
|
|
248
247
|
(this.dom as any)[COMPONENT] = this;
|
|
249
248
|
}
|
|
@@ -281,10 +280,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
281
280
|
* Multiple classes can be provided as a space-separated string.
|
|
282
281
|
* @param cls - The CSS class(es) to add.
|
|
283
282
|
*/
|
|
284
|
-
|
|
283
|
+
|
|
285
284
|
addClass( cls: string ) {
|
|
286
285
|
if( !cls ) return;
|
|
287
|
-
|
|
286
|
+
|
|
288
287
|
cls = cls.trim( );
|
|
289
288
|
|
|
290
289
|
if( cls.includes(' ') ) {
|
|
@@ -309,13 +308,13 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
309
308
|
if( cls=='*' ) {
|
|
310
309
|
this.dom.classList.value = "";
|
|
311
310
|
return;
|
|
312
|
-
|
|
311
|
+
}
|
|
313
312
|
|
|
314
313
|
if( cls.indexOf(' ')>=0 ) {
|
|
315
314
|
const ccs = cls.split( " " );
|
|
316
315
|
this.dom.classList.remove(...ccs);
|
|
317
|
-
|
|
318
|
-
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
319
318
|
this.dom.classList.remove(cls);
|
|
320
319
|
}
|
|
321
320
|
}
|
|
@@ -351,11 +350,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
351
350
|
if( cls.indexOf(' ')>=0 ) {
|
|
352
351
|
const ccs = cls.split( " " );
|
|
353
352
|
ccs.forEach( toggle );
|
|
354
|
-
|
|
355
|
-
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
356
355
|
toggle( cls );
|
|
357
356
|
}
|
|
358
|
-
|
|
357
|
+
}
|
|
359
358
|
|
|
360
359
|
/**
|
|
361
360
|
* Sets or removes a CSS class based on a boolean condition.
|
|
@@ -368,7 +367,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
368
367
|
if( set ) this.addClass(cls);
|
|
369
368
|
else this.removeClass( cls );
|
|
370
369
|
return this;
|
|
371
|
-
|
|
370
|
+
}
|
|
372
371
|
|
|
373
372
|
// :: ATTRIBUTES ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
374
373
|
|
|
@@ -383,7 +382,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
383
382
|
this.setAttribute( name, attrs[name] );
|
|
384
383
|
}
|
|
385
384
|
return this;
|
|
386
|
-
|
|
385
|
+
}
|
|
387
386
|
|
|
388
387
|
/**
|
|
389
388
|
* Sets a single HTML attribute on the component's DOM element.
|
|
@@ -399,7 +398,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
399
398
|
else {
|
|
400
399
|
this.dom.setAttribute( name, ""+value );
|
|
401
400
|
}
|
|
402
|
-
|
|
401
|
+
}
|
|
403
402
|
|
|
404
403
|
/**
|
|
405
404
|
* Retrieves the value of an HTML attribute from the component's DOM element.
|
|
@@ -420,8 +419,8 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
420
419
|
* @see Component.getIntData
|
|
421
420
|
* @see Component.setInternalData
|
|
422
421
|
* @see Component.getInternalData
|
|
423
|
-
|
|
424
|
-
|
|
422
|
+
*/
|
|
423
|
+
|
|
425
424
|
getData( name: string ) : string {
|
|
426
425
|
return this.getAttribute( "data-"+name );
|
|
427
426
|
}
|
|
@@ -794,7 +793,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
794
793
|
/**
|
|
795
794
|
* Sets pointer capture on the component's DOM element for a specific pointer.
|
|
796
795
|
* @param pointerId - The unique ID of the pointer.
|
|
797
|
-
*
|
|
796
|
+
*
|
|
798
797
|
* @example
|
|
799
798
|
* control.on("pointerdown", (ev) => {
|
|
800
799
|
* ev.preventDefault(); // Prevent default browser actions
|
|
@@ -858,7 +857,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
858
857
|
/**
|
|
859
858
|
* Checks if the component's DOM element is currently visible (i.e., not hidden by `display: none`).
|
|
860
859
|
* @returns `true` if the component is visible, `false` otherwise.
|
|
861
|
-
|
|
860
|
+
*/
|
|
862
861
|
|
|
863
862
|
isVisible( ) {
|
|
864
863
|
return (this.dom as HTMLElement).offsetParent !== null;
|
|
@@ -944,7 +943,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
944
943
|
/**
|
|
945
944
|
* Returns the previous sibling element as a Component instance.
|
|
946
945
|
* @returns The previous sibling component, or `null` if none exists.
|
|
947
|
-
|
|
946
|
+
*/
|
|
948
947
|
|
|
949
948
|
prevElement<T extends Component = Component>( ): T {
|
|
950
949
|
const nxt = this.dom.previousElementSibling;
|
|
@@ -962,7 +961,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
962
961
|
}
|
|
963
962
|
|
|
964
963
|
/**
|
|
965
|
-
|
|
964
|
+
*
|
|
966
965
|
*/
|
|
967
966
|
|
|
968
967
|
childCount( ) {
|
|
@@ -974,9 +973,9 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
974
973
|
* @param dom - The starting DOM node from which to search upwards.
|
|
975
974
|
* @param cls - Optional. The constructor of the Component type to match.
|
|
976
975
|
* @returns The matching parent Component instance, or `null` if not found.
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
976
|
+
*/
|
|
977
|
+
|
|
978
|
+
|
|
980
979
|
static parentElement<T extends Component>( dom: Node, cls?: Constructor<T> ): T {
|
|
981
980
|
|
|
982
981
|
while( dom.parentElement ) {
|
|
@@ -991,14 +990,14 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
991
990
|
|
|
992
991
|
dom = dom.parentElement;
|
|
993
992
|
}
|
|
994
|
-
|
|
993
|
+
|
|
995
994
|
return null;
|
|
996
995
|
}
|
|
997
996
|
|
|
998
997
|
/**
|
|
999
998
|
* Returns the first child element as a Component instance.
|
|
1000
999
|
* @returns The first child component, or `null` if none exists.
|
|
1001
|
-
|
|
1000
|
+
*/
|
|
1002
1001
|
|
|
1003
1002
|
firstChild<T extends Component = Component>( ) : T {
|
|
1004
1003
|
const nxt = this.dom.firstElementChild;
|
|
@@ -1008,7 +1007,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
1008
1007
|
/**
|
|
1009
1008
|
* Returns the last child element as a Component instance.
|
|
1010
1009
|
* @returns The last child component, or `null` if none exists.
|
|
1011
|
-
|
|
1010
|
+
*/
|
|
1012
1011
|
|
|
1013
1012
|
lastChild<T extends Component = Component>( ) : T {
|
|
1014
1013
|
const nxt = this.dom.lastElementChild;
|
|
@@ -1019,19 +1018,19 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
1019
1018
|
* Enumerates all child components of this component.
|
|
1020
1019
|
* @param recursive - If `true`, searches all descendants; otherwise, only direct children.
|
|
1021
1020
|
* @returns An array of child Component instances.
|
|
1022
|
-
|
|
1021
|
+
*/
|
|
1023
1022
|
|
|
1024
1023
|
enumChildComponents( recursive: boolean ) {
|
|
1025
|
-
|
|
1024
|
+
|
|
1026
1025
|
const children: Component[] = [];
|
|
1027
|
-
|
|
1026
|
+
|
|
1028
1027
|
const nodes = this.enumChildNodes( recursive );
|
|
1029
1028
|
nodes.forEach( ( c: Node ) => {
|
|
1030
1029
|
const cc = componentFromDOM( c as HTMLElement );
|
|
1031
1030
|
if( cc ) {
|
|
1032
1031
|
children.push(cc);
|
|
1033
1032
|
}
|
|
1034
|
-
|
|
1033
|
+
});
|
|
1035
1034
|
|
|
1036
1035
|
return children;
|
|
1037
1036
|
}
|
|
@@ -1188,7 +1187,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
|
|
|
1188
1187
|
state.on( "change", ( ) => {
|
|
1189
1188
|
this.setTimeout( key, 500, ( ) => {
|
|
1190
1189
|
Application.instance().setStorage( key, JSON.stringify( raw ) );
|
|
1191
|
-
|
|
1190
|
+
} );
|
|
1192
1191
|
});
|
|
1193
1192
|
|
|
1194
1193
|
this.#pstate[name] = state;
|
|
@@ -1214,7 +1213,7 @@ type ComponentConstructor = {
|
|
|
1214
1213
|
|
|
1215
1214
|
export function componentFromDOM<T extends Component = Component>( node: Element ) {
|
|
1216
1215
|
return node ? (node as any)[COMPONENT] as T : null;
|
|
1217
|
-
}
|
|
1216
|
+
}
|
|
1218
1217
|
|
|
1219
1218
|
/**
|
|
1220
1219
|
* Wraps an existing HTMLElement with a new Component instance.
|
|
@@ -27,9 +27,15 @@ export interface EvMessage extends CoreEvent {
|
|
|
27
27
|
params: any;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
interface EvWindowResize extends CoreEvent {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
export interface ApplicationEvents extends EventMap {
|
|
31
36
|
global: EvMessage;
|
|
32
37
|
message: EvMessage;
|
|
38
|
+
resize: EvWindowResize;
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
// singleton
|
|
@@ -104,6 +110,15 @@ export class Application<E extends ApplicationEvents = ApplicationEvents> extend
|
|
|
104
110
|
else {
|
|
105
111
|
window.addEventListener( "load", loaded, { once: true } );
|
|
106
112
|
}
|
|
113
|
+
|
|
114
|
+
const resize = ( ) => {
|
|
115
|
+
this.fire( "resize", {
|
|
116
|
+
width: window.innerWidth,
|
|
117
|
+
height: window.innerHeight,
|
|
118
|
+
} );
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
window.addEventListener('resize', resize, { passive: true });
|
|
107
122
|
}
|
|
108
123
|
|
|
109
124
|
/**
|
package/src/core/core_dom.ts
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
|
+
export const COMPONENT = Symbol( "component" );
|
|
18
|
+
|
|
17
19
|
/** @ignore this events must be defined on domNode (do not bubble) */
|
|
18
20
|
export const unbubbleEvents = {
|
|
19
21
|
mouseleave: 1, mouseenter: 1, load: 1, unload: 1, scroll: 1, focus: 1, blur: 1, rowexit: 1, beforeunload: 1, stop: 1,
|
|
@@ -33,9 +35,33 @@ let mutObserver: MutationObserver = null;
|
|
|
33
35
|
|
|
34
36
|
const observeMutation = (mutations: MutationRecord[], observer: MutationObserver): void => {
|
|
35
37
|
|
|
38
|
+
// moves are handled this way
|
|
39
|
+
const added = new Set<Node>( );
|
|
40
|
+
const removed = new Set<Node>( );
|
|
41
|
+
|
|
42
|
+
for( const mutation of mutations ) {
|
|
43
|
+
if( mutation.type == "childList" ) {
|
|
44
|
+
mutation.addedNodes.forEach( n => {
|
|
45
|
+
if( removed.has( n ) ) {
|
|
46
|
+
removed.delete( n );
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
added.add( n );
|
|
50
|
+
}
|
|
51
|
+
} );
|
|
52
|
+
|
|
53
|
+
mutation.removedNodes.forEach( n => {
|
|
54
|
+
if( added.has( n ) ) {
|
|
55
|
+
added.delete( n );
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
removed.add( n );
|
|
59
|
+
}
|
|
60
|
+
} );
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
36
64
|
const sendEvent = ( node: Node, code: "created" | "removed" ) => {
|
|
37
|
-
// console.log( "notify", node, code );
|
|
38
|
-
|
|
39
65
|
const store = event_handlers.get( node );
|
|
40
66
|
if ( store && store[code] ) {
|
|
41
67
|
node.dispatchEvent( new Event( code, {} ) );
|
|
@@ -53,26 +79,17 @@ const observeMutation = (mutations: MutationRecord[], observer: MutationObserver
|
|
|
53
79
|
}
|
|
54
80
|
|
|
55
81
|
if( !create ) {
|
|
82
|
+
const core = (node as any)[COMPONENT];
|
|
83
|
+
if( core && core.cleanUp ) { //<yes: dirty hack
|
|
84
|
+
core.cleanUp();
|
|
85
|
+
}
|
|
86
|
+
|
|
56
87
|
sendEvent( node, "removed" );
|
|
57
88
|
}
|
|
58
89
|
}
|
|
59
90
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if( mutation.type=="childList" ) {
|
|
63
|
-
if( mutation.addedNodes ) {
|
|
64
|
-
mutation.addedNodes.forEach( node => {
|
|
65
|
-
notify( node, true );
|
|
66
|
-
} );
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if( mutation.removedNodes ) {
|
|
70
|
-
mutation.removedNodes.forEach( node => {
|
|
71
|
-
notify( node, false );
|
|
72
|
-
} );
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
91
|
+
added.forEach( n => { if( n.isConnected ) notify( n, true ); } );
|
|
92
|
+
removed.forEach( n => { if( !n.isConnected ) notify( n, false ); } );
|
|
76
93
|
}
|
|
77
94
|
|
|
78
95
|
|
|
@@ -144,17 +161,27 @@ export function dispatchEvent(ev: Event) {
|
|
|
144
161
|
|
|
145
162
|
export function addEvent( node: Node, name: string, handler: DOMEventHandler, prepend = false ) {
|
|
146
163
|
|
|
164
|
+
if( !mutObserver ) {
|
|
165
|
+
mutObserver = new MutationObserver( observeMutation )
|
|
166
|
+
mutObserver.observe( document.body, {childList: true,subtree: true} );
|
|
167
|
+
}
|
|
168
|
+
|
|
147
169
|
if( name=="removed" || name=="created" ) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
170
|
+
const core = (node as any)[COMPONENT];
|
|
171
|
+
if( core && core.addClass ) { //<yes: dirty hack
|
|
172
|
+
core.addClass( "x4:mut")
|
|
151
173
|
}
|
|
152
174
|
}
|
|
153
175
|
else if( name=="resized" ) {
|
|
154
176
|
if (!sizeObserver) {
|
|
155
177
|
sizeObserver = new ResizeObserver( observeSize );
|
|
156
178
|
}
|
|
157
|
-
|
|
179
|
+
|
|
180
|
+
const core = (node as any)[COMPONENT];
|
|
181
|
+
if( core && core.addClass ) { //<yes: dirty hack
|
|
182
|
+
core.addClass( "x4:sze")
|
|
183
|
+
}
|
|
184
|
+
|
|
158
185
|
sizeObserver.observe( node as Element );
|
|
159
186
|
}
|
|
160
187
|
|
|
@@ -470,12 +497,3 @@ export interface GlobalDOMEvents {
|
|
|
470
497
|
created?: ( ev: Event ) => void; // occurs when inserted in the dom
|
|
471
498
|
removed?: ( ev: Event ) => void; // occurs when removed from dom
|
|
472
499
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
package/src/core/core_element.ts
CHANGED
|
@@ -17,6 +17,13 @@
|
|
|
17
17
|
import { EventMap, EventSource } from './core_events';
|
|
18
18
|
|
|
19
19
|
|
|
20
|
+
interface TimerEntry {
|
|
21
|
+
cb: Function;
|
|
22
|
+
id: number;
|
|
23
|
+
clear: Function;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
20
27
|
/**
|
|
21
28
|
* CoreElement
|
|
22
29
|
*
|
|
@@ -77,10 +84,14 @@ import { EventMap, EventSource } from './core_events';
|
|
|
77
84
|
* el.clearInterval("poll");
|
|
78
85
|
* ```
|
|
79
86
|
*/
|
|
87
|
+
|
|
80
88
|
export class CoreElement<E extends EventMap = EventMap> {
|
|
81
89
|
|
|
82
90
|
#events: EventSource<E>;
|
|
83
|
-
#timers: Map<string,
|
|
91
|
+
#timers: Map<string, TimerEntry>;
|
|
92
|
+
#cleanup: Function[];
|
|
93
|
+
|
|
94
|
+
/** changed to stop timers when object is down
|
|
84
95
|
|
|
85
96
|
private __startTimer( name: string, ms: number, repeat: boolean, callback: ( ) => void ) {
|
|
86
97
|
if (!this.#timers) {
|
|
@@ -102,6 +113,69 @@ export class CoreElement<E extends EventMap = EventMap> {
|
|
|
102
113
|
const clear = this.#timers?.get(name);
|
|
103
114
|
if (clear) { clear(); }
|
|
104
115
|
}
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
private __startTimer(name: string, ms: number, repeat: boolean, callback: () => void) {
|
|
119
|
+
if (!this.#timers) {
|
|
120
|
+
this.#timers = new Map();
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
this.__stopTimer(name);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Weak reference only: the native timer must not keep the element alive.
|
|
127
|
+
// The callback itself is stored in #timers, held by the element,
|
|
128
|
+
// so the element remains collectable while a timer is active.
|
|
129
|
+
const ref = new WeakRef(this); // avoid keeping a ref on this.
|
|
130
|
+
|
|
131
|
+
let tick: () => void;
|
|
132
|
+
|
|
133
|
+
if (repeat) {
|
|
134
|
+
tick = () => {
|
|
135
|
+
const self = ref.deref();
|
|
136
|
+
if (!self) {
|
|
137
|
+
clearInterval(id);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
self.#timers.get(name)!.cb();
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const id = setInterval( tick, ms );
|
|
145
|
+
|
|
146
|
+
this.#timers.set(name, {
|
|
147
|
+
cb: callback,
|
|
148
|
+
id,
|
|
149
|
+
clear( ) { clearInterval(id); }
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
tick = () => {
|
|
154
|
+
const self = ref.deref();
|
|
155
|
+
if (!self) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// One-shot: remove the entry before firing so the map stays clean.
|
|
160
|
+
self.#timers.delete(name);
|
|
161
|
+
callback();
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
this.#timers.set(name, {
|
|
165
|
+
cb: callback,
|
|
166
|
+
id: setTimeout(tick, ms),
|
|
167
|
+
clear() { clearTimeout(this.id); }
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private __stopTimer(name: string) {
|
|
173
|
+
const entry = this.#timers?.get(name);
|
|
174
|
+
if (entry) {
|
|
175
|
+
entry.clear();
|
|
176
|
+
this.#timers.delete(name);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
105
179
|
|
|
106
180
|
/**
|
|
107
181
|
* Sets a timeout that executes a callback function after a specified delay.
|
|
@@ -110,19 +184,19 @@ export class CoreElement<E extends EventMap = EventMap> {
|
|
|
110
184
|
* @param ms - The delay in milliseconds before the callback is executed.
|
|
111
185
|
* @param callback - The function to execute after the delay.
|
|
112
186
|
*/
|
|
113
|
-
|
|
114
|
-
setTimeout(
|
|
115
|
-
this.__startTimer(
|
|
187
|
+
|
|
188
|
+
setTimeout(name: string, ms: number, callback: () => void) {
|
|
189
|
+
this.__startTimer(name, ms, false, callback);
|
|
116
190
|
}
|
|
117
|
-
|
|
191
|
+
|
|
118
192
|
/**
|
|
119
193
|
* Clears a previously set timeout.
|
|
120
194
|
* @param name - The name of the timeout to clear.
|
|
121
195
|
* @see setTimeout
|
|
122
196
|
*/
|
|
123
197
|
|
|
124
|
-
clearTimeout(
|
|
125
|
-
this.__stopTimer(
|
|
198
|
+
clearTimeout(name: string) {
|
|
199
|
+
this.__stopTimer(name);
|
|
126
200
|
}
|
|
127
201
|
|
|
128
202
|
/**
|
|
@@ -133,8 +207,8 @@ export class CoreElement<E extends EventMap = EventMap> {
|
|
|
133
207
|
* @param callback - The function to execute after the delay.
|
|
134
208
|
*/
|
|
135
209
|
|
|
136
|
-
setInterval(
|
|
137
|
-
this.__startTimer(
|
|
210
|
+
setInterval(name: string, ms: number, callback: () => void) {
|
|
211
|
+
this.__startTimer(name, ms, true, callback);
|
|
138
212
|
}
|
|
139
213
|
|
|
140
214
|
/**
|
|
@@ -143,8 +217,8 @@ export class CoreElement<E extends EventMap = EventMap> {
|
|
|
143
217
|
* @see setInterval
|
|
144
218
|
*/
|
|
145
219
|
|
|
146
|
-
clearInterval(
|
|
147
|
-
this.__stopTimer(
|
|
220
|
+
clearInterval(name: string) {
|
|
221
|
+
this.__stopTimer(name);
|
|
148
222
|
}
|
|
149
223
|
|
|
150
224
|
/**
|
|
@@ -152,12 +226,40 @@ export class CoreElement<E extends EventMap = EventMap> {
|
|
|
152
226
|
* This stops all scheduled callbacks and removes their references.
|
|
153
227
|
* @see setTimeout
|
|
154
228
|
*/
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
229
|
+
|
|
230
|
+
clearTimeouts() {
|
|
231
|
+
if (!this.#timers) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Entries no longer mutate the map in clear(), so plain iteration is safe.
|
|
236
|
+
for (const entry of this.#timers.values()) {
|
|
237
|
+
entry.clear();
|
|
158
238
|
}
|
|
159
|
-
|
|
160
|
-
this.#timers.clear(
|
|
239
|
+
|
|
240
|
+
this.#timers.clear();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* add a cleanup function to the cleanup list
|
|
245
|
+
* @see cleanUp
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
addCleanup( fn : Function ) {
|
|
249
|
+
if( !this.#cleanup ) {
|
|
250
|
+
this.#cleanup = [];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
this.#cleanup.push( fn );
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* called when element is removed from dom
|
|
258
|
+
*/
|
|
259
|
+
|
|
260
|
+
cleanUp( ) {
|
|
261
|
+
this.clearTimeouts( );
|
|
262
|
+
this.#cleanup?.forEach( x => x() );
|
|
161
263
|
}
|
|
162
264
|
|
|
163
265
|
// :: EVENTS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
@@ -173,17 +275,17 @@ export class CoreElement<E extends EventMap = EventMap> {
|
|
|
173
275
|
* attach to an event
|
|
174
276
|
*/
|
|
175
277
|
|
|
176
|
-
on<K extends keyof E>(
|
|
177
|
-
console.assert(
|
|
278
|
+
on<K extends keyof E>(name: K, listener: (ev: E[K]) => void) {
|
|
279
|
+
console.assert(listener !== undefined && listener !== null);
|
|
178
280
|
|
|
179
|
-
if(
|
|
180
|
-
this.#events = new EventSource(
|
|
281
|
+
if (!this.#events) {
|
|
282
|
+
this.#events = new EventSource(this);
|
|
181
283
|
}
|
|
182
|
-
|
|
183
|
-
this.#events.addListener(
|
|
284
|
+
|
|
285
|
+
this.#events.addListener(name, listener);
|
|
184
286
|
return {
|
|
185
|
-
off: (
|
|
186
|
-
this.#events.removeListener(
|
|
287
|
+
off: () => {
|
|
288
|
+
this.#events.removeListener(name, listener);
|
|
187
289
|
}
|
|
188
290
|
}
|
|
189
291
|
}
|
|
@@ -197,11 +299,11 @@ export class CoreElement<E extends EventMap = EventMap> {
|
|
|
197
299
|
* @see fire
|
|
198
300
|
*/
|
|
199
301
|
|
|
200
|
-
off<K extends keyof E>(
|
|
201
|
-
console.assert(
|
|
302
|
+
off<K extends keyof E>(name: K, listener: (ev: E[K]) => void) {
|
|
303
|
+
console.assert(listener !== undefined && listener !== null);
|
|
202
304
|
|
|
203
|
-
if(
|
|
204
|
-
this.#events.removeListener(
|
|
305
|
+
if (this.#events) {
|
|
306
|
+
this.#events.removeListener(name, listener);
|
|
205
307
|
}
|
|
206
308
|
}
|
|
207
309
|
|
|
@@ -214,9 +316,9 @@ export class CoreElement<E extends EventMap = EventMap> {
|
|
|
214
316
|
* @see off
|
|
215
317
|
*/
|
|
216
318
|
|
|
217
|
-
fire<K extends keyof E>(
|
|
218
|
-
if(
|
|
219
|
-
this.#events.fire(
|
|
319
|
+
fire<K extends keyof E>(name: K, ev: E[K]) {
|
|
320
|
+
if (this.#events) {
|
|
321
|
+
this.#events.fire(name, ev);
|
|
220
322
|
}
|
|
221
323
|
}
|
|
222
324
|
}
|