lexgui 0.1.28 → 0.1.30

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.
@@ -8,12 +8,16 @@
8
8
  */
9
9
 
10
10
  var LX = {
11
- version: "0.1.28",
11
+ version: "0.1.30",
12
12
  ready: false,
13
13
  components: [], // specific pre-build components
14
14
  signals: {} // events and triggers
15
15
  };
16
16
 
17
+ LX.MOUSE_LEFT_CLICK = 0;
18
+ LX.MOUSE_MIDDLE_CLICK = 1;
19
+ LX.MOUSE_RIGHT_CLICK = 2;
20
+
17
21
  LX.MOUSE_DOUBLE_CLICK = 2;
18
22
  LX.MOUSE_TRIPLE_CLICK = 3;
19
23
 
@@ -75,27 +79,31 @@ function getBase64Image(img) {
75
79
 
76
80
  LX.getBase64Image = getBase64Image;
77
81
 
78
- function hexToRgb(string) {
79
- const red = parseInt(string.substring(1, 3), 16) / 255;
80
- const green = parseInt(string.substring(3, 5), 16) / 255;
81
- const blue = parseInt(string.substring(5, 7), 16) / 255;
82
- return [red, green, blue];
82
+ function hexToRgb( hexStr ) {
83
+ const red = parseInt( hexStr.substring( 1, 3 ), 16 ) / 255;
84
+ const green = parseInt( hexStr.substring( 3, 5 ), 16 ) / 255;
85
+ const blue = parseInt( hexStr.substring( 5, 7 ), 16 ) / 255;
86
+ return [ red, green, blue ];
83
87
  }
84
88
 
85
- function rgbToHex(rgb) {
89
+ LX.hexToRgb = hexToRgb;
90
+
91
+ function rgbToHex( rgb ) {
86
92
  let hex = "#";
87
- for(let c of rgb) {
88
- c = Math.floor(c * 255);
89
- hex += c.toString(16);
93
+ for( let c of rgb ) {
94
+ c = Math.floor( c * 255 );
95
+ hex += c.toString( 16 );
90
96
  }
91
97
  return hex;
92
98
  }
93
99
 
100
+ LX.rgbToHex = rgbToHex;
101
+
94
102
  function simple_guidGenerator() {
95
103
  var S4 = function() {
96
104
  return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
97
105
  };
98
- return (S4()+"-"+S4());
106
+ return (S4()+"-"+S4()+"-"+S4());
99
107
  }
100
108
 
101
109
  // Timer that works everywhere (from litegraph.js)
@@ -140,6 +148,7 @@ class vec2 {
140
148
  sub ( v, v0 = new vec2() ) { v0.set( this.x - v.x, this.y - v.y ); return v0; }
141
149
  mul ( v, v0 = new vec2() ) { if( v.constructor == Number ) { v = new vec2( v ) } v0.set( this.x * v.x, this.y * v.y ); return v0; }
142
150
  div ( v, v0 = new vec2() ) { if( v.constructor == Number ) { v = new vec2( v ) } v0.set( this.x / v.x, this.y / v.y ); return v0; }
151
+ abs ( v0 = new vec2() ) { v0.set( Math.abs( this.x ), Math.abs( this.y ) ); return v0; }
143
152
  };
144
153
 
145
154
  LX.vec2 = vec2;
@@ -153,45 +162,57 @@ function makeDraggable( domEl, options = { } ) {
153
162
  let currentTarget = null;
154
163
  let targetClass = options.targetClass;
155
164
 
156
- const moveFunc = (e) => {
157
- if(!currentTarget) return;
165
+ let id = LX.UTILS.uidGenerator();
166
+ domEl[ 'draggable-id' ] = id;
167
+
168
+ const defaultMoveFunc = e => {
169
+ if( !currentTarget ) return;
158
170
  let left = e.clientX - offsetX;
159
171
  let top = e.clientY - offsetY;
160
- if(left > 3 && (left + domEl.offsetWidth + 6) <= window.innerWidth)
172
+ if( left > 3 && ( left + domEl.offsetWidth + 6 ) <= window.innerWidth )
161
173
  domEl.style.left = left + 'px';
162
- if(top > 3 && (top + domEl.offsetHeight + 6) <= window.innerHeight)
174
+ if( top > 3 && ( top + domEl.offsetHeight + 6 ) <= window.innerHeight )
163
175
  domEl.style.top = top + 'px';
164
176
  };
165
177
 
166
- let onMove = options.onMove ?? moveFunc;
178
+ const customMoveFunc = e => {
179
+ if( !currentTarget ) return;
180
+ if( options.onMove )
181
+ options.onMove( currentTarget );
182
+ };
183
+
184
+ let onMove = options.onMove ? customMoveFunc : defaultMoveFunc;
185
+ let onDragStart = options.onDragStart;
167
186
 
168
- domEl.setAttribute('draggable', true);
169
- domEl.addEventListener("mousedown", function(e) {
187
+ domEl.setAttribute( 'draggable', true );
188
+ domEl.addEventListener( "mousedown", function( e ) {
170
189
  currentTarget = (e.target.classList.contains(targetClass) || !targetClass) ? e.target : null;
171
- });
190
+ } );
172
191
 
173
- domEl.addEventListener("dragstart", function(e) {
192
+ domEl.addEventListener( "dragstart", function( e ) {
174
193
  e.preventDefault();
175
194
  e.stopPropagation();
176
195
  e.stopImmediatePropagation();
177
- if(!currentTarget) return;
196
+ if( !currentTarget ) return;
178
197
  // Remove image when dragging
179
198
  var img = new Image();
180
199
  img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=';
181
- e.dataTransfer.setDragImage(img, 0, 0);
200
+ e.dataTransfer.setDragImage( img, 0, 0 );
182
201
  e.dataTransfer.effectAllowed = "move";
183
202
  const rect = e.target.getBoundingClientRect();
184
203
  offsetX = e.clientX - rect.x;
185
204
  offsetY = e.clientY - rect.y;
186
- document.addEventListener("mousemove", onMove );
187
- }, false);
205
+ document.addEventListener( "mousemove", onMove );
206
+ if( onDragStart )
207
+ onDragStart( currentTarget, e );
208
+ }, false );
188
209
 
189
- document.addEventListener('mouseup', () => {
190
- if(currentTarget) {
210
+ document.addEventListener( 'mouseup', () => {
211
+ if( currentTarget ) {
191
212
  currentTarget = null;
192
- document.removeEventListener("mousemove", onMove );
213
+ document.removeEventListener( "mousemove", onMove );
193
214
  }
194
- });
215
+ } );
195
216
  }
196
217
 
197
218
  LX.makeDraggable = makeDraggable;
@@ -397,33 +418,38 @@ function create_global_searchbar( root ) {
397
418
 
398
419
  /**
399
420
  * @method init
400
- * @param {*} options
421
+ * @param {Object} options
401
422
  * container: Root location for the gui (default is the document body)
423
+ * id: Id of the main area
402
424
  * skip_default_area: Skip creation of main area
403
425
  */
404
426
 
405
- function init(options = {})
427
+ function init( options = { } )
406
428
  {
407
- if(this.ready)
429
+ if( this.ready )
408
430
  return this.main_area;
409
431
 
410
- // LexGUI root
411
- var root = document.createElement("div");
432
+ // LexGUI root
433
+
434
+ var root = document.createElement( 'div' );
412
435
  root.id = "lexroot";
413
436
  root.tabIndex = -1;
414
437
 
415
- var modal = document.createElement("div");
438
+ var modal = document.createElement( 'div' );
416
439
  modal.id = "modal";
417
440
 
418
441
  this.modal = modal;
419
442
  this.root = root;
420
443
  this.container = document.body;
421
444
 
422
- this.modal.toggleAttribute('hidden', true);
423
- this.modal.toggle = function(force) { this.toggleAttribute('hidden', force); };
445
+ // this.modal.toggleAttribute( 'hidden', true );
446
+ // this.modal.toggle = function( force ) { this.toggleAttribute( 'hidden', force ); };
447
+
448
+ this.modal.classList.add( 'hiddenOpacity' );
449
+ this.modal.toggle = function( force ) { this.classList.toggle( 'hiddenOpacity', force ); };
424
450
 
425
- if(options.container)
426
- this.container = document.getElementById(options.container);
451
+ if( options.container )
452
+ this.container = document.getElementById( options.container );
427
453
 
428
454
  this.global_search = create_global_searchbar( this.container );
429
455
 
@@ -431,17 +457,17 @@ function init(options = {})
431
457
  this.container.appendChild( root );
432
458
 
433
459
  // Disable drag icon
434
- root.addEventListener("dragover", function(e) {
460
+ root.addEventListener( 'dragover', function( e ) {
435
461
  e.preventDefault();
436
462
  }, false );
437
463
 
438
464
  // CSS fontawesome
439
- var head = document.getElementsByTagName('HEAD')[0];
440
- var link = document.createElement('link');
465
+ var head = document.getElementsByTagName( 'HEAD' )[ 0 ];
466
+ var link = document.createElement( 'link' );
441
467
  link.rel = 'stylesheet';
442
468
  link.type = 'text/css';
443
- link.href = 'https://use.fontawesome.com/releases/v6.4.2/css/all.css';
444
- head.appendChild(link);
469
+ link.href = 'https://use.fontawesome.com/releases/v6.5.1/css/all.css';
470
+ head.appendChild( link );
445
471
 
446
472
  // Global vars
447
473
  this.DEFAULT_NAME_WIDTH = "30%";
@@ -449,10 +475,10 @@ function init(options = {})
449
475
  this.OPEN_CONTEXTMENU_ENTRY = 'click';
450
476
 
451
477
  this.ready = true;
452
- this.menubars = [];
478
+ this.menubars = [ ];
453
479
 
454
- if(!options.skip_default_area)
455
- this.main_area = new Area( {id: options.id ?? "mainarea"} );
480
+ if( !options.skip_default_area )
481
+ this.main_area = new Area( { id: options.id ?? 'mainarea' } );
456
482
 
457
483
  return this.main_area;
458
484
  }
@@ -1282,7 +1308,8 @@ class Area {
1282
1308
  selectable: b.selectable,
1283
1309
  selected: b.selected,
1284
1310
  icon: b.icon,
1285
- img: b.img
1311
+ img: b.img,
1312
+ className: b.class
1286
1313
  };
1287
1314
 
1288
1315
  if( group )
@@ -1492,7 +1519,7 @@ class Tabs {
1492
1519
 
1493
1520
  let container = document.createElement('div');
1494
1521
  container.className = "lexareatabs " + (options.fit ? "fit" : "row");
1495
-
1522
+
1496
1523
  const folding = options.folding ?? false;
1497
1524
  if(folding) container.classList.add("folding");
1498
1525
 
@@ -1544,6 +1571,29 @@ class Tabs {
1544
1571
  this.tabs = {};
1545
1572
  this.tabDOMs = {};
1546
1573
 
1574
+ if( options.fit )
1575
+ {
1576
+ // Create movable element
1577
+ let mEl = document.createElement('span');
1578
+ mEl.className = "lexareatab thumb";
1579
+ this.thumb = mEl;
1580
+ this.root.appendChild( mEl );
1581
+
1582
+ const resizeObserver = new ResizeObserver((entries) => {
1583
+ const tabEl = this.thumb.item;
1584
+ if( !tabEl ) return;
1585
+ var transition = this.thumb.style.transition;
1586
+ this.thumb.style.transition = "none";
1587
+ this.thumb.style.transform = "translate( " + ( tabEl.childIndex * tabEl.offsetWidth ) + "px )";
1588
+ this.thumb.style.width = ( tabEl.offsetWidth - 5 ) + "px";
1589
+ this.thumb.style.height = ( tabEl.offsetHeight - 6 ) + "px";
1590
+ flushCss( this.thumb );
1591
+ this.thumb.style.transition = transition;
1592
+ });
1593
+
1594
+ resizeObserver.observe( this.area.root );
1595
+ }
1596
+
1547
1597
  // debug
1548
1598
  if(folding)
1549
1599
  {
@@ -1641,6 +1691,14 @@ class Tabs {
1641
1691
 
1642
1692
  if(options.onSelect)
1643
1693
  options.onSelect(e, tabEl.dataset.name);
1694
+
1695
+ if( this.thumb )
1696
+ {
1697
+ this.thumb.style.transform = "translate( " + ( tabEl.childIndex * tabEl.offsetWidth ) + "px )";
1698
+ this.thumb.style.width = ( tabEl.offsetWidth - 5 ) + "px";
1699
+ this.thumb.style.height = ( tabEl.offsetHeight - 6 ) + "px";
1700
+ this.thumb.item = tabEl;
1701
+ }
1644
1702
  });
1645
1703
 
1646
1704
  tabEl.addEventListener("contextmenu", e => {
@@ -1669,13 +1727,26 @@ class Tabs {
1669
1727
  });
1670
1728
 
1671
1729
  // Attach content
1730
+ tabEl.childIndex = ( this.root.childElementCount - 1 );
1672
1731
  this.root.appendChild( tabEl );
1673
1732
  this.area.attach( contentEl );
1674
1733
  this.tabDOMs[ name ] = tabEl;
1675
1734
  this.tabs[ name ] = content;
1676
1735
 
1677
1736
  setTimeout( () => {
1678
- if( options.onCreate ) options.onCreate.call(this, this.area.root.getBoundingClientRect());
1737
+
1738
+ if( options.onCreate ) {
1739
+ options.onCreate.call(this, this.area.root.getBoundingClientRect());
1740
+ }
1741
+
1742
+ if( isSelected && this.thumb )
1743
+ {
1744
+ this.thumb.style.transform = "translate( " + ( tabEl.childIndex * tabEl.offsetWidth ) + "px )";
1745
+ this.thumb.style.width = ( tabEl.offsetWidth - 5 ) + "px";
1746
+ this.thumb.style.height = ( tabEl.offsetHeight - 6 ) + "px";
1747
+ this.thumb.item = tabEl;
1748
+ }
1749
+
1679
1750
  }, 10 );
1680
1751
  }
1681
1752
 
@@ -2170,6 +2241,7 @@ class SideBar {
2170
2241
  * @param {*} options:
2171
2242
  * callback: Function to call on each item
2172
2243
  * bottom: Bool to set item at the bottom as helper button (not selectable)
2244
+ * className: Add class to the entry DOM element
2173
2245
  */
2174
2246
 
2175
2247
  add( key, options = {} ) {
@@ -2186,14 +2258,14 @@ class SideBar {
2186
2258
  }
2187
2259
 
2188
2260
  let entry = document.createElement( 'div' );
2189
- entry.className = "lexsidebarentry";
2261
+ entry.className = "lexsidebarentry " + ( options.className ?? "" );
2190
2262
  entry.id = pKey;
2191
- entry.title = key;
2192
2263
 
2193
2264
  if( options.bottom )
2194
2265
  {
2195
2266
  this.footer.appendChild( entry );
2196
- }else
2267
+ }
2268
+ else
2197
2269
  {
2198
2270
  this.root.appendChild( entry );
2199
2271
  }
@@ -2205,6 +2277,11 @@ class SideBar {
2205
2277
  button.innerHTML = "<i class='"+ (options.icon ?? "") + "'></i>";
2206
2278
  entry.appendChild( button );
2207
2279
 
2280
+ let desc = document.createElement( 'span' );
2281
+ desc.className = 'lexsidebarentrydesc';
2282
+ desc.innerHTML = key;
2283
+ entry.appendChild( desc );
2284
+
2208
2285
  entry.addEventListener("click", () => {
2209
2286
 
2210
2287
  const f = options.callback;
@@ -2220,6 +2297,23 @@ class SideBar {
2220
2297
 
2221
2298
  this.items.push( { name: pKey, domEl: entry, callback: options.callback } );
2222
2299
  }
2300
+
2301
+ /**
2302
+ * @method select
2303
+ * @param {String} name Element name to select
2304
+ */
2305
+
2306
+ select( name ) {
2307
+
2308
+ let pKey = name.replace( /\s/g, '' ).replaceAll( '.', '' );
2309
+
2310
+ const entry = this.items.find( v => v.name === pKey );
2311
+
2312
+ if( !entry )
2313
+ return;
2314
+
2315
+ entry.domEl.click();
2316
+ }
2223
2317
  };
2224
2318
 
2225
2319
  LX.SideBar = SideBar;
@@ -3112,7 +3206,7 @@ class Panel {
3112
3206
 
3113
3207
  if( type != Widget.TITLE )
3114
3208
  {
3115
- element.style.width = "calc(100% - " + (this.current_branch || type == Widget.FILE ? 10 : 20) + "px)";
3209
+ element.style.width = "calc(100% - " + (this.current_branch || type == Widget.FILE || ( type == Widget.BUTTON && !name ) ? 10 : 20) + "px)";
3116
3210
  if( options.width ) {
3117
3211
  element.style.width = element.style.minWidth = options.width;
3118
3212
  }
@@ -3443,99 +3537,105 @@ class Panel {
3443
3537
 
3444
3538
  addText( name, value, callback, options = {} ) {
3445
3539
 
3446
- let widget = this.create_widget(name, Widget.TEXT, options);
3540
+ let widget = this.create_widget( name, Widget.TEXT, options );
3447
3541
  widget.onGetValue = () => {
3448
3542
  return wValue.value;
3449
3543
  };
3450
- widget.onSetValue = (new_value) => {
3451
- this.disabled ? wValue.innerText = new_value : wValue.value = new_value;
3452
- Panel._dispatch_event(wValue, "focusout");
3544
+ widget.onSetValue = newValue => {
3545
+ this.disabled ? wValue.innerText = newValue : wValue.value = newValue;
3546
+ Panel._dispatch_event( wValue, "focusout" );
3453
3547
  };
3454
3548
 
3455
3549
  let element = widget.domEl;
3456
3550
 
3457
3551
  // Add reset functionality
3458
- if(widget.name && !(options.skipReset ?? false)) {
3459
- Panel._add_reset_property(element.domName, function() {
3552
+ if( widget.name && !( options.skipReset ?? false ) ) {
3553
+ Panel._add_reset_property( element.domName, function() {
3460
3554
  wValue.value = wValue.iValue;
3461
3555
  this.style.display = "none";
3462
- Panel._dispatch_event(wValue, "focusout");
3463
- });
3556
+ Panel._dispatch_event( wValue, "focusout" );
3557
+ } );
3464
3558
  }
3465
3559
 
3466
3560
  // Add widget value
3467
3561
 
3468
- let container = document.createElement('div');
3469
- container.className = "lextext" + (options.warning ? " lexwarning" : "");
3562
+ let container = document.createElement( 'div' );
3563
+ container.className = "lextext" + ( options.warning ? " lexwarning" : "" );
3470
3564
  container.style.width = options.inputWidth || "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + " )";
3471
3565
  container.style.display = "flex";
3472
3566
 
3473
- this.disabled = (options.disabled || options.warning) ?? ( options.url ? true : false );
3567
+ this.disabled = ( options.disabled || options.warning ) ?? ( options.url ? true : false );
3474
3568
  let wValue = null;
3475
3569
 
3476
3570
  if( !this.disabled )
3477
3571
  {
3478
- wValue = document.createElement('input');
3572
+ wValue = document.createElement( 'input' );
3479
3573
  wValue.type = options.type || "";
3480
3574
  wValue.value = wValue.iValue = value || "";
3481
3575
  wValue.style.width = "100%";
3482
3576
  wValue.style.textAlign = options.float ?? "";
3483
3577
 
3484
- if(options.placeholder) wValue.setAttribute("placeholder", options.placeholder);
3578
+ if( options.placeholder )
3579
+ wValue.setAttribute( "placeholder", options.placeholder );
3485
3580
 
3486
- var resolve = (function(val, event) {
3487
- let btn = element.querySelector(".lexwidgetname .lexicon");
3488
- if(btn) btn.style.display = (val != wValue.iValue ? "block" : "none");
3489
- this._trigger( new IEvent(name, val, event), callback );
3490
- }).bind(this);
3581
+ var resolve = ( function( val, event ) {
3582
+ let btn = element.querySelector( ".lexwidgetname .lexicon" );
3583
+ if( btn ) btn.style.display = ( val != wValue.iValue ? "block" : "none" );
3584
+ this._trigger( new IEvent( name, val, event ), callback );
3585
+ }).bind( this );
3491
3586
 
3492
3587
  const trigger = options.trigger ?? 'default';
3493
3588
 
3494
- if(trigger == 'default')
3589
+ if( trigger == 'default' )
3495
3590
  {
3496
- wValue.addEventListener("keyup", function(e){
3591
+ wValue.addEventListener( "keyup", function( e ){
3497
3592
  if(e.key == 'Enter')
3498
- resolve(e.target.value, e);
3593
+ resolve( e.target.value, e );
3499
3594
  });
3500
- wValue.addEventListener("focusout", function(e){
3501
- resolve(e.target.value, e);
3595
+ wValue.addEventListener( "focusout", function( e ){
3596
+ resolve( e.target.value, e );
3502
3597
  });
3503
3598
  }
3504
- else if(trigger == 'input')
3599
+ else if( trigger == 'input' )
3505
3600
  {
3506
- wValue.addEventListener("input", function(e){
3507
- resolve(e.target.value, e);
3601
+ wValue.addEventListener("input", function( e ){
3602
+ resolve( e.target.value, e );
3508
3603
  });
3509
3604
  }
3510
3605
 
3511
- if(options.icon)
3606
+ wValue.addEventListener( "mousedown", function( e ){
3607
+ e.stopImmediatePropagation();
3608
+ e.stopPropagation();
3609
+ });
3610
+
3611
+ if( options.icon )
3512
3612
  {
3513
- let icon = document.createElement('a');
3613
+ let icon = document.createElement( 'a' );
3514
3614
  icon.className = "inputicon " + options.icon;
3515
- container.appendChild(icon);
3615
+ container.appendChild( icon );
3516
3616
  }
3517
3617
 
3518
3618
  } else
3519
3619
  {
3520
- wValue = document.createElement(options.url ? 'a' : 'div');
3521
- if(options.url)
3620
+ wValue = document.createElement( options.url ? 'a' : 'div' );
3621
+ if( options.url )
3522
3622
  {
3523
3623
  wValue.href = options.url;
3524
3624
  wValue.target = "_blank";
3525
3625
  }
3526
3626
  const icon = options.warning ? '<i class="fa-solid fa-triangle-exclamation"></i>' : '';
3527
- wValue.innerHTML = (icon + value) || "";
3627
+ wValue.innerHTML = ( icon + value ) || "";
3528
3628
  wValue.style.width = "100%";
3529
3629
  wValue.style.textAlign = options.float ?? "";
3530
3630
  }
3531
3631
 
3532
- Object.assign(wValue.style, options.style ?? {});
3632
+ Object.assign( wValue.style, options.style ?? {} );
3533
3633
 
3534
- container.appendChild(wValue);
3535
- element.appendChild(container);
3634
+ container.appendChild( wValue );
3635
+ element.appendChild( container );
3536
3636
 
3537
3637
  // Remove branch padding and margins
3538
- if(!widget.name) {
3638
+ if( !widget.name ) {
3539
3639
  element.className += " noname";
3540
3640
  container.style.width = "100%";
3541
3641
  }
@@ -3957,10 +4057,7 @@ class Panel {
3957
4057
  delete list.unfocus_event;
3958
4058
  return;
3959
4059
  }
3960
- let container = selectedOption.parentElement.parentElement.parentElement.parentElement; // there must be a nicer way...
3961
- let rect = event.currentTarget.getBoundingClientRect();
3962
- let y_pos = container.classList.contains('lexdialog') ? rect.top - 5 + rect.height : rect.y + rect.height - 5;
3963
- element.querySelector(".lexoptions").style.top = y_pos + 'px';
4060
+ element.querySelector(".lexoptions").style.top = (selectedOption.offsetTop + selectedOption.offsetHeight) + 'px';
3964
4061
  element.querySelector(".lexoptions").style.width = (event.currentTarget.clientWidth) + 'px';
3965
4062
  element.querySelector(".lexoptions").toggleAttribute('hidden');
3966
4063
  list.focus();
@@ -4369,7 +4466,7 @@ class Panel {
4369
4466
  buttonName = "Add item";
4370
4467
  buttonName += "<a class='fa-solid fa-plus' style='float:right; margin-right: 3px; margin-top: 2px;'></a>";
4371
4468
  this.addButton(null, buttonName, (v, event) => {
4372
- values.push( "" );
4469
+ values.push( options.innerValues ? options.innerValues[ 0 ] : "" );
4373
4470
  updateItems();
4374
4471
  this._trigger( new IEvent(name, values, event), callback );
4375
4472
  }, { buttonClass: 'array' });
@@ -4888,6 +4985,8 @@ class Panel {
4888
4985
  document.body.classList.add('nocursor');
4889
4986
  document.body.classList.add('noevents');
4890
4987
  drag_icon.classList.remove('hidden');
4988
+ e.stopImmediatePropagation();
4989
+ e.stopPropagation();
4891
4990
  }
4892
4991
 
4893
4992
  function inner_mousemove(e) {
@@ -5060,6 +5159,8 @@ class Panel {
5060
5159
  document.body.classList.add('nocursor');
5061
5160
  document.body.classList.add('noevents');
5062
5161
  drag_icon.classList.remove('hidden');
5162
+ e.stopImmediatePropagation();
5163
+ e.stopPropagation();
5063
5164
  }
5064
5165
 
5065
5166
  function inner_mousemove(e) {
@@ -5239,16 +5340,17 @@ class Panel {
5239
5340
  * @param {Function} callback Callback function on change
5240
5341
  * @param {*} options:
5241
5342
  * local: Ask for local file
5343
+ * read: Return the file itself (False) or the contents (True)
5242
5344
  * type: type to read as [text (Default), buffer, bin, url]
5243
5345
  */
5244
5346
 
5245
5347
  addFile( name, callback, options = { } ) {
5246
5348
 
5247
- if(!name) {
5248
- throw("Set Widget Name!");
5349
+ if( !name ) {
5350
+ throw( "Set Widget Name!" );
5249
5351
  }
5250
5352
 
5251
- let widget = this.create_widget(name, Widget.FILE, options);
5353
+ let widget = this.create_widget( name, Widget.FILE, options );
5252
5354
  let element = widget.domEl;
5253
5355
 
5254
5356
  let local = options.local ?? true;
@@ -5256,31 +5358,36 @@ class Panel {
5256
5358
  let read = options.read ?? true;
5257
5359
 
5258
5360
  // Create hidden input
5259
- let input = document.createElement('input');
5361
+ let input = document.createElement( 'input' );
5260
5362
  input.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + " - 10%)";
5261
5363
  input.type = 'file';
5262
- if(options.placeholder)
5364
+
5365
+ if( options.placeholder )
5263
5366
  input.placeholder = options.placeholder;
5264
5367
 
5265
- input.addEventListener('change', function(e) {
5368
+ input.addEventListener( 'change', function( e ) {
5369
+
5266
5370
  const files = e.target.files;
5267
5371
  if( !files.length ) return;
5268
- if(read)
5372
+ if( read )
5269
5373
  {
5374
+ if( options.onBeforeRead )
5375
+ options.onBeforeRead();
5376
+
5270
5377
  const reader = new FileReader();
5271
5378
 
5272
- if(type === 'text') reader.readAsText(files[0]);
5273
- else if(type === 'buffer') reader.readAsArrayBuffer(files[0]);
5274
- else if(type === 'bin') reader.readAsBinaryString(files[0]);
5275
- else if(type === 'url') reader.readAsDataURL(files[0]);
5379
+ if( type === 'text' ) reader.readAsText( files[ 0 ] );
5380
+ else if( type === 'buffer' ) reader.readAsArrayBuffer( files[ 0 ] );
5381
+ else if( type === 'bin' ) reader.readAsBinaryString( files[ 0 ] );
5382
+ else if( type === 'url' ) reader.readAsDataURL( files[ 0 ] );
5276
5383
 
5277
- reader.onload = (e) => { callback.call( this, e.target.result, files[0] ) } ;
5384
+ reader.onload = e => { callback.call( this, e.target.result, files[ 0 ] ) } ;
5278
5385
  }
5279
- else callback(files[0]);
5280
-
5386
+ else
5387
+ callback( files[ 0 ] );
5281
5388
  });
5282
5389
 
5283
- element.appendChild(input);
5390
+ element.appendChild( input );
5284
5391
 
5285
5392
  this.queue( element );
5286
5393
 
@@ -5288,9 +5395,9 @@ class Panel {
5288
5395
  {
5289
5396
  this.addButton(null, "<a style='margin-top: 0px;' class='fa-solid fa-gear'></a>", () => {
5290
5397
 
5291
- new Dialog("Load Settings", p => {
5292
- p.addDropdown("Type", ['text', 'buffer', 'bin', 'url'], type, v => { type = v } );
5293
- p.addButton(null, "Reload", v => { input.dispatchEvent( new Event('change') ) } );
5398
+ new Dialog( "Load Settings", p => {
5399
+ p.addDropdown( "Type", [ 'text', 'buffer', 'bin', 'url' ], type, v => { type = v } );
5400
+ p.addButton( null, "Reload", v => { input.dispatchEvent( new Event( 'change' ) ) } );
5294
5401
  });
5295
5402
 
5296
5403
  }, { className: "micro", skipInlineCount: true });
@@ -5844,6 +5951,7 @@ class Dialog {
5844
5951
  }
5845
5952
 
5846
5953
  destroy() {
5954
+
5847
5955
  this.root.remove();
5848
5956
  }
5849
5957
 
@@ -5858,6 +5966,14 @@ class Dialog {
5858
5966
  this.root.style.left = x + "px";
5859
5967
  this.root.style.top = y + "px";
5860
5968
  }
5969
+
5970
+ setTitle( title ) {
5971
+
5972
+ const titleDOM = this.root.querySelector( '.lexdialogtitle' );
5973
+ if( !titleDOM )
5974
+ return;
5975
+ titleDOM.innerText = title;
5976
+ }
5861
5977
  }
5862
5978
 
5863
5979
  LX.Dialog = Dialog;
@@ -5887,8 +6003,10 @@ class PocketDialog extends Dialog {
5887
6003
 
5888
6004
  // Custom
5889
6005
  this.root.classList.add( "pocket" );
5890
- this.root.style.left = "calc(100% - " + (this.root.offsetWidth + 6) + "px)";
5891
- this.root.style.top = "0px";
6006
+ if( !options.position ) {
6007
+ this.root.style.left = "calc(100% - " + (this.root.offsetWidth + 6) + "px)";
6008
+ this.root.style.top = "0px";
6009
+ }
5892
6010
  this.panel.root.style.width = "calc( 100% - 12px )";
5893
6011
  this.panel.root.style.height = "calc( 100% - 40px )";
5894
6012
  this.dock_pos = PocketDialog.TOP;
@@ -5927,7 +6045,7 @@ class PocketDialog extends Dialog {
5927
6045
  this.root.style.top = "calc(100% - " + (this.root.offsetHeight + 6) + "px)";
5928
6046
  break;
5929
6047
  case 'l':
5930
- this.root.style.left = "0px";
6048
+ this.root.style.left = options.position ? options.position[ 1 ] : "0px";
5931
6049
  break;
5932
6050
  }
5933
6051
  }
@@ -6032,7 +6150,7 @@ class ContextMenu {
6032
6150
  contextmenu.style.marginTop = 3.5 - c.offsetHeight + "px";
6033
6151
 
6034
6152
  // Set final width
6035
- contextmenu.style.width = contextmenu.offsetWidth + "px";
6153
+ // contextmenu.style.width = contextmenu.offsetWidth + "px";
6036
6154
  this._adjust_position( contextmenu, 6, true );
6037
6155
  }
6038
6156
 
@@ -7480,9 +7598,15 @@ Object.defineProperty(String.prototype, 'lastChar', {
7480
7598
  configurable: true
7481
7599
  });
7482
7600
 
7483
- Element.prototype.insertChildAtIndex = function(child, index = Infinity) {
7484
- if (index >= this.children.length) this.appendChild(child);
7485
- else this.insertBefore(child, this.children[index]);
7601
+ Element.prototype.insertChildAtIndex = function( child, index = Infinity ) {
7602
+ if ( index >= this.children.length ) this.appendChild( child );
7603
+ else this.insertBefore( child, this.children[index] );
7604
+ }
7605
+
7606
+ Element.prototype.hasClass = function( list ) {
7607
+ list = [].concat( list );
7608
+ var r = list.filter( v => this.classList.contains( v ) );
7609
+ return !!r.length;
7486
7610
  }
7487
7611
 
7488
7612
  Element.prototype.getComputedSize = function() {
@@ -7498,7 +7622,14 @@ LX.UTILS = {
7498
7622
  compareThreshold( v, p, n, t ) { return Math.abs(v - p) >= t || Math.abs(v - n) >= t },
7499
7623
  compareThresholdRange( v0, v1, t0, t1 ) { return v0 >= t0 && v0 <= t1 || v1 >= t0 && v1 <= t1 || v0 <= t0 && v1 >= t1},
7500
7624
  clamp (num, min, max) { return Math.min(Math.max(num, min), max) },
7501
-
7625
+ uidGenerator: simple_guidGenerator,
7626
+ deleteElement( el ) { if( el ) el.remove(); },
7627
+ flushCss(element) {
7628
+ // By reading the offsetHeight property, we are forcing
7629
+ // the browser to flush the pending CSS changes (which it
7630
+ // does to ensure the value obtained is accurate).
7631
+ element.offsetHeight;
7632
+ },
7502
7633
  getControlPoints( x0, y0, x1, y1, x2, y2, t ) {
7503
7634
 
7504
7635
  // x0,y0,x1,y1 are the coordinates of the end (knot) pts of this segment
@@ -7523,7 +7654,6 @@ LX.UTILS = {
7523
7654
 
7524
7655
  return [p1x,p1y,p2x,p2y]
7525
7656
  },
7526
-
7527
7657
  drawSpline( ctx, pts, t ) {
7528
7658
 
7529
7659
  ctx.save();