lexgui 0.1.12 → 0.1.13

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.
@@ -102,6 +102,8 @@ class CodeEditor {
102
102
 
103
103
  constructor( area, options = {} ) {
104
104
 
105
+ window.editor = this;
106
+
105
107
  CodeEditor.__instances.push( this );
106
108
 
107
109
  this.disable_edition = options.disable_edition ?? false;
@@ -160,6 +162,7 @@ class CodeEditor {
160
162
  cursor.style.top = "4px";
161
163
  cursor.position = 0;
162
164
  cursor.line = 0;
165
+ cursor.print = (function() { console.log( this.line, this.position ) }).bind(cursor);
163
166
  this.cursors.appendChild(cursor);
164
167
  }
165
168
 
@@ -192,7 +195,7 @@ class CodeEditor {
192
195
  this.tabSpaces = 4;
193
196
  this.maxUndoSteps = 16;
194
197
  this.lineHeight = 20;
195
- this.charWidth = 8;//this.measureChar();
198
+ this.charWidth = 8; //this.measureChar();
196
199
  this._lastTime = null;
197
200
 
198
201
  this.languages = [
@@ -210,30 +213,25 @@ class CodeEditor {
210
213
  'WGSL': ['var', 'let', 'true', 'false', 'fn', 'bool', 'u32', 'i32', 'f16', 'f32', 'vec2f', 'vec3f', 'vec4f', 'mat2x2f', 'mat3x3f', 'mat4x4f', 'array', 'atomic', 'struct',
211
214
  'sampler', 'sampler_comparison', 'texture_depth_2d', 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d',
212
215
  'texture_external', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array', 'texture_storage_1d', 'texture_storage_2d',
213
- 'texture_storage_2d_array', 'texture_storage_3d'],
214
- 'JSON': []
216
+ 'texture_storage_2d_array', 'texture_storage_3d']
217
+ };
218
+ this.utils = { // These ones don't have hightlight, used as suggestions to autocomplete only...
219
+ 'JavaScript': ['querySelector', 'body', 'addEventListener', 'removeEventListener', 'remove', 'sort', 'keys', 'filter', 'isNaN', 'parseFloat', 'parseInt', 'EPSILON', 'isFinite',
220
+ 'bind', 'prototype', 'length', 'assign', 'entries', 'values', 'concat', 'substring', 'substr', 'splice', 'slice', 'buffer', 'appendChild', 'createElement'],
221
+ 'WGSL': ['textureSample']
215
222
  };
216
- this.utils = {
217
- 'JavaScript': ['querySelector', 'body', 'addEventListener', 'removeEventListener', 'remove', 'sort', 'filter', 'isNaN', 'parseFloat', 'parseInt'],
218
- 'GLSL': [],
219
- 'CSS': [],
220
- 'WGSL': [],
221
- 'JSON': []
223
+ this.types = {
224
+ 'JavaScript': ['Object', 'String', 'Function', 'Boolean', 'Symbol', 'Error', 'Number']
222
225
  };
223
226
  this.builtin = {
224
- 'JavaScript': ['document', 'console', 'window', 'navigator', 'Object', 'Function', 'Boolean', 'Symbol', 'Error'],
225
- 'CSS': ['*', '!important'],
226
- 'GLSL': [],
227
- 'WGSL': [],
228
- 'JSON': []
227
+ 'JavaScript': ['document', 'console', 'window', 'navigator'],
228
+ 'CSS': ['*', '!important']
229
229
  };
230
230
  this.statementsAndDeclarations = {
231
231
  'JavaScript': ['for', 'if', 'else', 'case', 'switch', 'return', 'while', 'continue', 'break', 'do', 'import',
232
232
  'from', 'throw', 'async', 'try', 'catch'],
233
233
  'GLSL': ['for', 'if', 'else', 'return', 'continue', 'break'],
234
- 'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'uniform'],
235
- 'JSON': [],
236
- 'CSS': []
234
+ 'WGSL': ['const','for', 'if', 'else', 'return', 'continue', 'break', 'storage', 'read', 'uniform']
237
235
  };
238
236
  this.symbols = {
239
237
  'JavaScript': ['<', '>', '[', ']', '{', '}', '(', ')', ';', '=', '|', '||', '&', '&&', '?', '??'],
@@ -265,6 +263,8 @@ class CodeEditor {
265
263
  this.code.lines[ln] = sliceChar( this.code.lines[ln], cursor.position - 1 );
266
264
  this.cursorToLeft( letter );
267
265
  this.processLine(ln);
266
+ if( this.useAutoComplete )
267
+ this.showAutoCompleteBox( 'foo', cursor );
268
268
  }
269
269
  else if(this.code.lines[ln - 1] != undefined) {
270
270
  this.lineUp();
@@ -326,16 +326,17 @@ class CodeEditor {
326
326
  this._refreshCodeInfo(cursor.line + 1, cursor.position);
327
327
  this.code.scrollLeft = 0;
328
328
 
329
- if( !e.shiftKey || e.cancelShift )
330
- return;
331
-
332
- // Get last selection range
333
- if(this.selection)
329
+ if( e.shiftKey && !e.cancelShift )
330
+ {
331
+ // Get last selection range
332
+ if(this.selection)
334
333
  last_pos += this.selection.chars;
335
334
 
336
- this.startSelection(cursor);
337
- var string = this.code.lines[ln].substring(idx, last_pos);
338
- this.selection.selectInline(idx, cursor.line, this.measureString(string));
335
+ this.startSelection(cursor);
336
+ var string = this.code.lines[ln].substring(idx, last_pos);
337
+ this.selection.selectInline(idx, cursor.line, this.measureString(string));
338
+ } else
339
+ this.endSelection();
339
340
  });
340
341
 
341
342
  this.action('End', false, ( ln, cursor, e ) => {
@@ -346,7 +347,8 @@ class CodeEditor {
346
347
  if(!this.selection)
347
348
  this.startSelection(cursor);
348
349
  this.selection.selectInline(cursor.position, cursor.line, this.measureString(string));
349
- }
350
+ } else
351
+ this.endSelection();
350
352
 
351
353
  this.resetCursorPos( CodeEditor.CURSOR_LEFT );
352
354
  this.cursorToString( cursor, this.code.lines[ln] );
@@ -403,11 +405,18 @@ class CodeEditor {
403
405
  if( e.shiftKey ) {
404
406
  if(!this.selection)
405
407
  this.startSelection(cursor);
406
- this.selection.fromX = cursor.position;
407
- this.selection.toY = this.selection.toY > 0 ? this.selection.toY - 1 : 0;
408
- this.processSelection(null, true);
409
- this.cursorToPosition(cursor, this.selection.fromX);
408
+
409
+ this.selection.toY = (this.selection.toY > 0) ? (this.selection.toY - 1) : 0;
410
410
  this.cursorToLine(cursor, this.selection.toY);
411
+
412
+ var letter = this.getCharAtPos( cursor );
413
+ if(!letter) {
414
+ this.selection.toX = (this.code.lines[cursor.line].length - 1);
415
+ this.cursorToPosition(cursor, this.selection.toX);
416
+ }
417
+
418
+ this.processSelection(null, true);
419
+
411
420
  } else {
412
421
  this.endSelection();
413
422
  this.lineUp();
@@ -431,11 +440,17 @@ class CodeEditor {
431
440
  if( e.shiftKey ) {
432
441
  if(!this.selection)
433
442
  this.startSelection(cursor);
434
- this.selection.toX = cursor.position;
443
+
435
444
  this.selection.toY = this.selection.toY < this.code.lines.length - 1 ? this.selection.toY + 1 : this.code.lines.length - 1;
436
- this.processSelection(null, true);
437
- this.cursorToPosition(cursor, this.selection.toX);
438
445
  this.cursorToLine(cursor, this.selection.toY);
446
+
447
+ var letter = this.getCharAtPos( cursor );
448
+ if(!letter) {
449
+ this.selection.toX = Math.max(this.code.lines[cursor.line].length - 1, 0);
450
+ this.cursorToPosition(cursor, this.selection.toX);
451
+ }
452
+
453
+ this.processSelection(null, true);
439
454
  } else {
440
455
 
441
456
  if( this.code.lines[ ln + 1 ] == undefined )
@@ -487,7 +502,11 @@ class CodeEditor {
487
502
  this.processSelection(null, true);
488
503
  }
489
504
  else {
490
- if(!this.selection) this.cursorToLeft( letter, cursor );
505
+ if(!this.selection) {
506
+ this.cursorToLeft( letter, cursor );
507
+ if( this.useAutoComplete && this.isAutoCompleteActive )
508
+ this.showAutoCompleteBox( 'foo', cursor );
509
+ }
491
510
  else {
492
511
  this.selection.invertIfNecessary();
493
512
  this.resetCursorPos( CodeEditor.CURSOR_LEFT | CodeEditor.CURSOR_TOP );
@@ -546,7 +565,11 @@ class CodeEditor {
546
565
  this.cursorToRight( letter, cursor );
547
566
  this.processSelection(null, keep_range);
548
567
  }else{
549
- if(!this.selection) this.cursorToRight( letter, cursor );
568
+ if(!this.selection) {
569
+ this.cursorToRight( letter, cursor );
570
+ if( this.useAutoComplete && this.isAutoCompleteActive )
571
+ this.showAutoCompleteBox( 'foo', cursor );
572
+ }
550
573
  else
551
574
  {
552
575
  this.selection.invertIfNecessary();
@@ -562,6 +585,7 @@ class CodeEditor {
562
585
  this.lineDown( cursor );
563
586
  e.cancelShift = true;
564
587
  this.actions['Home'].callback(cursor.line, cursor, e);
588
+ this.hideAutoCompleteBox();
565
589
 
566
590
  if( e.shiftKey ) {
567
591
  if(!this.selection) this.startSelection(cursor);
@@ -918,10 +942,26 @@ class CodeEditor {
918
942
  {
919
943
  if( mouse_pos[0] > this.code.scrollWidth || mouse_pos[1] > this.code.scrollHeight )
920
944
  return; // Scrollbar click
945
+
946
+ // Left click only...
947
+ if( e.button === 2 )
948
+ {
949
+ this.processClick(e);
950
+
951
+ this.canOpenContextMenu = !this.selection;
952
+
953
+ if( this.selection )
954
+ {
955
+ this.canOpenContextMenu |= (cursor.line >= this.selection.fromY && cursor.line <= this.selection.toY
956
+ && cursor.position >= this.selection.fromX && cursor.position <= this.selection.toX);
957
+ if( this.canOpenContextMenu )
958
+ return;
959
+ }
960
+ }
961
+
921
962
  this.lastMouseDown = LX.getTime();
922
963
  this.state.selectingText = true;
923
964
  this.endSelection();
924
- return;
925
965
  }
926
966
 
927
967
  else if( e.type == 'mouseup' )
@@ -964,15 +1004,26 @@ class CodeEditor {
964
1004
  }
965
1005
  }
966
1006
 
967
- else if ( e.type == 'contextmenu' ) {
968
- e.preventDefault()
969
- LX.addContextMenu( "Format code", e, m => {
970
- m.add( "JSON", () => {
1007
+ else if ( e.type == 'contextmenu' )
1008
+ {
1009
+ e.preventDefault();
1010
+
1011
+ if( !this.canOpenContextMenu )
1012
+ return;
1013
+
1014
+ LX.addContextMenu( null, e, m => {
1015
+ m.add( "Format/JSON", () => {
971
1016
  let json = this.toJSONFormat(this.getText());
972
1017
  this.code.lines = json.split("\n");
973
1018
  this.processLines();
974
1019
  } );
1020
+ m.add( "" )
1021
+ m.add( "Cut", () => { this._cutContent(); } );
1022
+ m.add( "Copy", () => { this._copyContent(); } );
1023
+ m.add( "Paste", () => { this._pasteContent(); } );
975
1024
  });
1025
+
1026
+ this.canOpenContextMenu = false;
976
1027
  }
977
1028
  }
978
1029
 
@@ -1143,27 +1194,7 @@ class CodeEditor {
1143
1194
  this.cursorToLine(cursor, this.selection.toY);
1144
1195
  break;
1145
1196
  case 'c': // copy
1146
- let text_to_copy = "";
1147
- if( !this.selection ) {
1148
- text_to_copy = "\n" + this.code.lines[cursor.line];
1149
- }
1150
- else {
1151
- const separator = "_NEWLINE_";
1152
- let code = this.code.lines.join(separator);
1153
-
1154
- // Get linear start index
1155
- let index = 0;
1156
-
1157
- for(let i = 0; i <= this.selection.fromY; i++)
1158
- index += (i == this.selection.fromY ? this.selection.fromX : this.code.lines[i].length);
1159
-
1160
- index += this.selection.fromY * separator.length;
1161
- const num_chars = this.selection.chars + (this.selection.toY - this.selection.fromY) * separator.length;
1162
- const text = code.substr(index, num_chars);
1163
- const lines = text.split(separator);
1164
- text_to_copy = lines.join('\n');
1165
- }
1166
- navigator.clipboard.writeText(text_to_copy).then(() => console.log("Successfully copied"), (err) => console.error("Error"));
1197
+ this._copyContent();
1167
1198
  return;
1168
1199
  case 'd': // duplicate line
1169
1200
  e.preventDefault();
@@ -1176,13 +1207,10 @@ class CodeEditor {
1176
1207
  this.onsave( this.getText() );
1177
1208
  return;
1178
1209
  case 'v': // paste
1179
- let text = await navigator.clipboard.readText();
1180
- this.appendText(text);
1210
+ this._pasteContent();
1181
1211
  return;
1182
1212
  case 'x': // cut line
1183
- const to_copy = this.code.lines.splice(lidx, 1)[0];
1184
- this.processLines(lidx);
1185
- navigator.clipboard.writeText(to_copy + '\n');
1213
+ this._cutContent();
1186
1214
  return;
1187
1215
  case 'z': // undo
1188
1216
  if(!this.code.undoSteps.length)
@@ -1272,6 +1300,7 @@ class CodeEditor {
1272
1300
  if( this.selection )
1273
1301
  {
1274
1302
  this.actions['Backspace'].callback(lidx, cursor, e);
1303
+ lidx = cursor.line; // Update this, since it's from the old code
1275
1304
  }
1276
1305
 
1277
1306
  // Append key
@@ -1284,15 +1313,33 @@ class CodeEditor {
1284
1313
 
1285
1314
  this.cursorToRight( key );
1286
1315
 
1287
- // Other special char cases...
1316
+ // Some custom cases for auto key pair (), {}, "", '', ...
1288
1317
 
1289
- if( key == '{' )
1318
+ const pairKeys = ["\"", "'", "(", "{"];
1319
+ if( pairKeys.indexOf( key ) > -1 && !this.wasKeyPaired )
1290
1320
  {
1291
- this.root.dispatchEvent(new KeyboardEvent('keydown', {'key': '}'}));
1321
+ // Find pair key
1322
+ let pair = key;
1323
+ switch(key)
1324
+ {
1325
+ case "'":
1326
+ case "\"":
1327
+ break;
1328
+ case "(": pair = ")"; break;
1329
+ case "{": pair = "}"; break;
1330
+ }
1331
+
1332
+ // Make sure to detect later that the key is paired automatically to avoid loops...
1333
+ this.wasKeyPaired = true;
1334
+
1335
+ this.root.dispatchEvent(new KeyboardEvent('keydown', { 'key': pair }));
1292
1336
  this.cursorToLeft( key, cursor );
1293
- return; // It will be processed with the above event
1337
+ return;
1294
1338
  }
1295
1339
 
1340
+ // Once here we can pair keys again
1341
+ delete this.wasKeyPaired;
1342
+
1296
1343
  // Update only the current line, since it's only an appended key
1297
1344
  this.processLine( lidx );
1298
1345
 
@@ -1302,6 +1349,73 @@ class CodeEditor {
1302
1349
  this.showAutoCompleteBox( key, cursor );
1303
1350
  }
1304
1351
 
1352
+ async _pasteContent() {
1353
+ let text = await navigator.clipboard.readText();
1354
+ this.appendText(text);
1355
+ }
1356
+
1357
+ async _copyContent() {
1358
+
1359
+ let cursor = this.cursors.children[0];
1360
+ let text_to_copy = "";
1361
+
1362
+ if( !this.selection ) {
1363
+ text_to_copy = "\n" + this.code.lines[cursor.line];
1364
+ }
1365
+ else {
1366
+ const separator = "_NEWLINE_";
1367
+ let code = this.code.lines.join(separator);
1368
+
1369
+ // Get linear start index
1370
+ let index = 0;
1371
+
1372
+ for(let i = 0; i <= this.selection.fromY; i++)
1373
+ index += (i == this.selection.fromY ? this.selection.fromX : this.code.lines[i].length);
1374
+
1375
+ index += this.selection.fromY * separator.length;
1376
+ const num_chars = this.selection.chars + (this.selection.toY - this.selection.fromY) * separator.length;
1377
+ const text = code.substr(index, num_chars);
1378
+ const lines = text.split(separator);
1379
+ text_to_copy = lines.join('\n');
1380
+ }
1381
+
1382
+ navigator.clipboard.writeText(text_to_copy).then(() => console.log("Successfully copied"), (err) => console.error("Error"));
1383
+ }
1384
+
1385
+ async _cutContent() {
1386
+
1387
+ let cursor = this.cursors.children[0];
1388
+ let lidx = cursor.line;
1389
+ let text_to_cut = "";
1390
+
1391
+ if( !this.selection ) {
1392
+ text_to_cut = "\n" + this.code.lines[cursor.line];
1393
+ this.code.lines.splice(lidx, 1);
1394
+ this.processLines(lidx);
1395
+ this.resetCursorPos( CodeEditor.CURSOR_LEFT );
1396
+ }
1397
+ else {
1398
+ const separator = "_NEWLINE_";
1399
+ let code = this.code.lines.join(separator);
1400
+
1401
+ // Get linear start index
1402
+ let index = 0;
1403
+
1404
+ for(let i = 0; i <= this.selection.fromY; i++)
1405
+ index += (i == this.selection.fromY ? this.selection.fromX : this.code.lines[i].length);
1406
+
1407
+ index += this.selection.fromY * separator.length;
1408
+ const num_chars = this.selection.chars + (this.selection.toY - this.selection.fromY) * separator.length;
1409
+ const text = code.substr(index, num_chars);
1410
+ const lines = text.split(separator);
1411
+ text_to_cut = lines.join('\n');
1412
+
1413
+ this.deleteSelection( cursor );
1414
+ }
1415
+
1416
+ navigator.clipboard.writeText(text_to_cut).then(() => console.log("Successfully cut"), (err) => console.error("Error"));
1417
+ }
1418
+
1305
1419
  action( key, deleteSelection, fn ) {
1306
1420
 
1307
1421
  this.actions[ key ] = {
@@ -1431,6 +1545,11 @@ class CodeEditor {
1431
1545
  }
1432
1546
  }
1433
1547
 
1548
+ _mustHightlightWord( token, kindArray ) {
1549
+
1550
+ return kindArray[this.highlight] && kindArray[this.highlight].indexOf(token) > -1;
1551
+ }
1552
+
1434
1553
  processToken(token, linespan, prev, next) {
1435
1554
 
1436
1555
  let sString = false;
@@ -1457,16 +1576,16 @@ class CodeEditor {
1457
1576
  else if( this._building_string )
1458
1577
  span.classList.add("cm-str");
1459
1578
 
1460
- else if( this.keywords[this.highlight] && this.keywords[this.highlight].indexOf(token) > -1 )
1579
+ else if( this._mustHightlightWord( token, this.keywords ) )
1461
1580
  span.classList.add("cm-kwd");
1462
1581
 
1463
- else if( this.builtin[this.highlight] && this.builtin[this.highlight].indexOf(token) > -1 )
1582
+ else if( this._mustHightlightWord( token, this.builtin ) )
1464
1583
  span.classList.add("cm-bln");
1465
1584
 
1466
- else if( this.statementsAndDeclarations[this.highlight] && this.statementsAndDeclarations[this.highlight].indexOf(token) > -1 )
1585
+ else if( this._mustHightlightWord( token, this.statementsAndDeclarations ) )
1467
1586
  span.classList.add("cm-std");
1468
1587
 
1469
- else if( this.symbols[this.highlight] && this.symbols[this.highlight].indexOf(token) > -1 )
1588
+ else if( this._mustHightlightWord( token, this.symbols ) )
1470
1589
  span.classList.add("cm-sym");
1471
1590
 
1472
1591
  else if( token.substr(0, 2) == '//' )
@@ -1525,6 +1644,10 @@ class CodeEditor {
1525
1644
 
1526
1645
  isType( token, prev, next ) {
1527
1646
 
1647
+ // Common case
1648
+ if( this._mustHightlightWord( token, this.types ) )
1649
+ return true;
1650
+
1528
1651
  if( this.highlight == 'JavaScript' )
1529
1652
  {
1530
1653
  return (prev == 'class' && next == '{') || (prev == 'new' && next == '(');
@@ -1543,7 +1666,7 @@ class CodeEditor {
1543
1666
 
1544
1667
  if( !this.selection || (this.selection.fromY != this.selection.toY) )
1545
1668
  return false;
1546
-
1669
+
1547
1670
  const _lastLeft = cursor._left;
1548
1671
 
1549
1672
  // Insert first..
@@ -1554,8 +1677,7 @@ class CodeEditor {
1554
1677
  ].join('');
1555
1678
 
1556
1679
  // Go to the end of the word
1557
- this.cursorToString(cursor,
1558
- this.code.lines[lidx].slice(this.selection.fromX, this.selection.toX + 1));
1680
+ this.cursorToPosition(cursor, this.selection.toX + 1);
1559
1681
 
1560
1682
  // Change next key?
1561
1683
  switch(key)
@@ -1942,11 +2064,16 @@ class CodeEditor {
1942
2064
  let suggestions = [];
1943
2065
 
1944
2066
  // Add language special keys...
1945
- suggestions = suggestions.concat( this.keywords[ this.highlight ] );
1946
- suggestions = suggestions.concat( this.statementsAndDeclarations[ this.highlight ] );
1947
- suggestions = suggestions.concat( this.builtin[ this.highlight ] );
1948
- suggestions = suggestions.concat( this.utils[ this.highlight ] );
1949
- suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
2067
+ suggestions = suggestions.concat(
2068
+ this.builtin[ this.highlight ] ?? [],
2069
+ this.keywords[ this.highlight ] ?? [],
2070
+ this.statementsAndDeclarations[ this.highlight ] ?? [],
2071
+ this.types[ this.highlight ] ?? [],
2072
+ this.utils[ this.highlight ] ?? []
2073
+ );
2074
+
2075
+ // Add words in current tab plus remove current word
2076
+ // suggestions = suggestions.concat( Object.keys(this.code.tokens).filter( a => a != word ) );
1950
2077
 
1951
2078
  // Remove single chars and duplicates...
1952
2079
  suggestions = suggestions.filter( (value, index) => value.length > 1 && suggestions.indexOf(value) === index );
@@ -1962,6 +2089,17 @@ class CodeEditor {
1962
2089
  var pre = document.createElement('pre');
1963
2090
  this.autocomplete.appendChild(pre);
1964
2091
 
2092
+ var icon = document.createElement('a');
2093
+
2094
+ if( this._mustHightlightWord( s, this.utils ) )
2095
+ icon.className = "fa fa-cube";
2096
+ else if( this._mustHightlightWord( s, this.types ) )
2097
+ icon.className = "fa fa-code";
2098
+ else
2099
+ icon.className = "fa fa-font";
2100
+
2101
+ pre.appendChild(icon);
2102
+
1965
2103
  pre.addEventListener( 'click', () => {
1966
2104
  this.autoCompleteWord( cursor, s );
1967
2105
  } );
@@ -2042,13 +2180,13 @@ class CodeEditor {
2042
2180
  for( let childSpan of child.childNodes )
2043
2181
  word += childSpan.innerHTML;
2044
2182
 
2045
- return [word, i ]; // Get text of the span inside the 'pre' element
2183
+ return [ word, i ]; // Get text of the span inside the 'pre' element
2046
2184
  }
2047
2185
  }
2048
2186
  }
2049
2187
 
2050
2188
  moveArrowSelectedAutoComplete( dir ) {
2051
-
2189
+
2052
2190
  if( !this.isAutoCompleteActive )
2053
2191
  return;
2054
2192
 
@@ -2061,7 +2199,7 @@ class CodeEditor {
2061
2199
  if( (idx + offset) < 0 ) return;
2062
2200
  }
2063
2201
 
2064
- this.autocomplete.scrollTop += offset * 20;
2202
+ this.autocomplete.scrollTop += offset * 18;
2065
2203
 
2066
2204
  // Remove selected from the current word and add it to the next one
2067
2205
  this.autocomplete.childNodes[ idx ].classList.remove('selected');
@@ -787,7 +787,7 @@ class Timeline {
787
787
  for(var i = this.tracksDrawn.length - 1; i >= 0; --i)
788
788
  {
789
789
  var t = this.tracksDrawn[i];
790
- if( localY >= t[1] && localY < (t[1] + t[2]) )
790
+ if( t[1] >= this.topMargin && localY >= t[1] && localY < (t[1] + t[2]) )
791
791
  {
792
792
  track = t[0];
793
793
  break;
@@ -820,10 +820,6 @@ class Timeline {
820
820
  const discard = this.movingKeys || (LX.UTILS.getTime() - this.clickTime) > 420; // ms
821
821
  this.movingKeys ? innerSetTime( this.currentTime ) : 0;
822
822
 
823
- if(e.button == 0 && this.grabbing && this.onClipMoved && this.lastClipsSelected.length){
824
- this.onClipMoved(this.lastClipsSelected);
825
- }
826
-
827
823
  this.grabbing_timeline = false;
828
824
  this.grabbing = false;
829
825
  this.grabbingScroll = false;
package/build/lexgui.css CHANGED
@@ -2900,6 +2900,14 @@ ul.lexassetscontent {
2900
2900
  margin: 0;
2901
2901
  pointer-events: unset;
2902
2902
  cursor: default;
2903
+ height: 18px;
2904
+ }
2905
+
2906
+ .lexcodeeditor .autocomplete pre a {
2907
+ font-size: 11px;
2908
+ margin-top: 4px;
2909
+ margin-right: 6px;
2910
+ margin-left: 2px;
2903
2911
  }
2904
2912
 
2905
2913
  .lexcodeeditor .autocomplete pre:hover {
@@ -2912,7 +2920,6 @@ ul.lexassetscontent {
2912
2920
  }
2913
2921
 
2914
2922
  .lexcodeeditor .autocomplete pre span {
2915
- margin: 2px 0px;
2916
2923
  cursor: inherit;
2917
2924
  }
2918
2925
 
package/build/lexgui.js CHANGED
@@ -12,7 +12,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
12
12
  */
13
13
 
14
14
  var LX = global.LX = {
15
- version: "0.1.12",
15
+ version: "0.1.13",
16
16
  ready: false,
17
17
  components: [], // specific pre-build components
18
18
  signals: {} // events and triggers
@@ -3835,6 +3835,8 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
3835
3835
  list_options.style.height = "calc(100% - 25px)";
3836
3836
 
3837
3837
  filter.addEventListener('focusout', function(e) {
3838
+ if (e.relatedTarget && e.relatedTarget.tagName == "UL" && e.relatedTarget.classList.contains("lexoptions"))
3839
+ return;
3838
3840
  list.toggleAttribute('hidden', true);
3839
3841
  });
3840
3842
  }
@@ -6415,6 +6417,7 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6415
6417
  this.skip_preview = options.skip_preview ?? false;
6416
6418
  this.only_folders = options.only_folders ?? true;
6417
6419
  this.preview_actions = options.preview_actions ?? [];
6420
+ this.context_menu = options.context_menu ?? [];
6418
6421
 
6419
6422
  if( !this.skip_browser )
6420
6423
  {
@@ -6801,23 +6804,26 @@ console.warn( 'Script "build/lexgui.js" is depracated and will be removed soon.
6801
6804
  }
6802
6805
  });
6803
6806
 
6804
- itemEl.addEventListener('contextmenu', function(e) {
6805
- e.preventDefault();
6806
-
6807
- const multiple = that.content.querySelectorAll('.selected').length;
6808
-
6809
- LX.addContextMenu( multiple > 1 ? (multiple + " selected") :
6810
- is_folder ? item.id : item.type, e, m => {
6811
- if(multiple <= 1)
6812
- m.add("Rename");
6813
- if( !is_folder )
6814
- m.add("Clone", that._cloneItem.bind(that, item));
6815
- if(multiple <= 1)
6816
- m.add("Properties");
6817
- m.add("");
6818
- m.add("Delete", that._deleteItem.bind(that, item));
6807
+ if( that.context_menu )
6808
+ {
6809
+ itemEl.addEventListener('contextmenu', function(e) {
6810
+ e.preventDefault();
6811
+
6812
+ const multiple = that.content.querySelectorAll('.selected').length;
6813
+
6814
+ LX.addContextMenu( multiple > 1 ? (multiple + " selected") :
6815
+ is_folder ? item.id : item.type, e, m => {
6816
+ if(multiple <= 1)
6817
+ m.add("Rename");
6818
+ if( !is_folder )
6819
+ m.add("Clone", that._clone_item.bind(that, item));
6820
+ if(multiple <= 1)
6821
+ m.add("Properties");
6822
+ m.add("");
6823
+ m.add("Delete", that._delete_item.bind(that, item));
6824
+ });
6819
6825
  });
6820
- });
6826
+ }
6821
6827
 
6822
6828
  itemEl.addEventListener("dragstart", function(e) {
6823
6829
  e.preventDefault();
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  var LX = {
11
- version: "0.1.12",
11
+ version: "0.1.13",
12
12
  ready: false,
13
13
  components: [], // specific pre-build components
14
14
  signals: {} // events and triggers
@@ -3831,6 +3831,8 @@ class Panel {
3831
3831
  list_options.style.height = "calc(100% - 25px)";
3832
3832
 
3833
3833
  filter.addEventListener('focusout', function(e) {
3834
+ if (e.relatedTarget && e.relatedTarget.tagName == "UL" && e.relatedTarget.classList.contains("lexoptions"))
3835
+ return;
3834
3836
  list.toggleAttribute('hidden', true);
3835
3837
  });
3836
3838
  }
@@ -6411,6 +6413,7 @@ class AssetView {
6411
6413
  this.skip_preview = options.skip_preview ?? false;
6412
6414
  this.only_folders = options.only_folders ?? true;
6413
6415
  this.preview_actions = options.preview_actions ?? [];
6416
+ this.context_menu = options.context_menu ?? [];
6414
6417
 
6415
6418
  if( !this.skip_browser )
6416
6419
  {
@@ -6797,23 +6800,26 @@ class AssetView {
6797
6800
  }
6798
6801
  });
6799
6802
 
6800
- itemEl.addEventListener('contextmenu', function(e) {
6801
- e.preventDefault();
6803
+ if( that.context_menu )
6804
+ {
6805
+ itemEl.addEventListener('contextmenu', function(e) {
6806
+ e.preventDefault();
6802
6807
 
6803
- const multiple = that.content.querySelectorAll('.selected').length;
6804
-
6805
- LX.addContextMenu( multiple > 1 ? (multiple + " selected") :
6806
- is_folder ? item.id : item.type, e, m => {
6807
- if(multiple <= 1)
6808
- m.add("Rename");
6809
- if( !is_folder )
6810
- m.add("Clone", that._cloneItem.bind(that, item));
6811
- if(multiple <= 1)
6812
- m.add("Properties");
6813
- m.add("");
6814
- m.add("Delete", that._deleteItem.bind(that, item));
6808
+ const multiple = that.content.querySelectorAll('.selected').length;
6809
+
6810
+ LX.addContextMenu( multiple > 1 ? (multiple + " selected") :
6811
+ is_folder ? item.id : item.type, e, m => {
6812
+ if(multiple <= 1)
6813
+ m.add("Rename");
6814
+ if( !is_folder )
6815
+ m.add("Clone", that._clone_item.bind(that, item));
6816
+ if(multiple <= 1)
6817
+ m.add("Properties");
6818
+ m.add("");
6819
+ m.add("Delete", that._delete_item.bind(that, item));
6820
+ });
6815
6821
  });
6816
- });
6822
+ }
6817
6823
 
6818
6824
  itemEl.addEventListener("dragstart", function(e) {
6819
6825
  e.preventDefault();
@@ -46,8 +46,6 @@
46
46
  // autocomplete: false
47
47
  });
48
48
 
49
- editor.loadFile( "../data/test.json" );
50
- editor.loadFile( "../data/style.css" );
51
49
  editor.loadFile( "../data/script.js" );
52
50
 
53
51
  var ctx = canvas.getContext("2d");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lexgui",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "JS library to create web graphical user interfaces",
5
5
  "type": "module",
6
6
  "main": "./build/lexgui.js",