lexgui 0.1.37 → 0.1.40

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 = global.LX = {
15
- version: "0.1.37",
15
+ version: "0.1.40",
16
16
  ready: false,
17
17
  components: [], // specific pre-build components
18
18
  signals: {} // events and triggers
@@ -30,6 +30,11 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
30
30
 
31
31
  function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
32
32
  function round( number, precision ) { return +(( number ).toFixed( precision ?? 2 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' )); }
33
+ function remapRange( oldValue, oldMin, oldMax, newMin, newMax ) { return ((( oldValue - oldMin ) * ( newMax - newMin )) / ( oldMax - oldMin )) + newMin; }
34
+
35
+ LX.clamp = clamp;
36
+ LX.round = round;
37
+ LX.remapRange = remapRange;
33
38
 
34
39
  function getSupportedDOMName( string )
35
40
  {
@@ -106,6 +111,18 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
106
111
 
107
112
  LX.rgbToHex = rgbToHex;
108
113
 
114
+ function measureRealWidth( value, paddingPlusMargin = 8 ) {
115
+ var i = document.createElement( "span" );
116
+ i.className = "lexinputmeasure";
117
+ i.innerHTML = value;
118
+ document.body.appendChild( i );
119
+ var rect = i.getBoundingClientRect();
120
+ LX.UTILS.deleteElement( i );
121
+ return rect.width + paddingPlusMargin;
122
+ }
123
+
124
+ LX.measureRealWidth = measureRealWidth;
125
+
109
126
  function simple_guidGenerator() {
110
127
  var S4 = function() {
111
128
  return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
@@ -167,46 +184,79 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
167
184
  len () { return Math.sqrt( this.len2() ); }
168
185
  nrm ( v0 = new vec2() ) { v0.set( this.x, this.y ); return v0.mul( 1.0 / this.len(), v0 ); }
169
186
  dst ( v ) { return v.sub( this ).len(); }
187
+ clp ( min, max, v0 = new vec2() ) { v0.set( clamp( this.x, min, max ), clamp( this.y, min, max ) ); return v0; }
170
188
  };
171
189
 
172
190
  LX.vec2 = vec2;
173
191
 
174
192
  // Other utils
175
193
 
194
+ /**
195
+ * @method makeDraggable
196
+ * @param {Element} domEl
197
+ * @param {Object} options
198
+ * autoAdjust (Bool): Sets in a correct position at the beggining
199
+ * dragMargin (Number): Margin of drag container
200
+ * onMove (Function): Called each move event
201
+ * onDragStart (Function): Called when drag event starts
202
+ */
176
203
  function makeDraggable( domEl, options = { } ) {
177
204
 
178
- let offsetX;
179
- let offsetY;
205
+ let offsetX = 0;
206
+ let offsetY = 0;
180
207
  let currentTarget = null;
181
208
  let targetClass = options.targetClass;
182
-
209
+ let dragMargin = options.dragMargin ?? 3;
210
+
211
+ let _computePosition = ( e, top, left ) => {
212
+ const nullRect = { x: 0, y: 0, width: 0, height: 0 };
213
+ const parentRect = domEl.parentElement ? domEl.parentElement.getBoundingClientRect() : nullRect;
214
+ const isFixed = ( domEl.style.position == "fixed" );
215
+ const fixedOffset = isFixed ? new LX.vec2( parentRect.x, parentRect.y ) : new LX.vec2();
216
+ left = left ?? e.clientX - offsetX - parentRect.x;
217
+ top = top ?? e.clientY - offsetY - parentRect.y;
218
+ domEl.style.left = clamp( left, dragMargin + fixedOffset.x, fixedOffset.x + parentRect.width - domEl.offsetWidth - dragMargin ) + 'px';
219
+ domEl.style.top = clamp( top, dragMargin + fixedOffset.y, fixedOffset.y + parentRect.height - domEl.offsetHeight - dragMargin ) + 'px';
220
+ };
221
+
222
+ // Initial adjustment
223
+ if( options.autoAdjust )
224
+ {
225
+ _computePosition( null, parseInt( domEl.style.left ), parseInt( domEl.style.top ) )
226
+ }
227
+
183
228
  let id = LX.UTILS.uidGenerator();
184
229
  domEl[ 'draggable-id' ] = id;
185
-
230
+
186
231
  const defaultMoveFunc = e => {
187
- if( !currentTarget ) return;
188
- let left = e.clientX - offsetX;
189
- let top = e.clientY - offsetY;
190
- if( left > 3 && ( left + domEl.offsetWidth + 6 ) <= window.innerWidth )
191
- domEl.style.left = left + 'px';
192
- if( top > 3 && ( top + domEl.offsetHeight + 6 ) <= window.innerHeight )
193
- domEl.style.top = top + 'px';
232
+ if( !currentTarget )
233
+ {
234
+ return;
235
+ }
236
+
237
+ _computePosition( e );
194
238
  };
195
-
239
+
196
240
  const customMoveFunc = e => {
197
- if( !currentTarget ) return;
241
+ if( !currentTarget )
242
+ {
243
+ return;
244
+ }
245
+
198
246
  if( options.onMove )
247
+ {
199
248
  options.onMove( currentTarget );
249
+ }
200
250
  };
201
-
251
+
202
252
  let onMove = options.onMove ? customMoveFunc : defaultMoveFunc;
203
253
  let onDragStart = options.onDragStart;
204
-
254
+
205
255
  domEl.setAttribute( 'draggable', true );
206
256
  domEl.addEventListener( "mousedown", function( e ) {
207
- currentTarget = (e.target.classList.contains(targetClass) || !targetClass) ? e.target : null;
257
+ currentTarget = ( e.target.classList.contains( targetClass ) || !targetClass ) ? e.target : null;
208
258
  } );
209
-
259
+
210
260
  domEl.addEventListener( "dragstart", function( e ) {
211
261
  e.preventDefault();
212
262
  e.stopPropagation();
@@ -218,15 +268,21 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
218
268
  e.dataTransfer.setDragImage( img, 0, 0 );
219
269
  e.dataTransfer.effectAllowed = "move";
220
270
  const rect = e.target.getBoundingClientRect();
221
- offsetX = e.clientX - rect.x;
222
- offsetY = e.clientY - rect.y;
271
+ const parentRect = currentTarget.parentElement.getBoundingClientRect();
272
+ const isFixed = ( currentTarget.style.position == "fixed" );
273
+ const fixedOffset = isFixed ? new LX.vec2( parentRect.x, parentRect.y ) : new LX.vec2();
274
+ offsetX = e.clientX - rect.x - fixedOffset.x;
275
+ offsetY = e.clientY - rect.y - fixedOffset.y;
223
276
  document.addEventListener( "mousemove", onMove );
224
277
  if( onDragStart )
278
+ {
225
279
  onDragStart( currentTarget, e );
280
+ }
226
281
  }, false );
227
282
 
228
283
  document.addEventListener( 'mouseup', () => {
229
- if( currentTarget ) {
284
+ if( currentTarget )
285
+ {
230
286
  currentTarget = null;
231
287
  document.removeEventListener( "mousemove", onMove );
232
288
  }
@@ -665,7 +721,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
665
721
  }
666
722
 
667
723
  string() {
668
- switch(this.type) {
724
+ switch( this.type )
725
+ {
669
726
  case TreeEvent.NONE: return "tree_event_none";
670
727
  case TreeEvent.NODE_SELECTED: return "tree_event_selected";
671
728
  case TreeEvent.NODE_DELETED: return "tree_event_deleted";
@@ -819,7 +876,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
819
876
 
820
877
  const draggable = options.draggable ?? true;
821
878
  if( draggable )
822
- makeDraggable( root );
879
+ {
880
+ makeDraggable( root, options );
881
+ }
823
882
 
824
883
  if( options.resizeable ) {
825
884
  root.classList.add("resizeable");
@@ -1141,7 +1200,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
1141
1200
  // Send area resize to every widget in the area
1142
1201
  for( let widget of widgets )
1143
1202
  {
1144
- const jsInstance = widget.jsIinstance;
1203
+ const jsInstance = widget.jsInstance;
1145
1204
 
1146
1205
  if( jsInstance.onresize )
1147
1206
  {
@@ -1181,23 +1240,33 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
1181
1240
  * @method resize
1182
1241
  * Resize element
1183
1242
  */
1184
- setSize(size) {
1243
+ setSize( size ) {
1185
1244
 
1186
- let [width, height] = size;
1187
-
1188
- if(width != undefined && width.constructor == Number)
1245
+ let [ width, height ] = size;
1246
+
1247
+ if( width != undefined && width.constructor == Number )
1248
+ {
1189
1249
  width += "px";
1190
- if(height != undefined && height.constructor == Number)
1250
+ }
1251
+
1252
+ if( height != undefined && height.constructor == Number )
1253
+ {
1191
1254
  height += "px";
1192
-
1193
- if(width)
1255
+ }
1256
+
1257
+ if( width )
1258
+ {
1194
1259
  this.root.style.width = width;
1195
- if(height)
1260
+ }
1261
+
1262
+ if( height )
1263
+ {
1196
1264
  this.root.style.height = height;
1265
+ }
1197
1266
 
1198
- this.size = [this.root.clientWidth, this.root.clientHeight];
1267
+ this.size = [ this.root.clientWidth, this.root.clientHeight ];
1199
1268
 
1200
- this.propagateEvent("onresize");
1269
+ this.propagateEvent( "onresize" );
1201
1270
  }
1202
1271
 
1203
1272
  /**
@@ -1207,7 +1276,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
1207
1276
  extend() {
1208
1277
 
1209
1278
  if( this.split_extended )
1210
- return;
1279
+ {
1280
+ return;
1281
+ }
1211
1282
 
1212
1283
  let [area1, area2] = this.sections;
1213
1284
  this.split_extended = true;
@@ -1877,11 +1948,15 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
1877
1948
 
1878
1949
  const tabEl = this.tabDOMs[ name ];
1879
1950
 
1880
- if(!tabEl || tabEl.fixed)
1881
- return;
1951
+ if( !tabEl || tabEl.fixed )
1952
+ {
1953
+ return;
1954
+ }
1882
1955
 
1883
1956
  if( this.onclose )
1957
+ {
1884
1958
  this.onclose( name );
1959
+ }
1885
1960
 
1886
1961
  // Delete tab element
1887
1962
  this.tabDOMs[ name ].remove();
@@ -1892,11 +1967,12 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
1892
1967
  delete this.tabs[ name ];
1893
1968
 
1894
1969
  // Select last tab
1895
- const last_tab = this.root.lastChild;
1896
- if(last_tab && !last_tab.fixed)
1970
+ const lastTab = this.root.lastChild;
1971
+ if( lastTab && !lastTab.fixed )
1972
+ {
1897
1973
  this.root.lastChild.click();
1974
+ }
1898
1975
  }
1899
-
1900
1976
  }
1901
1977
 
1902
1978
  LX.Tabs = Tabs;
@@ -2463,6 +2539,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2463
2539
  static CUSTOM = 21;
2464
2540
  static SEPARATOR = 22;
2465
2541
  static KNOB = 23;
2542
+ static SIZE = 24;
2543
+ static PAD = 25;
2544
+ static FORM = 26;
2466
2545
 
2467
2546
  static NO_CONTEXT_TYPES = [
2468
2547
  Widget.BUTTON,
@@ -2520,14 +2599,16 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2520
2599
 
2521
2600
  paste() {
2522
2601
  if( !this._can_paste() )
2523
- return;
2602
+ {
2603
+ return;
2604
+ }
2524
2605
 
2525
2606
  this.set(navigator.clipboard.data);
2526
2607
  }
2527
2608
 
2528
2609
  typeName() {
2529
2610
 
2530
- switch(this.type) {
2611
+ switch( this.type ) {
2531
2612
  case Widget.TEXT: return "Text";
2532
2613
  case Widget.TEXTAREA: return "TextArea";
2533
2614
  case Widget.BUTTON: return "Button";
@@ -2545,6 +2626,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2545
2626
  case Widget.TAGS: return "Tags";
2546
2627
  case Widget.CURVE: return "Curve";
2547
2628
  case Widget.KNOB: return "Knob";
2629
+ case Widget.SIZE: return "Size";
2630
+ case Widget.PAD: return "Pad";
2631
+ case Widget.FORM: return "Form";
2548
2632
  case Widget.CUSTOM: return this.customName;
2549
2633
  }
2550
2634
  }
@@ -2639,40 +2723,50 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2639
2723
  custom_widgets.className = "lexcustomitems";
2640
2724
  custom_widgets.toggleAttribute('hidden', true);
2641
2725
 
2642
- element.appendChild(container);
2643
- element.appendChild(custom_widgets);
2644
-
2645
- if( instance ) {
2646
-
2726
+ element.appendChild( container );
2727
+ element.appendChild( custom_widgets );
2728
+
2729
+ if( instance )
2730
+ {
2731
+
2647
2732
  this.queue( custom_widgets );
2648
2733
 
2649
- const on_instance_changed = (key, value, event) => {
2650
- instance[key] = value;
2651
- this._trigger( new IEvent(name, instance, event), callback );
2734
+ const on_instance_changed = ( key, value, event ) => {
2735
+ instance[ key ] = value;
2736
+ this._trigger( new IEvent( name, instance, event ), callback );
2652
2737
  };
2653
2738
 
2654
2739
  for( let key in default_instance )
2655
2740
  {
2656
- const value = instance[key] ?? default_instance[key];
2741
+ const value = instance[ key ] ?? default_instance[ key ];
2657
2742
 
2658
- switch(value.constructor) {
2743
+ switch( value.constructor )
2744
+ {
2659
2745
  case String:
2660
- if(value[0] === '#')
2661
- this.addColor(key, value, on_instance_changed.bind(this, key));
2746
+ if( value[ 0 ] === '#' )
2747
+ {
2748
+ this.addColor( key, value, on_instance_changed.bind( this, key ) );
2749
+ }
2662
2750
  else
2663
- this.addText(key, value, on_instance_changed.bind(this, key));
2751
+ {
2752
+ this.addText( key, value, on_instance_changed.bind( this, key ) );
2753
+ }
2664
2754
  break;
2665
2755
  case Number:
2666
- this.addNumber(key, value, on_instance_changed.bind(this, key));
2756
+ this.addNumber( key, value, on_instance_changed.bind( this, key ) );
2667
2757
  break;
2668
2758
  case Boolean:
2669
- this.addCheckbox(key, value, on_instance_changed.bind(this, key));
2759
+ this.addCheckbox( key, value, on_instance_changed.bind( this, key ) );
2670
2760
  break;
2671
2761
  case Array:
2672
2762
  if( value.length > 4 )
2673
- this.addArray(key, value, on_instance_changed.bind(this, key));
2763
+ {
2764
+ this.addArray( key, value, on_instance_changed.bind( this, key ) );
2765
+ }
2674
2766
  else
2675
- this._add_vector(value.length, key, value, on_instance_changed.bind(this, key));
2767
+ {
2768
+ this._add_vector( value.length, key, value, on_instance_changed.bind( this, key ) );
2769
+ }
2676
2770
  break;
2677
2771
  }
2678
2772
  }
@@ -2710,37 +2804,40 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2710
2804
  _create_item( parent, node, level = 0, selectedId ) {
2711
2805
 
2712
2806
  const that = this;
2713
- const node_filter_input = this.domEl.querySelector("#lexnodetree_filter");
2807
+ const node_filter_input = this.domEl.querySelector( "#lexnodetree_filter" );
2714
2808
 
2715
2809
  node.children = node.children ?? [];
2716
- if(node_filter_input && !node.id.includes(node_filter_input.value) || (selectedId != undefined) && selectedId != node.id)
2810
+ if( node_filter_input && !node.id.includes( node_filter_input.value ) || (selectedId != undefined) && selectedId != node.id )
2717
2811
  {
2718
2812
  for( var i = 0; i < node.children.length; ++i )
2719
- this._create_item( node, node.children[i], level + 1, selectedId );
2813
+ {
2814
+ this._create_item( node, node.children[ i ], level + 1, selectedId );
2815
+ }
2720
2816
  return;
2721
2817
  }
2722
2818
 
2723
- const list = this.domEl.querySelector("ul");
2819
+ const list = this.domEl.querySelector( 'ul' );
2724
2820
 
2725
2821
  node.visible = node.visible ?? true;
2726
2822
  node.parent = parent;
2727
- let is_parent = node.children.length > 0;
2728
- let is_selected = this.selected.indexOf( node ) > -1;
2823
+ let isParent = node.children.length > 0;
2824
+ let isSelected = this.selected.indexOf( node ) > -1;
2729
2825
 
2730
- if( this.options.only_folders ) {
2826
+ if( this.options.only_folders )
2827
+ {
2731
2828
  let has_folders = false;
2732
2829
  node.children.forEach( c => has_folders |= (c.type == 'folder') );
2733
- is_parent = !!has_folders;
2830
+ isParent = !!has_folders;
2734
2831
  }
2735
2832
 
2736
2833
  let item = document.createElement('li');
2737
- item.className = "lextreeitem " + "datalevel" + level + (is_parent ? " parent" : "") + (is_selected ? " selected" : "");
2834
+ item.className = "lextreeitem " + "datalevel" + level + (isParent ? " parent" : "") + (isSelected ? " selected" : "");
2738
2835
  item.id = LX.getSupportedDOMName( node.id );
2739
2836
  item.tabIndex = "0";
2740
2837
 
2741
2838
  // Select hierarchy icon
2742
2839
  let icon = (this.options.skip_default_icon ?? true) ? "" : "fa-solid fa-square"; // Default: no childs
2743
- if( is_parent ) icon = node.closed ? "fa-solid fa-caret-right" : "fa-solid fa-caret-down";
2840
+ if( isParent ) icon = node.closed ? "fa-solid fa-caret-right" : "fa-solid fa-caret-down";
2744
2841
  item.innerHTML = "<a class='" + icon + " hierarchy'></a>";
2745
2842
 
2746
2843
  // Add display icon
@@ -2760,18 +2857,20 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2760
2857
 
2761
2858
  item.innerHTML += (node.rename ? "" : node.id);
2762
2859
 
2763
- item.setAttribute('draggable', true);
2764
- item.style.paddingLeft = ((is_parent ? 0 : 3 ) + (3 + (level+1) * 15)) + "px";
2765
- list.appendChild(item);
2860
+ item.setAttribute( 'draggable', true );
2861
+ item.style.paddingLeft = ((isParent ? 0 : 3 ) + (3 + (level+1) * 15)) + "px";
2862
+ list.appendChild( item );
2766
2863
 
2767
2864
  // Callbacks
2768
2865
  item.addEventListener("click", e => {
2769
- if( handled ) {
2866
+ if( handled )
2867
+ {
2770
2868
  handled = false;
2771
2869
  return;
2772
2870
  }
2773
2871
 
2774
- if(!e.shiftKey) {
2872
+ if( !e.shiftKey )
2873
+ {
2775
2874
  list.querySelectorAll("li").forEach( e => { e.classList.remove('selected'); } );
2776
2875
  this.selected.length = 0;
2777
2876
  }
@@ -2787,16 +2886,18 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2787
2886
  }
2788
2887
 
2789
2888
  // Only Show children...
2790
- if(is_parent && node.id.length > 1 /* Strange case... */) {
2889
+ if(isParent && node.id.length > 1 /* Strange case... */) {
2791
2890
  node.closed = false;
2792
- if(that.onevent) {
2793
- const event = new TreeEvent(TreeEvent.NODE_CARETCHANGED, node, node.closed);
2891
+ if( that.onevent )
2892
+ {
2893
+ const event = new TreeEvent( TreeEvent.NODE_CARETCHANGED, node, node.closed );
2794
2894
  that.onevent( event );
2795
2895
  }
2796
2896
  that.frefresh( node.id );
2797
2897
  }
2798
2898
 
2799
- if(that.onevent) {
2899
+ if( that.onevent )
2900
+ {
2800
2901
  const event = new TreeEvent(TreeEvent.NODE_SELECTED, e.shiftKey ? this.selected : node );
2801
2902
  event.multiple = e.shiftKey;
2802
2903
  that.onevent( event );
@@ -2804,37 +2905,110 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2804
2905
  });
2805
2906
 
2806
2907
  item.addEventListener("dblclick", function() {
2908
+
2807
2909
  if( that.options.rename ?? true )
2808
2910
  {
2809
2911
  // Trigger rename
2810
2912
  node.rename = true;
2811
2913
  that.refresh();
2812
2914
  }
2915
+
2813
2916
  if( that.onevent )
2814
2917
  {
2815
- const event = new TreeEvent(TreeEvent.NODE_DBLCLICKED, node);
2918
+ const event = new TreeEvent( TreeEvent.NODE_DBLCLICKED, node );
2816
2919
  that.onevent( event );
2817
2920
  }
2818
2921
  });
2819
2922
 
2820
- item.addEventListener("contextmenu", e => {
2923
+ item.addEventListener( "contextmenu", e => {
2924
+
2821
2925
  e.preventDefault();
2822
- if(that.onevent) {
2823
- const event = new TreeEvent(TreeEvent.NODE_CONTEXTMENU, this.selected.length > 1 ? this.selected : node, e);
2824
- event.multiple = this.selected.length > 1;
2825
- that.onevent( event );
2926
+
2927
+ if( !that.onevent )
2928
+ {
2929
+ return;
2930
+ }
2931
+
2932
+ const event = new TreeEvent(TreeEvent.NODE_CONTEXTMENU, this.selected.length > 1 ? this.selected : node, e);
2933
+ event.multiple = this.selected.length > 1;
2934
+
2935
+ LX.addContextMenu( event.multiple ? "Selected Nodes" : event.node.id, event.value, m => {
2936
+ event.panel = m;
2937
+ });
2938
+
2939
+ that.onevent( event );
2940
+
2941
+ if( ( this.options.addDefault ?? false ) == true )
2942
+ {
2943
+ if( event.panel.items )
2944
+ {
2945
+ event.panel.add( "" );
2946
+ }
2947
+
2948
+ event.panel.add( "Select Children", () => {
2949
+
2950
+ const selectChildren = ( n ) => {
2951
+
2952
+ if( n.closed )
2953
+ {
2954
+ return;
2955
+ }
2956
+
2957
+ for( let child of n.children ?? [] )
2958
+ {
2959
+ if( !child )
2960
+ {
2961
+ continue;
2962
+ }
2963
+
2964
+ let nodeItem = this.domEl.querySelector( '#' + child.id );
2965
+ nodeItem.classList.add('selected');
2966
+ this.selected.push( child );
2967
+ selectChildren( child );
2968
+ }
2969
+ };
2970
+
2971
+ // Add childs of the clicked node
2972
+ selectChildren( node );
2973
+ } );
2974
+
2975
+ event.panel.add( "Delete", { callback: () => {
2976
+
2977
+ // It's the root node
2978
+ if( !node.parent )
2979
+ {
2980
+ return;
2981
+ }
2982
+
2983
+ if( that.onevent ) {
2984
+ const event = new TreeEvent( TreeEvent.NODE_DELETED, node, e );
2985
+ that.onevent( event );
2986
+ }
2987
+
2988
+ // Delete nodes now
2989
+ let childs = node.parent.children;
2990
+ const index = childs.indexOf( node );
2991
+ childs.splice( index, 1 );
2992
+
2993
+ this.refresh();
2994
+ } } );
2826
2995
  }
2827
2996
  });
2828
2997
 
2829
2998
  item.addEventListener("keydown", e => {
2830
- if(node.rename)
2831
- return;
2999
+
3000
+ if( node.rename )
3001
+ {
3002
+ return;
3003
+ }
3004
+
2832
3005
  e.preventDefault();
3006
+
2833
3007
  if( e.key == "Delete" )
2834
3008
  {
2835
3009
  // Send event now so we have the info in selected array..
2836
- if(that.onevent) {
2837
- const event = new TreeEvent(TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e);
3010
+ if( that.onevent ) {
3011
+ const event = new TreeEvent( TreeEvent.NODE_DELETED, this.selected.length > 1 ? this.selected : node, e );
2838
3012
  event.multiple = this.selected.length > 1;
2839
3013
  that.onevent( event );
2840
3014
  }
@@ -2852,10 +3026,13 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2852
3026
  }
2853
3027
  else if( e.key == "ArrowUp" || e.key == "ArrowDown" ) // Unique or zero selected
2854
3028
  {
2855
- var selected = this.selected.length > 1 ? (e.key == "ArrowUp" ? this.selected.shift() : this.selected.pop()) : this.selected[0];
2856
- var el = this.domEl.querySelector("#" + LX.getSupportedDOMName( selected.id ) );
3029
+ var selected = this.selected.length > 1 ? ( e.key == "ArrowUp" ? this.selected.shift() : this.selected.pop() ) : this.selected[ 0 ];
3030
+ var el = this.domEl.querySelector( "#" + LX.getSupportedDOMName( selected.id ) );
2857
3031
  var sibling = e.key == "ArrowUp" ? el.previousSibling : el.nextSibling;
2858
- if( sibling ) sibling.click();
3032
+ if( sibling )
3033
+ {
3034
+ sibling.click();
3035
+ }
2859
3036
  }
2860
3037
  });
2861
3038
 
@@ -2961,7 +3138,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
2961
3138
  let handled = false;
2962
3139
 
2963
3140
  // Show/hide children
2964
- if(is_parent) {
3141
+ if(isParent) {
2965
3142
  item.querySelector('a.hierarchy').addEventListener("click", function(e) {
2966
3143
 
2967
3144
  handled = true;
@@ -3099,19 +3276,25 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3099
3276
  getValue( name ) {
3100
3277
 
3101
3278
  let widget = this.widgets[ name ];
3102
- if(!widget)
3103
- throw("No widget called " + name);
3279
+
3280
+ if( !widget )
3281
+ {
3282
+ throw( "No widget called " + name );
3283
+ }
3104
3284
 
3105
3285
  return widget.value();
3106
3286
  }
3107
3287
 
3108
- setValue( name, value ) {
3288
+ setValue( name, value, skipCallback ) {
3109
3289
 
3110
3290
  let widget = this.widgets[ name ];
3111
- if(!widget)
3112
- throw("No widget called " + name);
3113
3291
 
3114
- return widget.set(value);
3292
+ if( !widget )
3293
+ {
3294
+ throw( "No widget called " + name );
3295
+ }
3296
+
3297
+ return widget.set( value, skipCallback );
3115
3298
  }
3116
3299
 
3117
3300
  /**
@@ -3290,9 +3473,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3290
3473
  return (typeof arg == 'undefined' ? def : arg);
3291
3474
  }
3292
3475
 
3293
- static _dispatch_event( element, type, bubbles, cancelable ) {
3294
- let event = new Event(type, { 'bubbles': bubbles, 'cancelable': cancelable });
3295
- element.dispatchEvent(event);
3476
+ static _dispatch_event( element, type, data, bubbles, cancelable ) {
3477
+ let event = new CustomEvent( type, { 'detail': data, 'bubbles': bubbles, 'cancelable': cancelable } );
3478
+ element.dispatchEvent( event );
3296
3479
  }
3297
3480
 
3298
3481
  static _add_reset_property( container, callback ) {
@@ -3300,8 +3483,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3300
3483
  domEl.style.display = "none";
3301
3484
  domEl.style.marginRight = "6px";
3302
3485
  domEl.className = "lexicon fa fa-rotate-left";
3303
- domEl.addEventListener("click", callback);
3304
- container.appendChild(domEl);
3486
+ domEl.addEventListener( "click", callback );
3487
+ container.appendChild( domEl );
3305
3488
  return domEl;
3306
3489
  }
3307
3490
 
@@ -3311,39 +3494,45 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3311
3494
 
3312
3495
  create_widget( name, type, options = {} ) {
3313
3496
 
3314
- let widget = new Widget(name, type, options);
3497
+ let widget = new Widget( name, type, options );
3315
3498
 
3316
- let element = document.createElement('div');
3499
+ let element = document.createElement( 'div' );
3317
3500
  element.className = "lexwidget";
3318
- if(options.id)
3319
- element.id = options.id;
3320
- if(options.className)
3501
+ element.id = options.id ?? "";
3502
+ element.title = options.title ?? "";
3503
+
3504
+ if( options.className )
3505
+ {
3321
3506
  element.className += " " + options.className;
3322
- if(options.title)
3323
- element.title = options.title;
3507
+ }
3324
3508
 
3325
3509
  if( type != Widget.TITLE )
3326
3510
  {
3327
3511
  element.style.width = "calc(100% - " + (this.current_branch || type == Widget.FILE ? 10 : 20) + "px)";
3328
- if( options.width ) {
3512
+
3513
+ if( options.width )
3514
+ {
3329
3515
  element.style.width = element.style.minWidth = options.width;
3330
3516
  }
3331
- if( options.maxWidth ) {
3517
+ if( options.maxWidth )
3518
+ {
3332
3519
  element.style.maxWidth = options.maxWidth;
3333
3520
  }
3334
- if( options.minWidth ) {
3521
+ if( options.minWidth )
3522
+ {
3335
3523
  element.style.minWidth = options.minWidth;
3336
3524
  }
3337
- if( options.height ) {
3525
+ if( options.height )
3526
+ {
3338
3527
  element.style.height = element.style.minHeight = options.height;
3339
3528
  }
3340
3529
  }
3341
3530
 
3342
- if(name != undefined) {
3343
-
3344
- if(!(options.no_name ?? false) )
3531
+ if( name != undefined )
3532
+ {
3533
+ if( !(options.hideName ?? false) )
3345
3534
  {
3346
- let domName = document.createElement('div');
3535
+ let domName = document.createElement( 'div' );
3347
3536
  domName.className = "lexwidgetname";
3348
3537
  if( options.justifyName )
3349
3538
  {
@@ -3356,26 +3545,32 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3356
3545
  element.domName = domName;
3357
3546
 
3358
3547
  // Copy-paste info
3359
- domName.addEventListener('contextmenu', function(e) {
3548
+ domName.addEventListener('contextmenu', function( e ) {
3360
3549
  e.preventDefault();
3361
- widget.oncontextmenu(e);
3550
+ widget.oncontextmenu( e );
3362
3551
  });
3363
3552
  }
3364
3553
 
3365
3554
  this.widgets[ name ] = widget;
3366
3555
  }
3367
3556
 
3368
- if(options.signal)
3557
+ if( options.signal )
3369
3558
  {
3370
- if(!name) {
3371
- if(!this.signals)
3559
+ if( !name )
3560
+ {
3561
+ if( !this.signals )
3562
+ {
3372
3563
  this.signals = [];
3373
- this.signals.push({[options.signal]: widget})
3564
+ }
3565
+
3566
+ this.signals.push( { [ options.signal ]: widget } )
3374
3567
  }
3568
+
3375
3569
  LX.addSignal( options.signal, widget );
3376
3570
  }
3377
3571
 
3378
3572
  widget.domEl = element;
3573
+ element.jsInstance = widget;
3379
3574
 
3380
3575
  const insert_widget = el => {
3381
3576
  if(options.container)
@@ -3445,7 +3640,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3445
3640
  element.className += " lexfilter noname";
3446
3641
 
3447
3642
  let input = document.createElement('input');
3448
- input.id = 'input-filter';
3643
+ input.className = 'lexinput-filter';
3449
3644
  input.setAttribute("placeholder", options.placeholder);
3450
3645
  input.style.width = "calc( 100% - 17px )";
3451
3646
  input.value = options.filterValue || "";
@@ -4030,7 +4225,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
4030
4225
 
4031
4226
  addCard( name, options = {} ) {
4032
4227
 
4033
- options.no_name = true;
4228
+ options.hideName = true;
4034
4229
  let widget = this.create_widget(name, Widget.CARD, options);
4035
4230
  let element = widget.domEl;
4036
4231
 
@@ -4081,6 +4276,89 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
4081
4276
  return widget;
4082
4277
  }
4083
4278
 
4279
+ /**
4280
+ * @method addForm
4281
+ * @param {String} name Widget name
4282
+ * @param {Object} data Form data
4283
+ * @param {Function} callback Callback function on submit form
4284
+ * @param {*} options:
4285
+ * actionName: Text to be shown in the button
4286
+ */
4287
+
4288
+ addForm( name, data, callback, options = {} ) {
4289
+
4290
+ if( data.constructor != Object )
4291
+ {
4292
+ console.error( "Form data must be an Object" );
4293
+ return;
4294
+ }
4295
+
4296
+ // Always hide name for this one
4297
+ options.hideName = true;
4298
+
4299
+ let widget = this.create_widget( name, Widget.FORM, options );
4300
+
4301
+ widget.onGetValue = () => {
4302
+ return container.formData;
4303
+ };
4304
+
4305
+ widget.onSetValue = ( newValue, skipCallback ) => {
4306
+ container.formData = newValue;
4307
+ const entries = container.querySelectorAll( ".lexwidget" );
4308
+ for( let i = 0; i < entries.length; ++i )
4309
+ {
4310
+ const entry = entries[ i ];
4311
+ if( entry.jsInstance.type != LX.Widget.TEXT )
4312
+ {
4313
+ continue;
4314
+ }
4315
+ let entryName = entries[ i ].querySelector( ".lexwidgetname" ).innerText;
4316
+ let entryInput = entries[ i ].querySelector( ".lextext input" );
4317
+ entryInput.value = newValue[ entryName ] ?? "";
4318
+ Panel._dispatch_event( entryInput, "focusout", skipCallback );
4319
+ }
4320
+ };
4321
+
4322
+ // Add widget value
4323
+
4324
+ let element = widget.domEl;
4325
+
4326
+ let container = document.createElement( 'div' );
4327
+ container.className = "lexformdata";
4328
+
4329
+ this.queue( container );
4330
+
4331
+ container.formData = {};
4332
+
4333
+ for( let entry in data )
4334
+ {
4335
+ const entryData = data[ entry ];
4336
+ this.addText( entry, entryData.constructor == Object ? entryData.value : entryData, ( value ) => {
4337
+ container.formData[ entry ] = value;
4338
+ }, entryData );
4339
+
4340
+ container.formData[ entry ] = entryData.constructor == Object ? entryData.value : entryData;
4341
+ }
4342
+
4343
+ this.addButton( null, options.actionName ?? "Submit", ( value, event ) => {
4344
+ if( callback )
4345
+ {
4346
+ callback( container.formData, event );
4347
+ }
4348
+ } );
4349
+
4350
+ this.clearQueue();
4351
+
4352
+ element.appendChild( container );
4353
+
4354
+ if( !widget.name || options.hideName ) {
4355
+ element.className += " noname";
4356
+ container.style.width = "100%";
4357
+ }
4358
+
4359
+ return widget;
4360
+ }
4361
+
4084
4362
  /**
4085
4363
  * @method addContent
4086
4364
  * @param {HTMLElement} element
@@ -4105,27 +4383,29 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
4105
4383
  async addImage( url, options = {} ) {
4106
4384
 
4107
4385
  if( !url )
4108
- return;
4386
+ {
4387
+ return;
4388
+ }
4109
4389
 
4110
- options.no_name = true;
4111
- let widget = this.create_widget(null, Widget.IMAGE, options);
4390
+ options.hideName = true;
4391
+ let widget = this.create_widget( null, Widget.IMAGE, options );
4112
4392
  let element = widget.domEl;
4113
4393
 
4114
- let container = document.createElement('div');
4394
+ let container = document.createElement( 'div' );
4115
4395
  container.className = "leximage";
4116
4396
  container.style.width = "100%";
4117
4397
 
4118
- let img = document.createElement('img');
4398
+ let img = document.createElement( 'img' );
4119
4399
  img.src = url;
4120
4400
 
4121
- for(let s in options.style) {
4122
-
4123
- img.style[s] = options.style[s];
4401
+ for( let s in options.style )
4402
+ {
4403
+ img.style[ s ] = options.style[ s ];
4124
4404
  }
4125
4405
 
4126
4406
  await img.decode();
4127
- container.appendChild(img);
4128
- element.appendChild(container);
4407
+ container.appendChild( img );
4408
+ element.appendChild( container );
4129
4409
 
4130
4410
  return widget;
4131
4411
  }
@@ -4224,7 +4504,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
4224
4504
  setTimeout( () => delete this.unfocus_event, 200 );
4225
4505
  } else if ( e.relatedTarget && e.relatedTarget.tagName == "INPUT" ) {
4226
4506
  return;
4227
- }else if ( e.target.id == 'input-filter' ) {
4507
+ }else if ( e.target.id == 'lexinput-filter' ) {
4228
4508
  return;
4229
4509
  }
4230
4510
  this.toggleAttribute( 'hidden', true );
@@ -5027,6 +5307,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5027
5307
  * min, max: Min and Max values for the input
5028
5308
  * skipSlider: If there are min and max values, skip the slider
5029
5309
  * units: Unit as string added to the end of the value
5310
+ * onPress: Callback function on mouse down
5311
+ * onRelease: Callback function on mouse is released
5030
5312
  */
5031
5313
 
5032
5314
  addNumber( name, value, callback, options = {} ) {
@@ -5036,6 +5318,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5036
5318
  widget.onGetValue = () => {
5037
5319
  return +vecinput.value;
5038
5320
  };
5321
+
5039
5322
  widget.onSetValue = ( newValue, skipCallback ) => {
5040
5323
  vecinput.value = round( newValue, options.precision );
5041
5324
  Panel._dispatch_event( vecinput, "change", skipCallback );
@@ -5078,16 +5361,6 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5078
5361
  vecinput.value = vecinput.iValue = value;
5079
5362
  box.appendChild( vecinput );
5080
5363
 
5081
- let measureRealWidth = function( value, paddingPlusMargin = 8 ) {
5082
- var i = document.createElement( "span" );
5083
- i.className = "lexinputmeasure";
5084
- i.innerHTML = value;
5085
- document.body.appendChild( i );
5086
- var rect = i.getBoundingClientRect();
5087
- LX.UTILS.deleteElement( i );
5088
- return rect.width + paddingPlusMargin;
5089
- }
5090
-
5091
5364
  if( options.units )
5092
5365
  {
5093
5366
  let unitSpan = document.createElement( 'span' );
@@ -5107,21 +5380,47 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5107
5380
  vecinput.disabled = true;
5108
5381
  }
5109
5382
 
5110
- // add slider below
5111
- if( !options.skipSlider && options.min !== undefined && options.max !== undefined ) {
5383
+ // Add slider below
5384
+ if( !options.skipSlider && options.min !== undefined && options.max !== undefined )
5385
+ {
5112
5386
  let slider = document.createElement( 'input' );
5113
5387
  slider.className = "lexinputslider";
5114
- slider.step = options.step ?? 1;
5115
5388
  slider.min = options.min;
5116
5389
  slider.max = options.max;
5390
+ slider.step = options.step ?? 1;
5117
5391
  slider.type = "range";
5118
5392
  slider.value = value;
5393
+
5119
5394
  slider.addEventListener( "input", function( e ) {
5120
5395
  let new_value = +this.valueAsNumber;
5121
5396
  vecinput.value = round( new_value, options.precision );
5122
5397
  Panel._dispatch_event( vecinput, "change" );
5123
5398
  }, false );
5399
+
5400
+ slider.addEventListener( "mousedown", function( e ) {
5401
+ if( options.onPress )
5402
+ {
5403
+ options.onPress.bind( slider )( e, slider );
5404
+ }
5405
+ }, false );
5406
+
5407
+ slider.addEventListener( "mouseup", function( e ) {
5408
+ if( options.onRelease )
5409
+ {
5410
+ options.onRelease.bind( slider )( e, slider );
5411
+ }
5412
+ }, false );
5413
+
5124
5414
  box.appendChild( slider );
5415
+
5416
+ // Method to change min, max, step parameters
5417
+ widget.setLimits = ( newMin, newMax, newStep ) => {
5418
+ vecinput.min = slider.min = newMin ?? vecinput.min;
5419
+ vecinput.max = slider.max = newMax ?? vecinput.max;
5420
+ vecinput.step = newStep ?? vecinput.step;
5421
+ slider.step = newStep ?? slider.step;
5422
+ Panel._dispatch_event( vecinput, "change", true );
5423
+ };
5125
5424
  }
5126
5425
 
5127
5426
  // Add wheel input
@@ -5129,7 +5428,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5129
5428
  vecinput.addEventListener( "wheel", function( e ) {
5130
5429
  e.preventDefault();
5131
5430
  if( this !== document.activeElement )
5431
+ {
5132
5432
  return;
5433
+ }
5133
5434
  let mult = options.step ?? 1;
5134
5435
  if( e.shiftKey ) mult *= 10;
5135
5436
  else if( e.altKey ) mult *= 0.1;
@@ -5141,7 +5442,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5141
5442
  vecinput.addEventListener( "change", e => {
5142
5443
 
5143
5444
  if( isNaN( e.target.valueAsNumber ) )
5445
+ {
5144
5446
  return;
5447
+ }
5145
5448
 
5146
5449
  const skipCallback = e.detail;
5147
5450
 
@@ -5176,50 +5479,76 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5176
5479
  vecinput.addEventListener( "mousedown", inner_mousedown );
5177
5480
 
5178
5481
  var that = this;
5179
- var lastY = 0;
5180
- function inner_mousedown(e) {
5181
- if(document.activeElement == vecinput) return;
5482
+
5483
+ function inner_mousedown( e )
5484
+ {
5485
+ if( document.activeElement == vecinput )
5486
+ {
5487
+ return;
5488
+ }
5489
+
5182
5490
  var doc = that.root.ownerDocument;
5183
- doc.addEventListener("mousemove",inner_mousemove);
5184
- doc.addEventListener("mouseup",inner_mouseup);
5185
- lastY = e.pageY;
5186
- document.body.classList.add('nocursor');
5187
- document.body.classList.add('noevents');
5188
- dragIcon.classList.remove('hidden');
5491
+ doc.addEventListener( 'mousemove', inner_mousemove );
5492
+ doc.addEventListener( 'mouseup', inner_mouseup );
5493
+ document.body.classList.add( 'noevents' );
5494
+ dragIcon.classList.remove( 'hidden' );
5189
5495
  e.stopImmediatePropagation();
5190
5496
  e.stopPropagation();
5497
+
5498
+ if( !document.pointerLockElement )
5499
+ {
5500
+ vecinput.requestPointerLock();
5501
+ }
5502
+
5503
+ if( options.onPress )
5504
+ {
5505
+ options.onPress.bind( vecinput )( e, vecinput );
5506
+ }
5191
5507
  }
5192
5508
 
5193
- function inner_mousemove(e) {
5194
- if (lastY != e.pageY) {
5195
- let dt = lastY - e.pageY;
5509
+ function inner_mousemove( e )
5510
+ {
5511
+ let dt = -e.movementY;
5512
+
5513
+ if ( dt != 0 )
5514
+ {
5196
5515
  let mult = options.step ?? 1;
5197
- if(e.shiftKey) mult *= 10;
5198
- else if(e.altKey) mult *= 0.1;
5199
- let new_value = (+vecinput.valueAsNumber + mult * dt);
5200
- vecinput.value = (+new_value).toFixed( 4 ).replace(/([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/,'$1');
5516
+ if( e.shiftKey ) mult *= 10;
5517
+ else if( e.altKey ) mult *= 0.1;
5518
+ let new_value = ( +vecinput.valueAsNumber + mult * dt );
5519
+ vecinput.value = ( +new_value ).toFixed( 4 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' );
5201
5520
  Panel._dispatch_event( vecinput, "change" );
5202
5521
  }
5203
5522
 
5204
- lastY = e.pageY;
5205
5523
  e.stopPropagation();
5206
5524
  e.preventDefault();
5207
5525
  }
5208
5526
 
5209
- function inner_mouseup(e) {
5527
+ function inner_mouseup( e )
5528
+ {
5210
5529
  var doc = that.root.ownerDocument;
5211
- doc.removeEventListener("mousemove",inner_mousemove);
5212
- doc.removeEventListener("mouseup",inner_mouseup);
5213
- document.body.classList.remove('nocursor');
5214
- document.body.classList.remove('noevents');
5215
- dragIcon.classList.add('hidden');
5530
+ doc.removeEventListener( 'mousemove', inner_mousemove );
5531
+ doc.removeEventListener( 'mouseup', inner_mouseup );
5532
+ document.body.classList.remove( 'noevents' );
5533
+ dragIcon.classList.add( 'hidden' );
5534
+
5535
+ if( document.pointerLockElement )
5536
+ {
5537
+ document.exitPointerLock();
5538
+ }
5539
+
5540
+ if( options.onRelease )
5541
+ {
5542
+ options.onRelease.bind( vecinput )( e, vecinput );
5543
+ }
5216
5544
  }
5217
5545
 
5218
- container.appendChild(box);
5219
- element.appendChild(container);
5546
+ container.appendChild( box );
5547
+ element.appendChild( container );
5220
5548
 
5221
5549
  // Remove branch padding and margins
5222
- if(!widget.name) {
5550
+ if( !widget.name )
5551
+ {
5223
5552
  element.className += " noname";
5224
5553
  container.style.width = "100%";
5225
5554
  }
@@ -5227,14 +5556,15 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5227
5556
  return widget;
5228
5557
  }
5229
5558
 
5230
- static VECTOR_COMPONENTS = {0: 'x', 1: 'y', 2: 'z', 3: 'w'};
5559
+ static VECTOR_COMPONENTS = { 0: 'x', 1: 'y', 2: 'z', 3: 'w' };
5231
5560
 
5232
5561
  _add_vector( num_components, name, value, callback, options = {} ) {
5233
5562
 
5234
5563
  num_components = clamp( num_components, 2, 4 );
5235
5564
  value = value ?? new Array( num_components ).fill( 0 );
5236
5565
 
5237
- if( !name ) {
5566
+ if( !name )
5567
+ {
5238
5568
  throw( "Set Widget Name!" );
5239
5569
  }
5240
5570
 
@@ -5244,9 +5574,12 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5244
5574
  let inputs = element.querySelectorAll( "input" );
5245
5575
  let value = [];
5246
5576
  for( var v of inputs )
5577
+ {
5247
5578
  value.push( +v.value );
5579
+ }
5248
5580
  return value;
5249
5581
  };
5582
+
5250
5583
  widget.onSetValue = ( newValue, skipCallback ) => {
5251
5584
  const inputs = element.querySelectorAll( ".vecinput" );
5252
5585
  if( inputs.length == newValue.length )
@@ -5255,7 +5588,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5255
5588
  return;
5256
5589
  }
5257
5590
 
5258
- for( var i = 0; i < inputs.length; ++i ) {
5591
+ for( let i = 0; i < inputs.length; ++i ) {
5259
5592
  let value = newValue[ i ];
5260
5593
  inputs[ i ].value = round( value, options.precision ) ?? 0;
5261
5594
  Panel._dispatch_event( inputs[ i ], "change", skipCallback );
@@ -5275,7 +5608,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5275
5608
 
5276
5609
  // Add widget value
5277
5610
 
5278
- var container = document.createElement('div');
5611
+ var container = document.createElement( 'div' );
5279
5612
  container.className = "lexvector";
5280
5613
  container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
5281
5614
 
@@ -5296,7 +5629,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5296
5629
 
5297
5630
  if( value[ i ].constructor == Number )
5298
5631
  {
5299
- value[ i ] = clamp(value[ i ], +vecinput.min, +vecinput.max);
5632
+ value[ i ] = clamp( value[ i ], +vecinput.min, +vecinput.max );
5300
5633
  value[ i ] = round( value[ i ], options.precision );
5301
5634
  }
5302
5635
 
@@ -5306,12 +5639,12 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5306
5639
  dragIcon.className = "fa-solid fa-arrows-up-down drag-icon hidden";
5307
5640
  box.appendChild( dragIcon );
5308
5641
 
5309
- if( options.disabled ) {
5642
+ if( options.disabled )
5643
+ {
5310
5644
  vecinput.disabled = true;
5311
5645
  }
5312
5646
 
5313
5647
  // Add wheel input
5314
-
5315
5648
  vecinput.addEventListener( "wheel", function( e ) {
5316
5649
  e.preventDefault();
5317
5650
  if( this !== document.activeElement )
@@ -5325,7 +5658,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5325
5658
  for( let v of element.querySelectorAll(".vecinput") )
5326
5659
  {
5327
5660
  v.value = round( +v.valueAsNumber - mult * ( e.deltaY > 0 ? 1 : -1 ), options.precision );
5328
- Panel._dispatch_event(v, "change");
5661
+ Panel._dispatch_event( v, "change" );
5329
5662
  }
5330
5663
  }
5331
5664
  else
@@ -5338,7 +5671,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5338
5671
  vecinput.addEventListener( "change", e => {
5339
5672
 
5340
5673
  if( isNaN( e.target.value ) )
5674
+ {
5341
5675
  return;
5676
+ }
5342
5677
 
5343
5678
  const skipCallback = e.detail;
5344
5679
 
@@ -5349,7 +5684,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5349
5684
  if( !skipCallback )
5350
5685
  {
5351
5686
  let btn = element.querySelector( ".lexwidgetname .lexicon" );
5352
- if( btn ) btn.style.display = val != vecinput.iValue ? "block": "none";
5687
+ if( btn ) btn.style.display = val != vecinput.iValue ? "block" : "none";
5353
5688
  }
5354
5689
 
5355
5690
  if( locker.locked )
@@ -5358,7 +5693,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5358
5693
  v.value = val;
5359
5694
  value[ v.idx ] = val;
5360
5695
  }
5361
- } else {
5696
+ }
5697
+ else
5698
+ {
5362
5699
  vecinput.value = val;
5363
5700
  value[ e.target.idx ] = val;
5364
5701
  }
@@ -5371,70 +5708,118 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5371
5708
  vecinput.addEventListener( "mousedown", inner_mousedown );
5372
5709
 
5373
5710
  var that = this;
5374
- var lastY = 0;
5375
- function inner_mousedown(e) {
5376
- if(document.activeElement == vecinput) return;
5711
+
5712
+ function inner_mousedown( e )
5713
+ {
5714
+ if( document.activeElement == vecinput )
5715
+ {
5716
+ return;
5717
+ }
5718
+
5377
5719
  var doc = that.root.ownerDocument;
5378
- doc.addEventListener("mousemove",inner_mousemove);
5379
- doc.addEventListener("mouseup",inner_mouseup);
5380
- lastY = e.pageY;
5381
- document.body.classList.add('nocursor');
5382
- document.body.classList.add('noevents');
5383
- dragIcon.classList.remove('hidden');
5720
+ doc.addEventListener( 'mousemove', inner_mousemove );
5721
+ doc.addEventListener( 'mouseup', inner_mouseup );
5722
+ document.body.classList.add( 'nocursor' );
5723
+ document.body.classList.add( 'noevents' );
5724
+ dragIcon.classList.remove( 'hidden' );
5384
5725
  e.stopImmediatePropagation();
5385
5726
  e.stopPropagation();
5727
+
5728
+ if( !document.pointerLockElement )
5729
+ {
5730
+ vecinput.requestPointerLock();
5731
+ }
5732
+
5733
+ if( options.onPress )
5734
+ {
5735
+ options.onPress.bind( vecinput )( e, vecinput );
5736
+ }
5386
5737
  }
5387
5738
 
5388
- function inner_mousemove(e) {
5389
- if (lastY != e.pageY) {
5390
- let dt = lastY - e.pageY;
5739
+ function inner_mousemove( e )
5740
+ {
5741
+ let dt = -e.movementY;
5742
+
5743
+ if ( dt != 0 )
5744
+ {
5391
5745
  let mult = options.step ?? 1;
5392
- if(e.shiftKey) mult = 10;
5393
- else if(e.altKey) mult = 0.1;
5746
+ if( e.shiftKey ) mult = 10;
5747
+ else if( e.altKey ) mult = 0.1;
5394
5748
 
5395
5749
  if( locker.locked )
5396
5750
  {
5397
- for( let v of element.querySelectorAll(".vecinput") ) {
5751
+ for( let v of element.querySelectorAll( ".vecinput" ) ) {
5398
5752
  v.value = round( +v.valueAsNumber + mult * dt, options.precision );
5399
- Panel._dispatch_event(v, "change");
5753
+ Panel._dispatch_event( v, "change" );
5400
5754
  }
5401
- } else {
5755
+ }
5756
+ else
5757
+ {
5402
5758
  vecinput.value = round( +vecinput.valueAsNumber + mult * dt, options.precision );
5403
- Panel._dispatch_event(vecinput, "change");
5759
+ Panel._dispatch_event( vecinput, "change" );
5404
5760
  }
5405
5761
  }
5406
5762
 
5407
- lastY = e.pageY;
5408
5763
  e.stopPropagation();
5409
5764
  e.preventDefault();
5410
5765
  }
5411
5766
 
5412
- function inner_mouseup( e ) {
5767
+ function inner_mouseup( e )
5768
+ {
5413
5769
  var doc = that.root.ownerDocument;
5414
- doc.removeEventListener("mousemove",inner_mousemove);
5415
- doc.removeEventListener("mouseup",inner_mouseup);
5416
- document.body.classList.remove('nocursor');
5417
- document.body.classList.remove('noevents');
5770
+ doc.removeEventListener( 'mousemove', inner_mousemove );
5771
+ doc.removeEventListener( 'mouseup', inner_mouseup );
5772
+ document.body.classList.remove( 'noevents' );
5418
5773
  dragIcon.classList.add('hidden');
5774
+
5775
+ if( document.pointerLockElement )
5776
+ {
5777
+ document.exitPointerLock();
5778
+ }
5779
+
5780
+ if( options.onRelease )
5781
+ {
5782
+ options.onRelease.bind( vecinput )( e, vecinput );
5783
+ }
5419
5784
  }
5420
5785
 
5421
5786
  box.appendChild( vecinput );
5422
5787
  container.appendChild( box );
5423
5788
  }
5424
5789
 
5425
- let locker = document.createElement('a');
5790
+ // Method to change min, max, step parameters
5791
+ if( options.min !== undefined || options.max !== undefined )
5792
+ {
5793
+ widget.setLimits = ( newMin, newMax, newStep ) => {
5794
+ const inputs = element.querySelectorAll(".vecinput");
5795
+ for( let v of inputs )
5796
+ {
5797
+ v.min = newMin ?? v.min;
5798
+ v.max = newMax ?? v.max;
5799
+ v.step = newStep ?? v.step;
5800
+ Panel._dispatch_event( v, "change", true );
5801
+ }
5802
+
5803
+ // To call onChange callback
5804
+ this._trigger( new IEvent( name, value ), callback );
5805
+ };
5806
+ }
5807
+
5808
+ let locker = document.createElement( 'a' );
5426
5809
  locker.className = "fa-solid fa-lock-open lexicon";
5427
- container.appendChild(locker);
5428
- locker.addEventListener("click", function(e) {
5810
+ container.appendChild( locker );
5811
+ locker.addEventListener( "click", function( e ) {
5429
5812
  this.locked = !this.locked;
5430
- if(this.locked){
5431
- this.classList.add("fa-lock");
5432
- this.classList.remove("fa-lock-open");
5433
- } else {
5434
- this.classList.add("fa-lock-open");
5435
- this.classList.remove("fa-lock");
5436
- }
5437
- }, false);
5813
+ if( this.locked )
5814
+ {
5815
+ this.classList.add( "fa-lock" );
5816
+ this.classList.remove( "fa-lock-open" );
5817
+ }
5818
+ else {
5819
+ this.classList.add( "fa-lock-open" );
5820
+ this.classList.remove( "fa-lock" );
5821
+ }
5822
+ }, false );
5438
5823
 
5439
5824
  element.appendChild( container );
5440
5825
 
@@ -5450,21 +5835,231 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5450
5835
  * disabled: Make the widget disabled [false]
5451
5836
  * step: Step of the inputs
5452
5837
  * min, max: Min and Max values for the inputs
5838
+ * onPress: Callback function on mouse down
5839
+ * onRelease: Callback function on mouse up
5453
5840
  */
5454
5841
 
5455
5842
  addVector2( name, value, callback, options ) {
5456
5843
 
5457
- return this._add_vector(2, name, value, callback, options);
5844
+ return this._add_vector( 2, name, value, callback, options );
5458
5845
  }
5459
5846
 
5460
5847
  addVector3( name, value, callback, options ) {
5461
5848
 
5462
- return this._add_vector(3, name, value, callback, options);
5849
+ return this._add_vector( 3, name, value, callback, options );
5463
5850
  }
5464
5851
 
5465
5852
  addVector4( name, value, callback, options ) {
5466
5853
 
5467
- return this._add_vector(4, name, value, callback, options);
5854
+ return this._add_vector( 4, name, value, callback, options );
5855
+ }
5856
+
5857
+ /**
5858
+ * @method addSize
5859
+ * @param {String} name Widget name
5860
+ * @param {Number} value Default number value
5861
+ * @param {Function} callback Callback function on change
5862
+ * @param {*} options:
5863
+ * disabled: Make the widget disabled [false]
5864
+ * units: Unit as string added to the end of the value
5865
+ */
5866
+
5867
+ addSize( name, value, callback, options = {} ) {
5868
+
5869
+ let widget = this.create_widget( name, Widget.SIZE, options );
5870
+
5871
+ widget.onGetValue = () => {
5872
+ const value = [];
5873
+ for( let i = 0; i < element.dimensions.length; ++i )
5874
+ {
5875
+ value.push( element.dimensions[ i ].onGetValue() );
5876
+ }
5877
+ return value;
5878
+ };
5879
+
5880
+ widget.onSetValue = ( newValue, skipCallback ) => {
5881
+ for( let i = 0; i < element.dimensions.length; ++i )
5882
+ {
5883
+ element.dimensions[ i ].onSetValue( newValue[ i ], skipCallback );
5884
+ }
5885
+ };
5886
+
5887
+ let element = widget.domEl;
5888
+
5889
+ this.queue( element );
5890
+
5891
+ element.dimensions = [];
5892
+
5893
+ for( let i = 0; i < value.length; ++i )
5894
+ {
5895
+ const size = measureRealWidth( JSON.stringify( value[ i ] ), 24 ) + 'px';
5896
+ element.dimensions[ i ] = this.addNumber( null, value[ i ], ( v ) => {
5897
+
5898
+ const value = [];
5899
+
5900
+ for( let i = 0; i < element.dimensions.length; ++i )
5901
+ {
5902
+ value.push( element.dimensions[ i ].onGetValue() );
5903
+ }
5904
+
5905
+ if( callback )
5906
+ {
5907
+ callback( value );
5908
+ }
5909
+
5910
+ }, { width: size, min: 0, disabled: options.disabled } );
5911
+
5912
+ if( ( i + 1 ) != value.length )
5913
+ {
5914
+ let cross = document.createElement( 'a' );
5915
+ cross.className = "lexsizecross fa-solid fa-xmark";
5916
+ element.appendChild( cross );
5917
+ }
5918
+ }
5919
+
5920
+ this.clearQueue();
5921
+
5922
+ if( options.units )
5923
+ {
5924
+ let unitSpan = document.createElement( 'span' );
5925
+ unitSpan.className = "lexunit";
5926
+ unitSpan.innerText = options.units;
5927
+ element.appendChild( unitSpan );
5928
+ }
5929
+
5930
+ // Remove branch padding and margins
5931
+ if( !widget.name )
5932
+ {
5933
+ element.className += " noname";
5934
+ container.style.width = "100%";
5935
+ }
5936
+
5937
+ return widget;
5938
+ }
5939
+
5940
+ /**
5941
+ * @method addPad
5942
+ * @param {String} name Widget name
5943
+ * @param {Number} value Pad value
5944
+ * @param {Function} callback Callback function on change
5945
+ * @param {*} options:
5946
+ * disabled: Make the widget disabled [false]
5947
+ * min, max: Min and Max values
5948
+ * onPress: Callback function on mouse down
5949
+ * onRelease: Callback function on mouse up
5950
+ */
5951
+
5952
+ addPad( name, value, callback, options = {} ) {
5953
+
5954
+ if( !name )
5955
+ {
5956
+ throw( "Set Widget Name!" );
5957
+ }
5958
+
5959
+ let widget = this.create_widget( name, Widget.PAD, options );
5960
+
5961
+ widget.onGetValue = () => {
5962
+ return thumb.value.xy;
5963
+ };
5964
+
5965
+ widget.onSetValue = ( newValue, skipCallback ) => {
5966
+ thumb.value.set( newValue[ 0 ], newValue[ 1 ] );
5967
+ _updateValue( thumb.value );
5968
+ if( !skipCallback )
5969
+ {
5970
+ this._trigger( new IEvent( name, thumb.value.xy ), callback );
5971
+ }
5972
+ };
5973
+
5974
+ let element = widget.domEl;
5975
+
5976
+ var container = document.createElement( 'div' );
5977
+ container.className = "lexpad";
5978
+ container.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
5979
+
5980
+ let pad = document.createElement('div');
5981
+ pad.id = "lexpad-" + name;
5982
+ pad.className = "lexinnerpad";
5983
+ pad.style.width = options.padSize ?? '96px';
5984
+ pad.style.height = options.padSize ?? '96px';
5985
+
5986
+ let thumb = document.createElement('div');
5987
+ thumb.className = "lexpadthumb";
5988
+ thumb.value = new LX.vec2( value[ 0 ], value[ 1 ] );
5989
+ thumb.min = options.min ?? 0;
5990
+ thumb.max = options.max ?? 1;
5991
+
5992
+ let _updateValue = v => {
5993
+ const [ w, h ] = [ pad.offsetWidth, pad.offsetHeight ];
5994
+ const value0to1 = new LX.vec2( remapRange( v.x, thumb.min, thumb.max, 0.0, 1.0 ), remapRange( v.y, thumb.min, thumb.max, 0.0, 1.0 ) );
5995
+ thumb.style.transform = `translate(calc( ${ w * value0to1.x }px - 50% ), calc( ${ h * value0to1.y }px - 50%)`;
5996
+ }
5997
+
5998
+ doAsync( () => {
5999
+ _updateValue( thumb.value )
6000
+ } );
6001
+
6002
+ pad.appendChild( thumb );
6003
+ container.appendChild( pad );
6004
+ element.appendChild( container );
6005
+
6006
+ pad.addEventListener( "mousedown", innerMouseDown );
6007
+
6008
+ let that = this;
6009
+
6010
+ function innerMouseDown( e )
6011
+ {
6012
+ if( document.activeElement == thumb )
6013
+ {
6014
+ return;
6015
+ }
6016
+
6017
+ var doc = that.root.ownerDocument;
6018
+ doc.addEventListener( 'mousemove', innerMouseMove );
6019
+ doc.addEventListener( 'mouseup', innerMouseUp );
6020
+ document.body.classList.add( 'nocursor' );
6021
+ document.body.classList.add( 'noevents' );
6022
+ e.stopImmediatePropagation();
6023
+ e.stopPropagation();
6024
+
6025
+ if( options.onPress )
6026
+ {
6027
+ options.onPress.bind( thumb )( e, thumb );
6028
+ }
6029
+ }
6030
+
6031
+ function innerMouseMove( e )
6032
+ {
6033
+ const rect = pad.getBoundingClientRect();
6034
+ const relativePosition = new LX.vec2( e.x - rect.x, e.y - rect.y );
6035
+ relativePosition.clp( 0.0, pad.offsetWidth, relativePosition);
6036
+ const [ w, h ] = [ pad.offsetWidth, pad.offsetHeight ];
6037
+ const value0to1 = relativePosition.div( new LX.vec2( pad.offsetWidth, pad.offsetHeight ) );
6038
+
6039
+ thumb.style.transform = `translate(calc( ${ w * value0to1.x }px - 50% ), calc( ${ h * value0to1.y }px - 50%)`;
6040
+ thumb.value = new LX.vec2( remapRange( value0to1.x, 0.0, 1.0, thumb.min, thumb.max ), remapRange( value0to1.y, 0.0, 1.0, thumb.min, thumb.max ) );
6041
+
6042
+ that._trigger( new IEvent( name, thumb.value.xy, e ), callback );
6043
+
6044
+ e.stopPropagation();
6045
+ e.preventDefault();
6046
+ }
6047
+
6048
+ function innerMouseUp( e )
6049
+ {
6050
+ var doc = that.root.ownerDocument;
6051
+ doc.removeEventListener( 'mousemove', innerMouseMove );
6052
+ doc.removeEventListener( 'mouseup', innerMouseUp );
6053
+ document.body.classList.remove( 'nocursor' );
6054
+ document.body.classList.remove( 'noevents' );
6055
+
6056
+ if( options.onRelease )
6057
+ {
6058
+ options.onRelease.bind( thumb )( e, thumb );
6059
+ }
6060
+ }
6061
+
6062
+ return widget;
5468
6063
  }
5469
6064
 
5470
6065
  /**
@@ -5965,8 +6560,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
5965
6560
 
5966
6561
  this.grabber = grabber;
5967
6562
 
5968
- function getBranchHeight(){
5969
-
6563
+ function getBranchHeight() {
5970
6564
  return that.root.offsetHeight - that.root.children[0].offsetHeight;
5971
6565
  }
5972
6566
 
@@ -6020,20 +6614,23 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6020
6614
  var size = this.grabber.style.marginLeft;
6021
6615
 
6022
6616
  // Update sizes of widgets inside
6023
- for(var i = 0; i < this.widgets.length;i++) {
6617
+ for(var i = 0; i < this.widgets.length; i++) {
6024
6618
 
6025
- let widget = this.widgets[i];
6619
+ let widget = this.widgets[ i ];
6026
6620
  let element = widget.domEl;
6027
6621
 
6028
- if(element.children.length < 2)
6622
+ if( element.children.length < 2 )
6623
+ {
6029
6624
  continue;
6625
+ }
6030
6626
 
6031
- var name = element.children[0];
6032
- var value = element.children[1];
6627
+ var name = element.children[ 0 ];
6628
+ var value = element.children[ 1 ];
6033
6629
 
6034
6630
  name.style.width = size;
6035
6631
  let padding = "0px";
6036
- switch(widget.type) {
6632
+ switch( widget.type )
6633
+ {
6037
6634
  case Widget.FILE:
6038
6635
  padding = "10%";
6039
6636
  break;
@@ -6046,7 +6643,10 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6046
6643
  value.style.width = "-webkit-calc( 100% - " + size + " - " + padding + " )";
6047
6644
  value.style.width = "calc( 100% - " + size + " - " + padding + " )";
6048
6645
 
6049
- if(widget.onresize) widget.onresize();
6646
+ if( widget.onresize )
6647
+ {
6648
+ widget.onresize();
6649
+ }
6050
6650
  }
6051
6651
  }
6052
6652
  };
@@ -6063,8 +6663,10 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6063
6663
 
6064
6664
  constructor( title, callback, options = {} ) {
6065
6665
 
6066
- if(!callback)
6067
- console.warn("Content is empty, add some widgets using 'callback' parameter!");
6666
+ if( !callback )
6667
+ {
6668
+ console.warn("Content is empty, add some widgets using 'callback' parameter!");
6669
+ }
6068
6670
 
6069
6671
  this._oncreate = callback;
6070
6672
  this.id = simple_guidGenerator();
@@ -6074,8 +6676,10 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6074
6676
  draggable = options.draggable ?? true,
6075
6677
  modal = options.modal ?? false;
6076
6678
 
6077
- if(modal)
6078
- LX.modal.toggle(false);
6679
+ if( modal )
6680
+ {
6681
+ LX.modal.toggle( false );
6682
+ }
6079
6683
 
6080
6684
  var root = document.createElement('div');
6081
6685
  root.className = "lexdialog " + (options.class ?? "");
@@ -6086,8 +6690,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6086
6690
 
6087
6691
  var titleDiv = document.createElement('div');
6088
6692
 
6089
- if(title) {
6090
-
6693
+ if( title )
6694
+ {
6091
6695
  titleDiv.className = "lexdialogtitle";
6092
6696
  titleDiv.innerHTML = title;
6093
6697
  titleDiv.setAttribute('draggable', false);
@@ -6191,7 +6795,9 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6191
6795
  this.title = titleDiv;
6192
6796
 
6193
6797
  if( draggable )
6194
- makeDraggable( root, { targetClass: 'lexdialogtitle' } );
6798
+ {
6799
+ makeDraggable( root, Object.assign( { targetClass: 'lexdialogtitle' }, options ) );
6800
+ }
6195
6801
 
6196
6802
  // Process position and size
6197
6803
  if(size.length && typeof(size[0]) != "string")
@@ -6366,28 +6972,42 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6366
6972
  }
6367
6973
  }
6368
6974
 
6369
- _adjust_position(div, margin, useAbsolute = false) {
6370
-
6975
+ _adjust_position( div, margin, useAbsolute = false ) {
6976
+
6371
6977
  let rect = div.getBoundingClientRect();
6372
6978
 
6373
- if(!useAbsolute)
6979
+ if( !useAbsolute )
6374
6980
  {
6375
6981
  let width = rect.width;
6376
- if(window.innerWidth - rect.right < 0)
6982
+ if( rect.left < 0 )
6983
+ {
6984
+ div.style.left = margin + "px";
6985
+ }
6986
+ else if( window.innerWidth - rect.right < 0 )
6987
+ {
6377
6988
  div.style.left = (window.innerWidth - width - margin) + "px";
6989
+ }
6378
6990
 
6379
- if(rect.top + rect.height > window.innerHeight)
6991
+ if( rect.top < 0 )
6992
+ {
6993
+ div.style.top = margin + "px";
6994
+ }
6995
+ else if( (rect.top + rect.height) > window.innerHeight )
6996
+ {
6380
6997
  div.style.top = (window.innerHeight - rect.height - margin) + "px";
6998
+ }
6381
6999
  }
6382
7000
  else
6383
7001
  {
6384
7002
  let dt = window.innerWidth - rect.right;
6385
- if(dt < 0) {
7003
+ if( dt < 0 )
7004
+ {
6386
7005
  div.style.left = div.offsetLeft + (dt - margin) + "px";
6387
7006
  }
6388
7007
 
6389
7008
  dt = window.innerHeight - (rect.top + rect.height);
6390
- if(dt < 0) {
7009
+ if( dt < 0 )
7010
+ {
6391
7011
  div.style.top = div.offsetTop + (dt - margin + 20 ) + "px";
6392
7012
  }
6393
7013
  }