diff --git a/src/commons/editor/Editor.tsx b/src/commons/editor/Editor.tsx
index 70927a0270..bf10545724 100644
--- a/src/commons/editor/Editor.tsx
+++ b/src/commons/editor/Editor.tsx
@@ -2,6 +2,7 @@
import { Ace, require as acequire, createEditSession } from 'ace-builds';
import 'ace-builds/src-noconflict/ext-language_tools';
import 'ace-builds/src-noconflict/ext-searchbox';
+import 'ace-builds/src-noconflict/ext-settings_menu';
import 'js-slang/dist/editors/ace/theme/source';
import * as AceBuilds from 'ace-builds';
@@ -559,6 +560,88 @@ const EditorBase = React.memo((props: EditorProps & LocalStateProps) => {
}
});
+ // Override the overlayPage function to add an id to the overlay div.
+ // This allows the overlay div to be referenced and removed when the editor is unmounted.
+ // See https://github.com/source-academy/frontend/pull/2832
+ acequire('ace/ext/menu_tools/overlay_page').overlayPage = function (
+ editor: any,
+ contentElement: HTMLElement,
+ callback: any
+ ) {
+ let closer: HTMLElement | null = document.createElement('div');
+ // Add id to the overlay div
+ closer.id = 'overlay';
+ let ignoreFocusOut = false;
+
+ function documentEscListener(e: KeyboardEvent) {
+ if (e.keyCode === 27) {
+ close();
+ }
+ }
+
+ function close() {
+ if (!closer) return;
+ document.removeEventListener('keydown', documentEscListener);
+ closer?.parentNode?.removeChild(closer);
+ if (editor) {
+ editor.focus();
+ }
+ closer = null;
+ callback && callback();
+ }
+
+ /**
+ * Defines whether overlay is closed when user clicks outside of it.
+ *
+ * @param {Boolean} ignore If set to true overlay stays open when focus moves to another part of the editor.
+ */
+ function setIgnoreFocusOut(ignore: boolean) {
+ ignoreFocusOut = ignore;
+ if (ignore) {
+ closer!.style.pointerEvents = 'none';
+ contentElement.style.pointerEvents = 'auto';
+ }
+ }
+
+ closer.style.cssText =
+ 'margin: 0; padding: 0; ' +
+ 'position: fixed; top:0; bottom:0; left:0; right:0;' +
+ 'z-index: 9990; ' +
+ (editor ? 'background-color: rgba(0, 0, 0, 0.3);' : '');
+ closer.addEventListener('click', function (e: Event) {
+ if (!ignoreFocusOut) {
+ close();
+ }
+ });
+
+ // click closer if esc key is pressed
+ document.addEventListener('keydown', documentEscListener);
+
+ contentElement.addEventListener('click', function (e: Event) {
+ e.stopPropagation();
+ });
+
+ closer.appendChild(contentElement);
+ document.body.appendChild(closer);
+ if (editor) {
+ editor.blur();
+ }
+ return {
+ close: close,
+ setIgnoreFocusOut: setIgnoreFocusOut
+ };
+ };
+
+ // Remove the overlay div when the editor is unmounted
+ React.useEffect(() => {
+ return () => {
+ const div = document.getElementById('overlay');
+ if (div) {
+ div.parentNode?.removeChild(div);
+ }
+ };
+ }, []);
+
return (