lexgui 0.2.0 → 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/timeline.js +47 -25
- package/build/lexgui.css +938 -328
- package/build/lexgui.js +1608 -459
- package/build/lexgui.min.css +1 -1
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +1608 -459
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +34 -2
- package/demo.js +2 -5
- 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,11 +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: {}, //
|
|
15
|
-
extraCommandbarEntries: [] //
|
|
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
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
LX.MOUSE_LEFT_CLICK = 0;
|
|
@@ -25,6 +26,8 @@ LX.MOUSE_TRIPLE_CLICK = 3;
|
|
|
25
26
|
LX.CURVE_MOVEOUT_CLAMP = 0;
|
|
26
27
|
LX.CURVE_MOVEOUT_DELETE = 1;
|
|
27
28
|
|
|
29
|
+
LX.DRAGGABLE_Z_INDEX = 101;
|
|
30
|
+
|
|
28
31
|
function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
|
|
29
32
|
function round( number, precision ) { return precision == 0 ? Math.floor( number ) : +(( number ).toFixed( precision ?? 2 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' )); }
|
|
30
33
|
function remapRange( oldValue, oldMin, oldMax, newMin, newMax ) { return ((( oldValue - oldMin ) * ( newMax - newMin )) / ( oldMax - oldMin )) + newMin; }
|
|
@@ -84,7 +87,7 @@ LX.doAsync = doAsync;
|
|
|
84
87
|
*/
|
|
85
88
|
function getSupportedDOMName( text )
|
|
86
89
|
{
|
|
87
|
-
return text.replace(/\s/g, '').replaceAll('@', '_').replaceAll('+', '_plus_').replaceAll('.', '');
|
|
90
|
+
return text.replace( /\s/g, '' ).replaceAll('@', '_').replaceAll('+', '_plus_').replaceAll( '.', '' );
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
LX.getSupportedDOMName = getSupportedDOMName;
|
|
@@ -223,7 +226,8 @@ LX.hexToRgb = hexToRgb;
|
|
|
223
226
|
function rgbToHex( rgb )
|
|
224
227
|
{
|
|
225
228
|
let hex = "#";
|
|
226
|
-
for( let c of rgb )
|
|
229
|
+
for( let c of rgb )
|
|
230
|
+
{
|
|
227
231
|
c = Math.floor( c * 255 );
|
|
228
232
|
hex += c.toString( 16 );
|
|
229
233
|
}
|
|
@@ -298,7 +302,7 @@ LX.buildTextPattern = buildTextPattern;
|
|
|
298
302
|
|
|
299
303
|
/**
|
|
300
304
|
* @method makeDraggable
|
|
301
|
-
* @description
|
|
305
|
+
* @description Allows an element to be dragged
|
|
302
306
|
* @param {Element} domEl
|
|
303
307
|
* @param {Object} options
|
|
304
308
|
* autoAdjust (Bool): Sets in a correct position at the beggining
|
|
@@ -323,6 +327,7 @@ function makeDraggable( domEl, options = { } )
|
|
|
323
327
|
top = top ?? e.clientY - offsetY - parentRect.y;
|
|
324
328
|
domEl.style.left = clamp( left, dragMargin + fixedOffset.x, fixedOffset.x + parentRect.width - domEl.offsetWidth - dragMargin ) + 'px';
|
|
325
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
|
|
326
331
|
};
|
|
327
332
|
|
|
328
333
|
// Initial adjustment
|
|
@@ -367,26 +372,45 @@ function makeDraggable( domEl, options = { } )
|
|
|
367
372
|
e.preventDefault();
|
|
368
373
|
e.stopPropagation();
|
|
369
374
|
e.stopImmediatePropagation();
|
|
370
|
-
|
|
375
|
+
|
|
376
|
+
if( !currentTarget )
|
|
377
|
+
{
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
371
381
|
// Remove image when dragging
|
|
372
382
|
var img = new Image();
|
|
373
383
|
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=';
|
|
374
384
|
e.dataTransfer.setDragImage( img, 0, 0 );
|
|
375
385
|
e.dataTransfer.effectAllowed = "move";
|
|
386
|
+
|
|
376
387
|
const rect = e.target.getBoundingClientRect();
|
|
377
388
|
const parentRect = currentTarget.parentElement.getBoundingClientRect();
|
|
378
389
|
const isFixed = ( currentTarget.style.position == "fixed" );
|
|
379
390
|
const fixedOffset = isFixed ? new LX.vec2( parentRect.x, parentRect.y ) : new LX.vec2();
|
|
380
391
|
offsetX = e.clientX - rect.x - fixedOffset.x;
|
|
381
392
|
offsetY = e.clientY - rect.y - fixedOffset.y;
|
|
393
|
+
|
|
382
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
|
+
|
|
383
407
|
if( onDragStart )
|
|
384
408
|
{
|
|
385
409
|
onDragStart( currentTarget, e );
|
|
386
410
|
}
|
|
387
411
|
}, false );
|
|
388
412
|
|
|
389
|
-
document.addEventListener( 'mouseup', () => {
|
|
413
|
+
document.addEventListener( 'mouseup', (e) => {
|
|
390
414
|
if( currentTarget )
|
|
391
415
|
{
|
|
392
416
|
currentTarget = null;
|
|
@@ -397,6 +421,48 @@ function makeDraggable( domEl, options = { } )
|
|
|
397
421
|
|
|
398
422
|
LX.makeDraggable = makeDraggable;
|
|
399
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
|
+
|
|
400
466
|
/**
|
|
401
467
|
* @method makeCodeSnippet
|
|
402
468
|
* @description Create a code snippet in a specific language
|
|
@@ -499,6 +565,23 @@ function makeCodeSnippet( code, size, options = { } )
|
|
|
499
565
|
|
|
500
566
|
LX.makeCodeSnippet = makeCodeSnippet;
|
|
501
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
|
+
|
|
502
585
|
/**
|
|
503
586
|
* @method registerCommandbarEntry
|
|
504
587
|
* @description Adds an extra command bar entry
|
|
@@ -768,12 +851,12 @@ function _createCommandbar( root )
|
|
|
768
851
|
if( LX.has('CodeEditor') )
|
|
769
852
|
{
|
|
770
853
|
const instances = LX.CodeEditor.getInstances();
|
|
771
|
-
if(!instances.length) return;
|
|
854
|
+
if( !instances.length ) return;
|
|
772
855
|
|
|
773
856
|
const languages = instances[ 0 ].languages;
|
|
774
857
|
|
|
775
|
-
for( let l of Object.keys( languages ) )
|
|
776
|
-
|
|
858
|
+
for( let l of Object.keys( languages ) )
|
|
859
|
+
{
|
|
777
860
|
const key = "Language: " + l;
|
|
778
861
|
const icon = instances[ 0 ]._getFileIcon( null, languages[ l ].ext );
|
|
779
862
|
|
|
@@ -781,9 +864,11 @@ function _createCommandbar( root )
|
|
|
781
864
|
"<img src='" + ( "https://raw.githubusercontent.com/jxarco/lexgui.js/master/" + icon ) + "'>";
|
|
782
865
|
|
|
783
866
|
value += key + " <span class='lang-ext'>(" + languages[ l ].ext + ")</span>";
|
|
784
|
-
if( key.toLowerCase().includes( filter ) )
|
|
867
|
+
if( key.toLowerCase().includes( filter ) )
|
|
868
|
+
{
|
|
785
869
|
_addElement( value, () => {
|
|
786
|
-
for( let i of instances )
|
|
870
|
+
for( let i of instances )
|
|
871
|
+
{
|
|
787
872
|
i._changeLanguage( l );
|
|
788
873
|
}
|
|
789
874
|
}, "", {} );
|
|
@@ -856,6 +941,25 @@ function init( options = { } )
|
|
|
856
941
|
this.root = document.body;
|
|
857
942
|
}
|
|
858
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
|
+
|
|
859
963
|
// Disable drag icon
|
|
860
964
|
root.addEventListener( 'dragover', function( e ) {
|
|
861
965
|
e.preventDefault();
|
|
@@ -1006,6 +1110,7 @@ LX.popup = popup;
|
|
|
1006
1110
|
function prompt( text, title, callback, options = {} )
|
|
1007
1111
|
{
|
|
1008
1112
|
options.modal = true;
|
|
1113
|
+
options.className = "prompt";
|
|
1009
1114
|
|
|
1010
1115
|
let value = "";
|
|
1011
1116
|
|
|
@@ -1020,7 +1125,9 @@ function prompt( text, title, callback, options = {} )
|
|
|
1020
1125
|
|
|
1021
1126
|
p.sameLine( 2 );
|
|
1022
1127
|
|
|
1023
|
-
p.addButton(
|
|
1128
|
+
p.addButton(null, "Cancel", () => {if(options.on_cancel) options.on_cancel(); dialog.close();} );
|
|
1129
|
+
|
|
1130
|
+
p.addButton( null, options.accept || "Continue", () => {
|
|
1024
1131
|
if( options.required && value === '' )
|
|
1025
1132
|
{
|
|
1026
1133
|
text += text.includes("You must fill the input text.") ? "": "\nYou must fill the input text.";
|
|
@@ -1034,8 +1141,6 @@ function prompt( text, title, callback, options = {} )
|
|
|
1034
1141
|
}
|
|
1035
1142
|
}, { buttonClass: "primary" });
|
|
1036
1143
|
|
|
1037
|
-
p.addButton(null, "Cancel", () => {if(options.on_cancel) options.on_cancel(); dialog.close();} );
|
|
1038
|
-
|
|
1039
1144
|
}, options );
|
|
1040
1145
|
|
|
1041
1146
|
// Focus text prompt
|
|
@@ -1049,6 +1154,101 @@ function prompt( text, title, callback, options = {} )
|
|
|
1049
1154
|
|
|
1050
1155
|
LX.prompt = prompt;
|
|
1051
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
|
+
|
|
1052
1252
|
/**
|
|
1053
1253
|
* @method badge
|
|
1054
1254
|
* @param {String} text
|
|
@@ -1350,7 +1550,8 @@ class Area {
|
|
|
1350
1550
|
|
|
1351
1551
|
function inner_mousemove( e )
|
|
1352
1552
|
{
|
|
1353
|
-
switch( that.type )
|
|
1553
|
+
switch( that.type )
|
|
1554
|
+
{
|
|
1354
1555
|
case "right":
|
|
1355
1556
|
var dt = ( lastMousePosition[ 0 ] - e.x );
|
|
1356
1557
|
var size = ( that.root.offsetWidth + dt );
|
|
@@ -1545,7 +1746,8 @@ class Area {
|
|
|
1545
1746
|
|
|
1546
1747
|
// Listen resize event on first area
|
|
1547
1748
|
const resizeObserver = new ResizeObserver( entries => {
|
|
1548
|
-
for (const entry of entries)
|
|
1749
|
+
for ( const entry of entries )
|
|
1750
|
+
{
|
|
1549
1751
|
const bb = entry.contentRect;
|
|
1550
1752
|
area2.root.style.height = "calc(100% - " + ( bb.height + 4) + "px )";
|
|
1551
1753
|
}
|
|
@@ -1686,9 +1888,15 @@ class Area {
|
|
|
1686
1888
|
this.root.style.height = height;
|
|
1687
1889
|
}
|
|
1688
1890
|
|
|
1689
|
-
|
|
1891
|
+
if( this.onresize )
|
|
1892
|
+
{
|
|
1893
|
+
this.onresize( this.root.getBoundingClientRect() );
|
|
1894
|
+
}
|
|
1690
1895
|
|
|
1691
|
-
|
|
1896
|
+
doAsync( () => {
|
|
1897
|
+
this.size = [ this.root.clientWidth, this.root.clientHeight ];
|
|
1898
|
+
this.propagateEvent( "onresize" );
|
|
1899
|
+
}, 150 );
|
|
1692
1900
|
}
|
|
1693
1901
|
|
|
1694
1902
|
/**
|
|
@@ -1705,7 +1913,7 @@ class Area {
|
|
|
1705
1913
|
let [area1, area2] = this.sections;
|
|
1706
1914
|
this.splitExtended = true;
|
|
1707
1915
|
|
|
1708
|
-
if(this.type == "vertical")
|
|
1916
|
+
if( this.type == "vertical")
|
|
1709
1917
|
{
|
|
1710
1918
|
this.offset = area2.root.offsetHeight;
|
|
1711
1919
|
area2.root.classList.add("fadeout-vertical");
|
|
@@ -1719,7 +1927,6 @@ class Area {
|
|
|
1719
1927
|
this._moveSplit(-Infinity, true, 8);
|
|
1720
1928
|
}
|
|
1721
1929
|
|
|
1722
|
-
// Async resize in some ms...
|
|
1723
1930
|
doAsync( () => this.propagateEvent('onresize'), 150 );
|
|
1724
1931
|
}
|
|
1725
1932
|
|
|
@@ -1735,7 +1942,7 @@ class Area {
|
|
|
1735
1942
|
this.splitExtended = false;
|
|
1736
1943
|
let [area1, area2] = this.sections;
|
|
1737
1944
|
|
|
1738
|
-
if(this.type == "vertical")
|
|
1945
|
+
if( this.type == "vertical")
|
|
1739
1946
|
{
|
|
1740
1947
|
area2.root.classList.add("fadein-vertical");
|
|
1741
1948
|
this._moveSplit(this.offset);
|
|
@@ -1746,7 +1953,6 @@ class Area {
|
|
|
1746
1953
|
this._moveSplit(this.offset);
|
|
1747
1954
|
}
|
|
1748
1955
|
|
|
1749
|
-
// Async resize in some ms...
|
|
1750
1956
|
doAsync( () => this.propagateEvent('onresize'), 150 );
|
|
1751
1957
|
}
|
|
1752
1958
|
|
|
@@ -1780,11 +1986,15 @@ class Area {
|
|
|
1780
1986
|
|
|
1781
1987
|
propagateEvent( eventName ) {
|
|
1782
1988
|
|
|
1783
|
-
for(var i = 0; i < this.sections.length; i++)
|
|
1989
|
+
for( var i = 0; i < this.sections.length; i++ )
|
|
1784
1990
|
{
|
|
1785
|
-
const area = this.sections[i];
|
|
1786
|
-
|
|
1991
|
+
const area = this.sections[ i ];
|
|
1992
|
+
|
|
1993
|
+
if( area[ eventName ] )
|
|
1994
|
+
{
|
|
1787
1995
|
area[ eventName ].call( this, area.root.getBoundingClientRect() );
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1788
1998
|
area.propagateEvent( eventName );
|
|
1789
1999
|
}
|
|
1790
2000
|
}
|
|
@@ -1807,42 +2017,63 @@ class Area {
|
|
|
1807
2017
|
* @param {Function} callback Function to fill the menubar
|
|
1808
2018
|
* @param {*} options:
|
|
1809
2019
|
* float: Justify content (left, center, right) [left]
|
|
2020
|
+
* sticky: Fix menubar at the top [true]
|
|
1810
2021
|
*/
|
|
1811
2022
|
|
|
1812
2023
|
addMenubar( callback, options = {} ) {
|
|
1813
2024
|
|
|
1814
|
-
let menubar = new Menubar(options);
|
|
2025
|
+
let menubar = new Menubar( options );
|
|
1815
2026
|
|
|
1816
|
-
if(
|
|
2027
|
+
if( callback )
|
|
2028
|
+
{
|
|
2029
|
+
callback( menubar );
|
|
2030
|
+
}
|
|
1817
2031
|
|
|
1818
2032
|
LX.menubars.push( menubar );
|
|
1819
2033
|
|
|
1820
2034
|
const height = 48; // pixels
|
|
2035
|
+
const [ bar, content ] = this.split({ type: 'vertical', sizes: [height, null], resize: false, menubar: true });
|
|
2036
|
+
menubar.siblingArea = content;
|
|
1821
2037
|
|
|
1822
|
-
const [bar, content] = this.split({type: 'vertical', sizes: [height, null], resize: false, menubar: true});
|
|
1823
2038
|
bar.attach( menubar );
|
|
1824
|
-
bar.
|
|
2039
|
+
bar.isMenubar = true;
|
|
2040
|
+
|
|
2041
|
+
if( options.sticky ?? true )
|
|
2042
|
+
{
|
|
2043
|
+
bar.root.classList.add( "sticky" );
|
|
2044
|
+
}
|
|
2045
|
+
|
|
1825
2046
|
return menubar;
|
|
1826
2047
|
}
|
|
1827
2048
|
|
|
1828
2049
|
/**
|
|
1829
2050
|
* @method addSidebar
|
|
1830
2051
|
* @param {Function} callback Function to fill the sidebar
|
|
2052
|
+
* @param {Object} options: Sidebar options
|
|
2053
|
+
* width: Width of the sidebar [16rem]
|
|
1831
2054
|
*/
|
|
1832
2055
|
|
|
1833
2056
|
addSidebar( callback, options = {} ) {
|
|
1834
2057
|
|
|
1835
2058
|
let sidebar = new SideBar( options );
|
|
1836
2059
|
|
|
1837
|
-
if( callback )
|
|
2060
|
+
if( callback )
|
|
2061
|
+
{
|
|
2062
|
+
callback( sidebar );
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// Generate DOM elements after adding all entries
|
|
2066
|
+
sidebar._build();
|
|
1838
2067
|
|
|
1839
2068
|
LX.menubars.push( sidebar );
|
|
1840
2069
|
|
|
1841
|
-
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;
|
|
1842
2073
|
|
|
1843
|
-
const [bar, content] = this.split( { type: 'horizontal', sizes: [ width, null ], resize: false, sidebar: true } );
|
|
1844
2074
|
bar.attach( sidebar );
|
|
1845
|
-
bar.
|
|
2075
|
+
bar.isSidebar = true;
|
|
2076
|
+
|
|
1846
2077
|
return sidebar;
|
|
1847
2078
|
}
|
|
1848
2079
|
|
|
@@ -2098,7 +2329,8 @@ class Area {
|
|
|
2098
2329
|
|
|
2099
2330
|
this.size = [ rect.width, rect.height ];
|
|
2100
2331
|
|
|
2101
|
-
for(var i = 0; i < this.sections.length; i++)
|
|
2332
|
+
for( var i = 0; i < this.sections.length; i++ )
|
|
2333
|
+
{
|
|
2102
2334
|
this.sections[i]._update();
|
|
2103
2335
|
}
|
|
2104
2336
|
}
|
|
@@ -2122,7 +2354,7 @@ class Tabs {
|
|
|
2122
2354
|
static TAB_SIZE = 28;
|
|
2123
2355
|
static TAB_ID = 0;
|
|
2124
2356
|
|
|
2125
|
-
constructor( area, options = {} )
|
|
2357
|
+
constructor( area, options = {} ) {
|
|
2126
2358
|
|
|
2127
2359
|
this.onclose = options.onclose;
|
|
2128
2360
|
|
|
@@ -2204,24 +2436,28 @@ class Tabs {
|
|
|
2204
2436
|
}
|
|
2205
2437
|
|
|
2206
2438
|
// debug
|
|
2207
|
-
if(folding)
|
|
2439
|
+
if( folding )
|
|
2208
2440
|
{
|
|
2209
2441
|
this.folded = true;
|
|
2210
2442
|
this.folding = folding;
|
|
2211
2443
|
|
|
2212
|
-
if(folding == "up"
|
|
2444
|
+
if( folding == "up" )
|
|
2445
|
+
{
|
|
2446
|
+
area.root.insertChildAtIndex(area.sections[1].root, 0);
|
|
2447
|
+
}
|
|
2213
2448
|
|
|
2214
2449
|
// Listen resize event on parent area
|
|
2215
2450
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
2216
|
-
for (const entry of entries)
|
|
2451
|
+
for (const entry of entries)
|
|
2452
|
+
{
|
|
2217
2453
|
const bb = entry.contentRect;
|
|
2218
|
-
const sibling = area.parentArea.sections[0].root;
|
|
2219
|
-
const
|
|
2220
|
-
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 )";
|
|
2221
2457
|
}
|
|
2222
2458
|
});
|
|
2223
2459
|
|
|
2224
|
-
resizeObserver.observe(this.area.root);
|
|
2460
|
+
resizeObserver.observe( this.area.root );
|
|
2225
2461
|
this.area.root.classList.add('folded');
|
|
2226
2462
|
}
|
|
2227
2463
|
}
|
|
@@ -2358,7 +2594,8 @@ class Tabs {
|
|
|
2358
2594
|
|
|
2359
2595
|
setTimeout( () => {
|
|
2360
2596
|
|
|
2361
|
-
if( options.onCreate )
|
|
2597
|
+
if( options.onCreate )
|
|
2598
|
+
{
|
|
2362
2599
|
options.onCreate.call(this, this.area.root.getBoundingClientRect());
|
|
2363
2600
|
}
|
|
2364
2601
|
|
|
@@ -2420,34 +2657,41 @@ LX.Tabs = Tabs;
|
|
|
2420
2657
|
|
|
2421
2658
|
class Menubar {
|
|
2422
2659
|
|
|
2423
|
-
constructor( options = {} )
|
|
2660
|
+
constructor( options = {} ) {
|
|
2424
2661
|
|
|
2425
|
-
this.root = document.createElement(
|
|
2662
|
+
this.root = document.createElement( "div" );
|
|
2426
2663
|
this.root.className = "lexmenubar";
|
|
2427
|
-
|
|
2664
|
+
|
|
2665
|
+
if( options.float )
|
|
2666
|
+
{
|
|
2428
2667
|
this.root.style.justifyContent = options.float;
|
|
2429
|
-
|
|
2668
|
+
}
|
|
2430
2669
|
|
|
2431
|
-
this.
|
|
2432
|
-
this.
|
|
2433
|
-
this.
|
|
2670
|
+
this.items = [ ];
|
|
2671
|
+
this.buttons = [ ];
|
|
2672
|
+
this.icons = { };
|
|
2673
|
+
this.shorts = { };
|
|
2434
2674
|
}
|
|
2435
2675
|
|
|
2436
2676
|
/**
|
|
2437
2677
|
* @method add
|
|
2438
|
-
* @param {
|
|
2678
|
+
* @param {Object} options:
|
|
2439
2679
|
* callback: Function to call on each item
|
|
2680
|
+
* icon: Entry icon
|
|
2681
|
+
* short: Entry shortcut name
|
|
2440
2682
|
*/
|
|
2441
2683
|
|
|
2442
2684
|
add( path, options = {} ) {
|
|
2443
2685
|
|
|
2444
|
-
if(options.constructor == Function)
|
|
2686
|
+
if( options.constructor == Function )
|
|
2687
|
+
{
|
|
2445
2688
|
options = { callback: options };
|
|
2689
|
+
}
|
|
2446
2690
|
|
|
2447
|
-
//
|
|
2448
|
-
const tokens = path.split("/");
|
|
2691
|
+
// Process path
|
|
2692
|
+
const tokens = path.split( "/" );
|
|
2449
2693
|
|
|
2450
|
-
//
|
|
2694
|
+
// Assign icons and shortcuts to last token in path
|
|
2451
2695
|
const lastPath = tokens[tokens.length - 1];
|
|
2452
2696
|
this.icons[ lastPath ] = options.icon;
|
|
2453
2697
|
this.shorts[ lastPath ] = options.short;
|
|
@@ -2455,105 +2699,146 @@ class Menubar {
|
|
|
2455
2699
|
let idx = 0;
|
|
2456
2700
|
let that = this;
|
|
2457
2701
|
|
|
2458
|
-
const
|
|
2459
|
-
if(token == undefined)
|
|
2702
|
+
const _insertEntry = ( token, list ) => {
|
|
2703
|
+
if( token == undefined )
|
|
2704
|
+
{
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2460
2707
|
|
|
2461
2708
|
let found = null;
|
|
2462
2709
|
list.forEach( o => {
|
|
2463
|
-
const keys = Object.keys(o);
|
|
2710
|
+
const keys = Object.keys( o );
|
|
2464
2711
|
const key = keys.find( t => t == token );
|
|
2465
|
-
if(key) found = o[ key ];
|
|
2712
|
+
if( key ) found = o[ key ];
|
|
2466
2713
|
} );
|
|
2467
2714
|
|
|
2468
|
-
if(found)
|
|
2469
|
-
|
|
2715
|
+
if( found )
|
|
2716
|
+
{
|
|
2717
|
+
_insertEntry( tokens[ idx++ ], found );
|
|
2470
2718
|
}
|
|
2471
|
-
else
|
|
2719
|
+
else
|
|
2720
|
+
{
|
|
2472
2721
|
let item = {};
|
|
2473
2722
|
item[ token ] = [];
|
|
2474
|
-
const
|
|
2723
|
+
const nextToken = tokens[ idx++ ];
|
|
2475
2724
|
// Check if last token -> add callback
|
|
2476
|
-
if(!
|
|
2725
|
+
if( !nextToken )
|
|
2726
|
+
{
|
|
2477
2727
|
item[ 'callback' ] = options.callback;
|
|
2728
|
+
item[ 'disabled' ] = options.disabled;
|
|
2478
2729
|
item[ 'type' ] = options.type;
|
|
2479
2730
|
item[ 'checked' ] = options.checked;
|
|
2480
2731
|
}
|
|
2481
2732
|
list.push( item );
|
|
2482
|
-
|
|
2733
|
+
_insertEntry( nextToken, item[ token ] );
|
|
2483
2734
|
}
|
|
2484
2735
|
};
|
|
2485
2736
|
|
|
2486
|
-
|
|
2737
|
+
_insertEntry( tokens[idx++], this.items );
|
|
2487
2738
|
|
|
2488
2739
|
// Create elements
|
|
2489
2740
|
|
|
2490
2741
|
for( let item of this.items )
|
|
2491
2742
|
{
|
|
2492
|
-
let key = Object.keys(item)[0];
|
|
2493
|
-
let pKey = key.replace(/\s/g, '').replaceAll('.', '');
|
|
2743
|
+
let key = Object.keys( item )[ 0 ];
|
|
2744
|
+
let pKey = key.replace( /\s/g, '' ).replaceAll( '.', '' );
|
|
2494
2745
|
|
|
2495
2746
|
// Item already created
|
|
2496
|
-
if( this.root.querySelector("#" + pKey) )
|
|
2747
|
+
if( this.root.querySelector( "#" + pKey ) )
|
|
2748
|
+
{
|
|
2497
2749
|
continue;
|
|
2750
|
+
}
|
|
2498
2751
|
|
|
2499
2752
|
let entry = document.createElement('div');
|
|
2500
2753
|
entry.className = "lexmenuentry";
|
|
2501
2754
|
entry.id = pKey;
|
|
2502
2755
|
entry.innerHTML = "<span>" + key + "</span>";
|
|
2503
|
-
|
|
2756
|
+
entry.tabIndex = "1";
|
|
2757
|
+
|
|
2758
|
+
if( options.position == "left" )
|
|
2759
|
+
{
|
|
2504
2760
|
this.root.prepend( entry );
|
|
2505
2761
|
}
|
|
2506
|
-
else
|
|
2507
|
-
|
|
2762
|
+
else
|
|
2763
|
+
{
|
|
2764
|
+
if( options.position == "right" )
|
|
2765
|
+
{
|
|
2508
2766
|
entry.right = true;
|
|
2509
|
-
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
if( this.root.lastChild && this.root.lastChild.right )
|
|
2770
|
+
{
|
|
2510
2771
|
this.root.lastChild.before( entry );
|
|
2511
2772
|
}
|
|
2512
|
-
else
|
|
2773
|
+
else
|
|
2774
|
+
{
|
|
2513
2775
|
this.root.appendChild( entry );
|
|
2514
2776
|
}
|
|
2515
2777
|
}
|
|
2516
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
|
+
|
|
2517
2791
|
const create_submenu = function( o, k, c, d ) {
|
|
2518
2792
|
|
|
2519
|
-
let
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
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;
|
|
2523
2799
|
var rect = c.getBoundingClientRect();
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
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();
|
|
2528
2803
|
|
|
2529
|
-
|
|
2804
|
+
doAsync( () => {
|
|
2805
|
+
menuElement.dataset[ "open" ] = true;
|
|
2806
|
+
}, 10 );
|
|
2530
2807
|
|
|
2531
|
-
|
|
2808
|
+
LX.root.appendChild( menuElement );
|
|
2532
2809
|
|
|
2533
|
-
for( var i = 0; i < o[k].length; ++i )
|
|
2810
|
+
for( var i = 0; i < o[ k ].length; ++i )
|
|
2534
2811
|
{
|
|
2535
|
-
const subitem = o[k][i];
|
|
2536
|
-
const subkey = Object.keys(subitem)[0];
|
|
2812
|
+
const subitem = o[ k ][ i ];
|
|
2813
|
+
const subkey = Object.keys( subitem )[ 0 ];
|
|
2537
2814
|
const hasSubmenu = subitem[ subkey ].length;
|
|
2538
2815
|
const isCheckbox = subitem[ 'type' ] == 'checkbox';
|
|
2539
2816
|
let subentry = document.createElement('div');
|
|
2540
|
-
subentry.className = "
|
|
2541
|
-
subentry.className += (i == o[k].length - 1 ? " last" : "");
|
|
2542
|
-
if(subkey == '')
|
|
2543
|
-
subentry.className = " lexseparator";
|
|
2544
|
-
else {
|
|
2817
|
+
subentry.className = "lexmenuboxentry";
|
|
2818
|
+
subentry.className += (i == o[k].length - 1 ? " last" : "") + ( subitem.disabled ? " disabled" : "" );
|
|
2545
2819
|
|
|
2820
|
+
if( subkey == '' )
|
|
2821
|
+
{
|
|
2822
|
+
subentry.className = " lexseparator";
|
|
2823
|
+
}
|
|
2824
|
+
else
|
|
2825
|
+
{
|
|
2546
2826
|
subentry.id = subkey;
|
|
2547
2827
|
let subentrycont = document.createElement('div');
|
|
2548
2828
|
subentrycont.innerHTML = "";
|
|
2549
|
-
subentrycont.classList = "
|
|
2829
|
+
subentrycont.classList = "lexmenuboxentrycontainer";
|
|
2550
2830
|
subentry.appendChild(subentrycont);
|
|
2551
2831
|
const icon = that.icons[ subkey ];
|
|
2552
|
-
if(isCheckbox)
|
|
2832
|
+
if( isCheckbox )
|
|
2833
|
+
{
|
|
2553
2834
|
subentrycont.innerHTML += "<input type='checkbox' >";
|
|
2554
|
-
}
|
|
2835
|
+
}
|
|
2836
|
+
else if( icon )
|
|
2837
|
+
{
|
|
2555
2838
|
subentrycont.innerHTML += "<a class='" + icon + " fa-sm'></a>";
|
|
2556
|
-
}
|
|
2839
|
+
}
|
|
2840
|
+
else
|
|
2841
|
+
{
|
|
2557
2842
|
subentrycont.innerHTML += "<a class='fa-solid fa-sm noicon'></a>";
|
|
2558
2843
|
subentrycont.classList.add( "noicon" );
|
|
2559
2844
|
|
|
@@ -2561,46 +2846,54 @@ class Menubar {
|
|
|
2561
2846
|
subentrycont.innerHTML += "<div class='lexentryname'>" + subkey + "</div>";
|
|
2562
2847
|
}
|
|
2563
2848
|
|
|
2564
|
-
let
|
|
2565
|
-
if(
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
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;
|
|
2569
2855
|
const f = subitem[ 'callback' ];
|
|
2570
|
-
if(f)
|
|
2856
|
+
if( f )
|
|
2857
|
+
{
|
|
2571
2858
|
f.call( this, subitem.checked, subkey, subentry );
|
|
2572
|
-
|
|
2859
|
+
_resetMenubar();
|
|
2573
2860
|
}
|
|
2574
2861
|
e.stopPropagation();
|
|
2575
2862
|
e.stopImmediatePropagation();
|
|
2576
2863
|
})
|
|
2577
2864
|
}
|
|
2578
2865
|
|
|
2579
|
-
|
|
2866
|
+
menuElement.appendChild( subentry );
|
|
2580
2867
|
|
|
2581
2868
|
// Nothing more for separators
|
|
2582
|
-
if(subkey == '')
|
|
2869
|
+
if( subkey == '' )
|
|
2870
|
+
{
|
|
2871
|
+
continue;
|
|
2872
|
+
}
|
|
2583
2873
|
|
|
2584
|
-
|
|
2874
|
+
menuElement.addEventListener('keydown', function(e) {
|
|
2585
2875
|
e.preventDefault();
|
|
2586
2876
|
let short = that.shorts[ subkey ];
|
|
2587
2877
|
if(!short) return;
|
|
2588
2878
|
// check if it's a letter or other key
|
|
2589
2879
|
short = short.length == 1 ? short.toLowerCase() : short;
|
|
2590
|
-
if(short == e.key)
|
|
2880
|
+
if( short == e.key )
|
|
2881
|
+
{
|
|
2591
2882
|
subentry.click()
|
|
2592
2883
|
}
|
|
2593
2884
|
});
|
|
2594
2885
|
|
|
2595
2886
|
// Add callback
|
|
2596
2887
|
subentry.addEventListener("click", e => {
|
|
2597
|
-
if(
|
|
2888
|
+
if( checkboxInput )
|
|
2889
|
+
{
|
|
2598
2890
|
subitem.checked = !subitem.checked;
|
|
2599
2891
|
}
|
|
2600
2892
|
const f = subitem[ 'callback' ];
|
|
2601
|
-
if(f)
|
|
2602
|
-
|
|
2603
|
-
|
|
2893
|
+
if( f )
|
|
2894
|
+
{
|
|
2895
|
+
f.call( this, checkboxInput ? subitem.checked : subkey, checkboxInput ? subkey : subentry );
|
|
2896
|
+
_resetMenubar();
|
|
2604
2897
|
}
|
|
2605
2898
|
e.stopPropagation();
|
|
2606
2899
|
e.stopImmediatePropagation();
|
|
@@ -2609,7 +2902,8 @@ class Menubar {
|
|
|
2609
2902
|
// Add icon if has submenu, else check for shortcut
|
|
2610
2903
|
if( !hasSubmenu)
|
|
2611
2904
|
{
|
|
2612
|
-
if(that.shorts[ subkey ])
|
|
2905
|
+
if( that.shorts[ subkey ] )
|
|
2906
|
+
{
|
|
2613
2907
|
let shortEl = document.createElement('div');
|
|
2614
2908
|
shortEl.className = "lexentryshort";
|
|
2615
2909
|
shortEl.innerText = that.shorts[ subkey ];
|
|
@@ -2623,43 +2917,66 @@ class Menubar {
|
|
|
2623
2917
|
subentry.appendChild( submenuIcon );
|
|
2624
2918
|
|
|
2625
2919
|
subentry.addEventListener("mouseover", e => {
|
|
2626
|
-
if(subentry.built)
|
|
2627
|
-
|
|
2920
|
+
if( subentry.built )
|
|
2921
|
+
{
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2628
2924
|
subentry.built = true;
|
|
2629
2925
|
create_submenu( subitem, subkey, subentry, ++d );
|
|
2630
2926
|
e.stopPropagation();
|
|
2631
2927
|
});
|
|
2632
2928
|
|
|
2633
|
-
subentry.addEventListener("mouseleave", () => {
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
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
|
+
}
|
|
2637
2937
|
});
|
|
2638
2938
|
}
|
|
2639
2939
|
|
|
2640
2940
|
// Set final width
|
|
2641
|
-
|
|
2941
|
+
menuElement.style.width = menuElement.offsetWidth + "px";
|
|
2642
2942
|
};
|
|
2643
2943
|
|
|
2644
|
-
|
|
2944
|
+
const _showEntry = () => {
|
|
2945
|
+
_resetMenubar();
|
|
2946
|
+
entry.classList.add( "selected" );
|
|
2947
|
+
entry.built = true;
|
|
2948
|
+
create_submenu( item, key, entry, -1 );
|
|
2949
|
+
};
|
|
2645
2950
|
|
|
2951
|
+
entry.addEventListener("click", () => {
|
|
2646
2952
|
const f = item[ 'callback' ];
|
|
2647
|
-
if(f)
|
|
2953
|
+
if( f )
|
|
2954
|
+
{
|
|
2648
2955
|
f.call( this, key, entry );
|
|
2649
2956
|
return;
|
|
2650
2957
|
}
|
|
2651
2958
|
|
|
2652
|
-
|
|
2653
|
-
this.root.querySelectorAll(".lexmenuentry").forEach( e => e.classList.remove( 'selected' ) );
|
|
2654
|
-
entry.classList.add( "selected" );
|
|
2959
|
+
_showEntry();
|
|
2655
2960
|
|
|
2656
|
-
this.
|
|
2657
|
-
|
|
2961
|
+
this.focused = true;
|
|
2962
|
+
});
|
|
2963
|
+
|
|
2964
|
+
entry.addEventListener( "mouseover", (e) => {
|
|
2965
|
+
|
|
2966
|
+
if( this.focused && !entry.built )
|
|
2967
|
+
{
|
|
2968
|
+
_showEntry();
|
|
2969
|
+
}
|
|
2658
2970
|
});
|
|
2659
2971
|
|
|
2660
|
-
entry.addEventListener("
|
|
2661
|
-
|
|
2662
|
-
|
|
2972
|
+
entry.addEventListener("blur", (e) => {
|
|
2973
|
+
|
|
2974
|
+
if( e.relatedTarget && e.relatedTarget.classList.contains( "lexmenubox" ) )
|
|
2975
|
+
{
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2979
|
+
_resetMenubar();
|
|
2663
2980
|
});
|
|
2664
2981
|
}
|
|
2665
2982
|
}
|
|
@@ -2678,20 +2995,24 @@ class Menubar {
|
|
|
2678
2995
|
* @param {Object} item: parent item
|
|
2679
2996
|
* @param {Array} tokens: split path strings
|
|
2680
2997
|
*/
|
|
2681
|
-
getSubitem(item, tokens) {
|
|
2998
|
+
getSubitem( item, tokens ) {
|
|
2682
2999
|
|
|
2683
3000
|
let subitem = null;
|
|
2684
|
-
let path = tokens[0];
|
|
2685
|
-
for(let i = 0; i < item.length; i++) {
|
|
2686
|
-
if(item[i][path]) {
|
|
3001
|
+
let path = tokens[ 0 ];
|
|
2687
3002
|
|
|
2688
|
-
|
|
2689
|
-
|
|
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 ];
|
|
2690
3010
|
return subitem;
|
|
2691
3011
|
}
|
|
2692
|
-
else
|
|
2693
|
-
|
|
2694
|
-
|
|
3012
|
+
else
|
|
3013
|
+
{
|
|
3014
|
+
tokens.splice( 0, 1 );
|
|
3015
|
+
return this.getSubitem( item[ i ][ path ], tokens );
|
|
2695
3016
|
}
|
|
2696
3017
|
|
|
2697
3018
|
}
|
|
@@ -2718,11 +3039,12 @@ class Menubar {
|
|
|
2718
3039
|
setButtonIcon( title, icon, callback, options = {} ) {
|
|
2719
3040
|
|
|
2720
3041
|
const button = this.buttons[ title ];
|
|
2721
|
-
if(button)
|
|
2722
|
-
|
|
3042
|
+
if( button )
|
|
3043
|
+
{
|
|
2723
3044
|
button.querySelector('a').className = "fa-solid" + " " + icon + " lexicon";
|
|
2724
3045
|
}
|
|
2725
|
-
else
|
|
3046
|
+
else
|
|
3047
|
+
{
|
|
2726
3048
|
let button = document.createElement('div');
|
|
2727
3049
|
const disabled = options.disabled ?? false;
|
|
2728
3050
|
button.className = "lexmenubutton" + (disabled ? " disabled" : "");
|
|
@@ -2732,15 +3054,21 @@ class Menubar {
|
|
|
2732
3054
|
button.style.maxHeight = "calc(100% - 10px)";
|
|
2733
3055
|
button.style.alignItems = "center";
|
|
2734
3056
|
|
|
2735
|
-
if(options.float == "right")
|
|
3057
|
+
if( options.float == "right" )
|
|
3058
|
+
{
|
|
2736
3059
|
button.right = true;
|
|
2737
|
-
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
if( this.root.lastChild && this.root.lastChild.right )
|
|
3063
|
+
{
|
|
2738
3064
|
this.root.lastChild.before( button );
|
|
2739
3065
|
}
|
|
2740
|
-
else if(options.float == "left")
|
|
2741
|
-
|
|
3066
|
+
else if( options.float == "left" )
|
|
3067
|
+
{
|
|
3068
|
+
this.root.prepend( button );
|
|
2742
3069
|
}
|
|
2743
|
-
else
|
|
3070
|
+
else
|
|
3071
|
+
{
|
|
2744
3072
|
this.root.appendChild( button );
|
|
2745
3073
|
}
|
|
2746
3074
|
|
|
@@ -2760,11 +3088,12 @@ class Menubar {
|
|
|
2760
3088
|
|
|
2761
3089
|
setButtonImage( title, src, callback, options = {} ) {
|
|
2762
3090
|
const button = this.buttons[ title ];
|
|
2763
|
-
if(button)
|
|
2764
|
-
|
|
3091
|
+
if( button )
|
|
3092
|
+
{
|
|
2765
3093
|
button.querySelector('a').className = "fa-solid" + " " + icon + " lexicon";
|
|
2766
3094
|
}
|
|
2767
|
-
else
|
|
3095
|
+
else
|
|
3096
|
+
{
|
|
2768
3097
|
let button = document.createElement('div');
|
|
2769
3098
|
const disabled = options.disabled ?? false;
|
|
2770
3099
|
button.className = "lexmenubutton" + (disabled ? " disabled" : "");
|
|
@@ -2773,15 +3102,21 @@ class Menubar {
|
|
|
2773
3102
|
button.style.padding = "5px";
|
|
2774
3103
|
button.style.alignItems = "center";
|
|
2775
3104
|
|
|
2776
|
-
if(options.float == "right")
|
|
3105
|
+
if( options.float == "right" )
|
|
3106
|
+
{
|
|
2777
3107
|
button.right = true;
|
|
2778
|
-
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
if( this.root.lastChild && this.root.lastChild.right )
|
|
3111
|
+
{
|
|
2779
3112
|
this.root.lastChild.before( button );
|
|
2780
3113
|
}
|
|
2781
|
-
else if(options.float == "left")
|
|
2782
|
-
|
|
3114
|
+
else if( options.float == "left" )
|
|
3115
|
+
{
|
|
3116
|
+
this.root.prepend( button );
|
|
2783
3117
|
}
|
|
2784
|
-
else
|
|
3118
|
+
else
|
|
3119
|
+
{
|
|
2785
3120
|
this.root.appendChild( button );
|
|
2786
3121
|
}
|
|
2787
3122
|
|
|
@@ -2894,90 +3229,306 @@ LX.Menubar = Menubar;
|
|
|
2894
3229
|
|
|
2895
3230
|
class SideBar {
|
|
2896
3231
|
|
|
2897
|
-
|
|
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 = {} ) {
|
|
2898
3253
|
|
|
2899
3254
|
this.root = document.createElement( 'div' );
|
|
2900
3255
|
this.root.className = "lexsidebar";
|
|
2901
3256
|
|
|
2902
|
-
|
|
2903
|
-
this.footer.className = "lexsidebarfooter";
|
|
2904
|
-
this.root.appendChild( this.footer );
|
|
3257
|
+
window.sidebar = this;
|
|
2905
3258
|
|
|
2906
|
-
this.
|
|
2907
|
-
|
|
3259
|
+
this.collapsable = options.collapsable ?? true;
|
|
3260
|
+
this.collapseWidth = ( options.collapseToIcons ?? true ) ? "58px" : "0px";
|
|
3261
|
+
this.collapsed = false;
|
|
2908
3262
|
|
|
2909
|
-
|
|
2910
|
-
* @method add
|
|
2911
|
-
* @param {*} options:
|
|
2912
|
-
* callback: Function to call on each item
|
|
2913
|
-
* bottom: Bool to set item at the bottom as helper button (not selectable)
|
|
2914
|
-
* className: Add class to the entry DOM element
|
|
2915
|
-
*/
|
|
3263
|
+
doAsync( () => {
|
|
2916
3264
|
|
|
2917
|
-
|
|
3265
|
+
this.root.parentElement.ogWidth = this.root.parentElement.style.width;
|
|
3266
|
+
this.root.parentElement.style.transition = "width 0.25s ease-out";
|
|
2918
3267
|
|
|
2919
|
-
|
|
2920
|
-
|
|
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
|
+
} );
|
|
2921
3365
|
|
|
2922
|
-
|
|
3366
|
+
const avatar = document.createElement( 'span' );
|
|
3367
|
+
avatar.className = "lexavatar";
|
|
3368
|
+
this.footer.appendChild( avatar );
|
|
2923
3369
|
|
|
2924
|
-
|
|
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)`;
|
|
3404
|
+
|
|
3405
|
+
this.items = [ ];
|
|
3406
|
+
this.icons = { };
|
|
3407
|
+
this.groups = { };
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
/**
|
|
3411
|
+
* @method toggleCollapsed
|
|
3412
|
+
*/
|
|
3413
|
+
|
|
3414
|
+
toggleCollapsed() {
|
|
3415
|
+
|
|
3416
|
+
if( !this.collapsable )
|
|
2925
3417
|
{
|
|
2926
|
-
console.warn( `'${key}' already created in Sidebar` );
|
|
2927
3418
|
return;
|
|
2928
3419
|
}
|
|
2929
3420
|
|
|
2930
|
-
|
|
2931
|
-
entry.className = "lexsidebarentry " + ( options.className ?? "" );
|
|
2932
|
-
entry.id = pKey;
|
|
3421
|
+
this.collapsed = !this.collapsed;
|
|
2933
3422
|
|
|
2934
|
-
if(
|
|
3423
|
+
if( this.collapsed )
|
|
2935
3424
|
{
|
|
2936
|
-
this.
|
|
3425
|
+
this.root.classList.add( "collapsing" );
|
|
3426
|
+
this.root.parentElement.style.width = this.collapseWidth;
|
|
2937
3427
|
}
|
|
2938
3428
|
else
|
|
2939
3429
|
{
|
|
2940
|
-
this.root.
|
|
3430
|
+
this.root.classList.remove( "collapsing" );
|
|
3431
|
+
this.root.classList.remove( "collapsed" );
|
|
3432
|
+
this.root.parentElement.style.width = this.root.parentElement.ogWidth;
|
|
2941
3433
|
}
|
|
2942
3434
|
|
|
2943
|
-
|
|
2944
|
-
this.root.appendChild( this.footer );
|
|
3435
|
+
this.resizeObserver.observe( this.root.parentElement );
|
|
2945
3436
|
|
|
2946
|
-
|
|
2947
|
-
button.innerHTML = "<i class='"+ (options.icon ?? "") + "'></i>";
|
|
2948
|
-
entry.appendChild( button );
|
|
3437
|
+
doAsync( () => {
|
|
2949
3438
|
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
desc.innerHTML = key;
|
|
2953
|
-
entry.appendChild( desc );
|
|
3439
|
+
this.root.classList.toggle( "collapsed", this.collapsed );
|
|
3440
|
+
this.resizeObserver.unobserve( this.root.parentElement );
|
|
2954
3441
|
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
desc.style.display = "unset";
|
|
2958
|
-
}, 100 );
|
|
2959
|
-
});
|
|
3442
|
+
}, 250 );
|
|
3443
|
+
}
|
|
2960
3444
|
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3445
|
+
/**
|
|
3446
|
+
* @method separator
|
|
3447
|
+
*/
|
|
3448
|
+
|
|
3449
|
+
separator() {
|
|
3450
|
+
|
|
3451
|
+
this.currentGroup = null;
|
|
3452
|
+
|
|
3453
|
+
this.add( "" );
|
|
3454
|
+
}
|
|
2966
3455
|
|
|
2967
|
-
|
|
3456
|
+
/**
|
|
3457
|
+
* @method group
|
|
3458
|
+
* @param {String} groupName
|
|
3459
|
+
* @param {Object} action: { icon, callback }
|
|
3460
|
+
*/
|
|
3461
|
+
|
|
3462
|
+
group( groupName, action ) {
|
|
2968
3463
|
|
|
2969
|
-
|
|
2970
|
-
|
|
3464
|
+
this.currentGroup = groupName;
|
|
3465
|
+
|
|
3466
|
+
this.groups[ groupName ] = action;
|
|
3467
|
+
}
|
|
2971
3468
|
|
|
2972
|
-
|
|
2973
|
-
|
|
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;
|
|
3492
|
+
|
|
3493
|
+
|
|
3494
|
+
let idx = 0;
|
|
3495
|
+
|
|
3496
|
+
const _insertEntry = ( token, list ) => {
|
|
3497
|
+
|
|
3498
|
+
if( token == undefined )
|
|
2974
3499
|
{
|
|
2975
|
-
|
|
2976
|
-
entry.classList.add( "selected" );
|
|
3500
|
+
return;
|
|
2977
3501
|
}
|
|
2978
|
-
});
|
|
2979
3502
|
|
|
2980
|
-
|
|
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 );
|
|
2981
3532
|
}
|
|
2982
3533
|
|
|
2983
3534
|
/**
|
|
@@ -2996,6 +3547,246 @@ class SideBar {
|
|
|
2996
3547
|
|
|
2997
3548
|
entry.domEl.click();
|
|
2998
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
|
+
}
|
|
2999
3790
|
};
|
|
3000
3791
|
|
|
3001
3792
|
LX.SideBar = SideBar;
|
|
@@ -3013,30 +3804,32 @@ class Widget {
|
|
|
3013
3804
|
static DROPDOWN = 4;
|
|
3014
3805
|
static CHECKBOX = 5;
|
|
3015
3806
|
static TOGGLE = 6;
|
|
3016
|
-
static
|
|
3017
|
-
static
|
|
3018
|
-
static
|
|
3019
|
-
static
|
|
3020
|
-
static
|
|
3021
|
-
static
|
|
3022
|
-
static
|
|
3023
|
-
static
|
|
3024
|
-
static
|
|
3025
|
-
static
|
|
3026
|
-
static
|
|
3027
|
-
static
|
|
3028
|
-
static
|
|
3029
|
-
static
|
|
3030
|
-
static
|
|
3031
|
-
static
|
|
3032
|
-
static
|
|
3033
|
-
static
|
|
3034
|
-
static
|
|
3035
|
-
static
|
|
3036
|
-
static
|
|
3037
|
-
static
|
|
3038
|
-
static
|
|
3039
|
-
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;
|
|
3040
3833
|
|
|
3041
3834
|
static NO_CONTEXT_TYPES = [
|
|
3042
3835
|
Widget.BUTTON,
|
|
@@ -3064,7 +3857,9 @@ class Widget {
|
|
|
3064
3857
|
set( value, skipCallback = false, signalName = "" ) {
|
|
3065
3858
|
|
|
3066
3859
|
if( this.onSetValue )
|
|
3860
|
+
{
|
|
3067
3861
|
return this.onSetValue( value, skipCallback );
|
|
3862
|
+
}
|
|
3068
3863
|
|
|
3069
3864
|
console.warn("Can't set value of " + this.typeName());
|
|
3070
3865
|
}
|
|
@@ -3103,14 +3898,17 @@ class Widget {
|
|
|
3103
3898
|
|
|
3104
3899
|
typeName() {
|
|
3105
3900
|
|
|
3106
|
-
switch( this.type )
|
|
3901
|
+
switch( this.type )
|
|
3902
|
+
{
|
|
3107
3903
|
case Widget.TEXT: return "Text";
|
|
3108
3904
|
case Widget.TEXTAREA: return "TextArea";
|
|
3109
3905
|
case Widget.BUTTON: return "Button";
|
|
3110
3906
|
case Widget.DROPDOWN: return "Dropdown";
|
|
3111
3907
|
case Widget.CHECKBOX: return "Checkbox";
|
|
3112
3908
|
case Widget.TOGGLE: return "Toggle";
|
|
3909
|
+
case Widget.RADIO: return "Radio";
|
|
3113
3910
|
case Widget.COLOR: return "Color";
|
|
3911
|
+
case Widget.RANGE: return "Range";
|
|
3114
3912
|
case Widget.NUMBER: return "Number";
|
|
3115
3913
|
case Widget.VECTOR: return "Vector";
|
|
3116
3914
|
case Widget.TREE: return "Tree";
|
|
@@ -3188,11 +3986,12 @@ function ADD_CUSTOM_WIDGET( custom_widget_name, options = {} )
|
|
|
3188
3986
|
buttonName += "<a class='fa-solid " + (instance ? "fa-bars-staggered" : " ") + " menu' style='float:right; width:5%;'></a>";
|
|
3189
3987
|
|
|
3190
3988
|
let buttonEl = this.addButton(null, buttonName, (value, event) => {
|
|
3191
|
-
|
|
3192
|
-
|
|
3989
|
+
if( instance )
|
|
3990
|
+
{
|
|
3193
3991
|
element.querySelector(".lexcustomitems").toggleAttribute('hidden');
|
|
3194
3992
|
}
|
|
3195
|
-
else
|
|
3993
|
+
else
|
|
3994
|
+
{
|
|
3196
3995
|
addContextMenu(null, event, c => {
|
|
3197
3996
|
c.add("New " + custom_widget_name, () => {
|
|
3198
3997
|
instance = {};
|
|
@@ -3379,16 +4178,20 @@ class NodeTree {
|
|
|
3379
4178
|
|
|
3380
4179
|
// Add or remove
|
|
3381
4180
|
const idx = this.selected.indexOf( node );
|
|
3382
|
-
if( idx > -1 )
|
|
4181
|
+
if( idx > -1 )
|
|
4182
|
+
{
|
|
3383
4183
|
item.classList.remove( 'selected' );
|
|
3384
4184
|
this.selected.splice( idx, 1 );
|
|
3385
|
-
}
|
|
4185
|
+
}
|
|
4186
|
+
else
|
|
4187
|
+
{
|
|
3386
4188
|
item.classList.add( 'selected' );
|
|
3387
4189
|
this.selected.push( node );
|
|
3388
4190
|
}
|
|
3389
4191
|
|
|
3390
4192
|
// Only Show children...
|
|
3391
|
-
if( isParent && node.id.length > 1 /* Strange case... */)
|
|
4193
|
+
if( isParent && node.id.length > 1 /* Strange case... */)
|
|
4194
|
+
{
|
|
3392
4195
|
node.closed = false;
|
|
3393
4196
|
if( that.onevent )
|
|
3394
4197
|
{
|
|
@@ -3426,7 +4229,7 @@ class NodeTree {
|
|
|
3426
4229
|
|
|
3427
4230
|
e.preventDefault();
|
|
3428
4231
|
|
|
3429
|
-
if( that.onevent )
|
|
4232
|
+
if( !that.onevent )
|
|
3430
4233
|
{
|
|
3431
4234
|
return;
|
|
3432
4235
|
}
|
|
@@ -3482,7 +4285,8 @@ class NodeTree {
|
|
|
3482
4285
|
return;
|
|
3483
4286
|
}
|
|
3484
4287
|
|
|
3485
|
-
if( that.onevent )
|
|
4288
|
+
if( that.onevent )
|
|
4289
|
+
{
|
|
3486
4290
|
const event = new TreeEvent( TreeEvent.NODE_DELETED, node, e );
|
|
3487
4291
|
that.onevent( event );
|
|
3488
4292
|
}
|
|
@@ -3509,7 +4313,8 @@ class NodeTree {
|
|
|
3509
4313
|
if( e.key == "Delete" )
|
|
3510
4314
|
{
|
|
3511
4315
|
// Send event now so we have the info in selected array..
|
|
3512
|
-
if( that.onevent )
|
|
4316
|
+
if( that.onevent )
|
|
4317
|
+
{
|
|
3513
4318
|
const event = new TreeEvent( TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e );
|
|
3514
4319
|
event.multiple = this.selected.length > 1;
|
|
3515
4320
|
that.onevent( event );
|
|
@@ -3540,22 +4345,24 @@ class NodeTree {
|
|
|
3540
4345
|
|
|
3541
4346
|
// Node rename
|
|
3542
4347
|
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
item.appendChild(
|
|
4348
|
+
const nameInput = document.createElement( "input" );
|
|
4349
|
+
nameInput.toggleAttribute( "hidden", !node.rename );
|
|
4350
|
+
nameInput.value = node.id;
|
|
4351
|
+
item.appendChild(nameInput);
|
|
3547
4352
|
|
|
3548
|
-
if(node.rename)
|
|
4353
|
+
if( node.rename )
|
|
4354
|
+
{
|
|
3549
4355
|
item.classList.add('selected');
|
|
3550
|
-
|
|
4356
|
+
nameInput.focus();
|
|
3551
4357
|
}
|
|
3552
4358
|
|
|
3553
|
-
|
|
3554
|
-
if(e.key ==
|
|
3555
|
-
|
|
4359
|
+
nameInput.addEventListener("keyup", function(e){
|
|
4360
|
+
if( e.key == "Enter" )
|
|
4361
|
+
{
|
|
3556
4362
|
this.value = this.value.replace(/\s/g, '_');
|
|
3557
4363
|
|
|
3558
|
-
if(that.onevent)
|
|
4364
|
+
if( that.onevent )
|
|
4365
|
+
{
|
|
3559
4366
|
const event = new TreeEvent(TreeEvent.NODE_RENAMED, node, this.value);
|
|
3560
4367
|
that.onevent( event );
|
|
3561
4368
|
}
|
|
@@ -3565,18 +4372,20 @@ class NodeTree {
|
|
|
3565
4372
|
that.frefresh( node.id );
|
|
3566
4373
|
list.querySelector("#" + node.id).classList.add('selected');
|
|
3567
4374
|
}
|
|
3568
|
-
if(e.key ==
|
|
4375
|
+
else if(e.key == "Escape")
|
|
4376
|
+
{
|
|
3569
4377
|
delete node.rename;
|
|
3570
4378
|
that.frefresh( node.id );
|
|
3571
4379
|
}
|
|
3572
4380
|
});
|
|
3573
4381
|
|
|
3574
|
-
|
|
4382
|
+
nameInput.addEventListener("blur", function(e){
|
|
3575
4383
|
delete node.rename;
|
|
3576
4384
|
that.refresh();
|
|
3577
4385
|
});
|
|
3578
4386
|
|
|
3579
|
-
if(this.options.draggable ?? true)
|
|
4387
|
+
if( this.options.draggable ?? true )
|
|
4388
|
+
{
|
|
3580
4389
|
// Drag nodes
|
|
3581
4390
|
if(parent) // Root doesn't move!
|
|
3582
4391
|
{
|
|
@@ -3602,29 +4411,32 @@ class NodeTree {
|
|
|
3602
4411
|
return;
|
|
3603
4412
|
let target = node;
|
|
3604
4413
|
// Can't drop to same node
|
|
3605
|
-
if(dragged.id == target.id)
|
|
4414
|
+
if( dragged.id == target.id )
|
|
4415
|
+
{
|
|
3606
4416
|
console.warn("Cannot parent node to itself!");
|
|
3607
4417
|
return;
|
|
3608
4418
|
}
|
|
3609
4419
|
|
|
3610
4420
|
// Can't drop to child node
|
|
3611
|
-
const isChild = function(
|
|
4421
|
+
const isChild = function( newParent, node ) {
|
|
3612
4422
|
var result = false;
|
|
3613
|
-
for( var c of node.children )
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
result |= isChild(
|
|
4423
|
+
for( var c of node.children )
|
|
4424
|
+
{
|
|
4425
|
+
if( c.id == newParent.id ) return true;
|
|
4426
|
+
result |= isChild( newParent, c );
|
|
3617
4427
|
}
|
|
3618
4428
|
return result;
|
|
3619
4429
|
};
|
|
3620
4430
|
|
|
3621
|
-
if(isChild(target, dragged))
|
|
4431
|
+
if( isChild( target, dragged ))
|
|
4432
|
+
{
|
|
3622
4433
|
console.warn("Cannot parent node to a current child!");
|
|
3623
4434
|
return;
|
|
3624
4435
|
}
|
|
3625
4436
|
|
|
3626
4437
|
// Trigger node dragger event
|
|
3627
|
-
if(that.onevent)
|
|
4438
|
+
if( that.onevent )
|
|
4439
|
+
{
|
|
3628
4440
|
const event = new TreeEvent(TreeEvent.NODE_DRAGGED, dragged, target);
|
|
3629
4441
|
that.onevent( event );
|
|
3630
4442
|
}
|
|
@@ -3640,7 +4452,8 @@ class NodeTree {
|
|
|
3640
4452
|
let handled = false;
|
|
3641
4453
|
|
|
3642
4454
|
// Show/hide children
|
|
3643
|
-
if(isParent)
|
|
4455
|
+
if( isParent )
|
|
4456
|
+
{
|
|
3644
4457
|
item.querySelector('a.hierarchy').addEventListener("click", function(e) {
|
|
3645
4458
|
|
|
3646
4459
|
handled = true;
|
|
@@ -3648,7 +4461,8 @@ class NodeTree {
|
|
|
3648
4461
|
e.stopPropagation();
|
|
3649
4462
|
|
|
3650
4463
|
node.closed = !node.closed;
|
|
3651
|
-
if(that.onevent)
|
|
4464
|
+
if( that.onevent )
|
|
4465
|
+
{
|
|
3652
4466
|
const event = new TreeEvent(TreeEvent.NODE_CARETCHANGED, node, node.closed);
|
|
3653
4467
|
that.onevent( event );
|
|
3654
4468
|
}
|
|
@@ -3668,7 +4482,8 @@ class NodeTree {
|
|
|
3668
4482
|
node.visible = node.visible === undefined ? false : !node.visible;
|
|
3669
4483
|
this.className = "itemicon fa-solid fa-eye" + (!node.visible ? "-slash" : "");
|
|
3670
4484
|
// Trigger visibility event
|
|
3671
|
-
if(that.onevent)
|
|
4485
|
+
if( that.onevent )
|
|
4486
|
+
{
|
|
3672
4487
|
const event = new TreeEvent(TreeEvent.NODE_VISIBILITY, node, node.visible);
|
|
3673
4488
|
that.onevent( event );
|
|
3674
4489
|
}
|
|
@@ -3677,9 +4492,10 @@ class NodeTree {
|
|
|
3677
4492
|
item.appendChild(visibility);
|
|
3678
4493
|
}
|
|
3679
4494
|
|
|
3680
|
-
if(node.actions)
|
|
4495
|
+
if( node.actions )
|
|
3681
4496
|
{
|
|
3682
|
-
for(var i = 0; i < node.actions.length; ++i)
|
|
4497
|
+
for( var i = 0; i < node.actions.length; ++i )
|
|
4498
|
+
{
|
|
3683
4499
|
let a = node.actions[i];
|
|
3684
4500
|
var actionEl = document.createElement('a');
|
|
3685
4501
|
actionEl.className = "itemicon " + a.icon;
|
|
@@ -3692,20 +4508,25 @@ class NodeTree {
|
|
|
3692
4508
|
}
|
|
3693
4509
|
}
|
|
3694
4510
|
|
|
3695
|
-
if(selectedId != undefined && node.id == selectedId)
|
|
3696
|
-
|
|
4511
|
+
if( selectedId != undefined && node.id == selectedId )
|
|
4512
|
+
{
|
|
4513
|
+
this.selected = [ node ];
|
|
3697
4514
|
item.click();
|
|
3698
4515
|
}
|
|
3699
4516
|
|
|
3700
|
-
if(node.closed )
|
|
4517
|
+
if( node.closed )
|
|
4518
|
+
{
|
|
3701
4519
|
return;
|
|
4520
|
+
}
|
|
3702
4521
|
|
|
3703
4522
|
for( var i = 0; i < node.children.length; ++i )
|
|
3704
4523
|
{
|
|
3705
|
-
let child = node.children[i];
|
|
4524
|
+
let child = node.children[ i ];
|
|
3706
4525
|
|
|
3707
|
-
if( this.options.onlyFolders && child.type != 'folder')
|
|
4526
|
+
if( this.options.onlyFolders && child.type != 'folder' )
|
|
4527
|
+
{
|
|
3708
4528
|
continue;
|
|
4529
|
+
}
|
|
3709
4530
|
|
|
3710
4531
|
this._create_item( node, child, level + 1 );
|
|
3711
4532
|
}
|
|
@@ -3744,12 +4565,12 @@ class Panel {
|
|
|
3744
4565
|
* style: CSS Style object to be applied to the panel
|
|
3745
4566
|
*/
|
|
3746
4567
|
|
|
3747
|
-
constructor( options = {} )
|
|
4568
|
+
constructor( options = {} ) {
|
|
3748
4569
|
var root = document.createElement('div');
|
|
3749
4570
|
root.className = "lexpanel";
|
|
3750
|
-
if(options.id)
|
|
4571
|
+
if( options.id )
|
|
3751
4572
|
root.id = options.id;
|
|
3752
|
-
if(options.className)
|
|
4573
|
+
if( options.className )
|
|
3753
4574
|
root.className += " " + options.className;
|
|
3754
4575
|
|
|
3755
4576
|
root.style.width = options.width || "calc( 100% - 6px )";
|
|
@@ -3826,23 +4647,31 @@ class Panel {
|
|
|
3826
4647
|
this.branches = [];
|
|
3827
4648
|
this.current_branch = null;
|
|
3828
4649
|
|
|
3829
|
-
for(let w in this.widgets)
|
|
3830
|
-
|
|
4650
|
+
for( let w in this.widgets )
|
|
4651
|
+
{
|
|
4652
|
+
if( this.widgets[w].options && this.widgets[w].options.signal )
|
|
4653
|
+
{
|
|
3831
4654
|
const signal = this.widgets[w].options.signal;
|
|
3832
|
-
for(let i = 0; i < LX.signals[signal].length; i++)
|
|
3833
|
-
|
|
4655
|
+
for( let i = 0; i < LX.signals[signal].length; i++ )
|
|
4656
|
+
{
|
|
4657
|
+
if( LX.signals[signal][i] == this.widgets[w] )
|
|
4658
|
+
{
|
|
3834
4659
|
LX.signals[signal] = [...LX.signals[signal].slice(0, i), ...LX.signals[signal].slice(i+1)];
|
|
3835
4660
|
}
|
|
3836
4661
|
}
|
|
3837
4662
|
}
|
|
3838
4663
|
}
|
|
3839
4664
|
|
|
3840
|
-
if(this.signals)
|
|
3841
|
-
|
|
4665
|
+
if( this.signals )
|
|
4666
|
+
{
|
|
4667
|
+
for( let w = 0; w < this.signals.length; w++ )
|
|
4668
|
+
{
|
|
3842
4669
|
let widget = Object.values(this.signals[w])[0];
|
|
3843
4670
|
let signal = widget.options.signal;
|
|
3844
|
-
for(let i = 0; i < LX.signals[signal].length; i++)
|
|
3845
|
-
|
|
4671
|
+
for( let i = 0; i < LX.signals[signal].length; i++ )
|
|
4672
|
+
{
|
|
4673
|
+
if( LX.signals[signal][i] == widget )
|
|
4674
|
+
{
|
|
3846
4675
|
LX.signals[signal] = [...LX.signals[signal].slice(0, i), ...LX.signals[signal].slice(i+1)];
|
|
3847
4676
|
}
|
|
3848
4677
|
}
|
|
@@ -3880,10 +4709,12 @@ class Panel {
|
|
|
3880
4709
|
|
|
3881
4710
|
this._inline_widgets_left = -1;
|
|
3882
4711
|
|
|
3883
|
-
if(!this._inlineContainer)
|
|
4712
|
+
if( !this._inlineContainer )
|
|
4713
|
+
{
|
|
3884
4714
|
this._inlineContainer = document.createElement('div');
|
|
3885
4715
|
this._inlineContainer.className = "lexinlinewidgets";
|
|
3886
|
-
|
|
4716
|
+
|
|
4717
|
+
if( justifyContent )
|
|
3887
4718
|
{
|
|
3888
4719
|
this._inlineContainer.style.justifyContent = justifyContent;
|
|
3889
4720
|
}
|
|
@@ -3897,7 +4728,7 @@ class Panel {
|
|
|
3897
4728
|
if(is_pair)
|
|
3898
4729
|
{
|
|
3899
4730
|
// eg. an array, inline items appended later to
|
|
3900
|
-
if(this._inline_queued_container)
|
|
4731
|
+
if( this._inline_queued_container)
|
|
3901
4732
|
this._inlineContainer.appendChild( item[0] );
|
|
3902
4733
|
// eg. a dropdown, item is appended to parent, not to inline cont.
|
|
3903
4734
|
else
|
|
@@ -3909,7 +4740,7 @@ class Panel {
|
|
|
3909
4740
|
|
|
3910
4741
|
if(!this._inline_queued_container)
|
|
3911
4742
|
{
|
|
3912
|
-
if(this.current_branch)
|
|
4743
|
+
if( this.current_branch)
|
|
3913
4744
|
this.current_branch.content.appendChild( this._inlineContainer );
|
|
3914
4745
|
else
|
|
3915
4746
|
this.root.appendChild( this._inlineContainer );
|
|
@@ -3948,7 +4779,7 @@ class Panel {
|
|
|
3948
4779
|
this.current_branch = branch;
|
|
3949
4780
|
|
|
3950
4781
|
// Append to panel
|
|
3951
|
-
if(this.branches.length == 0)
|
|
4782
|
+
if( this.branches.length == 0)
|
|
3952
4783
|
branch.root.classList.add('first');
|
|
3953
4784
|
|
|
3954
4785
|
// This is the last!
|
|
@@ -3959,7 +4790,8 @@ class Panel {
|
|
|
3959
4790
|
this.root.appendChild( branch.root );
|
|
3960
4791
|
|
|
3961
4792
|
// Add widget filter
|
|
3962
|
-
if(options.filter)
|
|
4793
|
+
if( options.filter )
|
|
4794
|
+
{
|
|
3963
4795
|
this._addFilter( options.filter, {callback: this._searchWidgets.bind(this, branch.name)} );
|
|
3964
4796
|
}
|
|
3965
4797
|
|
|
@@ -4076,14 +4908,18 @@ class Panel {
|
|
|
4076
4908
|
element.jsInstance = widget;
|
|
4077
4909
|
|
|
4078
4910
|
const insert_widget = el => {
|
|
4079
|
-
if(options.container)
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4911
|
+
if( options.container )
|
|
4912
|
+
{
|
|
4913
|
+
options.container.appendChild( el );
|
|
4914
|
+
}
|
|
4915
|
+
else if( !this.queuedContainer )
|
|
4916
|
+
{
|
|
4917
|
+
if( this.current_branch )
|
|
4084
4918
|
{
|
|
4085
|
-
if(!options.skipWidget)
|
|
4919
|
+
if( !options.skipWidget )
|
|
4920
|
+
{
|
|
4086
4921
|
this.current_branch.widgets.push( widget );
|
|
4922
|
+
}
|
|
4087
4923
|
this.current_branch.content.appendChild( el );
|
|
4088
4924
|
}
|
|
4089
4925
|
else
|
|
@@ -4093,40 +4929,47 @@ class Panel {
|
|
|
4093
4929
|
}
|
|
4094
4930
|
}
|
|
4095
4931
|
// Append content to queued tab container
|
|
4096
|
-
else
|
|
4932
|
+
else
|
|
4933
|
+
{
|
|
4097
4934
|
this.queuedContainer.appendChild( el );
|
|
4098
4935
|
}
|
|
4099
4936
|
};
|
|
4100
4937
|
|
|
4101
4938
|
const store_widget = el => {
|
|
4102
4939
|
|
|
4103
|
-
if(!this.queuedContainer)
|
|
4940
|
+
if( !this.queuedContainer )
|
|
4941
|
+
{
|
|
4104
4942
|
this._inlineWidgets.push( el );
|
|
4105
4943
|
}
|
|
4106
4944
|
// Append content to queued tab container
|
|
4107
|
-
else
|
|
4945
|
+
else
|
|
4946
|
+
{
|
|
4108
4947
|
this._inlineWidgets.push( [el, this.queuedContainer] );
|
|
4109
4948
|
}
|
|
4110
4949
|
};
|
|
4111
4950
|
|
|
4112
4951
|
// Process inline widgets
|
|
4113
|
-
if(this._inline_widgets_left > 0 && !options.skipInlineCount)
|
|
4952
|
+
if( this._inline_widgets_left > 0 && !options.skipInlineCount )
|
|
4114
4953
|
{
|
|
4115
|
-
if(!this._inlineWidgets)
|
|
4954
|
+
if( !this._inlineWidgets )
|
|
4955
|
+
{
|
|
4116
4956
|
this._inlineWidgets = [];
|
|
4117
4957
|
}
|
|
4118
4958
|
|
|
4119
4959
|
// Store widget and its container
|
|
4120
|
-
store_widget(element);
|
|
4960
|
+
store_widget( element );
|
|
4121
4961
|
|
|
4122
4962
|
this._inline_widgets_left--;
|
|
4123
4963
|
|
|
4124
4964
|
// Last widget
|
|
4125
|
-
if(!this._inline_widgets_left)
|
|
4965
|
+
if( !this._inline_widgets_left )
|
|
4966
|
+
{
|
|
4126
4967
|
this.endLine();
|
|
4127
4968
|
}
|
|
4128
|
-
}
|
|
4129
|
-
|
|
4969
|
+
}
|
|
4970
|
+
else
|
|
4971
|
+
{
|
|
4972
|
+
insert_widget( element );
|
|
4130
4973
|
}
|
|
4131
4974
|
|
|
4132
4975
|
return widget;
|
|
@@ -4163,15 +5006,20 @@ class Panel {
|
|
|
4163
5006
|
|
|
4164
5007
|
_searchWidgets(branchName, value) {
|
|
4165
5008
|
|
|
4166
|
-
for( let b of this.branches )
|
|
4167
|
-
|
|
4168
|
-
if(b.name !== branchName)
|
|
5009
|
+
for( let b of this.branches )
|
|
5010
|
+
{
|
|
5011
|
+
if( b.name !== branchName )
|
|
5012
|
+
{
|
|
4169
5013
|
continue;
|
|
5014
|
+
}
|
|
4170
5015
|
|
|
4171
5016
|
// remove all widgets
|
|
4172
|
-
for( let w of b.widgets )
|
|
4173
|
-
|
|
5017
|
+
for( let w of b.widgets )
|
|
5018
|
+
{
|
|
5019
|
+
if( w.domEl.classList.contains('lexfilter') )
|
|
5020
|
+
{
|
|
4174
5021
|
continue;
|
|
5022
|
+
}
|
|
4175
5023
|
w.domEl.remove();
|
|
4176
5024
|
}
|
|
4177
5025
|
|
|
@@ -4181,9 +5029,9 @@ class Panel {
|
|
|
4181
5029
|
const emptyFilter = !value.length;
|
|
4182
5030
|
|
|
4183
5031
|
// add widgets
|
|
4184
|
-
for( let w of b.widgets )
|
|
4185
|
-
|
|
4186
|
-
if(!emptyFilter)
|
|
5032
|
+
for( let w of b.widgets )
|
|
5033
|
+
{
|
|
5034
|
+
if( !emptyFilter )
|
|
4187
5035
|
{
|
|
4188
5036
|
if(!w.name) continue;
|
|
4189
5037
|
const filterWord = value.toLowerCase();
|
|
@@ -4277,7 +5125,7 @@ class Panel {
|
|
|
4277
5125
|
|
|
4278
5126
|
clearQueue() {
|
|
4279
5127
|
|
|
4280
|
-
if(this._queue && this._queue.length)
|
|
5128
|
+
if( this._queue && this._queue.length)
|
|
4281
5129
|
{
|
|
4282
5130
|
this.queuedContainer = this._queue.pop();
|
|
4283
5131
|
return;
|
|
@@ -4503,7 +5351,8 @@ class Panel {
|
|
|
4503
5351
|
element.appendChild( container );
|
|
4504
5352
|
|
|
4505
5353
|
// Remove branch padding and margins
|
|
4506
|
-
if( !widget.name )
|
|
5354
|
+
if( !widget.name )
|
|
5355
|
+
{
|
|
4507
5356
|
element.className += " noname";
|
|
4508
5357
|
container.style.width = "100%";
|
|
4509
5358
|
}
|
|
@@ -4603,7 +5452,8 @@ class Panel {
|
|
|
4603
5452
|
element.appendChild(container);
|
|
4604
5453
|
|
|
4605
5454
|
// Remove branch padding and margins
|
|
4606
|
-
if(!widget.name)
|
|
5455
|
+
if( !widget.name )
|
|
5456
|
+
{
|
|
4607
5457
|
element.className += " noname";
|
|
4608
5458
|
container.style.width = "100%";
|
|
4609
5459
|
}
|
|
@@ -4708,11 +5558,12 @@ class Panel {
|
|
|
4708
5558
|
/**
|
|
4709
5559
|
* @method addComboButtons
|
|
4710
5560
|
* @param {String} name Widget name
|
|
4711
|
-
* @param {Array} values Each of the {value, callback} items
|
|
5561
|
+
* @param {Array} values Each of the {value, callback, selected, disabled} items
|
|
4712
5562
|
* @param {*} options:
|
|
4713
5563
|
* float: Justify content (left, center, right) [center]
|
|
4714
|
-
* selected: Selected item by default by value
|
|
5564
|
+
* @legacy selected: Selected item by default by value
|
|
4715
5565
|
* noSelection: Buttons can be clicked, but they are not selectable
|
|
5566
|
+
* toggle: Buttons can be toggled insted of selecting only one
|
|
4716
5567
|
*/
|
|
4717
5568
|
|
|
4718
5569
|
addComboButtons( name, values, options = {} ) {
|
|
@@ -4734,7 +5585,8 @@ class Panel {
|
|
|
4734
5585
|
let buttonsBox = document.createElement('div');
|
|
4735
5586
|
buttonsBox.className = "lexcombobuttonsbox ";
|
|
4736
5587
|
|
|
4737
|
-
|
|
5588
|
+
const shouldSelect = !( options.noSelection ?? false );
|
|
5589
|
+
const shouldToggle = shouldSelect && ( options.toggle ?? false );
|
|
4738
5590
|
|
|
4739
5591
|
for( let b of values )
|
|
4740
5592
|
{
|
|
@@ -4753,14 +5605,14 @@ class Panel {
|
|
|
4753
5605
|
buttonEl.classList.add( options.buttonClass );
|
|
4754
5606
|
}
|
|
4755
5607
|
|
|
4756
|
-
if( shouldSelect && options.selected == b.value )
|
|
5608
|
+
if( shouldSelect && ( b.selected || options.selected == b.value ) )
|
|
4757
5609
|
{
|
|
4758
5610
|
buttonEl.classList.add("selected");
|
|
4759
5611
|
}
|
|
4760
5612
|
|
|
4761
5613
|
buttonEl.innerHTML = ( b.icon ? "<a class='" + b.icon +"'></a>" : "" ) + "<span>" + ( b.icon ? "" : b.value ) + "</span>";
|
|
4762
5614
|
|
|
4763
|
-
if(
|
|
5615
|
+
if( b.disabled )
|
|
4764
5616
|
{
|
|
4765
5617
|
buttonEl.setAttribute( "disabled", true );
|
|
4766
5618
|
}
|
|
@@ -4768,8 +5620,15 @@ class Panel {
|
|
|
4768
5620
|
buttonEl.addEventListener("click", function( e ) {
|
|
4769
5621
|
if( shouldSelect )
|
|
4770
5622
|
{
|
|
4771
|
-
|
|
4772
|
-
|
|
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
|
+
}
|
|
4773
5632
|
}
|
|
4774
5633
|
|
|
4775
5634
|
that._trigger( new IEvent( name, b.value, e ), b.callback );
|
|
@@ -4779,7 +5638,7 @@ class Panel {
|
|
|
4779
5638
|
}
|
|
4780
5639
|
|
|
4781
5640
|
// Remove branch padding and margins
|
|
4782
|
-
if( !widget.name)
|
|
5641
|
+
if( !widget.name )
|
|
4783
5642
|
{
|
|
4784
5643
|
element.className += " noname";
|
|
4785
5644
|
container.style.width = "100%";
|
|
@@ -4953,7 +5812,8 @@ class Panel {
|
|
|
4953
5812
|
|
|
4954
5813
|
element.appendChild( container );
|
|
4955
5814
|
|
|
4956
|
-
if( !widget.name || options.hideName )
|
|
5815
|
+
if( !widget.name || options.hideName )
|
|
5816
|
+
{
|
|
4957
5817
|
element.className += " noname";
|
|
4958
5818
|
container.style.width = "100%";
|
|
4959
5819
|
}
|
|
@@ -5089,8 +5949,6 @@ class Panel {
|
|
|
5089
5949
|
|
|
5090
5950
|
const _placeOptions = ( parent ) => {
|
|
5091
5951
|
|
|
5092
|
-
console.log("Replacing container");
|
|
5093
|
-
|
|
5094
5952
|
const overflowContainer = parent.getParentArea();
|
|
5095
5953
|
const rect = selectedOption.getBoundingClientRect();
|
|
5096
5954
|
const nestedDialog = parent.parentElement.closest( "dialog" );
|
|
@@ -5374,15 +6232,16 @@ class Panel {
|
|
|
5374
6232
|
|
|
5375
6233
|
addCurve( name, values, callback, options = {} ) {
|
|
5376
6234
|
|
|
5377
|
-
if(!name)
|
|
5378
|
-
|
|
6235
|
+
if( !name )
|
|
6236
|
+
{
|
|
6237
|
+
throw( "Set Widget Name!" );
|
|
5379
6238
|
}
|
|
5380
6239
|
|
|
5381
6240
|
let that = this;
|
|
5382
|
-
let widget = this.create_widget(name, Widget.CURVE, options);
|
|
6241
|
+
let widget = this.create_widget( name, Widget.CURVE, options );
|
|
5383
6242
|
|
|
5384
6243
|
widget.onGetValue = () => {
|
|
5385
|
-
return JSON.parse(JSON.stringify(curveInstance.element.value));
|
|
6244
|
+
return JSON.parse(JSON.stringify( curveInstance.element.value ));
|
|
5386
6245
|
};
|
|
5387
6246
|
|
|
5388
6247
|
widget.onSetValue = ( newValue, skipCallback ) => {
|
|
@@ -5527,7 +6386,8 @@ class Panel {
|
|
|
5527
6386
|
|
|
5528
6387
|
addLayers( name, value, callback, options = {} ) {
|
|
5529
6388
|
|
|
5530
|
-
if(!name)
|
|
6389
|
+
if( !name )
|
|
6390
|
+
{
|
|
5531
6391
|
throw("Set Widget Name!");
|
|
5532
6392
|
}
|
|
5533
6393
|
|
|
@@ -5569,7 +6429,8 @@ class Panel {
|
|
|
5569
6429
|
let binary = value.toString( 2 );
|
|
5570
6430
|
let nbits = binary.length;
|
|
5571
6431
|
// fill zeros
|
|
5572
|
-
for(var i = 0; i < (16 - nbits); ++i)
|
|
6432
|
+
for( var i = 0; i < (16 - nbits); ++i )
|
|
6433
|
+
{
|
|
5573
6434
|
binary = '0' + binary;
|
|
5574
6435
|
}
|
|
5575
6436
|
|
|
@@ -5622,8 +6483,9 @@ class Panel {
|
|
|
5622
6483
|
|
|
5623
6484
|
addArray( name, values = [], callback, options = {} ) {
|
|
5624
6485
|
|
|
5625
|
-
if(!name)
|
|
5626
|
-
|
|
6486
|
+
if( !name )
|
|
6487
|
+
{
|
|
6488
|
+
throw( "Set Widget Name!" );
|
|
5627
6489
|
}
|
|
5628
6490
|
|
|
5629
6491
|
let widget = this.create_widget(name, Widget.ARRAY, options);
|
|
@@ -5804,7 +6666,8 @@ class Panel {
|
|
|
5804
6666
|
widget.updateValues( values );
|
|
5805
6667
|
|
|
5806
6668
|
// Remove branch padding and margins
|
|
5807
|
-
if( !widget.name )
|
|
6669
|
+
if( !widget.name )
|
|
6670
|
+
{
|
|
5808
6671
|
element.className += " noname";
|
|
5809
6672
|
listContainer.style.width = "100%";
|
|
5810
6673
|
}
|
|
@@ -5891,7 +6754,7 @@ class Panel {
|
|
|
5891
6754
|
tagsContainer.appendChild( tagInput );
|
|
5892
6755
|
|
|
5893
6756
|
tagInput.onkeydown = function( e ) {
|
|
5894
|
-
const val = this.value.replace(/\s/g, '');
|
|
6757
|
+
const val = this.value.replace( /\s/g, '' );
|
|
5895
6758
|
if( e.key == ' ' || e.key == 'Enter' )
|
|
5896
6759
|
{
|
|
5897
6760
|
e.preventDefault();
|
|
@@ -5929,15 +6792,16 @@ class Panel {
|
|
|
5929
6792
|
* @param {Function} callback Callback function on change
|
|
5930
6793
|
* @param {*} options:
|
|
5931
6794
|
* disabled: Make the widget disabled [false]
|
|
6795
|
+
* label: Checkbox label
|
|
5932
6796
|
* suboptions: Callback to add widgets in case of TRUE value
|
|
5933
|
-
* className:
|
|
6797
|
+
* className: Extra classes to customize style
|
|
5934
6798
|
*/
|
|
5935
6799
|
|
|
5936
6800
|
addCheckbox( name, value, callback, options = {} ) {
|
|
5937
6801
|
|
|
5938
|
-
if( !name )
|
|
6802
|
+
if( !name && !options.label )
|
|
5939
6803
|
{
|
|
5940
|
-
throw( "Set Widget Name!" );
|
|
6804
|
+
throw( "Set Widget Name or at least a label!" );
|
|
5941
6805
|
}
|
|
5942
6806
|
|
|
5943
6807
|
let widget = this.create_widget( name, Widget.CHECKBOX, options );
|
|
@@ -5957,10 +6821,13 @@ class Panel {
|
|
|
5957
6821
|
let element = widget.domEl;
|
|
5958
6822
|
|
|
5959
6823
|
// Add reset functionality
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
Panel.
|
|
5963
|
-
|
|
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
|
+
}
|
|
5964
6831
|
|
|
5965
6832
|
// Add widget value
|
|
5966
6833
|
|
|
@@ -5976,7 +6843,7 @@ class Panel {
|
|
|
5976
6843
|
|
|
5977
6844
|
let valueName = document.createElement( 'span' );
|
|
5978
6845
|
valueName.className = "checkboxtext";
|
|
5979
|
-
valueName.innerHTML = "On";
|
|
6846
|
+
valueName.innerHTML = options.label ?? "On";
|
|
5980
6847
|
|
|
5981
6848
|
container.appendChild( checkbox );
|
|
5982
6849
|
container.appendChild( valueName );
|
|
@@ -6114,6 +6981,96 @@ class Panel {
|
|
|
6114
6981
|
return widget;
|
|
6115
6982
|
}
|
|
6116
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
|
+
|
|
6117
7074
|
/**
|
|
6118
7075
|
* @method addColor
|
|
6119
7076
|
* @param {String} name Widget name
|
|
@@ -6126,7 +7083,8 @@ class Panel {
|
|
|
6126
7083
|
|
|
6127
7084
|
addColor( name, value, callback, options = {} ) {
|
|
6128
7085
|
|
|
6129
|
-
if( !name )
|
|
7086
|
+
if( !name )
|
|
7087
|
+
{
|
|
6130
7088
|
throw( "Set Widget Name!" );
|
|
6131
7089
|
}
|
|
6132
7090
|
|
|
@@ -6164,7 +7122,8 @@ class Panel {
|
|
|
6164
7122
|
color.useRGB = options.useRGB ?? false;
|
|
6165
7123
|
color.value = color.iValue = value.constructor === Array ? rgbToHex( value ) : value;
|
|
6166
7124
|
|
|
6167
|
-
if( options.disabled )
|
|
7125
|
+
if( options.disabled )
|
|
7126
|
+
{
|
|
6168
7127
|
color.disabled = true;
|
|
6169
7128
|
}
|
|
6170
7129
|
|
|
@@ -6209,6 +7168,137 @@ class Panel {
|
|
|
6209
7168
|
return widget;
|
|
6210
7169
|
}
|
|
6211
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;
|
|
7246
|
+
|
|
7247
|
+
// Reset button (default value)
|
|
7248
|
+
if( !skipCallback )
|
|
7249
|
+
{
|
|
7250
|
+
let btn = element.querySelector( ".lexwidgetname .lexicon" );
|
|
7251
|
+
if( btn ) btn.style.display = val != slider.iValue ? "block": "none";
|
|
7252
|
+
}
|
|
7253
|
+
|
|
7254
|
+
if( options.left )
|
|
7255
|
+
{
|
|
7256
|
+
val = ( +slider.max ) - val + ( +slider.min );
|
|
7257
|
+
}
|
|
7258
|
+
|
|
7259
|
+
if( !skipCallback ) this._trigger( new IEvent( name, val, e ), callback );
|
|
7260
|
+
}, { passive: false });
|
|
7261
|
+
|
|
7262
|
+
slider.addEventListener( "mousedown", function( e ) {
|
|
7263
|
+
if( options.onPress )
|
|
7264
|
+
{
|
|
7265
|
+
options.onPress.bind( slider )( e, slider );
|
|
7266
|
+
}
|
|
7267
|
+
}, false );
|
|
7268
|
+
|
|
7269
|
+
slider.addEventListener( "mouseup", function( e ) {
|
|
7270
|
+
if( options.onRelease )
|
|
7271
|
+
{
|
|
7272
|
+
options.onRelease.bind( slider )( e, slider );
|
|
7273
|
+
}
|
|
7274
|
+
}, false );
|
|
7275
|
+
|
|
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
|
+
};
|
|
7283
|
+
|
|
7284
|
+
if( value.constructor == Number )
|
|
7285
|
+
{
|
|
7286
|
+
value = clamp( value, +slider.min, +slider.max );
|
|
7287
|
+
}
|
|
7288
|
+
|
|
7289
|
+
container.appendChild( slider );
|
|
7290
|
+
element.appendChild( container );
|
|
7291
|
+
|
|
7292
|
+
// Remove branch padding and margins
|
|
7293
|
+
if( !widget.name )
|
|
7294
|
+
{
|
|
7295
|
+
element.className += " noname";
|
|
7296
|
+
container.style.width = "100%";
|
|
7297
|
+
}
|
|
7298
|
+
|
|
7299
|
+
return widget;
|
|
7300
|
+
}
|
|
7301
|
+
|
|
6212
7302
|
/**
|
|
6213
7303
|
* @method addNumber
|
|
6214
7304
|
* @param {String} name Widget name
|
|
@@ -6241,7 +7331,8 @@ class Panel {
|
|
|
6241
7331
|
let element = widget.domEl;
|
|
6242
7332
|
|
|
6243
7333
|
// add reset functionality
|
|
6244
|
-
if( widget.name )
|
|
7334
|
+
if( widget.name )
|
|
7335
|
+
{
|
|
6245
7336
|
Panel._add_reset_property( element.domName, function() {
|
|
6246
7337
|
this.style.display = "none";
|
|
6247
7338
|
vecinput.value = vecinput.iValue;
|
|
@@ -6509,7 +7600,8 @@ class Panel {
|
|
|
6509
7600
|
return;
|
|
6510
7601
|
}
|
|
6511
7602
|
|
|
6512
|
-
for( let i = 0; i < inputs.length; ++i )
|
|
7603
|
+
for( let i = 0; i < inputs.length; ++i )
|
|
7604
|
+
{
|
|
6513
7605
|
let value = newValue[ i ];
|
|
6514
7606
|
inputs[ i ].value = round( value, options.precision ) ?? 0;
|
|
6515
7607
|
Panel._dispatch_event( inputs[ i ], "change", skipCallback );
|
|
@@ -6521,7 +7613,8 @@ class Panel {
|
|
|
6521
7613
|
// Add reset functionality
|
|
6522
7614
|
Panel._add_reset_property( element.domName, function() {
|
|
6523
7615
|
this.style.display = "none";
|
|
6524
|
-
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7616
|
+
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7617
|
+
{
|
|
6525
7618
|
v.value = v.iValue;
|
|
6526
7619
|
Panel._dispatch_event( v, "change" );
|
|
6527
7620
|
}
|
|
@@ -6533,8 +7626,8 @@ class Panel {
|
|
|
6533
7626
|
container.className = "lexvector";
|
|
6534
7627
|
container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
|
|
6535
7628
|
|
|
6536
|
-
for( let i = 0; i < num_components; ++i )
|
|
6537
|
-
|
|
7629
|
+
for( let i = 0; i < num_components; ++i )
|
|
7630
|
+
{
|
|
6538
7631
|
let box = document.createElement( 'div' );
|
|
6539
7632
|
box.className = "vecbox";
|
|
6540
7633
|
box.innerHTML = "<span class='" + Panel.VECTOR_COMPONENTS[ i ] + "'></span>";
|
|
@@ -6610,7 +7703,8 @@ class Panel {
|
|
|
6610
7703
|
|
|
6611
7704
|
if( locker.locked )
|
|
6612
7705
|
{
|
|
6613
|
-
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7706
|
+
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7707
|
+
{
|
|
6614
7708
|
v.value = val;
|
|
6615
7709
|
value[ v.idx ] = val;
|
|
6616
7710
|
}
|
|
@@ -6668,7 +7762,8 @@ class Panel {
|
|
|
6668
7762
|
|
|
6669
7763
|
if( locker.locked )
|
|
6670
7764
|
{
|
|
6671
|
-
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7765
|
+
for( let v of element.querySelectorAll( ".vecinput" ) )
|
|
7766
|
+
{
|
|
6672
7767
|
v.value = round( +v.valueAsNumber + mult * dt, options.precision );
|
|
6673
7768
|
Panel._dispatch_event( v, "change" );
|
|
6674
7769
|
}
|
|
@@ -6794,7 +7889,7 @@ class Panel {
|
|
|
6794
7889
|
const value = [];
|
|
6795
7890
|
for( let i = 0; i < element.dimensions.length; ++i )
|
|
6796
7891
|
{
|
|
6797
|
-
value.push( element.dimensions[ i ].
|
|
7892
|
+
value.push( element.dimensions[ i ].value() );
|
|
6798
7893
|
}
|
|
6799
7894
|
return value;
|
|
6800
7895
|
};
|
|
@@ -6802,7 +7897,7 @@ class Panel {
|
|
|
6802
7897
|
widget.onSetValue = ( newValue, skipCallback ) => {
|
|
6803
7898
|
for( let i = 0; i < element.dimensions.length; ++i )
|
|
6804
7899
|
{
|
|
6805
|
-
element.dimensions[ i ].
|
|
7900
|
+
element.dimensions[ i ].set( newValue[ i ], skipCallback );
|
|
6806
7901
|
}
|
|
6807
7902
|
};
|
|
6808
7903
|
|
|
@@ -6817,14 +7912,14 @@ class Panel {
|
|
|
6817
7912
|
{
|
|
6818
7913
|
element.dimensions[ i ] = this.addNumber( null, value[ i ], ( v ) => {
|
|
6819
7914
|
|
|
6820
|
-
const value = widget.
|
|
7915
|
+
const value = widget.value();
|
|
6821
7916
|
|
|
6822
7917
|
if( element.locked )
|
|
6823
7918
|
{
|
|
6824
7919
|
const ar = ( i == 0 ? 1.0 / element.aspectRatio : element.aspectRatio );
|
|
6825
7920
|
const index = ( 1 + i ) % 2;
|
|
6826
7921
|
value[ index ] = v * ar;
|
|
6827
|
-
element.dimensions[ index ].
|
|
7922
|
+
element.dimensions[ index ].set( value[ index ], true );
|
|
6828
7923
|
}
|
|
6829
7924
|
|
|
6830
7925
|
if( callback )
|
|
@@ -6867,7 +7962,7 @@ class Panel {
|
|
|
6867
7962
|
this.classList.remove( "fa-lock-open" );
|
|
6868
7963
|
|
|
6869
7964
|
// Recompute ratio
|
|
6870
|
-
const value = widget.
|
|
7965
|
+
const value = widget.value();
|
|
6871
7966
|
element.aspectRatio = value[ 0 ] / value[ 1 ];
|
|
6872
7967
|
}
|
|
6873
7968
|
else
|
|
@@ -7264,7 +8359,8 @@ class Panel {
|
|
|
7264
8359
|
let container = document.createElement('div');
|
|
7265
8360
|
container.className = "lextree";
|
|
7266
8361
|
|
|
7267
|
-
if(name)
|
|
8362
|
+
if( name )
|
|
8363
|
+
{
|
|
7268
8364
|
let title = document.createElement('span');
|
|
7269
8365
|
title.innerHTML = name;
|
|
7270
8366
|
container.appendChild(title);
|
|
@@ -7276,8 +8372,8 @@ class Panel {
|
|
|
7276
8372
|
toolsDiv.className += " notitle";
|
|
7277
8373
|
|
|
7278
8374
|
// Tree icons
|
|
7279
|
-
if(options.icons)
|
|
7280
|
-
|
|
8375
|
+
if( options.icons )
|
|
8376
|
+
{
|
|
7281
8377
|
for( let data of options.icons )
|
|
7282
8378
|
{
|
|
7283
8379
|
let iconEl = document.createElement('a');
|
|
@@ -7337,11 +8433,15 @@ class Panel {
|
|
|
7337
8433
|
let widget = new Widget( null, Widget.SEPARATOR );
|
|
7338
8434
|
widget.domEl = element;
|
|
7339
8435
|
|
|
7340
|
-
if(this.current_branch)
|
|
8436
|
+
if( this.current_branch )
|
|
8437
|
+
{
|
|
7341
8438
|
this.current_branch.content.appendChild( element );
|
|
7342
8439
|
this.current_branch.widgets.push( widget );
|
|
7343
|
-
}
|
|
7344
|
-
|
|
8440
|
+
}
|
|
8441
|
+
else
|
|
8442
|
+
{
|
|
8443
|
+
this.root.appendChild( element );
|
|
8444
|
+
}
|
|
7345
8445
|
}
|
|
7346
8446
|
|
|
7347
8447
|
/**
|
|
@@ -7666,6 +8766,12 @@ class Panel {
|
|
|
7666
8766
|
|
|
7667
8767
|
input.addEventListener( 'change', function() {
|
|
7668
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
|
+
}
|
|
7669
8775
|
});
|
|
7670
8776
|
|
|
7671
8777
|
row.appendChild( td );
|
|
@@ -7791,7 +8897,7 @@ class Branch {
|
|
|
7791
8897
|
root.appendChild( title );
|
|
7792
8898
|
|
|
7793
8899
|
var branchContent = document.createElement( 'div' );
|
|
7794
|
-
branchContent.id = name.replace(/\s/g, '');
|
|
8900
|
+
branchContent.id = name.replace( /\s/g, '' );
|
|
7795
8901
|
branchContent.className = "lexbranchcontent";
|
|
7796
8902
|
root.appendChild(branchContent);
|
|
7797
8903
|
this.content = branchContent;
|
|
@@ -7847,7 +8953,8 @@ class Branch {
|
|
|
7847
8953
|
|
|
7848
8954
|
const dialog = new Dialog(this.name, p => {
|
|
7849
8955
|
// add widgets
|
|
7850
|
-
for( let w of this.widgets )
|
|
8956
|
+
for( let w of this.widgets )
|
|
8957
|
+
{
|
|
7851
8958
|
p.root.appendChild( w.domEl );
|
|
7852
8959
|
}
|
|
7853
8960
|
});
|
|
@@ -7940,8 +9047,8 @@ class Branch {
|
|
|
7940
9047
|
var size = this.grabber.style.marginLeft;
|
|
7941
9048
|
|
|
7942
9049
|
// Update sizes of widgets inside
|
|
7943
|
-
for(var i = 0; i < this.widgets.length; i++)
|
|
7944
|
-
|
|
9050
|
+
for( var i = 0; i < this.widgets.length; i++ )
|
|
9051
|
+
{
|
|
7945
9052
|
let widget = this.widgets[ i ];
|
|
7946
9053
|
let element = widget.domEl;
|
|
7947
9054
|
|
|
@@ -7960,9 +9067,6 @@ class Branch {
|
|
|
7960
9067
|
case Widget.FILE:
|
|
7961
9068
|
padding = "10%";
|
|
7962
9069
|
break;
|
|
7963
|
-
case Widget.TEXT:
|
|
7964
|
-
padding = "8px";
|
|
7965
|
-
break;
|
|
7966
9070
|
};
|
|
7967
9071
|
|
|
7968
9072
|
value.style.width = "-moz-calc( 100% - " + size + " - " + padding + " )";
|
|
@@ -8101,7 +9205,7 @@ class Dialog {
|
|
|
8101
9205
|
modal = options.modal ?? false;
|
|
8102
9206
|
|
|
8103
9207
|
var root = document.createElement('dialog');
|
|
8104
|
-
root.className = "lexdialog " + (options.
|
|
9208
|
+
root.className = "lexdialog " + (options.className ?? "");
|
|
8105
9209
|
root.id = options.id ?? "dialog" + Dialog._last_id++;
|
|
8106
9210
|
LX.root.appendChild( root );
|
|
8107
9211
|
|
|
@@ -8259,15 +9363,15 @@ class Dialog {
|
|
|
8259
9363
|
|
|
8260
9364
|
root.style.width = size[ 0 ] ? (size[ 0 ]) : "25%";
|
|
8261
9365
|
root.style.height = size[ 1 ] ? (size[ 1 ]) : "auto";
|
|
9366
|
+
root.style.translate = options.position ? "unset" : "-50% -50%";
|
|
8262
9367
|
|
|
8263
9368
|
if( options.size )
|
|
8264
9369
|
{
|
|
8265
9370
|
this.size = size;
|
|
8266
9371
|
}
|
|
8267
9372
|
|
|
8268
|
-
|
|
8269
|
-
root.style.
|
|
8270
|
-
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%";
|
|
8271
9375
|
|
|
8272
9376
|
panel.root.style.width = "calc( 100% - 30px )";
|
|
8273
9377
|
panel.root.style.height = title ? "calc( 100% - " + ( titleDiv.offsetHeight + 30 ) + "px )" : "calc( 100% - 51px )";
|
|
@@ -8284,7 +9388,7 @@ class Dialog {
|
|
|
8284
9388
|
this._oncreate.call(this, this.panel);
|
|
8285
9389
|
}
|
|
8286
9390
|
|
|
8287
|
-
setPosition(x, y) {
|
|
9391
|
+
setPosition( x, y ) {
|
|
8288
9392
|
|
|
8289
9393
|
this.root.style.left = x + "px";
|
|
8290
9394
|
this.root.style.top = y + "px";
|
|
@@ -8330,6 +9434,9 @@ class PocketDialog extends Dialog {
|
|
|
8330
9434
|
|
|
8331
9435
|
// Custom
|
|
8332
9436
|
this.root.classList.add( "pocket" );
|
|
9437
|
+
|
|
9438
|
+
this.root.style.translate = "none";
|
|
9439
|
+
this.root.style.top = "0";
|
|
8333
9440
|
this.root.style.left = "unset";
|
|
8334
9441
|
|
|
8335
9442
|
if( !options.position )
|
|
@@ -8345,6 +9452,11 @@ class PocketDialog extends Dialog {
|
|
|
8345
9452
|
this.minimized = false;
|
|
8346
9453
|
this.title.tabIndex = -1;
|
|
8347
9454
|
this.title.addEventListener("click", e => {
|
|
9455
|
+
if( this.title._eventCatched )
|
|
9456
|
+
{
|
|
9457
|
+
this.title._eventCatched = false;
|
|
9458
|
+
return;
|
|
9459
|
+
}
|
|
8348
9460
|
|
|
8349
9461
|
// Sized dialogs have to keep their size
|
|
8350
9462
|
if( this.size )
|
|
@@ -8427,12 +9539,12 @@ class ContextMenu {
|
|
|
8427
9539
|
constructor( event, title, options = {} ) {
|
|
8428
9540
|
|
|
8429
9541
|
// remove all context menus
|
|
8430
|
-
document.body.querySelectorAll(".
|
|
9542
|
+
document.body.querySelectorAll( ".lexcontextmenu" ).forEach( e => e.remove() );
|
|
8431
9543
|
|
|
8432
|
-
this.root = document.createElement(
|
|
8433
|
-
this.root.className = "
|
|
8434
|
-
this.root.style.left = (event.x - 48 + document.scrollingElement.scrollLeft) + "px";
|
|
8435
|
-
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";
|
|
8436
9548
|
|
|
8437
9549
|
this.root.addEventListener("mouseleave", function() {
|
|
8438
9550
|
this.remove();
|
|
@@ -8445,8 +9557,8 @@ class ContextMenu {
|
|
|
8445
9557
|
{
|
|
8446
9558
|
const item = {};
|
|
8447
9559
|
item[ title ] = [];
|
|
8448
|
-
item[
|
|
8449
|
-
item[
|
|
9560
|
+
item[ "className" ] = "cmtitle";
|
|
9561
|
+
item[ "icon" ] = options.icon;
|
|
8450
9562
|
this.items.push( item );
|
|
8451
9563
|
}
|
|
8452
9564
|
}
|
|
@@ -8494,16 +9606,16 @@ class ContextMenu {
|
|
|
8494
9606
|
|
|
8495
9607
|
_create_submenu( o, k, c, d ) {
|
|
8496
9608
|
|
|
8497
|
-
this.root.querySelectorAll(".
|
|
9609
|
+
this.root.querySelectorAll( ".lexcontextmenu" ).forEach( cm => cm.remove() );
|
|
8498
9610
|
|
|
8499
9611
|
let contextmenu = document.createElement('div');
|
|
8500
|
-
contextmenu.className = "
|
|
9612
|
+
contextmenu.className = "lexcontextmenu";
|
|
8501
9613
|
c.appendChild( contextmenu );
|
|
8502
9614
|
|
|
8503
9615
|
for( var i = 0; i < o[k].length; ++i )
|
|
8504
9616
|
{
|
|
8505
|
-
const subitem = o[k][i];
|
|
8506
|
-
const subkey = Object.keys(subitem)[0];
|
|
9617
|
+
const subitem = o[ k ][ i ];
|
|
9618
|
+
const subkey = Object.keys( subitem )[ 0 ];
|
|
8507
9619
|
this._create_entry(subitem, subkey, contextmenu, d);
|
|
8508
9620
|
}
|
|
8509
9621
|
|
|
@@ -8519,22 +9631,25 @@ class ContextMenu {
|
|
|
8519
9631
|
|
|
8520
9632
|
const hasSubmenu = o[ k ].length;
|
|
8521
9633
|
let entry = document.createElement('div');
|
|
8522
|
-
entry.className = "
|
|
9634
|
+
entry.className = "lexmenuboxentry" + (o[ 'className' ] ? " " + o[ 'className' ] : "" );
|
|
8523
9635
|
entry.id = o.id ?? ("eId" + getSupportedDOMName( k ));
|
|
8524
9636
|
entry.innerHTML = "";
|
|
8525
9637
|
const icon = o[ 'icon' ];
|
|
8526
|
-
if(icon)
|
|
9638
|
+
if( icon )
|
|
9639
|
+
{
|
|
8527
9640
|
entry.innerHTML += "<a class='" + icon + " fa-sm'></a>";
|
|
8528
9641
|
}
|
|
8529
9642
|
const disabled = o['disabled'];
|
|
8530
9643
|
entry.innerHTML += "<div class='lexentryname" + (disabled ? " disabled" : "") + "'>" + k + "</div>";
|
|
8531
9644
|
c.appendChild( entry );
|
|
8532
9645
|
|
|
8533
|
-
if( this.colors[ k ] )
|
|
9646
|
+
if( this.colors[ k ] )
|
|
9647
|
+
{
|
|
8534
9648
|
entry.style.borderColor = this.colors[ k ];
|
|
8535
9649
|
}
|
|
8536
9650
|
|
|
8537
|
-
if( k == "" )
|
|
9651
|
+
if( k == "" )
|
|
9652
|
+
{
|
|
8538
9653
|
entry.className += " cmseparator";
|
|
8539
9654
|
return;
|
|
8540
9655
|
}
|
|
@@ -8547,7 +9662,8 @@ class ContextMenu {
|
|
|
8547
9662
|
if(disabled) return;
|
|
8548
9663
|
|
|
8549
9664
|
const f = o[ 'callback' ];
|
|
8550
|
-
if(f)
|
|
9665
|
+
if( f )
|
|
9666
|
+
{
|
|
8551
9667
|
f.call( this, k, entry );
|
|
8552
9668
|
this.root.remove();
|
|
8553
9669
|
}
|
|
@@ -8579,8 +9695,7 @@ class ContextMenu {
|
|
|
8579
9695
|
|
|
8580
9696
|
entry.addEventListener("mouseleave", () => {
|
|
8581
9697
|
d = -1; // Reset depth
|
|
8582
|
-
|
|
8583
|
-
c.querySelectorAll(".lexcontextmenubox").forEach(e => e.remove());
|
|
9698
|
+
c.querySelectorAll(".lexcontextmenu").forEach(e => e.remove());
|
|
8584
9699
|
});
|
|
8585
9700
|
}
|
|
8586
9701
|
|
|
@@ -8613,22 +9728,25 @@ class ContextMenu {
|
|
|
8613
9728
|
if(key) found = o[ key ];
|
|
8614
9729
|
} );
|
|
8615
9730
|
|
|
8616
|
-
if(found)
|
|
9731
|
+
if( found )
|
|
9732
|
+
{
|
|
8617
9733
|
insert( tokens[idx++], found );
|
|
8618
9734
|
}
|
|
8619
|
-
else
|
|
9735
|
+
else
|
|
9736
|
+
{
|
|
8620
9737
|
let item = {};
|
|
8621
9738
|
item[ token ] = [];
|
|
8622
|
-
const
|
|
9739
|
+
const nextToken = tokens[idx++];
|
|
8623
9740
|
// Check if last token -> add callback
|
|
8624
|
-
if(!
|
|
9741
|
+
if( !nextToken )
|
|
9742
|
+
{
|
|
8625
9743
|
item[ 'id' ] = options.id;
|
|
8626
9744
|
item[ 'callback' ] = options.callback;
|
|
8627
9745
|
item[ 'disabled' ] = options.disabled ?? false;
|
|
8628
9746
|
}
|
|
8629
9747
|
|
|
8630
9748
|
list.push( item );
|
|
8631
|
-
insert(
|
|
9749
|
+
insert( nextToken, item[ token ] );
|
|
8632
9750
|
}
|
|
8633
9751
|
};
|
|
8634
9752
|
|
|
@@ -8652,7 +9770,8 @@ class ContextMenu {
|
|
|
8652
9770
|
_item[ key ].unshift( parent );
|
|
8653
9771
|
}
|
|
8654
9772
|
|
|
8655
|
-
for( var child of _item[ key ] )
|
|
9773
|
+
for( var child of _item[ key ] )
|
|
9774
|
+
{
|
|
8656
9775
|
let k = Object.keys(child)[0];
|
|
8657
9776
|
for( var i = 0; i < child[k].length; ++i )
|
|
8658
9777
|
setParent(child);
|
|
@@ -8666,7 +9785,7 @@ class ContextMenu {
|
|
|
8666
9785
|
|
|
8667
9786
|
for( let item of this.items )
|
|
8668
9787
|
{
|
|
8669
|
-
let key = Object.keys(item)[0];
|
|
9788
|
+
let key = Object.keys( item )[ 0 ];
|
|
8670
9789
|
let pKey = "eId" + getSupportedDOMName( key );
|
|
8671
9790
|
|
|
8672
9791
|
// Item already created
|
|
@@ -8783,7 +9902,7 @@ class Curve {
|
|
|
8783
9902
|
|
|
8784
9903
|
var r = [];
|
|
8785
9904
|
var dx = (element.xrange[1] - element.xrange[ 0 ]) / samples;
|
|
8786
|
-
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 )
|
|
8787
9906
|
{
|
|
8788
9907
|
r.push( element.getValueAt(i) );
|
|
8789
9908
|
}
|
|
@@ -8792,7 +9911,8 @@ class Curve {
|
|
|
8792
9911
|
|
|
8793
9912
|
element.addValue = function(v) {
|
|
8794
9913
|
|
|
8795
|
-
for(var i = 0; i < element.value; i++)
|
|
9914
|
+
for( var i = 0; i < element.value; i++ )
|
|
9915
|
+
{
|
|
8796
9916
|
var value = element.value[i];
|
|
8797
9917
|
if(value[0] < v[0]) continue;
|
|
8798
9918
|
element.value.splice(i,0,v);
|
|
@@ -8818,7 +9938,7 @@ class Curve {
|
|
|
8818
9938
|
|
|
8819
9939
|
var selected = -1;
|
|
8820
9940
|
|
|
8821
|
-
element.redraw = function( o = {} )
|
|
9941
|
+
element.redraw = function( o = {} ) {
|
|
8822
9942
|
|
|
8823
9943
|
if( o.value ) element.value = o.value;
|
|
8824
9944
|
if( o.xrange ) element.xrange = o.xrange;
|
|
@@ -8847,13 +9967,16 @@ class Curve {
|
|
|
8847
9967
|
ctx.moveTo( pos[ 0 ], pos[ 1 ] );
|
|
8848
9968
|
let values = [pos[ 0 ], pos[ 1 ]];
|
|
8849
9969
|
|
|
8850
|
-
for(var i in element.value)
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
values.push(pos[
|
|
8855
|
-
|
|
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
|
+
{
|
|
8856
9978
|
ctx.lineTo( pos[ 0 ], pos[ 1 ] );
|
|
9979
|
+
}
|
|
8857
9980
|
}
|
|
8858
9981
|
|
|
8859
9982
|
pos = convert([ element.xrange[ 1 ], element.defaulty ]);
|
|
@@ -8870,7 +9993,8 @@ class Curve {
|
|
|
8870
9993
|
}
|
|
8871
9994
|
|
|
8872
9995
|
// Draw points
|
|
8873
|
-
for( var i = 0; i < element.value.length; i += 1 )
|
|
9996
|
+
for( var i = 0; i < element.value.length; i += 1 )
|
|
9997
|
+
{
|
|
8874
9998
|
var value = element.value[ i ];
|
|
8875
9999
|
pos = convert( value );
|
|
8876
10000
|
if( selected == i )
|
|
@@ -8882,10 +10006,11 @@ class Curve {
|
|
|
8882
10006
|
ctx.fill();
|
|
8883
10007
|
}
|
|
8884
10008
|
|
|
8885
|
-
if(element.show_samples)
|
|
10009
|
+
if( element.show_samples )
|
|
10010
|
+
{
|
|
8886
10011
|
var samples = element.resample(element.show_samples);
|
|
8887
10012
|
ctx.fillStyle = "#888";
|
|
8888
|
-
for(var i = 0; i < samples.length; i += 1)
|
|
10013
|
+
for( var i = 0; i < samples.length; i += 1)
|
|
8889
10014
|
{
|
|
8890
10015
|
var value = [ i * ((element.xrange[ 1 ] - element.xrange[ 0 ]) / element.show_samples) + element.xrange[ 0 ], samples[ i ] ];
|
|
8891
10016
|
pos = convert(value);
|
|
@@ -8908,7 +10033,8 @@ class Curve {
|
|
|
8908
10033
|
|
|
8909
10034
|
selected = computeSelected( mousex, canvas.height - mousey );
|
|
8910
10035
|
|
|
8911
|
-
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
|
+
{
|
|
8912
10038
|
var v = unconvert([ mousex, canvas.height - mousey ]);
|
|
8913
10039
|
element.value.push( v );
|
|
8914
10040
|
sortValues();
|
|
@@ -8956,7 +10082,8 @@ class Curve {
|
|
|
8956
10082
|
var dy = element.draggable_y ? last_mouse[ 1 ] - mousey : 0;
|
|
8957
10083
|
var delta = unconvert([ -dx, dy ]);
|
|
8958
10084
|
|
|
8959
|
-
if( selected != -1 )
|
|
10085
|
+
if( selected != -1 )
|
|
10086
|
+
{
|
|
8960
10087
|
var minx = element.xrange[ 0 ];
|
|
8961
10088
|
var maxx = element.xrange[ 1 ];
|
|
8962
10089
|
|
|
@@ -9113,7 +10240,7 @@ class Dial {
|
|
|
9113
10240
|
|
|
9114
10241
|
var r = [];
|
|
9115
10242
|
var dx = (element.xrange[1] - element.xrange[ 0 ]) / samples;
|
|
9116
|
-
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)
|
|
9117
10244
|
{
|
|
9118
10245
|
r.push( element.getValueAt(i) );
|
|
9119
10246
|
}
|
|
@@ -9122,15 +10249,16 @@ class Dial {
|
|
|
9122
10249
|
|
|
9123
10250
|
element.addValue = function(v) {
|
|
9124
10251
|
|
|
9125
|
-
for(var i = 0; i < element.value; i++)
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
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 );
|
|
9129
10257
|
redraw();
|
|
9130
10258
|
return;
|
|
9131
10259
|
}
|
|
9132
10260
|
|
|
9133
|
-
element.value.push(v);
|
|
10261
|
+
element.value.push( v );
|
|
9134
10262
|
redraw();
|
|
9135
10263
|
}
|
|
9136
10264
|
|
|
@@ -9150,7 +10278,7 @@ class Dial {
|
|
|
9150
10278
|
|
|
9151
10279
|
var selected = -1;
|
|
9152
10280
|
|
|
9153
|
-
element.redraw = function( o = {} )
|
|
10281
|
+
element.redraw = function( o = {} ) {
|
|
9154
10282
|
|
|
9155
10283
|
if( o.value ) element.value = o.value;
|
|
9156
10284
|
if( o.xrange ) element.xrange = o.xrange;
|
|
@@ -9179,17 +10307,17 @@ class Dial {
|
|
|
9179
10307
|
ctx.moveTo( pos[ 0 ], pos[ 1 ] );
|
|
9180
10308
|
let values = [pos[ 0 ], pos[ 1 ]];
|
|
9181
10309
|
|
|
9182
|
-
for(var i in element.value)
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
values.push(pos[
|
|
9187
|
-
|
|
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 ] );
|
|
9188
10316
|
}
|
|
9189
10317
|
|
|
9190
10318
|
pos = convert([ element.xrange[ 1 ], element.defaulty ]);
|
|
9191
|
-
values.push(pos[ 0 ]);
|
|
9192
|
-
values.push(pos[ 1 ]);
|
|
10319
|
+
values.push( pos[ 0 ] );
|
|
10320
|
+
values.push( pos[ 1 ] );
|
|
9193
10321
|
|
|
9194
10322
|
// Draw points
|
|
9195
10323
|
const center = [0,0];
|
|
@@ -9199,7 +10327,8 @@ class Dial {
|
|
|
9199
10327
|
ctx.arc( pos[ 0 ], pos[ 1 ], 3, 0, Math.PI * 2);
|
|
9200
10328
|
ctx.fill();
|
|
9201
10329
|
|
|
9202
|
-
for( var i = 0; i < element.value.length; i += 1 )
|
|
10330
|
+
for( var i = 0; i < element.value.length; i += 1 )
|
|
10331
|
+
{
|
|
9203
10332
|
var value = element.value[ i ];
|
|
9204
10333
|
pos = convert( value );
|
|
9205
10334
|
if( selected == i )
|
|
@@ -9211,10 +10340,11 @@ class Dial {
|
|
|
9211
10340
|
ctx.fill();
|
|
9212
10341
|
}
|
|
9213
10342
|
|
|
9214
|
-
if(element.show_samples)
|
|
10343
|
+
if( element.show_samples )
|
|
10344
|
+
{
|
|
9215
10345
|
var samples = element.resample(element.show_samples);
|
|
9216
10346
|
ctx.fillStyle = "#888";
|
|
9217
|
-
for(var i = 0; i < samples.length; i += 1)
|
|
10347
|
+
for( var i = 0; i < samples.length; i += 1)
|
|
9218
10348
|
{
|
|
9219
10349
|
var value = [ i * ((element.xrange[ 1 ] - element.xrange[ 0 ]) / element.show_samples) + element.xrange[ 0 ], samples[ i ] ];
|
|
9220
10350
|
pos = convert(value);
|
|
@@ -9237,7 +10367,8 @@ class Dial {
|
|
|
9237
10367
|
|
|
9238
10368
|
selected = computeSelected( mousex, canvas.height - mousey );
|
|
9239
10369
|
|
|
9240
|
-
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
|
+
{
|
|
9241
10372
|
var v = unconvert([ mousex, canvas.height - mousey ]);
|
|
9242
10373
|
element.value.push( v );
|
|
9243
10374
|
sortValues();
|
|
@@ -9285,7 +10416,8 @@ class Dial {
|
|
|
9285
10416
|
var dy = element.draggable_y ? last_mouse[ 1 ] - mousey : 0;
|
|
9286
10417
|
var delta = unconvert([ -dx, dy ]);
|
|
9287
10418
|
|
|
9288
|
-
if( selected != -1 )
|
|
10419
|
+
if( selected != -1 )
|
|
10420
|
+
{
|
|
9289
10421
|
var minx = element.xrange[ 0 ];
|
|
9290
10422
|
var maxx = element.xrange[ 1 ];
|
|
9291
10423
|
|
|
@@ -9393,7 +10525,8 @@ class AssetViewEvent {
|
|
|
9393
10525
|
}
|
|
9394
10526
|
|
|
9395
10527
|
string() {
|
|
9396
|
-
switch(this.type)
|
|
10528
|
+
switch(this.type)
|
|
10529
|
+
{
|
|
9397
10530
|
case AssetViewEvent.NONE: return "assetview_event_none";
|
|
9398
10531
|
case AssetViewEvent.ASSET_SELECTED: return "assetview_event_selected";
|
|
9399
10532
|
case AssetViewEvent.ASSET_DELETED: return "assetview_event_deleted";
|
|
@@ -9747,8 +10880,8 @@ class AssetView {
|
|
|
9747
10880
|
icon: "fa-solid fa-arrows-rotate",
|
|
9748
10881
|
callback: domEl => { this._refreshContent(); }
|
|
9749
10882
|
}
|
|
9750
|
-
], { width: "
|
|
9751
|
-
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" } });
|
|
9752
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"})
|
|
9753
10886
|
this.rightPanel.endLine();
|
|
9754
10887
|
}
|
|
@@ -9874,8 +11007,8 @@ class AssetView {
|
|
|
9874
11007
|
title.innerText = item.id;
|
|
9875
11008
|
itemEl.appendChild( title );
|
|
9876
11009
|
|
|
9877
|
-
if( !that.skipPreview )
|
|
9878
|
-
|
|
11010
|
+
if( !that.skipPreview )
|
|
11011
|
+
{
|
|
9879
11012
|
let preview = null;
|
|
9880
11013
|
const hasImage = item.src && (['png', 'jpg'].indexOf( getExtension( item.src ) ) > -1 || item.src.includes("data:image/") ); // Support b64 image as src
|
|
9881
11014
|
|
|
@@ -9902,7 +11035,8 @@ class AssetView {
|
|
|
9902
11035
|
var newEmSize = charsPerLine / newLength;
|
|
9903
11036
|
var textBaseSize = 64;
|
|
9904
11037
|
|
|
9905
|
-
if(newEmSize < 1)
|
|
11038
|
+
if( newEmSize < 1 )
|
|
11039
|
+
{
|
|
9906
11040
|
var newFontSize = newEmSize * textBaseSize;
|
|
9907
11041
|
textEl.style.fontSize = newFontSize + "px";
|
|
9908
11042
|
preview.style.paddingTop = "calc(50% - " + (textEl.offsetHeight * 0.5 + 10) + "px)"
|
|
@@ -10131,7 +11265,8 @@ class AssetView {
|
|
|
10131
11265
|
|
|
10132
11266
|
this.currentData.push( item );
|
|
10133
11267
|
|
|
10134
|
-
if(i == (num_files - 1))
|
|
11268
|
+
if( i == (num_files - 1) )
|
|
11269
|
+
{
|
|
10135
11270
|
this._refreshContent();
|
|
10136
11271
|
if( !this.skipBrowser )
|
|
10137
11272
|
this.tree.refresh();
|
|
@@ -10183,7 +11318,7 @@ class AssetView {
|
|
|
10183
11318
|
this.currentData.splice( idx, 1 );
|
|
10184
11319
|
this._refreshContent( this.searchValue, this.filter );
|
|
10185
11320
|
|
|
10186
|
-
if(this.onevent)
|
|
11321
|
+
if( this.onevent)
|
|
10187
11322
|
{
|
|
10188
11323
|
const event = new AssetViewEvent( AssetViewEvent.ASSET_DELETED, item );
|
|
10189
11324
|
this.onevent( event );
|
|
@@ -10259,7 +11394,7 @@ Object.assign(LX, {
|
|
|
10259
11394
|
xhr.onload = function(load)
|
|
10260
11395
|
{
|
|
10261
11396
|
var response = this.response;
|
|
10262
|
-
if(this.status != 200)
|
|
11397
|
+
if( this.status != 200)
|
|
10263
11398
|
{
|
|
10264
11399
|
var err = "Error " + this.status;
|
|
10265
11400
|
if(request.error)
|
|
@@ -10307,7 +11442,7 @@ Object.assign(LX, {
|
|
|
10307
11442
|
var data = new FormData();
|
|
10308
11443
|
if( request.data )
|
|
10309
11444
|
{
|
|
10310
|
-
for(var i in request.data)
|
|
11445
|
+
for( var i in request.data)
|
|
10311
11446
|
data.append(i,request.data[i]);
|
|
10312
11447
|
}
|
|
10313
11448
|
|
|
@@ -10368,7 +11503,7 @@ Object.assign(LX, {
|
|
|
10368
11503
|
var size = total;
|
|
10369
11504
|
var loaded_scripts = [];
|
|
10370
11505
|
|
|
10371
|
-
for(var i in url)
|
|
11506
|
+
for( var i in url)
|
|
10372
11507
|
{
|
|
10373
11508
|
var script = document.createElement('script');
|
|
10374
11509
|
script.num = i;
|
|
@@ -10493,6 +11628,18 @@ Element.prototype.getParentArea = function() {
|
|
|
10493
11628
|
}
|
|
10494
11629
|
}
|
|
10495
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
|
+
|
|
10496
11643
|
LX.UTILS = {
|
|
10497
11644
|
getTime() { return new Date().getTime() },
|
|
10498
11645
|
compareThreshold( v, p, n, t ) { return Math.abs(v - p) >= t || Math.abs(v - n) >= t },
|
|
@@ -10532,17 +11679,19 @@ LX.UTILS = {
|
|
|
10532
11679
|
drawSpline( ctx, pts, t ) {
|
|
10533
11680
|
|
|
10534
11681
|
ctx.save();
|
|
10535
|
-
var cp=[]; // array of control points, as x0,y0,x1,y1,...
|
|
10536
|
-
var n=pts.length;
|
|
11682
|
+
var cp = []; // array of control points, as x0,y0,x1,y1,...
|
|
11683
|
+
var n = pts.length;
|
|
10537
11684
|
|
|
10538
11685
|
// Draw an open curve, not connected at the ends
|
|
10539
|
-
for(var i=0;i<n-4;i+=2)
|
|
10540
|
-
|
|
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));
|
|
10541
11689
|
}
|
|
10542
11690
|
|
|
10543
|
-
for(var i=2;i<pts.length-5;i+=2)
|
|
11691
|
+
for( var i = 2; i < ( pts.length - 5 ); i += 2 )
|
|
11692
|
+
{
|
|
10544
11693
|
ctx.beginPath();
|
|
10545
|
-
ctx.moveTo(pts[i],pts[i+1]);
|
|
11694
|
+
ctx.moveTo(pts[i], pts[i+1]);
|
|
10546
11695
|
ctx.bezierCurveTo(cp[2*i-2],cp[2*i-1],cp[2*i],cp[2*i+1],pts[i+2],pts[i+3]);
|
|
10547
11696
|
ctx.stroke();
|
|
10548
11697
|
ctx.closePath();
|
|
@@ -10550,14 +11699,14 @@ LX.UTILS = {
|
|
|
10550
11699
|
|
|
10551
11700
|
// For open curves the first and last arcs are simple quadratics.
|
|
10552
11701
|
ctx.beginPath();
|
|
10553
|
-
ctx.moveTo(pts[0],pts[1]);
|
|
10554
|
-
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 ]);
|
|
10555
11704
|
ctx.stroke();
|
|
10556
11705
|
ctx.closePath();
|
|
10557
11706
|
|
|
10558
11707
|
ctx.beginPath();
|
|
10559
|
-
ctx.moveTo(pts[n-2],pts[n-1]);
|
|
10560
|
-
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 ]);
|
|
10561
11710
|
ctx.stroke();
|
|
10562
11711
|
ctx.closePath();
|
|
10563
11712
|
|