lexgui 0.7.5 → 0.7.6

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.
@@ -319,6 +319,25 @@ class CodeEditor {
319
319
 
320
320
  constructor( area, options = {} ) {
321
321
 
322
+ if( options.filesAsync )
323
+ {
324
+ options.files = [ ...options.filesAsync ];
325
+
326
+ return (async () => {
327
+ await this._init( area, options );
328
+ // Constructors return `this` implicitly, but this is an IIFE, so
329
+ // return `this` explicitly (else we'd return an empty object).
330
+ return this;
331
+ })();
332
+ }
333
+ else
334
+ {
335
+ this._init( area, options );
336
+ }
337
+ }
338
+
339
+ async _init( area, options ) {
340
+
322
341
  window.editor = this;
323
342
 
324
343
  CodeEditor.__instances.push( this );
@@ -1259,7 +1278,6 @@ class CodeEditor {
1259
1278
  if( options.allowAddScripts ?? true )
1260
1279
  {
1261
1280
  this.onCreateFile = options.onCreateFile;
1262
-
1263
1281
  this.addTab( "+", false, "Create file" );
1264
1282
  }
1265
1283
 
@@ -1267,11 +1285,14 @@ class CodeEditor {
1267
1285
  {
1268
1286
  console.assert( options.files.constructor === Array, "_files_ must be an Array!" );
1269
1287
  const numFiles = options.files.length;
1288
+ const loadAsync = ( options.filesAsync !== undefined );
1270
1289
  let filesLoaded = 0;
1271
-
1272
1290
  for( let url of options.files )
1273
1291
  {
1274
- this.loadFile( url, { callback: ( name, text ) => {
1292
+ const finalUrl = url.constructor === Array ? url[ 0 ] : url;
1293
+ const finalFileName = url.constructor === Array ? url[ 1 ] : url;
1294
+
1295
+ await this.loadFile( finalUrl, { filename: finalFileName, async: loadAsync, callback: ( name, text ) => {
1275
1296
  filesLoaded++;
1276
1297
  if( filesLoaded == numFiles )
1277
1298
  {
@@ -1279,7 +1300,7 @@ class CodeEditor {
1279
1300
 
1280
1301
  if( options.onFilesLoaded )
1281
1302
  {
1282
- options.onFilesLoaded( this, numFiles );
1303
+ options.onFilesLoaded( this.loadedTabs, numFiles );
1283
1304
  }
1284
1305
  }
1285
1306
  }});
@@ -1421,15 +1442,12 @@ class CodeEditor {
1421
1442
  const _innerAddTab = ( text, name, title ) => {
1422
1443
 
1423
1444
  // Remove Carriage Return in some cases and sub tabs using spaces
1424
- text = text.replaceAll( '\r', '' );
1425
- text = text.replaceAll( /\t|\\t/g, ' '.repeat( this.tabSpaces ) );
1445
+ text = text.replaceAll( '\r', '' ).replaceAll( /\t|\\t/g, ' '.repeat( this.tabSpaces ) );
1426
1446
 
1427
1447
  // Set current text and language
1428
-
1429
1448
  const lines = text.split( '\n' );
1430
1449
 
1431
1450
  // Add item in the explorer if used
1432
-
1433
1451
  if( this.useFileExplorer || this.skipTabs )
1434
1452
  {
1435
1453
  this._tabStorage[ name ] = {
@@ -1465,13 +1483,20 @@ class CodeEditor {
1465
1483
 
1466
1484
  if( file.constructor == String )
1467
1485
  {
1468
- let filename = file;
1469
-
1470
- LX.request({ url: filename, success: text => {
1471
- const name = filename.substring(filename.lastIndexOf( '/' ) + 1);
1472
- _innerAddTab( text, name, filename );
1473
- } });
1486
+ const filename = file;
1487
+ const name = options.filename ?? filename.substring(filename.lastIndexOf( '/' ) + 1);
1474
1488
 
1489
+ if( options.async ?? false )
1490
+ {
1491
+ const text = await this._requestFileAsync( filename, "text" );
1492
+ _innerAddTab( text, name, options.filename ?? filename );
1493
+ }
1494
+ else
1495
+ {
1496
+ LX.request({ url: filename, success: text => {
1497
+ _innerAddTab( text, name, options.filename ?? filename );
1498
+ } });
1499
+ }
1475
1500
  }
1476
1501
  else // File Blob
1477
1502
  {
@@ -5602,6 +5627,36 @@ s
5602
5627
  delete this._lastResult;
5603
5628
  delete this._scopeStack;
5604
5629
  }
5630
+
5631
+ async _requestFileAsync( url, dataType, nocache ) {
5632
+ return new Promise( (resolve, reject) => {
5633
+ dataType = dataType ?? "arraybuffer";
5634
+ const mimeType = dataType === "arraybuffer" ? "application/octet-stream" : undefined;
5635
+ var xhr = new XMLHttpRequest();
5636
+ xhr.open( 'GET', url, true );
5637
+ xhr.responseType = dataType;
5638
+ if( mimeType )
5639
+ xhr.overrideMimeType( mimeType );
5640
+ if( nocache )
5641
+ xhr.setRequestHeader('Cache-Control', 'no-cache');
5642
+ xhr.onload = function(load)
5643
+ {
5644
+ var response = this.response;
5645
+ if( this.status != 200)
5646
+ {
5647
+ var err = "Error " + this.status;
5648
+ reject(err);
5649
+ return;
5650
+ }
5651
+ resolve( response );
5652
+ };
5653
+ xhr.onerror = function(err) {
5654
+ reject(err);
5655
+ };
5656
+ xhr.send();
5657
+ return xhr;
5658
+ });
5659
+ }
5605
5660
  }
5606
5661
 
5607
5662
  CodeEditor.languages = {
package/build/lexgui.css CHANGED
@@ -6337,7 +6337,11 @@ ul.lexassetscontent {
6337
6337
 
6338
6338
  .uppercase { text-transform: uppercase }
6339
6339
  .capitalize { text-transform: capitalize }
6340
+
6340
6341
  .decoration-none { text-decoration: none }
6342
+ .text-underline { text-decoration: underline }
6343
+
6344
+ .hover\:text-underline:hover { text-decoration: underline }
6341
6345
 
6342
6346
  /* Width / Height */
6343
6347
 
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.5",
17
+ version: "0.7.6",
18
18
  ready: false,
19
19
  extensions: [], // Store extensions used
20
20
  signals: {}, // Events and triggers
@@ -543,16 +543,30 @@ async function init( options = { } )
543
543
  this.main_area = new LX.Area( { id: options.id ?? 'mainarea' } );
544
544
  }
545
545
 
546
- if( ( options.autoTheme ?? true ) )
546
+ // Initial or automatic changes don't force color scheme
547
+ // to be stored in localStorage
548
+
549
+ this._onChangeSystemTheme = function( event ) {
550
+ const storedcolorScheme = localStorage.getItem( "lxColorScheme" );
551
+ if( storedcolorScheme ) return;
552
+ LX.setTheme( event.matches ? "dark" : "light", false );
553
+ };
554
+
555
+ this._mqlPrefersDarkScheme = window.matchMedia ? window.matchMedia("(prefers-color-scheme: dark)") : null;
556
+
557
+ const storedcolorScheme = localStorage.getItem( "lxColorScheme" );
558
+ if( storedcolorScheme )
559
+ {
560
+ LX.setTheme( storedcolorScheme );
561
+ }
562
+ else if( this._mqlPrefersDarkScheme && ( options.autoTheme ?? true ) )
547
563
  {
548
- if( window.matchMedia && window.matchMedia( "(prefers-color-scheme: light)" ).matches )
564
+ if( window.matchMedia( "(prefers-color-scheme: light)" ).matches )
549
565
  {
550
- LX.setTheme( "light" );
566
+ LX.setTheme( "light", false );
551
567
  }
552
568
 
553
- window.matchMedia( "(prefers-color-scheme: dark)" ).addEventListener( "change", event => {
554
- LX.setTheme( event.matches ? "dark" : "light" );
555
- });
569
+ this._mqlPrefersDarkScheme.addEventListener( "change", this._onChangeSystemTheme );
556
570
  }
557
571
 
558
572
  return this.main_area;
@@ -2552,8 +2566,9 @@ class Tabs {
2552
2566
  });
2553
2567
 
2554
2568
  // Attach content
2555
- tabEl.childIndex = ( this.root.childElementCount - 1 );
2556
- this.root.appendChild( tabEl );
2569
+ const indexOffset = options.indexOffset ?? -1;
2570
+ tabEl.childIndex = ( this.root.childElementCount + indexOffset );
2571
+ this.root.insertChildAtIndex( tabEl, tabEl.childIndex + 1 );
2557
2572
  this.area.attach( contentEl );
2558
2573
  this.tabDOMs[ name ] = tabEl;
2559
2574
  this.tabs[ name ] = content;
@@ -4978,11 +4993,13 @@ LX.deepCopy = deepCopy;
4978
4993
  * @method setTheme
4979
4994
  * @description Set dark or light theme
4980
4995
  * @param {String} colorScheme Name of the scheme
4996
+ * @param {Boolean} storeLocal Store in localStorage
4981
4997
  */
4982
- function setTheme( colorScheme )
4998
+ function setTheme( colorScheme, storeLocal = true )
4983
4999
  {
4984
5000
  colorScheme = ( colorScheme == "light" ) ? "light" : "dark";
4985
5001
  document.documentElement.setAttribute( "data-theme", colorScheme );
5002
+ if( storeLocal ) localStorage.setItem( "lxColorScheme", colorScheme );
4986
5003
  LX.emit( "@on_new_color_scheme", colorScheme );
4987
5004
  }
4988
5005
 
@@ -5011,6 +5028,26 @@ function switchTheme()
5011
5028
 
5012
5029
  LX.switchTheme = switchTheme;
5013
5030
 
5031
+ /**
5032
+ * @method setSystemTheme
5033
+ * @description Sets back the system theme
5034
+ */
5035
+ function setSystemTheme()
5036
+ {
5037
+ const currentTheme = ( window.matchMedia && window.matchMedia( "(prefers-color-scheme: light)" ).matches ) ? "light" : "dark";
5038
+ setTheme( currentTheme );
5039
+ localStorage.removeItem( "lxColorScheme" );
5040
+
5041
+ // Reapply listener
5042
+ if( this._mqlPrefersDarkScheme )
5043
+ {
5044
+ this._mqlPrefersDarkScheme.removeEventListener( "change", this._onChangeSystemTheme );
5045
+ this._mqlPrefersDarkScheme.addEventListener( "change", this._onChangeSystemTheme );
5046
+ }
5047
+ }
5048
+
5049
+ LX.setSystemTheme = setSystemTheme;
5050
+
5014
5051
  /**
5015
5052
  * @method setThemeColor
5016
5053
  * @description Sets a new value for one of the main theme variables
@@ -8993,7 +9030,7 @@ class TextInput extends BaseComponent {
8993
9030
 
8994
9031
  this.valid = ( v ) => {
8995
9032
  v = v ?? this.value();
8996
- if( !v.length || wValue.pattern == "" ) return true;
9033
+ if( ( wValue.pattern ?? "" ) == "" ) return true;
8997
9034
  const regexp = new RegExp( wValue.pattern );
8998
9035
  return regexp.test( v );
8999
9036
  };
@@ -9732,19 +9769,21 @@ class Form extends BaseComponent {
9732
9769
 
9733
9770
  const primaryButton = new LX.Button( null, options.primaryActionName ?? "Submit", ( value, event ) => {
9734
9771
 
9772
+ const errors = [];
9773
+
9735
9774
  for( let entry in data )
9736
9775
  {
9737
9776
  let entryData = data[ entry ];
9738
9777
 
9739
9778
  if( !entryData.textComponent.valid() )
9740
9779
  {
9741
- return;
9780
+ errors.push( { type: "input_not_valid", entry } );
9742
9781
  }
9743
9782
  }
9744
9783
 
9745
9784
  if( callback )
9746
9785
  {
9747
- callback( container.formData, event );
9786
+ callback( container.formData, errors, event );
9748
9787
  }
9749
9788
  }, { width: "100%", minWidth: "0", buttonClass: options.primaryButtonClass ?? "contrast" } );
9750
9789
 
@@ -15949,8 +15988,7 @@ class Sidebar {
15949
15988
  return;
15950
15989
  }
15951
15990
 
15952
- const f = options.callback;
15953
- if( f ) f.call( this, key, item.value, e );
15991
+ let value = undefined;
15954
15992
 
15955
15993
  if( isCollapsable )
15956
15994
  {
@@ -15960,14 +15998,18 @@ class Sidebar {
15960
15998
  {
15961
15999
  item.value = !item.value;
15962
16000
  item.checkbox.set( item.value, true );
16001
+ value = item.value;
15963
16002
  }
15964
-
15965
- if( options.swap && !( e.target instanceof HTMLInputElement ) )
16003
+ else if( options.swap && !( e.target instanceof HTMLInputElement ) )
15966
16004
  {
15967
16005
  const swapInput = itemDom.querySelector( "input" );
15968
16006
  swapInput.checked = !swapInput.checked;
16007
+ value = swapInput.checked;
15969
16008
  }
15970
16009
 
16010
+ const f = options.callback;
16011
+ if( f ) f.call( this, key, value ?? entry, e );
16012
+
15971
16013
  // Manage selected
15972
16014
  if( this.displaySelected && !options.skipSelection )
15973
16015
  {