lexgui 0.7.7 → 0.7.9

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.
@@ -131,13 +131,51 @@ class Timeline {
131
131
  }
132
132
  this.resize(this.size);
133
133
 
134
- // update color theme
135
- this.updateTheme();
136
- LX.addSignal( "@on_new_color_scheme", (el, value) => {
137
- // Retrieve again the color using LX.getThemeColor, which checks the applied theme
138
- this.updateTheme();
139
- } );
134
+ /**
135
+ * updates theme (light - dark) based on LX's current theme
136
+ */
137
+ function updateTheme( ){
138
+ Timeline.BACKGROUND_COLOR = LX.getThemeColor("global-blur-background");
139
+ Timeline.TRACK_COLOR_PRIMARY = LX.getThemeColor("global-color-primary");
140
+ Timeline.TRACK_COLOR_SECONDARY = LX.getThemeColor("global-color-secondary");
141
+ Timeline.TRACK_COLOR_TERCIARY = LX.getThemeColor("global-color-terciary");
142
+ Timeline.TRACK_COLOR_QUATERNARY = LX.getThemeColor("global-color-quaternary");
143
+ Timeline.FONT = LX.getThemeColor("global-font");
144
+ Timeline.FONT_COLOR_PRIMARY = LX.getThemeColor("global-text-primary");
145
+ Timeline.FONT_COLOR_TERTIARY = LX.getThemeColor("global-text-tertiary");
146
+ Timeline.FONT_COLOR_QUATERNARY = LX.getThemeColor("global-text-quaternary");
147
+
148
+ Timeline.KEYFRAME_COLOR = LX.getThemeColor("lxTimeline-keyframe");
149
+ Timeline.KEYFRAME_COLOR_SELECTED = Timeline.KEYFRAME_COLOR_HOVERED = LX.getThemeColor("lxTimeline-keyframe-selected");
150
+ Timeline.KEYFRAME_COLOR_LOCK = LX.getThemeColor("lxTimeline-keyframe-locked");
151
+ Timeline.KEYFRAME_COLOR_EDITED = LX.getThemeColor("lxTimeline-keyframe-edited");
152
+ Timeline.KEYFRAME_COLOR_INACTIVE = LX.getThemeColor("lxTimeline-keyframe-inactive");
153
+ }
154
+
155
+ this.updateTheme = updateTheme.bind(this);
156
+ LX.addSignal( "@on_new_color_scheme", this.updateTheme );
140
157
  }
158
+
159
+ // makes it ready to be deleted
160
+ clear(){
161
+ if( this.header ){
162
+ this.header.clear();
163
+ }
164
+
165
+ if( this.leftPanel ){
166
+ this.leftPanel.clear();
167
+ }
168
+
169
+ if( this.updateTheme ){
170
+ let signals = LX.signals[ "@on_new_color_scheme" ] ?? [];
171
+ for( let i =0; i < signals.length; ++i ){
172
+ if( signals[i] == this.updateTheme ){
173
+ signals.splice(i, 1);
174
+ }
175
+ }
176
+ }
177
+ }
178
+
141
179
 
