|
2 | 2 | import { Ace, require as acequire, createEditSession } from 'ace-builds';
|
3 | 3 | import 'ace-builds/src-noconflict/ext-language_tools';
|
4 | 4 | import 'ace-builds/src-noconflict/ext-searchbox';
|
| 5 | +import 'ace-builds/src-noconflict/ext-settings_menu'; |
5 | 6 | import 'js-slang/dist/editors/ace/theme/source';
|
6 | 7 |
|
7 | 8 | import * as AceBuilds from 'ace-builds';
|
@@ -559,6 +560,88 @@ const EditorBase = React.memo((props: EditorProps & LocalStateProps) => {
|
559 | 560 | }
|
560 | 561 | });
|
561 | 562 |
|
| 563 | + // Override the overlayPage function to add an id to the overlay div. |
| 564 | + // This allows the overlay div to be referenced and removed when the editor is unmounted. |
| 565 | + // See https://github.com/source-academy/frontend/pull/2832 |
| 566 | + acequire('ace/ext/menu_tools/overlay_page').overlayPage = function ( |
| 567 | + editor: any, |
| 568 | + contentElement: HTMLElement, |
| 569 | + callback: any |
| 570 | + ) { |
| 571 | + let closer: HTMLElement | null = document.createElement('div'); |
| 572 | + // Add id to the overlay div |
| 573 | + closer.id = 'overlay'; |
| 574 | + let ignoreFocusOut = false; |
| 575 | + |
| 576 | + function documentEscListener(e: KeyboardEvent) { |
| 577 | + if (e.keyCode === 27) { |
| 578 | + close(); |
| 579 | + } |
| 580 | + } |
| 581 | + |
| 582 | + function close() { |
| 583 | + if (!closer) return; |
| 584 | + document.removeEventListener('keydown', documentEscListener); |
| 585 | + closer?.parentNode?.removeChild(closer); |
| 586 | + if (editor) { |
| 587 | + editor.focus(); |
| 588 | + } |
| 589 | + closer = null; |
| 590 | + callback && callback(); |
| 591 | + } |
| 592 | + |
| 593 | + /** |
| 594 | + * Defines whether overlay is closed when user clicks outside of it. |
| 595 | + * |
| 596 | + * @param {Boolean} ignore If set to true overlay stays open when focus moves to another part of the editor. |
| 597 | + */ |
| 598 | + function setIgnoreFocusOut(ignore: boolean) { |
| 599 | + ignoreFocusOut = ignore; |
| 600 | + if (ignore) { |
| 601 | + closer!.style.pointerEvents = 'none'; |
| 602 | + contentElement.style.pointerEvents = 'auto'; |
| 603 | + } |
| 604 | + } |
| 605 | + |
| 606 | + closer.style.cssText = |
| 607 | + 'margin: 0; padding: 0; ' + |
| 608 | + 'position: fixed; top:0; bottom:0; left:0; right:0;' + |
| 609 | + 'z-index: 9990; ' + |
| 610 | + (editor ? 'background-color: rgba(0, 0, 0, 0.3);' : ''); |
| 611 | + closer.addEventListener('click', function (e: Event) { |
| 612 | + if (!ignoreFocusOut) { |
| 613 | + close(); |
| 614 | + } |
| 615 | + }); |
| 616 | + |
| 617 | + // click closer if esc key is pressed |
| 618 | + document.addEventListener('keydown', documentEscListener); |
| 619 | + |
| 620 | + contentElement.addEventListener('click', function (e: Event) { |
| 621 | + e.stopPropagation(); |
| 622 | + }); |
| 623 | + |
| 624 | + closer.appendChild(contentElement); |
| 625 | + document.body.appendChild(closer); |
| 626 | + if (editor) { |
| 627 | + editor.blur(); |
| 628 | + } |
| 629 | + return { |
| 630 | + close: close, |
| 631 | + setIgnoreFocusOut: setIgnoreFocusOut |
| 632 | + }; |
| 633 | + }; |
| 634 | + |
| 635 | + // Remove the overlay div when the editor is unmounted |
| 636 | + React.useEffect(() => { |
| 637 | + return () => { |
| 638 | + const div = document.getElementById('overlay'); |
| 639 | + if (div) { |
| 640 | + div.parentNode?.removeChild(div); |
| 641 | + } |
| 642 | + }; |
| 643 | + }, []); |
| 644 | + |
562 | 645 | return (
|
563 | 646 | <HotKeys className="Editor bp4-card bp4-elevation-0" handlers={handlers}>
|
564 | 647 | <div className="row editor-react-ace" data-testid="Editor">
|
|
0 commit comments