lexgui 0.1.46 → 0.4.0
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/build/components/codeeditor.js +12 -10
- package/build/components/timeline.js +47 -25
- package/build/lexgui.css +1220 -384
- package/build/lexgui.js +9388 -7800
- package/build/lexgui.min.css +1 -0
- package/build/lexgui.min.js +1 -0
- package/build/lexgui.module.js +2237 -668
- package/build/lexgui.module.min.js +1 -0
- package/changelog.md +56 -2
- package/demo.js +86 -873
- package/examples/index.html +0 -3
- package/examples/previews/side_bar.png +0 -0
- package/examples/side_bar.html +43 -11
- package/package.json +1 -1
package/build/lexgui.module.js
CHANGED
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
var LX = {
|
|
11
|
-
version: "0.
|
|
11
|
+
version: "0.4.0",
|
|
12
12
|
ready: false,
|
|
13
|
-
components: [], //
|
|
14
|
-
signals: {} //
|
|
13
|
+
components: [], // Specific pre-build components
|
|
14
|
+
signals: {}, // Events and triggers
|
|
15
|
+
extraCommandbarEntries: [], // User specific entries for command bar
|
|
16
|
+
activeDraggable: null // Watch for the current active draggable
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
LX.MOUSE_LEFT_CLICK = 0;
|
|
@@ -24,6 +26,8 @@ LX.MOUSE_TRIPLE_CLICK = 3;
|
|
|
24
26
|
LX.CURVE_MOVEOUT_CLAMP = 0;
|
|
25
27
|
LX.CURVE_MOVEOUT_DELETE = 1;
|
|
26
28
|
|
|
29
|
+
LX.DRAGGABLE_Z_INDEX = 101;
|
|
30
|
+
|
|
27
31
|
function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
|
|
28
32
|
function round( number, precision ) { return precision == 0 ? Math.floor( number ) : +(( number ).toFixed( precision ?? 2 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' )); }
|
|
29
33
|
function remapRange( oldValue, oldMin, oldMax, newMin, newMax ) { return ((( oldValue - oldMin ) * ( newMax - newMin )) / ( oldMax - oldMin )) + newMin; }
|
|
@@ -83,7 +87,7 @@ LX.doAsync = doAsync;
|
|
|
83
87
|
*/
|
|
84
88
|
function getSupportedDOMName( text )
|
|
85
89
|
{
|
|
86
|
-
return text.replace(/\s/g, '').replaceAll('@', '_').replaceAll('+', '_plus_').replaceAll('.', '');
|
|
90
|
+
return text.replace( /\s/g, '' ).replaceAll('@', '_').replaceAll('+', '_plus_').replaceAll( '.', '' );
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
LX.getSupportedDOMName = getSupportedDOMName;
|
|
@@ -161,12 +165,13 @@ function getThemeColor( colorName )
|
|
|
161
165
|
{
|
|
162
166
|
const r = getComputedStyle( document.querySelector( ':root' ) );
|
|
163
167
|
const value = r.getPropertyValue( '--' + colorName );
|
|
168
|
+
const theme = document.documentElement.getAttribute( "data-theme" );
|
|
164
169
|
|
|
165
|
-
if( value.includes( "light-dark" )
|
|
170
|
+
if( value.includes( "light-dark" ) )
|
|
166
171
|
{
|
|
167
172
|
const currentScheme = r.getPropertyValue( "color-scheme" );
|
|
168
173
|
|
|
169
|
-
if(
|
|
174
|
+
if( currentScheme == "light" )
|
|
170
175
|
{
|
|
171
176
|
return value.substring( value.indexOf( '(' ) + 1, value.indexOf( ',' ) ).replace( /\s/g, '' );
|
|
172
177
|
}
|
|
@@ -221,7 +226,8 @@ LX.hexToRgb = hexToRgb;
|
|
|
221
226
|
function rgbToHex( rgb )
|
|
222
227
|
{
|
|
223
228
|
let hex = "#";
|
|
224
|
-
for( let c of rgb )
|
|
229
|
+
for( let c of rgb )
|
|
230
|
+
{
|
|
225
231
|
c = Math.floor( c * 255 );
|
|
226
232
|
hex += c.toString( 16 );
|
|
227
233
|
}
|
|
@@ -296,7 +302,7 @@ LX.buildTextPattern = buildTextPattern;
|
|
|
296
302
|
|
|
297
303
|
/**
|
|
298
304
|
* @method makeDraggable
|
|
299
|
-
* @description
|
|
305
|
+
* @description Allows an element to be dragged
|
|
300
306
|
* @param {Element} domEl
|
|
301
307
|
* @param {Object} options
|
|
302
308
|
* autoAdjust (Bool): Sets in a correct position at the beggining
|
|
@@ -321,6 +327,7 @@ function makeDraggable( domEl, options = { } )
|
|
|
321
327
|
top = top ?? e.clientY - offsetY - parentRect.y;
|
|
322
328
|
domEl.style.left = clamp( left, dragMargin + fixedOffset.x, fixedOffset.x + parentRect.width - domEl.offsetWidth - dragMargin ) + 'px';
|
|
323
329
|
domEl.style.top = clamp( top, dragMargin + fixedOffset.y, fixedOffset.y + parentRect.height - domEl.offsetHeight - dragMargin ) + 'px';
|
|
330
|
+
domEl.style.translate = "none"; // Force remove translation
|
|
324
331
|
};
|
|
325
332
|
|
|
326
333
|
// Initial adjustment
|
|
@@ -365,26 +372,45 @@ function makeDraggable( domEl, options = { } )
|
|
|
365
372
|
e.preventDefault();
|
|
366
373
|
e.stopPropagation();
|
|
367
374
|
e.stopImmediatePropagation();
|
|
368
|
-
|
|
375
|
+
|
|
376
|
+
if( !currentTarget )
|
|
377
|
+
{
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
369
381
|
// Remove image when dragging
|
|
370
382
|
var img = new Image();
|
|
371
383
|
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=';
|
|
372
384
|
e.dataTransfer.setDragImage( img, 0, 0 );
|
|
373
385
|
e.dataTransfer.effectAllowed = "move";
|
|
386
|
+
|
|
374
387
|
const rect = e.target.getBoundingClientRect();
|
|
375
388
|
const parentRect = currentTarget.parentElement.getBoundingClientRect();
|
|
376
389
|
const isFixed = ( currentTarget.style.position == "fixed" );
|
|
377
390
|
const fixedOffset = isFixed ? new LX.vec2( parentRect.x, parentRect.y ) : new LX.vec2();
|
|
378
391
|
offsetX = e.clientX - rect.x - fixedOffset.x;
|
|
379
392
|
offsetY = e.clientY - rect.y - fixedOffset.y;
|
|
393
|
+
|
|
380
394
|
document.addEventListener( "mousemove", onMove );
|
|
395
|
+
|
|
396
|
+
currentTarget._eventCatched = true;
|
|
397
|
+
|
|
398
|
+
// Force active dialog to show on top
|
|
399
|
+
if( LX.activeDraggable )
|
|
400
|
+
{
|
|
401
|
+
LX.activeDraggable.style.zIndex = LX.DRAGGABLE_Z_INDEX;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
LX.activeDraggable = domEl;
|
|
405
|
+
LX.activeDraggable.style.zIndex = LX.DRAGGABLE_Z_INDEX + 1;
|
|
406
|
+
|
|
381
407
|
if( onDragStart )
|
|
382
408
|
{
|
|
383
409
|
onDragStart( currentTarget, e );
|
|
384
410
|
}
|
|
385
411
|
}, false );
|
|
386
412
|
|
|
387
|
-
document.addEventListener( 'mouseup', () => {
|
|
413
|
+
document.addEventListener( 'mouseup', (e) => {
|
|
388
414
|
if( currentTarget )
|
|
389
415
|
{
|
|
390
416
|
currentTarget = null;
|
|
@@ -395,6 +421,48 @@ function makeDraggable( domEl, options = { } )
|
|
|
395
421
|
|
|
396
422
|
LX.makeDraggable = makeDraggable;
|
|
397
423
|
|
|
424
|
+
/**
|
|
425
|
+
* @method makeCollapsible
|
|
426
|
+
* @description Allows an element to be collapsed/expanded
|
|
427
|
+
* @param {Element} domEl: Element to be treated as collapsible
|
|
428
|
+
* @param {Element} content: Content to display/hide on collapse/extend
|
|
429
|
+
* @param {Element} parent: Element where the content will be appended (default is domEl.parent)
|
|
430
|
+
* @param {Object} options
|
|
431
|
+
*/
|
|
432
|
+
function makeCollapsible( domEl, content, parent, options = { } )
|
|
433
|
+
{
|
|
434
|
+
domEl.classList.add( "collapsible" );
|
|
435
|
+
|
|
436
|
+
const collapsed = ( options.collapsed ?? true );
|
|
437
|
+
const actionIcon = LX.makeIcon( "Right" );
|
|
438
|
+
actionIcon.classList.add( "collapser" );
|
|
439
|
+
actionIcon.dataset[ "collapsed" ] = collapsed;
|
|
440
|
+
actionIcon.style.marginLeft = "auto";
|
|
441
|
+
|
|
442
|
+
actionIcon.addEventListener( "click", function(e) {
|
|
443
|
+
e.preventDefault();
|
|
444
|
+
e.stopPropagation();
|
|
445
|
+
if( this.dataset[ "collapsed" ] )
|
|
446
|
+
{
|
|
447
|
+
delete this.dataset[ "collapsed" ];
|
|
448
|
+
content.style.display = "block";
|
|
449
|
+
}
|
|
450
|
+
else
|
|
451
|
+
{
|
|
452
|
+
this.dataset[ "collapsed" ] = true;
|
|
453
|
+
content.style.display = "none";
|
|
454
|
+
}
|
|
455
|
+
} );
|
|
456
|
+
|
|
457
|
+
domEl.appendChild( actionIcon );
|
|
458
|
+
|
|
459
|
+
parent = parent ?? domEl.parentElement;
|
|
460
|
+
|
|
461
|
+
parent.appendChild( content );
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
LX.makeCollapsible = makeCollapsible;
|
|
465
|
+
|
|
398
466
|
/**
|
|
399
467
|
* @method makeCodeSnippet
|
|
400
468
|
* @description Create a code snippet in a specific language
|
|
@@ -404,6 +472,9 @@ LX.makeDraggable = makeDraggable;
|
|
|
404
472
|
* language (String):
|
|
405
473
|
* windowMode (Boolean):
|
|
406
474
|
* lineNumbers (Boolean):
|
|
475
|
+
* firstLine (Number): TODO
|
|
476
|
+
* linesAdded (Array):
|
|
477
|
+
* linesRemoved (Array):
|
|
407
478
|
* tabName (String):
|
|
408
479
|
*/
|
|
409
480
|
function makeCodeSnippet( code, size, options = { } )
|
|
@@ -416,16 +487,15 @@ function makeCodeSnippet( code, size, options = { } )
|
|
|
416
487
|
|
|
417
488
|
const snippet = document.createElement( "div" );
|
|
418
489
|
snippet.className = "lexcodesnippet";
|
|
419
|
-
snippet.style.width = size[ 0 ];
|
|
420
|
-
snippet.style.height = size[ 1 ];
|
|
490
|
+
snippet.style.width = size ? size[ 0 ] : "auto";
|
|
491
|
+
snippet.style.height = size ? size[ 1 ] : "auto";
|
|
421
492
|
const area = new Area( { noAppend: true } );
|
|
422
493
|
let editor = new LX.CodeEditor( area, {
|
|
423
494
|
skipInfo: true,
|
|
424
495
|
disableEdition: true,
|
|
425
496
|
allowAddScripts: false,
|
|
426
497
|
name: options.tabName,
|
|
427
|
-
// showTab: options.showTab ?? true
|
|
428
|
-
// lineNumbers: options.lineNumbers ?? true
|
|
498
|
+
// showTab: options.showTab ?? true
|
|
429
499
|
} );
|
|
430
500
|
editor.setText( code, options.language ?? "Plain Text" );
|
|
431
501
|
|
|
@@ -484,12 +554,47 @@ function makeCodeSnippet( code, size, options = { } )
|
|
|
484
554
|
tabs.prepend( windowActionButtons );
|
|
485
555
|
}
|
|
486
556
|
|
|
557
|
+
if( !( options.lineNumbers ?? true ) )
|
|
558
|
+
{
|
|
559
|
+
editor.root.classList.add( "no-gutter" );
|
|
560
|
+
}
|
|
561
|
+
|
|
487
562
|
snippet.appendChild( area.root );
|
|
488
563
|
return snippet;
|
|
489
564
|
}
|
|
490
565
|
|
|
491
566
|
LX.makeCodeSnippet = makeCodeSnippet;
|
|
492
567
|
|
|
568
|
+
/**
|
|
569
|
+
* @method makeIcon
|
|
570
|
+
* @description Gets an SVG element using one of LX.ICONS
|
|
571
|
+
* @param {String} iconName
|
|
572
|
+
* @param {String} iconTitle
|
|
573
|
+
*/
|
|
574
|
+
function makeIcon( iconName, iconTitle )
|
|
575
|
+
{
|
|
576
|
+
const icon = document.createElement( "a" );
|
|
577
|
+
icon.title = iconTitle ?? "";
|
|
578
|
+
icon.className = "lexicon";
|
|
579
|
+
icon.innerHTML = LX.ICONS[ iconName ] ?? "";
|
|
580
|
+
return icon;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
LX.makeIcon = makeIcon;
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* @method registerCommandbarEntry
|
|
587
|
+
* @description Adds an extra command bar entry
|
|
588
|
+
* @param {String} name
|
|
589
|
+
* @param {Function} callback
|
|
590
|
+
*/
|
|
591
|
+
function registerCommandbarEntry( name, callback )
|
|
592
|
+
{
|
|
593
|
+
LX.extraCommandbarEntries.push( { name, callback } );
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
LX.registerCommandbarEntry = registerCommandbarEntry;
|
|
597
|
+
|
|
493
598
|
// Math classes
|
|
494
599
|
|
|
495
600
|
class vec2 {
|
|
@@ -518,24 +623,23 @@ class vec2 {
|
|
|
518
623
|
|
|
519
624
|
LX.vec2 = vec2;
|
|
520
625
|
|
|
521
|
-
function
|
|
626
|
+
function _createCommandbar( root )
|
|
522
627
|
{
|
|
523
|
-
let
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
root.appendChild( globalSearch );
|
|
628
|
+
let commandbar = document.createElement( "dialog" );
|
|
629
|
+
commandbar.className = "commandbar";
|
|
630
|
+
commandbar.tabIndex = -1;
|
|
631
|
+
root.appendChild( commandbar );
|
|
528
632
|
|
|
529
633
|
let allItems = [];
|
|
530
634
|
let hoverElId = null;
|
|
531
635
|
|
|
532
|
-
|
|
636
|
+
commandbar.addEventListener('keydown', function( e ) {
|
|
533
637
|
e.stopPropagation();
|
|
534
638
|
e.stopImmediatePropagation();
|
|
535
639
|
hoverElId = hoverElId ?? -1;
|
|
536
640
|
if( e.key == 'Escape' )
|
|
537
641
|
{
|
|
538
|
-
this.
|
|
642
|
+
this.close();
|
|
539
643
|
_resetBar( true );
|
|
540
644
|
}
|
|
541
645
|
else if( e.key == 'Enter' )
|
|
@@ -544,7 +648,7 @@ function create_global_searchbar( root )
|
|
|
544
648
|
if( el )
|
|
545
649
|
{
|
|
546
650
|
const isCheckbox = (el.item.type && el.item.type === 'checkbox');
|
|
547
|
-
this.
|
|
651
|
+
this.close();
|
|
548
652
|
if( isCheckbox )
|
|
549
653
|
{
|
|
550
654
|
el.item.checked = !el.item.checked;
|
|
@@ -559,7 +663,7 @@ function create_global_searchbar( root )
|
|
|
559
663
|
else if ( e.key == 'ArrowDown' && hoverElId < (allItems.length - 1) )
|
|
560
664
|
{
|
|
561
665
|
hoverElId++;
|
|
562
|
-
|
|
666
|
+
commandbar.querySelectorAll(".hovered").forEach(e => e.classList.remove('hovered'));
|
|
563
667
|
allItems[ hoverElId ].classList.add('hovered');
|
|
564
668
|
|
|
565
669
|
let dt = allItems[ hoverElId ].offsetHeight * (hoverElId + 1) - itemContainer.offsetHeight;
|
|
@@ -574,19 +678,19 @@ function create_global_searchbar( root )
|
|
|
574
678
|
} else if ( e.key == 'ArrowUp' && hoverElId > 0 )
|
|
575
679
|
{
|
|
576
680
|
hoverElId--;
|
|
577
|
-
|
|
681
|
+
commandbar.querySelectorAll(".hovered").forEach(e => e.classList.remove('hovered'));
|
|
578
682
|
allItems[ hoverElId ].classList.add('hovered');
|
|
579
683
|
}
|
|
580
684
|
});
|
|
581
685
|
|
|
582
|
-
|
|
686
|
+
commandbar.addEventListener('focusout', function( e ) {
|
|
583
687
|
if( e.relatedTarget == e.currentTarget )
|
|
584
688
|
{
|
|
585
689
|
return;
|
|
586
690
|
}
|
|
587
691
|
e.stopPropagation();
|
|
588
692
|
e.stopImmediatePropagation();
|
|
589
|
-
this.
|
|
693
|
+
this.close();
|
|
590
694
|
_resetBar( true );
|
|
591
695
|
});
|
|
592
696
|
|
|
@@ -595,9 +699,7 @@ function create_global_searchbar( root )
|
|
|
595
699
|
{
|
|
596
700
|
e.stopImmediatePropagation();
|
|
597
701
|
e.stopPropagation();
|
|
598
|
-
|
|
599
|
-
globalSearch.querySelector('input').focus();
|
|
600
|
-
_addElements( undefined );
|
|
702
|
+
LX.setCommandbarState( true );
|
|
601
703
|
}
|
|
602
704
|
else
|
|
603
705
|
{
|
|
@@ -675,22 +777,22 @@ function create_global_searchbar( root )
|
|
|
675
777
|
const isCheckbox = (i && i.type && i.type === 'checkbox');
|
|
676
778
|
if( isCheckbox )
|
|
677
779
|
{
|
|
678
|
-
searchItem.innerHTML = "<a class='fa fa-check'></a><span>" + p + t + "</span>"
|
|
780
|
+
searchItem.innerHTML = "<a class='fa fa-check'></a><span>" + ( p + t ) + "</span>"
|
|
679
781
|
}
|
|
680
782
|
else
|
|
681
783
|
{
|
|
682
|
-
searchItem.innerHTML = p + t;
|
|
784
|
+
searchItem.innerHTML = ( p + t );
|
|
683
785
|
}
|
|
684
786
|
searchItem.entry_name = t;
|
|
685
787
|
searchItem.callback = c;
|
|
686
788
|
searchItem.item = i;
|
|
687
789
|
searchItem.addEventListener('click', function(e) {
|
|
688
|
-
this.callback.call(window, this.entry_name);
|
|
689
|
-
|
|
790
|
+
this.callback.call( window, this.entry_name );
|
|
791
|
+
LX.setCommandbarState( false );
|
|
690
792
|
_resetBar( true );
|
|
691
793
|
});
|
|
692
794
|
searchItem.addEventListener('mouseenter', function(e) {
|
|
693
|
-
|
|
795
|
+
commandbar.querySelectorAll(".hovered").forEach(e => e.classList.remove('hovered'));
|
|
694
796
|
this.classList.add('hovered');
|
|
695
797
|
hoverElId = allItems.indexOf( this );
|
|
696
798
|
});
|
|
@@ -724,7 +826,7 @@ function create_global_searchbar( root )
|
|
|
724
826
|
_propagateAdd( c, filter, path );
|
|
725
827
|
};
|
|
726
828
|
|
|
727
|
-
|
|
829
|
+
commandbar._addElements = filter => {
|
|
728
830
|
|
|
729
831
|
_resetBar();
|
|
730
832
|
|
|
@@ -736,15 +838,25 @@ function create_global_searchbar( root )
|
|
|
736
838
|
}
|
|
737
839
|
}
|
|
738
840
|
|
|
841
|
+
for( let entry of LX.extraCommandbarEntries )
|
|
842
|
+
{
|
|
843
|
+
const name = entry.name;
|
|
844
|
+
if( !name.toLowerCase().includes( filter ) )
|
|
845
|
+
{
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
_addElement( name, entry.callback, "", {} );
|
|
849
|
+
}
|
|
850
|
+
|
|
739
851
|
if( LX.has('CodeEditor') )
|
|
740
852
|
{
|
|
741
853
|
const instances = LX.CodeEditor.getInstances();
|
|
742
|
-
if(!instances.length) return;
|
|
854
|
+
if( !instances.length ) return;
|
|
743
855
|
|
|
744
856
|
const languages = instances[ 0 ].languages;
|
|
745
857
|
|
|
746
|
-
for( let l of Object.keys( languages ) )
|
|
747
|
-
|
|
858
|
+
for( let l of Object.keys( languages ) )
|
|
859
|
+
{
|
|
748
860
|
const key = "Language: " + l;
|
|
749
861
|
const icon = instances[ 0 ]._getFileIcon( null, languages[ l ].ext );
|
|
750
862
|
|
|
@@ -752,9 +864,11 @@ function create_global_searchbar( root )
|
|
|
752
864
|
"<img src='" + ( "https://raw.githubusercontent.com/jxarco/lexgui.js/master/" + icon ) + "'>";
|
|
753
865
|
|
|
754
866
|
value += key + " <span class='lang-ext'>(" + languages[ l ].ext + ")</span>";
|
|
755
|
-
if( key.toLowerCase().includes( filter ) )
|
|
756
|
-
|
|
757
|
-
|
|
867
|
+
if( key.toLowerCase().includes( filter ) )
|
|
868
|
+
{
|
|
869
|
+
_addElement( value, () => {
|
|
870
|
+
for( let i of instances )
|
|
871
|
+
{
|
|
758
872
|
i._changeLanguage( l );
|
|
759
873
|
}
|
|
760
874
|
}, "", {} );
|
|
@@ -764,14 +878,14 @@ function create_global_searchbar( root )
|
|
|
764
878
|
}
|
|
765
879
|
|
|
766
880
|
input.addEventListener('input', function(e) {
|
|
767
|
-
_addElements( this.value.toLowerCase() );
|
|
881
|
+
commandbar._addElements( this.value.toLowerCase() );
|
|
768
882
|
});
|
|
769
883
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
884
|
+
commandbar.appendChild( header );
|
|
885
|
+
commandbar.appendChild( tabArea.root );
|
|
886
|
+
commandbar.appendChild( itemContainer );
|
|
773
887
|
|
|
774
|
-
return
|
|
888
|
+
return commandbar;
|
|
775
889
|
}
|
|
776
890
|
|
|
777
891
|
/**
|
|
@@ -781,6 +895,7 @@ function create_global_searchbar( root )
|
|
|
781
895
|
* id: Id of the main area
|
|
782
896
|
* skipRoot: Skip adding LX root container
|
|
783
897
|
* skipDefaultArea: Skip creation of main area
|
|
898
|
+
* strictViewport: Use only window area
|
|
784
899
|
*/
|
|
785
900
|
|
|
786
901
|
function init( options = { } )
|
|
@@ -803,16 +918,17 @@ function init( options = { } )
|
|
|
803
918
|
this.root = root;
|
|
804
919
|
this.container = document.body;
|
|
805
920
|
|
|
806
|
-
// this.modal.toggleAttribute( 'hidden', true );
|
|
807
|
-
// this.modal.toggle = function( force ) { this.toggleAttribute( 'hidden', force ); };
|
|
808
|
-
|
|
809
921
|
this.modal.classList.add( 'hiddenOpacity' );
|
|
810
922
|
this.modal.toggle = function( force ) { this.classList.toggle( 'hiddenOpacity', force ); };
|
|
811
923
|
|
|
812
924
|
if( options.container )
|
|
925
|
+
{
|
|
813
926
|
this.container = document.getElementById( options.container );
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
document.documentElement.setAttribute( "data-strictVP", ( options.strictViewport ?? true ) ? "true" : "false" );
|
|
814
930
|
|
|
815
|
-
this.
|
|
931
|
+
this.commandbar = _createCommandbar( this.container );
|
|
816
932
|
|
|
817
933
|
this.container.appendChild( modal );
|
|
818
934
|
|
|
@@ -825,6 +941,25 @@ function init( options = { } )
|
|
|
825
941
|
this.root = document.body;
|
|
826
942
|
}
|
|
827
943
|
|
|
944
|
+
// Notifications
|
|
945
|
+
{
|
|
946
|
+
const notifSection = document.createElement( "section" );
|
|
947
|
+
notifSection.className = "notifications";
|
|
948
|
+
this.notifications = document.createElement( "ol" );
|
|
949
|
+
this.notifications.className = "";
|
|
950
|
+
this.notifications.iWidth = 0;
|
|
951
|
+
notifSection.appendChild( this.notifications );
|
|
952
|
+
this.container.appendChild( notifSection );
|
|
953
|
+
|
|
954
|
+
this.notifications.addEventListener( "mouseenter", () => {
|
|
955
|
+
this.notifications.classList.add( "list" );
|
|
956
|
+
} );
|
|
957
|
+
|
|
958
|
+
this.notifications.addEventListener( "mouseleave", () => {
|
|
959
|
+
this.notifications.classList.remove( "list" );
|
|
960
|
+
} );
|
|
961
|
+
}
|
|
962
|
+
|
|
828
963
|
// Disable drag icon
|
|
829
964
|
root.addEventListener( 'dragover', function( e ) {
|
|
830
965
|
e.preventDefault();
|
|
@@ -856,16 +991,48 @@ function init( options = { } )
|
|
|
856
991
|
this.main_area = new Area( { id: options.id ?? 'mainarea' } );
|
|
857
992
|
}
|
|
858
993
|
|
|
859
|
-
window.matchMedia( "(prefers-color-scheme:
|
|
860
|
-
|
|
861
|
-
LX.
|
|
862
|
-
|
|
994
|
+
if( ( options.autoTheme ?? true ) && window.matchMedia && window.matchMedia( "(prefers-color-scheme: light)" ).matches )
|
|
995
|
+
{
|
|
996
|
+
LX.setTheme( "light" );
|
|
997
|
+
|
|
998
|
+
window.matchMedia( "(prefers-color-scheme: dark)" ).addEventListener( "change", event => {
|
|
999
|
+
LX.setTheme( event.matches ? "dark" : "light" );
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
863
1002
|
|
|
864
1003
|
return this.main_area;
|
|
865
1004
|
}
|
|
866
1005
|
|
|
867
1006
|
LX.init = init;
|
|
868
1007
|
|
|
1008
|
+
/**
|
|
1009
|
+
* @method setCommandbarState
|
|
1010
|
+
* @param {Boolean} value
|
|
1011
|
+
* @param {Boolean} resetEntries
|
|
1012
|
+
*/
|
|
1013
|
+
|
|
1014
|
+
function setCommandbarState( value, resetEntries = true )
|
|
1015
|
+
{
|
|
1016
|
+
const cb = this.commandbar;
|
|
1017
|
+
|
|
1018
|
+
if( value )
|
|
1019
|
+
{
|
|
1020
|
+
cb.show();
|
|
1021
|
+
cb.querySelector('input').focus();
|
|
1022
|
+
|
|
1023
|
+
if( resetEntries )
|
|
1024
|
+
{
|
|
1025
|
+
cb._addElements( undefined );
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
else
|
|
1029
|
+
{
|
|
1030
|
+
cb.close();
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
LX.setCommandbarState = setCommandbarState;
|
|
1035
|
+
|
|
869
1036
|
/**
|
|
870
1037
|
* @method message
|
|
871
1038
|
* @param {String} text
|
|
@@ -898,9 +1065,9 @@ LX.message = message;
|
|
|
898
1065
|
* @param {String} title (Optional)
|
|
899
1066
|
* @param {*} options
|
|
900
1067
|
* id: Id of the message dialog
|
|
901
|
-
*
|
|
902
|
-
* position
|
|
903
|
-
* size
|
|
1068
|
+
* timeout (Number): Delay time before it closes automatically (ms). Default: [3000]
|
|
1069
|
+
* position (Array): [x,y] Dialog position in screen. Default: [screen centered]
|
|
1070
|
+
* size (Array): [width, height]
|
|
904
1071
|
*/
|
|
905
1072
|
|
|
906
1073
|
function popup( text, title, options = {} )
|
|
@@ -910,7 +1077,7 @@ function popup( text, title, options = {} )
|
|
|
910
1077
|
throw("No message to show");
|
|
911
1078
|
}
|
|
912
1079
|
|
|
913
|
-
options.size = options.size ?? [ "
|
|
1080
|
+
options.size = options.size ?? [ "max-content", "auto" ];
|
|
914
1081
|
options.class = "lexpopup";
|
|
915
1082
|
|
|
916
1083
|
const time = options.timeout || 3000;
|
|
@@ -918,13 +1085,9 @@ function popup( text, title, options = {} )
|
|
|
918
1085
|
p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
|
|
919
1086
|
}, options );
|
|
920
1087
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
dialog.root.classList.add( 'fadeout' );
|
|
925
|
-
}, time - 1000 );
|
|
926
|
-
|
|
927
|
-
setTimeout( dialog.close, time );
|
|
1088
|
+
setTimeout( () => {
|
|
1089
|
+
dialog.close();
|
|
1090
|
+
}, Math.max( time, 150 ) );
|
|
928
1091
|
|
|
929
1092
|
return dialog;
|
|
930
1093
|
}
|
|
@@ -947,6 +1110,7 @@ LX.popup = popup;
|
|
|
947
1110
|
function prompt( text, title, callback, options = {} )
|
|
948
1111
|
{
|
|
949
1112
|
options.modal = true;
|
|
1113
|
+
options.className = "prompt";
|
|
950
1114
|
|
|
951
1115
|
let value = "";
|
|
952
1116
|
|
|
@@ -961,7 +1125,9 @@ function prompt( text, title, callback, options = {} )
|
|
|
961
1125
|
|
|
962
1126
|
p.sameLine( 2 );
|
|
963
1127
|
|
|
964
|
-
p.addButton(
|
|
1128
|
+
p.addButton(null, "Cancel", () => {if(options.on_cancel) options.on_cancel(); dialog.close();} );
|
|
1129
|
+
|
|
1130
|
+
p.addButton( null, options.accept || "Continue", () => {
|
|
965
1131
|
if( options.required && value === '' )
|
|
966
1132
|
{
|
|
967
1133
|
text += text.includes("You must fill the input text.") ? "": "\nYou must fill the input text.";
|
|
@@ -975,8 +1141,6 @@ function prompt( text, title, callback, options = {} )
|
|
|
975
1141
|
}
|
|
976
1142
|
}, { buttonClass: "primary" });
|
|
977
1143
|
|
|
978
|
-
p.addButton(null, "Cancel", () => {if(options.on_cancel) options.on_cancel(); dialog.close();} );
|
|
979
|
-
|
|
980
1144
|
}, options );
|
|
981
1145
|
|
|
982
1146
|
// Focus text prompt
|
|
@@ -990,6 +1154,101 @@ function prompt( text, title, callback, options = {} )
|
|
|
990
1154
|
|
|
991
1155
|
LX.prompt = prompt;
|
|
992
1156
|
|
|
1157
|
+
/**
|
|
1158
|
+
* @method toast
|
|
1159
|
+
* @param {String} title
|
|
1160
|
+
* @param {String} description (Optional)
|
|
1161
|
+
* @param {*} options
|
|
1162
|
+
* action: Data of the custom action { name, callback }
|
|
1163
|
+
* closable: Allow closing the toast
|
|
1164
|
+
* timeout: Time in which the toast closed automatically, in ms. -1 means persistent. [3000]
|
|
1165
|
+
*/
|
|
1166
|
+
|
|
1167
|
+
function toast( title, description, options = {} )
|
|
1168
|
+
{
|
|
1169
|
+
if( !title )
|
|
1170
|
+
{
|
|
1171
|
+
throw( "The toast needs at least a title!" );
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
console.assert( this.notifications );
|
|
1175
|
+
|
|
1176
|
+
const toast = document.createElement( "li" );
|
|
1177
|
+
toast.className = "lextoast";
|
|
1178
|
+
toast.style.translate = "0 calc(100% + 30px)";
|
|
1179
|
+
this.notifications.prepend( toast );
|
|
1180
|
+
|
|
1181
|
+
doAsync( () => {
|
|
1182
|
+
|
|
1183
|
+
if( this.notifications.offsetWidth > this.notifications.iWidth )
|
|
1184
|
+
{
|
|
1185
|
+
this.notifications.iWidth = Math.min( this.notifications.offsetWidth, 480 );
|
|
1186
|
+
this.notifications.style.width = this.notifications.iWidth + "px";
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
toast.dataset[ "open" ] = true;
|
|
1190
|
+
}, 10 );
|
|
1191
|
+
|
|
1192
|
+
const content = document.createElement( "div" );
|
|
1193
|
+
content.className = "lextoastcontent";
|
|
1194
|
+
toast.appendChild( content );
|
|
1195
|
+
|
|
1196
|
+
const titleContent = document.createElement( "div" );
|
|
1197
|
+
titleContent.className = "title";
|
|
1198
|
+
titleContent.innerHTML = title;
|
|
1199
|
+
content.appendChild( titleContent );
|
|
1200
|
+
|
|
1201
|
+
if( description )
|
|
1202
|
+
{
|
|
1203
|
+
const desc = document.createElement( "div" );
|
|
1204
|
+
desc.className = "desc";
|
|
1205
|
+
desc.innerHTML = description;
|
|
1206
|
+
content.appendChild( desc );
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
if( options.action )
|
|
1210
|
+
{
|
|
1211
|
+
const panel = new Panel();
|
|
1212
|
+
panel.addButton(null, options.action.name ?? "Accept", options.action.callback.bind( this, toast ), { width: "auto", maxWidth: "150px", className: "right", buttonClass: "outline" });
|
|
1213
|
+
toast.appendChild( panel.root.childNodes[ 0 ] );
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
const that = this;
|
|
1217
|
+
|
|
1218
|
+
toast.close = function() {
|
|
1219
|
+
this.dataset[ "closed" ] = true;
|
|
1220
|
+
doAsync( () => {
|
|
1221
|
+
this.remove();
|
|
1222
|
+
if( !that.notifications.childElementCount )
|
|
1223
|
+
{
|
|
1224
|
+
that.notifications.style.width = "unset";
|
|
1225
|
+
that.notifications.iWidth = 0;
|
|
1226
|
+
}
|
|
1227
|
+
}, 500 );
|
|
1228
|
+
};
|
|
1229
|
+
|
|
1230
|
+
if( options.closable ?? true )
|
|
1231
|
+
{
|
|
1232
|
+
const closeButton = document.createElement( "a" );
|
|
1233
|
+
closeButton.className = "fa fa-xmark lexicon closer";
|
|
1234
|
+
closeButton.addEventListener( "click", () => {
|
|
1235
|
+
toast.close();
|
|
1236
|
+
} );
|
|
1237
|
+
toast.appendChild( closeButton );
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
const timeout = options.timeout ?? 3000;
|
|
1241
|
+
|
|
1242
|
+
if( timeout != -1 )
|
|
1243
|
+
{
|
|
1244
|
+
doAsync( () => {
|
|
1245
|
+
toast.close();
|
|
1246
|
+
}, timeout );
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
LX.toast = toast;
|
|
1251
|
+
|
|
993
1252
|
/**
|
|
994
1253
|
* @method badge
|
|
995
1254
|
* @param {String} text
|
|
@@ -1009,6 +1268,25 @@ function badge( text, className, options = {} )
|
|
|
1009
1268
|
|
|
1010
1269
|
LX.badge = badge;
|
|
1011
1270
|
|
|
1271
|
+
/**
|
|
1272
|
+
* @method makeContainer
|
|
1273
|
+
* @param {Array} size
|
|
1274
|
+
* @param {String} className
|
|
1275
|
+
* @param {Object} overrideStyle
|
|
1276
|
+
*/
|
|
1277
|
+
|
|
1278
|
+
function makeContainer( size, className, overrideStyle = {} )
|
|
1279
|
+
{
|
|
1280
|
+
const container = document.createElement( "div" );
|
|
1281
|
+
container.className = "lexcontainer " + ( className ?? "" );
|
|
1282
|
+
container.style.width = size && size[ 0 ] ? size[ 0 ] : "100%";
|
|
1283
|
+
container.style.height = size && size[ 1 ] ? size[ 1 ] : "100%";
|
|
1284
|
+
Object.assign( container.style, overrideStyle );
|
|
1285
|
+
return container;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
LX.makeContainer = makeContainer;
|
|
1289
|
+
|
|
1012
1290
|
/*
|
|
1013
1291
|
* Events and Signals
|
|
1014
1292
|
*/
|
|
@@ -1272,7 +1550,8 @@ class Area {
|
|
|
1272
1550
|
|
|
1273
1551
|
function inner_mousemove( e )
|
|
1274
1552
|
{
|
|
1275
|
-
switch( that.type )
|
|
1553
|
+
switch( that.type )
|
|
1554
|
+
{
|
|
1276
1555
|
case "right":
|
|
1277
1556
|
var dt = ( lastMousePosition[ 0 ] - e.x );
|
|
1278
1557
|
var size = ( that.root.offsetWidth + dt );
|
|
@@ -1467,7 +1746,8 @@ class Area {
|
|
|
1467
1746
|
|
|
1468
1747
|
// Listen resize event on first area
|
|
1469
1748
|
const resizeObserver = new ResizeObserver( entries => {
|
|
1470
|
-
for (const entry of entries)
|
|
1749
|
+
for ( const entry of entries )
|
|
1750
|
+
{
|
|
1471
1751
|
const bb = entry.contentRect;
|
|
1472
1752
|
area2.root.style.height = "calc(100% - " + ( bb.height + 4) + "px )";
|
|
1473
1753
|
}
|
|
@@ -1491,8 +1771,8 @@ class Area {
|
|
|
1491
1771
|
}
|
|
1492
1772
|
|
|
1493
1773
|
area1.root.style.width = "100%";
|
|
1494
|
-
area1.root.style.height = "calc( " + height1 + " - " + data + " )";
|
|
1495
|
-
area2.root.style.height = "calc( " + height2 + " - " + data + " )";
|
|
1774
|
+
area1.root.style.height = ( height1 == "auto" ? height1 : "calc( " + height1 + " - " + data + " )");
|
|
1775
|
+
area2.root.style.height = ( height2 == "auto" ? height2 : "calc( " + height2 + " - " + data + " )");
|
|
1496
1776
|
}
|
|
1497
1777
|
}
|
|
1498
1778
|
|
|
@@ -1608,9 +1888,15 @@ class Area {
|
|
|
1608
1888
|
this.root.style.height = height;
|
|
1609
1889
|
}
|
|
1610
1890
|
|
|
1611
|
-
|
|
1891
|
+
if( this.onresize )
|
|
1892
|
+
{
|
|
1893
|
+
this.onresize( this.root.getBoundingClientRect() );
|
|
1894
|
+
}
|
|
1612
1895
|
|
|
1613
|
-
|
|
1896
|
+
doAsync( () => {
|
|
1897
|
+
this.size = [ this.root.clientWidth, this.root.clientHeight ];
|
|
1898
|
+
this.propagateEvent( "onresize" );
|
|
1899
|
+
}, 150 );
|
|
1614
1900
|
}
|
|
1615
1901
|
|
|
1616
1902
|
/**
|
|
@@ -1627,7 +1913,7 @@ class Area {
|
|
|
1627
1913
|
let [area1, area2] = this.sections;
|
|
1628
1914
|
this.splitExtended = true;
|
|
1629
1915
|
|
|
1630
|
-
if(this.type == "vertical")
|
|
1916
|
+
if( this.type == "vertical")
|
|
1631
1917
|
{
|
|
1632
1918
|
this.offset = area2.root.offsetHeight;
|
|
1633
1919
|
area2.root.classList.add("fadeout-vertical");
|
|
@@ -1641,7 +1927,6 @@ class Area {
|
|
|
1641
1927
|
this._moveSplit(-Infinity, true, 8);
|
|
1642
1928
|
}
|
|
1643
1929
|
|
|
1644
|
-
// Async resize in some ms...
|
|
1645
1930
|
doAsync( () => this.propagateEvent('onresize'), 150 );
|
|
1646
1931
|
}
|
|
1647
1932
|
|
|
@@ -1657,7 +1942,7 @@ class Area {
|
|
|
1657
1942
|
this.splitExtended = false;
|
|
1658
1943
|
let [area1, area2] = this.sections;
|
|
1659
1944
|
|
|
1660
|
-
if(this.type == "vertical")
|
|
1945
|
+
if( this.type == "vertical")
|
|
1661
1946
|
{
|
|
1662
1947
|
area2.root.classList.add("fadein-vertical");
|
|
1663
1948
|
this._moveSplit(this.offset);
|
|
@@ -1668,7 +1953,6 @@ class Area {
|
|
|
1668
1953
|
this._moveSplit(this.offset);
|
|
1669
1954
|
}
|
|
1670
1955
|
|
|
1671
|
-
// Async resize in some ms...
|
|
1672
1956
|
doAsync( () => this.propagateEvent('onresize'), 150 );
|
|
1673
1957
|
}
|
|
1674
1958
|
|
|
@@ -1702,11 +1986,15 @@ class Area {
|
|
|
1702
1986
|
|
|
1703
1987
|
propagateEvent( eventName ) {
|
|
1704
1988
|
|
|
1705
|
-
for(var i = 0; i < this.sections.length; i++)
|
|
1989
|
+
for( var i = 0; i < this.sections.length; i++ )
|
|
1706
1990
|
{
|
|
1707
|
-
const area = this.sections[i];
|
|
1708
|
-
|
|
1991
|
+
const area = this.sections[ i ];
|
|
1992
|
+
|
|
1993
|
+
if( area[ eventName ] )
|
|
1994
|
+
{
|
|
1709
1995
|
area[ eventName ].call( this, area.root.getBoundingClientRect() );
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1710
1998
|
area.propagateEvent( eventName );
|
|
1711
1999
|
}
|
|
1712
2000
|
}
|
|
@@ -1729,42 +2017,63 @@ class Area {
|
|
|
1729
2017
|
* @param {Function} callback Function to fill the menubar
|
|
1730
2018
|
* @param {*} options:
|
|
1731
2019
|
* float: Justify content (left, center, right) [left]
|
|
2020
|
+
* sticky: Fix menubar at the top [true]
|
|
1732
2021
|
*/
|
|
1733
2022
|
|
|
1734
2023
|
addMenubar( callback, options = {} ) {
|
|
1735
2024
|
|
|
1736
|
-
let menubar = new Menubar(options);
|
|
2025
|
+
let menubar = new Menubar( options );
|
|
1737
2026
|
|
|
1738
|
-
if(
|
|
2027
|
+
if( callback )
|
|
2028
|
+
{
|
|
2029
|
+
callback( menubar );
|
|
2030
|
+
}
|
|
1739
2031
|
|
|
1740
2032
|
LX.menubars.push( menubar );
|
|
1741
2033
|
|
|
1742
2034
|
const height = 48; // pixels
|
|
2035
|
+
const [ bar, content ] = this.split({ type: 'vertical', sizes: [height, null], resize: false, menubar: true });
|
|
2036
|
+
menubar.siblingArea = content;
|
|
1743
2037
|
|
|
1744
|
-
const [bar, content] = this.split({type: 'vertical', sizes: [height, null], resize: false, menubar: true});
|
|
1745
2038
|
bar.attach( menubar );
|
|
1746
|
-
bar.
|
|
2039
|
+
bar.isMenubar = true;
|
|
2040
|
+
|
|
2041
|
+
if( options.sticky ?? true )
|
|
2042
|
+
{
|
|
2043
|
+
bar.root.classList.add( "sticky" );
|
|
2044
|
+
}
|
|
2045
|
+
|
|
1747
2046
|
return menubar;
|
|
1748
2047
|
}
|
|
1749
2048
|
|
|
1750
2049
|
/**
|
|
1751
2050
|
* @method addSidebar
|
|
1752
2051
|
* @param {Function} callback Function to fill the sidebar
|
|
2052
|
+
* @param {Object} options: Sidebar options
|
|
2053
|
+
* width: Width of the sidebar [16rem]
|
|
1753
2054
|
*/
|
|
1754
2055
|
|
|
1755
2056
|
addSidebar( callback, options = {} ) {
|
|
1756
2057
|
|
|
1757
2058
|
let sidebar = new SideBar( options );
|
|
1758
2059
|
|
|
1759
|
-
if( callback )
|
|
2060
|
+
if( callback )
|
|
2061
|
+
{
|
|
2062
|
+
callback( sidebar );
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// Generate DOM elements after adding all entries
|
|
2066
|
+
sidebar._build();
|
|
1760
2067
|
|
|
1761
2068
|
LX.menubars.push( sidebar );
|
|
1762
2069
|
|
|
1763
|
-
const width =
|
|
2070
|
+
const width = options.width ?? "16rem";
|
|
2071
|
+
const [ bar, content ] = this.split( { type: 'horizontal', sizes: [ width, null ], resize: false, sidebar: true } );
|
|
2072
|
+
sidebar.siblingArea = content;
|
|
1764
2073
|
|
|
1765
|
-
const [bar, content] = this.split( { type: 'horizontal', sizes: [ width, null ], resize: false, sidebar: true } );
|
|
1766
2074
|
bar.attach( sidebar );
|
|
1767
|
-
bar.
|
|
2075
|
+
bar.isSidebar = true;
|
|
2076
|
+
|
|
1768
2077
|
return sidebar;
|
|
1769
2078
|
}
|
|
1770
2079
|
|
|
@@ -2020,7 +2329,8 @@ class Area {
|
|
|
2020
2329
|
|
|
2021
2330
|
this.size = [ rect.width, rect.height ];
|
|
2022
2331
|
|
|
2023
|
-
for(var i = 0; i < this.sections.length; i++)
|
|
2332
|
+
for( var i = 0; i < this.sections.length; i++ )
|
|
2333
|
+
{
|
|
2024
2334
|
this.sections[i]._update();
|
|
2025
2335
|
}
|
|
2026
2336
|
}
|
|
@@ -2044,7 +2354,7 @@ class Tabs {
|
|
|
2044
2354
|
static TAB_SIZE = 28;
|
|
2045
2355
|
static TAB_ID = 0;
|
|
2046
2356
|
|
|
2047
|
-
constructor( area, options = {} )
|
|
2357
|
+
constructor( area, options = {} ) {
|
|
2048
2358
|
|
|
2049
2359
|
this.onclose = options.onclose;
|
|
2050
2360
|
|
|
@@ -2092,7 +2402,7 @@ class Tabs {
|
|
|
2092
2402
|
|
|
2093
2403
|
area.root.classList.add( "lexareatabscontainer" );
|
|
2094
2404
|
|
|
2095
|
-
area.split({type: 'vertical', sizes: "auto", resize: false, top: 6});
|
|
2405
|
+
area.split({type: 'vertical', sizes: options.sizes ?? "auto", resize: false, top: 6});
|
|
2096
2406
|
area.sections[0].attach( container );
|
|
2097
2407
|
|
|
2098
2408
|
this.area = area.sections[1];
|
|
@@ -2126,24 +2436,28 @@ class Tabs {
|
|
|
2126
2436
|
}
|
|
2127
2437
|
|
|
2128
2438
|
// debug
|
|
2129
|
-
if(folding)
|
|
2439
|
+
if( folding )
|
|
2130
2440
|
{
|
|
2131
2441
|
this.folded = true;
|
|
2132
2442
|
this.folding = folding;
|
|
2133
2443
|
|
|
2134
|
-
if(folding == "up"
|
|
2444
|
+
if( folding == "up" )
|
|
2445
|
+
{
|
|
2446
|
+
area.root.insertChildAtIndex(area.sections[1].root, 0);
|
|
2447
|
+
}
|
|
2135
2448
|
|
|
2136
2449
|
// Listen resize event on parent area
|
|
2137
2450
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
2138
|
-
for (const entry of entries)
|
|
2451
|
+
for (const entry of entries)
|
|
2452
|
+
{
|
|
2139
2453
|
const bb = entry.contentRect;
|
|
2140
|
-
const sibling = area.parentArea.sections[0].root;
|
|
2141
|
-
const
|
|
2142
|
-
sibling.style.height = "calc(100% - " + ((
|
|
2454
|
+
const sibling = area.parentArea.sections[ 0 ].root;
|
|
2455
|
+
const addOffset = true; // hardcoded...
|
|
2456
|
+
sibling.style.height = "calc(100% - " + ((addOffset ? 42 : 0) + bb.height) + "px )";
|
|
2143
2457
|
}
|
|
2144
2458
|
});
|
|
2145
2459
|
|
|
2146
|
-
resizeObserver.observe(this.area.root);
|
|
2460
|
+
resizeObserver.observe( this.area.root );
|
|
2147
2461
|
this.area.root.classList.add('folded');
|
|
2148
2462
|
}
|
|
2149
2463
|
}
|
|
@@ -2280,7 +2594,8 @@ class Tabs {
|
|
|
2280
2594
|
|
|
2281
2595
|
setTimeout( () => {
|
|
2282
2596
|
|
|
2283
|
-
if( options.onCreate )
|
|
2597
|
+
if( options.onCreate )
|
|
2598
|
+
{
|
|
2284
2599
|
options.onCreate.call(this, this.area.root.getBoundingClientRect());
|
|
2285
2600
|
}
|
|
2286
2601
|
|
|
@@ -2342,34 +2657,41 @@ LX.Tabs = Tabs;
|
|
|
2342
2657
|
|
|
2343
2658
|
class Menubar {
|
|
2344
2659
|
|
|
2345
|
-
constructor( options = {} )
|
|
2660
|
+
constructor( options = {} ) {
|
|
2346
2661
|
|
|
2347
|
-
this.root = document.createElement(
|
|
2662
|
+
this.root = document.createElement( "div" );
|
|
2348
2663
|
this.root.className = "lexmenubar";
|
|
2349
|
-
|
|
2664
|
+
|
|
2665
|
+
if( options.float )
|
|
2666
|
+
{
|
|
2350
2667
|
this.root.style.justifyContent = options.float;
|
|
2351
|
-
|
|
2668
|
+
}
|
|
2352
2669
|
|
|
2353
|
-
this.
|
|
2354
|
-
this.
|
|
2355
|
-
this.
|
|
2670
|
+
this.items = [ ];
|
|
2671
|
+
this.buttons = [ ];
|
|
2672
|
+
this.icons = { };
|
|
2673
|
+
this.shorts = { };
|
|
2356
2674
|
}
|
|
2357
2675
|
|
|
2358
2676
|
/**
|
|
2359
2677
|
* @method add
|
|
2360
|
-
* @param {
|
|
2678
|
+
* @param {Object} options:
|
|
2361
2679
|
* callback: Function to call on each item
|
|
2680
|
+
* icon: Entry icon
|
|
2681
|
+
* short: Entry shortcut name
|
|
2362
2682
|
*/
|
|
2363
2683
|
|
|
2364
2684
|
add( path, options = {} ) {
|
|
2365
2685
|
|
|
2366
|
-
if(options.constructor == Function)
|
|
2686
|
+
if( options.constructor == Function )
|
|
2687
|
+
{
|
|
2367
2688
|
options = { callback: options };
|
|
2689
|
+
}
|
|
2368
2690
|
|
|
2369
|
-
//
|
|
2370
|
-
const tokens = path.split("/");
|
|
2691
|
+
// Process path
|
|
2692
|
+
const tokens = path.split( "/" );
|
|
2371
2693
|
|
|
2372
|
-
//
|
|
2694
|
+
// Assign icons and shortcuts to last token in path
|
|
2373
2695
|
const lastPath = tokens[tokens.length - 1];
|
|
2374
2696
|
this.icons[ lastPath ] = options.icon;
|
|
2375
2697
|
this.shorts[ lastPath ] = options.short;
|
|
@@ -2377,105 +2699,146 @@ class Menubar {
|
|
|
2377
2699
|
let idx = 0;
|
|
2378
2700
|
let that = this;
|
|
2379
2701
|
|
|
2380
|
-
const
|
|
2381
|
-
if(token == undefined)
|
|
2702
|
+
const _insertEntry = ( token, list ) => {
|
|
2703
|
+
if( token == undefined )
|
|
2704
|
+
{
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2382
2707
|
|
|
2383
2708
|
let found = null;
|
|
2384
2709
|
list.forEach( o => {
|
|
2385
|
-
const keys = Object.keys(o);
|
|
2710
|
+
const keys = Object.keys( o );
|
|
2386
2711
|
const key = keys.find( t => t == token );
|
|
2387
|
-
if(key) found = o[ key ];
|
|
2712
|
+
if( key ) found = o[ key ];
|
|
2388
2713
|
} );
|
|
2389
2714
|
|
|
2390
|
-
if(found)
|
|
2391
|
-
|
|
2715
|
+
if( found )
|
|
2716
|
+
{
|
|
2717
|
+
_insertEntry( tokens[ idx++ ], found );
|
|
2392
2718
|
}
|
|
2393
|
-
else
|
|
2719
|
+
else
|
|
2720
|
+
{
|
|
2394
2721
|
let item = {};
|
|
2395
2722
|
item[ token ] = [];
|
|
2396
|
-
const
|
|
2723
|
+
const nextToken = tokens[ idx++ ];
|
|
2397
2724
|
// Check if last token -> add callback
|
|
2398
|
-
if(!
|
|
2725
|
+
if( !nextToken )
|
|
2726
|
+
{
|
|
2399
2727
|
item[ 'callback' ] = options.callback;
|
|
2728
|
+
item[ 'disabled' ] = options.disabled;
|
|
2400
2729
|
item[ 'type' ] = options.type;
|
|
2401
2730
|
item[ 'checked' ] = options.checked;
|
|
2402
2731
|
}
|
|
2403
2732
|
list.push( item );
|
|
2404
|
-
|
|
2733
|
+
_insertEntry( nextToken, item[ token ] );
|
|
2405
2734
|
}
|
|
2406
2735
|
};
|
|
2407
2736
|
|
|
2408
|
-
|
|
2737
|
+
_insertEntry( tokens[idx++], this.items );
|
|
2409
2738
|
|
|
2410
2739
|
// Create elements
|
|
2411
2740
|
|
|
2412
2741
|
for( let item of this.items )
|
|
2413
2742
|
{
|
|
2414
|
-
let key = Object.keys(item)[0];
|
|
2415
|
-
let pKey = key.replace(/\s/g, '').replaceAll('.', '');
|
|
2743
|
+
let key = Object.keys( item )[ 0 ];
|
|
2744
|
+
let pKey = key.replace( /\s/g, '' ).replaceAll( '.', '' );
|
|
2416
2745
|
|
|
2417
2746
|
// Item already created
|
|
2418
|
-
if( this.root.querySelector("#" + pKey) )
|
|
2747
|
+
if( this.root.querySelector( "#" + pKey ) )
|
|
2748
|
+
{
|
|
2419
2749
|
continue;
|
|
2750
|
+
}
|
|
2420
2751
|
|
|
2421
2752
|
let entry = document.createElement('div');
|
|
2422
2753
|
entry.className = "lexmenuentry";
|
|
2423
2754
|
entry.id = pKey;
|
|
2424
2755
|
entry.innerHTML = "<span>" + key + "</span>";
|
|
2425
|
-
|
|
2756
|
+
entry.tabIndex = "1";
|
|
2757
|
+
|
|
2758
|
+
if( options.position == "left" )
|
|
2759
|
+
{
|
|
2426
2760
|
this.root.prepend( entry );
|
|
2427
2761
|
}
|
|
2428
|
-
else
|
|
2429
|
-
|
|
2762
|
+
else
|
|
2763
|
+
{
|
|
2764
|
+
if( options.position == "right" )
|
|
2765
|
+
{
|
|
2430
2766
|
entry.right = true;
|
|
2431
|
-
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
if( this.root.lastChild && this.root.lastChild.right )
|
|
2770
|
+
{
|
|
2432
2771
|
this.root.lastChild.before( entry );
|
|
2433
2772
|
}
|
|
2434
|
-
else
|
|
2773
|
+
else
|
|
2774
|
+
{
|
|
2435
2775
|
this.root.appendChild( entry );
|
|
2436
2776
|
}
|
|
2437
2777
|
}
|
|
2438
2778
|
|
|
2779
|
+
const _resetMenubar = function() {
|
|
2780
|
+
// Menu entries are in the menubar..
|
|
2781
|
+
that.root.querySelectorAll(".lexmenuentry").forEach( _entry => {
|
|
2782
|
+
_entry.classList.remove( 'selected' );
|
|
2783
|
+
_entry.built = false;
|
|
2784
|
+
} );
|
|
2785
|
+
// Menuboxes are in the root area!
|
|
2786
|
+
LX.root.querySelectorAll(".lexmenubox").forEach(e => e.remove());
|
|
2787
|
+
// Next time we need to click again
|
|
2788
|
+
that.focused = false;
|
|
2789
|
+
};
|
|
2790
|
+
|
|
2439
2791
|
const create_submenu = function( o, k, c, d ) {
|
|
2440
2792
|
|
|
2441
|
-
let
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2793
|
+
let menuElement = document.createElement('div');
|
|
2794
|
+
menuElement.className = "lexmenubox";
|
|
2795
|
+
menuElement.tabIndex = "0";
|
|
2796
|
+
c.currentMenu = menuElement;
|
|
2797
|
+
const isSubMenu = c.classList.contains( "lexmenuboxentry" );
|
|
2798
|
+
if( isSubMenu ) menuElement.dataset[ "submenu" ] = true;
|
|
2445
2799
|
var rect = c.getBoundingClientRect();
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
c.appendChild( contextmenu );
|
|
2800
|
+
menuElement.style.left = ( isSubMenu ? ( rect.x + rect.width ) : rect.left ) + "px";
|
|
2801
|
+
menuElement.style.top = ( isSubMenu ? rect.y : rect.bottom - 4 ) + "px";
|
|
2802
|
+
rect = menuElement.getBoundingClientRect();
|
|
2450
2803
|
|
|
2451
|
-
|
|
2804
|
+
doAsync( () => {
|
|
2805
|
+
menuElement.dataset[ "open" ] = true;
|
|
2806
|
+
}, 10 );
|
|
2452
2807
|
|
|
2453
|
-
|
|
2808
|
+
LX.root.appendChild( menuElement );
|
|
2454
2809
|
|
|
2455
|
-
for( var i = 0; i < o[k].length; ++i )
|
|
2810
|
+
for( var i = 0; i < o[ k ].length; ++i )
|
|
2456
2811
|
{
|
|
2457
|
-
const subitem = o[k][i];
|
|
2458
|
-
const subkey = Object.keys(subitem)[0];
|
|
2812
|
+
const subitem = o[ k ][ i ];
|
|
2813
|
+
const subkey = Object.keys( subitem )[ 0 ];
|
|
2459
2814
|
const hasSubmenu = subitem[ subkey ].length;
|
|
2460
2815
|
const isCheckbox = subitem[ 'type' ] == 'checkbox';
|
|
2461
2816
|
let subentry = document.createElement('div');
|
|
2462
|
-
subentry.className = "
|
|
2463
|
-
subentry.className += (i == o[k].length - 1 ? " last" : "");
|
|
2464
|
-
if(subkey == '')
|
|
2465
|
-
subentry.className = " lexseparator";
|
|
2466
|
-
else {
|
|
2817
|
+
subentry.className = "lexmenuboxentry";
|
|
2818
|
+
subentry.className += (i == o[k].length - 1 ? " last" : "") + ( subitem.disabled ? " disabled" : "" );
|
|
2467
2819
|
|
|
2820
|
+
if( subkey == '' )
|
|
2821
|
+
{
|
|
2822
|
+
subentry.className = " lexseparator";
|
|
2823
|
+
}
|
|
2824
|
+
else
|
|
2825
|
+
{
|
|
2468
2826
|
subentry.id = subkey;
|
|
2469
2827
|
let subentrycont = document.createElement('div');
|
|
2470
2828
|
subentrycont.innerHTML = "";
|
|
2471
|
-
subentrycont.classList = "
|
|
2829
|
+
subentrycont.classList = "lexmenuboxentrycontainer";
|
|
2472
2830
|
subentry.appendChild(subentrycont);
|
|
2473
2831
|
const icon = that.icons[ subkey ];
|
|
2474
|
-
if(isCheckbox)
|
|
2832
|
+
if( isCheckbox )
|
|
2833
|
+
{
|
|
2475
2834
|
subentrycont.innerHTML += "<input type='checkbox' >";
|
|
2476
|
-
}
|
|
2835
|
+
}
|
|
2836
|
+
else if( icon )
|
|
2837
|
+
{
|
|
2477
2838
|
subentrycont.innerHTML += "<a class='" + icon + " fa-sm'></a>";
|
|
2478
|
-
}
|
|
2839
|
+
}
|
|
2840
|
+
else
|
|
2841
|
+
{
|
|
2479
2842
|
subentrycont.innerHTML += "<a class='fa-solid fa-sm noicon'></a>";
|
|
2480
2843
|
subentrycont.classList.add( "noicon" );
|
|
2481
2844
|
|
|
@@ -2483,46 +2846,54 @@ class Menubar {
|
|
|
2483
2846
|
subentrycont.innerHTML += "<div class='lexentryname'>" + subkey + "</div>";
|
|
2484
2847
|
}
|
|
2485
2848
|
|
|
2486
|
-
let
|
|
2487
|
-
if(
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2849
|
+
let checkboxInput = subentry.querySelector('input');
|
|
2850
|
+
if( checkboxInput )
|
|
2851
|
+
{
|
|
2852
|
+
checkboxInput.checked = subitem.checked ?? false;
|
|
2853
|
+
checkboxInput.addEventListener('change', e => {
|
|
2854
|
+
subitem.checked = checkboxInput.checked;
|
|
2491
2855
|
const f = subitem[ 'callback' ];
|
|
2492
|
-
if(f)
|
|
2856
|
+
if( f )
|
|
2857
|
+
{
|
|
2493
2858
|
f.call( this, subitem.checked, subkey, subentry );
|
|
2494
|
-
|
|
2859
|
+
_resetMenubar();
|
|
2495
2860
|
}
|
|
2496
2861
|
e.stopPropagation();
|
|
2497
2862
|
e.stopImmediatePropagation();
|
|
2498
2863
|
})
|
|
2499
2864
|
}
|
|
2500
2865
|
|
|
2501
|
-
|
|
2866
|
+
menuElement.appendChild( subentry );
|
|
2502
2867
|
|
|
2503
2868
|
// Nothing more for separators
|
|
2504
|
-
if(subkey == '')
|
|
2869
|
+
if( subkey == '' )
|
|
2870
|
+
{
|
|
2871
|
+
continue;
|
|
2872
|
+
}
|
|
2505
2873
|
|
|
2506
|
-
|
|
2874
|
+
menuElement.addEventListener('keydown', function(e) {
|
|
2507
2875
|
e.preventDefault();
|
|
2508
2876
|
let short = that.shorts[ subkey ];
|
|
2509
2877
|
if(!short) return;
|
|
2510
2878
|
// check if it's a letter or other key
|
|
2511
2879
|
short = short.length == 1 ? short.toLowerCase() : short;
|
|
2512
|
-
if(short == e.key)
|
|
2880
|
+
if( short == e.key )
|
|
2881
|
+
{
|
|
2513
2882
|
subentry.click()
|
|
2514
2883
|
}
|
|
2515
2884
|
});
|
|
2516
2885
|
|
|
2517
2886
|
// Add callback
|
|
2518
2887
|
subentry.addEventListener("click", e => {
|
|
2519
|
-
if(
|
|
2888
|
+
if( checkboxInput )
|
|
2889
|
+
{
|
|
2520
2890
|
subitem.checked = !subitem.checked;
|
|
2521
2891
|
}
|
|
2522
2892
|
const f = subitem[ 'callback' ];
|
|
2523
|
-
if(f)
|
|
2524
|
-
|
|
2525
|
-
|
|
2893
|
+
if( f )
|
|
2894
|
+
{
|
|
2895
|
+
f.call( this, checkboxInput ? subitem.checked : subkey, checkboxInput ? subkey : subentry );
|
|
2896
|
+
_resetMenubar();
|
|
2526
2897
|
}
|
|
2527
2898
|
e.stopPropagation();
|
|
2528
2899
|
e.stopImmediatePropagation();
|
|
@@ -2531,7 +2902,8 @@ class Menubar {
|
|
|
2531
2902
|
// Add icon if has submenu, else check for shortcut
|
|
2532
2903
|
if( !hasSubmenu)
|
|
2533
2904
|
{
|
|
2534
|
-
if(that.shorts[ subkey ])
|
|
2905
|
+
if( that.shorts[ subkey ] )
|
|
2906
|
+
{
|
|
2535
2907
|
let shortEl = document.createElement('div');
|
|
2536
2908
|
shortEl.className = "lexentryshort";
|
|
2537
2909
|
shortEl.innerText = that.shorts[ subkey ];
|
|
@@ -2545,44 +2917,67 @@ class Menubar {
|
|
|
2545
2917
|
subentry.appendChild( submenuIcon );
|
|
2546
2918
|
|
|
2547
2919
|
subentry.addEventListener("mouseover", e => {
|
|
2548
|
-
if(subentry.built)
|
|
2549
|
-
|
|
2920
|
+
if( subentry.built )
|
|
2921
|
+
{
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2550
2924
|
subentry.built = true;
|
|
2551
2925
|
create_submenu( subitem, subkey, subentry, ++d );
|
|
2552
2926
|
e.stopPropagation();
|
|
2553
2927
|
});
|
|
2554
2928
|
|
|
2555
|
-
subentry.addEventListener("mouseleave", () => {
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2929
|
+
subentry.addEventListener("mouseleave", (e) => {
|
|
2930
|
+
if( subentry.currentMenu && ( subentry.currentMenu != e.toElement ) )
|
|
2931
|
+
{
|
|
2932
|
+
d = -1; // Reset depth
|
|
2933
|
+
delete subentry.built;
|
|
2934
|
+
subentry.currentMenu.remove();
|
|
2935
|
+
delete subentry.currentMenu;
|
|
2936
|
+
}
|
|
2559
2937
|
});
|
|
2560
2938
|
}
|
|
2561
2939
|
|
|
2562
2940
|
// Set final width
|
|
2563
|
-
|
|
2941
|
+
menuElement.style.width = menuElement.offsetWidth + "px";
|
|
2564
2942
|
};
|
|
2565
2943
|
|
|
2566
|
-
|
|
2944
|
+
const _showEntry = () => {
|
|
2945
|
+
_resetMenubar();
|
|
2946
|
+
entry.classList.add( "selected" );
|
|
2947
|
+
entry.built = true;
|
|
2948
|
+
create_submenu( item, key, entry, -1 );
|
|
2949
|
+
};
|
|
2567
2950
|
|
|
2951
|
+
entry.addEventListener("click", () => {
|
|
2568
2952
|
const f = item[ 'callback' ];
|
|
2569
|
-
if(f)
|
|
2953
|
+
if( f )
|
|
2954
|
+
{
|
|
2570
2955
|
f.call( this, key, entry );
|
|
2571
2956
|
return;
|
|
2572
2957
|
}
|
|
2573
2958
|
|
|
2574
|
-
|
|
2575
|
-
this.root.querySelectorAll(".lexmenuentry").forEach( e => e.classList.remove( 'selected' ) );
|
|
2576
|
-
entry.classList.add( "selected" );
|
|
2959
|
+
_showEntry();
|
|
2577
2960
|
|
|
2578
|
-
this.
|
|
2579
|
-
create_submenu( item, key, entry, -1 );
|
|
2961
|
+
this.focused = true;
|
|
2580
2962
|
});
|
|
2581
2963
|
|
|
2582
|
-
entry.addEventListener("
|
|
2583
|
-
|
|
2584
|
-
this.
|
|
2585
|
-
|
|
2964
|
+
entry.addEventListener( "mouseover", (e) => {
|
|
2965
|
+
|
|
2966
|
+
if( this.focused && !entry.built )
|
|
2967
|
+
{
|
|
2968
|
+
_showEntry();
|
|
2969
|
+
}
|
|
2970
|
+
});
|
|
2971
|
+
|
|
2972
|
+
entry.addEventListener("blur", (e) => {
|
|
2973
|
+
|
|
2974
|
+
if( e.relatedTarget && e.relatedTarget.classList.contains( "lexmenubox" ) )
|
|
2975
|
+
{
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2979
|
+
_resetMenubar();
|
|
2980
|
+
});
|
|
2586
2981
|
}
|
|
2587
2982
|
}
|
|
2588
2983
|
|
|
@@ -2600,20 +2995,24 @@ class Menubar {
|
|
|
2600
2995
|
* @param {Object} item: parent item
|
|
2601
2996
|
* @param {Array} tokens: split path strings
|
|
2602
2997
|
*/
|
|
2603
|
-
getSubitem(item, tokens) {
|
|
2998
|
+
getSubitem( item, tokens ) {
|
|
2604
2999
|
|
|
2605
3000
|
let subitem = null;
|
|
2606
|
-
let path = tokens[0];
|
|
2607
|
-
for(let i = 0; i < item.length; i++) {
|
|
2608
|
-
if(item[i][path]) {
|
|
3001
|
+
let path = tokens[ 0 ];
|
|
2609
3002
|
|
|
2610
|
-
|
|
2611
|
-
|
|
3003
|
+
for( let i = 0; i < item.length; i++ )
|
|
3004
|
+
{
|
|
3005
|
+
if( item[ i ][ path ] )
|
|
3006
|
+
{
|
|
3007
|
+
if( tokens.length == 1 )
|
|
3008
|
+
{
|
|
3009
|
+
subitem = item[ i ];
|
|
2612
3010
|
return subitem;
|
|
2613
3011
|
}
|
|
2614
|
-
else
|
|
2615
|
-
|
|
2616
|
-
|
|
3012
|
+
else
|
|
3013
|
+
{
|
|
3014
|
+
tokens.splice( 0, 1 );
|
|
3015
|
+
return this.getSubitem( item[ i ][ path ], tokens );
|
|
2617
3016
|
}
|
|
2618
3017
|
|
|
2619
3018
|
}
|
|
@@ -2640,11 +3039,12 @@ class Menubar {
|
|
|
2640
3039
|
setButtonIcon( title, icon, callback, options = {} ) {
|
|
2641
3040
|
|
|
2642
3041
|
const button = this.buttons[ title ];
|
|
2643
|
-
if(button)
|
|
2644
|
-
|
|
3042
|
+
if( button )
|
|
3043
|
+
{
|
|
2645
3044
|
button.querySelector('a').className = "fa-solid" + " " + icon + " lexicon";
|
|
2646
3045
|
}
|
|
2647
|
-
else
|
|
3046
|
+
else
|
|
3047
|
+
{
|
|
2648
3048
|
let button = document.createElement('div');
|
|
2649
3049
|
const disabled = options.disabled ?? false;
|
|
2650
3050
|
button.className = "lexmenubutton" + (disabled ? " disabled" : "");
|
|
@@ -2654,15 +3054,21 @@ class Menubar {
|
|
|
2654
3054
|
button.style.maxHeight = "calc(100% - 10px)";
|
|
2655
3055
|
button.style.alignItems = "center";
|
|
2656
3056
|
|
|
2657
|
-
if(options.float == "right")
|
|
3057
|
+
if( options.float == "right" )
|
|
3058
|
+
{
|
|
2658
3059
|
button.right = true;
|
|
2659
|
-
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
if( this.root.lastChild && this.root.lastChild.right )
|
|
3063
|
+
{
|
|
2660
3064
|
this.root.lastChild.before( button );
|
|
2661
3065
|
}
|
|
2662
|
-
else if(options.float == "left")
|
|
2663
|
-
|
|
3066
|
+
else if( options.float == "left" )
|
|
3067
|
+
{
|
|
3068
|
+
this.root.prepend( button );
|
|
2664
3069
|
}
|
|
2665
|
-
else
|
|
3070
|
+
else
|
|
3071
|
+
{
|
|
2666
3072
|
this.root.appendChild( button );
|
|
2667
3073
|
}
|
|
2668
3074
|
|
|
@@ -2682,11 +3088,12 @@ class Menubar {
|
|
|
2682
3088
|
|
|
2683
3089
|
setButtonImage( title, src, callback, options = {} ) {
|
|
2684
3090
|
const button = this.buttons[ title ];
|
|
2685
|
-
if(button)
|
|
2686
|
-
|
|
3091
|
+
if( button )
|
|
3092
|
+
{
|
|
2687
3093
|
button.querySelector('a').className = "fa-solid" + " " + icon + " lexicon";
|
|
2688
3094
|
}
|
|
2689
|
-
else
|
|
3095
|
+
else
|
|
3096
|
+
{
|
|
2690
3097
|
let button = document.createElement('div');
|
|
2691
3098
|
const disabled = options.disabled ?? false;
|
|
2692
3099
|
button.className = "lexmenubutton" + (disabled ? " disabled" : "");
|
|
@@ -2695,15 +3102,21 @@ class Menubar {
|
|
|
2695
3102
|
button.style.padding = "5px";
|
|
2696
3103
|
button.style.alignItems = "center";
|
|
2697
3104
|
|
|
2698
|
-
if(options.float == "right")
|
|
3105
|
+
if( options.float == "right" )
|
|
3106
|
+
{
|
|
2699
3107
|
button.right = true;
|
|
2700
|
-
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
if( this.root.lastChild && this.root.lastChild.right )
|
|
3111
|
+
{
|
|
2701
3112
|
this.root.lastChild.before( button );
|
|
2702
3113
|
}
|
|
2703
|
-
else if(options.float == "left")
|
|
2704
|
-
|
|
3114
|
+
else if( options.float == "left" )
|
|
3115
|
+
{
|
|
3116
|
+
this.root.prepend( button );
|
|
2705
3117
|
}
|
|
2706
|
-
else
|
|
3118
|
+
else
|
|
3119
|
+
{
|
|
2707
3120
|
this.root.appendChild( button );
|
|
2708
3121
|
}
|
|
2709
3122
|
|
|
@@ -2816,90 +3229,306 @@ LX.Menubar = Menubar;
|
|
|
2816
3229
|
|
|
2817
3230
|
class SideBar {
|
|
2818
3231
|
|
|
2819
|
-
|
|
3232
|
+
/**
|
|
3233
|
+
* @param {Object} options
|
|
3234
|
+
* inset: TODO
|
|
3235
|
+
* filter: TODO
|
|
3236
|
+
* skipHeader: Do not use sidebar header [false]
|
|
3237
|
+
* headerImg: Image to be shown as avatar
|
|
3238
|
+
* headerIcon: Icon to be shown as avatar (from LX.ICONS)
|
|
3239
|
+
* headerTitle
|
|
3240
|
+
* headerSubtitle
|
|
3241
|
+
* skipFooter: Do not use sidebar footer [false]
|
|
3242
|
+
* footerImg: Image to be shown as avatar
|
|
3243
|
+
* footerIcon: Icon to be shown as avatar (from LX.ICONS)
|
|
3244
|
+
* footerTitle
|
|
3245
|
+
* footerSubtitle
|
|
3246
|
+
* collapsable: Sidebar can toggle between collapsed/expanded [true]
|
|
3247
|
+
* collapseToIcons: When Sidebar collapses, icons remains visible [true]
|
|
3248
|
+
* onHeaderPressed: Function to call when header is pressed
|
|
3249
|
+
* onFooterPressed: Function to call when footer is pressed
|
|
3250
|
+
*/
|
|
3251
|
+
|
|
3252
|
+
constructor( options = {} ) {
|
|
2820
3253
|
|
|
2821
3254
|
this.root = document.createElement( 'div' );
|
|
2822
3255
|
this.root.className = "lexsidebar";
|
|
2823
3256
|
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
this.
|
|
3257
|
+
window.sidebar = this;
|
|
3258
|
+
|
|
3259
|
+
this.collapsable = options.collapsable ?? true;
|
|
3260
|
+
this.collapseWidth = ( options.collapseToIcons ?? true ) ? "58px" : "0px";
|
|
3261
|
+
this.collapsed = false;
|
|
3262
|
+
|
|
3263
|
+
doAsync( () => {
|
|
3264
|
+
|
|
3265
|
+
this.root.parentElement.ogWidth = this.root.parentElement.style.width;
|
|
3266
|
+
this.root.parentElement.style.transition = "width 0.25s ease-out";
|
|
3267
|
+
|
|
3268
|
+
this.resizeObserver = new ResizeObserver( entries => {
|
|
3269
|
+
for ( const entry of entries )
|
|
3270
|
+
{
|
|
3271
|
+
this.siblingArea.setSize( [ "calc(100% - " + ( entry.contentRect.width ) + "px )", null ] );
|
|
3272
|
+
}
|
|
3273
|
+
});
|
|
3274
|
+
|
|
3275
|
+
}, 100 );
|
|
3276
|
+
|
|
3277
|
+
// This account for header, footer and all inner paddings
|
|
3278
|
+
let contentOffset = 32;
|
|
3279
|
+
|
|
3280
|
+
// Header
|
|
3281
|
+
if( !( options.skipHeader ?? false ) )
|
|
3282
|
+
{
|
|
3283
|
+
this.header = document.createElement( 'div' );
|
|
3284
|
+
this.header.className = "lexsidebarheader";
|
|
3285
|
+
this.root.appendChild( this.header );
|
|
3286
|
+
|
|
3287
|
+
this.header.addEventListener( "click", e => {
|
|
3288
|
+
if( this.collapsed )
|
|
3289
|
+
{
|
|
3290
|
+
e.preventDefault();
|
|
3291
|
+
e.stopPropagation();
|
|
3292
|
+
this.toggleCollapsed();
|
|
3293
|
+
}
|
|
3294
|
+
else if( options.onHeaderPressed )
|
|
3295
|
+
{
|
|
3296
|
+
options.onHeaderPressed( e );
|
|
3297
|
+
}
|
|
3298
|
+
} );
|
|
3299
|
+
|
|
3300
|
+
const avatar = document.createElement( 'span' );
|
|
3301
|
+
avatar.className = "lexavatar";
|
|
3302
|
+
this.header.appendChild( avatar );
|
|
3303
|
+
|
|
3304
|
+
if( options.headerImage )
|
|
3305
|
+
{
|
|
3306
|
+
const avatarImg = document.createElement( 'img' );
|
|
3307
|
+
avatarImg.src = options.headerImage;
|
|
3308
|
+
avatar.appendChild( avatarImg );
|
|
3309
|
+
}
|
|
3310
|
+
else if( options.headerIcon )
|
|
3311
|
+
{
|
|
3312
|
+
const avatarIcon = LX.makeIcon( options.headerIcon );
|
|
3313
|
+
avatar.appendChild( avatarIcon );
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
// Info
|
|
3317
|
+
{
|
|
3318
|
+
const info = document.createElement( 'div' );
|
|
3319
|
+
this.header.appendChild( info );
|
|
3320
|
+
|
|
3321
|
+
const infoText = document.createElement( 'span' );
|
|
3322
|
+
infoText.innerHTML = options.headerTitle ?? "";
|
|
3323
|
+
info.appendChild( infoText );
|
|
3324
|
+
|
|
3325
|
+
const infoSubtext = document.createElement( 'span' );
|
|
3326
|
+
infoSubtext.innerHTML = options.headerSubtitle ?? "";
|
|
3327
|
+
info.appendChild( infoSubtext );
|
|
3328
|
+
}
|
|
3329
|
+
|
|
3330
|
+
if( this.collapsable )
|
|
3331
|
+
{
|
|
3332
|
+
const icon = LX.makeIcon( "Sidebar", "Toggle Sidebar" );
|
|
3333
|
+
this.header.appendChild( icon );
|
|
3334
|
+
|
|
3335
|
+
icon.addEventListener( "click", (e) => {
|
|
3336
|
+
e.preventDefault();
|
|
3337
|
+
e.stopPropagation();
|
|
3338
|
+
this.toggleCollapsed();
|
|
3339
|
+
} );
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
contentOffset += 52;
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
// Content
|
|
3346
|
+
{
|
|
3347
|
+
this.content = document.createElement( 'div' );
|
|
3348
|
+
this.content.className = "lexsidebarcontent";
|
|
3349
|
+
this.root.appendChild( this.content );
|
|
3350
|
+
}
|
|
3351
|
+
|
|
3352
|
+
// Footer
|
|
3353
|
+
if( !( options.skipFooter ?? false ) )
|
|
3354
|
+
{
|
|
3355
|
+
this.footer = document.createElement( 'div' );
|
|
3356
|
+
this.footer.className = "lexsidebarfooter";
|
|
3357
|
+
this.root.appendChild( this.footer );
|
|
3358
|
+
|
|
3359
|
+
this.footer.addEventListener( "click", e => {
|
|
3360
|
+
if( options.onFooterPressed )
|
|
3361
|
+
{
|
|
3362
|
+
options.onFooterPressed( e );
|
|
3363
|
+
}
|
|
3364
|
+
} );
|
|
3365
|
+
|
|
3366
|
+
const avatar = document.createElement( 'span' );
|
|
3367
|
+
avatar.className = "lexavatar";
|
|
3368
|
+
this.footer.appendChild( avatar );
|
|
3369
|
+
|
|
3370
|
+
if( options.footerImage )
|
|
3371
|
+
{
|
|
3372
|
+
const avatarImg = document.createElement( 'img' );
|
|
3373
|
+
avatarImg.src = options.footerImage;
|
|
3374
|
+
avatar.appendChild( avatarImg );
|
|
3375
|
+
}
|
|
3376
|
+
else if( options.footerIcon )
|
|
3377
|
+
{
|
|
3378
|
+
const avatarIcon = LX.makeIcon( options.footerIcon );
|
|
3379
|
+
avatar.appendChild( avatarIcon );
|
|
3380
|
+
}
|
|
3381
|
+
|
|
3382
|
+
// Info
|
|
3383
|
+
{
|
|
3384
|
+
const info = document.createElement( 'div' );
|
|
3385
|
+
this.footer.appendChild( info );
|
|
3386
|
+
|
|
3387
|
+
const infoText = document.createElement( 'span' );
|
|
3388
|
+
infoText.innerHTML = options.footerTitle ?? "";
|
|
3389
|
+
info.appendChild( infoText );
|
|
3390
|
+
|
|
3391
|
+
const infoSubtext = document.createElement( 'span' );
|
|
3392
|
+
infoSubtext.innerHTML = options.footerSubtitle ?? "";
|
|
3393
|
+
info.appendChild( infoSubtext );
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
const icon = LX.makeIcon( "MenuArrows" );
|
|
3397
|
+
this.footer.appendChild( icon );
|
|
3398
|
+
|
|
3399
|
+
contentOffset += 52;
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3402
|
+
// Set width depending on header/footer
|
|
3403
|
+
this.content.style.height = `calc(100% - ${ contentOffset }px)`;
|
|
2827
3404
|
|
|
2828
3405
|
this.items = [ ];
|
|
3406
|
+
this.icons = { };
|
|
3407
|
+
this.groups = { };
|
|
2829
3408
|
}
|
|
2830
3409
|
|
|
2831
3410
|
/**
|
|
2832
|
-
* @method
|
|
2833
|
-
* @param {*} options:
|
|
2834
|
-
* callback: Function to call on each item
|
|
2835
|
-
* bottom: Bool to set item at the bottom as helper button (not selectable)
|
|
2836
|
-
* className: Add class to the entry DOM element
|
|
3411
|
+
* @method toggleCollapsed
|
|
2837
3412
|
*/
|
|
2838
3413
|
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
if( options.constructor == Function )
|
|
2842
|
-
options = { callback: options };
|
|
2843
|
-
|
|
2844
|
-
let pKey = key.replace( /\s/g, '' ).replaceAll( '.', '' );
|
|
3414
|
+
toggleCollapsed() {
|
|
2845
3415
|
|
|
2846
|
-
if( this.
|
|
3416
|
+
if( !this.collapsable )
|
|
2847
3417
|
{
|
|
2848
|
-
console.warn( `'${key}' already created in Sidebar` );
|
|
2849
3418
|
return;
|
|
2850
3419
|
}
|
|
2851
3420
|
|
|
2852
|
-
|
|
2853
|
-
entry.className = "lexsidebarentry " + ( options.className ?? "" );
|
|
2854
|
-
entry.id = pKey;
|
|
3421
|
+
this.collapsed = !this.collapsed;
|
|
2855
3422
|
|
|
2856
|
-
if(
|
|
3423
|
+
if( this.collapsed )
|
|
2857
3424
|
{
|
|
2858
|
-
this.
|
|
3425
|
+
this.root.classList.add( "collapsing" );
|
|
3426
|
+
this.root.parentElement.style.width = this.collapseWidth;
|
|
2859
3427
|
}
|
|
2860
3428
|
else
|
|
2861
3429
|
{
|
|
2862
|
-
this.root.
|
|
3430
|
+
this.root.classList.remove( "collapsing" );
|
|
3431
|
+
this.root.classList.remove( "collapsed" );
|
|
3432
|
+
this.root.parentElement.style.width = this.root.parentElement.ogWidth;
|
|
2863
3433
|
}
|
|
2864
3434
|
|
|
2865
|
-
|
|
2866
|
-
this.root.appendChild( this.footer );
|
|
3435
|
+
this.resizeObserver.observe( this.root.parentElement );
|
|
2867
3436
|
|
|
2868
|
-
|
|
2869
|
-
button.innerHTML = "<i class='"+ (options.icon ?? "") + "'></i>";
|
|
2870
|
-
entry.appendChild( button );
|
|
3437
|
+
doAsync( () => {
|
|
2871
3438
|
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
desc.innerHTML = key;
|
|
2875
|
-
entry.appendChild( desc );
|
|
3439
|
+
this.root.classList.toggle( "collapsed", this.collapsed );
|
|
3440
|
+
this.resizeObserver.unobserve( this.root.parentElement );
|
|
2876
3441
|
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
desc.style.display = "unset";
|
|
2880
|
-
}, 100 );
|
|
2881
|
-
});
|
|
3442
|
+
}, 250 );
|
|
3443
|
+
}
|
|
2882
3444
|
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
3445
|
+
/**
|
|
3446
|
+
* @method separator
|
|
3447
|
+
*/
|
|
3448
|
+
|
|
3449
|
+
separator() {
|
|
3450
|
+
|
|
3451
|
+
this.currentGroup = null;
|
|
3452
|
+
|
|
3453
|
+
this.add( "" );
|
|
3454
|
+
}
|
|
3455
|
+
|
|
3456
|
+
/**
|
|
3457
|
+
* @method group
|
|
3458
|
+
* @param {String} groupName
|
|
3459
|
+
* @param {Object} action: { icon, callback }
|
|
3460
|
+
*/
|
|
3461
|
+
|
|
3462
|
+
group( groupName, action ) {
|
|
3463
|
+
|
|
3464
|
+
this.currentGroup = groupName;
|
|
3465
|
+
|
|
3466
|
+
this.groups[ groupName ] = action;
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
/**
|
|
3470
|
+
* @method add
|
|
3471
|
+
* @param {String} path
|
|
3472
|
+
* @param {Object} options:
|
|
3473
|
+
* callback: Function to call on each item
|
|
3474
|
+
* icon: Entry icon
|
|
3475
|
+
* collapsable: Add entry as a collapsable section
|
|
3476
|
+
* className: Add class to the entry DOM element
|
|
3477
|
+
*/
|
|
3478
|
+
|
|
3479
|
+
add( path, options = {} ) {
|
|
3480
|
+
|
|
3481
|
+
if( options.constructor == Function )
|
|
3482
|
+
{
|
|
3483
|
+
options = { callback: options };
|
|
3484
|
+
}
|
|
3485
|
+
|
|
3486
|
+
// Process path
|
|
3487
|
+
const tokens = path.split( "/" );
|
|
3488
|
+
|
|
3489
|
+
// Assign icons and shortcuts to last token in path
|
|
3490
|
+
const lastPath = tokens[tokens.length - 1];
|
|
3491
|
+
this.icons[ lastPath ] = options.icon;
|
|
2888
3492
|
|
|
2889
|
-
entry.addEventListener("click", () => {
|
|
2890
3493
|
|
|
2891
|
-
|
|
2892
|
-
|
|
3494
|
+
let idx = 0;
|
|
3495
|
+
|
|
3496
|
+
const _insertEntry = ( token, list ) => {
|
|
2893
3497
|
|
|
2894
|
-
|
|
2895
|
-
if( !options.bottom )
|
|
3498
|
+
if( token == undefined )
|
|
2896
3499
|
{
|
|
2897
|
-
|
|
2898
|
-
entry.classList.add( "selected" );
|
|
3500
|
+
return;
|
|
2899
3501
|
}
|
|
2900
|
-
});
|
|
2901
3502
|
|
|
2902
|
-
|
|
3503
|
+
let found = null;
|
|
3504
|
+
list.forEach( o => {
|
|
3505
|
+
const keys = Object.keys( o );
|
|
3506
|
+
const key = keys.find( t => t == token );
|
|
3507
|
+
if( key ) found = o[ key ];
|
|
3508
|
+
} );
|
|
3509
|
+
|
|
3510
|
+
if( found )
|
|
3511
|
+
{
|
|
3512
|
+
_insertEntry( tokens[ idx++ ], found );
|
|
3513
|
+
}
|
|
3514
|
+
else
|
|
3515
|
+
{
|
|
3516
|
+
let item = {};
|
|
3517
|
+
item[ token ] = [];
|
|
3518
|
+
const nextToken = tokens[ idx++ ];
|
|
3519
|
+
// Check if last token -> add callback
|
|
3520
|
+
if( !nextToken )
|
|
3521
|
+
{
|
|
3522
|
+
item[ 'callback' ] = options.callback;
|
|
3523
|
+
item[ 'group' ] = this.currentGroup;
|
|
3524
|
+
item[ 'options' ] = options;
|
|
3525
|
+
}
|
|
3526
|
+
list.push( item );
|
|
3527
|
+
_insertEntry( nextToken, item[ token ] );
|
|
3528
|
+
}
|
|
3529
|
+
};
|
|
3530
|
+
|
|
3531
|
+
_insertEntry( tokens[idx++], this.items );
|
|
2903
3532
|
}
|
|
2904
3533
|
|
|
2905
3534
|
/**
|
|
@@ -2918,6 +3547,246 @@ class SideBar {
|
|
|
2918
3547
|
|
|
2919
3548
|
entry.domEl.click();
|
|
2920
3549
|
}
|
|
3550
|
+
|
|
3551
|
+
_build() {
|
|
3552
|
+
|
|
3553
|
+
for( let item of this.items )
|
|
3554
|
+
{
|
|
3555
|
+
const options = item.options ?? { };
|
|
3556
|
+
|
|
3557
|
+
// Item already created
|
|
3558
|
+
if( item.dom )
|
|
3559
|
+
{
|
|
3560
|
+
continue;
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
let key = Object.keys( item )[ 0 ];
|
|
3564
|
+
let pKey = key.replace( /\s/g, '' ).replaceAll( '.', '' );
|
|
3565
|
+
let currentGroup = null;
|
|
3566
|
+
|
|
3567
|
+
let entry = document.createElement( 'div' );
|
|
3568
|
+
entry.className = "lexsidebarentry " + ( options.className ?? "" );
|
|
3569
|
+
entry.id = pKey;
|
|
3570
|
+
|
|
3571
|
+
if( item.group )
|
|
3572
|
+
{
|
|
3573
|
+
const pGroupKey = item.group.replace( /\s/g, '' ).replaceAll( '.', '' );
|
|
3574
|
+
currentGroup = this.content.querySelector( "#" + pGroupKey );
|
|
3575
|
+
|
|
3576
|
+
if( !currentGroup )
|
|
3577
|
+
{
|
|
3578
|
+
currentGroup = document.createElement( 'div' );
|
|
3579
|
+
currentGroup.id = pGroupKey;
|
|
3580
|
+
currentGroup.className = "lexsidebargroup";
|
|
3581
|
+
this.content.appendChild( currentGroup );
|
|
3582
|
+
|
|
3583
|
+
let groupEntry = document.createElement( 'div' );
|
|
3584
|
+
groupEntry.className = "lexsidebargrouptitle";
|
|
3585
|
+
currentGroup.appendChild( groupEntry );
|
|
3586
|
+
|
|
3587
|
+
let groupLabel = document.createElement( 'div' );
|
|
3588
|
+
groupLabel.innerHTML = item.group;
|
|
3589
|
+
groupEntry.appendChild( groupLabel );
|
|
3590
|
+
|
|
3591
|
+
if( this.groups[ item.group ] != null )
|
|
3592
|
+
{
|
|
3593
|
+
let groupAction = document.createElement( 'a' );
|
|
3594
|
+
groupAction.className = ( this.groups[ item.group ].icon ?? "" ) + " lexicon";
|
|
3595
|
+
groupEntry.appendChild( groupAction );
|
|
3596
|
+
groupAction.addEventListener( "click", (e) => {
|
|
3597
|
+
if( this.groups[ item.group ].callback )
|
|
3598
|
+
{
|
|
3599
|
+
this.groups[ item.group ].callback( item.group, e );
|
|
3600
|
+
}
|
|
3601
|
+
} );
|
|
3602
|
+
}
|
|
3603
|
+
|
|
3604
|
+
}
|
|
3605
|
+
else if( !currentGroup.classList.contains( "lexsidebargroup" ) )
|
|
3606
|
+
{
|
|
3607
|
+
throw( "Bad id: " + item.group );
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
|
|
3611
|
+
if( pKey == "" )
|
|
3612
|
+
{
|
|
3613
|
+
let separatorDom = document.createElement( 'div' );
|
|
3614
|
+
separatorDom.className = "lexsidebarseparator";
|
|
3615
|
+
this.content.appendChild( separatorDom );
|
|
3616
|
+
continue;
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
if( this.collapseContainer )
|
|
3620
|
+
{
|
|
3621
|
+
this.collapseContainer.appendChild( entry );
|
|
3622
|
+
|
|
3623
|
+
this.collapseQueue--;
|
|
3624
|
+
if( !this.collapseQueue )
|
|
3625
|
+
{
|
|
3626
|
+
delete this.collapseContainer;
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
else if( currentGroup )
|
|
3630
|
+
{
|
|
3631
|
+
currentGroup.appendChild( entry );
|
|
3632
|
+
}
|
|
3633
|
+
else
|
|
3634
|
+
{
|
|
3635
|
+
this.content.appendChild( entry );
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3638
|
+
let itemDom = document.createElement( 'div' );
|
|
3639
|
+
entry.appendChild( itemDom );
|
|
3640
|
+
item.dom = itemDom;
|
|
3641
|
+
|
|
3642
|
+
if( options.type == "checkbox" )
|
|
3643
|
+
{
|
|
3644
|
+
item.value = options.value ?? false;
|
|
3645
|
+
const panel = new Panel();
|
|
3646
|
+
item.checkbox = panel.addCheckbox(null, item.value, (value, event) => {
|
|
3647
|
+
event.preventDefault();
|
|
3648
|
+
event.stopPropagation();
|
|
3649
|
+
const f = options.callback;
|
|
3650
|
+
item.value = value;
|
|
3651
|
+
if( f ) f.call( this, key, value, event );
|
|
3652
|
+
}, { label: key, signal: ( "@checkbox_" + key ) });
|
|
3653
|
+
itemDom.appendChild( panel.root.childNodes[ 0 ] );
|
|
3654
|
+
}
|
|
3655
|
+
else
|
|
3656
|
+
{
|
|
3657
|
+
if( options.icon )
|
|
3658
|
+
{
|
|
3659
|
+
let itemIcon = document.createElement( 'i' );
|
|
3660
|
+
itemIcon.className = options.icon;
|
|
3661
|
+
itemDom.appendChild( itemIcon );
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
let itemName = document.createElement( 'a' );
|
|
3665
|
+
itemName.innerHTML = key;
|
|
3666
|
+
itemDom.appendChild( itemName );
|
|
3667
|
+
}
|
|
3668
|
+
|
|
3669
|
+
entry.addEventListener("click", ( e ) => {
|
|
3670
|
+
if( e.target && e.target.classList.contains( "lexcheckbox" ) )
|
|
3671
|
+
{
|
|
3672
|
+
return;
|
|
3673
|
+
}
|
|
3674
|
+
|
|
3675
|
+
if( options.collapsable )
|
|
3676
|
+
{
|
|
3677
|
+
itemDom.querySelector( ".collapser" ).click();
|
|
3678
|
+
}
|
|
3679
|
+
else
|
|
3680
|
+
{
|
|
3681
|
+
const f = options.callback;
|
|
3682
|
+
if( f ) f.call( this, key, item.value, e );
|
|
3683
|
+
|
|
3684
|
+
if( item.checkbox )
|
|
3685
|
+
{
|
|
3686
|
+
item.value = !item.value;
|
|
3687
|
+
item.checkbox.set( item.value, true );
|
|
3688
|
+
}
|
|
3689
|
+
}
|
|
3690
|
+
|
|
3691
|
+
// Manage selected
|
|
3692
|
+
this.root.querySelectorAll(".lexsidebarentry").forEach( e => e.classList.remove( 'selected' ) );
|
|
3693
|
+
entry.classList.add( "selected" );
|
|
3694
|
+
});
|
|
3695
|
+
|
|
3696
|
+
if( options.action )
|
|
3697
|
+
{
|
|
3698
|
+
const actionIcon = LX.makeIcon( options.action.icon ?? "MoreHorizontal", options.action.name );
|
|
3699
|
+
itemDom.appendChild( actionIcon );
|
|
3700
|
+
|
|
3701
|
+
actionIcon.addEventListener( "click", (e) => {
|
|
3702
|
+
e.preventDefault();
|
|
3703
|
+
e.stopImmediatePropagation();
|
|
3704
|
+
const f = options.action.callback;
|
|
3705
|
+
if( f ) f.call( this, key, e );
|
|
3706
|
+
} );
|
|
3707
|
+
}
|
|
3708
|
+
else if( options.collapsable )
|
|
3709
|
+
{
|
|
3710
|
+
const collapsableContent = document.createElement( 'div' );
|
|
3711
|
+
Object.assign( collapsableContent.style, { width: "100%", display: "none" } );
|
|
3712
|
+
LX.makeCollapsible( itemDom, collapsableContent, currentGroup ?? this.content );
|
|
3713
|
+
this.collapseQueue = options.collapsable;
|
|
3714
|
+
this.collapseContainer = collapsableContent;
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3717
|
+
let desc = document.createElement( 'span' );
|
|
3718
|
+
desc.className = 'lexsidebarentrydesc';
|
|
3719
|
+
desc.innerHTML = key;
|
|
3720
|
+
entry.appendChild( desc );
|
|
3721
|
+
|
|
3722
|
+
itemDom.addEventListener("mouseenter", () => {
|
|
3723
|
+
setTimeout( () => {
|
|
3724
|
+
desc.style.display = "unset";
|
|
3725
|
+
}, 150 );
|
|
3726
|
+
});
|
|
3727
|
+
|
|
3728
|
+
itemDom.addEventListener("mouseleave", () => {
|
|
3729
|
+
setTimeout( () => {
|
|
3730
|
+
desc.style.display = "none";
|
|
3731
|
+
}, 150 );
|
|
3732
|
+
});
|
|
3733
|
+
|
|
3734
|
+
// Subentries
|
|
3735
|
+
if( !item[ key ].length )
|
|
3736
|
+
{
|
|
3737
|
+
continue;
|
|
3738
|
+
}
|
|
3739
|
+
|
|
3740
|
+
let subentryContainer = document.createElement( 'div' );
|
|
3741
|
+
subentryContainer.className = "lexsidebarsubentrycontainer";
|
|
3742
|
+
|
|
3743
|
+
if( currentGroup )
|
|
3744
|
+
{
|
|
3745
|
+
currentGroup.appendChild( subentryContainer );
|
|
3746
|
+
}
|
|
3747
|
+
else
|
|
3748
|
+
{
|
|
3749
|
+
this.content.appendChild( subentryContainer );
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
for( var i = 0; i < item[ key ].length; ++i )
|
|
3753
|
+
{
|
|
3754
|
+
const subitem = item[ key ][ i ];
|
|
3755
|
+
const suboptions = subitem.options ?? {};
|
|
3756
|
+
const subkey = Object.keys( subitem )[ 0 ];
|
|
3757
|
+
|
|
3758
|
+
let subentry = document.createElement( 'div' );
|
|
3759
|
+
subentry.innerHTML = `<span>${ subkey }</span>`;
|
|
3760
|
+
|
|
3761
|
+
if( suboptions.action )
|
|
3762
|
+
{
|
|
3763
|
+
const actionIcon = LX.makeIcon( suboptions.action.icon ?? "MoreHorizontal", suboptions.action.name );
|
|
3764
|
+
subentry.appendChild( actionIcon );
|
|
3765
|
+
|
|
3766
|
+
actionIcon.addEventListener( "click", (e) => {
|
|
3767
|
+
e.preventDefault();
|
|
3768
|
+
e.stopImmediatePropagation();
|
|
3769
|
+
const f = suboptions.action.callback;
|
|
3770
|
+
if( f ) f.call( this, subkey, e );
|
|
3771
|
+
} );
|
|
3772
|
+
}
|
|
3773
|
+
|
|
3774
|
+
subentry.className = "lexsidebarentry";
|
|
3775
|
+
subentry.id = subkey;
|
|
3776
|
+
subentryContainer.appendChild( subentry );
|
|
3777
|
+
|
|
3778
|
+
subentry.addEventListener("click", (e) => {
|
|
3779
|
+
|
|
3780
|
+
const f = suboptions.callback;
|
|
3781
|
+
if( f ) f.call( this, subkey, subentry, e );
|
|
3782
|
+
|
|
3783
|
+
// Manage selected
|
|
3784
|
+
this.root.querySelectorAll(".lexsidebarentry").forEach( e => e.classList.remove( 'selected' ) );
|
|
3785
|
+
entry.classList.add( "selected" );
|
|
3786
|
+
});
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
2921
3790
|
};
|
|
2922
3791
|
|
|
2923
3792
|
LX.SideBar = SideBar;
|
|
@@ -2935,29 +3804,32 @@ class Widget {
|
|
|
2935
3804
|
static DROPDOWN = 4;
|
|
2936
3805
|
static CHECKBOX = 5;
|
|
2937
3806
|
static TOGGLE = 6;
|
|
2938
|
-
static
|
|
2939
|
-
static
|
|
2940
|
-
static
|
|
2941
|
-
static
|
|
2942
|
-
static
|
|
2943
|
-
static
|
|
2944
|
-
static
|
|
2945
|
-
static
|
|
2946
|
-
static
|
|
2947
|
-
static
|
|
2948
|
-
static
|
|
2949
|
-
static
|
|
2950
|
-
static
|
|
2951
|
-
static
|
|
2952
|
-
static
|
|
2953
|
-
static
|
|
2954
|
-
static
|
|
2955
|
-
static
|
|
2956
|
-
static
|
|
2957
|
-
static
|
|
2958
|
-
static
|
|
2959
|
-
static
|
|
2960
|
-
static
|
|
3807
|
+
static RADIO = 7;
|
|
3808
|
+
static COLOR = 8;
|
|
3809
|
+
static RANGE = 9;
|
|
3810
|
+
static NUMBER = 10;
|
|
3811
|
+
static TITLE = 11;
|
|
3812
|
+
static VECTOR = 12;
|
|
3813
|
+
static TREE = 13;
|
|
3814
|
+
static PROGRESS = 14;
|
|
3815
|
+
static FILE = 15;
|
|
3816
|
+
static LAYERS = 16;
|
|
3817
|
+
static ARRAY = 17;
|
|
3818
|
+
static LIST = 18;
|
|
3819
|
+
static TAGS = 19;
|
|
3820
|
+
static CURVE = 20;
|
|
3821
|
+
static CARD = 21;
|
|
3822
|
+
static IMAGE = 22;
|
|
3823
|
+
static CONTENT = 23;
|
|
3824
|
+
static CUSTOM = 24;
|
|
3825
|
+
static SEPARATOR = 25;
|
|
3826
|
+
static KNOB = 26;
|
|
3827
|
+
static SIZE = 27;
|
|
3828
|
+
static PAD = 28;
|
|
3829
|
+
static FORM = 29;
|
|
3830
|
+
static DIAL = 30;
|
|
3831
|
+
static COUNTER = 31;
|
|
3832
|
+
static TABLE = 32;
|
|
2961
3833
|
|
|
2962
3834
|
static NO_CONTEXT_TYPES = [
|
|
2963
3835
|
Widget.BUTTON,
|
|
@@ -2985,7 +3857,9 @@ class Widget {
|
|
|
2985
3857
|
set( value, skipCallback = false, signalName = "" ) {
|
|
2986
3858
|
|
|
2987
3859
|
if( this.onSetValue )
|
|
3860
|
+
{
|
|
2988
3861
|
return this.onSetValue( value, skipCallback );
|
|
3862
|
+
}
|
|
2989
3863
|
|
|
2990
3864
|
console.warn("Can't set value of " + this.typeName());
|
|
2991
3865
|
}
|
|
@@ -3024,14 +3898,17 @@ class Widget {
|
|
|
3024
3898
|
|
|
3025
3899
|
typeName() {
|
|
3026
3900
|
|
|
3027
|
-
switch( this.type )
|
|
3901
|
+
switch( this.type )
|
|
3902
|
+
{
|
|
3028
3903
|
case Widget.TEXT: return "Text";
|
|
3029
3904
|
case Widget.TEXTAREA: return "TextArea";
|
|
3030
3905
|
case Widget.BUTTON: return "Button";
|
|
3031
3906
|
case Widget.DROPDOWN: return "Dropdown";
|
|
3032
3907
|
case Widget.CHECKBOX: return "Checkbox";
|
|
3033
3908
|
case Widget.TOGGLE: return "Toggle";
|
|
3909
|
+
case Widget.RADIO: return "Radio";
|
|
3034
3910
|
case Widget.COLOR: return "Color";
|
|
3911
|
+
case Widget.RANGE: return "Range";
|
|
3035
3912
|
case Widget.NUMBER: return "Number";
|
|
3036
3913
|
case Widget.VECTOR: return "Vector";
|
|
3037
3914
|
case Widget.TREE: return "Tree";
|
|
@@ -3048,6 +3925,7 @@ class Widget {
|
|
|
3048
3925
|
case Widget.FORM: return "Form";
|
|
3049
3926
|
case Widget.DIAL: return "Dial";
|
|
3050
3927
|
case Widget.COUNTER: return "Counter";
|
|
3928
|
+
case Widget.TABLE: return "Table";
|
|
3051
3929
|
case Widget.CUSTOM: return this.customName;
|
|
3052
3930
|
}
|
|
3053
3931
|
|
|
@@ -3108,11 +3986,12 @@ function ADD_CUSTOM_WIDGET( custom_widget_name, options = {} )
|
|
|
3108
3986
|
buttonName += "<a class='fa-solid " + (instance ? "fa-bars-staggered" : " ") + " menu' style='float:right; width:5%;'></a>";
|
|
3109
3987
|
|
|
3110
3988
|
let buttonEl = this.addButton(null, buttonName, (value, event) => {
|
|
3111
|
-
|
|
3112
|
-
|
|
3989
|
+
if( instance )
|
|
3990
|
+
{
|
|
3113
3991
|
element.querySelector(".lexcustomitems").toggleAttribute('hidden');
|
|
3114
3992
|
}
|
|
3115
|
-
else
|
|
3993
|
+
else
|
|
3994
|
+
{
|
|
3116
3995
|
addContextMenu(null, event, c => {
|
|
3117
3996
|
c.add("New " + custom_widget_name, () => {
|
|
3118
3997
|
instance = {};
|
|
@@ -3299,16 +4178,20 @@ class NodeTree {
|
|
|
3299
4178
|
|
|
3300
4179
|
// Add or remove
|
|
3301
4180
|
const idx = this.selected.indexOf( node );
|
|
3302
|
-
if( idx > -1 )
|
|
4181
|
+
if( idx > -1 )
|
|
4182
|
+
{
|
|
3303
4183
|
item.classList.remove( 'selected' );
|
|
3304
4184
|
this.selected.splice( idx, 1 );
|
|
3305
|
-
}
|
|
4185
|
+
}
|
|
4186
|
+
else
|
|
4187
|
+
{
|
|
3306
4188
|
item.classList.add( 'selected' );
|
|
3307
4189
|
this.selected.push( node );
|
|
3308
4190
|
}
|
|
3309
4191
|
|
|
3310
4192
|
// Only Show children...
|
|
3311
|
-
if( isParent && node.id.length > 1 /* Strange case... */)
|
|
4193
|
+
if( isParent && node.id.length > 1 /* Strange case... */)
|
|
4194
|
+
{
|
|
3312
4195
|
node.closed = false;
|
|
3313
4196
|
if( that.onevent )
|
|
3314
4197
|
{
|
|
@@ -3346,7 +4229,7 @@ class NodeTree {
|
|
|
3346
4229
|
|
|
3347
4230
|
e.preventDefault();
|
|
3348
4231
|
|
|
3349
|
-
if( that.onevent )
|
|
4232
|
+
if( !that.onevent )
|
|
3350
4233
|
{
|
|
3351
4234
|
return;
|
|
3352
4235
|
}
|
|
@@ -3402,7 +4285,8 @@ class NodeTree {
|
|
|
3402
4285
|
return;
|
|
3403
4286
|
}
|
|
3404
4287
|
|
|
3405
|
-
if( that.onevent )
|
|
4288
|
+
if( that.onevent )
|
|
4289
|
+
{
|
|
3406
4290
|
const event = new TreeEvent( TreeEvent.NODE_DELETED, node, e );
|
|
3407
4291
|
that.onevent( event );
|
|
3408
4292
|
}
|
|
@@ -3429,7 +4313,8 @@ class NodeTree {
|
|
|
3429
4313
|
if( e.key == "Delete" )
|
|
3430
4314
|
{
|
|
3431
4315
|
// Send event now so we have the info in selected array..
|
|
3432
|
-
if( that.onevent )
|
|
4316
|
+
if( that.onevent )
|
|
4317
|
+
{
|
|
3433
4318
|
const event = new TreeEvent( TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e );
|
|
3434
4319
|
event.multiple = this.selected.length > 1;
|
|
3435
4320
|
that.onevent( event );
|
|
@@ -3460,22 +4345,24 @@ class NodeTree {
|
|
|
3460
4345
|
|
|
3461
4346
|
// Node rename
|
|
3462
4347
|
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
item.appendChild(
|
|
4348
|
+
const nameInput = document.createElement( "input" );
|
|
4349
|
+
nameInput.toggleAttribute( "hidden", !node.rename );
|
|
4350
|
+
nameInput.value = node.id;
|
|
4351
|
+
item.appendChild(nameInput);
|
|
3467
4352
|
|
|
3468
|
-
if(node.rename)
|
|
4353
|
+
if( node.rename )
|
|
4354
|
+
{
|
|
3469
4355
|
item.classList.add('selected');
|
|
3470
|
-
|
|
4356
|
+
nameInput.focus();
|
|
3471
4357
|
}
|
|
3472
4358
|
|
|
3473
|
-
|
|
3474
|
-
if(e.key ==
|
|
3475
|
-
|
|
4359
|
+
nameInput.addEventListener("keyup", function(e){
|
|
4360
|
+
if( e.key == "Enter" )
|
|
4361
|
+
{
|
|
3476
4362
|
this.value = this.value.replace(/\s/g, '_');
|
|
3477
4363
|
|
|
3478
|
-
if(that.onevent)
|
|
4364
|
+
if( that.onevent )
|
|
4365
|
+
{
|
|
3479
4366
|
const event = new TreeEvent(TreeEvent.NODE_RENAMED, node, this.value);
|
|
3480
4367
|
that.onevent( event );
|
|
3481
4368
|
}
|
|
@@ -3485,18 +4372,20 @@ class NodeTree {
|
|
|
3485
4372
|
that.frefresh( node.id );
|
|
3486
4373
|
list.querySelector("#" + node.id).classList.add('selected');
|
|
3487
4374
|
}
|
|
3488
|
-
if(e.key ==
|
|
4375
|
+
else if(e.key == "Escape")
|
|
4376
|
+
{
|
|
3489
4377
|
delete node.rename;
|
|
3490
4378
|
that.frefresh( node.id );
|
|
3491
4379
|
}
|
|
3492
4380
|
});
|
|
3493
4381
|
|
|
3494
|
-
|
|
4382
|
+
nameInput.addEventListener("blur", function(e){
|
|
3495
4383
|
delete node.rename;
|
|
3496
4384
|
that.refresh();
|
|
3497
4385
|
});
|
|
3498
4386
|
|
|
3499
|
-
if(this.options.draggable ?? true)
|
|
4387
|
+
if( this.options.draggable ?? true )
|
|
4388
|
+
{
|
|
3500
4389
|
// Drag nodes
|
|
3501
4390
|
if(parent) // Root doesn't move!
|
|
3502
4391
|
{
|
|
@@ -3522,29 +4411,32 @@ class NodeTree {
|
|
|
3522
4411
|
return;
|
|
3523
4412
|
let target = node;
|
|
3524
4413
|
// Can't drop to same node
|
|
3525
|
-
if(dragged.id == target.id)
|
|
4414
|
+
if( dragged.id == target.id )
|
|
4415
|
+
{
|
|
3526
4416
|
console.warn("Cannot parent node to itself!");
|
|
3527
4417
|
return;
|
|
3528
4418
|
}
|
|
3529
4419
|
|
|
3530
4420
|
// Can't drop to child node
|
|
3531
|
-
const isChild = function(
|
|
4421
|
+
const isChild = function( newParent, node ) {
|
|
3532
4422
|
var result = false;
|
|
3533
|
-
for( var c of node.children )
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
result |= isChild(
|
|
4423
|
+
for( var c of node.children )
|
|
4424
|
+
{
|
|
4425
|
+
if( c.id == newParent.id ) return true;
|
|
4426
|
+
result |= isChild( newParent, c );
|
|
3537
4427
|
}
|
|
3538
4428
|
return result;
|
|
3539
4429
|
};
|
|
3540
4430
|
|
|
3541
|
-
if(isChild(target, dragged))
|
|
4431
|
+
if( isChild( target, dragged ))
|
|
4432
|
+
{
|
|
3542
4433
|
console.warn("Cannot parent node to a current child!");
|
|
3543
4434
|
return;
|
|
3544
4435
|
}
|
|
3545
4436
|
|
|
3546
4437
|
// Trigger node dragger event
|
|
3547
|
-
if(that.onevent)
|
|
4438
|
+
if( that.onevent )
|
|
4439
|
+
{
|
|
3548
4440
|
const event = new TreeEvent(TreeEvent.NODE_DRAGGED, dragged, target);
|
|
3549
4441
|
that.onevent( event );
|
|
3550
4442
|
}
|
|
@@ -3560,7 +4452,8 @@ class NodeTree {
|
|
|
3560
4452
|
let handled = false;
|
|
3561
4453
|
|
|
3562
4454
|
// Show/hide children
|
|
3563
|
-
if(isParent)
|
|
4455
|
+
if( isParent )
|
|
4456
|
+
{
|
|
3564
4457
|
item.querySelector('a.hierarchy').addEventListener("click", function(e) {
|
|
3565
4458
|
|
|
3566
4459
|
handled = true;
|
|
@@ -3568,7 +4461,8 @@ class NodeTree {
|
|
|
3568
4461
|
e.stopPropagation();
|
|
3569
4462
|
|
|
3570
4463
|
node.closed = !node.closed;
|
|
3571
|
-
if(that.onevent)
|
|
4464
|
+
if( that.onevent )
|
|
4465
|
+
{
|
|
3572
4466
|
const event = new TreeEvent(TreeEvent.NODE_CARETCHANGED, node, node.closed);
|
|
3573
4467
|
that.onevent( event );
|
|
3574
4468
|
}
|
|
@@ -3588,7 +4482,8 @@ class NodeTree {
|
|
|
3588
4482
|
node.visible = node.visible === undefined ? false : !node.visible;
|
|
3589
4483
|
this.className = "itemicon fa-solid fa-eye" + (!node.visible ? "-slash" : "");
|
|
3590
4484
|
// Trigger visibility event
|
|
3591
|
-
if(that.onevent)
|
|
4485
|
+
if( that.onevent )
|
|
4486
|
+
{
|
|
3592
4487
|
const event = new TreeEvent(TreeEvent.NODE_VISIBILITY, node, node.visible);
|
|
3593
4488
|
that.onevent( event );
|
|
3594
4489
|
}
|
|
@@ -3597,9 +4492,10 @@ class NodeTree {
|
|
|
3597
4492
|
item.appendChild(visibility);
|
|
3598
4493
|
}
|
|
3599
4494
|
|
|
3600
|
-
if(node.actions)
|
|
4495
|
+
if( node.actions )
|
|
3601
4496
|
{
|
|
3602
|
-
for(var i = 0; i < node.actions.length; ++i)
|
|
4497
|
+
for( var i = 0; i < node.actions.length; ++i )
|
|
4498
|
+
{
|
|
3603
4499
|
let a = node.actions[i];
|
|
3604
4500
|
var actionEl = document.createElement('a');
|
|
3605
4501
|
actionEl.className = "itemicon " + a.icon;
|
|
@@ -3612,20 +4508,25 @@ class NodeTree {
|
|
|
3612
4508
|
}
|
|
3613
4509
|
}
|
|
3614
4510
|
|
|
3615
|
-
if(selectedId != undefined && node.id == selectedId)
|
|
3616
|
-
|
|
4511
|
+
if( selectedId != undefined && node.id == selectedId )
|
|
4512
|
+
{
|
|
4513
|
+
this.selected = [ node ];
|
|
3617
4514
|
item.click();
|
|
3618
4515
|
}
|
|
3619
4516
|
|
|
3620
|
-
if(node.closed )
|
|
4517
|
+
if( node.closed )
|
|
4518
|
+
{
|
|
3621
4519
|
return;
|
|
4520
|
+
}
|
|
3622
4521
|
|
|
3623
4522
|
for( var i = 0; i < node.children.length; ++i )
|
|
3624
4523
|
{
|
|
3625
|
-
let child = node.children[i];
|
|
4524
|
+
let child = node.children[ i ];
|
|
3626
4525
|
|
|
3627
|
-
if( this.options.onlyFolders && child.type != 'folder')
|
|
4526
|
+
if( this.options.onlyFolders && child.type != 'folder' )
|
|
4527
|
+
{
|
|
3628
4528
|
continue;
|
|
4529
|
+
}
|
|
3629
4530
|
|
|
3630
4531
|
this._create_item( node, child, level + 1 );
|
|
3631
4532
|
}
|
|
@@ -3664,12 +4565,12 @@ class Panel {
|
|
|
3664
4565
|
* style: CSS Style object to be applied to the panel
|
|
3665
4566
|
*/
|
|
3666
4567
|
|
|
3667
|
-
constructor( options = {} )
|
|
4568
|
+
constructor( options = {} ) {
|
|
3668
4569
|
var root = document.createElement('div');
|
|
3669
4570
|
root.className = "lexpanel";
|
|
3670
|
-
if(options.id)
|
|
4571
|
+
if( options.id )
|
|
3671
4572
|
root.id = options.id;
|
|
3672
|
-
if(options.className)
|
|
4573
|
+
if( options.className )
|
|
3673
4574
|
root.className += " " + options.className;
|
|
3674
4575
|
|
|
3675
4576
|
root.style.width = options.width || "calc( 100% - 6px )";
|
|
@@ -3746,23 +4647,31 @@ class Panel {
|
|
|
3746
4647
|
this.branches = [];
|
|
3747
4648
|
this.current_branch = null;
|
|
3748
4649
|
|
|
3749
|
-
for(let w in this.widgets)
|
|
3750
|
-
|
|
4650
|
+
for( let w in this.widgets )
|
|
4651
|
+
{
|
|
4652
|
+
if( this.widgets[w].options && this.widgets[w].options.signal )
|
|
4653
|
+
{
|
|
3751
4654
|
const signal = this.widgets[w].options.signal;
|
|
3752
|
-
for(let i = 0; i < LX.signals[signal].length; i++)
|
|
3753
|
-
|
|
4655
|
+
for( let i = 0; i < LX.signals[signal].length; i++ )
|
|
4656
|
+
{
|
|
4657
|
+
if( LX.signals[signal][i] == this.widgets[w] )
|
|
4658
|
+
{
|
|
3754
4659
|
LX.signals[signal] = [...LX.signals[signal].slice(0, i), ...LX.signals[signal].slice(i+1)];
|
|
3755
4660
|
}
|
|
3756
4661
|
}
|
|
3757
4662
|
}
|
|
3758
4663
|
}
|
|
3759
4664
|
|
|
3760
|
-
if(this.signals)
|
|
3761
|
-
|
|
4665
|
+
if( this.signals )
|
|
4666
|
+
{
|
|
4667
|
+
for( let w = 0; w < this.signals.length; w++ )
|
|
4668
|
+
{
|
|
3762
4669
|
let widget = Object.values(this.signals[w])[0];
|
|
3763
4670
|
let signal = widget.options.signal;
|
|
3764
|
-
for(let i = 0; i < LX.signals[signal].length; i++)
|
|
3765
|
-
|
|
4671
|
+
for( let i = 0; i < LX.signals[signal].length; i++ )
|
|
4672
|
+
{
|
|
4673
|
+
if( LX.signals[signal][i] == widget )
|
|
4674
|
+
{
|
|
3766
4675
|
LX.signals[signal] = [...LX.signals[signal].slice(0, i), ...LX.signals[signal].slice(i+1)];
|
|
3767
4676
|
}
|
|
3768
4677
|
}
|
|
@@ -3800,10 +4709,12 @@ class Panel {
|
|
|
3800
4709
|
|
|
3801
4710
|
this._inline_widgets_left = -1;
|
|
3802
4711
|
|
|
3803
|
-
if(!this._inlineContainer)
|
|
4712
|
+
if( !this._inlineContainer )
|
|
4713
|
+
{
|
|
3804
4714
|
this._inlineContainer = document.createElement('div');
|
|
3805
4715
|
this._inlineContainer.className = "lexinlinewidgets";
|
|
3806
|
-
|
|
4716
|
+
|
|
4717
|
+
if( justifyContent )
|
|
3807
4718
|
{
|
|
3808
4719
|
this._inlineContainer.style.justifyContent = justifyContent;
|
|
3809
4720
|
}
|
|
@@ -3817,7 +4728,7 @@ class Panel {
|
|
|
3817
4728
|
if(is_pair)
|
|
3818
4729
|
{
|
|
3819
4730
|
// eg. an array, inline items appended later to
|
|
3820
|
-
if(this._inline_queued_container)
|
|
4731
|
+
if( this._inline_queued_container)
|
|
3821
4732
|
this._inlineContainer.appendChild( item[0] );
|
|
3822
4733
|
// eg. a dropdown, item is appended to parent, not to inline cont.
|
|
3823
4734
|
else
|
|
@@ -3829,7 +4740,7 @@ class Panel {
|
|
|
3829
4740
|
|
|
3830
4741
|
if(!this._inline_queued_container)
|
|
3831
4742
|
{
|
|
3832
|
-
if(this.current_branch)
|
|
4743
|
+
if( this.current_branch)
|
|
3833
4744
|
this.current_branch.content.appendChild( this._inlineContainer );
|
|
3834
4745
|
else
|
|
3835
4746
|
this.root.appendChild( this._inlineContainer );
|
|
@@ -3868,7 +4779,7 @@ class Panel {
|
|
|
3868
4779
|
this.current_branch = branch;
|
|
3869
4780
|
|
|
3870
4781
|
// Append to panel
|
|
3871
|
-
if(this.branches.length == 0)
|
|
4782
|
+
if( this.branches.length == 0)
|
|
3872
4783
|
branch.root.classList.add('first');
|
|
3873
4784
|
|
|
3874
4785
|
// This is the last!
|
|
@@ -3879,7 +4790,8 @@ class Panel {
|
|
|
3879
4790
|
this.root.appendChild( branch.root );
|
|
3880
4791
|
|
|
3881
4792
|
// Add widget filter
|
|
3882
|
-
if(options.filter)
|
|
4793
|
+
if( options.filter )
|
|
4794
|
+
{
|
|
3883
4795
|
this._addFilter( options.filter, {callback: this._searchWidgets.bind(this, branch.name)} );
|
|
3884
4796
|
}
|
|
3885
4797
|
|
|
@@ -3996,14 +4908,18 @@ class Panel {
|
|
|
3996
4908
|
element.jsInstance = widget;
|
|
3997
4909
|
|
|
3998
4910
|
const insert_widget = el => {
|
|
3999
|
-
if(options.container)
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4911
|
+
if( options.container )
|
|
4912
|
+
{
|
|
4913
|
+
options.container.appendChild( el );
|
|
4914
|
+
}
|
|
4915
|
+
else if( !this.queuedContainer )
|
|
4916
|
+
{
|
|
4917
|
+
if( this.current_branch )
|
|
4004
4918
|
{
|
|
4005
|
-
if(!options.skipWidget)
|
|
4919
|
+
if( !options.skipWidget )
|
|
4920
|
+
{
|
|
4006
4921
|
this.current_branch.widgets.push( widget );
|
|
4922
|
+
}
|
|
4007
4923
|
this.current_branch.content.appendChild( el );
|
|
4008
4924
|
}
|
|
4009
4925
|
else
|
|
@@ -4013,40 +4929,47 @@ class Panel {
|
|
|
4013
4929
|
}
|
|
4014
4930
|
}
|
|
4015
4931
|
// Append content to queued tab container
|
|
4016
|
-
else
|
|
4932
|
+
else
|
|
4933
|
+
{
|
|
4017
4934
|
this.queuedContainer.appendChild( el );
|
|
4018
4935
|
}
|
|
4019
4936
|
};
|
|
4020
4937
|
|
|
4021
4938
|
const store_widget = el => {
|
|
4022
4939
|
|
|
4023
|
-
if(!this.queuedContainer)
|
|
4940
|
+
if( !this.queuedContainer )
|
|
4941
|
+
{
|
|
4024
4942
|
this._inlineWidgets.push( el );
|
|
4025
4943
|
}
|
|
4026
4944
|
// Append content to queued tab container
|
|
4027
|
-
else
|
|
4945
|
+
else
|
|
4946
|
+
{
|
|
4028
4947
|
this._inlineWidgets.push( [el, this.queuedContainer] );
|
|
4029
4948
|
}
|
|
4030
4949
|
};
|
|
4031
4950
|
|
|
4032
4951
|
// Process inline widgets
|
|
4033
|
-
if(this._inline_widgets_left > 0 && !options.skipInlineCount)
|
|
4952
|
+
if( this._inline_widgets_left > 0 && !options.skipInlineCount )
|
|
4034
4953
|
{
|
|
4035
|
-
if(!this._inlineWidgets)
|
|
4954
|
+
if( !this._inlineWidgets )
|
|
4955
|
+
{
|
|
4036
4956
|
this._inlineWidgets = [];
|
|
4037
4957
|
}
|
|
4038
4958
|
|
|
4039
4959
|
// Store widget and its container
|
|
4040
|
-
store_widget(element);
|
|
4960
|
+
store_widget( element );
|
|
4041
4961
|
|
|
4042
4962
|
this._inline_widgets_left--;
|
|
4043
4963
|
|
|
4044
4964
|
// Last widget
|
|
4045
|
-
if(!this._inline_widgets_left)
|
|
4965
|
+
if( !this._inline_widgets_left )
|
|
4966
|
+
{
|
|
4046
4967
|
this.endLine();
|
|
4047
4968
|
}
|
|
4048
|
-
}
|
|
4049
|
-
|
|
4969
|
+
}
|
|
4970
|
+
else
|
|
4971
|
+
{
|
|
4972
|
+
insert_widget( element );
|
|
4050
4973
|
}
|
|
4051
4974
|
|
|
4052
4975
|
return widget;
|
|
@@ -4070,8 +4993,8 @@ class Panel {
|
|
|
4070
4993
|
|
|
4071
4994
|
let searchIcon = document.createElement('a');
|
|
4072
4995
|
searchIcon.className = "fa-solid fa-magnifying-glass";
|
|
4073
|
-
element.appendChild(input);
|
|
4074
4996
|
element.appendChild(searchIcon);
|
|
4997
|
+
element.appendChild(input);
|
|
4075
4998
|
|
|
4076
4999
|
input.addEventListener("input", (e) => {
|
|
4077
5000
|
if(options.callback)
|
|
@@ -4083,15 +5006,20 @@ class Panel {
|
|
|
4083
5006
|
|
|
4084
5007
|
_searchWidgets(branchName, value) {
|
|
4085
5008
|
|
|
4086
|
-
for( let b of this.branches )
|
|
4087
|
-
|
|
4088
|
-
if(b.name !== branchName)
|
|
5009
|
+
for( let b of this.branches )
|
|
5010
|
+
{
|
|
5011
|
+
if( b.name !== branchName )
|
|
5012
|
+
{
|
|
4089
5013
|
continue;
|
|
5014
|
+
}
|
|
4090
5015
|
|
|
4091
5016
|
// remove all widgets
|
|
4092
|
-
for( let w of b.widgets )
|
|
4093
|
-
|
|
5017
|
+
for( let w of b.widgets )
|
|
5018
|
+
{
|
|
5019
|
+
if( w.domEl.classList.contains('lexfilter') )
|
|
5020
|
+
{
|
|
4094
5021
|
continue;
|
|
5022
|
+
}
|
|
4095
5023
|
w.domEl.remove();
|
|
4096
5024
|
}
|
|
4097
5025
|
|
|
@@ -4101,9 +5029,9 @@ class Panel {
|
|
|
4101
5029
|
const emptyFilter = !value.length;
|
|
4102
5030
|
|
|
4103
5031
|
// add widgets
|
|
4104
|
-
for( let w of b.widgets )
|
|
4105
|
-
|
|
4106
|
-
if(!emptyFilter)
|
|
5032
|
+
for( let w of b.widgets )
|
|
5033
|
+
{
|
|
5034
|
+
if( !emptyFilter )
|
|
4107
5035
|
{
|
|
4108
5036
|
if(!w.name) continue;
|
|
4109
5037
|
const filterWord = value.toLowerCase();
|
|
@@ -4123,26 +5051,28 @@ class Panel {
|
|
|
4123
5051
|
}
|
|
4124
5052
|
}
|
|
4125
5053
|
|
|
4126
|
-
|
|
4127
|
-
|
|
5054
|
+
_filterOptions( options, value ) {
|
|
5055
|
+
|
|
5056
|
+
// Push to right container
|
|
4128
5057
|
const emptyFilter = !value.length;
|
|
4129
5058
|
let filteredOptions = [];
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
5059
|
+
|
|
5060
|
+
// Add widgets
|
|
5061
|
+
for( let i = 0; i < options.length; i++ )
|
|
5062
|
+
{
|
|
5063
|
+
let o = options[ i ];
|
|
5064
|
+
if( !emptyFilter )
|
|
4134
5065
|
{
|
|
4135
|
-
let toCompare = (typeof o == 'string') ? o : o.value;
|
|
4136
|
-
;
|
|
5066
|
+
let toCompare = ( typeof o == 'string' ) ? o : o.value;
|
|
4137
5067
|
const filterWord = value.toLowerCase();
|
|
4138
5068
|
const name = toCompare.toLowerCase();
|
|
4139
|
-
if(!name.includes(filterWord)) continue;
|
|
5069
|
+
if( !name.includes( filterWord ) ) continue;
|
|
4140
5070
|
}
|
|
4141
|
-
|
|
4142
|
-
filteredOptions.push(o);
|
|
5071
|
+
|
|
5072
|
+
filteredOptions.push( o );
|
|
4143
5073
|
}
|
|
4144
5074
|
|
|
4145
|
-
this.refresh(filteredOptions);
|
|
5075
|
+
this.refresh( filteredOptions );
|
|
4146
5076
|
}
|
|
4147
5077
|
|
|
4148
5078
|
_trigger( event, callback ) {
|
|
@@ -4195,7 +5125,7 @@ class Panel {
|
|
|
4195
5125
|
|
|
4196
5126
|
clearQueue() {
|
|
4197
5127
|
|
|
4198
|
-
if(this._queue && this._queue.length)
|
|
5128
|
+
if( this._queue && this._queue.length)
|
|
4199
5129
|
{
|
|
4200
5130
|
this.queuedContainer = this._queue.pop();
|
|
4201
5131
|
return;
|
|
@@ -4421,7 +5351,8 @@ class Panel {
|
|
|
4421
5351
|
element.appendChild( container );
|
|
4422
5352
|
|
|
4423
5353
|
// Remove branch padding and margins
|
|
4424
|
-
if( !widget.name )
|
|
5354
|
+
if( !widget.name )
|
|
5355
|
+
{
|
|
4425
5356
|
element.className += " noname";
|
|
4426
5357
|
container.style.width = "100%";
|
|
4427
5358
|
}
|
|
@@ -4521,7 +5452,8 @@ class Panel {
|
|
|
4521
5452
|
element.appendChild(container);
|
|
4522
5453
|
|
|
4523
5454
|
// Remove branch padding and margins
|
|
4524
|
-
if(!widget.name)
|
|
5455
|
+
if( !widget.name )
|
|
5456
|
+
{
|
|
4525
5457
|
element.className += " noname";
|
|
4526
5458
|
container.style.width = "100%";
|
|
4527
5459
|
}
|
|
@@ -4626,69 +5558,94 @@ class Panel {
|
|
|
4626
5558
|
/**
|
|
4627
5559
|
* @method addComboButtons
|
|
4628
5560
|
* @param {String} name Widget name
|
|
4629
|
-
* @param {Array} values Each of the {value, callback} items
|
|
5561
|
+
* @param {Array} values Each of the {value, callback, selected, disabled} items
|
|
4630
5562
|
* @param {*} options:
|
|
4631
5563
|
* float: Justify content (left, center, right) [center]
|
|
5564
|
+
* @legacy selected: Selected item by default by value
|
|
4632
5565
|
* noSelection: Buttons can be clicked, but they are not selectable
|
|
5566
|
+
* toggle: Buttons can be toggled insted of selecting only one
|
|
4633
5567
|
*/
|
|
4634
5568
|
|
|
4635
5569
|
addComboButtons( name, values, options = {} ) {
|
|
4636
5570
|
|
|
4637
|
-
let widget = this.create_widget(name, Widget.BUTTON, options);
|
|
5571
|
+
let widget = this.create_widget( name, Widget.BUTTON, options );
|
|
4638
5572
|
let element = widget.domEl;
|
|
4639
5573
|
|
|
4640
5574
|
let that = this;
|
|
4641
5575
|
let container = document.createElement('div');
|
|
4642
5576
|
container.className = "lexcombobuttons ";
|
|
4643
|
-
|
|
5577
|
+
|
|
5578
|
+
if( options.float )
|
|
5579
|
+
{
|
|
5580
|
+
container.className += options.float;
|
|
5581
|
+
}
|
|
5582
|
+
|
|
4644
5583
|
container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
|
|
4645
5584
|
|
|
4646
|
-
let
|
|
5585
|
+
let buttonsBox = document.createElement('div');
|
|
5586
|
+
buttonsBox.className = "lexcombobuttonsbox ";
|
|
5587
|
+
|
|
5588
|
+
const shouldSelect = !( options.noSelection ?? false );
|
|
5589
|
+
const shouldToggle = shouldSelect && ( options.toggle ?? false );
|
|
5590
|
+
|
|
4647
5591
|
for( let b of values )
|
|
4648
5592
|
{
|
|
4649
|
-
if( !b.value )
|
|
5593
|
+
if( !b.value )
|
|
5594
|
+
{
|
|
5595
|
+
throw( "Set 'value' for each button!" );
|
|
5596
|
+
}
|
|
4650
5597
|
|
|
4651
5598
|
let buttonEl = document.createElement('button');
|
|
4652
5599
|
buttonEl.className = "lexbutton combo";
|
|
4653
5600
|
buttonEl.title = b.icon ? b.value : "";
|
|
4654
|
-
|
|
4655
|
-
buttonEl.classList.add(options.buttonClass);
|
|
5601
|
+
buttonEl.id = b.id ?? "";
|
|
4656
5602
|
|
|
4657
|
-
if(options.
|
|
4658
|
-
|
|
5603
|
+
if( options.buttonClass )
|
|
5604
|
+
{
|
|
5605
|
+
buttonEl.classList.add( options.buttonClass );
|
|
5606
|
+
}
|
|
4659
5607
|
|
|
4660
|
-
if(b.
|
|
4661
|
-
|
|
5608
|
+
if( shouldSelect && ( b.selected || options.selected == b.value ) )
|
|
5609
|
+
{
|
|
5610
|
+
buttonEl.classList.add("selected");
|
|
5611
|
+
}
|
|
4662
5612
|
|
|
4663
|
-
buttonEl.innerHTML = (b.icon ? "<a class='" + b.icon +"'></a>" : "") + "<span>" + (b.icon ? "" : b.value) + "</span>";
|
|
5613
|
+
buttonEl.innerHTML = ( b.icon ? "<a class='" + b.icon +"'></a>" : "" ) + "<span>" + ( b.icon ? "" : b.value ) + "</span>";
|
|
4664
5614
|
|
|
4665
|
-
if(
|
|
4666
|
-
|
|
5615
|
+
if( b.disabled )
|
|
5616
|
+
{
|
|
5617
|
+
buttonEl.setAttribute( "disabled", true );
|
|
5618
|
+
}
|
|
4667
5619
|
|
|
4668
|
-
buttonEl.addEventListener("click", function(e) {
|
|
4669
|
-
if(
|
|
4670
|
-
|
|
4671
|
-
|
|
5620
|
+
buttonEl.addEventListener("click", function( e ) {
|
|
5621
|
+
if( shouldSelect )
|
|
5622
|
+
{
|
|
5623
|
+
if( shouldToggle )
|
|
5624
|
+
{
|
|
5625
|
+
this.classList.toggle('selected');
|
|
5626
|
+
}
|
|
5627
|
+
else
|
|
5628
|
+
{
|
|
5629
|
+
container.querySelectorAll('button').forEach( s => s.classList.remove('selected'));
|
|
5630
|
+
this.classList.add('selected');
|
|
5631
|
+
}
|
|
4672
5632
|
}
|
|
4673
|
-
that._trigger( new IEvent(name, b.value, e), b.callback );
|
|
4674
|
-
});
|
|
4675
5633
|
|
|
4676
|
-
|
|
5634
|
+
that._trigger( new IEvent( name, b.value, e ), b.callback );
|
|
5635
|
+
});
|
|
4677
5636
|
|
|
4678
|
-
|
|
4679
|
-
if(widget.name === undefined) {
|
|
4680
|
-
buttonEl.className += " noname";
|
|
4681
|
-
buttonEl.style.width = "100%";
|
|
4682
|
-
}
|
|
5637
|
+
buttonsBox.appendChild( buttonEl );
|
|
4683
5638
|
}
|
|
4684
5639
|
|
|
4685
5640
|
// Remove branch padding and margins
|
|
4686
|
-
if(widget.name
|
|
5641
|
+
if( !widget.name )
|
|
5642
|
+
{
|
|
4687
5643
|
element.className += " noname";
|
|
4688
5644
|
container.style.width = "100%";
|
|
4689
5645
|
}
|
|
4690
5646
|
|
|
4691
|
-
|
|
5647
|
+
container.appendChild( buttonsBox );
|
|
5648
|
+
element.appendChild( container );
|
|
4692
5649
|
|
|
4693
5650
|
return widget;
|
|
4694
5651
|
}
|
|
@@ -4855,7 +5812,8 @@ class Panel {
|
|
|
4855
5812
|
|
|
4856
5813
|
element.appendChild( container );
|
|
4857
5814
|
|
|
4858
|
-
if( !widget.name || options.hideName )
|
|
5815
|
+
if( !widget.name || options.hideName )
|
|
5816
|
+
{
|
|
4859
5817
|
element.className += " noname";
|
|
4860
5818
|
container.style.width = "100%";
|
|
4861
5819
|
}
|
|
@@ -4940,6 +5898,8 @@ class Panel {
|
|
|
4940
5898
|
* filter: Add a search bar to the widget [false]
|
|
4941
5899
|
* disabled: Make the widget disabled [false]
|
|
4942
5900
|
* skipReset: Don't add the reset value button when value changes
|
|
5901
|
+
* placeholder: Placeholder for the filter input
|
|
5902
|
+
* emptyMsg: Custom message to show when no filtered results
|
|
4943
5903
|
*/
|
|
4944
5904
|
|
|
4945
5905
|
addDropdown( name, values, value, callback, options = {} ) {
|
|
@@ -4985,17 +5945,72 @@ class Panel {
|
|
|
4985
5945
|
let buttonName = value;
|
|
4986
5946
|
buttonName += "<a class='fa-solid fa-angle-down' style='float:right; margin-right: 3px;'></a>";
|
|
4987
5947
|
|
|
4988
|
-
this.queue(container);
|
|
5948
|
+
this.queue( container );
|
|
5949
|
+
|
|
5950
|
+
const _placeOptions = ( parent ) => {
|
|
5951
|
+
|
|
5952
|
+
const overflowContainer = parent.getParentArea();
|
|
5953
|
+
const rect = selectedOption.getBoundingClientRect();
|
|
5954
|
+
const nestedDialog = parent.parentElement.closest( "dialog" );
|
|
5955
|
+
|
|
5956
|
+
// Manage vertical aspect
|
|
5957
|
+
{
|
|
5958
|
+
const listHeight = parent.offsetHeight;
|
|
5959
|
+
let topPosition = rect.y;
|
|
5960
|
+
|
|
5961
|
+
let maxY = window.innerHeight;
|
|
5962
|
+
|
|
5963
|
+
if( overflowContainer )
|
|
5964
|
+
{
|
|
5965
|
+
const parentRect = overflowContainer.getBoundingClientRect();
|
|
5966
|
+
maxY = parentRect.y + parentRect.height;
|
|
5967
|
+
}
|
|
5968
|
+
|
|
5969
|
+
if( nestedDialog )
|
|
5970
|
+
{
|
|
5971
|
+
const rect = nestedDialog.getBoundingClientRect();
|
|
5972
|
+
topPosition -= rect.y;
|
|
5973
|
+
}
|
|
5974
|
+
|
|
5975
|
+
parent.style.top = ( topPosition + selectedOption.offsetHeight ) + 'px';
|
|
4989
5976
|
|
|
4990
|
-
|
|
5977
|
+
const showAbove = ( topPosition + listHeight ) > maxY;
|
|
5978
|
+
if( showAbove )
|
|
5979
|
+
{
|
|
5980
|
+
parent.style.top = ( topPosition - listHeight ) + 'px';
|
|
5981
|
+
parent.classList.add( "place-above" );
|
|
5982
|
+
}
|
|
5983
|
+
}
|
|
4991
5984
|
|
|
4992
|
-
|
|
4993
|
-
for( let i of values )
|
|
5985
|
+
// Manage horizontal aspect
|
|
4994
5986
|
{
|
|
4995
|
-
const
|
|
4996
|
-
|
|
5987
|
+
const listWidth = parent.offsetWidth;
|
|
5988
|
+
let leftPosition = rect.x;
|
|
5989
|
+
|
|
5990
|
+
parent.style.minWidth = ( rect.width ) + 'px';
|
|
5991
|
+
|
|
5992
|
+
if( nestedDialog )
|
|
5993
|
+
{
|
|
5994
|
+
const rect = nestedDialog.getBoundingClientRect();
|
|
5995
|
+
leftPosition -= rect.x;
|
|
5996
|
+
}
|
|
5997
|
+
|
|
5998
|
+
parent.style.left = ( leftPosition ) + 'px';
|
|
5999
|
+
|
|
6000
|
+
let maxX = window.innerWidth;
|
|
6001
|
+
|
|
6002
|
+
if( overflowContainer )
|
|
6003
|
+
{
|
|
6004
|
+
const parentRect = overflowContainer.getBoundingClientRect();
|
|
6005
|
+
maxX = parentRect.x + parentRect.width;
|
|
6006
|
+
}
|
|
6007
|
+
|
|
6008
|
+
const showLeft = ( leftPosition + listWidth ) > maxX;
|
|
6009
|
+
if( showLeft )
|
|
6010
|
+
{
|
|
6011
|
+
parent.style.left = ( leftPosition - ( listWidth - rect.width ) ) + 'px';
|
|
6012
|
+
}
|
|
4997
6013
|
}
|
|
4998
|
-
return Math.max( maxWidth * 10, 80 );
|
|
4999
6014
|
};
|
|
5000
6015
|
|
|
5001
6016
|
let selectedOption = this.addButton( null, buttonName, ( value, event ) => {
|
|
@@ -5005,52 +6020,50 @@ class Panel {
|
|
|
5005
6020
|
return;
|
|
5006
6021
|
}
|
|
5007
6022
|
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
const listHeight = 26 * values.length;
|
|
5012
|
-
const rect = selectedOption.getBoundingClientRect();
|
|
5013
|
-
const topPosition = rect.y;
|
|
5014
|
-
|
|
5015
|
-
let maxY = window.innerHeight;
|
|
5016
|
-
let overflowContainer = list.getParentArea();
|
|
6023
|
+
listDialog.classList.remove( "place-above" );
|
|
6024
|
+
const opened = listDialog.hasAttribute( "open" );
|
|
5017
6025
|
|
|
5018
|
-
if(
|
|
6026
|
+
if( !opened )
|
|
5019
6027
|
{
|
|
5020
|
-
|
|
5021
|
-
|
|
6028
|
+
listDialog.show();
|
|
6029
|
+
_placeOptions( listDialog );
|
|
6030
|
+
}
|
|
6031
|
+
else
|
|
6032
|
+
{
|
|
6033
|
+
listDialog.close();
|
|
5022
6034
|
}
|
|
5023
6035
|
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
const showAbove = ( topPosition + listHeight ) > maxY;
|
|
5027
|
-
if( showAbove )
|
|
6036
|
+
if( filter )
|
|
5028
6037
|
{
|
|
5029
|
-
|
|
5030
|
-
list.classList.add( "place-above" );
|
|
6038
|
+
filter.querySelector( "input" ).focus();
|
|
5031
6039
|
}
|
|
5032
6040
|
|
|
5033
|
-
|
|
5034
|
-
list.style.minWidth = (_getMaxListWidth()) + 'px';
|
|
5035
|
-
list.focus();
|
|
5036
|
-
}, { buttonClass: "array", skipInlineCount: true });
|
|
6041
|
+
}, { buttonClass: "array", skipInlineCount: true, disabled: options.disabled });
|
|
5037
6042
|
|
|
5038
6043
|
this.clearQueue();
|
|
5039
6044
|
|
|
5040
6045
|
selectedOption.style.width = "100%";
|
|
5041
6046
|
|
|
5042
6047
|
selectedOption.refresh = (v) => {
|
|
5043
|
-
if(selectedOption.querySelector("span").innerText == "")
|
|
6048
|
+
if( selectedOption.querySelector("span").innerText == "" )
|
|
6049
|
+
{
|
|
5044
6050
|
selectedOption.querySelector("span").innerText = v;
|
|
6051
|
+
}
|
|
5045
6052
|
else
|
|
6053
|
+
{
|
|
5046
6054
|
selectedOption.querySelector("span").innerHTML = selectedOption.querySelector("span").innerHTML.replaceAll(selectedOption.querySelector("span").innerText, v);
|
|
6055
|
+
}
|
|
5047
6056
|
}
|
|
5048
6057
|
|
|
5049
6058
|
// Add dropdown options container
|
|
6059
|
+
|
|
6060
|
+
const listDialog = document.createElement( 'dialog' );
|
|
6061
|
+
listDialog.className = "lexdropdownoptions";
|
|
6062
|
+
|
|
5050
6063
|
let list = document.createElement( 'ul' );
|
|
5051
6064
|
list.tabIndex = -1;
|
|
5052
6065
|
list.className = "lexoptions";
|
|
5053
|
-
|
|
6066
|
+
listDialog.appendChild( list )
|
|
5054
6067
|
|
|
5055
6068
|
list.addEventListener( 'focusout', function( e ) {
|
|
5056
6069
|
e.stopPropagation();
|
|
@@ -5068,97 +6081,118 @@ class Panel {
|
|
|
5068
6081
|
{
|
|
5069
6082
|
return;
|
|
5070
6083
|
}
|
|
5071
|
-
|
|
6084
|
+
listDialog.close();
|
|
5072
6085
|
});
|
|
5073
6086
|
|
|
5074
6087
|
// Add filter options
|
|
5075
6088
|
let filter = null;
|
|
5076
|
-
if(options.filter ?? false)
|
|
6089
|
+
if( options.filter ?? false )
|
|
5077
6090
|
{
|
|
5078
|
-
filter = this._addFilter("Search
|
|
5079
|
-
}
|
|
5080
|
-
|
|
5081
|
-
// Create option list to empty it easily..
|
|
5082
|
-
const listOptions = document.createElement('span');
|
|
5083
|
-
list.appendChild( listOptions );
|
|
6091
|
+
filter = this._addFilter( options.placeholder ?? "Search...", { container: list, callback: this._filterOptions.bind( list, values )} );
|
|
5084
6092
|
|
|
5085
|
-
|
|
5086
|
-
{
|
|
5087
|
-
list.prepend( filter );
|
|
5088
|
-
listOptions.style.height = "calc(100% - 25px)";
|
|
6093
|
+
list.appendChild( filter );
|
|
5089
6094
|
|
|
5090
6095
|
filter.addEventListener('focusout', function( e ) {
|
|
5091
6096
|
if (e.relatedTarget && e.relatedTarget.tagName == "UL" && e.relatedTarget.classList.contains("lexoptions"))
|
|
5092
6097
|
{
|
|
5093
6098
|
return;
|
|
5094
6099
|
}
|
|
5095
|
-
|
|
6100
|
+
listDialog.close();
|
|
5096
6101
|
});
|
|
5097
6102
|
}
|
|
5098
6103
|
|
|
6104
|
+
// Create option list to empty it easily..
|
|
6105
|
+
const listOptions = document.createElement('span');
|
|
6106
|
+
listOptions.style.height = "calc(100% - 25px)";
|
|
6107
|
+
list.appendChild( listOptions );
|
|
6108
|
+
|
|
5099
6109
|
// Add dropdown options list
|
|
5100
|
-
list.refresh = options => {
|
|
6110
|
+
list.refresh = ( options ) => {
|
|
5101
6111
|
|
|
5102
6112
|
// Empty list
|
|
5103
6113
|
listOptions.innerHTML = "";
|
|
5104
6114
|
|
|
5105
|
-
|
|
6115
|
+
if( !options.length )
|
|
6116
|
+
{
|
|
6117
|
+
let iValue = options.emptyMsg ?? "No options found.";
|
|
6118
|
+
|
|
6119
|
+
let option = document.createElement( "div" );
|
|
6120
|
+
option.className = "option";
|
|
6121
|
+
option.style.flexDirection = "unset";
|
|
6122
|
+
option.innerHTML = iValue;
|
|
6123
|
+
|
|
6124
|
+
let li = document.createElement( "li" );
|
|
6125
|
+
li.className = "lexdropdownitem empty";
|
|
6126
|
+
li.appendChild( option );
|
|
6127
|
+
|
|
6128
|
+
listOptions.appendChild( li );
|
|
6129
|
+
return;
|
|
6130
|
+
}
|
|
6131
|
+
|
|
6132
|
+
for( let i = 0; i < options.length; i++ )
|
|
5106
6133
|
{
|
|
5107
|
-
let iValue = options[i];
|
|
5108
|
-
let li = document.createElement(
|
|
5109
|
-
let option = document.createElement(
|
|
6134
|
+
let iValue = options[ i ];
|
|
6135
|
+
let li = document.createElement( "li" );
|
|
6136
|
+
let option = document.createElement( "div" );
|
|
5110
6137
|
option.className = "option";
|
|
5111
|
-
li.appendChild(option);
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
e.currentTarget.
|
|
5118
|
-
e.currentTarget.
|
|
6138
|
+
li.appendChild( option );
|
|
6139
|
+
|
|
6140
|
+
li.addEventListener( "click", e => {
|
|
6141
|
+
listDialog.close();
|
|
6142
|
+
const currentSelected = element.querySelector( ".lexoptions .selected" );
|
|
6143
|
+
if(currentSelected) currentSelected.classList.remove( "selected" );
|
|
6144
|
+
value = e.currentTarget.getAttribute( "value" );
|
|
6145
|
+
e.currentTarget.toggleAttribute( "hidden", false );
|
|
6146
|
+
e.currentTarget.classList.add( "selected" );
|
|
5119
6147
|
selectedOption.refresh(value);
|
|
5120
6148
|
|
|
5121
|
-
let btn = element.querySelector(".lexwidgetname .lexicon");
|
|
5122
|
-
if(btn) btn.style.display = (value != wValue.iValue ? "block" : "none");
|
|
5123
|
-
that._trigger( new IEvent(name, value, null), callback );
|
|
6149
|
+
let btn = element.querySelector( ".lexwidgetname .lexicon" );
|
|
6150
|
+
if( btn ) btn.style.display = (value != wValue.iValue ? "block" : "none");
|
|
6151
|
+
that._trigger( new IEvent( name, value, null ), callback );
|
|
5124
6152
|
|
|
5125
6153
|
// Reset filter
|
|
5126
|
-
if(filter)
|
|
6154
|
+
if( filter )
|
|
5127
6155
|
{
|
|
5128
|
-
filter.querySelector(
|
|
5129
|
-
this.
|
|
6156
|
+
filter.querySelector( "input" ).value = "";
|
|
6157
|
+
this._filterOptions.bind( list, values, "" )();
|
|
5130
6158
|
}
|
|
5131
6159
|
});
|
|
5132
6160
|
|
|
5133
6161
|
// Add string option
|
|
5134
|
-
if( iValue.constructor != Object )
|
|
5135
|
-
|
|
6162
|
+
if( iValue.constructor != Object )
|
|
6163
|
+
{
|
|
6164
|
+
option.style.flexDirection = "unset";
|
|
5136
6165
|
option.innerHTML = "</a><span>" + iValue + "</span><a class='fa-solid fa-check'>";
|
|
5137
6166
|
option.value = iValue;
|
|
5138
|
-
li.setAttribute("value", iValue);
|
|
6167
|
+
li.setAttribute( "value", iValue );
|
|
5139
6168
|
li.className = "lexdropdownitem";
|
|
5140
|
-
|
|
5141
|
-
if(iValue == value)
|
|
5142
|
-
|
|
6169
|
+
|
|
6170
|
+
if( iValue == value )
|
|
6171
|
+
{
|
|
6172
|
+
li.classList.add( "selected" );
|
|
5143
6173
|
wValue.innerHTML = iValue;
|
|
5144
6174
|
}
|
|
5145
6175
|
}
|
|
5146
|
-
else
|
|
6176
|
+
else
|
|
6177
|
+
{
|
|
5147
6178
|
// Add image option
|
|
5148
|
-
let img = document.createElement("img");
|
|
6179
|
+
let img = document.createElement( "img" );
|
|
5149
6180
|
img.src = iValue.src;
|
|
5150
|
-
li.setAttribute("value", iValue.value);
|
|
6181
|
+
li.setAttribute( "value", iValue.value );
|
|
5151
6182
|
li.className = "lexlistitem";
|
|
5152
6183
|
option.innerText = iValue.value;
|
|
5153
6184
|
option.className += " media";
|
|
5154
|
-
option.prepend(img);
|
|
6185
|
+
option.prepend( img );
|
|
5155
6186
|
|
|
5156
|
-
option.setAttribute("value", iValue.value);
|
|
5157
|
-
option.setAttribute("data-index", i);
|
|
5158
|
-
option.setAttribute("data-src", iValue.src);
|
|
5159
|
-
option.setAttribute("title", iValue.value);
|
|
5160
|
-
|
|
5161
|
-
|
|
6187
|
+
option.setAttribute( "value", iValue.value );
|
|
6188
|
+
option.setAttribute( "data-index", i );
|
|
6189
|
+
option.setAttribute( "data-src", iValue.src );
|
|
6190
|
+
option.setAttribute( "title", iValue.value );
|
|
6191
|
+
|
|
6192
|
+
if( value == iValue.value )
|
|
6193
|
+
{
|
|
6194
|
+
li.classList.add( "selected" );
|
|
6195
|
+
}
|
|
5162
6196
|
}
|
|
5163
6197
|
|
|
5164
6198
|
listOptions.appendChild( li );
|
|
@@ -5167,7 +6201,7 @@ class Panel {
|
|
|
5167
6201
|
|
|
5168
6202
|
list.refresh( values );
|
|
5169
6203
|
|
|
5170
|
-
container.appendChild(
|
|
6204
|
+
container.appendChild( listDialog );
|
|
5171
6205
|
element.appendChild( container );
|
|
5172
6206
|
|
|
5173
6207
|
// Remove branch padding and margins
|
|
@@ -5198,15 +6232,16 @@ class Panel {
|
|
|
5198
6232
|
|
|
5199
6233
|
addCurve( name, values, callback, options = {} ) {
|
|
5200
6234
|
|
|
5201
|
-
if(!name)
|
|
5202
|
-
|
|
6235
|
+
if( !name )
|
|
6236
|
+
{
|
|
6237
|
+
throw( "Set Widget Name!" );
|
|
5203
6238
|
}
|
|
5204
6239
|
|
|
5205
6240
|
let that = this;
|
|
5206
|
-
let widget = this.create_widget(name, Widget.CURVE, options);
|
|
6241
|
+
let widget = this.create_widget( name, Widget.CURVE, options );
|
|
5207
6242
|
|
|
5208
6243
|
widget.onGetValue = () => {
|
|
5209
|
-
return JSON.parse(JSON.stringify(curveInstance.element.value));
|
|
6244
|
+
return JSON.parse(JSON.stringify( curveInstance.element.value ));
|
|
5210
6245
|
};
|
|
5211
6246
|
|
|
5212
6247
|
widget.onSetValue = ( newValue, skipCallback ) => {
|
|
@@ -5351,7 +6386,8 @@ class Panel {
|
|
|
5351
6386
|
|
|
5352
6387
|
addLayers( name, value, callback, options = {} ) {
|
|
5353
6388
|
|
|
5354
|
-
if(!name)
|
|
6389
|
+
if( !name )
|
|
6390
|
+
{
|
|
5355
6391
|
throw("Set Widget Name!");
|
|
5356
6392
|
}
|
|
5357
6393
|
|
|
@@ -5393,7 +6429,8 @@ class Panel {
|
|
|
5393
6429
|
let binary = value.toString( 2 );
|
|
5394
6430
|
let nbits = binary.length;
|
|
5395
6431
|
// fill zeros
|
|
5396
|
-
for(var i = 0; i < (16 - nbits); ++i)
|
|
6432
|
+
for( var i = 0; i < (16 - nbits); ++i )
|
|
6433
|
+
{
|
|
5397
6434
|
binary = '0' + binary;
|
|
5398
6435
|
}
|
|
5399
6436
|
|
|
@@ -5446,8 +6483,9 @@ class Panel {
|
|
|
5446
6483
|
|
|
5447
6484
|
addArray( name, values = [], callback, options = {} ) {
|
|
5448
6485
|
|
|
5449
|
-
if(!name)
|
|
5450
|
-
|
|
6486
|
+
if( !name )
|
|
6487
|
+
{
|
|
6488
|
+
throw( "Set Widget Name!" );
|
|
5451
6489
|
}
|
|
5452
6490
|
|
|
5453
6491
|
let widget = this.create_widget(name, Widget.ARRAY, options);
|
|
@@ -5628,7 +6666,8 @@ class Panel {
|
|
|
5628
6666
|
widget.updateValues( values );
|
|
5629
6667
|
|
|
5630
6668
|
// Remove branch padding and margins
|
|
5631
|
-
if( !widget.name )
|
|
6669
|
+
if( !widget.name )
|
|
6670
|
+
{
|
|
5632
6671
|
element.className += " noname";
|
|
5633
6672
|
listContainer.style.width = "100%";
|
|
5634
6673
|
}
|
|
@@ -5715,7 +6754,7 @@ class Panel {
|
|
|
5715
6754
|
tagsContainer.appendChild( tagInput );
|
|
5716
6755
|
|
|
5717
6756
|
tagInput.onkeydown = function( e ) {
|
|
5718
|
-
const val = this.value.replace(/\s/g, '');
|
|
6757
|
+
const val = this.value.replace( /\s/g, '' );
|
|
5719
6758
|
if( e.key == ' ' || e.key == 'Enter' )
|
|
5720
6759
|
{
|
|
5721
6760
|
e.preventDefault();
|
|
@@ -5753,15 +6792,16 @@ class Panel {
|
|
|
5753
6792
|
* @param {Function} callback Callback function on change
|
|
5754
6793
|
* @param {*} options:
|
|
5755
6794
|
* disabled: Make the widget disabled [false]
|
|
6795
|
+
* label: Checkbox label
|
|
5756
6796
|
* suboptions: Callback to add widgets in case of TRUE value
|
|
5757
|
-
* className:
|
|
6797
|
+
* className: Extra classes to customize style
|
|
5758
6798
|
*/
|
|
5759
6799
|
|
|
5760
6800
|
addCheckbox( name, value, callback, options = {} ) {
|
|
5761
6801
|
|
|
5762
|
-
if( !name )
|
|
6802
|
+
if( !name && !options.label )
|
|
5763
6803
|
{
|
|
5764
|
-
throw( "Set Widget Name!" );
|
|
6804
|
+
throw( "Set Widget Name or at least a label!" );
|
|
5765
6805
|
}
|
|
5766
6806
|
|
|
5767
6807
|
let widget = this.create_widget( name, Widget.CHECKBOX, options );
|
|
@@ -5781,10 +6821,13 @@ class Panel {
|
|
|
5781
6821
|
let element = widget.domEl;
|
|
5782
6822
|
|
|
5783
6823
|
// Add reset functionality
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
Panel.
|
|
5787
|
-
|
|
6824
|
+
if( name )
|
|
6825
|
+
{
|
|
6826
|
+
Panel._add_reset_property( element.domName, function() {
|
|
6827
|
+
checkbox.checked = !checkbox.checked;
|
|
6828
|
+
Panel._dispatch_event( checkbox, "change" );
|
|
6829
|
+
});
|
|
6830
|
+
}
|
|
5788
6831
|
|
|
5789
6832
|
// Add widget value
|
|
5790
6833
|
|
|
@@ -5800,7 +6843,7 @@ class Panel {
|
|
|
5800
6843
|
|
|
5801
6844
|
let valueName = document.createElement( 'span' );
|
|
5802
6845
|
valueName.className = "checkboxtext";
|
|
5803
|
-
valueName.innerHTML = "On";
|
|
6846
|
+
valueName.innerHTML = options.label ?? "On";
|
|
5804
6847
|
|
|
5805
6848
|
container.appendChild( checkbox );
|
|
5806
6849
|
container.appendChild( valueName );
|
|
@@ -5938,6 +6981,96 @@ class Panel {
|
|
|
5938
6981
|
return widget;
|
|
5939
6982
|
}
|
|
5940
6983
|
|
|
6984
|
+
/**
|
|
6985
|
+
* @method addRadioGroup
|
|
6986
|
+
* @param {String} label Radio label
|
|
6987
|
+
* @param {Array} values Radio options
|
|
6988
|
+
* @param {Function} callback Callback function on change
|
|
6989
|
+
* @param {*} options:
|
|
6990
|
+
* disabled: Make the widget disabled [false]
|
|
6991
|
+
* className: Customize colors
|
|
6992
|
+
*/
|
|
6993
|
+
|
|
6994
|
+
addRadioGroup( label, values, callback, options = {} ) {
|
|
6995
|
+
|
|
6996
|
+
let widget = this.create_widget( null, Widget.RADIO, options );
|
|
6997
|
+
|
|
6998
|
+
widget.onGetValue = () => {
|
|
6999
|
+
const items = container.querySelectorAll( 'button' );
|
|
7000
|
+
for( let i = 0; i < items.length; ++i )
|
|
7001
|
+
{
|
|
7002
|
+
const optionItem = items[ i ];
|
|
7003
|
+
if( optionItem.checked )
|
|
7004
|
+
{
|
|
7005
|
+
return [ i, values[ i ] ];
|
|
7006
|
+
}
|
|
7007
|
+
}
|
|
7008
|
+
};
|
|
7009
|
+
|
|
7010
|
+
widget.onSetValue = ( newValue, skipCallback ) => {
|
|
7011
|
+
const items = container.querySelectorAll( 'button' );
|
|
7012
|
+
for( let i = 0; i < items.length; ++i )
|
|
7013
|
+
{
|
|
7014
|
+
const optionItem = items[ i ];
|
|
7015
|
+
if( newValue == i )
|
|
7016
|
+
{
|
|
7017
|
+
Panel._dispatch_event( optionItem, "click", skipCallback );
|
|
7018
|
+
}
|
|
7019
|
+
}
|
|
7020
|
+
};
|
|
7021
|
+
|
|
7022
|
+
let element = widget.domEl;
|
|
7023
|
+
|
|
7024
|
+
// Add widget value
|
|
7025
|
+
var container = document.createElement( 'div' );
|
|
7026
|
+
container.className = "lexradiogroup " + ( options.className ?? "" );
|
|
7027
|
+
|
|
7028
|
+
let labelSpan = document.createElement( 'span' );
|
|
7029
|
+
labelSpan.innerHTML = label;
|
|
7030
|
+
container.appendChild( labelSpan );
|
|
7031
|
+
|
|
7032
|
+
const that = this;
|
|
7033
|
+
|
|
7034
|
+
for( let i = 0; i < values.length; ++i )
|
|
7035
|
+
{
|
|
7036
|
+
const optionItem = document.createElement( 'div' );
|
|
7037
|
+
optionItem.className = "lexradiogroupitem";
|
|
7038
|
+
container.appendChild( optionItem );
|
|
7039
|
+
|
|
7040
|
+
const optionButton = document.createElement( 'button' );
|
|
7041
|
+
optionButton.className = "lexbutton";
|
|
7042
|
+
optionButton.disabled = options.disabled ?? false;
|
|
7043
|
+
optionItem.appendChild( optionButton );
|
|
7044
|
+
|
|
7045
|
+
optionButton.addEventListener( "click", function( e ) {
|
|
7046
|
+
const skipCallback = ( e.detail?.constructor == Number ? null : e.detail );
|
|
7047
|
+
container.querySelectorAll( 'button' ).forEach( e => { e.checked = false; e.classList.remove( "checked" ) } );
|
|
7048
|
+
this.checked = !this.checked;
|
|
7049
|
+
this.classList.toggle( "checked" );
|
|
7050
|
+
if( !skipCallback ) that._trigger( new IEvent( null, [ i, values[ i ] ], e ), callback );
|
|
7051
|
+
} );
|
|
7052
|
+
|
|
7053
|
+
{
|
|
7054
|
+
const checkedSpan = document.createElement( 'span' );
|
|
7055
|
+
optionButton.appendChild( checkedSpan );
|
|
7056
|
+
}
|
|
7057
|
+
|
|
7058
|
+
const optionLabel = document.createElement( 'span' );
|
|
7059
|
+
optionLabel.innerHTML = values[ i ];
|
|
7060
|
+
optionItem.appendChild( optionLabel );
|
|
7061
|
+
}
|
|
7062
|
+
|
|
7063
|
+
if( options.selected )
|
|
7064
|
+
{
|
|
7065
|
+
console.assert( options.selected.constructor == Number );
|
|
7066
|
+
widget.set( options.selected, true );
|
|
7067
|
+
}
|
|
7068
|
+
|
|
7069
|
+
element.appendChild( container );
|
|
7070
|
+
|
|
7071
|
+
return widget;
|
|
7072
|
+
}
|
|
7073
|
+
|
|
5941
7074
|
/**
|
|
5942
7075
|
* @method addColor
|
|
5943
7076
|
* @param {String} name Widget name
|
|
@@ -5950,7 +7083,8 @@ class Panel {
|
|
|
5950
7083
|
|
|
5951
7084
|
addColor( name, value, callback, options = {} ) {
|
|
5952
7085
|
|
|
5953
|
-
if( !name )
|
|
7086
|
+
if( !name )
|
|
7087
|
+
{
|
|
5954
7088
|
throw( "Set Widget Name!" );
|
|
5955
7089
|
}
|
|
5956
7090
|
|
|
@@ -5988,7 +7122,8 @@ class Panel {
|
|
|
5988
7122
|
color.useRGB = options.useRGB ?? false;
|
|
5989
7123
|
color.value = color.iValue = value.constructor === Array ? rgbToHex( value ) : value;
|
|
5990
7124
|
|
|
5991
|
-
if( options.disabled )
|
|
7125
|
+
if( options.disabled )
|
|
7126
|
+
{
|
|
5992
7127
|
color.disabled = true;
|
|
5993
7128
|
}
|
|
5994
7129
|
|
|
@@ -5997,39 +7132,170 @@ class Panel {
|
|
|
5997
7132
|
|
|
5998
7133
|
const skipCallback = e.detail;
|
|
5999
7134
|
|
|
6000
|
-
// Change value (always hex)
|
|
6001
|
-
if( !change_from_input )
|
|
6002
|
-
text_widget.set( val );
|
|
7135
|
+
// Change value (always hex)
|
|
7136
|
+
if( !change_from_input )
|
|
7137
|
+
text_widget.set( val );
|
|
7138
|
+
|
|
7139
|
+
// Reset button (default value)
|
|
7140
|
+
if( !skipCallback )
|
|
7141
|
+
{
|
|
7142
|
+
let btn = element.querySelector( ".lexwidgetname .lexicon" );
|
|
7143
|
+
if( btn ) btn.style.display = val != color.iValue ? "block": "none";
|
|
7144
|
+
}
|
|
7145
|
+
|
|
7146
|
+
if( color.useRGB )
|
|
7147
|
+
val = hexToRgb( val );
|
|
7148
|
+
|
|
7149
|
+
if( !skipCallback ) this._trigger( new IEvent( name, val, e ), callback );
|
|
7150
|
+
}, false );
|
|
7151
|
+
|
|
7152
|
+
container.appendChild( color );
|
|
7153
|
+
|
|
7154
|
+
this.queue( container );
|
|
7155
|
+
|
|
7156
|
+
const text_widget = this.addText( null, color.value, v => {
|
|
7157
|
+
change_from_input = true;
|
|
7158
|
+
widget.set( v );
|
|
7159
|
+
change_from_input = false;
|
|
7160
|
+
}, { width: "calc( 100% - 32px )"});
|
|
7161
|
+
|
|
7162
|
+
text_widget.domEl.style.marginLeft = "4px";
|
|
7163
|
+
|
|
7164
|
+
this.clearQueue();
|
|
7165
|
+
|
|
7166
|
+
element.appendChild( container );
|
|
7167
|
+
|
|
7168
|
+
return widget;
|
|
7169
|
+
}
|
|
7170
|
+
|
|
7171
|
+
/**
|
|
7172
|
+
* @method addRange
|
|
7173
|
+
* @param {String} name Widget name
|
|
7174
|
+
* @param {Number} value Default number value
|
|
7175
|
+
* @param {Function} callback Callback function on change
|
|
7176
|
+
* @param {*} options:
|
|
7177
|
+
* className: Extra classes to customize style
|
|
7178
|
+
* disabled: Make the widget disabled [false]
|
|
7179
|
+
* left: The slider goes to the left instead of the right
|
|
7180
|
+
* fill: Fill slider progress [true]
|
|
7181
|
+
* step: Step of the input
|
|
7182
|
+
* min, max: Min and Max values for the input
|
|
7183
|
+
*/
|
|
7184
|
+
|
|
7185
|
+
addRange( name, value, callback, options = {} ) {
|
|
7186
|
+
|
|
7187
|
+
let widget = this.create_widget( name, Widget.RANGE, options );
|
|
7188
|
+
|
|
7189
|
+
widget.onGetValue = () => {
|
|
7190
|
+
return +slider.value;
|
|
7191
|
+
};
|
|
7192
|
+
|
|
7193
|
+
widget.onSetValue = ( newValue, skipCallback ) => {
|
|
7194
|
+
slider.value = newValue;
|
|
7195
|
+
Panel._dispatch_event( slider, "input", skipCallback );
|
|
7196
|
+
};
|
|
7197
|
+
|
|
7198
|
+
let element = widget.domEl;
|
|
7199
|
+
|
|
7200
|
+
// add reset functionality
|
|
7201
|
+
if( widget.name )
|
|
7202
|
+
{
|
|
7203
|
+
Panel._add_reset_property( element.domName, function() {
|
|
7204
|
+
this.style.display = "none";
|
|
7205
|
+
slider.value = slider.iValue;
|
|
7206
|
+
Panel._dispatch_event( slider, "input" );
|
|
7207
|
+
});
|
|
7208
|
+
}
|
|
7209
|
+
|
|
7210
|
+
// add widget value
|
|
7211
|
+
|
|
7212
|
+
var container = document.createElement( 'div' );
|
|
7213
|
+
container.className = "lexrange";
|
|
7214
|
+
container.style.width = options.inputWidth || "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
|
|
7215
|
+
|
|
7216
|
+
let slider = document.createElement( 'input' );
|
|
7217
|
+
slider.className = "lexrangeslider " + ( options.className ?? "" );
|
|
7218
|
+
slider.value = slider.iValue = value;
|
|
7219
|
+
slider.min = options.min;
|
|
7220
|
+
slider.max = options.max;
|
|
7221
|
+
slider.step = options.step ?? 1;
|
|
7222
|
+
slider.type = "range";
|
|
7223
|
+
slider.disabled = options.disabled ?? false;
|
|
7224
|
+
|
|
7225
|
+
if( options.left ?? false )
|
|
7226
|
+
{
|
|
7227
|
+
slider.classList.add( "left" );
|
|
7228
|
+
}
|
|
7229
|
+
|
|
7230
|
+
if( !( options.fill ?? true ) )
|
|
7231
|
+
{
|
|
7232
|
+
slider.classList.add( "no-fill" );
|
|
7233
|
+
}
|
|
7234
|
+
|
|
7235
|
+
slider.addEventListener( "input", e => {
|
|
7236
|
+
|
|
7237
|
+
if( isNaN( e.target.valueAsNumber ) )
|
|
7238
|
+
{
|
|
7239
|
+
return;
|
|
7240
|
+
}
|
|
7241
|
+
|
|
7242
|
+
const skipCallback = e.detail;
|
|
7243
|
+
|
|
7244
|
+
let val = e.target.value = clamp( +e.target.valueAsNumber, +slider.min, +slider.max );
|
|
7245
|
+
slider.value = val;
|
|
6003
7246
|
|
|
6004
7247
|
// Reset button (default value)
|
|
6005
7248
|
if( !skipCallback )
|
|
6006
7249
|
{
|
|
6007
7250
|
let btn = element.querySelector( ".lexwidgetname .lexicon" );
|
|
6008
|
-
if( btn ) btn.style.display = val !=
|
|
7251
|
+
if( btn ) btn.style.display = val != slider.iValue ? "block": "none";
|
|
6009
7252
|
}
|
|
6010
7253
|
|
|
6011
|
-
if(
|
|
6012
|
-
|
|
7254
|
+
if( options.left )
|
|
7255
|
+
{
|
|
7256
|
+
val = ( +slider.max ) - val + ( +slider.min );
|
|
7257
|
+
}
|
|
6013
7258
|
|
|
6014
7259
|
if( !skipCallback ) this._trigger( new IEvent( name, val, e ), callback );
|
|
6015
|
-
}, false );
|
|
6016
|
-
|
|
6017
|
-
container.appendChild( color );
|
|
7260
|
+
}, { passive: false });
|
|
6018
7261
|
|
|
6019
|
-
|
|
7262
|
+
slider.addEventListener( "mousedown", function( e ) {
|
|
7263
|
+
if( options.onPress )
|
|
7264
|
+
{
|
|
7265
|
+
options.onPress.bind( slider )( e, slider );
|
|
7266
|
+
}
|
|
7267
|
+
}, false );
|
|
6020
7268
|
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
7269
|
+
slider.addEventListener( "mouseup", function( e ) {
|
|
7270
|
+
if( options.onRelease )
|
|
7271
|
+
{
|
|
7272
|
+
options.onRelease.bind( slider )( e, slider );
|
|
7273
|
+
}
|
|
7274
|
+
}, false );
|
|
6026
7275
|
|
|
6027
|
-
|
|
7276
|
+
// Method to change min, max, step parameters
|
|
7277
|
+
widget.setLimits = ( newMin, newMax, newStep ) => {
|
|
7278
|
+
slider.min = newMin ?? slider.min;
|
|
7279
|
+
slider.max = newMax ?? slider.max;
|
|
7280
|
+
slider.step = newStep ?? slider.step;
|
|
7281
|
+
Panel._dispatch_event( slider, "input", true );
|
|
7282
|
+
};
|
|
6028
7283
|
|
|
6029
|
-
|
|
7284
|
+
if( value.constructor == Number )
|
|
7285
|
+
{
|
|
7286
|
+
value = clamp( value, +slider.min, +slider.max );
|
|
7287
|
+
}
|
|
6030
7288
|
|
|
7289
|
+
container.appendChild( slider );
|
|
6031
7290
|
element.appendChild( container );
|
|
6032
7291
|
|
|
7292
|
+
// Remove branch padding and margins
|
|
7293
|
+
if( !widget.name )
|
|
7294
|
+
{
|
|
7295
|
+
element.className += " noname";
|
|
7296
|
+
container.style.width = "100%";
|
|
7297
|
+
}
|
|
7298
|
+
|
|
6033
7299
|
return widget;
|
|
6034
7300
|
}
|
|
6035
7301
|
|
|
@@ -6065,7 +7331,8 @@ class Panel {
|
|
|
6065
7331
|
let element = widget.domEl;
|
|
6066
7332
|
|
|
6067
7333
|
// add reset functionality
|
|
6068
|
-
if( widget.name )
|
|
7334
|
+
if( widget.name )
|
|
7335
|
+
{
|
|
6069
7336
|
Panel._add_reset_property( element.domName, function() {
|
|
6070
7337
|
this.style.display = "none";
|
|
6071
7338
|
vecinput.value = vecinput.iValue;
|
|
@@ -6333,7 +7600,8 @@ class Panel {
|
|
|
6333
7600
|
return;
|
|
6334
7601
|
}
|
|
6335
7602
|
|
|
6336
|
-
for( let i = 0; i < inputs.length; ++i )
|
|
7603
|
+
for( let i = 0; i < inputs.length; ++i )
|
|
7604
|
+
{
|
|
6337
7605
|
let value = newValue[ i ];
|
|
6338
7606
|
inputs[ i ].value = round( value, options.precision ) ?? 0;
|
|
6339
7607
|
Panel._dispatch_event( inputs[ i ], "change", skipCallback );
|
|
@@ -6345,7 +7613,8 @@ class Panel {
|
|
|
6345
7613
|
// Add reset functionality
|
|
6346
7614
|
Panel._add_reset_property( element.domName, function() {
|
|
6347
7615
|
this.style.display = "none";
|
|
6348
|
-
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7616
|
+
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7617
|
+
{
|
|
6349
7618
|
v.value = v.iValue;
|
|
6350
7619
|
Panel._dispatch_event( v, "change" );
|
|
6351
7620
|
}
|
|
@@ -6357,8 +7626,8 @@ class Panel {
|
|
|
6357
7626
|
container.className = "lexvector";
|
|
6358
7627
|
container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
|
|
6359
7628
|
|
|
6360
|
-
for( let i = 0; i < num_components; ++i )
|
|
6361
|
-
|
|
7629
|
+
for( let i = 0; i < num_components; ++i )
|
|
7630
|
+
{
|
|
6362
7631
|
let box = document.createElement( 'div' );
|
|
6363
7632
|
box.className = "vecbox";
|
|
6364
7633
|
box.innerHTML = "<span class='" + Panel.VECTOR_COMPONENTS[ i ] + "'></span>";
|
|
@@ -6434,7 +7703,8 @@ class Panel {
|
|
|
6434
7703
|
|
|
6435
7704
|
if( locker.locked )
|
|
6436
7705
|
{
|
|
6437
|
-
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7706
|
+
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7707
|
+
{
|
|
6438
7708
|
v.value = val;
|
|
6439
7709
|
value[ v.idx ] = val;
|
|
6440
7710
|
}
|
|
@@ -6492,7 +7762,8 @@ class Panel {
|
|
|
6492
7762
|
|
|
6493
7763
|
if( locker.locked )
|
|
6494
7764
|
{
|
|
6495
|
-
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7765
|
+
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7766
|
+
{
|
|
6496
7767
|
v.value = round( +v.valueAsNumber + mult * dt, options.precision );
|
|
6497
7768
|
Panel._dispatch_event( v, "change" );
|
|
6498
7769
|
}
|
|
@@ -6618,7 +7889,7 @@ class Panel {
|
|
|
6618
7889
|
const value = [];
|
|
6619
7890
|
for( let i = 0; i < element.dimensions.length; ++i )
|
|
6620
7891
|
{
|
|
6621
|
-
value.push( element.dimensions[ i ].
|
|
7892
|
+
value.push( element.dimensions[ i ].value() );
|
|
6622
7893
|
}
|
|
6623
7894
|
return value;
|
|
6624
7895
|
};
|
|
@@ -6626,7 +7897,7 @@ class Panel {
|
|
|
6626
7897
|
widget.onSetValue = ( newValue, skipCallback ) => {
|
|
6627
7898
|
for( let i = 0; i < element.dimensions.length; ++i )
|
|
6628
7899
|
{
|
|
6629
|
-
element.dimensions[ i ].
|
|
7900
|
+
element.dimensions[ i ].set( newValue[ i ], skipCallback );
|
|
6630
7901
|
}
|
|
6631
7902
|
};
|
|
6632
7903
|
|
|
@@ -6641,14 +7912,14 @@ class Panel {
|
|
|
6641
7912
|
{
|
|
6642
7913
|
element.dimensions[ i ] = this.addNumber( null, value[ i ], ( v ) => {
|
|
6643
7914
|
|
|
6644
|
-
const value = widget.
|
|
7915
|
+
const value = widget.value();
|
|
6645
7916
|
|
|
6646
7917
|
if( element.locked )
|
|
6647
7918
|
{
|
|
6648
7919
|
const ar = ( i == 0 ? 1.0 / element.aspectRatio : element.aspectRatio );
|
|
6649
7920
|
const index = ( 1 + i ) % 2;
|
|
6650
7921
|
value[ index ] = v * ar;
|
|
6651
|
-
element.dimensions[ index ].
|
|
7922
|
+
element.dimensions[ index ].set( value[ index ], true );
|
|
6652
7923
|
}
|
|
6653
7924
|
|
|
6654
7925
|
if( callback )
|
|
@@ -6691,7 +7962,7 @@ class Panel {
|
|
|
6691
7962
|
this.classList.remove( "fa-lock-open" );
|
|
6692
7963
|
|
|
6693
7964
|
// Recompute ratio
|
|
6694
|
-
const value = widget.
|
|
7965
|
+
const value = widget.value();
|
|
6695
7966
|
element.aspectRatio = value[ 0 ] / value[ 1 ];
|
|
6696
7967
|
}
|
|
6697
7968
|
else
|
|
@@ -7088,7 +8359,8 @@ class Panel {
|
|
|
7088
8359
|
let container = document.createElement('div');
|
|
7089
8360
|
container.className = "lextree";
|
|
7090
8361
|
|
|
7091
|
-
if(name)
|
|
8362
|
+
if( name )
|
|
8363
|
+
{
|
|
7092
8364
|
let title = document.createElement('span');
|
|
7093
8365
|
title.innerHTML = name;
|
|
7094
8366
|
container.appendChild(title);
|
|
@@ -7100,8 +8372,8 @@ class Panel {
|
|
|
7100
8372
|
toolsDiv.className += " notitle";
|
|
7101
8373
|
|
|
7102
8374
|
// Tree icons
|
|
7103
|
-
if(options.icons)
|
|
7104
|
-
|
|
8375
|
+
if( options.icons )
|
|
8376
|
+
{
|
|
7105
8377
|
for( let data of options.icons )
|
|
7106
8378
|
{
|
|
7107
8379
|
let iconEl = document.createElement('a');
|
|
@@ -7161,11 +8433,15 @@ class Panel {
|
|
|
7161
8433
|
let widget = new Widget( null, Widget.SEPARATOR );
|
|
7162
8434
|
widget.domEl = element;
|
|
7163
8435
|
|
|
7164
|
-
if(this.current_branch)
|
|
8436
|
+
if( this.current_branch )
|
|
8437
|
+
{
|
|
7165
8438
|
this.current_branch.content.appendChild( element );
|
|
7166
8439
|
this.current_branch.widgets.push( widget );
|
|
7167
|
-
}
|
|
7168
|
-
|
|
8440
|
+
}
|
|
8441
|
+
else
|
|
8442
|
+
{
|
|
8443
|
+
this.root.appendChild( element );
|
|
8444
|
+
}
|
|
7169
8445
|
}
|
|
7170
8446
|
|
|
7171
8447
|
/**
|
|
@@ -7346,6 +8622,234 @@ class Panel {
|
|
|
7346
8622
|
|
|
7347
8623
|
return widget;
|
|
7348
8624
|
}
|
|
8625
|
+
|
|
8626
|
+
/**
|
|
8627
|
+
* @method addTable
|
|
8628
|
+
* @param {String} name Widget name
|
|
8629
|
+
* @param {Number} data Table data
|
|
8630
|
+
* @param {*} options:
|
|
8631
|
+
* head: Table headers (each of the headers per column)
|
|
8632
|
+
* body: Table body (data per row for each column)
|
|
8633
|
+
* rowActions: Allow to add actions per row
|
|
8634
|
+
* onMenuAction: Function callback to fill the "menu" context
|
|
8635
|
+
* selectable: Each row can be selected
|
|
8636
|
+
*/
|
|
8637
|
+
|
|
8638
|
+
addTable( name, data, options = { } ) {
|
|
8639
|
+
|
|
8640
|
+
if( !data )
|
|
8641
|
+
{
|
|
8642
|
+
throw( "Data is needed to create a table!" );
|
|
8643
|
+
}
|
|
8644
|
+
|
|
8645
|
+
let widget = this.create_widget( name, Widget.TABLE, options );
|
|
8646
|
+
|
|
8647
|
+
widget.onGetValue = () => {
|
|
8648
|
+
|
|
8649
|
+
};
|
|
8650
|
+
|
|
8651
|
+
widget.onSetValue = ( newValue, skipCallback ) => {
|
|
8652
|
+
|
|
8653
|
+
};
|
|
8654
|
+
|
|
8655
|
+
let element = widget.domEl;
|
|
8656
|
+
|
|
8657
|
+
const container = document.createElement('div');
|
|
8658
|
+
container.className = "lextable";
|
|
8659
|
+
container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
|
|
8660
|
+
|
|
8661
|
+
const table = document.createElement( 'table' );
|
|
8662
|
+
container.appendChild( table );
|
|
8663
|
+
|
|
8664
|
+
data.head = data.head ?? [];
|
|
8665
|
+
data.body = data.body ?? [];
|
|
8666
|
+
data.orderMap = { };
|
|
8667
|
+
data.checkMap = { };
|
|
8668
|
+
|
|
8669
|
+
function compareFn( idx, order, a, b) {
|
|
8670
|
+
if (a[idx] < b[idx]) return -order;
|
|
8671
|
+
else if (a[idx] > b[idx]) return order;
|
|
8672
|
+
return 0;
|
|
8673
|
+
}
|
|
8674
|
+
|
|
8675
|
+
widget.refreshTable = () => {
|
|
8676
|
+
|
|
8677
|
+
table.innerHTML = "";
|
|
8678
|
+
|
|
8679
|
+
// Head
|
|
8680
|
+
{
|
|
8681
|
+
const head = document.createElement( 'thead' );
|
|
8682
|
+
head.className = "lextablehead";
|
|
8683
|
+
table.appendChild( head );
|
|
8684
|
+
|
|
8685
|
+
const hrow = document.createElement( 'tr' );
|
|
8686
|
+
|
|
8687
|
+
if( options.selectable )
|
|
8688
|
+
{
|
|
8689
|
+
const th = document.createElement( 'th' );
|
|
8690
|
+
const input = document.createElement( 'input' );
|
|
8691
|
+
input.type = "checkbox";
|
|
8692
|
+
input.className = "lexcheckbox";
|
|
8693
|
+
input.checked = data.checkMap[ ":root" ] ?? false;
|
|
8694
|
+
th.appendChild( input );
|
|
8695
|
+
|
|
8696
|
+
input.addEventListener( 'change', function() {
|
|
8697
|
+
|
|
8698
|
+
data.checkMap[ ":root" ] = this.checked;
|
|
8699
|
+
|
|
8700
|
+
const body = table.querySelector( "tbody" );
|
|
8701
|
+
for( const el of body.childNodes )
|
|
8702
|
+
{
|
|
8703
|
+
data.checkMap[ el.getAttribute( "rowId" ) ] = this.checked;
|
|
8704
|
+
el.querySelector( "input" ).checked = this.checked;
|
|
8705
|
+
}
|
|
8706
|
+
});
|
|
8707
|
+
|
|
8708
|
+
hrow.appendChild( th );
|
|
8709
|
+
}
|
|
8710
|
+
|
|
8711
|
+
for( const headData of data.head )
|
|
8712
|
+
{
|
|
8713
|
+
const th = document.createElement( 'th' );
|
|
8714
|
+
th.innerHTML = `${ headData } <a class="fa-solid fa-sort"></a>`;
|
|
8715
|
+
|
|
8716
|
+
th.querySelector( 'a' ).addEventListener( 'click', () => {
|
|
8717
|
+
|
|
8718
|
+
if( !data.orderMap[ headData ] )
|
|
8719
|
+
{
|
|
8720
|
+
data.orderMap[ headData ] = 1;
|
|
8721
|
+
}
|
|
8722
|
+
|
|
8723
|
+
const idx = data.head.indexOf(headData);
|
|
8724
|
+
data.body = data.body.sort( compareFn.bind( this, idx,data.orderMap[ headData ] ) );
|
|
8725
|
+
data.orderMap[ headData ] = -data.orderMap[ headData ];
|
|
8726
|
+
|
|
8727
|
+
widget.refreshTable();
|
|
8728
|
+
|
|
8729
|
+
});
|
|
8730
|
+
|
|
8731
|
+
hrow.appendChild( th );
|
|
8732
|
+
}
|
|
8733
|
+
|
|
8734
|
+
// Add empty header column
|
|
8735
|
+
if( options.rowActions )
|
|
8736
|
+
{
|
|
8737
|
+
const th = document.createElement( 'th' );
|
|
8738
|
+
th.className = "sm";
|
|
8739
|
+
hrow.appendChild( th );
|
|
8740
|
+
}
|
|
8741
|
+
|
|
8742
|
+
head.appendChild( hrow );
|
|
8743
|
+
}
|
|
8744
|
+
|
|
8745
|
+
// Body
|
|
8746
|
+
{
|
|
8747
|
+
const body = document.createElement( 'tbody' );
|
|
8748
|
+
body.className = "lextablebody";
|
|
8749
|
+
table.appendChild( body );
|
|
8750
|
+
|
|
8751
|
+
for( let r = 0; r < data.body.length; ++r )
|
|
8752
|
+
{
|
|
8753
|
+
const bodyData = data.body[ r ];
|
|
8754
|
+
const row = document.createElement( 'tr' );
|
|
8755
|
+
const rowId = LX.getSupportedDOMName( bodyData.join( '-' ) );
|
|
8756
|
+
row.setAttribute( "rowId", rowId );
|
|
8757
|
+
|
|
8758
|
+
if( options.selectable )
|
|
8759
|
+
{
|
|
8760
|
+
const td = document.createElement( 'td' );
|
|
8761
|
+
const input = document.createElement( 'input' );
|
|
8762
|
+
input.type = "checkbox";
|
|
8763
|
+
input.className = "lexcheckbox";
|
|
8764
|
+
input.checked = data.checkMap[ rowId ];
|
|
8765
|
+
td.appendChild( input );
|
|
8766
|
+
|
|
8767
|
+
input.addEventListener( 'change', function() {
|
|
8768
|
+
data.checkMap[ rowId ] = this.checked;
|
|
8769
|
+
|
|
8770
|
+
if( !this.checked )
|
|
8771
|
+
{
|
|
8772
|
+
const input = table.querySelector( "thead input[type='checkbox']" );
|
|
8773
|
+
input.checked = data.checkMap[ ":root" ] = false;
|
|
8774
|
+
}
|
|
8775
|
+
});
|
|
8776
|
+
|
|
8777
|
+
row.appendChild( td );
|
|
8778
|
+
}
|
|
8779
|
+
|
|
8780
|
+
for( const rowData of bodyData )
|
|
8781
|
+
{
|
|
8782
|
+
const td = document.createElement( 'td' );
|
|
8783
|
+
td.innerHTML = `${ rowData }`;
|
|
8784
|
+
row.appendChild( td );
|
|
8785
|
+
}
|
|
8786
|
+
|
|
8787
|
+
if( options.rowActions )
|
|
8788
|
+
{
|
|
8789
|
+
const td = document.createElement( 'td' );
|
|
8790
|
+
td.className = "sm";
|
|
8791
|
+
|
|
8792
|
+
const buttons = document.createElement( 'div' );
|
|
8793
|
+
buttons.className = "lextablebuttons";
|
|
8794
|
+
td.appendChild( buttons );
|
|
8795
|
+
|
|
8796
|
+
for( const action of options.rowActions )
|
|
8797
|
+
{
|
|
8798
|
+
const button = document.createElement( 'a' );
|
|
8799
|
+
button.className = "lexicon";
|
|
8800
|
+
|
|
8801
|
+
if( action == "delete" )
|
|
8802
|
+
{
|
|
8803
|
+
button.className += " fa-solid fa-trash-can";
|
|
8804
|
+
button.addEventListener( 'click', function() {
|
|
8805
|
+
// Don't need to refresh table..
|
|
8806
|
+
data.body.splice( r, 1 );
|
|
8807
|
+
row.remove();
|
|
8808
|
+
});
|
|
8809
|
+
}
|
|
8810
|
+
else if( action == "menu" )
|
|
8811
|
+
{
|
|
8812
|
+
button.className += " fa-solid fa-ellipsis";
|
|
8813
|
+
button.addEventListener( 'click', function( event ) {
|
|
8814
|
+
addContextMenu( null, event, c => {
|
|
8815
|
+
if( options.onMenuAction )
|
|
8816
|
+
{
|
|
8817
|
+
options.onMenuAction( c );
|
|
8818
|
+
return;
|
|
8819
|
+
}
|
|
8820
|
+
console.warn( "Using <Menu action> without action callbacks." );
|
|
8821
|
+
} );
|
|
8822
|
+
});
|
|
8823
|
+
}
|
|
8824
|
+
else // custom actions
|
|
8825
|
+
{
|
|
8826
|
+
console.assert( action.constructor == Object );
|
|
8827
|
+
button.className += ` ${ action.icon }`;
|
|
8828
|
+
}
|
|
8829
|
+
|
|
8830
|
+
buttons.appendChild( button );
|
|
8831
|
+
}
|
|
8832
|
+
|
|
8833
|
+
row.appendChild( td );
|
|
8834
|
+
}
|
|
8835
|
+
|
|
8836
|
+
body.appendChild( row );
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
}
|
|
8840
|
+
|
|
8841
|
+
widget.refreshTable();
|
|
8842
|
+
|
|
8843
|
+
if( !widget.name )
|
|
8844
|
+
{
|
|
8845
|
+
element.className += " noname";
|
|
8846
|
+
container.style.width = "100%";
|
|
8847
|
+
}
|
|
8848
|
+
|
|
8849
|
+
element.appendChild( container );
|
|
8850
|
+
|
|
8851
|
+
return widget;
|
|
8852
|
+
}
|
|
7349
8853
|
}
|
|
7350
8854
|
|
|
7351
8855
|
LX.Panel = Panel;
|
|
@@ -7393,7 +8897,7 @@ class Branch {
|
|
|
7393
8897
|
root.appendChild( title );
|
|
7394
8898
|
|
|
7395
8899
|
var branchContent = document.createElement( 'div' );
|
|
7396
|
-
branchContent.id = name.replace(/\s/g, '');
|
|
8900
|
+
branchContent.id = name.replace( /\s/g, '' );
|
|
7397
8901
|
branchContent.className = "lexbranchcontent";
|
|
7398
8902
|
root.appendChild(branchContent);
|
|
7399
8903
|
this.content = branchContent;
|
|
@@ -7449,7 +8953,8 @@ class Branch {
|
|
|
7449
8953
|
|
|
7450
8954
|
const dialog = new Dialog(this.name, p => {
|
|
7451
8955
|
// add widgets
|
|
7452
|
-
for( let w of this.widgets )
|
|
8956
|
+
for( let w of this.widgets )
|
|
8957
|
+
{
|
|
7453
8958
|
p.root.appendChild( w.domEl );
|
|
7454
8959
|
}
|
|
7455
8960
|
});
|
|
@@ -7542,8 +9047,8 @@ class Branch {
|
|
|
7542
9047
|
var size = this.grabber.style.marginLeft;
|
|
7543
9048
|
|
|
7544
9049
|
// Update sizes of widgets inside
|
|
7545
|
-
for(var i = 0; i < this.widgets.length; i++)
|
|
7546
|
-
|
|
9050
|
+
for( var i = 0; i < this.widgets.length; i++ )
|
|
9051
|
+
{
|
|
7547
9052
|
let widget = this.widgets[ i ];
|
|
7548
9053
|
let element = widget.domEl;
|
|
7549
9054
|
|
|
@@ -7562,9 +9067,6 @@ class Branch {
|
|
|
7562
9067
|
case Widget.FILE:
|
|
7563
9068
|
padding = "10%";
|
|
7564
9069
|
break;
|
|
7565
|
-
case Widget.TEXT:
|
|
7566
|
-
padding = "8px";
|
|
7567
|
-
break;
|
|
7568
9070
|
};
|
|
7569
9071
|
|
|
7570
9072
|
value.style.width = "-moz-calc( 100% - " + size + " - " + padding + " )";
|
|
@@ -7702,16 +9204,15 @@ class Dialog {
|
|
|
7702
9204
|
draggable = options.draggable ?? true,
|
|
7703
9205
|
modal = options.modal ?? false;
|
|
7704
9206
|
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
LX.modal.toggle( false );
|
|
7708
|
-
}
|
|
7709
|
-
|
|
7710
|
-
var root = document.createElement('div');
|
|
7711
|
-
root.className = "lexdialog " + (options.class ?? "");
|
|
9207
|
+
var root = document.createElement('dialog');
|
|
9208
|
+
root.className = "lexdialog " + (options.className ?? "");
|
|
7712
9209
|
root.id = options.id ?? "dialog" + Dialog._last_id++;
|
|
7713
9210
|
LX.root.appendChild( root );
|
|
7714
9211
|
|
|
9212
|
+
doAsync( () => {
|
|
9213
|
+
modal ? root.showModal() : root.show();
|
|
9214
|
+
}, 10 );
|
|
9215
|
+
|
|
7715
9216
|
let that = this;
|
|
7716
9217
|
|
|
7717
9218
|
var titleDiv = document.createElement('div');
|
|
@@ -7793,18 +9294,17 @@ class Dialog {
|
|
|
7793
9294
|
|
|
7794
9295
|
if( !options.onclose )
|
|
7795
9296
|
{
|
|
7796
|
-
|
|
7797
|
-
|
|
9297
|
+
root.close();
|
|
9298
|
+
|
|
9299
|
+
doAsync( () => {
|
|
9300
|
+
that.panel.clear();
|
|
9301
|
+
root.remove();
|
|
9302
|
+
}, 150 );
|
|
7798
9303
|
}
|
|
7799
9304
|
else
|
|
7800
9305
|
{
|
|
7801
9306
|
options.onclose( this.root );
|
|
7802
9307
|
}
|
|
7803
|
-
|
|
7804
|
-
if( modal )
|
|
7805
|
-
{
|
|
7806
|
-
LX.modal.toggle( true );
|
|
7807
|
-
}
|
|
7808
9308
|
};
|
|
7809
9309
|
|
|
7810
9310
|
var closeButton = document.createElement( 'a' );
|
|
@@ -7863,15 +9363,15 @@ class Dialog {
|
|
|
7863
9363
|
|
|
7864
9364
|
root.style.width = size[ 0 ] ? (size[ 0 ]) : "25%";
|
|
7865
9365
|
root.style.height = size[ 1 ] ? (size[ 1 ]) : "auto";
|
|
9366
|
+
root.style.translate = options.position ? "unset" : "-50% -50%";
|
|
7866
9367
|
|
|
7867
9368
|
if( options.size )
|
|
7868
9369
|
{
|
|
7869
9370
|
this.size = size;
|
|
7870
9371
|
}
|
|
7871
9372
|
|
|
7872
|
-
|
|
7873
|
-
root.style.
|
|
7874
|
-
root.style.top = position[ 1 ] ? (position[ 1 ]) : "calc( 50% - " + ( rect.height * 0.5 ) + "px )";
|
|
9373
|
+
root.style.left = position[ 0 ] ?? "50%";
|
|
9374
|
+
root.style.top = position[ 1 ] ?? "50%";
|
|
7875
9375
|
|
|
7876
9376
|
panel.root.style.width = "calc( 100% - 30px )";
|
|
7877
9377
|
panel.root.style.height = title ? "calc( 100% - " + ( titleDiv.offsetHeight + 30 ) + "px )" : "calc( 100% - 51px )";
|
|
@@ -7888,7 +9388,7 @@ class Dialog {
|
|
|
7888
9388
|
this._oncreate.call(this, this.panel);
|
|
7889
9389
|
}
|
|
7890
9390
|
|
|
7891
|
-
setPosition(x, y) {
|
|
9391
|
+
setPosition( x, y ) {
|
|
7892
9392
|
|
|
7893
9393
|
this.root.style.left = x + "px";
|
|
7894
9394
|
this.root.style.top = y + "px";
|
|
@@ -7919,21 +9419,32 @@ class PocketDialog extends Dialog {
|
|
|
7919
9419
|
options.draggable = options.draggable ?? false;
|
|
7920
9420
|
options.closable = options.closable ?? false;
|
|
7921
9421
|
|
|
9422
|
+
const dragMargin = 3;
|
|
9423
|
+
|
|
7922
9424
|
super( title, callback, options );
|
|
7923
9425
|
|
|
7924
9426
|
let that = this;
|
|
7925
9427
|
// Update margins on branch title closes/opens
|
|
7926
9428
|
LX.addSignal("@on_branch_closed", this.panel, closed => {
|
|
7927
9429
|
if( this.dock_pos == PocketDialog.BOTTOM )
|
|
7928
|
-
|
|
9430
|
+
{
|
|
9431
|
+
this.root.style.top = "calc(100% - " + (this.root.offsetHeight + dragMargin) + "px)";
|
|
9432
|
+
}
|
|
7929
9433
|
});
|
|
7930
9434
|
|
|
7931
9435
|
// Custom
|
|
7932
9436
|
this.root.classList.add( "pocket" );
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
|
|
9437
|
+
|
|
9438
|
+
this.root.style.translate = "none";
|
|
9439
|
+
this.root.style.top = "0";
|
|
9440
|
+
this.root.style.left = "unset";
|
|
9441
|
+
|
|
9442
|
+
if( !options.position )
|
|
9443
|
+
{
|
|
9444
|
+
this.root.style.right = dragMargin + "px";
|
|
9445
|
+
this.root.style.top = dragMargin + "px";
|
|
7936
9446
|
}
|
|
9447
|
+
|
|
7937
9448
|
this.panel.root.style.width = "calc( 100% - 12px )";
|
|
7938
9449
|
this.panel.root.style.height = "calc( 100% - 40px )";
|
|
7939
9450
|
this.dock_pos = PocketDialog.TOP;
|
|
@@ -7941,6 +9452,11 @@ class PocketDialog extends Dialog {
|
|
|
7941
9452
|
this.minimized = false;
|
|
7942
9453
|
this.title.tabIndex = -1;
|
|
7943
9454
|
this.title.addEventListener("click", e => {
|
|
9455
|
+
if( this.title._eventCatched )
|
|
9456
|
+
{
|
|
9457
|
+
this.title._eventCatched = false;
|
|
9458
|
+
return;
|
|
9459
|
+
}
|
|
7944
9460
|
|
|
7945
9461
|
// Sized dialogs have to keep their size
|
|
7946
9462
|
if( this.size )
|
|
@@ -7954,7 +9470,7 @@ class PocketDialog extends Dialog {
|
|
|
7954
9470
|
|
|
7955
9471
|
if( this.dock_pos == PocketDialog.BOTTOM )
|
|
7956
9472
|
that.root.style.top = this.root.classList.contains("minimized") ?
|
|
7957
|
-
"calc(100% - " + (that.title.offsetHeight + 6) + "px)" : "calc(100% - " + (that.root.offsetHeight +
|
|
9473
|
+
"calc(100% - " + (that.title.offsetHeight + 6) + "px)" : "calc(100% - " + (that.root.offsetHeight + dragMargin) + "px)";
|
|
7958
9474
|
});
|
|
7959
9475
|
|
|
7960
9476
|
if( !options.draggable )
|
|
@@ -7969,26 +9485,42 @@ class PocketDialog extends Dialog {
|
|
|
7969
9485
|
switch( t )
|
|
7970
9486
|
{
|
|
7971
9487
|
case 'b':
|
|
7972
|
-
this.root.style.top = "calc(100% - " + (this.root.offsetHeight +
|
|
9488
|
+
this.root.style.top = "calc(100% - " + (this.root.offsetHeight + dragMargin) + "px)";
|
|
7973
9489
|
break;
|
|
7974
9490
|
case 'l':
|
|
7975
|
-
this.root.style.
|
|
9491
|
+
this.root.style.right = "unset";
|
|
9492
|
+
this.root.style.left = options.position ? options.position[ 1 ] : ( dragMargin + "px" );
|
|
7976
9493
|
break;
|
|
7977
9494
|
}
|
|
7978
9495
|
}
|
|
7979
9496
|
}
|
|
7980
9497
|
|
|
7981
9498
|
this.root.classList.add('dockable');
|
|
7982
|
-
|
|
7983
|
-
|
|
9499
|
+
|
|
9500
|
+
this.title.addEventListener("keydown", function( e ) {
|
|
9501
|
+
if( !e.ctrlKey )
|
|
9502
|
+
{
|
|
9503
|
+
return;
|
|
9504
|
+
}
|
|
9505
|
+
|
|
9506
|
+
that.root.style.right = "unset";
|
|
9507
|
+
|
|
9508
|
+
if( e.key == 'ArrowLeft' )
|
|
9509
|
+
{
|
|
7984
9510
|
that.root.style.left = '0px';
|
|
7985
|
-
}
|
|
7986
|
-
|
|
7987
|
-
|
|
9511
|
+
}
|
|
9512
|
+
else if( e.key == 'ArrowRight' )
|
|
9513
|
+
{
|
|
9514
|
+
that.root.style.left = "calc(100% - " + (that.root.offsetWidth + dragMargin) + "px)";
|
|
9515
|
+
}
|
|
9516
|
+
else if( e.key == 'ArrowUp' )
|
|
9517
|
+
{
|
|
7988
9518
|
that.root.style.top = "0px";
|
|
7989
9519
|
that.dock_pos = PocketDialog.TOP;
|
|
7990
|
-
}
|
|
7991
|
-
|
|
9520
|
+
}
|
|
9521
|
+
else if( e.key == 'ArrowDown' )
|
|
9522
|
+
{
|
|
9523
|
+
that.root.style.top = "calc(100% - " + (that.root.offsetHeight + dragMargin) + "px)";
|
|
7992
9524
|
that.dock_pos = PocketDialog.BOTTOM;
|
|
7993
9525
|
}
|
|
7994
9526
|
});
|
|
@@ -8007,12 +9539,12 @@ class ContextMenu {
|
|
|
8007
9539
|
constructor( event, title, options = {} ) {
|
|
8008
9540
|
|
|
8009
9541
|
// remove all context menus
|
|
8010
|
-
document.body.querySelectorAll(".
|
|
9542
|
+
document.body.querySelectorAll( ".lexcontextmenu" ).forEach( e => e.remove() );
|
|
8011
9543
|
|
|
8012
|
-
this.root = document.createElement(
|
|
8013
|
-
this.root.className = "
|
|
8014
|
-
this.root.style.left = (event.x - 48 + document.scrollingElement.scrollLeft) + "px";
|
|
8015
|
-
this.root.style.top = (event.y - 8 + document.scrollingElement.scrollTop) + "px";
|
|
9544
|
+
this.root = document.createElement( "div" );
|
|
9545
|
+
this.root.className = "lexcontextmenu";
|
|
9546
|
+
this.root.style.left = ( event.x - 48 + document.scrollingElement.scrollLeft ) + "px";
|
|
9547
|
+
this.root.style.top = ( event.y - 8 + document.scrollingElement.scrollTop ) + "px";
|
|
8016
9548
|
|
|
8017
9549
|
this.root.addEventListener("mouseleave", function() {
|
|
8018
9550
|
this.remove();
|
|
@@ -8025,8 +9557,8 @@ class ContextMenu {
|
|
|
8025
9557
|
{
|
|
8026
9558
|
const item = {};
|
|
8027
9559
|
item[ title ] = [];
|
|
8028
|
-
item[
|
|
8029
|
-
item[
|
|
9560
|
+
item[ "className" ] = "cmtitle";
|
|
9561
|
+
item[ "icon" ] = options.icon;
|
|
8030
9562
|
this.items.push( item );
|
|
8031
9563
|
}
|
|
8032
9564
|
}
|
|
@@ -8074,16 +9606,16 @@ class ContextMenu {
|
|
|
8074
9606
|
|
|
8075
9607
|
_create_submenu( o, k, c, d ) {
|
|
8076
9608
|
|
|
8077
|
-
this.root.querySelectorAll(".
|
|
9609
|
+
this.root.querySelectorAll( ".lexcontextmenu" ).forEach( cm => cm.remove() );
|
|
8078
9610
|
|
|
8079
9611
|
let contextmenu = document.createElement('div');
|
|
8080
|
-
contextmenu.className = "
|
|
9612
|
+
contextmenu.className = "lexcontextmenu";
|
|
8081
9613
|
c.appendChild( contextmenu );
|
|
8082
9614
|
|
|
8083
9615
|
for( var i = 0; i < o[k].length; ++i )
|
|
8084
9616
|
{
|
|
8085
|
-
const subitem = o[k][i];
|
|
8086
|
-
const subkey = Object.keys(subitem)[0];
|
|
9617
|
+
const subitem = o[ k ][ i ];
|
|
9618
|
+
const subkey = Object.keys( subitem )[ 0 ];
|
|
8087
9619
|
this._create_entry(subitem, subkey, contextmenu, d);
|
|
8088
9620
|
}
|
|
8089
9621
|
|
|
@@ -8099,22 +9631,25 @@ class ContextMenu {
|
|
|
8099
9631
|
|
|
8100
9632
|
const hasSubmenu = o[ k ].length;
|
|
8101
9633
|
let entry = document.createElement('div');
|
|
8102
|
-
entry.className = "
|
|
9634
|
+
entry.className = "lexmenuboxentry" + (o[ 'className' ] ? " " + o[ 'className' ] : "" );
|
|
8103
9635
|
entry.id = o.id ?? ("eId" + getSupportedDOMName( k ));
|
|
8104
9636
|
entry.innerHTML = "";
|
|
8105
9637
|
const icon = o[ 'icon' ];
|
|
8106
|
-
if(icon)
|
|
9638
|
+
if( icon )
|
|
9639
|
+
{
|
|
8107
9640
|
entry.innerHTML += "<a class='" + icon + " fa-sm'></a>";
|
|
8108
9641
|
}
|
|
8109
9642
|
const disabled = o['disabled'];
|
|
8110
9643
|
entry.innerHTML += "<div class='lexentryname" + (disabled ? " disabled" : "") + "'>" + k + "</div>";
|
|
8111
9644
|
c.appendChild( entry );
|
|
8112
9645
|
|
|
8113
|
-
if( this.colors[ k ] )
|
|
9646
|
+
if( this.colors[ k ] )
|
|
9647
|
+
{
|
|
8114
9648
|
entry.style.borderColor = this.colors[ k ];
|
|
8115
9649
|
}
|
|
8116
9650
|
|
|
8117
|
-
if( k == "" )
|
|
9651
|
+
if( k == "" )
|
|
9652
|
+
{
|
|
8118
9653
|
entry.className += " cmseparator";
|
|
8119
9654
|
return;
|
|
8120
9655
|
}
|
|
@@ -8127,7 +9662,8 @@ class ContextMenu {
|
|
|
8127
9662
|
if(disabled) return;
|
|
8128
9663
|
|
|
8129
9664
|
const f = o[ 'callback' ];
|
|
8130
|
-
if(f)
|
|
9665
|
+
if( f )
|
|
9666
|
+
{
|
|
8131
9667
|
f.call( this, k, entry );
|
|
8132
9668
|
this.root.remove();
|
|
8133
9669
|
}
|
|
@@ -8159,8 +9695,7 @@ class ContextMenu {
|
|
|
8159
9695
|
|
|
8160
9696
|
entry.addEventListener("mouseleave", () => {
|
|
8161
9697
|
d = -1; // Reset depth
|
|
8162
|
-
|
|
8163
|
-
c.querySelectorAll(".lexcontextmenubox").forEach(e => e.remove());
|
|
9698
|
+
c.querySelectorAll(".lexcontextmenu").forEach(e => e.remove());
|
|
8164
9699
|
});
|
|
8165
9700
|
}
|
|
8166
9701
|
|
|
@@ -8193,22 +9728,25 @@ class ContextMenu {
|
|
|
8193
9728
|
if(key) found = o[ key ];
|
|
8194
9729
|
} );
|
|
8195
9730
|
|
|
8196
|
-
if(found)
|
|
9731
|
+
if( found )
|
|
9732
|
+
{
|
|
8197
9733
|
insert( tokens[idx++], found );
|
|
8198
9734
|
}
|
|
8199
|
-
else
|
|
9735
|
+
else
|
|
9736
|
+
{
|
|
8200
9737
|
let item = {};
|
|
8201
9738
|
item[ token ] = [];
|
|
8202
|
-
const
|
|
9739
|
+
const nextToken = tokens[idx++];
|
|
8203
9740
|
// Check if last token -> add callback
|
|
8204
|
-
if(!
|
|
9741
|
+
if( !nextToken )
|
|
9742
|
+
{
|
|
8205
9743
|
item[ 'id' ] = options.id;
|
|
8206
9744
|
item[ 'callback' ] = options.callback;
|
|
8207
9745
|
item[ 'disabled' ] = options.disabled ?? false;
|
|
8208
9746
|
}
|
|
8209
9747
|
|
|
8210
9748
|
list.push( item );
|
|
8211
|
-
insert(
|
|
9749
|
+
insert( nextToken, item[ token ] );
|
|
8212
9750
|
}
|
|
8213
9751
|
};
|
|
8214
9752
|
|
|
@@ -8232,7 +9770,8 @@ class ContextMenu {
|
|
|
8232
9770
|
_item[ key ].unshift( parent );
|
|
8233
9771
|
}
|
|
8234
9772
|
|
|
8235
|
-
for( var child of _item[ key ] )
|
|
9773
|
+
for( var child of _item[ key ] )
|
|
9774
|
+
{
|
|
8236
9775
|
let k = Object.keys(child)[0];
|
|
8237
9776
|
for( var i = 0; i < child[k].length; ++i )
|
|
8238
9777
|
setParent(child);
|
|
@@ -8246,7 +9785,7 @@ class ContextMenu {
|
|
|
8246
9785
|
|
|
8247
9786
|
for( let item of this.items )
|
|
8248
9787
|
{
|
|
8249
|
-
let key = Object.keys(item)[0];
|
|
9788
|
+
let key = Object.keys( item )[ 0 ];
|
|
8250
9789
|
let pKey = "eId" + getSupportedDOMName( key );
|
|
8251
9790
|
|
|
8252
9791
|
// Item already created
|
|
@@ -8363,7 +9902,7 @@ class Curve {
|
|
|
8363
9902
|
|
|
8364
9903
|
var r = [];
|
|
8365
9904
|
var dx = (element.xrange[1] - element.xrange[ 0 ]) / samples;
|
|
8366
|
-
for(var i = element.xrange[0]; i <= element.xrange[1]; i += dx)
|
|
9905
|
+
for( var i = element.xrange[0]; i <= element.xrange[1]; i += dx )
|
|
8367
9906
|
{
|
|
8368
9907
|
r.push( element.getValueAt(i) );
|
|
8369
9908
|
}
|
|
@@ -8372,7 +9911,8 @@ class Curve {
|
|
|
8372
9911
|
|
|
8373
9912
|
element.addValue = function(v) {
|
|
8374
9913
|
|
|
8375
|
-
for(var i = 0; i < element.value; i++)
|
|
9914
|
+
for( var i = 0; i < element.value; i++ )
|
|
9915
|
+
{
|
|
8376
9916
|
var value = element.value[i];
|
|
8377
9917
|
if(value[0] < v[0]) continue;
|
|
8378
9918
|
element.value.splice(i,0,v);
|
|
@@ -8398,7 +9938,7 @@ class Curve {
|
|
|
8398
9938
|
|
|
8399
9939
|
var selected = -1;
|
|
8400
9940
|
|
|
8401
|
-
element.redraw = function( o = {} )
|
|
9941
|
+
element.redraw = function( o = {} ) {
|
|
8402
9942
|
|
|
8403
9943
|
if( o.value ) element.value = o.value;
|
|
8404
9944
|
if( o.xrange ) element.xrange = o.xrange;
|
|
@@ -8427,13 +9967,16 @@ class Curve {
|
|
|
8427
9967
|
ctx.moveTo( pos[ 0 ], pos[ 1 ] );
|
|
8428
9968
|
let values = [pos[ 0 ], pos[ 1 ]];
|
|
8429
9969
|
|
|
8430
|
-
for(var i in element.value)
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
values.push(pos[
|
|
8435
|
-
|
|
9970
|
+
for( var i in element.value )
|
|
9971
|
+
{
|
|
9972
|
+
var value = element.value[ i ];
|
|
9973
|
+
pos = convert( value );
|
|
9974
|
+
values.push( pos[ 0 ] );
|
|
9975
|
+
values.push( pos[ 1 ] );
|
|
9976
|
+
if( !element.smooth )
|
|
9977
|
+
{
|
|
8436
9978
|
ctx.lineTo( pos[ 0 ], pos[ 1 ] );
|
|
9979
|
+
}
|
|
8437
9980
|
}
|
|
8438
9981
|
|
|
8439
9982
|
pos = convert([ element.xrange[ 1 ], element.defaulty ]);
|
|
@@ -8450,7 +9993,8 @@ class Curve {
|
|
|
8450
9993
|
}
|
|
8451
9994
|
|
|
8452
9995
|
// Draw points
|
|
8453
|
-
for( var i = 0; i < element.value.length; i += 1 )
|
|
9996
|
+
for( var i = 0; i < element.value.length; i += 1 )
|
|
9997
|
+
{
|
|
8454
9998
|
var value = element.value[ i ];
|
|
8455
9999
|
pos = convert( value );
|
|
8456
10000
|
if( selected == i )
|
|
@@ -8462,10 +10006,11 @@ class Curve {
|
|
|
8462
10006
|
ctx.fill();
|
|
8463
10007
|
}
|
|
8464
10008
|
|
|
8465
|
-
if(element.show_samples)
|
|
10009
|
+
if( element.show_samples )
|
|
10010
|
+
{
|
|
8466
10011
|
var samples = element.resample(element.show_samples);
|
|
8467
10012
|
ctx.fillStyle = "#888";
|
|
8468
|
-
for(var i = 0; i < samples.length; i += 1)
|
|
10013
|
+
for( var i = 0; i < samples.length; i += 1)
|
|
8469
10014
|
{
|
|
8470
10015
|
var value = [ i * ((element.xrange[ 1 ] - element.xrange[ 0 ]) / element.show_samples) + element.xrange[ 0 ], samples[ i ] ];
|
|
8471
10016
|
pos = convert(value);
|
|
@@ -8488,7 +10033,8 @@ class Curve {
|
|
|
8488
10033
|
|
|
8489
10034
|
selected = computeSelected( mousex, canvas.height - mousey );
|
|
8490
10035
|
|
|
8491
|
-
if( e.button == LX.MOUSE_LEFT_CLICK && selected == -1 && element.allow_add_values )
|
|
10036
|
+
if( e.button == LX.MOUSE_LEFT_CLICK && selected == -1 && element.allow_add_values )
|
|
10037
|
+
{
|
|
8492
10038
|
var v = unconvert([ mousex, canvas.height - mousey ]);
|
|
8493
10039
|
element.value.push( v );
|
|
8494
10040
|
sortValues();
|
|
@@ -8536,7 +10082,8 @@ class Curve {
|
|
|
8536
10082
|
var dy = element.draggable_y ? last_mouse[ 1 ] - mousey : 0;
|
|
8537
10083
|
var delta = unconvert([ -dx, dy ]);
|
|
8538
10084
|
|
|
8539
|
-
if( selected != -1 )
|
|
10085
|
+
if( selected != -1 )
|
|
10086
|
+
{
|
|
8540
10087
|
var minx = element.xrange[ 0 ];
|
|
8541
10088
|
var maxx = element.xrange[ 1 ];
|
|
8542
10089
|
|
|
@@ -8693,7 +10240,7 @@ class Dial {
|
|
|
8693
10240
|
|
|
8694
10241
|
var r = [];
|
|
8695
10242
|
var dx = (element.xrange[1] - element.xrange[ 0 ]) / samples;
|
|
8696
|
-
for(var i = element.xrange[0]; i <= element.xrange[1]; i += dx)
|
|
10243
|
+
for( var i = element.xrange[0]; i <= element.xrange[1]; i += dx)
|
|
8697
10244
|
{
|
|
8698
10245
|
r.push( element.getValueAt(i) );
|
|
8699
10246
|
}
|
|
@@ -8702,15 +10249,16 @@ class Dial {
|
|
|
8702
10249
|
|
|
8703
10250
|
element.addValue = function(v) {
|
|
8704
10251
|
|
|
8705
|
-
for(var i = 0; i < element.value; i++)
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
10252
|
+
for( var i = 0; i < element.value; i++ )
|
|
10253
|
+
{
|
|
10254
|
+
var value = element.value[ i ];
|
|
10255
|
+
if(value[ 0 ] < v[ 0 ]) continue;
|
|
10256
|
+
element.value.splice( i, 0, v );
|
|
8709
10257
|
redraw();
|
|
8710
10258
|
return;
|
|
8711
10259
|
}
|
|
8712
10260
|
|
|
8713
|
-
element.value.push(v);
|
|
10261
|
+
element.value.push( v );
|
|
8714
10262
|
redraw();
|
|
8715
10263
|
}
|
|
8716
10264
|
|
|
@@ -8730,7 +10278,7 @@ class Dial {
|
|
|
8730
10278
|
|
|
8731
10279
|
var selected = -1;
|
|
8732
10280
|
|
|
8733
|
-
element.redraw = function( o = {} )
|
|
10281
|
+
element.redraw = function( o = {} ) {
|
|
8734
10282
|
|
|
8735
10283
|
if( o.value ) element.value = o.value;
|
|
8736
10284
|
if( o.xrange ) element.xrange = o.xrange;
|
|
@@ -8759,17 +10307,17 @@ class Dial {
|
|
|
8759
10307
|
ctx.moveTo( pos[ 0 ], pos[ 1 ] );
|
|
8760
10308
|
let values = [pos[ 0 ], pos[ 1 ]];
|
|
8761
10309
|
|
|
8762
|
-
for(var i in element.value)
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
values.push(pos[
|
|
8767
|
-
|
|
10310
|
+
for( var i in element.value)
|
|
10311
|
+
{
|
|
10312
|
+
var value = element.value[ i ];
|
|
10313
|
+
pos = convert( value );
|
|
10314
|
+
values.push( pos[ 0 ] );
|
|
10315
|
+
values.push( pos[ 1 ] );
|
|
8768
10316
|
}
|
|
8769
10317
|
|
|
8770
10318
|
pos = convert([ element.xrange[ 1 ], element.defaulty ]);
|
|
8771
|
-
values.push(pos[ 0 ]);
|
|
8772
|
-
values.push(pos[ 1 ]);
|
|
10319
|
+
values.push( pos[ 0 ] );
|
|
10320
|
+
values.push( pos[ 1 ] );
|
|
8773
10321
|
|
|
8774
10322
|
// Draw points
|
|
8775
10323
|
const center = [0,0];
|
|
@@ -8779,7 +10327,8 @@ class Dial {
|
|
|
8779
10327
|
ctx.arc( pos[ 0 ], pos[ 1 ], 3, 0, Math.PI * 2);
|
|
8780
10328
|
ctx.fill();
|
|
8781
10329
|
|
|
8782
|
-
for( var i = 0; i < element.value.length; i += 1 )
|
|
10330
|
+
for( var i = 0; i < element.value.length; i += 1 )
|
|
10331
|
+
{
|
|
8783
10332
|
var value = element.value[ i ];
|
|
8784
10333
|
pos = convert( value );
|
|
8785
10334
|
if( selected == i )
|
|
@@ -8791,10 +10340,11 @@ class Dial {
|
|
|
8791
10340
|
ctx.fill();
|
|
8792
10341
|
}
|
|
8793
10342
|
|
|
8794
|
-
if(element.show_samples)
|
|
10343
|
+
if( element.show_samples )
|
|
10344
|
+
{
|
|
8795
10345
|
var samples = element.resample(element.show_samples);
|
|
8796
10346
|
ctx.fillStyle = "#888";
|
|
8797
|
-
for(var i = 0; i < samples.length; i += 1)
|
|
10347
|
+
for( var i = 0; i < samples.length; i += 1)
|
|
8798
10348
|
{
|
|
8799
10349
|
var value = [ i * ((element.xrange[ 1 ] - element.xrange[ 0 ]) / element.show_samples) + element.xrange[ 0 ], samples[ i ] ];
|
|
8800
10350
|
pos = convert(value);
|
|
@@ -8817,7 +10367,8 @@ class Dial {
|
|
|
8817
10367
|
|
|
8818
10368
|
selected = computeSelected( mousex, canvas.height - mousey );
|
|
8819
10369
|
|
|
8820
|
-
if( e.button == LX.MOUSE_LEFT_CLICK && selected == -1 && element.allow_add_values )
|
|
10370
|
+
if( e.button == LX.MOUSE_LEFT_CLICK && selected == -1 && element.allow_add_values )
|
|
10371
|
+
{
|
|
8821
10372
|
var v = unconvert([ mousex, canvas.height - mousey ]);
|
|
8822
10373
|
element.value.push( v );
|
|
8823
10374
|
sortValues();
|
|
@@ -8865,7 +10416,8 @@ class Dial {
|
|
|
8865
10416
|
var dy = element.draggable_y ? last_mouse[ 1 ] - mousey : 0;
|
|
8866
10417
|
var delta = unconvert([ -dx, dy ]);
|
|
8867
10418
|
|
|
8868
|
-
if( selected != -1 )
|
|
10419
|
+
if( selected != -1 )
|
|
10420
|
+
{
|
|
8869
10421
|
var minx = element.xrange[ 0 ];
|
|
8870
10422
|
var maxx = element.xrange[ 1 ];
|
|
8871
10423
|
|
|
@@ -8973,7 +10525,8 @@ class AssetViewEvent {
|
|
|
8973
10525
|
}
|
|
8974
10526
|
|
|
8975
10527
|
string() {
|
|
8976
|
-
switch(this.type)
|
|
10528
|
+
switch(this.type)
|
|
10529
|
+
{
|
|
8977
10530
|
case AssetViewEvent.NONE: return "assetview_event_none";
|
|
8978
10531
|
case AssetViewEvent.ASSET_SELECTED: return "assetview_event_selected";
|
|
8979
10532
|
case AssetViewEvent.ASSET_DELETED: return "assetview_event_deleted";
|
|
@@ -9287,7 +10840,7 @@ class AssetView {
|
|
|
9287
10840
|
}
|
|
9288
10841
|
|
|
9289
10842
|
this.rightPanel.sameLine();
|
|
9290
|
-
this.rightPanel.addDropdown( "Filter", this.allowedTypes, this.allowedTypes[ 0 ], v => this._refreshContent.call(this, null, v), { width: "
|
|
10843
|
+
this.rightPanel.addDropdown( "Filter", this.allowedTypes, this.allowedTypes[ 0 ], v => this._refreshContent.call(this, null, v), { width: "30%", minWidth: "128px" } );
|
|
9291
10844
|
this.rightPanel.addText( null, this.searchValue ?? "", v => this._refreshContent.call(this, v, null), { placeholder: "Search assets.." } );
|
|
9292
10845
|
this.rightPanel.addButton( null, "<a class='fa fa-arrow-up-short-wide'></a>", on_sort.bind(this), { className: "micro", title: "Sort" } );
|
|
9293
10846
|
this.rightPanel.addButton( null, "<a class='fa-solid fa-grip'></a>", on_change_view.bind(this), { className: "micro", title: "View" } );
|
|
@@ -9327,8 +10880,8 @@ class AssetView {
|
|
|
9327
10880
|
icon: "fa-solid fa-arrows-rotate",
|
|
9328
10881
|
callback: domEl => { this._refreshContent(); }
|
|
9329
10882
|
}
|
|
9330
|
-
], { width: "
|
|
9331
|
-
this.rightPanel.addText(null, this.path.join('/'), null, { disabled: true, signal: "@on_folder_change", style: { fontWeight: "bolder", fontSize: "16px", color: "#aaa" } });
|
|
10883
|
+
], { width: "20%", minWidth: "164px", noSelection: true } );
|
|
10884
|
+
this.rightPanel.addText(null, this.path.join('/'), null, { width: "70%", maxWidth: "calc(70% - 64px)", minWidth: "164px", disabled: true, signal: "@on_folder_change", style: { fontWeight: "bolder", fontSize: "16px", color: "#aaa" } });
|
|
9332
10885
|
this.rightPanel.addText(null, "Page " + this.contentPage + " / " + ((((this.currentData.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1), null, {disabled: true, signal: "@on_page_change", width: "fit-content"})
|
|
9333
10886
|
this.rightPanel.endLine();
|
|
9334
10887
|
}
|
|
@@ -9454,8 +11007,8 @@ class AssetView {
|
|
|
9454
11007
|
title.innerText = item.id;
|
|
9455
11008
|
itemEl.appendChild( title );
|
|
9456
11009
|
|
|
9457
|
-
if( !that.skipPreview )
|
|
9458
|
-
|
|
11010
|
+
if( !that.skipPreview )
|
|
11011
|
+
{
|
|
9459
11012
|
let preview = null;
|
|
9460
11013
|
const hasImage = item.src && (['png', 'jpg'].indexOf( getExtension( item.src ) ) > -1 || item.src.includes("data:image/") ); // Support b64 image as src
|
|
9461
11014
|
|
|
@@ -9482,7 +11035,8 @@ class AssetView {
|
|
|
9482
11035
|
var newEmSize = charsPerLine / newLength;
|
|
9483
11036
|
var textBaseSize = 64;
|
|
9484
11037
|
|
|
9485
|
-
if(newEmSize < 1)
|
|
11038
|
+
if( newEmSize < 1 )
|
|
11039
|
+
{
|
|
9486
11040
|
var newFontSize = newEmSize * textBaseSize;
|
|
9487
11041
|
textEl.style.fontSize = newFontSize + "px";
|
|
9488
11042
|
preview.style.paddingTop = "calc(50% - " + (textEl.offsetHeight * 0.5 + 10) + "px)"
|
|
@@ -9711,7 +11265,8 @@ class AssetView {
|
|
|
9711
11265
|
|
|
9712
11266
|
this.currentData.push( item );
|
|
9713
11267
|
|
|
9714
|
-
if(i == (num_files - 1))
|
|
11268
|
+
if( i == (num_files - 1) )
|
|
11269
|
+
{
|
|
9715
11270
|
this._refreshContent();
|
|
9716
11271
|
if( !this.skipBrowser )
|
|
9717
11272
|
this.tree.refresh();
|
|
@@ -9763,7 +11318,7 @@ class AssetView {
|
|
|
9763
11318
|
this.currentData.splice( idx, 1 );
|
|
9764
11319
|
this._refreshContent( this.searchValue, this.filter );
|
|
9765
11320
|
|
|
9766
|
-
if(this.onevent)
|
|
11321
|
+
if( this.onevent)
|
|
9767
11322
|
{
|
|
9768
11323
|
const event = new AssetViewEvent( AssetViewEvent.ASSET_DELETED, item );
|
|
9769
11324
|
this.onevent( event );
|
|
@@ -9839,7 +11394,7 @@ Object.assign(LX, {
|
|
|
9839
11394
|
xhr.onload = function(load)
|
|
9840
11395
|
{
|
|
9841
11396
|
var response = this.response;
|
|
9842
|
-
if(this.status != 200)
|
|
11397
|
+
if( this.status != 200)
|
|
9843
11398
|
{
|
|
9844
11399
|
var err = "Error " + this.status;
|
|
9845
11400
|
if(request.error)
|
|
@@ -9887,7 +11442,7 @@ Object.assign(LX, {
|
|
|
9887
11442
|
var data = new FormData();
|
|
9888
11443
|
if( request.data )
|
|
9889
11444
|
{
|
|
9890
|
-
for(var i in request.data)
|
|
11445
|
+
for( var i in request.data)
|
|
9891
11446
|
data.append(i,request.data[i]);
|
|
9892
11447
|
}
|
|
9893
11448
|
|
|
@@ -9948,7 +11503,7 @@ Object.assign(LX, {
|
|
|
9948
11503
|
var size = total;
|
|
9949
11504
|
var loaded_scripts = [];
|
|
9950
11505
|
|
|
9951
|
-
for(var i in url)
|
|
11506
|
+
for( var i in url)
|
|
9952
11507
|
{
|
|
9953
11508
|
var script = document.createElement('script');
|
|
9954
11509
|
script.num = i;
|
|
@@ -10073,6 +11628,18 @@ Element.prototype.getParentArea = function() {
|
|
|
10073
11628
|
}
|
|
10074
11629
|
}
|
|
10075
11630
|
|
|
11631
|
+
LX.ICONS = {
|
|
11632
|
+
"Sidebar": `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_iconCarrier"> <g id="Complete"> <g id="sidebar-left"> <g> <rect id="Square-2" data-name="Square" x="3" y="3" width="18" height="18" rx="2" ry="2" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></rect> <line x1="9" y1="21" x2="9" y2="3" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></line> </g> </g> </g> </g></svg>`,
|
|
11633
|
+
"More": `<svg fill="#000000" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_iconCarrier"> <g id="Complete"> <g id="F-More"> <path id="Vertical" d="M12,16a2,2,0,1,1-2,2A2,2,0,0,1,12,16ZM10,6a2,2,0,1,0,2-2A2,2,0,0,0,10,6Zm0,6a2,2,0,1,0,2-2A2,2,0,0,0,10,12Z"></path> </g> </g> </g></svg>`,
|
|
11634
|
+
"MoreHorizontal": `<svg fill="#000000" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_iconCarrier"> <g id="Complete"> <g id="F-More"> <path id="Horizontal" d="M8,12a2,2,0,1,1-2-2A2,2,0,0,1,8,12Zm10-2a2,2,0,1,0,2,2A2,2,0,0,0,18,10Zm-6,0a2,2,0,1,0,2,2A2,2,0,0,0,12,10Z"></path> </g> </g> </g></svg>`,
|
|
11635
|
+
"MenuArrows": `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#000000" transform="rotate(90)"><g id="SVGRepo_iconCarrier"> <g id="Complete"> <g id="Code"> <g> <polyline id="Right-2" data-name="Right" points="15.5 7 20.5 12 15.5 17" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></polyline> <polyline id="Left-2" data-name="Left" points="8.5 7 3.5 12 8.5 17" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></polyline> </g> </g> </g> </g></svg>`,
|
|
11636
|
+
"Plus": `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#000000"<g id="SVGRepo_iconCarrier"> <g id="Complete"> <g id="add-2" data-name="add"> <g> <line x1="12" y1="19" x2="12" y2="5" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></line> <line x1="5" y1="12" x2="19" y2="12" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></line> </g> </g> </g> </g></svg>`,
|
|
11637
|
+
"Down": `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#000000"><g id="SVGRepo_iconCarrier"> <title>i</title> <g id="Complete"> <g id="F-Chevron"> <polyline id="Down" points="5 8.5 12 15.5 19 8.5" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></polyline> </g> </g> </g></svg>`,
|
|
11638
|
+
"Up": `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#000000"><g id="SVGRepo_iconCarrier"> <title>i</title> <g id="Complete"> <g id="F-Chevron"> <polyline id="Up" points="5 15.5 12 8.5 19 15.5" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></polyline> </g> </g> </g></svg>`,
|
|
11639
|
+
"Right": `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#000000"><g id="SVGRepo_iconCarrier"> <title>i</title> <g id="Complete"> <g id="F-Chevron"> <polyline id="Right" points="8.5 5 15.5 12 8.5 19" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></polyline> </g> </g> </g></svg>`,
|
|
11640
|
+
"Left": `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#000000"><g id="SVGRepo_iconCarrier"> <title>i</title> <g id="Complete"> <g id="F-Chevron"> <polyline id="Left" points="15.5 5 8.5 12 15.5 19" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></polyline> </g> </g> </g></svg>`,
|
|
11641
|
+
}
|
|
11642
|
+
|
|
10076
11643
|
LX.UTILS = {
|
|
10077
11644
|
getTime() { return new Date().getTime() },
|
|
10078
11645
|
compareThreshold( v, p, n, t ) { return Math.abs(v - p) >= t || Math.abs(v - n) >= t },
|
|
@@ -10112,17 +11679,19 @@ LX.UTILS = {
|
|
|
10112
11679
|
drawSpline( ctx, pts, t ) {
|
|
10113
11680
|
|
|
10114
11681
|
ctx.save();
|
|
10115
|
-
var cp=[]; // array of control points, as x0,y0,x1,y1,...
|
|
10116
|
-
var n=pts.length;
|
|
11682
|
+
var cp = []; // array of control points, as x0,y0,x1,y1,...
|
|
11683
|
+
var n = pts.length;
|
|
10117
11684
|
|
|
10118
11685
|
// Draw an open curve, not connected at the ends
|
|
10119
|
-
for(var i=0;i<n-4;i+=2)
|
|
10120
|
-
|
|
11686
|
+
for( var i = 0; i < (n - 4); i += 2 )
|
|
11687
|
+
{
|
|
11688
|
+
cp = cp.concat(LX.UTILS.getControlPoints(pts[i],pts[i+1],pts[i+2],pts[i+3],pts[i+4],pts[i+5],t));
|
|
10121
11689
|
}
|
|
10122
11690
|
|
|
10123
|
-
for(var i=2;i<pts.length-5;i+=2)
|
|
11691
|
+
for( var i = 2; i < ( pts.length - 5 ); i += 2 )
|
|
11692
|
+
{
|
|
10124
11693
|
ctx.beginPath();
|
|
10125
|
-
ctx.moveTo(pts[i],pts[i+1]);
|
|
11694
|
+
ctx.moveTo(pts[i], pts[i+1]);
|
|
10126
11695
|
ctx.bezierCurveTo(cp[2*i-2],cp[2*i-1],cp[2*i],cp[2*i+1],pts[i+2],pts[i+3]);
|
|
10127
11696
|
ctx.stroke();
|
|
10128
11697
|
ctx.closePath();
|
|
@@ -10130,14 +11699,14 @@ LX.UTILS = {
|
|
|
10130
11699
|
|
|
10131
11700
|
// For open curves the first and last arcs are simple quadratics.
|
|
10132
11701
|
ctx.beginPath();
|
|
10133
|
-
ctx.moveTo(pts[0],pts[1]);
|
|
10134
|
-
ctx.quadraticCurveTo(cp[0],cp[1],pts[2],pts[3]);
|
|
11702
|
+
ctx.moveTo( pts[ 0 ], pts[ 1 ] );
|
|
11703
|
+
ctx.quadraticCurveTo( cp[ 0 ], cp[ 1 ], pts[ 2 ], pts[ 3 ]);
|
|
10135
11704
|
ctx.stroke();
|
|
10136
11705
|
ctx.closePath();
|
|
10137
11706
|
|
|
10138
11707
|
ctx.beginPath();
|
|
10139
|
-
ctx.moveTo(pts[n-2],pts[n-1]);
|
|
10140
|
-
ctx.quadraticCurveTo(cp[2*n-10],cp[2*n-9],pts[n-4],pts[n-3]);
|
|
11708
|
+
ctx.moveTo( pts[ n-2 ], pts[ n-1 ] );
|
|
11709
|
+
ctx.quadraticCurveTo( cp[ 2*n-10 ], cp[ 2*n-9 ], pts[ n-4 ], pts[ n-3 ]);
|
|
10141
11710
|
ctx.stroke();
|
|
10142
11711
|
ctx.closePath();
|
|
10143
11712
|
|