142
180
  /**
143
181
  * @method updateHeader
@@ -1249,28 +1287,6 @@ class Timeline {
1249
1287
  this.updateLeftPanel();
1250
1288
  }
1251
1289
 
1252
- /**
1253
- * updates theme (light - dark) based on LX's current theme
1254
- */
1255
- updateTheme( ){
1256
- Timeline.BACKGROUND_COLOR = LX.getThemeColor("global-blur-background");
1257
- Timeline.TRACK_COLOR_PRIMARY = LX.getThemeColor("global-color-primary");
1258
- Timeline.TRACK_COLOR_SECONDARY = LX.getThemeColor("global-color-secondary");
1259
- Timeline.TRACK_COLOR_TERCIARY = LX.getThemeColor("global-color-terciary");
1260
- Timeline.TRACK_COLOR_QUATERNARY = LX.getThemeColor("global-color-quaternary");
1261
- Timeline.FONT = LX.getThemeColor("global-font");
1262
- Timeline.FONT_COLOR_PRIMARY = LX.getThemeColor("global-text-primary");
1263
- Timeline.FONT_COLOR_TERTIARY = LX.getThemeColor("global-text-tertiary");
1264
- Timeline.FONT_COLOR_QUATERNARY = LX.getThemeColor("global-text-quaternary");
1265
-
1266
- Timeline.KEYFRAME_COLOR = LX.getThemeColor("lxTimeline-keyframe");
1267
- Timeline.KEYFRAME_COLOR_SELECTED = Timeline.KEYFRAME_COLOR_HOVERED = LX.getThemeColor("lxTimeline-keyframe-selected");
1268
- Timeline.KEYFRAME_COLOR_LOCK = LX.getThemeColor("lxTimeline-keyframe-locked");
1269
- Timeline.KEYFRAME_COLOR_EDITED = LX.getThemeColor("lxTimeline-keyframe-edited");
1270
- Timeline.KEYFRAME_COLOR_INACTIVE =LX.getThemeColor("lxTimeline-keyframe-inactive");
1271
- }
1272
-
1273
-
1274
1290
  // ----- BASE FUNCTIONS -----
