lexgui 0.4.0 → 0.4.1

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/lexgui.js CHANGED
@@ -12,7 +12,7 @@ console.warn( 'Script _build/lexgui.js_ is depracated and will be removed soon.
12
12
  */
13
13
 
14
14
  var LX = {
15
- version: "0.4.0",
15
+ version: "0.4.1",
16
16
  ready: false,
17
17
  components: [], // Specific pre-build components
18
18
  signals: {}, // Events and triggers
@@ -24,13 +24,13 @@ LX.MOUSE_LEFT_CLICK = 0;
24
24
  LX.MOUSE_MIDDLE_CLICK = 1;
25
25
  LX.MOUSE_RIGHT_CLICK = 2;
26
26
 
27
- LX.MOUSE_DOUBLE_CLICK = 2;
28
- LX.MOUSE_TRIPLE_CLICK = 3;
27
+ LX.MOUSE_DOUBLE_CLICK = 2;
28
+ LX.MOUSE_TRIPLE_CLICK = 3;
29
29
 
30
- LX.CURVE_MOVEOUT_CLAMP = 0;
30
+ LX.CURVE_MOVEOUT_CLAMP = 0;
31
31
  LX.CURVE_MOVEOUT_DELETE = 1;
32
32
 
33
- LX.DRAGGABLE_Z_INDEX = 101;
33
+ LX.DRAGGABLE_Z_INDEX = 101;
34
34
 
35
35
  function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
36
36
  function round( number, precision ) { return precision == 0 ? Math.floor( number ) : +(( number ).toFixed( precision ?? 2 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' )); }
@@ -930,7 +930,19 @@ function init( options = { } )
930
930
  this.container = document.getElementById( options.container );
931
931
  }
932
932
 
933
- document.documentElement.setAttribute( "data-strictVP", ( options.strictViewport ?? true ) ? "true" : "false" );
933
+ this.usingStrictViewport = options.strictViewport ?? true;
934
+ document.documentElement.setAttribute( "data-strictVP", ( this.usingStrictViewport ) ? "true" : "false" );
935
+
936
+ if( !this.usingStrictViewport )
937
+ {
938
+ document.addEventListener( "scroll", e => {
939
+ // Get all active menuboxes
940
+ const mbs = document.body.querySelectorAll( ".lexmenubox" );
941
+ mbs.forEach( ( mb ) => {
942
+ mb._updatePosition();
943
+ } );
944
+ } );
945
+ }
934
946
 
935
947
  this.commandbar = _createCommandbar( this.container );
936
948
 
@@ -2067,7 +2079,7 @@ class Area {
2067
2079
  }
2068
2080
 
2069
2081
  // Generate DOM elements after adding all entries
2070
- sidebar._build();
2082
+ sidebar.update();
2071
2083
 
2072
2084
  LX.menubars.push( sidebar );
2073
2085
 
@@ -2677,6 +2689,195 @@ class Menubar {
2677
2689
  this.shorts = { };
2678
2690
  }
2679
2691
 
2692
+ _resetMenubar() {
2693
+
2694
+ // Menu entries are in the menubar..
2695
+ this.root.querySelectorAll(".lexmenuentry").forEach( _entry => {
2696
+ _entry.classList.remove( 'selected' );
2697
+ _entry.built = false;
2698
+ } );
2699
+
2700
+ // Menuboxes are in the root area!
2701
+ LX.root.querySelectorAll(".lexmenubox").forEach(e => e.remove());
2702
+
2703
+ // Next time we need to click again
2704
+ this.focused = false;
2705
+ }
2706
+
2707
+ _createSubmenu( o, k, c, d ) {
2708
+
2709
+ let menuElement = document.createElement('div');
2710
+ menuElement.className = "lexmenubox";
2711
+ menuElement.tabIndex = "0";
2712
+ c.currentMenu = menuElement;
2713
+ menuElement.parentEntry = c;
2714
+
2715
+ const isSubMenu = c.classList.contains( "lexmenuboxentry" );
2716
+ if( isSubMenu )
2717
+ {
2718
+ menuElement.dataset[ "submenu" ] = true;
2719
+ }
2720
+
2721
+ menuElement._updatePosition = () => {
2722
+
2723
+ // Remove transitions for this change..
2724
+ const transition = menuElement.style.transition;
2725
+ menuElement.style.transition = "none";
2726
+ flushCss( menuElement );
2727
+
2728
+ doAsync( () => {
2729
+ let rect = c.getBoundingClientRect();
2730
+ rect.x += document.scrollingElement.scrollLeft;
2731
+ rect.y += document.scrollingElement.scrollTop;
2732
+ menuElement.style.left = ( isSubMenu ? ( rect.x + rect.width ) : rect.x ) + "px";
2733
+ menuElement.style.top = ( isSubMenu ? rect.y : ( ( rect.y + rect.height ) ) - 4 ) + "px";
2734
+
2735
+ menuElement.style.transition = transition;
2736
+ } );
2737
+ };
2738
+
2739
+ menuElement._updatePosition();
2740
+
2741
+ doAsync( () => {
2742
+ menuElement.dataset[ "open" ] = true;
2743
+ }, 10 );
2744
+
2745
+ LX.root.appendChild( menuElement );
2746
+
2747
+ for( var i = 0; i < o[ k ].length; ++i )
2748
+ {
2749
+ const subitem = o[ k ][ i ];
2750
+ const subkey = Object.keys( subitem )[ 0 ];
2751
+ const hasSubmenu = subitem[ subkey ].length;
2752
+ const isCheckbox = subitem[ 'type' ] == 'checkbox';
2753
+ let subentry = document.createElement('div');
2754
+ subentry.className = "lexmenuboxentry";
2755
+ subentry.className += (i == o[k].length - 1 ? " last" : "") + ( subitem.disabled ? " disabled" : "" );
2756
+
2757
+ if( subkey == '' )
2758
+ {
2759
+ subentry.className = " lexseparator";
2760
+ }
2761
+ else
2762
+ {
2763
+ subentry.id = subkey;
2764
+ let subentrycont = document.createElement('div');
2765
+ subentrycont.innerHTML = "";
2766
+ subentrycont.classList = "lexmenuboxentrycontainer";
2767
+ subentry.appendChild(subentrycont);
2768
+ const icon = this.icons[ subkey ];
2769
+ if( isCheckbox )
2770
+ {
2771
+ subentrycont.innerHTML += "<input type='checkbox' >";
2772
+ }
2773
+ else if( icon )
2774
+ {
2775
+ subentrycont.innerHTML += "<a class='" + icon + " fa-sm'></a>";
2776
+ }
2777
+ else
2778
+ {
2779
+ subentrycont.innerHTML += "<a class='fa-solid fa-sm noicon'></a>";
2780
+ subentrycont.classList.add( "noicon" );
2781
+
2782
+ }
2783
+ subentrycont.innerHTML += "<div class='lexentryname'>" + subkey + "</div>";
2784
+ }
2785
+
2786
+ let checkboxInput = subentry.querySelector('input');
2787
+ if( checkboxInput )
2788
+ {
2789
+ checkboxInput.checked = subitem.checked ?? false;
2790
+ checkboxInput.addEventListener('change', e => {
2791
+ subitem.checked = checkboxInput.checked;
2792
+ const f = subitem[ 'callback' ];
2793
+ if( f )
2794
+ {
2795
+ f.call( this, subitem.checked, subkey, subentry );
2796
+ this._resetMenubar();
2797
+ }
2798
+ e.stopPropagation();
2799
+ e.stopImmediatePropagation();
2800
+ })
2801
+ }
2802
+
2803
+ menuElement.appendChild( subentry );
2804
+
2805
+ // Nothing more for separators
2806
+ if( subkey == '' )
2807
+ {
2808
+ continue;
2809
+ }
2810
+
2811
+ menuElement.addEventListener('keydown', e => {
2812
+ e.preventDefault();
2813
+ let short = this.shorts[ subkey ];
2814
+ if(!short) return;
2815
+ // check if it's a letter or other key
2816
+ short = short.length == 1 ? short.toLowerCase() : short;
2817
+ if( short == e.key )
2818
+ {
2819
+ subentry.click()
2820
+ }
2821
+ });
2822
+
2823
+ // Add callback
2824
+ subentry.addEventListener("click", e => {
2825
+ if( checkboxInput )
2826
+ {
2827
+ subitem.checked = !subitem.checked;
2828
+ }
2829
+ const f = subitem[ 'callback' ];
2830
+ if( f )
2831
+ {
2832
+ f.call( this, checkboxInput ? subitem.checked : subkey, checkboxInput ? subkey : subentry );
2833
+ this._resetMenubar();
2834
+ }
2835
+ e.stopPropagation();
2836
+ e.stopImmediatePropagation();
2837
+ });
2838
+
2839
+ // Add icon if has submenu, else check for shortcut
2840
+ if( !hasSubmenu)
2841
+ {
2842
+ if( this.shorts[ subkey ] )
2843
+ {
2844
+ let shortEl = document.createElement('div');
2845
+ shortEl.className = "lexentryshort";
2846
+ shortEl.innerText = this.shorts[ subkey ];
2847
+ subentry.appendChild( shortEl );
2848
+ }
2849
+ continue;
2850
+ }
2851
+
2852
+ let submenuIcon = document.createElement('a');
2853
+ submenuIcon.className = "fa-solid fa-angle-right fa-xs";
2854
+ subentry.appendChild( submenuIcon );
2855
+
2856
+ subentry.addEventListener("mouseover", e => {
2857
+ if( subentry.built )
2858
+ {
2859
+ return;
2860
+ }
2861
+ subentry.built = true;
2862
+ this._createSubmenu( subitem, subkey, subentry, ++d );
2863
+ e.stopPropagation();
2864
+ });
2865
+
2866
+ subentry.addEventListener("mouseleave", e => {
2867
+ if( subentry.currentMenu && ( subentry.currentMenu != e.toElement ) )
2868
+ {
2869
+ d = -1; // Reset depth
2870
+ delete subentry.built;
2871
+ subentry.currentMenu.remove();
2872
+ delete subentry.currentMenu;
2873
+ }
2874
+ });
2875
+ }
2876
+
2877
+ // Set final width
2878
+ menuElement.style.width = menuElement.offsetWidth + "px";
2879
+ }
2880
+
2680
2881
  /**
2681
2882
  * @method add
2682
2883
  * @param {Object} options:
@@ -2780,176 +2981,11 @@ class Menubar {
2780
2981
  }
2781
2982
  }
2782
2983
 
2783
- const _resetMenubar = function() {
2784
- // Menu entries are in the menubar..
2785
- that.root.querySelectorAll(".lexmenuentry").forEach( _entry => {
2786
- _entry.classList.remove( 'selected' );
2787
- _entry.built = false;
2788
- } );
2789
- // Menuboxes are in the root area!
2790
- LX.root.querySelectorAll(".lexmenubox").forEach(e => e.remove());
2791
- // Next time we need to click again
2792
- that.focused = false;
2793
- };
2794
-
2795
- const create_submenu = function( o, k, c, d ) {
2796
-
2797
- let menuElement = document.createElement('div');
2798
- menuElement.className = "lexmenubox";
2799
- menuElement.tabIndex = "0";
2800
- c.currentMenu = menuElement;
2801
- const isSubMenu = c.classList.contains( "lexmenuboxentry" );
2802
- if( isSubMenu ) menuElement.dataset[ "submenu" ] = true;
2803
- var rect = c.getBoundingClientRect();
2804
- menuElement.style.left = ( isSubMenu ? ( rect.x + rect.width ) : rect.left ) + "px";
2805
- menuElement.style.top = ( isSubMenu ? rect.y : rect.bottom - 4 ) + "px";
2806
- rect = menuElement.getBoundingClientRect();
2807
-
2808
- doAsync( () => {
2809
- menuElement.dataset[ "open" ] = true;
2810
- }, 10 );
2811
-
2812
- LX.root.appendChild( menuElement );
2813
-
2814
- for( var i = 0; i < o[ k ].length; ++i )
2815
- {
2816
- const subitem = o[ k ][ i ];
2817
- const subkey = Object.keys( subitem )[ 0 ];
2818
- const hasSubmenu = subitem[ subkey ].length;
2819
- const isCheckbox = subitem[ 'type' ] == 'checkbox';
2820
- let subentry = document.createElement('div');
2821
- subentry.className = "lexmenuboxentry";
2822
- subentry.className += (i == o[k].length - 1 ? " last" : "") + ( subitem.disabled ? " disabled" : "" );
2823
-
2824
- if( subkey == '' )
2825
- {
2826
- subentry.className = " lexseparator";
2827
- }
2828
- else
2829
- {
2830
- subentry.id = subkey;
2831
- let subentrycont = document.createElement('div');
2832
- subentrycont.innerHTML = "";
2833
- subentrycont.classList = "lexmenuboxentrycontainer";
2834
- subentry.appendChild(subentrycont);
2835
- const icon = that.icons[ subkey ];
2836
- if( isCheckbox )
2837
- {
2838
- subentrycont.innerHTML += "<input type='checkbox' >";
2839
- }
2840
- else if( icon )
2841
- {
2842
- subentrycont.innerHTML += "<a class='" + icon + " fa-sm'></a>";
2843
- }
2844
- else
2845
- {
2846
- subentrycont.innerHTML += "<a class='fa-solid fa-sm noicon'></a>";
2847
- subentrycont.classList.add( "noicon" );
2848
-
2849
- }
2850
- subentrycont.innerHTML += "<div class='lexentryname'>" + subkey + "</div>";
2851
- }
2852
-
2853
- let checkboxInput = subentry.querySelector('input');
2854
- if( checkboxInput )
2855
- {
2856
- checkboxInput.checked = subitem.checked ?? false;
2857
- checkboxInput.addEventListener('change', e => {
2858
- subitem.checked = checkboxInput.checked;
2859
- const f = subitem[ 'callback' ];
2860
- if( f )
2861
- {
2862
- f.call( this, subitem.checked, subkey, subentry );
2863
- _resetMenubar();
2864
- }
2865
- e.stopPropagation();
2866
- e.stopImmediatePropagation();
2867
- })
2868
- }
2869
-
2870
- menuElement.appendChild( subentry );
2871
-
2872
- // Nothing more for separators
2873
- if( subkey == '' )
2874
- {
2875
- continue;
2876
- }
2877
-
2878
- menuElement.addEventListener('keydown', function(e) {
2879
- e.preventDefault();
2880
- let short = that.shorts[ subkey ];
2881
- if(!short) return;
2882
- // check if it's a letter or other key
2883
- short = short.length == 1 ? short.toLowerCase() : short;
2884
- if( short == e.key )
2885
- {
2886
- subentry.click()
2887
- }
2888
- });
2889
-
2890
- // Add callback
2891
- subentry.addEventListener("click", e => {
2892
- if( checkboxInput )
2893
- {
2894
- subitem.checked = !subitem.checked;
2895
- }
2896
- const f = subitem[ 'callback' ];
2897
- if( f )
2898
- {
2899
- f.call( this, checkboxInput ? subitem.checked : subkey, checkboxInput ? subkey : subentry );
2900
- _resetMenubar();
2901
- }
2902
- e.stopPropagation();
2903
- e.stopImmediatePropagation();
2904
- });
2905
-
2906
- // Add icon if has submenu, else check for shortcut
2907
- if( !hasSubmenu)
2908
- {
2909
- if( that.shorts[ subkey ] )
2910
- {
2911
- let shortEl = document.createElement('div');
2912
- shortEl.className = "lexentryshort";
2913
- shortEl.innerText = that.shorts[ subkey ];
2914
- subentry.appendChild( shortEl );
2915
- }
2916
- continue;
2917
- }
2918
-
2919
- let submenuIcon = document.createElement('a');
2920
- submenuIcon.className = "fa-solid fa-angle-right fa-xs";
2921
- subentry.appendChild( submenuIcon );
2922
-
2923
- subentry.addEventListener("mouseover", e => {
2924
- if( subentry.built )
2925
- {
2926
- return;
2927
- }
2928
- subentry.built = true;
2929
- create_submenu( subitem, subkey, subentry, ++d );
2930
- e.stopPropagation();
2931
- });
2932
-
2933
- subentry.addEventListener("mouseleave", (e) => {
2934
- if( subentry.currentMenu && ( subentry.currentMenu != e.toElement ) )
2935
- {
2936
- d = -1; // Reset depth
2937
- delete subentry.built;
2938
- subentry.currentMenu.remove();
2939
- delete subentry.currentMenu;
2940
- }
2941
- });
2942
- }
2943
-
2944
- // Set final width
2945
- menuElement.style.width = menuElement.offsetWidth + "px";
2946
- };
2947
-
2948
2984
  const _showEntry = () => {
2949
- _resetMenubar();
2985
+ this._resetMenubar();
2950
2986
  entry.classList.add( "selected" );
2951
2987
  entry.built = true;
2952
- create_submenu( item, key, entry, -1 );
2988
+ this._createSubmenu( item, key, entry, -1 );
2953
2989
  };
2954
2990
 
2955
2991
  entry.addEventListener("click", () => {
@@ -2980,7 +3016,7 @@ class Menubar {
2980
3016
  return;
2981
3017
  }
2982
3018
 
2983
- _resetMenubar();
3019
+ this._resetMenubar();
2984
3020
  });
2985
3021
  }
2986
3022
  }
@@ -3235,20 +3271,19 @@ class SideBar {
3235
3271
 
3236
3272
  /**
3237
3273
  * @param {Object} options
3238
- * inset: TODO
3239
- * filter: TODO
3274
+ * filter: Add search bar to filter entries [false]
3240
3275
  * skipHeader: Do not use sidebar header [false]
3241
3276
  * headerImg: Image to be shown as avatar
3242
3277
  * headerIcon: Icon to be shown as avatar (from LX.ICONS)
3243
- * headerTitle
3244
- * headerSubtitle
3278
+ * headerTitle: Header title
3279
+ * headerSubtitle: Header subtitle
3245
3280
  * skipFooter: Do not use sidebar footer [false]
3246
3281
  * footerImg: Image to be shown as avatar
3247
3282
  * footerIcon: Icon to be shown as avatar (from LX.ICONS)
3248
- * footerTitle
3249
- * footerSubtitle
3283
+ * footerTitle: Footer title
3284
+ * footerSubtitle: Footer subtitle
3250
3285
  * collapsable: Sidebar can toggle between collapsed/expanded [true]
3251
- * collapseToIcons: When Sidebar collapses, icons remains visible [true]
3286
+ * collapseToIcons: When Sidebar collapses, icons remains visible [true]
3252
3287
  * onHeaderPressed: Function to call when header is pressed
3253
3288
  * onFooterPressed: Function to call when footer is pressed
3254
3289
  */
@@ -3258,12 +3293,12 @@ class SideBar {
3258
3293
  this.root = document.createElement( 'div' );
3259
3294
  this.root.className = "lexsidebar";
3260
3295
 
3261
- window.sidebar = this;
3262
-
3263
3296
  this.collapsable = options.collapsable ?? true;
3264
- this.collapseWidth = ( options.collapseToIcons ?? true ) ? "58px" : "0px";
3297
+ this._collapseWidth = ( options.collapseToIcons ?? true ) ? "58px" : "0px";
3265
3298
  this.collapsed = false;
3266
3299
 
3300
+ this.filterString = "";
3301
+
3267
3302
  doAsync( () => {
3268
3303
 
3269
3304
  this.root.parentElement.ogWidth = this.root.parentElement.style.width;
@@ -3276,7 +3311,7 @@ class SideBar {
3276
3311
  }
3277
3312
  });
3278
3313
 
3279
- }, 100 );
3314
+ }, 10 );
3280
3315
 
3281
3316
  // This account for header, footer and all inner paddings
3282
3317
  let contentOffset = 32;
@@ -3346,6 +3381,19 @@ class SideBar {
3346
3381
  contentOffset += 52;
3347
3382
  }
3348
3383
 
3384
+ // Entry filter
3385
+ if( !( options.filter ?? false ) )
3386
+ {
3387
+ const panel = new Panel();
3388
+ panel.addText(null, "", (value, event) => {
3389
+ this.filterString = value;
3390
+ this.update();
3391
+ }, { placeholder: "Search...", icon: "fa-solid fa-magnifying-glass" });
3392
+ this.filter = panel.root.childNodes[ 0 ];
3393
+ this.root.appendChild( this.filter );
3394
+ contentOffset += 31;
3395
+ }
3396
+
3349
3397
  // Content
3350
3398
  {
3351
3399
  this.content = document.createElement( 'div' );
@@ -3413,21 +3461,22 @@ class SideBar {
3413
3461
 
3414
3462
  /**
3415
3463
  * @method toggleCollapsed
3464
+ * @param {Boolean} force: Force collapsed state
3416
3465
  */
3417
3466
 
3418
- toggleCollapsed() {
3467
+ toggleCollapsed( force ) {
3419
3468
 
3420
3469
  if( !this.collapsable )
3421
3470
  {
3422
3471
  return;
3423
3472
  }
3424
3473
 
3425
- this.collapsed = !this.collapsed;
3474
+ this.collapsed = force ?? !this.collapsed;
3426
3475
 
3427
3476
  if( this.collapsed )
3428
3477
  {
3429
3478
  this.root.classList.add( "collapsing" );
3430
- this.root.parentElement.style.width = this.collapseWidth;
3479
+ this.root.parentElement.style.width = this._collapseWidth;
3431
3480
  }
3432
3481
  else
3433
3482
  {
@@ -3436,6 +3485,11 @@ class SideBar {
3436
3485
  this.root.parentElement.style.width = this.root.parentElement.ogWidth;
3437
3486
  }
3438
3487
 
3488
+ if( !this.resizeObserver )
3489
+ {
3490
+ throw( "Wait until ResizeObserver has been created!" );
3491
+ }
3492
+
3439
3493
  this.resizeObserver.observe( this.root.parentElement );
3440
3494
 
3441
3495
  doAsync( () => {
@@ -3494,7 +3548,6 @@ class SideBar {
3494
3548
  const lastPath = tokens[tokens.length - 1];
3495
3549
  this.icons[ lastPath ] = options.icon;
3496
3550
 
3497
-
3498
3551
  let idx = 0;
3499
3552
 
3500
3553
  const _insertEntry = ( token, list ) => {
@@ -3549,10 +3602,19 @@ class SideBar {
3549
3602
  if( !entry )
3550
3603
  return;
3551
3604
 
3552
- entry.domEl.click();
3605
+ entry.dom.click();
3553
3606
  }
3554
3607
 
3555
- _build() {
3608
+ update() {
3609
+
3610
+ // Reset first
3611
+
3612
+ this.content.innerHTML = "";
3613
+
3614
+ for( let item of this.items )
3615
+ {
3616
+ delete item.dom;
3617
+ }
3556
3618
 
3557
3619
  for( let item of this.items )
3558
3620
  {
@@ -3565,12 +3627,18 @@ class SideBar {
3565
3627
  }
3566
3628
 
3567
3629
  let key = Object.keys( item )[ 0 ];
3630
+
3631
+ if( this.filterString.length && !key.toLowerCase().includes( this.filterString.toLowerCase() ) )
3632
+ {
3633
+ continue;
3634
+ }
3635
+
3568
3636
  let pKey = key.replace( /\s/g, '' ).replaceAll( '.', '' );
3569
3637
  let currentGroup = null;
3570
3638
 
3571
3639
  let entry = document.createElement( 'div' );
3572
3640
  entry.className = "lexsidebarentry " + ( options.className ?? "" );
3573
- entry.id = pKey;
3641
+ entry.id = item.name = pKey;
3574
3642
 
3575
3643
  if( item.group )
3576
3644
  {
@@ -3641,7 +3709,7 @@ class SideBar {
3641
3709
 
3642
3710
  let itemDom = document.createElement( 'div' );
3643
3711
  entry.appendChild( itemDom );
3644
- item.dom = itemDom;
3712
+ item.dom = entry;
3645
3713
 
3646
3714
  if( options.type == "checkbox" )
3647
3715
  {
@@ -3753,12 +3821,17 @@ class SideBar {
3753
3821
  this.content.appendChild( subentryContainer );
3754
3822
  }
3755
3823
 
3756
- for( var i = 0; i < item[ key ].length; ++i )
3824
+ for( let i = 0; i < item[ key ].length; ++i )
3757
3825
  {
3758
3826
  const subitem = item[ key ][ i ];
3759
3827
  const suboptions = subitem.options ?? {};
3760
3828
  const subkey = Object.keys( subitem )[ 0 ];
3761
3829
 
3830
+ if( this.filterString.length && !subkey.toLowerCase().includes( this.filterString.toLowerCase() ) )
3831
+ {
3832
+ continue;
3833
+ }
3834
+
3762
3835
  let subentry = document.createElement( 'div' );
3763
3836
  subentry.innerHTML = `<span>${ subkey }</span>`;
3764
3837
 
@@ -5289,7 +5362,7 @@ class Panel {
5289
5362
 
5290
5363
  var resolve = ( function( val, event ) {
5291
5364
 
5292
- if( !widget.valid() )
5365
+ if( !widget.valid() || ( this._lastValueTriggered == val ) )
5293
5366
  {
5294
5367
  return;
5295
5368
  }
@@ -5302,6 +5375,8 @@ class Panel {
5302
5375
  this._trigger( new IEvent( name, val, event ), callback );
5303
5376
  }
5304
5377
 
5378
+ this._lastValueTriggered = val;
5379
+
5305
5380
  }).bind( this );
5306
5381
 
5307
5382
  const trigger = options.trigger ?? 'default';
@@ -9567,7 +9642,7 @@ class ContextMenu {
9567
9642
  }
9568
9643
  }
9569
9644
 
9570
- _adjust_position( div, margin, useAbsolute = false ) {
9645
+ _adjustPosition( div, margin, useAbsolute = false ) {
9571
9646
 
9572
9647
  let rect = div.getBoundingClientRect();
9573
9648
 
@@ -9608,7 +9683,7 @@ class ContextMenu {
9608
9683
  }
9609
9684
  }
9610
9685
 
9611
- _create_submenu( o, k, c, d ) {
9686
+ _createSubmenu( o, k, c, d ) {
9612
9687
 
9613
9688
  this.root.querySelectorAll( ".lexcontextmenu" ).forEach( cm => cm.remove() );
9614
9689
 
@@ -9620,7 +9695,7 @@ class ContextMenu {
9620
9695
  {
9621
9696
  const subitem = o[ k ][ i ];
9622
9697
  const subkey = Object.keys( subitem )[ 0 ];
9623
- this._create_entry(subitem, subkey, contextmenu, d);
9698
+ this._createEntry(subitem, subkey, contextmenu, d);
9624
9699
  }
9625
9700
 
9626
9701
  var rect = c.getBoundingClientRect();
@@ -9628,10 +9703,10 @@ class ContextMenu {
9628
9703
  contextmenu.style.marginTop = 3.5 - c.offsetHeight + "px";
9629
9704
 
9630
9705
  // Set final width
9631
- this._adjust_position( contextmenu, 6, true );
9706
+ this._adjustPosition( contextmenu, 6, true );
9632
9707
  }
9633
9708
 
9634
- _create_entry( o, k, c, d ) {
9709
+ _createEntry( o, k, c, d ) {
9635
9710
 
9636
9711
  const hasSubmenu = o[ k ].length;
9637
9712
  let entry = document.createElement('div');
@@ -9676,7 +9751,7 @@ class ContextMenu {
9676
9751
  return;
9677
9752
 
9678
9753
  if( LX.OPEN_CONTEXTMENU_ENTRY == 'click' )
9679
- this._create_submenu( o, k, entry, ++d );
9754
+ this._createSubmenu( o, k, entry, ++d );
9680
9755
  });
9681
9756
 
9682
9757
  if( !hasSubmenu )
@@ -9692,7 +9767,7 @@ class ContextMenu {
9692
9767
  if(entry.built)
9693
9768
  return;
9694
9769
  entry.built = true;
9695
- this._create_submenu( o, k, entry, ++d );
9770
+ this._createSubmenu( o, k, entry, ++d );
9696
9771
  e.stopPropagation();
9697
9772
  });
9698
9773
  }
@@ -9704,7 +9779,7 @@ class ContextMenu {
9704
9779
  }
9705
9780
 
9706
9781
  onCreate() {
9707
- doAsync( () => this._adjust_position( this.root, 6 ) );
9782
+ doAsync( () => this._adjustPosition( this.root, 6 ) );
9708
9783
  }
9709
9784
 
9710
9785
  add( path, options = {} ) {
@@ -9734,13 +9809,13 @@ class ContextMenu {
9734
9809
 
9735
9810
  if( found )
9736
9811
  {
9737
- insert( tokens[idx++], found );
9812
+ insert( tokens[ idx++ ], found );
9738
9813
  }
9739
9814
  else
9740
9815
  {
9741
9816
  let item = {};
9742
9817
  item[ token ] = [];
9743
- const nextToken = tokens[idx++];
9818
+ const nextToken = tokens[ idx++ ];
9744
9819
  // Check if last token -> add callback
9745
9820
  if( !nextToken )
9746
9821
  {
@@ -9760,13 +9835,15 @@ class ContextMenu {
9760
9835
 
9761
9836
  const setParent = _item => {
9762
9837
 
9763
- let key = Object.keys(_item)[0];
9838
+ let key = Object.keys( _item )[ 0 ];
9764
9839
  let children = _item[ key ];
9765
9840
 
9766
- if(!children.length)
9841
+ if( !children.length )
9842
+ {
9767
9843
  return;
9844
+ }
9768
9845
 
9769
- if(children.find( c => Object.keys(c)[0] == key ) == null)
9846
+ if( children.find( c => Object.keys(c)[0] == key ) == null )
9770
9847
  {
9771
9848
  const parent = {};
9772
9849
  parent[ key ] = [];
@@ -9776,14 +9853,18 @@ class ContextMenu {
9776
9853
 
9777
9854
  for( var child of _item[ key ] )
9778
9855
  {
9779
- let k = Object.keys(child)[0];
9780
- for( var i = 0; i < child[k].length; ++i )
9781
- setParent(child);
9856
+ let k = Object.keys( child )[ 0 ];
9857
+ for( var i = 0; i < child[ k ].length; ++i )
9858
+ {
9859
+ setParent( child );
9860
+ }
9782
9861
  }
9783
9862
  };
9784
9863
 
9785
9864
  for( let item of this.items )
9786
- setParent(item);
9865
+ {
9866
+ setParent( item );
9867
+ }
9787
9868
 
9788
9869
  // Create elements
9789
9870
 
@@ -9793,9 +9874,11 @@ class ContextMenu {
9793
9874
  let pKey = "eId" + getSupportedDOMName( key );
9794
9875
 
9795
9876
  // Item already created
9796
- const id = "#" + (item.id ?? pKey);
9797
- if( !this.root.querySelector(id) )
9798
- this._create_entry(item, key, this.root, -1);
9877
+ const id = "#" + ( item.id ?? pKey );
9878
+ if( !this.root.querySelector( id ) )
9879
+ {
9880
+ this._createEntry( item, key, this.root, -1 );
9881
+ }
9799
9882
  }
9800
9883
  }
9801
9884