lexgui 0.1.39 → 0.1.41

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.39",
11
+ version: "0.1.41",
12
12
  ready: false,
13
13
  components: [], // specific pre-build components
14
14
  signals: {} // events and triggers
@@ -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
@@ -1198,7 +1199,7 @@ class Area {
1198
1199
  // Send area resize to every widget in the area
1199
1200
  for( let widget of widgets )
1200
1201
  {
1201
- const jsInstance = widget.jsIinstance;
1202
+ const jsInstance = widget.jsInstance;
1202
1203
 
1203
1204
  if( jsInstance.onresize )
1204
1205
  {
@@ -2538,6 +2539,7 @@ class Widget {
2538
2539
  static KNOB = 23;
2539
2540
  static SIZE = 24;
2540
2541
  static PAD = 25;
2542
+ static FORM = 26;
2541
2543
 
2542
2544
  static NO_CONTEXT_TYPES = [
2543
2545
  Widget.BUTTON,
@@ -2624,6 +2626,7 @@ class Widget {
2624
2626
  case Widget.KNOB: return "Knob";
2625
2627
  case Widget.SIZE: return "Size";
2626
2628
  case Widget.PAD: return "Pad";
2629
+ case Widget.FORM: return "Form";
2627
2630
  case Widget.CUSTOM: return this.customName;
2628
2631
  }
2629
2632
  }
@@ -2819,7 +2822,7 @@ class NodeTree {
2819
2822
  let isParent = node.children.length > 0;
2820
2823
  let isSelected = this.selected.indexOf( node ) > -1 || node.selected;
2821
2824
 
2822
- if( this.options.only_folders )
2825
+ if( this.options.onlyFolders )
2823
2826
  {
2824
2827
  let has_folders = false;
2825
2828
  node.children.forEach( c => has_folders |= (c.type == 'folder') );
@@ -3198,7 +3201,7 @@ class NodeTree {
3198
3201
  {
3199
3202
  let child = node.children[i];
3200
3203
 
3201
- if( this.options.only_folders && child.type != 'folder')
3204
+ if( this.options.onlyFolders && child.type != 'folder')
3202
3205
  continue;
3203
3206
 
3204
3207
  this._create_item( node, child, level + 1 );
@@ -3526,7 +3529,7 @@ class Panel {
3526
3529
 
3527
3530
  if( name != undefined )
3528
3531
  {
3529
- if( !(options.no_name ?? false) )
3532
+ if( !(options.hideName ?? false) )
3530
3533
  {
3531
3534
  let domName = document.createElement( 'div' );
3532
3535
  domName.className = "lexwidgetname";
@@ -3566,7 +3569,7 @@ class Panel {
3566
3569
  }
3567
3570
 
3568
3571
  widget.domEl = element;
3569
- element.jsIinstance = widget;
3572
+ element.jsInstance = widget;
3570
3573
 
3571
3574
  const insert_widget = el => {
3572
3575
  if(options.container)
@@ -3636,7 +3639,7 @@ class Panel {
3636
3639
  element.className += " lexfilter noname";
3637
3640
 
3638
3641
  let input = document.createElement('input');
3639
- input.id = 'input-filter';
3642
+ input.className = 'lexinput-filter';
3640
3643
  input.setAttribute("placeholder", options.placeholder);
3641
3644
  input.style.width = "calc( 100% - 17px )";
3642
3645
  input.value = options.filterValue || "";
@@ -4224,7 +4227,7 @@ class Panel {
4224
4227
 
4225
4228
  addCard( name, options = {} ) {
4226
4229
 
4227
- options.no_name = true;
4230
+ options.hideName = true;
4228
4231
  let widget = this.create_widget(name, Widget.CARD, options);
4229
4232
  let element = widget.domEl;
4230
4233
 
@@ -4275,6 +4278,89 @@ class Panel {
4275
4278
  return widget;
4276
4279
  }
4277
4280
 
4281
+ /**
4282
+ * @method addForm
4283
+ * @param {String} name Widget name
4284
+ * @param {Object} data Form data
4285
+ * @param {Function} callback Callback function on submit form
4286
+ * @param {*} options:
4287
+ * actionName: Text to be shown in the button
4288
+ */
4289
+
4290
+ addForm( name, data, callback, options = {} ) {
4291
+
4292
+ if( data.constructor != Object )
4293
+ {
4294
+ console.error( "Form data must be an Object" );
4295
+ return;
4296
+ }
4297
+
4298
+ // Always hide name for this one
4299
+ options.hideName = true;
4300
+
4301
+ let widget = this.create_widget( name, Widget.FORM, options );
4302
+
4303
+ widget.onGetValue = () => {
4304
+ return container.formData;
4305
+ };
4306
+
4307
+ widget.onSetValue = ( newValue, skipCallback ) => {
4308
+ container.formData = newValue;
4309
+ const entries = container.querySelectorAll( ".lexwidget" );
4310
+ for( let i = 0; i < entries.length; ++i )
4311
+ {
4312
+ const entry = entries[ i ];
4313
+ if( entry.jsInstance.type != LX.Widget.TEXT )
4314
+ {
4315
+ continue;
4316
+ }
4317
+ let entryName = entries[ i ].querySelector( ".lexwidgetname" ).innerText;
4318
+ let entryInput = entries[ i ].querySelector( ".lextext input" );
4319
+ entryInput.value = newValue[ entryName ] ?? "";
4320
+ Panel._dispatch_event( entryInput, "focusout", skipCallback );
4321
+ }
4322
+ };
4323
+
4324
+ // Add widget value
4325
+
4326
+ let element = widget.domEl;
4327
+
4328
+ let container = document.createElement( 'div' );
4329
+ container.className = "lexformdata";
4330
+
4331
+ this.queue( container );
4332
+
4333
+ container.formData = {};
4334
+
4335
+ for( let entry in data )
4336
+ {
4337
+ const entryData = data[ entry ];
4338
+ this.addText( entry, entryData.constructor == Object ? entryData.value : entryData, ( value ) => {
4339
+ container.formData[ entry ] = value;
4340
+ }, entryData );
4341
+
4342
+ container.formData[ entry ] = entryData.constructor == Object ? entryData.value : entryData;
4343
+ }
4344
+
4345
+ this.addButton( null, options.actionName ?? "Submit", ( value, event ) => {
4346
+ if( callback )
4347
+ {
4348
+ callback( container.formData, event );
4349
+ }
4350
+ } );
4351
+
4352
+ this.clearQueue();
4353
+
4354
+ element.appendChild( container );
4355
+
4356
+ if( !widget.name || options.hideName ) {
4357
+ element.className += " noname";
4358
+ container.style.width = "100%";
4359
+ }
4360
+
4361
+ return widget;
4362
+ }
4363
+
4278
4364
  /**
4279
4365
  * @method addContent
4280
4366
  * @param {HTMLElement} element
@@ -4299,27 +4385,29 @@ class Panel {
4299
4385
  async addImage( url, options = {} ) {
4300
4386
 
4301
4387
  if( !url )
4302
- return;
4388
+ {
4389
+ return;
4390
+ }
4303
4391
 
4304
- options.no_name = true;
4305
- let widget = this.create_widget(null, Widget.IMAGE, options);
4392
+ options.hideName = true;
4393
+ let widget = this.create_widget( null, Widget.IMAGE, options );
4306
4394
  let element = widget.domEl;
4307
4395
 
4308
- let container = document.createElement('div');
4396
+ let container = document.createElement( 'div' );
4309
4397
  container.className = "leximage";
4310
4398
  container.style.width = "100%";
4311
4399
 
4312
- let img = document.createElement('img');
4400
+ let img = document.createElement( 'img' );
4313
4401
  img.src = url;
4314
4402
 
4315
- for(let s in options.style) {
4316
-
4317
- img.style[s] = options.style[s];
4403
+ for( let s in options.style )
4404
+ {
4405
+ img.style[ s ] = options.style[ s ];
4318
4406
  }
4319
4407
 
4320
4408
  await img.decode();
4321
- container.appendChild(img);
4322
- element.appendChild(container);
4409
+ container.appendChild( img );
4410
+ element.appendChild( container );
4323
4411
 
4324
4412
  return widget;
4325
4413
  }
@@ -4418,7 +4506,7 @@ class Panel {
4418
4506
  setTimeout( () => delete this.unfocus_event, 200 );
4419
4507
  } else if ( e.relatedTarget && e.relatedTarget.tagName == "INPUT" ) {
4420
4508
  return;
4421
- }else if ( e.target.id == 'input-filter' ) {
4509
+ }else if ( e.target.className == 'lexinput-filter' ) {
4422
4510
  return;
4423
4511
  }
4424
4512
  this.toggleAttribute( 'hidden', true );
@@ -5393,7 +5481,6 @@ class Panel {
5393
5481
  vecinput.addEventListener( "mousedown", inner_mousedown );
5394
5482
 
5395
5483
  var that = this;
5396
- var lastY = 0;
5397
5484
 
5398
5485
  function inner_mousedown( e )
5399
5486
  {
@@ -5405,13 +5492,16 @@ class Panel {
5405
5492
  var doc = that.root.ownerDocument;
5406
5493
  doc.addEventListener( 'mousemove', inner_mousemove );
5407
5494
  doc.addEventListener( 'mouseup', inner_mouseup );
5408
- lastY = e.pageY;
5409
- document.body.classList.add( 'nocursor' );
5410
5495
  document.body.classList.add( 'noevents' );
5411
5496
  dragIcon.classList.remove( 'hidden' );
5412
5497
  e.stopImmediatePropagation();
5413
5498
  e.stopPropagation();
5414
5499
 
5500
+ if( !document.pointerLockElement )
5501
+ {
5502
+ vecinput.requestPointerLock();
5503
+ }
5504
+
5415
5505
  if( options.onPress )
5416
5506
  {
5417
5507
  options.onPress.bind( vecinput )( e, vecinput );
@@ -5420,8 +5510,10 @@ class Panel {
5420
5510
 
5421
5511
  function inner_mousemove( e )
5422
5512
  {
5423
- if ( lastY != e.pageY ) {
5424
- let dt = lastY - e.pageY;
5513
+ let dt = -e.movementY;
5514
+
5515
+ if ( dt != 0 )
5516
+ {
5425
5517
  let mult = options.step ?? 1;
5426
5518
  if( e.shiftKey ) mult *= 10;
5427
5519
  else if( e.altKey ) mult *= 0.1;
@@ -5430,7 +5522,6 @@ class Panel {
5430
5522
  Panel._dispatch_event( vecinput, "change" );
5431
5523
  }
5432
5524
 
5433
- lastY = e.pageY;
5434
5525
  e.stopPropagation();
5435
5526
  e.preventDefault();
5436
5527
  }
@@ -5440,10 +5531,14 @@ class Panel {
5440
5531
  var doc = that.root.ownerDocument;
5441
5532
  doc.removeEventListener( 'mousemove', inner_mousemove );
5442
5533
  doc.removeEventListener( 'mouseup', inner_mouseup );
5443
- document.body.classList.remove( 'nocursor' );
5444
5534
  document.body.classList.remove( 'noevents' );
5445
5535
  dragIcon.classList.add( 'hidden' );
5446
5536
 
5537
+ if( document.pointerLockElement )
5538
+ {
5539
+ document.exitPointerLock();
5540
+ }
5541
+
5447
5542
  if( options.onRelease )
5448
5543
  {
5449
5544
  options.onRelease.bind( vecinput )( e, vecinput );
@@ -5536,7 +5631,7 @@ class Panel {
5536
5631
 
5537
5632
  if( value[ i ].constructor == Number )
5538
5633
  {
5539
- value[ i ] = clamp(value[ i ], +vecinput.min, +vecinput.max);
5634
+ value[ i ] = clamp( value[ i ], +vecinput.min, +vecinput.max );
5540
5635
  value[ i ] = round( value[ i ], options.precision );
5541
5636
  }
5542
5637
 
@@ -5578,7 +5673,9 @@ class Panel {
5578
5673
  vecinput.addEventListener( "change", e => {
5579
5674
 
5580
5675
  if( isNaN( e.target.value ) )
5676
+ {
5581
5677
  return;
5678
+ }
5582
5679
 
5583
5680
  const skipCallback = e.detail;
5584
5681
 
@@ -5589,7 +5686,7 @@ class Panel {
5589
5686
  if( !skipCallback )
5590
5687
  {
5591
5688
  let btn = element.querySelector( ".lexwidgetname .lexicon" );
5592
- if( btn ) btn.style.display = val != vecinput.iValue ? "block": "none";
5689
+ if( btn ) btn.style.display = val != vecinput.iValue ? "block" : "none";
5593
5690
  }
5594
5691
 
5595
5692
  if( locker.locked )
@@ -5598,7 +5695,8 @@ class Panel {
5598
5695
  v.value = val;
5599
5696
  value[ v.idx ] = val;
5600
5697
  }
5601
- } else
5698
+ }
5699
+ else
5602
5700
  {
5603
5701
  vecinput.value = val;
5604
5702
  value[ e.target.idx ] = val;
@@ -5612,7 +5710,7 @@ class Panel {
5612
5710
  vecinput.addEventListener( "mousedown", inner_mousedown );
5613
5711
 
5614
5712
  var that = this;
5615
- var lastY = 0;
5713
+
5616
5714
  function inner_mousedown( e )
5617
5715
  {
5618
5716
  if( document.activeElement == vecinput )
@@ -5623,13 +5721,16 @@ class Panel {
5623
5721
  var doc = that.root.ownerDocument;
5624
5722
  doc.addEventListener( 'mousemove', inner_mousemove );
5625
5723
  doc.addEventListener( 'mouseup', inner_mouseup );
5626
- lastY = e.pageY;
5627
- document.body.classList.add( 'nocursor' );
5628
5724
  document.body.classList.add( 'noevents' );
5629
5725
  dragIcon.classList.remove( 'hidden' );
5630
5726
  e.stopImmediatePropagation();
5631
5727
  e.stopPropagation();
5632
5728
 
5729
+ if( !document.pointerLockElement )
5730
+ {
5731
+ vecinput.requestPointerLock();
5732
+ }
5733
+
5633
5734
  if( options.onPress )
5634
5735
  {
5635
5736
  options.onPress.bind( vecinput )( e, vecinput );
@@ -5638,8 +5739,10 @@ class Panel {
5638
5739
 
5639
5740
  function inner_mousemove( e )
5640
5741
  {
5641
- if ( lastY != e.pageY ) {
5642
- let dt = lastY - e.pageY;
5742
+ let dt = -e.movementY;
5743
+
5744
+ if ( dt != 0 )
5745
+ {
5643
5746
  let mult = options.step ?? 1;
5644
5747
  if( e.shiftKey ) mult = 10;
5645
5748
  else if( e.altKey ) mult = 0.1;
@@ -5658,7 +5761,6 @@ class Panel {
5658
5761
  }
5659
5762
  }
5660
5763
 
5661
- lastY = e.pageY;
5662
5764
  e.stopPropagation();
5663
5765
  e.preventDefault();
5664
5766
  }
@@ -5668,10 +5770,14 @@ class Panel {
5668
5770
  var doc = that.root.ownerDocument;
5669
5771
  doc.removeEventListener( 'mousemove', inner_mousemove );
5670
5772
  doc.removeEventListener( 'mouseup', inner_mouseup );
5671
- document.body.classList.remove( 'nocursor' );
5672
5773
  document.body.classList.remove( 'noevents' );
5673
5774
  dragIcon.classList.add('hidden');
5674
5775
 
5776
+ if( document.pointerLockElement )
5777
+ {
5778
+ document.exitPointerLock();
5779
+ }
5780
+
5675
5781
  if( options.onRelease )
5676
5782
  {
5677
5783
  options.onRelease.bind( vecinput )( e, vecinput );
@@ -5709,7 +5815,9 @@ class Panel {
5709
5815
  {
5710
5816
  this.classList.add( "fa-lock" );
5711
5817
  this.classList.remove( "fa-lock-open" );
5712
- } else {
5818
+ }
5819
+ else
5820
+ {
5713
5821
  this.classList.add( "fa-lock-open" );
5714
5822
  this.classList.remove( "fa-lock" );
5715
5823
  }
@@ -7513,12 +7621,12 @@ class AssetView {
7513
7621
  this.layout = options.layout ?? AssetView.LAYOUT_CONTENT;
7514
7622
  this.contentPage = 1;
7515
7623
 
7516
- if(options.root_path)
7624
+ if( options.rootPath )
7517
7625
  {
7518
- if(options.root_path.constructor !== String)
7626
+ if(options.rootPath.constructor !== String)
7519
7627
  console.warn("Asset Root Path must be a String (now is " + path.constructor.name + ")");
7520
7628
  else
7521
- this.rootPath = options.root_path;
7629
+ this.rootPath = options.rootPath;
7522
7630
  }
7523
7631
 
7524
7632
  let div = document.createElement('div');
@@ -7530,13 +7638,13 @@ class AssetView {
7530
7638
 
7531
7639
  let left, right, contentArea = area;
7532
7640
 
7533
- this.skip_browser = options.skip_browser ?? false;
7534
- this.skip_preview = options.skip_preview ?? false;
7535
- this.only_folders = options.only_folders ?? true;
7536
- this.preview_actions = options.preview_actions ?? [];
7537
- this.context_menu = options.context_menu ?? [];
7641
+ this.skipBrowser = options.skipBrowser ?? false;
7642
+ this.skipPreview = options.skipPreview ?? false;
7643
+ this.onlyFolders = options.onlyFolders ?? true;
7644
+ this.previewActions = options.previewActions ?? [];
7645
+ this.contextMenu = options.contextMenu ?? [];
7538
7646
 
7539
- if( !this.skip_browser )
7647
+ if( !this.skipBrowser )
7540
7648
  {
7541
7649
  [left, right] = area.split({ type: "horizontal", sizes: ["15%", "85%"]});
7542
7650
  contentArea = right;
@@ -7545,28 +7653,34 @@ class AssetView {
7545
7653
  right.setLimitBox( 512, 0 );
7546
7654
  }
7547
7655
 
7548
- if( !this.skip_preview )
7549
- [contentArea, right] = contentArea.split({ type: "horizontal", sizes: ["80%", "20%"]});
7656
+ if( !this.skipPreview )
7657
+ {
7658
+ [ contentArea, right ] = contentArea.split({ type: "horizontal", sizes: ["80%", "20%"]});
7659
+ }
7550
7660
 
7551
- this.allowedTypes = options.allowed_types || ["None", "Image", "Mesh", "Script", "JSON", "Clip"];
7661
+ this.allowedTypes = options.allowedTypes || ["None", "Image", "Mesh", "Script", "JSON", "Clip"];
7552
7662
 
7553
7663
  this.prevData = [];
7554
7664
  this.nextData = [];
7555
7665
  this.data = [];
7556
7666
 
7557
- this._processData(this.data, null);
7667
+ this._processData( this.data, null );
7558
7668
 
7559
7669
  this.currentData = this.data;
7560
7670
  this.path = ['@'];
7561
7671
 
7562
- if(!this.skip_browser)
7563
- this._createTreePanel(left);
7672
+ if( !this.skipBrowser )
7673
+ {
7674
+ this._createTreePanel( left );
7675
+ }
7564
7676
 
7565
- this._createContentPanel(contentArea);
7677
+ this._createContentPanel( contentArea );
7566
7678
 
7567
7679
  // Create resource preview panel
7568
- if( !this.skip_preview )
7569
- this.previewPanel = right.addPanel({className: 'lexassetcontentpanel', style: { overflow: 'scroll' }});
7680
+ if( !this.skipPreview )
7681
+ {
7682
+ this.previewPanel = right.addPanel( {className: 'lexassetcontentpanel', style: { overflow: 'scroll' }} );
7683
+ }
7570
7684
  }
7571
7685
 
7572
7686
  /**
@@ -7580,12 +7694,15 @@ class AssetView {
7580
7694
 
7581
7695
  this.data = data;
7582
7696
 
7583
- this._processData(this.data, null);
7697
+ this._processData( this.data, null );
7584
7698
  this.currentData = this.data;
7585
- this.path = ['@'];
7699
+ this.path = [ '@' ];
7700
+
7701
+ if( !this.skipBrowser )
7702
+ {
7703
+ this._createTreePanel( this.area );
7704
+ }
7586
7705
 
7587
- if(!this.skip_browser)
7588
- this._createTreePanel(this.area);
7589
7706
  this._refreshContent();
7590
7707
 
7591
7708
  this.onevent = onevent;
@@ -7595,12 +7712,18 @@ class AssetView {
7595
7712
  * @method clear
7596
7713
  */
7597
7714
  clear() {
7598
- if(this.previewPanel)
7715
+ if( this.previewPanel )
7716
+ {
7599
7717
  this.previewPanel.clear();
7600
- if(this.leftPanel)
7718
+ }
7719
+ if( this.leftPanel )
7720
+ {
7601
7721
  this.leftPanel.clear();
7602
- if(this.rightPanel)
7722
+ }
7723
+ if( this.rightPanel )
7724
+ {
7603
7725
  this.rightPanel.clear()
7726
+ }
7604
7727
  }
7605
7728
 
7606
7729
  /**
@@ -7611,14 +7734,16 @@ class AssetView {
7611
7734
 
7612
7735
  if( data.constructor !== Array )
7613
7736
  {
7614
- data['folder'] = parent;
7737
+ data[ 'folder' ] = parent;
7615
7738
  data.children = data.children ?? [];
7616
7739
  }
7617
7740
 
7618
7741
  let list = data.constructor === Array ? data : data.children;
7619
7742
 
7620
7743
  for( var i = 0; i < list.length; ++i )
7621
- this._processData( list[i], data );
7744
+ {
7745
+ this._processData( list[ i ], data );
7746
+ }
7622
7747
  }
7623
7748
 
7624
7749
  /**
@@ -7630,9 +7755,9 @@ class AssetView {
7630
7755
  this.path.length = 0;
7631
7756
 
7632
7757
  const push_parents_id = i => {
7633
- if(!i) return;
7758
+ if( !i ) return;
7634
7759
  let list = i.children ? i.children : i;
7635
- let c = list[0];
7760
+ let c = list[ 0 ];
7636
7761
  if( !c ) return;
7637
7762
  if( !c.folder ) return;
7638
7763
  this.path.push( c.folder.id ?? '@' );
@@ -7641,19 +7766,22 @@ class AssetView {
7641
7766
 
7642
7767
  push_parents_id( data );
7643
7768
 
7644
- LX.emit("@on_folder_change", this.path.reverse().join('/'));
7769
+ LX.emit( "@on_folder_change", this.path.reverse().join('/') );
7645
7770
  }
7646
7771
 
7647
7772
  /**
7648
7773
  * @method _createTreePanel
7649
7774
  */
7650
7775
 
7651
- _createTreePanel(area) {
7776
+ _createTreePanel( area ) {
7652
7777
 
7653
- if(this.leftPanel)
7778
+ if( this.leftPanel )
7779
+ {
7654
7780
  this.leftPanel.clear();
7655
- else {
7656
- this.leftPanel = area.addPanel({className: 'lexassetbrowserpanel'});
7781
+ }
7782
+ else
7783
+ {
7784
+ this.leftPanel = area.addPanel({ className: 'lexassetbrowserpanel' });
7657
7785
  }
7658
7786
 
7659
7787
  // Process data to show in tree
@@ -7665,18 +7793,21 @@ class AssetView {
7665
7793
  this.tree = this.leftPanel.addTree("Content Browser", tree_data, {
7666
7794
  // icons: tree_icons,
7667
7795
  filter: false,
7668
- only_folders: this.only_folders,
7669
- onevent: (event) => {
7796
+ onlyFolders: this.onlyFolders,
7797
+ onevent: event => {
7670
7798
 
7671
7799
  let node = event.node;
7672
7800
  let value = event.value;
7673
7801
 
7674
- switch(event.type) {
7802
+ switch( event.type )
7803
+ {
7675
7804
  case LX.TreeEvent.NODE_SELECTED:
7676
- if(!event.multiple) {
7805
+ if( !event.multiple )
7806
+ {
7677
7807
  this._enterFolder( node );
7678
7808
  }
7679
- if(!node.parent) {
7809
+ if( !node.parent )
7810
+ {
7680
7811
  this.prevData.push( this.currentData );
7681
7812
  this.currentData = this.data;
7682
7813
  this._refreshContent();
@@ -7698,9 +7829,9 @@ class AssetView {
7698
7829
  * @method _setContentLayout
7699
7830
  */
7700
7831
 
7701
- _setContentLayout( layout_mode ) {
7832
+ _setContentLayout( layoutMode ) {
7702
7833
 
7703
- this.layout = layout_mode;
7834
+ this.layout = layoutMode;
7704
7835
 
7705
7836
  this._refreshContent();
7706
7837
  }
@@ -7709,12 +7840,15 @@ class AssetView {
7709
7840
  * @method _createContentPanel
7710
7841
  */
7711
7842
 
7712
- _createContentPanel(area) {
7843
+ _createContentPanel( area ) {
7713
7844
 
7714
- if(this.rightPanel)
7845
+ if( this.rightPanel )
7846
+ {
7715
7847
  this.rightPanel.clear();
7716
- else {
7717
- this.rightPanel = area.addPanel({className: 'lexassetcontentpanel'});
7848
+ }
7849
+ else
7850
+ {
7851
+ this.rightPanel = area.addPanel({ className: 'lexassetcontentpanel' });
7718
7852
  }
7719
7853
 
7720
7854
  const on_sort = (value, event) => {
@@ -7742,20 +7876,24 @@ class AssetView {
7742
7876
  }
7743
7877
 
7744
7878
  const on_change_page = (value, event) => {
7745
- if(!this.allow_next_page)
7879
+ if( !this.allowNextPage )
7880
+ {
7746
7881
  return;
7747
- const last_page = this.contentPage;
7882
+ }
7883
+ const lastPage = this.contentPage;
7748
7884
  this.contentPage += value;
7749
7885
  this.contentPage = Math.min( this.contentPage, (((this.currentData.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1 );
7750
7886
  this.contentPage = Math.max( this.contentPage, 1 );
7751
7887
 
7752
- if( last_page != this.contentPage )
7888
+ if( lastPage != this.contentPage )
7889
+ {
7753
7890
  this._refreshContent();
7891
+ }
7754
7892
  }
7755
7893
 
7756
7894
  this.rightPanel.sameLine();
7757
7895
  this.rightPanel.addDropdown("Filter", this.allowedTypes, this.allowedTypes[0], (v) => this._refreshContent.call(this, null, v), { width: "20%", minWidth: "128px" });
7758
- this.rightPanel.addText(null, this.search_value ?? "", (v) => this._refreshContent.call(this, v, null), { placeholder: "Search assets.." });
7896
+ this.rightPanel.addText(null, this.searchValue ?? "", (v) => this._refreshContent.call(this, v, null), { placeholder: "Search assets.." });
7759
7897
  this.rightPanel.addButton(null, "<a class='fa fa-arrow-up-short-wide'></a>", on_sort.bind(this), { className: "micro", title: "Sort" });
7760
7898
  this.rightPanel.addButton(null, "<a class='fa-solid fa-grip'></a>", on_change_view.bind(this), { className: "micro", title: "View" });
7761
7899
  // Content Pages
@@ -7763,7 +7901,7 @@ class AssetView {
7763
7901
  this.rightPanel.addButton(null, "<a class='fa-solid fa-angles-right'></a>", on_change_page.bind(this, 1), { className: "micro", title: "Next Page" });
7764
7902
  this.rightPanel.endLine();
7765
7903
 
7766
- if( !this.skip_browser )
7904
+ if( !this.skipBrowser )
7767
7905
  {
7768
7906
  this.rightPanel.sameLine();
7769
7907
  this.rightPanel.addComboButtons( null, [
@@ -7823,27 +7961,27 @@ class AssetView {
7823
7961
  this._refreshContent();
7824
7962
  }
7825
7963
 
7826
- _refreshContent(search_value, filter) {
7964
+ _refreshContent( searchValue, filter ) {
7827
7965
 
7828
- const is_content_layout = (this.layout == AssetView.LAYOUT_CONTENT); // default
7966
+ const isContentLayout = (this.layout == AssetView.LAYOUT_CONTENT); // default
7829
7967
 
7830
7968
  this.filter = filter ?? (this.filter ?? "None");
7831
- this.search_value = search_value ?? (this.search_value ?? "");
7969
+ this.searchValue = searchValue ?? (this.searchValue ?? "");
7832
7970
  this.content.innerHTML = "";
7833
- this.content.className = (is_content_layout ? "lexassetscontent" : "lexassetscontent list");
7971
+ this.content.className = (isContentLayout ? "lexassetscontent" : "lexassetscontent list");
7834
7972
  let that = this;
7835
7973
 
7836
7974
  const add_item = function(item) {
7837
7975
 
7838
- const type = item.type.charAt(0).toUpperCase() + item.type.slice(1);
7976
+ const type = item.type.charAt( 0 ).toUpperCase() + item.type.slice( 1 );
7839
7977
  const extension = getExtension( item.id );
7840
- const is_folder = type === "Folder";
7978
+ const isFolder = type === "Folder";
7841
7979
 
7842
7980
  let itemEl = document.createElement('li');
7843
7981
  itemEl.className = "lexassetitem " + item.type.toLowerCase();
7844
7982
  itemEl.title = type + ": " + item.id;
7845
7983
  itemEl.tabIndex = -1;
7846
- that.content.appendChild(itemEl);
7984
+ that.content.appendChild( itemEl );
7847
7985
 
7848
7986
  if(item.selected != undefined) {
7849
7987
  let span = document.createElement('span');
@@ -7852,9 +7990,10 @@ class AssetView {
7852
7990
  checkbox_input.type = "checkbox";
7853
7991
  checkbox_input.className = "checkbox";
7854
7992
  checkbox_input.checked = item.selected;
7855
- checkbox_input.addEventListener('change', (e, v) => {
7993
+ checkbox_input.addEventListener('change', ( e, v ) => {
7856
7994
  item.selected = !item.selected;
7857
- if(that.onevent) {
7995
+ if( that.onevent )
7996
+ {
7858
7997
  const event = new AssetViewEvent(AssetViewEvent.ASSET_CHECKED, e.shiftKey ? [item] : item );
7859
7998
  event.multiple = !!e.shiftKey;
7860
7999
  that.onevent( event );
@@ -7869,19 +8008,19 @@ class AssetView {
7869
8008
  let title = document.createElement('span');
7870
8009
  title.className = "lexassettitle";
7871
8010
  title.innerText = item.id;
7872
- itemEl.appendChild(title);
8011
+ itemEl.appendChild( title );
7873
8012
 
7874
- if( !that.skip_preview ) {
8013
+ if( !that.skipPreview ) {
7875
8014
 
7876
8015
  let preview = null;
7877
- const has_image = item.src && (['png', 'jpg'].indexOf( getExtension( item.src ) ) > -1 || item.src.includes("data:image/") ); // Support b64 image as src
8016
+ const hasImage = item.src && (['png', 'jpg'].indexOf( getExtension( item.src ) ) > -1 || item.src.includes("data:image/") ); // Support b64 image as src
7878
8017
 
7879
- if( has_image || is_folder || !is_content_layout)
8018
+ if( hasImage || isFolder || !isContentLayout)
7880
8019
  {
7881
8020
  preview = document.createElement('img');
7882
- let real_src = item.unknown_extension ? that.rootPath + "images/file.png" : (is_folder ? that.rootPath + "images/folder.png" : item.src);
7883
- preview.src = (is_content_layout || is_folder ? real_src : that.rootPath + "images/file.png");
7884
- itemEl.appendChild(preview);
8021
+ let real_src = item.unknown_extension ? that.rootPath + "images/file.png" : (isFolder ? that.rootPath + "images/folder.png" : item.src);
8022
+ preview.src = (isContentLayout || isFolder ? real_src : that.rootPath + "images/file.png");
8023
+ itemEl.appendChild( preview );
7885
8024
  }
7886
8025
  else
7887
8026
  {
@@ -7907,7 +8046,7 @@ class AssetView {
7907
8046
  }
7908
8047
  }
7909
8048
 
7910
- if( !is_folder )
8049
+ if( !isFolder )
7911
8050
  {
7912
8051
  let info = document.createElement('span');
7913
8052
  info.className = "lexassetinfo";
@@ -7919,30 +8058,37 @@ class AssetView {
7919
8058
  e.stopImmediatePropagation();
7920
8059
  e.stopPropagation();
7921
8060
 
7922
- const is_double_click = e.detail == LX.MOUSE_DOUBLE_CLICK;
8061
+ const isDoubleClick = ( e.detail == LX.MOUSE_DOUBLE_CLICK );
7923
8062
 
7924
- if(!is_double_click)
8063
+ if( !isDoubleClick )
7925
8064
  {
7926
- if(!e.shiftKey)
8065
+ if( !e.shiftKey )
8066
+ {
7927
8067
  that.content.querySelectorAll('.lexassetitem').forEach( i => i.classList.remove('selected') );
8068
+ }
8069
+
7928
8070
  this.classList.add('selected');
7929
- if( !that.skip_preview )
8071
+
8072
+ if( !that.skipPreview )
8073
+ {
7930
8074
  that._previewAsset( item );
8075
+ }
7931
8076
  }
7932
- else if(is_folder)
8077
+ else if( isFolder )
7933
8078
  {
7934
8079
  that._enterFolder( item );
7935
8080
  return;
7936
8081
  }
7937
8082
 
7938
- if(that.onevent) {
7939
- const event = new AssetViewEvent(is_double_click ? AssetViewEvent.ASSET_DBLCLICKED : AssetViewEvent.ASSET_SELECTED, e.shiftKey ? [item] : item );
8083
+ if( that.onevent )
8084
+ {
8085
+ const event = new AssetViewEvent(isDoubleClick ? AssetViewEvent.ASSET_DBLCLICKED : AssetViewEvent.ASSET_SELECTED, e.shiftKey ? [item] : item );
7940
8086
  event.multiple = !!e.shiftKey;
7941
8087
  that.onevent( event );
7942
8088
  }
7943
8089
  });
7944
8090
 
7945
- if( that.context_menu )
8091
+ if( that.contextMenu )
7946
8092
  {
7947
8093
  itemEl.addEventListener('contextmenu', function(e) {
7948
8094
  e.preventDefault();
@@ -7950,10 +8096,10 @@ class AssetView {
7950
8096
  const multiple = that.content.querySelectorAll('.selected').length;
7951
8097
 
7952
8098
  LX.addContextMenu( multiple > 1 ? (multiple + " selected") :
7953
- is_folder ? item.id : item.type, e, m => {
8099
+ isFolder ? item.id : item.type, e, m => {
7954
8100
  if(multiple <= 1)
7955
8101
  m.add("Rename");
7956
- if( !is_folder )
8102
+ if( !isFolder )
7957
8103
  m.add("Clone", that._clone_item.bind(that, item));
7958
8104
  if(multiple <= 1)
7959
8105
  m.add("Properties");
@@ -7972,21 +8118,23 @@ class AssetView {
7972
8118
 
7973
8119
  const fr = new FileReader();
7974
8120
 
7975
- const filtered_data = this.currentData.filter( _i => {
8121
+ const filteredData = this.currentData.filter( _i => {
7976
8122
  return (this.filter != "None" ? _i.type.toLowerCase() == this.filter.toLowerCase() : true) &&
7977
- _i.id.toLowerCase().includes(this.search_value.toLowerCase())
8123
+ _i.id.toLowerCase().includes(this.searchValue.toLowerCase())
7978
8124
  } );
7979
8125
 
7980
- if(filter || search_value) {
8126
+ if( filter || searchValue )
8127
+ {
7981
8128
  this.contentPage = 1;
7982
8129
  }
8130
+
7983
8131
  // Show all data if using filters
7984
- const start_index = (this.contentPage - 1) * AssetView.MAX_PAGE_ELEMENTS;
7985
- const end_index = Math.min( start_index + AssetView.MAX_PAGE_ELEMENTS, filtered_data.length );
8132
+ const startIndex = (this.contentPage - 1) * AssetView.MAX_PAGE_ELEMENTS;
8133
+ const endIndex = Math.min( startIndex + AssetView.MAX_PAGE_ELEMENTS, filteredData.length );
7986
8134
 
7987
- for( let i = start_index; i < end_index; ++i )
8135
+ for( let i = startIndex; i < endIndex; ++i )
7988
8136
  {
7989
- let item = filtered_data[i];
8137
+ let item = filteredData[ i ];
7990
8138
 
7991
8139
  if( item.path )
7992
8140
  {
@@ -7997,7 +8145,7 @@ class AssetView {
7997
8145
  item.src = e.currentTarget.result; // This is a base64 string...
7998
8146
  item._path = item.path;
7999
8147
  delete item.path;
8000
- this._refreshContent(search_value, filter);
8148
+ this._refreshContent( searchValue, filter );
8001
8149
  };
8002
8150
  } });
8003
8151
  }else
@@ -8005,15 +8153,15 @@ class AssetView {
8005
8153
  item.domEl = add_item( item );
8006
8154
  }
8007
8155
  }
8008
- this.allow_next_page = filtered_data.length - 1 > AssetView.MAX_PAGE_ELEMENTS;
8009
- LX.emit("@on_page_change", "Page " + this.contentPage + " / " + ((((filtered_data.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1));
8156
+ this.allowNextPage = filteredData.length - 1 > AssetView.MAX_PAGE_ELEMENTS;
8157
+ LX.emit("@on_page_change", "Page " + this.contentPage + " / " + ((((filteredData.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1));
8010
8158
  }
8011
8159
 
8012
8160
  /**
8013
8161
  * @method _previewAsset
8014
8162
  */
8015
8163
 
8016
- _previewAsset(file) {
8164
+ _previewAsset( file ) {
8017
8165
 
8018
8166
  const is_base_64 = file.src && file.src.includes("data:image/");
8019
8167
 
@@ -8022,34 +8170,37 @@ class AssetView {
8022
8170
 
8023
8171
  if( file.type == 'image' || file.src )
8024
8172
  {
8025
- const has_image = ['png', 'jpg'].indexOf( getExtension( file.src ) ) > -1 || is_base_64;
8026
- if( has_image )
8027
- this.previewPanel.addImage(file.src, { style: { width: "100%" } });
8173
+ const hasImage = ['png', 'jpg'].indexOf( getExtension( file.src ) ) > -1 || is_base_64;
8174
+ if( hasImage )
8175
+ {
8176
+ this.previewPanel.addImage( file.src, { style: { width: "100%" } } );
8177
+ }
8028
8178
  }
8029
8179
 
8030
8180
  const options = { disabled: true };
8031
8181
 
8032
8182
  this.previewPanel.addText("Filename", file.id, null, options);
8033
- if(file._path || file.src ) this.previewPanel.addText("URL", file._path ? file._path : file.src, null, options);
8183
+ if( file.lastModified ) this.previewPanel.addText("Last Modified", new Date( file.lastModified ).toLocaleString(), null, options);
8184
+ if( file._path || file.src ) this.previewPanel.addText("URL", file._path ? file._path : file.src, null, options);
8034
8185
  this.previewPanel.addText("Path", this.path.join('/'), null, options);
8035
8186
  this.previewPanel.addText("Type", file.type, null, options);
8036
- if(file.bytesize) this.previewPanel.addText("Size", (file.bytesize/1024).toPrecision(3) + " KBs", null, options);
8037
- if(file.type == "folder") this.previewPanel.addText("Files", file.children ? file.children.length.toString() : "0", null, options);
8187
+ if( file.bytesize ) this.previewPanel.addText("Size", (file.bytesize/1024).toPrecision(3) + " KBs", null, options);
8188
+ if( file.type == "folder" ) this.previewPanel.addText("Files", file.children ? file.children.length.toString() : "0", null, options);
8038
8189
 
8039
8190
  this.previewPanel.addSeparator();
8040
8191
 
8041
- const preview_actions = [...this.preview_actions];
8192
+ const previewActions = [...this.previewActions];
8042
8193
 
8043
- if( !preview_actions.length )
8194
+ if( !previewActions.length )
8044
8195
  {
8045
8196
  // By default
8046
- preview_actions.push({
8197
+ previewActions.push({
8047
8198
  name: 'Download',
8048
8199
  callback: () => LX.downloadURL(file.src, file.id)
8049
8200
  });
8050
8201
  }
8051
8202
 
8052
- for( let action of preview_actions )
8203
+ for( let action of previewActions )
8053
8204
  {
8054
8205
  if( action.type && action.type !== file.type || action.path && action.path !== this.path.join('/') )
8055
8206
  continue;
@@ -8059,7 +8210,7 @@ class AssetView {
8059
8210
  this.previewPanel.merge();
8060
8211
  }
8061
8212
 
8062
- _processDrop(e) {
8213
+ _processDrop( e ) {
8063
8214
 
8064
8215
  const fr = new FileReader();
8065
8216
  const num_files = e.dataTransfer.files.length;
@@ -8079,7 +8230,8 @@ class AssetView {
8079
8230
  let item = {
8080
8231
  "id": file.name,
8081
8232
  "src": e.currentTarget.result,
8082
- "extension": ext
8233
+ "extension": ext,
8234
+ "lastModified": file.lastModified
8083
8235
  };
8084
8236
 
8085
8237
  switch(ext)
@@ -8104,7 +8256,7 @@ class AssetView {
8104
8256
 
8105
8257
  if(i == (num_files - 1)) {
8106
8258
  this._refreshContent();
8107
- if( !this.skip_browser )
8259
+ if( !this.skipBrowser )
8108
8260
  this.tree.refresh();
8109
8261
  }
8110
8262
  };
@@ -8124,10 +8276,10 @@ class AssetView {
8124
8276
  this._refreshContent();
8125
8277
  }
8126
8278
 
8127
- _enterFolder( folder_item ) {
8279
+ _enterFolder( folderItem ) {
8128
8280
 
8129
8281
  this.prevData.push( this.currentData );
8130
- this.currentData = folder_item.children;
8282
+ this.currentData = folderItem.children;
8131
8283
  this.contentPage = 1;
8132
8284
  this._refreshContent();
8133
8285
 
@@ -8135,27 +8287,33 @@ class AssetView {
8135
8287
  this._updatePath(this.currentData);
8136
8288
 
8137
8289
  // Trigger event
8138
- if(this.onevent) {
8139
- const event = new AssetViewEvent(AssetViewEvent.ENTER_FOLDER, folder_item);
8290
+ if( this.onevent )
8291
+ {
8292
+ const event = new AssetViewEvent( AssetViewEvent.ENTER_FOLDER, folderItem );
8140
8293
  this.onevent( event );
8141
8294
  }
8142
8295
  }
8143
8296
 
8144
8297
  _deleteItem( item ) {
8145
8298
 
8146
- const idx = this.currentData.indexOf(item);
8147
- if(idx > -1) {
8148
- this.currentData.splice(idx, 1);
8149
- this._refreshContent(this.search_value, this.filter);
8299
+ const idx = this.currentData.indexOf( item );
8300
+ if(idx < 0)
8301
+ {
8302
+ console.error( "[AssetView Error] Cannot delete. Item not found." );
8303
+ return;
8304
+ }
8150
8305
 
8151
- if(this.onevent) {
8152
- const event = new AssetViewEvent(AssetViewEvent.ASSET_DELETED, item );
8153
- this.onevent( event );
8154
- }
8306
+ this.currentData.splice( idx, 1 );
8307
+ this._refreshContent( this.searchValue, this.filter );
8155
8308
 
8156
- this.tree.refresh();
8157
- this._processData(this.data);
8309
+ if(this.onevent)
8310
+ {
8311
+ const event = new AssetViewEvent( AssetViewEvent.ASSET_DELETED, item );
8312
+ this.onevent( event );
8158
8313
  }
8314
+
8315
+ this.tree.refresh();
8316
+ this._processData( this.data );
8159
8317
  }
8160
8318
 
8161
8319
  _cloneItem( item ) {
@@ -8166,7 +8324,7 @@ class AssetView {
8166
8324
  delete item.folder;
8167
8325
  const new_item = deepCopy( item );
8168
8326
  this.currentData.splice(idx, 0, new_item);
8169
- this._refreshContent(this.search_value, this.filter);
8327
+ this._refreshContent(this.searchValue, this.filter);
8170
8328
 
8171
8329
  if(this.onevent) {
8172
8330
  const event = new AssetViewEvent(AssetViewEvent.ASSET_CLONED, item );
@@ -8433,6 +8591,10 @@ Element.prototype.hasClass = function( list ) {
8433
8591
  return !!r.length;
8434
8592
  }
8435
8593
 
8594
+ Element.prototype.addClass = function( className ) {
8595
+ if( className ) this.classList.add( className );
8596
+ }
8597
+
8436
8598
  Element.prototype.getComputedSize = function() {
8437
8599
  const cs = getComputedStyle( this );
8438
8600
  return {
@@ -8445,7 +8607,6 @@ LX.UTILS = {
8445
8607
  getTime() { return new Date().getTime() },
8446
8608
  compareThreshold( v, p, n, t ) { return Math.abs(v - p) >= t || Math.abs(v - n) >= t },
8447
8609
  compareThresholdRange( v0, v1, t0, t1 ) { return v0 >= t0 && v0 <= t1 || v1 >= t0 && v1 <= t1 || v0 <= t0 && v1 >= t1},
8448
- clamp (num, min, max) { return Math.min(Math.max(num, min), max) },
8449
8610
  uidGenerator: simple_guidGenerator,
8450
8611
  deleteElement( el ) { if( el ) el.remove(); },
8451
8612
  flushCss(element) {