lexgui 0.1.44 → 0.1.46
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.
- package/build/components/codeeditor.js +117 -89
- package/build/lexgui.css +349 -123
- package/build/lexgui.js +690 -169
- package/build/lexgui.module.js +687 -167
- package/changelog.md +26 -2
- package/demo.js +104 -15
- package/package.json +1 -1
|
@@ -313,6 +313,9 @@ class CodeEditor {
|
|
|
313
313
|
this.base_area = area;
|
|
314
314
|
this.area = new LX.Area( { className: "lexcodeeditor", height: "100%", skipAppend: true } );
|
|
315
315
|
|
|
316
|
+
this.skipCodeInfo = options.skipInfo ?? false;
|
|
317
|
+
this.disableEdition = options.disableEdition ?? false;
|
|
318
|
+
|
|
316
319
|
this.tabs = this.area.addTabs( { onclose: (name) => {
|
|
317
320
|
delete this.openedTabs[ name ];
|
|
318
321
|
if( Object.keys( this.openedTabs ).length < 2 )
|
|
@@ -322,12 +325,15 @@ class CodeEditor {
|
|
|
322
325
|
}
|
|
323
326
|
} } );
|
|
324
327
|
|
|
325
|
-
this.
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
328
|
+
if( !this.disableEdition )
|
|
329
|
+
{
|
|
330
|
+
this.tabs.root.addEventListener( 'dblclick', (e) => {
|
|
331
|
+
if( options.allowAddScripts ?? true ) {
|
|
332
|
+
e.preventDefault();
|
|
333
|
+
this.addTab("unnamed.js", true);
|
|
334
|
+
}
|
|
335
|
+
} );
|
|
336
|
+
}
|
|
331
337
|
|
|
332
338
|
// Full editor
|
|
333
339
|
area.root.classList.add('codebasearea');
|
|
@@ -339,15 +345,16 @@ class CodeEditor {
|
|
|
339
345
|
this.root.tabIndex = -1;
|
|
340
346
|
area.attach( this.root );
|
|
341
347
|
|
|
342
|
-
this.skipCodeInfo = options.skipInfo ?? false;
|
|
343
|
-
this.disableEdition = options.disableEdition ?? false;
|
|
344
|
-
|
|
345
348
|
if( !this.disableEdition )
|
|
346
349
|
{
|
|
347
350
|
this.root.addEventListener( 'keydown', this.processKey.bind( this) );
|
|
348
351
|
this.root.addEventListener( 'focus', this.processFocus.bind( this, true ) );
|
|
349
352
|
this.root.addEventListener( 'focusout', this.processFocus.bind( this, false ) );
|
|
350
353
|
}
|
|
354
|
+
else
|
|
355
|
+
{
|
|
356
|
+
this.root.classList.add( "disabled" );
|
|
357
|
+
}
|
|
351
358
|
|
|
352
359
|
this.root.addEventListener( 'mousedown', this.processMouse.bind(this) );
|
|
353
360
|
this.root.addEventListener( 'mouseup', this.processMouse.bind(this) );
|
|
@@ -386,54 +393,58 @@ class CodeEditor {
|
|
|
386
393
|
window.scroller = this.codeScroller;
|
|
387
394
|
|
|
388
395
|
let lastScrollTopValue = -1;
|
|
389
|
-
this.codeScroller.addEventListener( 'scroll', e => {
|
|
390
396
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
397
|
+
if( !this.disableEdition )
|
|
398
|
+
{
|
|
399
|
+
this.codeScroller.addEventListener( 'scroll', e => {
|
|
400
|
+
|
|
401
|
+
if( this._discardScroll )
|
|
402
|
+
{
|
|
403
|
+
this._discardScroll = false;
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
396
406
|
|
|
397
|
-
|
|
407
|
+
this.setScrollBarValue( 'vertical' );
|
|
398
408
|
|
|
399
|
-
|
|
409
|
+
const scrollTop = this.getScrollTop();
|
|
400
410
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
{
|
|
404
|
-
if( this.visibleLinesViewport.y < (this.code.lines.length - 1) )
|
|
411
|
+
// Scroll down...
|
|
412
|
+
if( scrollTop > lastScrollTopValue )
|
|
405
413
|
{
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
414
|
+
if( this.visibleLinesViewport.y < (this.code.lines.length - 1) )
|
|
415
|
+
{
|
|
416
|
+
const totalLinesInViewport = ((this.codeScroller.offsetHeight - 36) / this.lineHeight)|0;
|
|
417
|
+
const scrollDownBoundary =
|
|
418
|
+
( Math.max( this.visibleLinesViewport.y - totalLinesInViewport, 0 ) - 1 ) * this.lineHeight;
|
|
409
419
|
|
|
410
|
-
|
|
420
|
+
if( scrollTop >= scrollDownBoundary )
|
|
421
|
+
this.processLines( CodeEditor.UPDATE_VISIBLE_LINES );
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// Scroll up...
|
|
425
|
+
else
|
|
426
|
+
{
|
|
427
|
+
const scrollUpBoundary = parseInt( this.code.style.top );
|
|
428
|
+
if( scrollTop < scrollUpBoundary )
|
|
411
429
|
this.processLines( CodeEditor.UPDATE_VISIBLE_LINES );
|
|
412
430
|
}
|
|
413
|
-
}
|
|
414
|
-
// Scroll up...
|
|
415
|
-
else
|
|
416
|
-
{
|
|
417
|
-
const scrollUpBoundary = parseInt( this.code.style.top );
|
|
418
|
-
if( scrollTop < scrollUpBoundary )
|
|
419
|
-
this.processLines( CodeEditor.UPDATE_VISIBLE_LINES );
|
|
420
|
-
}
|
|
421
431
|
|
|
422
|
-
|
|
423
|
-
|
|
432
|
+
lastScrollTopValue = scrollTop;
|
|
433
|
+
});
|
|
424
434
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
435
|
+
this.codeScroller.addEventListener( 'wheel', e => {
|
|
436
|
+
if( e.ctrlKey )
|
|
437
|
+
{
|
|
438
|
+
e.preventDefault();
|
|
439
|
+
( e.deltaY > 0.0 ? this._decreaseFontSize() : this._increaseFontSize() );
|
|
440
|
+
}
|
|
441
|
+
else
|
|
442
|
+
{
|
|
443
|
+
const dX = ( e.deltaY > 0.0 ? 10.0 : -10.0 ) * ( e.shiftKey ? 1.0 : 0.0 );
|
|
444
|
+
if( dX != 0.0 ) this.setScrollBarValue( 'horizontal', dX );
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}
|
|
437
448
|
}
|
|
438
449
|
|
|
439
450
|
// This is only the container, line numbers are in the same line div
|
|
@@ -455,59 +466,62 @@ class CodeEditor {
|
|
|
455
466
|
area.attach( this.hScrollbar.root );
|
|
456
467
|
}
|
|
457
468
|
|
|
458
|
-
|
|
469
|
+
if( !this.disableEdition )
|
|
459
470
|
{
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
471
|
+
// Add autocomplete box
|
|
472
|
+
{
|
|
473
|
+
var box = document.createElement( 'div' );
|
|
474
|
+
box.className = "autocomplete";
|
|
475
|
+
this.autocomplete = box;
|
|
476
|
+
this.tabs.area.attach( box );
|
|
464
477
|
|
|
465
|
-
|
|
466
|
-
|
|
478
|
+
this.isAutoCompleteActive = false;
|
|
479
|
+
}
|
|
467
480
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
481
|
+
// Add search box
|
|
482
|
+
{
|
|
483
|
+
var box = document.createElement( 'div' );
|
|
484
|
+
box.className = "searchbox";
|
|
472
485
|
|
|
473
|
-
|
|
474
|
-
|
|
486
|
+
var searchPanel = new LX.Panel();
|
|
487
|
+
box.appendChild( searchPanel.root );
|
|
475
488
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
489
|
+
searchPanel.sameLine( 4 );
|
|
490
|
+
searchPanel.addText( null, "", null, { placeholder: "Find" } );
|
|
491
|
+
searchPanel.addButton( null, "up", () => this.search( null, true ), { className: 'micro', icon: "fa fa-arrow-up" } );
|
|
492
|
+
searchPanel.addButton( null, "down", () => this.search(), { className: 'micro', icon: "fa fa-arrow-down" } );
|
|
493
|
+
searchPanel.addButton( null, "x", this.hideSearchBox.bind( this ), { className: 'micro', icon: "fa fa-xmark" } );
|
|
481
494
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
495
|
+
box.querySelector( 'input' ).addEventListener( 'keyup', e => {
|
|
496
|
+
if( e.key == 'Escape' ) this.hideSearchBox();
|
|
497
|
+
else if( e.key == 'Enter' ) this.search( e.target.value, !!e.shiftKey );
|
|
498
|
+
} );
|
|
486
499
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
500
|
+
this.searchbox = box;
|
|
501
|
+
this.tabs.area.attach( box );
|
|
502
|
+
}
|
|
490
503
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
504
|
+
// Add search LINE box
|
|
505
|
+
{
|
|
506
|
+
var box = document.createElement( 'div' );
|
|
507
|
+
box.className = "searchbox gotoline";
|
|
495
508
|
|
|
496
|
-
|
|
497
|
-
|
|
509
|
+
var searchPanel = new LX.Panel();
|
|
510
|
+
box.appendChild( searchPanel.root );
|
|
498
511
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
512
|
+
searchPanel.addText( null, "", ( value, event ) => {
|
|
513
|
+
input.value = ":" + value.replaceAll( ':', '' );
|
|
514
|
+
this.goToLine( input.value.slice( 1 ) );
|
|
515
|
+
}, { placeholder: "Go to line", trigger: "input" } );
|
|
503
516
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
517
|
+
let input = box.querySelector( 'input' );
|
|
518
|
+
input.addEventListener( 'keyup', e => {
|
|
519
|
+
if( e.key == 'Escape' ) this.hideSearchLineBox();
|
|
520
|
+
} );
|
|
508
521
|
|
|
509
|
-
|
|
510
|
-
|
|
522
|
+
this.searchlinebox = box;
|
|
523
|
+
this.tabs.area.attach( box );
|
|
524
|
+
}
|
|
511
525
|
}
|
|
512
526
|
|
|
513
527
|
// Add code-sizer
|
|
@@ -1059,7 +1073,7 @@ class CodeEditor {
|
|
|
1059
1073
|
this.addTab("+", false, "New File");
|
|
1060
1074
|
}
|
|
1061
1075
|
|
|
1062
|
-
this.addTab( options.name || "untitled", true, options.title, { language: "
|
|
1076
|
+
this.addTab( options.name || "untitled", true, options.title, { language: "Plain Text" } );
|
|
1063
1077
|
|
|
1064
1078
|
// Create inspector panel
|
|
1065
1079
|
let panel = this._createPanelInfo();
|
|
@@ -1609,6 +1623,11 @@ class CodeEditor {
|
|
|
1609
1623
|
|
|
1610
1624
|
_onSelectTab( isNewTabButton, event, name ) {
|
|
1611
1625
|
|
|
1626
|
+
if( this.disableEdition )
|
|
1627
|
+
{
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1612
1631
|
if( isNewTabButton )
|
|
1613
1632
|
{
|
|
1614
1633
|
this._onNewTab( event );
|
|
@@ -1657,7 +1676,9 @@ class CodeEditor {
|
|
|
1657
1676
|
}, 0 );
|
|
1658
1677
|
|
|
1659
1678
|
if( repeats > 0 )
|
|
1679
|
+
{
|
|
1660
1680
|
name = name.split( '.' ).join( '_' + repeats + '.' );
|
|
1681
|
+
}
|
|
1661
1682
|
|
|
1662
1683
|
const isNewTabButton = ( name === '+' );
|
|
1663
1684
|
|
|
@@ -3369,7 +3390,9 @@ class CodeEditor {
|
|
|
3369
3390
|
|
|
3370
3391
|
// I think it's not necessary but...
|
|
3371
3392
|
if( this.disableEdition )
|
|
3393
|
+
{
|
|
3372
3394
|
return;
|
|
3395
|
+
}
|
|
3373
3396
|
|
|
3374
3397
|
// Some selections don't depend on mouse up..
|
|
3375
3398
|
if( cursor.selection ) cursor.selection.invertIfNecessary();
|
|
@@ -4040,6 +4063,11 @@ class CodeEditor {
|
|
|
4040
4063
|
|
|
4041
4064
|
hideAutoCompleteBox() {
|
|
4042
4065
|
|
|
4066
|
+
if( !this.autocomplete )
|
|
4067
|
+
{
|
|
4068
|
+
return;
|
|
4069
|
+
}
|
|
4070
|
+
|
|
4043
4071
|
const isActive = this.isAutoCompleteActive;
|
|
4044
4072
|
this.isAutoCompleteActive = false;
|
|
4045
4073
|
this.autocomplete.classList.remove( 'show' );
|