1275
1291
  /**
1276
1292
  These functions might be overriden by child classes. Nonetheless, they must have the same attributes, at least.
@@ -34,7 +34,7 @@ class TimeBar {
34
34
 
35
35
  this.markerWidth = options.markerWidth ?? 8;
36
36
  this.markerHeight = options.markerHeight ?? (this.canvas.height * 0.5);
37
- this.offset = options.offset || (this.markerWidth*0.5 + 8);
37
+ this.offset = options.offset || (this.markerWidth*0.5 + 5);
38
38
 
39
39
  // dimensions of line (not canvas)
40
40
  this.lineWidth = this.canvas.width - this.offset * 2;
@@ -147,7 +147,7 @@ class TimeBar {
147
147
  ctx.fillStyle = ctx.strokeStyle = options.fillColor || '#111' // "#FFF";
148
148
 
149
149
 
150
- y -= this.offset + 4;
150
+ y -= this.offset + 8;
151
151
  // Current time ball grab
152
152
  ctx.fillStyle = options.fillColor || '#e5e5e5';
153
153
  ctx.beginPath();
@@ -318,7 +318,7 @@ class VideoEditor {
318
318
 
319
319
  this.playing = false;
320
320
  this.requestId = null;
321
-
321
+ this.videoReady = false;
322
322
  this.currentTime = this.startTime = 0;
323
323
  this.startTimeString = "0:0";
324
324
  this.endTimeString = "0:0";
@@ -349,7 +349,7 @@ class VideoEditor {
349
349
  this.dragOffsetY = 0;
350
350
  // Create video element and load it
351
351
  let video = this.video = options.video ?? document.createElement( 'video' );
352
- this.video.loop = true;
352
+ this.loop = options.loop ?? false;
353
353
 
354
354
  if(options.src) {
355
355
  this.video.src = options.src;
@@ -397,7 +397,10 @@ class VideoEditor {
397
397
  this.controlsPanelLeft.addButton('', "", (v) => {
398
398
  this.playing = !this.playing;
399
399
  if(this.playing) {
400
- this.video.play();
400
+ if( this.video.currentTime + 0.000001 >= this.endTime) {
401
+ this.video.currentTime = this.startTime;
402
+ }
403
+ this.video.play()
401
404
  }
402
405
  else {
403
406
  this.video.pause();
@@ -447,13 +450,16 @@ class VideoEditor {
447
450
  event.preventDefault();
448
451
  event.stopPropagation();
449
452
 
450
- if(!this.playing) {
453
+ this.playing = !this.playing;
454
+ if(this.playing) {
455
+ if( this.video.currentTime + 0.000001 >= this.endTime) {
456
+ this.video.currentTime = this.startTime;
457
+ }
451
458
  this.video.play();
452
459
  }
453
460
  else {
454
461
  this.video.pause();
455
462
  }
456
- this.playing = !this.playing;
457
463
  this.controlsPanelLeft.refresh();
458
464
  }
459
465
  }
@@ -610,15 +616,41 @@ class VideoEditor {
610
616
  }
611
617
 
612
618
  async _loadVideo( options = {} ) {
619
+ this.videoReady = false;
613
620
  while(this.video.duration === Infinity || isNaN(this.video.duration) || !this.timebar) {
614
621
  await new Promise(r => setTimeout(r, 1000));
615
622
  this.video.currentTime = 10000000 * Math.random();
616
623
  }
624
+ this.video.currentTime = 0.01; // BUG: some videos will not play unless this line is present
617
625
 
626
+ // Duration can change if the video is dynamic (stream). This function is to ensure to load all buffer data
627
+ const forceLoadChunks = () => {
628
+ const state = this.videoReady;
629
+ if(this.video.readyState > 3) {
630
+ this.videoReady = true;
631
+ }
632
+ if(!state) {
633
+ this.video.currentTime = this.video.duration;
634
+ }
635
+ }
636
+
637
+ this.video.addEventListener( "canplaythrough", forceLoadChunks, {passive :true} );
638
+
639
+ this.video.ondurationchange = (v) => {
640
+ if( this.video.duration != this.endTime ) {
641
+
642
+ this.video.currentTime = this.startTime;
643
+ console.log("duration changed from", this.endTime, " to ", this.video.duration);
644
+ this.endTime = this.video.duration;
645
+ const x = this._timeToX(this.endTime);
646
+ this._setEndValue(x);
647
+ }
648
+ this.video.currentTime = this.startTime;
649
+ }
650
+
618
651
  this.timebar.startX = this.timebar.position.x;
619
652
  this.timebar.endX = this.timebar.position.x + this.timebar.lineWidth;
620
653
 
621
- this.video.currentTime = 0.01; // BUG: some videos will not play unless this line is present
622
654
  this.endTime = this.video.duration;
623
655
 
624
656
  this._setEndValue(this.timebar.endX);
@@ -660,8 +692,16 @@ class VideoEditor {
660
692
  this.onDraw();
661
693
  }
662
694
  if(this.playing) {
663
- if(this.video.currentTime >= this.endTime) {
664
- this.video.currentTime = this.startTime;
695
+ if( this.video.currentTime + 0.000001 >= this.endTime) {
696
+ this.video.pause();
697
+ if(!this.loop) {
698
+ this.playing = false;
699
+ this.controlsPanelLeft.refresh();
700
+ }
701
+ else {
702
+ this.video.currentTime = this.startTime;
703
+ this.video.play();
704
+ }
665
705
  }
666
706
  const x = this._timeToX(this.video.currentTime);
667
707
  this._setCurrentValue(x, false);
package/build/lexgui.css CHANGED
@@ -4614,13 +4614,19 @@ ul.lexassetscontent {
4614
4614
  overflow: auto;
4615
4615
  }
4616
4616
 
4617
- .lexassetscontent.list {
4617
+ .lexassetscontent.compact {
4618
4618
  width: 100%;
4619
4619
  display: grid;
4620
4620
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
4621
4621
  column-gap: 0.5rem;
4622
4622
  }
4623
4623
 
4624
+ .lexassetscontent.list {
4625
+ width: 100%;
4626
+ display: flex;
4627
+ flex-direction: column;
4628
+ }
4629
+
4624
4630
  .lexassetscontent li {
4625
4631
  -webkit-text-size-adjust: 100%;
4626
4632
  font-size: var(--global-font-size);
@@ -4670,7 +4676,7 @@ ul.lexassetscontent {
4670
4676
  opacity: 1;
4671
4677
  }
4672
4678
 
4673
- .lexassetscontent.list li {
4679
+ .lexassetscontent.list li, .lexassetscontent.compact li {
4674
4680
  width: 100%;
4675
4681
  height: 1.8em;
4676
4682
  border-top: 0px;
@@ -4755,7 +4761,7 @@ ul.lexassetscontent {
4755
4761
  z-index: 1;
4756
4762
  }
4757
4763
 
4758
- .lexassetscontent.list li .lexassettitle {
4764
+ .lexassetscontent.list li .lexassettitle, .lexassetscontent.compact li .lexassettitle {
4759
4765
  width: 100%;
4760
4766
  height: 100%;
4761
4767
  text-align: left;
@@ -4774,13 +4780,13 @@ ul.lexassetscontent {
4774
4780
  display: none;
4775
4781
  }
4776
4782
 
4777
- .lexassetscontent.list li .lexassetinfo {
4783
+ .lexassetscontent.list li .lexassetinfo, .lexassetscontent.compact li .lexassetinfo {
4778
4784
  display: block;
4779
4785
  right: 6px;
4780
4786
  z-index: 1;
4781
4787
  }
4782
4788
 
4783
- .lexassetscontent.list li:has(.lexcheckbox) .lexassetinfo {
4789
+ .lexassetscontent.list li:has(.lexcheckbox) .lexassetinfo, .lexassetscontent.compact li:has(.lexcheckbox) .lexassetinfo {
4784
4790
  display: block;
4785
4791
  right: 32px;
4786
4792
  z-index: 1;
@@ -4794,7 +4800,7 @@ ul.lexassetscontent {
4794
4800
  height: 1.15em;
4795
4801
  }
4796
4802
 
4797
- .lexassetscontent.list li .lexcheckbox {
4803
+ .lexassetscontent.list li .lexcheckbox, .lexassetscontent.compact li .lexcheckbox {
4798
4804
  right: 3px;
4799
4805
  top: 3px;
4800
4806
  }
@@ -4819,7 +4825,7 @@ ul.lexassetscontent {
4819
4825
  transition: all 0.2s;
4820
4826
  }
4821
4827
 
4822
- .lexassetscontent.list img {
4828
+ .lexassetscontent.list img, .lexassetscontent.compact img {
4823
4829
  width: unset;
4824
4830
  object-fit: contain;
4825
4831
  float: left;
@@ -4831,7 +4837,7 @@ ul.lexassetscontent {
4831
4837
  transform: translateY(-6px);
4832
4838
  }
4833
4839
 
4834
- .lexassetscontent.list li.folder img {
4840
+ .lexassetscontent.list li.folder img, .lexassetscontent.compact li.folder img {
4835
4841
  transform: scale(0.9);
4836
4842
  }
4837
4843
 
@@ -4922,7 +4928,7 @@ ul.lexassetscontent {
4922
4928
  display: flex;
4923
4929
  position: relative;
4924
4930
  overflow: inherit;
4925
- background-color: light-dark(var(--global-color-secondary), var(--global-medium-background));
4931
+ background-color: var(--global-color-secondary);
4926
4932
  }
4927
4933
 
4928
4934
  .codebasearea * {
@@ -5009,7 +5015,7 @@ ul.lexassetscontent {
5009
5015
  }
5010
5016
 
5011
5017
  .lexcodetabinfo {
5012
- background-color: light-dark(var(--global-color-secondary), var(--global-medium-background));
5018
+ background-color: var(--global-color-secondary);
5013
5019
  position: absolute;
5014
5020
  z-index: 3;
5015
5021
  bottom: 0px;
@@ -5254,7 +5260,6 @@ ul.lexassetscontent {
5254
5260
 
5255
5261
  .lexcodeeditor .searchbox {
5256
5262
  background-color: var(--global-color-secondary);
5257
- /* width: 256px; */
5258
5263
  position: absolute;
