lexgui 0.1.40 → 0.1.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  var LX = {
11
- version: "0.1.40",
11
+ version: "0.1.42",
12
12
  ready: false,
13
13
  components: [], // specific pre-build components
14
14
  signals: {} // events and triggers
@@ -498,7 +498,7 @@ function create_global_searchbar( root ) {
498
498
  * @param {Object} options
499
499
  * container: Root location for the gui (default is the document body)
500
500
  * id: Id of the main area
501
- * skip_default_area: Skip creation of main area
501
+ * skipDefaultArea: Skip creation of main area
502
502
  */
503
503
 
504
504
  function init( options = { } )
@@ -543,7 +543,8 @@ function init( options = { } )
543
543
  var link = document.createElement( 'link' );
544
544
  link.rel = 'stylesheet';
545
545
  link.type = 'text/css';
546
- link.href = 'https://use.fontawesome.com/releases/v6.6.0/css/all.css';
546
+ link.crossOrigin = 'anonymous';
547
+ link.href = 'https://use.fontawesome.com/releases/v6.7.2/css/all.css';
547
548
  head.appendChild( link );
548
549
 
549
550
  // Global vars
@@ -554,8 +555,10 @@ function init( options = { } )
554
555
  this.ready = true;
555
556
  this.menubars = [ ];
556
557
 
557
- if( !options.skip_default_area )
558
+ if( !options.skipDefaultArea )
559
+ {
558
560
  this.main_area = new Area( { id: options.id ?? 'mainarea' } );
561
+ }
559
562
 
560
563
  return this.main_area;
561
564
  }
@@ -572,16 +575,18 @@ LX.init = init;
572
575
  * draggable: Dialog can be dragged [false]
573
576
  */
574
577
 
575
- function message(text, title, options = {})
578
+ function message( text, title, options = {} )
576
579
  {
577
- if(!text)
578
- throw("No message to show");
580
+ if( !text )
581
+ {
582
+ throw( "No message to show" );
583
+ }
579
584
 
580
585
  options.modal = true;
581
586
 
582
- return new Dialog(title, p => {
583
- p.addTextArea(null, text, null, { disabled: true, fitHeight: true });
584
- }, options);
587
+ return new Dialog( title, p => {
588
+ p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
589
+ }, options );
585
590
  }
586
591
 
587
592
  LX.message = message;
@@ -661,7 +666,8 @@ function prompt( text, title, callback, options = {} )
661
666
  text += text.includes("You must fill the input text.") ? "": "\nYou must fill the input text.";
662
667
  dialog.close();
663
668
  prompt( text, title, callback, options );
664
- }else
669
+ }
670
+ else
665
671
  {
666
672
  if( callback ) callback.call( this, value );
667
673
  dialog.close();
@@ -741,7 +747,9 @@ function emit( signalName, value, options = {} )
741
747
  const data = LX.signals[ signalName ];
742
748
 
743
749
  if( !data )
744
- return;
750
+ {
751
+ return;
752
+ }
745
753
 
746
754
  const target = options.target;
747
755
 
@@ -780,10 +788,14 @@ function addSignal( name, obj, callback )
780
788
  obj[name] = callback;
781
789
 
782
790
  if( !LX.signals[ name ] )
791
+ {
783
792
  LX.signals[ name ] = [];
793
+ }
784
794
 
785
795
  if( LX.signals[ name ].indexOf( obj ) > -1 )
796
+ {
786
797
  return;
798
+ }
787
799
 
788
800
  LX.signals[ name ].push( obj );
789
801
  }