5259
5264
  right: 6px;
5260
5265
  top: 26px;
@@ -5268,10 +5273,6 @@ ul.lexassetscontent {
5268
5273
  transition: transform 0.2s ease-in, opacity 0.2s ease-in;
5269
5274
  }
5270
5275
 
5271
- .lexcodeeditor .searchbox.gotoline {
5272
- width: 124px;
5273
- }
5274
-
5275
5276
  .lexcodeeditor .searchbox.opened {
5276
5277
  transform: translateY(0px);
5277
5278
  opacity: 1;
package/build/lexgui.js CHANGED
@@ -14,7 +14,7 @@ console.warn( 'Script _build/lexgui.js_ is depracated and will be removed soon.
14
14
  */
15
15
 
16
16
  const LX = {
17
- version: "0.7.7",
17
+ version: "0.7.9",
18
18
  ready: false,
19
19
  extensions: [], // Store extensions used
20
20
  signals: {}, // Events and triggers
@@ -1246,7 +1246,7 @@ class DropdownMenu {
1246
1246
  }
1247
1247
 
1248
1248
  const menuItem = document.createElement('div');
1249
- menuItem.className = "lexdropdownmenuitem" + ( item.name ? "" : " label" ) + ( item.disabled ?? false ? " disabled" : "" ) + ( ` ${ item.className ?? "" }` );
1249
+ menuItem.className = "lexdropdownmenuitem" + ( ( item.name || item.options ) ? "" : " label" ) + ( item.disabled ?? false ? " disabled" : "" ) + ( ` ${ item.className ?? "" }` );
1250
1250
  menuItem.dataset["id"] = pKey;
1251
1251
  menuItem.innerHTML = `<span>${ key }</span>`;
1252
1252
  menuItem.tabIndex = "1";
@@ -1332,19 +1332,23 @@ class DropdownMenu {
1332
1332
  else
1333
1333
  {
1334
1334
  menuItem.addEventListener( "click", () => {
1335
- const f = item[ 'callback' ];
1336
- if( f )
1337
- {
1338
- f.call( this, key, menuItem );
1339
- }
1340
-
1341
1335
  const radioName = menuItem.getAttribute( "data-radioname" );
1342
1336
  if( radioName )
1343
1337
  {
1344
1338
  this._trigger[ radioName ] = key;
1345
1339
  }
1346
1340
 
1347
- this.destroy( true );
1341
+ const f = item.callback;
1342
+ if( f )
1343
+ {
1344
+ f.call( this, key, menuItem, radioName );
1345
+ }
1346
+
1347
+ // If has options, it's a radio group label, so don't close the menu
1348
+ if( !item.options && ( item.closeOnClick ?? true ) )
1349
+ {
1350
+ this.destroy( true );
1351
+ }
1348
1352
  } );
1349
1353
  }
1350
1354
 
@@ -1382,8 +1386,6 @@ class DropdownMenu {
1382
1386
 
1383
1387
  if( item.options )
1384
1388
  {
1385
- this._addSeparator();
1386
-
1387
1389
  console.assert( this._trigger[ item.name ] && "An item of the radio group must be selected!" );
1388
1390
  this._radioGroup = {
1389
1391
  name: item.name,
@@ -6617,6 +6619,22 @@ Object.assign(LX, {
6617
6619
  }
6618
6620
  });
6619
6621
 
6622
+ /**
6623
+ * @method formatBytes
6624
+ * @param {Number} bytes
6625
+ **/
6626
+ function formatBytes( bytes )
6627
+ {
6628
+ if( bytes === 0 ) return "0 B";
6629
+ const k = 1024;
6630
+ const sizes = [ "B", "KB", "MB", "GB", "TB" ];
6631
+ const i = Math.floor( Math.log( bytes ) / Math.log( k ) );
6632
+ const value = bytes / Math.pow( k, i );
6633
+ return value.toFixed( 2 ) + " " + sizes[ i ];
6634
+ }
6635
+
6636
+ LX.formatBytes = formatBytes;
6637
+
6620
6638
  /**
6621
6639
  * @method compareThreshold
6622
6640
  * @param {String} url
@@ -15151,17 +15169,26 @@ class Menubar {
15151
15169
  } });
15152
15170
  };
15153
15171
 
15154
- entry.addEventListener("click", () => {
15172
+ entry.addEventListener("mousedown", (e) => {
15173
+ e.preventDefault();
15174
+ });
15175
+
15176
+ entry.addEventListener("mouseup", (e) => {
15177
+
15178
+ e.preventDefault();
15179
+
15155
15180
  const f = item[ 'callback' ];
15156
15181
  if( f )
15157
15182
  {
15158
- f.call( this, key, entry );
15183
+ f.call( this, key, entry, e );
15159
15184
  return;
15160
15185
  }
15161
15186
 
15162
15187
  _showEntry();
15163
15188
 
15164
15189
  this.focused = true;
15190
+
15191
+ return false;
15165
15192
  });
15166
15193
 
15167
15194
  entry.addEventListener( "mouseover", (e) => {
@@ -15328,7 +15355,12 @@ class Menubar {
15328
15355
  }
15329
15356
 
15330
15357
  const _b = button.querySelector('a');
15331
- _b.addEventListener("click", (e) => {
15358
+
15359
+ _b.addEventListener( "mousedown", (e) => {
15360
+ e.preventDefault();
15361
+ });
15362
+
15363
+ _b.addEventListener( "mouseup", (e) => {
15332
15364
  if( callback && !disabled )
15333
15365
  {
15334
15366
  callback.call( this, _b, e );
@@ -16166,7 +16198,8 @@ LX.AssetViewEvent = AssetViewEvent;
16166
16198
  class AssetView {
16167
16199
 
16168
16200
  static LAYOUT_GRID = 0;
16169
- static LAYOUT_LIST = 1;
16201
+ static LAYOUT_COMPACT = 1;
16202
+ static LAYOUT_LIST = 2;
16170
16203
 
16171
16204
  static CONTENT_SORT_ASC = 0;
16172
16205
  static CONTENT_SORT_DESC = 1;
@@ -16428,7 +16461,9 @@ class AssetView {
16428
16461
  }
16429
16462
  else
16430
16463
  {
16464
+ area.root.classList.add( "flex", "flex-col" );
16431
16465
  this.toolsPanel = area.addPanel({ className: 'flex flex-col overflow-hidden', height:"auto" });
16466
+ this.toolsPanel.root.style.flex = "none";
16432
16467
  this.contentPanel = area.addPanel({ className: 'lexassetcontentpanel flex flex-col overflow-hidden' });
16433
16468
  }
16434
16469
 
@@ -16445,7 +16480,8 @@ class AssetView {
16445
16480
  const _onChangeView = ( value, event ) => {
16446
16481
  new LX.DropdownMenu( event.target, [
16447
16482
  { name: "Grid", icon: "LayoutGrid", callback: () => this._setContentLayout( AssetView.LAYOUT_GRID ) },
16448
- { name: "List", icon: "LayoutList", callback: () => this._setContentLayout( AssetView.LAYOUT_LIST ) }
16483
+ { name: "Compact", icon: "LayoutList", callback: () => this._setContentLayout( AssetView.LAYOUT_COMPACT ) },
16484
+ { name: "List", icon: "List", callback: () => this._setContentLayout( AssetView.LAYOUT_LIST ) }
16449
16485
  ], { side: "right", align: "start" });
16450
16486
  };
16451
16487
 
@@ -16555,11 +16591,13 @@ class AssetView {
16555
16591
  _refreshContent( searchValue, filter ) {
16556
16592
 
16557
16593
  const isGridLayout = ( this.layout == AssetView.LAYOUT_GRID ); // default
16594
+ const isCompactLayout = ( this.layout == AssetView.LAYOUT_COMPACT );
16595
+ const isListLayout = ( this.layout == AssetView.LAYOUT_LIST );
16558
16596
 
16559
16597
  this.filter = filter ?? ( this.filter ?? "None" );
16560
16598
  this.searchValue = searchValue ?? (this.searchValue ?? "");
16561
16599
  this.content.innerHTML = "";
16562
- this.content.className = (isGridLayout ? "lexassetscontent" : "lexassetscontent list");
16600
+ this.content.className = `lexassetscontent${ isCompactLayout ? " compact" : ( isListLayout ? " list" : "" ) }`;
16563
16601
  let that = this;
16564
16602
 
16565
16603
  const _addItem = function(item) {
@@ -16573,6 +16611,11 @@ class AssetView {
16573
16611
  itemEl.tabIndex = -1;
16574
16612
  that.content.appendChild( itemEl );
16575
16613
 
16614
+ if( item.lastModified && !item.lastModifiedDate )
16615
+ {
16616
+ item.lastModifiedDate = that._lastModifiedToStringDate( item.lastModified );
16617
+ }
16618
+
16576
16619
  if( !that.useNativeTitle )
16577
16620
  {
16578
16621
  let desc = document.createElement( 'span' );
@@ -16694,14 +16737,17 @@ class AssetView {
16694
16737
  }
16695
16738
  }
16696
16739
 
16697
- if( !isFolder )
16740
+ // Add item type info
16741
+ let itemInfoHtml = type;
16742
+
16743
+ if( isListLayout )
16698
16744
  {
16699
- let info = document.createElement('span');
16700
- info.className = "lexassetinfo";
16701
- info.innerText = type;
16702
- itemEl.appendChild(info);
16745
+ if( item.bytesize ) itemInfoHtml += ` | ${ LX.formatBytes( item.bytesize ) }`;
16746
+ if( item.lastModifiedDate ) itemInfoHtml += ` | ${ item.lastModifiedDate }`;
16703
16747
  }
16704
16748
 
16749
+ LX.makeContainer( [ "auto", "auto" ], "lexassetinfo", itemInfoHtml, itemEl );
16750
+
16705
16751
  itemEl.addEventListener('click', function( e ) {
16706
16752
  e.stopImmediatePropagation();
16707
16753
  e.stopPropagation();
@@ -16843,18 +16889,18 @@ class AssetView {
16843
16889
  const options = { disabled: true };
16844
16890
 
16845
16891
  this.previewPanel.addText("Filename", file.id, null, options);
16846
- if( file.lastModified ) this.previewPanel.addText("Last Modified", new Date( file.lastModified ).toLocaleString(), null, options);
16892
+ if( file.lastModifiedDate ) this.previewPanel.addText("Last Modified", file.lastModifiedDate, null, options);
16847
16893
  if( file._path || file.src ) this.previewPanel.addText("URL", file._path ? file._path : file.src, null, options);
16848
16894
  this.previewPanel.addText("Path", this.path.join('/'), null, options);
16849
16895
  this.previewPanel.addText("Type", file.type, null, options);
16850
- if( file.bytesize ) this.previewPanel.addText("Size", (file.bytesize/1024).toPrecision(3) + " KBs", null, options);
16896
+ if( file.bytesize ) this.previewPanel.addText("Size", LX.formatBytes( file.bytesize ), null, options);
16851
16897
  if( file.type == "folder" ) this.previewPanel.addText("Files", file.children ? file.children.length.toString() : "0", null, options);
16852
16898
 
16853
16899
  this.previewPanel.addSeparator();
16854
16900
 
16855
16901
  const previewActions = [...this.previewActions];
16856
16902
 
16857
- if( !previewActions.length )
16903
+ if( !previewActions.length && file.type !== "folder" )
16858
16904
  {
16859
16905
  // By default
16860
16906
  previewActions.push({
@@ -16894,7 +16940,8 @@ class AssetView {
16894
16940
  "id": file.name,
16895
16941
  "src": e.currentTarget.result,
16896
16942
  "extension": ext,
16897
- "lastModified": file.lastModified
16943
+ "lastModified": file.lastModified,
16944
+ "lastModifiedDate": this._lastModifiedToStringDate( file.lastModified )
16898
16945
  };
16899
16946
 
16900
16947
  switch(ext)
@@ -17007,6 +17054,11 @@ class AssetView {
17007
17054
 
17008
17055
  this._processData( this.data );
17009
17056
  }
17057
+
17058
+ _lastModifiedToStringDate( lm ) {
17059
+ const d = new Date( lm ).toLocaleString();
17060
+ return d.substring( 0, d.indexOf( ',' ) );
17061
+ }
17010
17062
  }
17011
17063
 
17012
17064
  LX.AssetView = AssetView;