@@ -803,7 +815,7 @@ class Area {
803
815
  * className: Add class to the element
804
816
  * width: Width of the area element [fit space]
805
817
  * height: Height of the area element [fit space]
806
- * no_append: Create but not append to GUI root [false]
818
+ * skipAppend: Create but not append to GUI root [false]
807
819
  */
808
820
 
809
821
  constructor( options = {} ) {
@@ -843,7 +855,7 @@ class Area {
843
855
  this.sections = [];
844
856
  this.panels = [];
845
857
 
846
- if( !options.no_append )
858
+ if( !options.skipAppend )
847
859
  {
848
860
  var lexroot = document.getElementById("lexroot");
849
861
  lexroot.appendChild( this.root );
@@ -878,94 +890,97 @@ class Area {
878
890
  makeDraggable( root, options );
879
891
  }
880
892
 
881
- if( options.resizeable ) {
893
+ if( options.resizeable )
894
+ {
882
895
  root.classList.add("resizeable");
883
896
  }
884
897
 
885
898
  if( options.resize )
886
899
  {
887
- this.split_bar = document.createElement("div");
900
+ this.splitBar = document.createElement("div");
888
901
  let type = (overlay == "left") || (overlay == "right") ? "horizontal" : "vertical";
889
- this.type = overlay;;
890
- this.split_bar.className = "lexsplitbar " + type;
902
+ this.type = overlay;
903
+ this.splitBar.className = "lexsplitbar " + type;
891
904
 
892
905
  if( overlay == "right" )
893
906
  {
894
- this.split_bar.style.width = LX.DEFAULT_SPLITBAR_SIZE + "px";
895
- this.split_bar.style.left = -(LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
907
+ this.splitBar.style.width = LX.DEFAULT_SPLITBAR_SIZE + "px";
908
+ this.splitBar.style.left = -(LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
896
909
  }
897
910
  else if( overlay == "left" )
898
911
  {
899
912
  let size = Math.min(document.body.clientWidth - LX.DEFAULT_SPLITBAR_SIZE, this.root.clientWidth);
900
- this.split_bar.style.width = LX.DEFAULT_SPLITBAR_SIZE + "px";
901
- this.split_bar.style.left = size + (LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
913
+ this.splitBar.style.width = LX.DEFAULT_SPLITBAR_SIZE + "px";
914
+ this.splitBar.style.left = size + (LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
902
915
  }
903
916
  else if( overlay == "top" )
904
917
  {
905
918
  let size = Math.min(document.body.clientHeight - LX.DEFAULT_SPLITBAR_SIZE, this.root.clientHeight);
906
- this.split_bar.style.height = LX.DEFAULT_SPLITBAR_SIZE + "px";
907
- this.split_bar.style.top = size + (LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
919
+ this.splitBar.style.height = LX.DEFAULT_SPLITBAR_SIZE + "px";
920
+ this.splitBar.style.top = size + (LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
908
921
  }
909
922
  else if( overlay == "bottom" )
910
923
  {
911
- this.split_bar.style.height = LX.DEFAULT_SPLITBAR_SIZE + "px";
912
- this.split_bar.style.top = -(LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
924
+ this.splitBar.style.height = LX.DEFAULT_SPLITBAR_SIZE + "px";
925
+ this.splitBar.style.top = -(LX.DEFAULT_SPLITBAR_SIZE / 2.0) + "px";
913
926
  }
914
927
 
915
- this.split_bar.addEventListener("mousedown", inner_mousedown);
916
- this.root.appendChild( this.split_bar );
928
+ this.splitBar.addEventListener("mousedown", inner_mousedown);
929
+ this.root.appendChild( this.splitBar );
917
930
 
918
931
  var that = this;
919
- var last_pos = [ 0, 0 ];
932
+ var lastMousePosition = [ 0, 0 ];
920
933
 
921
934
  function inner_mousedown( e )
922
935
  {
923
936
  var doc = that.root.ownerDocument;
924
937
  doc.addEventListener( 'mousemove', inner_mousemove );
925
938
  doc.addEventListener( 'mouseup', inner_mouseup );
926
- last_pos[ 0 ] = e.x;
927
- last_pos[ 1 ] = e.y;
939
+ lastMousePosition[ 0 ] = e.x;
940
+ lastMousePosition[ 1 ] = e.y;
928
941
  e.stopPropagation();
929
942
  e.preventDefault();
930
943
  document.body.classList.add( 'nocursor' );
931
- that.split_bar.classList.add( 'nocursor' );
944
+ that.splitBar.classList.add( 'nocursor' );
932
945
  }
933
946
 
934
947
  function inner_mousemove( e )
935
948
  {
936
949
  switch( that.type ) {
937
950
  case "right":
938
- var dt = ( last_pos[ 0 ] - e.x );
951
+ var dt = ( lastMousePosition[ 0 ] - e.x );
939
952
  var size = ( that.root.offsetWidth + dt );
940
953
  that.root.style.width = size + "px";
941
954
  break;
942
955
  case "left":
943
- var dt = ( last_pos[ 0 ] - e.x );
956
+ var dt = ( lastMousePosition[ 0 ] - e.x );
944
957
  var size = Math.min(document.body.clientWidth - LX.DEFAULT_SPLITBAR_SIZE, (that.root.offsetWidth - dt));
945
958
  that.root.style.width = size + "px";
946
- that.split_bar.style.left = size + LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
959
+ that.splitBar.style.left = size + LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
947
960
  break;
948
961
  case "top":
949
- var dt = ( last_pos[ 1 ] - e.y );
962
+ var dt = ( lastMousePosition[ 1 ] - e.y );
950
963
  var size = Math.min(document.body.clientHeight - LX.DEFAULT_SPLITBAR_SIZE, (that.root.offsetHeight - dt));
951
964
  that.root.style.height = size + "px";
952
- that.split_bar.style.top = size + LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
965
+ that.splitBar.style.top = size + LX.DEFAULT_SPLITBAR_SIZE/2 + "px";
953
966
  break;
954
967
  case "bottom":
955
- var dt = ( last_pos[ 1 ] - e.y );
968
+ var dt = ( lastMousePosition[ 1 ] - e.y );
956
969
  var size = ( that.root.offsetHeight + dt );
957
970
  that.root.style.height = size + "px";
958
971
  break;
959
972
  }
960
973
 
961
- last_pos[ 0 ] = e.x;
962
- last_pos[ 1 ] = e.y;
974
+ lastMousePosition[ 0 ] = e.x;
975
+ lastMousePosition[ 1 ] = e.y;
963
976
  e.stopPropagation();
964
977
  e.preventDefault();
965
978
 
966
979
  // Resize events
967
980
  if( that.onresize )
981
+ {
968
982
  that.onresize( that.root.getBoundingClientRect() );
983
+ }
969
984
  }
970
985
 
971
986
  function inner_mouseup( e )
@@ -974,7 +989,7 @@ class Area {
974
989
  doc.removeEventListener( 'mousemove', inner_mousemove );
975
990
  doc.removeEventListener( 'mouseup', inner_mouseup );
976
991
  document.body.classList.remove( 'nocursor' );
977
- that.split_bar.classList.remove( 'nocursor' );
992
+ that.splitBar.classList.remove( 'nocursor' );
978
993
  }
979
994
  }
980
995
  }
@@ -988,13 +1003,16 @@ class Area {
988
1003
  attach( content ) {
989
1004
 
990
1005
  // Append to last split section if area has been split
991
- if(this.sections.length) {
992
- this.sections[1].attach( content );
1006
+ if( this.sections.length)
1007
+ {
1008
+ this.sections[ 1 ].attach( content );
993
1009
  return;
994
1010
  }
995
1011
 
996
- if(!content)
997
- throw("no content to attach");
1012
+ if( !content )
1013
+ {
1014
+ throw("no content to attach");
1015
+ }
998
1016
 
999
1017
  content.parent = this;
1000
1018
 
@@ -1039,14 +1057,14 @@ class Area {
1039
1057
  }
1040
1058
 
1041
1059
  // Create areas
1042
- var area1 = new Area( { no_append: true, className: "split" + ( options.menubar || options.sidebar ? "" : " origin" ) } );
1043
- var area2 = new Area( { no_append: true, className: "split"} );
1060
+ var area1 = new Area( { skipAppend: true, className: "split" + ( options.menubar || options.sidebar ? "" : " origin" ) } );
1061
+ var area2 = new Area( { skipAppend: true, className: "split" } );
1044
1062
 
1045
1063
  area1.parentArea = this;
1046
1064
  area2.parentArea = this;
1047
1065
 
1048
1066
  let minimizable = options.minimizable ?? false;
1049
- let resize = (options.resize ?? true) || minimizable;
1067
+ let resize = ( options.resize ?? true ) || minimizable;
1050
1068
 
1051
1069
  var data = "0px";
1052
1070
  this.offset = 0;
@@ -1054,19 +1072,19 @@ class Area {
1054
1072
  if( resize )
1055
1073
  {
1056
1074
  this.resize = resize;
1057
- this.split_bar = document.createElement( "div" );
1058
- this.split_bar.className = "lexsplitbar " + type;
1075
+ this.splitBar = document.createElement( "div" );
1076
+ this.splitBar.className = "lexsplitbar " + type;
1059
1077
 
1060
1078
  if( type == "horizontal" )
1061
1079
  {
1062
- this.split_bar.style.width = LX.DEFAULT_SPLITBAR_SIZE + "px";
1080
+ this.splitBar.style.width = LX.DEFAULT_SPLITBAR_SIZE + "px";
1063
1081
  }
1064
1082
  else
1065
1083
  {
1066
- this.split_bar.style.height = LX.DEFAULT_SPLITBAR_SIZE + "px";
1084
+ this.splitBar.style.height = LX.DEFAULT_SPLITBAR_SIZE + "px";
1067
1085
  }
1068
1086
 
1069
- this.split_bar.addEventListener( 'mousedown', inner_mousedown );
1087
+ this.splitBar.addEventListener( 'mousedown', inner_mousedown );
1070
1088
 
1071
1089
  data = ( LX.DEFAULT_SPLITBAR_SIZE / 2 ) + "px"; // updates
1072
1090
 
@@ -1083,7 +1101,7 @@ class Area {
1083
1101
  flushCss(area2.root);
1084
1102
  });
1085
1103
 
1086
- this.split_bar.addEventListener("contextmenu", e => {
1104
+ this.splitBar.addEventListener("contextmenu", e => {
1087
1105
  e.preventDefault();
1088
1106
  addContextMenu(null, e, c => {
1089
1107
  c.add("Extend", { disabled: this.split_extended, callback: () => { this.extend() } });
@@ -1114,7 +1132,7 @@ class Area {
1114
1132
  area1.root.style.width = "100%";
1115
1133
  area2.root.style.width = "100%";
1116
1134
 
1117
- if(auto)
1135
+ if( auto )
1118
1136
  {
1119
1137
  area1.root.style.height = "auto";
1120
1138
 
@@ -1148,11 +1166,11 @@ class Area {
1148
1166
 
1149
1167
  if( resize )
1150
1168
  {
1151
- this.root.appendChild(this.split_bar);
1169
+ this.root.appendChild(this.splitBar);
1152
1170
  }
1153
1171
 
1154
1172
  this.root.appendChild( area2.root );
1155
- this.sections = [area1, area2];
1173
+ this.sections = [ area1, area2 ];
1156
1174
  this.type = type;
1157
1175
 
1158
1176
  // Update sizes
@@ -1164,34 +1182,34 @@ class Area {
1164
1182
  }
1165
1183
 
1166
1184
  var that = this;
1167
- var last_pos = [ 0, 0 ];
1185
+ var lastMousePosition = [ 0, 0 ];
1168
1186
 
1169
1187
  function inner_mousedown( e )
1170
1188
  {
1171
1189
  var doc = that.root.ownerDocument;
1172
1190
  doc.addEventListener( 'mousemove', inner_mousemove );
1173
1191
  doc.addEventListener( 'mouseup', inner_mouseup );
1174
- last_pos[0] = e.x;
1175
- last_pos[1] = e.y;
1192
+ lastMousePosition[0] = e.x;
1193
+ lastMousePosition[1] = e.y;
1176
1194
  e.stopPropagation();
1177
1195
  e.preventDefault();
1178
1196
  document.body.classList.add( 'nocursor' );
1179
- that.split_bar.classList.add( 'nocursor' );
1197
+ that.splitBar.classList.add( 'nocursor' );
1180
1198
  }
1181
1199
 
1182
1200
  function inner_mousemove( e )
1183
1201
  {
1184
1202
  if(that.type == "horizontal")
1185
1203
  {
1186
- that._moveSplit( last_pos[ 0 ] - e.x );
1204
+ that._moveSplit( lastMousePosition[ 0 ] - e.x );
1187
1205
  }
1188
1206
  else
1189
1207
  {
1190
- that._moveSplit( last_pos[ 1 ] - e.y );
1208
+ that._moveSplit( lastMousePosition[ 1 ] - e.y );
1191
1209
  }
1192
1210
 
1193
- last_pos[ 0 ] = e.x;
1194
- last_pos[ 1 ] = e.y;
1211
+ lastMousePosition[ 0 ] = e.x;
1212
+ lastMousePosition[ 1 ] = e.y;
1195
1213
 
1196
1214
  const widgets = that.root.querySelectorAll( ".lexwidget" );
1197
1215
 
@@ -1216,7 +1234,7 @@ class Area {
1216
1234
  doc.removeEventListener( 'mousemove', inner_mousemove );
1217
1235
  doc.removeEventListener( 'mouseup', inner_mouseup );
1218
1236
  document.body.classList.remove( 'nocursor' );
1219
- that.split_bar.classList.remove( 'nocursor' );
1237
+ that.splitBar.classList.remove( 'nocursor' );
1220
1238
  }
1221
1239
 
1222
1240
  return this.sections;
@@ -1648,8 +1666,8 @@ class Area {
1648
1666
  _disableSplitResize() {
1649
1667
 
1650
1668
  this.resize = false;
1651
- this.split_bar.remove();
1652
- delete this.split_bar;
1669
+ this.splitBar.remove();
1670
+ delete this.splitBar;
1653
1671
  }
1654
1672
 
1655
1673
  _update() {
@@ -2470,6 +2488,18 @@ class SideBar {
2470
2488
  desc.innerHTML = key;
2471
2489
  entry.appendChild( desc );
2472
2490
 
2491
+ button.addEventListener("mouseenter", () => {
2492
+ setTimeout( () => {
2493
+ desc.style.display = "unset";
2494
+ }, 100 );
2495
+ });
2496
+
2497
+ button.addEventListener("mouseleave", () => {
2498
+ setTimeout( () => {
2499
+ desc.style.display = "none";
2500
+ }, 100 );
2501
+ });
2502
+
2473
2503
  entry.addEventListener("click", () => {
2474
2504
 
2475
2505
  const f = options.callback;
@@ -2821,7 +2851,7 @@ class NodeTree {
2821
2851
  let isParent = node.children.length > 0;
2822
2852
  let isSelected = this.selected.indexOf( node ) > -1 || node.selected;
2823
2853
 
2824
- if( this.options.only_folders )
2854
+ if( this.options.onlyFolders )
2825
2855
  {
2826
2856
  let has_folders = false;
2827
2857
  node.children.forEach( c => has_folders |= (c.type == 'folder') );
@@ -3200,7 +3230,7 @@ class NodeTree {
3200
3230
  {
3201
3231
  let child = node.children[i];
3202
3232
 
3203
- if( this.options.only_folders && child.type != 'folder')
3233
+ if( this.options.onlyFolders && child.type != 'folder')
3204
3234
  continue;
3205
3235
 
3206
3236
  this._create_item( node, child, level + 1 );
@@ -4091,14 +4121,17 @@ class Panel {
4091
4121
  * disabled: Make the widget disabled [false]
4092
4122
  * icon: Icon class to show as button value
4093
4123
  * img: Path to image to show as button value
4124
+ * title: Text to show in native Element title
4094
4125
  */
4095
4126
 
4096
4127
  addButton( name, value, callback, options = {} ) {
4097
4128
 
4098
- let widget = this.create_widget(name, Widget.BUTTON, options);
4129
+ let widget = this.create_widget( name, Widget.BUTTON, options );
4130
+
4099
4131
  widget.onGetValue = () => {
4100
4132
  return wValue.innerText;
4101
4133
  };
4134
+
4102
4135
  widget.onSetValue = ( newValue, skipCallback ) => {
4103
4136
  wValue.innerHTML =
4104
4137
  (options.icon ? "<a class='" + options.icon + "'></a>" :
@@ -4107,36 +4140,50 @@ class Panel {
4107
4140
 
4108
4141
  let element = widget.domEl;
4109
4142
 
4110
- var wValue = document.createElement('button');
4111
- if(options.icon || options.img)
4112
- wValue.title = value;
4143
+ var wValue = document.createElement( 'button' );
4144
+ wValue.title = options.title ?? "";
4113
4145
  wValue.className = "lexbutton";
4114
- if(options.selected)
4115
- wValue.classList.add("selected");
4116
- if(options.buttonClass)
4117
- wValue.classList.add(options.buttonClass);
4146
+
4147
+ if( options.selected )
4148
+ {
4149
+ wValue.classList.add( "selected" );
4150
+ }
4151
+
4152
+ if( options.buttonClass )
4153
+ {
4154
+ wValue.classList.add( options.buttonClass );
4155
+ }
4156
+
4118
4157
  wValue.innerHTML =
4119
4158
  (options.icon ? "<a class='" + options.icon + "'></a>" :
4120
4159
  ( options.img ? "<img src='" + options.img + "'>" : "<span>" + (value || "") + "</span>" ));
4121
4160
 
4122
4161
  wValue.style.width = "calc( 100% - " + (options.nameWidth ?? LX.DEFAULT_NAME_WIDTH) + ")";
4123
4162
 
4124
- if(options.disabled)
4125
- wValue.setAttribute("disabled", true);
4163
+ if( options.disabled )
4164
+ {
4165
+ wValue.setAttribute( "disabled", true );
4166
+ }
4126
4167
 
4127
4168
  wValue.addEventListener("click", e => {
4128
- if( options.selectable ) {
4169
+ if( options.selectable )
4170
+ {
4129
4171
  if( options.parent )
4172
+ {
4130
4173
  options.parent.querySelectorAll(".lexbutton.selected").forEach( e => { if(e == wValue) return; e.classList.remove("selected") } );
4174
+ }
4175
+
4131
4176
  wValue.classList.toggle('selected');
4132
4177
  }
4133
- this._trigger( new IEvent(name, value, e), callback );
4178
+
4179
+ this._trigger( new IEvent( name, value, e ), callback );
4134
4180
  });
4135
4181
 
4136
- element.appendChild(wValue);
4182
+ element.appendChild( wValue );
4137
4183
 
4138
4184
  // Remove branch padding and margins
4139
- if(!widget.name) {
4185
+ if( !widget.name )
4186
+ {
4140
4187
  wValue.className += " noname";
4141
4188
  wValue.style.width = "100%";
4142
4189
  }
@@ -6077,7 +6124,8 @@ class Panel {
6077
6124
 
6078
6125
  addProgress( name, value, options = {} ) {
6079
6126
 
6080
- if(!name) {
6127
+ if( !name )
6128
+ {
6081
6129
  throw("Set Widget Name!");
6082
6130
  }
6083
6131
 
@@ -6108,46 +6156,74 @@ class Panel {
6108
6156
  progress.max = options.max ?? 1;
6109
6157
  progress.value = value;
6110
6158
 
6111
- if(options.low)
6159
+ if( options.low )
6112
6160
  progress.low = options.low;
6113
- if(options.high)
6161
+ if( options.high )
6114
6162
  progress.high = options.high;
6115
- if(options.optimum)
6163
+ if( options.optimum )
6116
6164
  progress.optimum = options.optimum;
6117
6165
 
6118
- container.appendChild(progress);
6119
- element.appendChild(container);
6166
+ container.appendChild( progress );
6167
+ element.appendChild( container );
6120
6168
 
6121
- if(options.showValue) {
6122
- if(document.getElementById('progressvalue-' + name ))
6169
+ if( options.showValue )
6170
+ {
6171
+ if( document.getElementById('progressvalue-' + name ) )
6172
+ {
6123
6173
  document.getElementById('progressvalue-' + name ).remove();
6174
+ }
6175
+
6124
6176
  let span = document.createElement("span");
6125
6177
  span.id = "progressvalue-" + name;
6126
6178
  span.style.padding = "0px 5px";
6127
6179
  span.innerText = value;
6128
- container.appendChild(span);
6180
+ container.appendChild( span );
6129
6181
  }
6130
6182
 
6131
- if(options.editable) {
6132
- progress.classList.add("editable");
6133
- progress.addEventListener("mousemove", inner_mousemove.bind(this, value));
6134
- progress.addEventListener("mouseup", inner_mouseup.bind(this, progress));
6183
+ if( options.editable )
6184
+ {
6185
+ progress.classList.add( "editable" );
6186
+ progress.addEventListener( "mousedown", inner_mousedown );
6135
6187
 
6136
- function inner_mousemove(value, e) {
6137
-
6138
- if(e.which < 1)
6139
- return;
6140
- let v = this.getValue(name, value);
6141
- v+=e.movementX/100;
6142
- v = v.toFixed(2);
6143
- this.setValue(name, v);
6188
+ var that = this;
6144
6189
 
6145
- if(options.callback)
6146
- options.callback(v, e);
6190
+ function inner_mousedown( e )
6191
+ {
6192
+ var doc = that.root.ownerDocument;
6193
+ doc.addEventListener( 'mousemove', inner_mousemove );
6194
+ doc.addEventListener( 'mouseup', inner_mouseup );
6195
+ document.body.classList.add( 'noevents' );
6196
+ e.stopImmediatePropagation();
6197
+ e.stopPropagation();
6147
6198
  }
6148
6199
 
6149
- function inner_mouseup(el) {
6150
- el.removeEventListener("mousemove", inner_mousemove);
6200
+ function inner_mousemove( e )
6201
+ {
6202
+ let dt = -e.movementX;
6203
+
6204
+ if ( dt != 0 )
6205
+ {
6206
+ let v = that.getValue( name, value );
6207
+ v += e.movementX / 100;
6208
+ v = round( v );
6209
+ that.setValue( name, v );
6210
+
6211
+ if( options.callback )
6212
+ {
6213
+ options.callback( v, e );
6214
+ }
6215
+ }
6216
+
6217
+ e.stopPropagation();
6218
+ e.preventDefault();
6219
+ }
6220
+
6221
+ function inner_mouseup( e )
6222
+ {
6223
+ var doc = that.root.ownerDocument;
6224
+ doc.removeEventListener( 'mousemove', inner_mousemove );
6225
+ doc.removeEventListener( 'mouseup', inner_mouseup );
6226
+ document.body.classList.remove( 'noevents' );
6151
6227
  }
6152
6228
  }
6153
6229
 
@@ -7620,12 +7696,12 @@ class AssetView {
7620
7696
  this.layout = options.layout ?? AssetView.LAYOUT_CONTENT;
7621
7697
  this.contentPage = 1;
7622
7698
 
7623
- if(options.root_path)
7699
+ if( options.rootPath )
7624
7700
  {
7625
- if(options.root_path.constructor !== String)
7701
+ if(options.rootPath.constructor !== String)
7626
7702
  console.warn("Asset Root Path must be a String (now is " + path.constructor.name + ")");
7627
7703
  else
7628
- this.rootPath = options.root_path;
7704
+ this.rootPath = options.rootPath;
7629
7705
  }
7630
7706
 
7631
7707
  let div = document.createElement('div');
@@ -7637,13 +7713,15 @@ class AssetView {
7637
7713
 
7638
7714
  let left, right, contentArea = area;
7639
7715
 
7640
- this.skip_browser = options.skip_browser ?? false;
7641
- this.skip_preview = options.skip_preview ?? false;
7642
- this.only_folders = options.only_folders ?? true;
7643
- this.preview_actions = options.preview_actions ?? [];
7644
- this.context_menu = options.context_menu ?? [];
7716
+ this.skipBrowser = options.skipBrowser ?? false;
7717
+ this.skipPreview = options.skipPreview ?? false;
7718
+ this.useNativeTitle = options.useNativeTitle ?? false;
7719
+ this.onlyFolders = options.onlyFolders ?? true;
7720
+ this.previewActions = options.previewActions ?? [];
7721
+ this.contextMenu = options.contextMenu ?? [];
7722
+ this.onRefreshContent = options.onRefreshContent;
7645
7723
 
7646
- if( !this.skip_browser )
7724
+ if( !this.skipBrowser )
7647
7725
  {
7648
7726
  [left, right] = area.split({ type: "horizontal", sizes: ["15%", "85%"]});
7649
7727
  contentArea = right;
@@ -7652,28 +7730,34 @@ class AssetView {
7652
7730
  right.setLimitBox( 512, 0 );
7653
7731
  }
7654
7732
 
7655
- if( !this.skip_preview )
7656
- [contentArea, right] = contentArea.split({ type: "horizontal", sizes: ["80%", "20%"]});
7733
+ if( !this.skipPreview )
7734
+ {
7735
+ [ contentArea, right ] = contentArea.split({ type: "horizontal", sizes: ["80%", "20%"]});
7736
+ }
7657
7737
 
7658
- this.allowedTypes = options.allowed_types || ["None", "Image", "Mesh", "Script", "JSON", "Clip"];
7738
+ this.allowedTypes = options.allowedTypes || ["None", "Image", "Mesh", "Script", "JSON", "Clip"];
7659
7739
 
7660
7740
  this.prevData = [];
7661
7741
  this.nextData = [];
7662
7742
  this.data = [];
7663
7743
 
7664
- this._processData(this.data, null);
7744
+ this._processData( this.data, null );
7665
7745
 
7666
7746
  this.currentData = this.data;
7667
7747
  this.path = ['@'];
7668
7748
 
7669
- if(!this.skip_browser)
7670
- this._createTreePanel(left);
7749
+ if( !this.skipBrowser )
7750
+ {
7751
+ this._createTreePanel( left );
7752
+ }
7671
7753
 
7672
- this._createContentPanel(contentArea);
7754
+ this._createContentPanel( contentArea );
7673
7755
 
7674
7756
  // Create resource preview panel
7675
- if( !this.skip_preview )
7676
- this.previewPanel = right.addPanel({className: 'lexassetcontentpanel', style: { overflow: 'scroll' }});
7757
+ if( !this.skipPreview )
7758
+ {
7759
+ this.previewPanel = right.addPanel( {className: 'lexassetcontentpanel', style: { overflow: 'scroll' }} );
7760
+ }
7677
7761
  }
7678
7762
 
7679
7763
  /**
@@ -7687,12 +7771,15 @@ class AssetView {
7687
7771
 
7688
7772
  this.data = data;
7689
7773
 
7690
- this._processData(this.data, null);
7774
+ this._processData( this.data, null );
7691
7775
  this.currentData = this.data;
7692
- this.path = ['@'];
7776
+ this.path = [ '@' ];
7777
+
7778
+ if( !this.skipBrowser )
7779
+ {
7780
+ this._createTreePanel( this.area );
7781
+ }
7693
7782
 
7694
- if(!this.skip_browser)
7695
- this._createTreePanel(this.area);
7696
7783
  this._refreshContent();
7697
7784
 
7698
7785
  this.onevent = onevent;
@@ -7702,12 +7789,21 @@ class AssetView {
7702
7789
  * @method clear
7703
7790
  */
7704
7791
  clear() {
7705
- if(this.previewPanel)
7792
+
7793
+ if( this.previewPanel )
7794
+ {
7706
7795
  this.previewPanel.clear();
7707
- if(this.leftPanel)
7796
+ }
7797
+
7798
+ if( this.leftPanel )
7799
+ {
7708
7800
  this.leftPanel.clear();
7709
- if(this.rightPanel)
7801
+ }
7802
+
7803
+ if( this.rightPanel )
7804
+ {
7710
7805
  this.rightPanel.clear()
7806
+ }
7711
7807
  }
7712
7808
 
7713
7809
  /**
@@ -7718,14 +7814,16 @@ class AssetView {
7718
7814
 
7719
7815
  if( data.constructor !== Array )
7720
7816
  {
7721
- data['folder'] = parent;
7817
+ data[ 'folder' ] = parent;
7722
7818
  data.children = data.children ?? [];
7723
7819
  }
7724
7820
 
7725
7821
  let list = data.constructor === Array ? data : data.children;
7726
7822
 
7727
7823
  for( var i = 0; i < list.length; ++i )
7728
- this._processData( list[i], data );
7824
+ {
7825
+ this._processData( list[ i ], data );
7826
+ }
7729
7827
  }
7730
7828
 
7731
7829
  /**
@@ -7737,9 +7835,9 @@ class AssetView {
7737
7835
  this.path.length = 0;
7738
7836
 
7739
7837
  const push_parents_id = i => {
7740
- if(!i) return;
7838
+ if( !i ) return;
7741
7839
  let list = i.children ? i.children : i;
7742
- let c = list[0];
7840
+ let c = list[ 0 ];
7743
7841
  if( !c ) return;
7744
7842
  if( !c.folder ) return;
7745
7843
  this.path.push( c.folder.id ?? '@' );
@@ -7748,19 +7846,22 @@ class AssetView {
7748
7846
 
7749
7847
  push_parents_id( data );
7750
7848
 
7751
- LX.emit("@on_folder_change", this.path.reverse().join('/'));
7849
+ LX.emit( "@on_folder_change", this.path.reverse().join('/') );
7752
7850
  }
7753
7851
 
7754
7852
  /**
7755
7853
  * @method _createTreePanel
7756
7854
  */
7757
7855
 
7758
- _createTreePanel(area) {
7856
+ _createTreePanel( area ) {
7759
7857
 
7760
- if(this.leftPanel)
7858
+ if( this.leftPanel )
7859
+ {
7761
7860
  this.leftPanel.clear();
7762
- else {
7763
- this.leftPanel = area.addPanel({className: 'lexassetbrowserpanel'});
7861
+ }
7862
+ else
7863
+ {
7864
+ this.leftPanel = area.addPanel({ className: 'lexassetbrowserpanel' });
7764
7865
  }
7765
7866
 
7766
7867
  // Process data to show in tree
@@ -7769,21 +7870,24 @@ class AssetView {
7769
7870
  children: this.data
7770
7871
  }
7771
7872
 
7772
- this.tree = this.leftPanel.addTree("Content Browser", tree_data, {
7873
+ this.tree = this.leftPanel.addTree( "Content Browser", tree_data, {
7773
7874
  // icons: tree_icons,
7774
7875
  filter: false,
7775
- only_folders: this.only_folders,
7776
- onevent: (event) => {
7876
+ onlyFolders: this.onlyFolders,
7877
+ onevent: event => {
7777
7878
 
7778
7879
  let node = event.node;
7779
7880
  let value = event.value;
7780
7881
 
7781
- switch(event.type) {
7882
+ switch( event.type )
7883
+ {
7782
7884
  case LX.TreeEvent.NODE_SELECTED:
7783
- if(!event.multiple) {
7885
+ if( !event.multiple )
7886
+ {
7784
7887
  this._enterFolder( node );
7785
7888
  }
7786
- if(!node.parent) {
7889
+ if( !node.parent )
7890
+ {
7787
7891
  this.prevData.push( this.currentData );
7788
7892
  this.currentData = this.data;
7789
7893
  this._refreshContent();
@@ -7805,9 +7909,9 @@ class AssetView {
7805
7909
  * @method _setContentLayout
7806
7910
  */
7807
7911
 
7808
- _setContentLayout( layout_mode ) {
7912
+ _setContentLayout( layoutMode ) {
7809
7913
 
7810
- this.layout = layout_mode;
7914
+ this.layout = layoutMode;
7811
7915
 
7812
7916
  this._refreshContent();
7813
7917
  }
@@ -7816,15 +7920,18 @@ class AssetView {
7816
7920
  * @method _createContentPanel
7817
7921
  */
7818
7922
 
7819
- _createContentPanel(area) {
7923
+ _createContentPanel( area ) {
7820
7924
 
7821
- if(this.rightPanel)
7925
+ if( this.rightPanel )
7926
+ {
7822
7927
  this.rightPanel.clear();
7823
- else {
7824
- this.rightPanel = area.addPanel({className: 'lexassetcontentpanel'});
7928
+ }
7929
+ else
7930
+ {
7931
+ this.rightPanel = area.addPanel({ className: 'lexassetcontentpanel' });
7825
7932
  }
7826
7933
 
7827
- const on_sort = (value, event) => {
7934
+ const on_sort = ( value, event ) => {
7828
7935
  const cmenu = addContextMenu( "Sort by", event, c => {
7829
7936
  c.add("Name", () => this._sortData('id') );
7830
7937
  c.add("Type", () => this._sortData('type') );
@@ -7834,10 +7941,12 @@ class AssetView {
7834
7941
  } );
7835
7942
  const parent = this.parent.root.parentElement;
7836
7943
  if( parent.classList.contains('lexdialog') )
7944
+ {
7837
7945
  cmenu.root.style.zIndex = (+getComputedStyle( parent ).zIndex) + 1;
7946
+ }
7838
7947
  }
7839
7948
 
7840
- const on_change_view = (value, event) => {
7949
+ const on_change_view = ( value, event ) => {
7841
7950
  const cmenu = addContextMenu( "Layout", event, c => {
7842
7951
  c.add("Content", () => this._setContentLayout( AssetView.LAYOUT_CONTENT ) );
7843
7952
  c.add("");
@@ -7848,36 +7957,40 @@ class AssetView {
7848
7957
  cmenu.root.style.zIndex = (+getComputedStyle( parent ).zIndex) + 1;
7849
7958
  }
7850
7959
 
7851
- const on_change_page = (value, event) => {
7852
- if(!this.allow_next_page)
7960
+ const on_change_page = ( value, event ) => {
7961
+ if( !this.allowNextPage )
7962
+ {
7853
7963
  return;
7854
- const last_page = this.contentPage;
7964
+ }
7965
+ const lastPage = this.contentPage;
7855
7966
  this.contentPage += value;
7856
7967
  this.contentPage = Math.min( this.contentPage, (((this.currentData.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1 );
7857
7968
  this.contentPage = Math.max( this.contentPage, 1 );
7858
7969
 
7859
- if( last_page != this.contentPage )
7970
+ if( lastPage != this.contentPage )
7971
+ {
7860
7972
  this._refreshContent();
7973
+ }
7861
7974
  }
7862
7975
 
7863
7976
  this.rightPanel.sameLine();
7864
- this.rightPanel.addDropdown("Filter", this.allowedTypes, this.allowedTypes[0], (v) => this._refreshContent.call(this, null, v), { width: "20%", minWidth: "128px" });
7865
- this.rightPanel.addText(null, this.search_value ?? "", (v) => this._refreshContent.call(this, v, null), { placeholder: "Search assets.." });
7866
- this.rightPanel.addButton(null, "<a class='fa fa-arrow-up-short-wide'></a>", on_sort.bind(this), { className: "micro", title: "Sort" });
7867
- this.rightPanel.addButton(null, "<a class='fa-solid fa-grip'></a>", on_change_view.bind(this), { className: "micro", title: "View" });
7977
+ this.rightPanel.addDropdown( "Filter", this.allowedTypes, this.allowedTypes[ 0 ], v => this._refreshContent.call(this, null, v), { width: "20%", minWidth: "128px" } );
7978
+ this.rightPanel.addText( null, this.searchValue ?? "", v => this._refreshContent.call(this, v, null), { placeholder: "Search assets.." } );
7979
+ this.rightPanel.addButton( null, "<a class='fa fa-arrow-up-short-wide'></a>", on_sort.bind(this), { className: "micro", title: "Sort" } );
7980
+ this.rightPanel.addButton( null, "<a class='fa-solid fa-grip'></a>", on_change_view.bind(this), { className: "micro", title: "View" } );
7868
7981
  // Content Pages
7869
- this.rightPanel.addButton(null, "<a class='fa-solid fa-angles-left'></a>", on_change_page.bind(this, -1), { className: "micro", title: "Previous Page" });
7870
- this.rightPanel.addButton(null, "<a class='fa-solid fa-angles-right'></a>", on_change_page.bind(this, 1), { className: "micro", title: "Next Page" });
7982
+ this.rightPanel.addButton( null, "<a class='fa-solid fa-angles-left'></a>", on_change_page.bind(this, -1), { className: "micro", title: "Previous Page" } );
7983
+ this.rightPanel.addButton( null, "<a class='fa-solid fa-angles-right'></a>", on_change_page.bind(this, 1), { className: "micro", title: "Next Page" } );
7871
7984
  this.rightPanel.endLine();
7872
7985
 
7873
- if( !this.skip_browser )
7986
+ if( !this.skipBrowser )
7874
7987
  {
7875
7988
  this.rightPanel.sameLine();
7876
7989
  this.rightPanel.addComboButtons( null, [
7877
7990
  {
7878
7991
  value: "Left",
7879
7992
  icon: "fa-solid fa-left-long",
7880
- callback: (domEl) => {
7993
+ callback: domEl => {
7881
7994
  if(!this.prevData.length) return;
7882
7995
  this.nextData.push( this.currentData );
7883
7996
  this.currentData = this.prevData.pop();
@@ -7888,7 +8001,7 @@ class AssetView {
7888
8001
  {
7889
8002
  value: "Right",
7890
8003
  icon: "fa-solid fa-right-long",
7891
- callback: (domEl) => {
8004
+ callback: domEl => {
7892
8005
  if(!this.nextData.length) return;
7893
8006
  this.prevData.push( this.currentData );
7894
8007
  this.currentData = this.nextData.pop();
@@ -7899,7 +8012,7 @@ class AssetView {
7899
8012
  {
7900
8013
  value: "Refresh",
7901
8014
  icon: "fa-solid fa-arrows-rotate",
7902
- callback: (domEl) => { this._refreshContent(); }
8015
+ callback: domEl => { this._refreshContent(); }
7903
8016
  }
7904
8017
  ], { width: "auto", noSelection: true } );
7905
8018
  this.rightPanel.addText(null, this.path.join('/'), null, { disabled: true, signal: "@on_folder_change", style: { fontWeight: "bolder", fontSize: "16px", color: "#aaa" } });
@@ -7911,17 +8024,17 @@ class AssetView {
7911
8024
  this.content.className = "lexassetscontent";
7912
8025
  this.rightPanel.root.appendChild(this.content);
7913
8026
 
7914
- this.content.addEventListener('dragenter', function(e) {
8027
+ this.content.addEventListener('dragenter', function( e ) {
7915
8028
  e.preventDefault();
7916
8029
  this.classList.add('dragging');
7917
8030
  });
7918
- this.content.addEventListener('dragleave', function(e) {
8031
+ this.content.addEventListener('dragleave', function( e ) {
7919
8032
  e.preventDefault();
7920
8033
  this.classList.remove('dragging');
7921
8034
  });
7922
- this.content.addEventListener('drop', (e) => {
8035
+ this.content.addEventListener('drop', ( e ) => {
7923
8036
  e.preventDefault();
7924
- this._processDrop(e);
8037
+ this._processDrop( e );
7925
8038
  });
7926
8039
  this.content.addEventListener('click', function() {
7927
8040
  this.querySelectorAll('.lexassetitem').forEach( i => i.classList.remove('selected') );
@@ -7930,38 +8043,90 @@ class AssetView {
7930
8043
  this._refreshContent();
7931
8044
  }
7932
8045
 
7933
- _refreshContent(search_value, filter) {
8046
+ _refreshContent( searchValue, filter ) {
7934
8047
 
7935
- const is_content_layout = (this.layout == AssetView.LAYOUT_CONTENT); // default
8048
+ const isContentLayout = ( this.layout == AssetView.LAYOUT_CONTENT ); // default
7936
8049
 
7937
- this.filter = filter ?? (this.filter ?? "None");
7938
- this.search_value = search_value ?? (this.search_value ?? "");
8050
+ this.filter = filter ?? ( this.filter ?? "None" );
8051
+ this.searchValue = searchValue ?? (this.searchValue ?? "");
7939
8052
  this.content.innerHTML = "";
7940
- this.content.className = (is_content_layout ? "lexassetscontent" : "lexassetscontent list");
8053
+ this.content.className = (isContentLayout ? "lexassetscontent" : "lexassetscontent list");
7941
8054
  let that = this;
7942
8055
 
7943
8056
  const add_item = function(item) {
7944
8057
 
7945
- const type = item.type.charAt(0).toUpperCase() + item.type.slice(1);
8058
+ const type = item.type.charAt( 0 ).toUpperCase() + item.type.slice( 1 );
7946
8059
  const extension = getExtension( item.id );
7947
- const is_folder = type === "Folder";
8060
+ const isFolder = type === "Folder";
7948
8061
 
7949
8062
  let itemEl = document.createElement('li');
7950
8063
  itemEl.className = "lexassetitem " + item.type.toLowerCase();
7951
- itemEl.title = type + ": " + item.id;
7952
8064
  itemEl.tabIndex = -1;
7953
- that.content.appendChild(itemEl);
8065
+ that.content.appendChild( itemEl );
8066
+
8067
+ if( !that.useNativeTitle )
8068
+ {
8069
+ let desc = document.createElement( 'span' );
8070
+ desc.className = 'lexitemdesc';
8071
+ desc.innerHTML = "File: " + item.id + "<br>Type: " + type;
8072
+ that.content.appendChild( desc );
8073
+
8074
+ itemEl.addEventListener("mousemove", e => {
8075
+
8076
+ if( !isContentLayout )
8077
+ {
8078
+ return;
8079
+ }
8080
+
8081
+ const rect = itemEl.getBoundingClientRect();
8082
+ const targetRect = e.target.getBoundingClientRect();
8083
+ const parentRect = desc.parentElement.getBoundingClientRect();
8084
+
8085
+ let localOffsetX = targetRect.x - parentRect.x - ( targetRect.x - rect.x );
8086
+ let localOffsetY = targetRect.y - parentRect.y - ( targetRect.y - rect.y );
8087
+
8088
+ if( e.target.classList.contains( "lexassettitle" ) )
8089
+ {
8090
+ localOffsetY += ( targetRect.y - rect.y );
8091
+ }
8092
+
8093
+ desc.style.left = (localOffsetX + e.offsetX + 12) + "px";
8094
+ desc.style.top = (localOffsetY + e.offsetY) + "px";
8095
+ });
8096
+
8097
+ itemEl.addEventListener("mouseenter", () => {
8098
+ if( isContentLayout )
8099
+ {
8100
+ desc.style.display = "unset";
8101
+ }
8102
+ });
8103
+
8104
+ itemEl.addEventListener("mouseleave", () => {
8105
+ if( isContentLayout )
8106
+ {
8107
+ setTimeout( () => {
8108
+ desc.style.display = "none";
8109
+ }, 100 );
8110
+ }
8111
+ });
8112
+ }
8113
+ else
8114
+ {
8115
+ itemEl.title = type + ": " + item.id;
8116
+ }
7954
8117
 
7955
- if(item.selected != undefined) {
8118
+ if( item.selected != undefined )
8119
+ {
7956
8120
  let span = document.createElement('span');
7957
8121
  span.className = "lexcheckbox";
7958
8122
  let checkbox_input = document.createElement('input');
7959
8123
  checkbox_input.type = "checkbox";
7960
8124
  checkbox_input.className = "checkbox";
7961
8125
  checkbox_input.checked = item.selected;
7962
- checkbox_input.addEventListener('change', (e, v) => {
8126
+ checkbox_input.addEventListener('change', ( e, v ) => {
7963
8127
  item.selected = !item.selected;
7964
- if(that.onevent) {
8128
+ if( that.onevent )
8129
+ {
7965
8130
  const event = new AssetViewEvent(AssetViewEvent.ASSET_CHECKED, e.shiftKey ? [item] : item );
7966
8131
  event.multiple = !!e.shiftKey;
7967
8132
  that.onevent( event );
@@ -7973,22 +8138,23 @@ class AssetView {
7973
8138
  itemEl.appendChild(span);
7974
8139
 
7975
8140
  }
8141
+
7976
8142
  let title = document.createElement('span');
7977
8143
  title.className = "lexassettitle";
7978
8144
  title.innerText = item.id;
7979
- itemEl.appendChild(title);
8145
+ itemEl.appendChild( title );
7980
8146
 
7981
- if( !that.skip_preview ) {
8147
+ if( !that.skipPreview ) {
7982
8148
 
7983
8149
  let preview = null;
7984
- const has_image = item.src && (['png', 'jpg'].indexOf( getExtension( item.src ) ) > -1 || item.src.includes("data:image/") ); // Support b64 image as src
8150
+ const hasImage = item.src && (['png', 'jpg'].indexOf( getExtension( item.src ) ) > -1 || item.src.includes("data:image/") ); // Support b64 image as src
7985
8151
 
7986
- if( has_image || is_folder || !is_content_layout)
8152
+ if( hasImage || isFolder || !isContentLayout)
7987
8153
  {
7988
8154
  preview = document.createElement('img');
7989
- let real_src = item.unknown_extension ? that.rootPath + "images/file.png" : (is_folder ? that.rootPath + "images/folder.png" : item.src);
7990
- preview.src = (is_content_layout || is_folder ? real_src : that.rootPath + "images/file.png");
7991
- itemEl.appendChild(preview);
8155
+ let real_src = item.unknown_extension ? that.rootPath + "images/file.png" : (isFolder ? that.rootPath + "images/folder.png" : item.src);
8156
+ preview.src = (isContentLayout || isFolder ? real_src : that.rootPath + "images/file.png");
8157
+ itemEl.appendChild( preview );
7992
8158
  }
7993
8159
  else
7994
8160
  {
@@ -8014,7 +8180,7 @@ class AssetView {
8014
8180
  }
8015
8181
  }
8016
8182
 
8017
- if( !is_folder )
8183
+ if( !isFolder )
8018
8184
  {
8019
8185
  let info = document.createElement('span');
8020
8186
  info.className = "lexassetinfo";
@@ -8026,30 +8192,37 @@ class AssetView {
8026
8192
  e.stopImmediatePropagation();
8027
8193
  e.stopPropagation();
8028
8194
 
8029
- const is_double_click = e.detail == LX.MOUSE_DOUBLE_CLICK;
8195
+ const isDoubleClick = ( e.detail == LX.MOUSE_DOUBLE_CLICK );
8030
8196
 
8031
- if(!is_double_click)
8197
+ if( !isDoubleClick )
8032
8198
  {
8033
- if(!e.shiftKey)
8199
+ if( !e.shiftKey )
8200
+ {
8034
8201
  that.content.querySelectorAll('.lexassetitem').forEach( i => i.classList.remove('selected') );
8202
+ }
8203
+
8035
8204
  this.classList.add('selected');
8036
- if( !that.skip_preview )
8205
+
8206
+ if( !that.skipPreview )
8207
+ {
8037
8208
  that._previewAsset( item );
8209
+ }
8038
8210
  }
8039
- else if(is_folder)
8211
+ else if( isFolder )
8040
8212
  {
8041
8213
  that._enterFolder( item );
8042
8214
  return;
8043
8215
  }
8044
8216
 
8045
- if(that.onevent) {
8046
- const event = new AssetViewEvent(is_double_click ? AssetViewEvent.ASSET_DBLCLICKED : AssetViewEvent.ASSET_SELECTED, e.shiftKey ? [item] : item );
8217
+ if( that.onevent )
8218
+ {
8219
+ const event = new AssetViewEvent(isDoubleClick ? AssetViewEvent.ASSET_DBLCLICKED : AssetViewEvent.ASSET_SELECTED, e.shiftKey ? [item] : item );
8047
8220
  event.multiple = !!e.shiftKey;
8048
8221
  that.onevent( event );
8049
8222
  }
8050
8223
  });
8051
8224
 
8052
- if( that.context_menu )
8225
+ if( that.contextMenu )
8053
8226
  {
8054
8227
  itemEl.addEventListener('contextmenu', function(e) {
8055
8228
  e.preventDefault();
@@ -8057,15 +8230,21 @@ class AssetView {
8057
8230
  const multiple = that.content.querySelectorAll('.selected').length;
8058
8231
 
8059
8232
  LX.addContextMenu( multiple > 1 ? (multiple + " selected") :
8060
- is_folder ? item.id : item.type, e, m => {
8061
- if(multiple <= 1)
8233
+ isFolder ? item.id : item.type, e, m => {
8234
+ if( multiple <= 1 )
8235
+ {
8062
8236
  m.add("Rename");
8063
- if( !is_folder )
8064
- m.add("Clone", that._clone_item.bind(that, item));
8065
- if(multiple <= 1)
8237
+ }
8238
+ if( !isFolder )
8239
+ {
8240
+ m.add("Clone", that._cloneItem.bind( that, item ));
8241
+ }
8242
+ if( multiple <= 1 )
8243
+ {
8066
8244
  m.add("Properties");
8245
+ }
8067
8246
  m.add("");
8068
- m.add("Delete", that._delete_item.bind(that, item));
8247
+ m.add("Delete", that._deleteItem.bind( that, item ));
8069
8248
  });
8070
8249
  });
8071
8250
  }
@@ -8079,21 +8258,23 @@ class AssetView {
8079
8258
 
8080
8259
  const fr = new FileReader();
8081
8260
 
8082
- const filtered_data = this.currentData.filter( _i => {
8261
+ const filteredData = this.currentData.filter( _i => {
8083
8262
  return (this.filter != "None" ? _i.type.toLowerCase() == this.filter.toLowerCase() : true) &&
8084
- _i.id.toLowerCase().includes(this.search_value.toLowerCase())
8263
+ _i.id.toLowerCase().includes(this.searchValue.toLowerCase())
8085
8264
  } );
8086
8265
 
8087
- if(filter || search_value) {
8266
+ if( filter || searchValue )
8267
+ {
8088
8268
  this.contentPage = 1;
8089
8269
  }
8270
+
8090
8271
  // Show all data if using filters
8091
- const start_index = (this.contentPage - 1) * AssetView.MAX_PAGE_ELEMENTS;
8092
- const end_index = Math.min( start_index + AssetView.MAX_PAGE_ELEMENTS, filtered_data.length );
8272
+ const startIndex = (this.contentPage - 1) * AssetView.MAX_PAGE_ELEMENTS;
8273
+ const endIndex = Math.min( startIndex + AssetView.MAX_PAGE_ELEMENTS, filteredData.length );
8093
8274
 
8094
- for( let i = start_index; i < end_index; ++i )
8275
+ for( let i = startIndex; i < endIndex; ++i )
8095
8276
  {
8096
- let item = filtered_data[i];
8277
+ let item = filteredData[ i ];
8097
8278
 
8098
8279
  if( item.path )
8099
8280
  {
@@ -8104,7 +8285,7 @@ class AssetView {
8104
8285
  item.src = e.currentTarget.result; // This is a base64 string...
8105
8286
  item._path = item.path;
8106
8287
  delete item.path;
8107
- this._refreshContent(search_value, filter);
8288
+ this._refreshContent( searchValue, filter );
8108
8289
  };
8109
8290
  } });
8110
8291
  }else
@@ -8112,15 +8293,21 @@ class AssetView {
8112
8293
  item.domEl = add_item( item );
8113
8294
  }
8114
8295
  }
8115
- this.allow_next_page = filtered_data.length - 1 > AssetView.MAX_PAGE_ELEMENTS;
8116
- LX.emit("@on_page_change", "Page " + this.contentPage + " / " + ((((filtered_data.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1));
8296
+
8297
+ this.allowNextPage = filteredData.length - 1 > AssetView.MAX_PAGE_ELEMENTS;
8298
+ LX.emit("@on_page_change", "Page " + this.contentPage + " / " + ((((filteredData.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1));
8299
+
8300
+ if( this.onRefreshContent )
8301
+ {
8302
+ this.onRefreshContent( searchValue, filter );
8303
+ }
8117
8304
  }
8118
8305
 
8119
8306
  /**
8120
8307
  * @method _previewAsset
8121
8308
  */
8122
8309
 
8123
- _previewAsset(file) {
8310
+ _previewAsset( file ) {
8124
8311
 
8125
8312
  const is_base_64 = file.src && file.src.includes("data:image/");
8126
8313
 
@@ -8129,34 +8316,37 @@ class AssetView {
8129
8316
 
8130
8317
  if( file.type == 'image' || file.src )
8131
8318
  {
8132
- const has_image = ['png', 'jpg'].indexOf( getExtension( file.src ) ) > -1 || is_base_64;
8133
- if( has_image )
8134
- this.previewPanel.addImage(file.src, { style: { width: "100%" } });
8319
+ const hasImage = ['png', 'jpg'].indexOf( getExtension( file.src ) ) > -1 || is_base_64;
8320
+ if( hasImage )
8321
+ {
8322
+ this.previewPanel.addImage( file.src, { style: { width: "100%" } } );
8323
+ }
8135
8324
  }
8136
8325
 
8137
8326
  const options = { disabled: true };
8138
8327
 
8139
8328
  this.previewPanel.addText("Filename", file.id, null, options);
8140
- if(file._path || file.src ) this.previewPanel.addText("URL", file._path ? file._path : file.src, null, options);
8329
+ if( file.lastModified ) this.previewPanel.addText("Last Modified", new Date( file.lastModified ).toLocaleString(), null, options);
8330
+ if( file._path || file.src ) this.previewPanel.addText("URL", file._path ? file._path : file.src, null, options);
8141
8331
  this.previewPanel.addText("Path", this.path.join('/'), null, options);
8142
8332
  this.previewPanel.addText("Type", file.type, null, options);
8143
- if(file.bytesize) this.previewPanel.addText("Size", (file.bytesize/1024).toPrecision(3) + " KBs", null, options);
8144
- if(file.type == "folder") this.previewPanel.addText("Files", file.children ? file.children.length.toString() : "0", null, options);
8333
+ if( file.bytesize ) this.previewPanel.addText("Size", (file.bytesize/1024).toPrecision(3) + " KBs", null, options);
8334
+ if( file.type == "folder" ) this.previewPanel.addText("Files", file.children ? file.children.length.toString() : "0", null, options);
8145
8335
 
8146
8336
  this.previewPanel.addSeparator();
8147
8337
 
8148
- const preview_actions = [...this.preview_actions];
8338
+ const previewActions = [...this.previewActions];
8149
8339
 
8150
- if( !preview_actions.length )
8340
+ if( !previewActions.length )
8151
8341
  {
8152
8342
  // By default
8153
- preview_actions.push({
8343
+ previewActions.push({
8154
8344
  name: 'Download',
8155
8345
  callback: () => LX.downloadURL(file.src, file.id)
8156
8346
  });
8157
8347
  }
8158
8348
 
8159
- for( let action of preview_actions )
8349
+ for( let action of previewActions )
8160
8350
  {
8161
8351
  if( action.type && action.type !== file.type || action.path && action.path !== this.path.join('/') )
8162
8352
  continue;
@@ -8166,7 +8356,7 @@ class AssetView {
8166
8356
  this.previewPanel.merge();
8167
8357
  }
8168
8358
 
8169
- _processDrop(e) {
8359
+ _processDrop( e ) {
8170
8360
 
8171
8361
  const fr = new FileReader();
8172
8362
  const num_files = e.dataTransfer.files.length;
@@ -8186,7 +8376,8 @@ class AssetView {
8186
8376
  let item = {
8187
8377
  "id": file.name,
8188
8378
  "src": e.currentTarget.result,
8189
- "extension": ext
8379
+ "extension": ext,
8380
+ "lastModified": file.lastModified
8190
8381
  };
8191
8382
 
8192
8383
  switch(ext)
@@ -8211,7 +8402,7 @@ class AssetView {
8211
8402
 
8212
8403
  if(i == (num_files - 1)) {
8213
8404
  this._refreshContent();
8214
- if( !this.skip_browser )
8405
+ if( !this.skipBrowser )
8215
8406
  this.tree.refresh();
8216
8407
  }
8217
8408
  };
@@ -8231,10 +8422,10 @@ class AssetView {
8231
8422
  this._refreshContent();
8232
8423
  }
8233
8424
 
8234
- _enterFolder( folder_item ) {
8425
+ _enterFolder( folderItem ) {
8235
8426
 
8236
8427
  this.prevData.push( this.currentData );
8237
- this.currentData = folder_item.children;
8428
+ this.currentData = folderItem.children;
8238
8429
  this.contentPage = 1;
8239
8430
  this._refreshContent();
8240
8431
 
@@ -8242,46 +8433,57 @@ class AssetView {
8242
8433
  this._updatePath(this.currentData);
8243
8434
 
8244
8435
  // Trigger event
8245
- if(this.onevent) {
8246
- const event = new AssetViewEvent(AssetViewEvent.ENTER_FOLDER, folder_item);
8436
+ if( this.onevent )
8437
+ {
8438
+ const event = new AssetViewEvent( AssetViewEvent.ENTER_FOLDER, folderItem );
8247
8439
  this.onevent( event );
8248
8440
  }
8249
8441
  }
8250
8442
 
8251
8443
  _deleteItem( item ) {
8252
8444
 
8253
- const idx = this.currentData.indexOf(item);
8254
- if(idx > -1) {
8255
- this.currentData.splice(idx, 1);
8256
- this._refreshContent(this.search_value, this.filter);
8445
+ const idx = this.currentData.indexOf( item );
8446
+ if(idx < 0)
8447
+ {
8448
+ console.error( "[AssetView Error] Cannot delete. Item not found." );
8449
+ return;
8450
+ }
8257
8451
 
8258
- if(this.onevent) {
8259
- const event = new AssetViewEvent(AssetViewEvent.ASSET_DELETED, item );
8260
- this.onevent( event );
8261
- }
8452
+ this.currentData.splice( idx, 1 );
8453
+ this._refreshContent( this.searchValue, this.filter );
8262
8454
 
8263
- this.tree.refresh();
8264
- this._processData(this.data);
8455
+ if(this.onevent)
8456
+ {
8457
+ const event = new AssetViewEvent( AssetViewEvent.ASSET_DELETED, item );
8458
+ this.onevent( event );
8265
8459
  }
8460
+
8461
+ this.tree.refresh();
8462
+ this._processData( this.data );
8266
8463
  }
8267
8464
 
8268
8465
  _cloneItem( item ) {
8269
8466
 
8270
- const idx = this.currentData.indexOf(item);
8271
- if(idx > -1) {
8272
- delete item.domEl;
8273
- delete item.folder;
8274
- const new_item = deepCopy( item );
8275
- this.currentData.splice(idx, 0, new_item);
8276
- this._refreshContent(this.search_value, this.filter);
8467
+ const idx = this.currentData.indexOf( item );
8468
+ if( idx < 0 )
8469
+ {
8470
+ return;
8471
+ }
8472
+
8473
+ delete item.domEl;
8474
+ delete item.folder;
8475
+ const new_item = deepCopy( item );
8476
+ this.currentData.splice( idx, 0, new_item );
8277
8477
 
8278
- if(this.onevent) {
8279
- const event = new AssetViewEvent(AssetViewEvent.ASSET_CLONED, item );
8280
- this.onevent( event );
8281
- }
8478
+ this._refreshContent( this.searchValue, this.filter );
8282
8479
 
8283
- this._processData(this.data);
8480
+ if( this.onevent )
8481
+ {
8482
+ const event = new AssetViewEvent( AssetViewEvent.ASSET_CLONED, item );
8483
+ this.onevent( event );
8284
8484
  }
8485
+
8486
+ this._processData( this.data );
8285
8487
  }
8286
8488
  }
8287
8489
 
@@ -8299,7 +8501,7 @@ Object.assign(LX, {
8299
8501
  * @param {Object} request object with all the parameters like data (for sending forms), dataType, success, error
8300
8502
  * @param {Function} on_complete
8301
8503
  **/
8302
- request(request) {
8504
+ request( request ) {
8303
8505
 
8304
8506
  var dataType = request.dataType || "text";
8305
8507
  if(dataType == "json") //parse it locally
@@ -8540,6 +8742,10 @@ Element.prototype.hasClass = function( list ) {
8540
8742
  return !!r.length;
8541
8743
  }
8542
8744
 
8745
+ Element.prototype.addClass = function( className ) {
8746
+ if( className ) this.classList.add( className );
8747
+ }
8748
+
8543
8749
  Element.prototype.getComputedSize = function() {
8544
8750
  const cs = getComputedStyle( this );
8545
8751
  return {
@@ -8552,7 +8758,6 @@ LX.UTILS = {
8552
8758
  getTime() { return new Date().getTime() },
8553
8759
  compareThreshold( v, p, n, t ) { return Math.abs(v - p) >= t || Math.abs(v - n) >= t },
8554
8760
  compareThresholdRange( v0, v1, t0, t1 ) { return v0 >= t0 && v0 <= t1 || v1 >= t0 && v1 <= t1 || v0 <= t0 && v1 >= t1},
8555
- clamp (num, min, max) { return Math.min(Math.max(num, min), max) },
8556
8761
  uidGenerator: simple_guidGenerator,
8557
8762
  deleteElement( el ) { if( el ) el.remove(); },
8558
8763
  flushCss(element) {