@elice/material-exercise 1.260529.0 → 1.260608.0

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.
@@ -37,6 +37,7 @@ var React__default = /*#__PURE__*/_interopDefaultCompat(React);
37
37
  */
38
38
  var ExerciseFileEditor = function ExerciseFileEditor(_ref) {
39
39
  var __intl = _ref.__intl;
40
+ var _a, _b, _c;
40
41
  var _React$useContext = React__default.default.useContext(context.ExerciseContext),
41
42
  materialExerciseId = _React$useContext.materialExerciseId,
42
43
  exerciseRoomId = _React$useContext.exerciseRoomId,
@@ -50,6 +51,8 @@ var ExerciseFileEditor = function ExerciseFileEditor(_ref) {
50
51
  var preference = recoil.useRecoilValue(recoil$1.exerciseEditorPreferenceState);
51
52
  var activeFilename = recoil.useRecoilValue(recoil$1.exerciseActiveFilenameState);
52
53
  var readOnly = readOnlyEditor || readOnlyActiveFile;
54
+ // Block clipboard when the lecture's cheat config requires it (server-driven).
55
+ var disableClipboard = (_c = (_b = (_a = lecture === null || lecture === void 0 ? void 0 : lecture.cheatInfo) === null || _a === void 0 ? void 0 : _a.detectionInfo) === null || _b === void 0 ? void 0 : _b.isCopyAndPasteBlocked) !== null && _c !== void 0 ? _c : false;
53
56
  var setUsercodeWebSocketState = recoil.useSetRecoilState(recoil$1.exerciseWebsocketQuery('usercodeEdit'));
54
57
  var _React$useState = React__default.default.useState(null),
55
58
  _React$useState2 = _rollupPluginBabelHelpers.slicedToArray(_React$useState, 2),
@@ -464,6 +467,7 @@ var ExerciseFileEditor = function ExerciseFileEditor(_ref) {
464
467
  preference: Object.assign(Object.assign({}, preference), {
465
468
  readOnly: readOnly
466
469
  }),
470
+ disableClipboard: disableClipboard,
467
471
  noLanguageIntellisense: (lecture === null || lecture === void 0 ? void 0 : lecture.lectureType) === types.enums.LectureType.Test,
468
472
  locale: locale,
469
473
  ref: editorApis,
@@ -61,6 +61,11 @@ export interface MonacoEditorProps {
61
61
  height?: React.CSSProperties['height'];
62
62
  /** Disable intellisense of editor. */
63
63
  noLanguageIntellisense?: boolean;
64
+ /**
65
+ * Block copy/cut/paste via keyboard, mouse (right-click), drag&drop and
66
+ * command palette. For exam environment. Expected to be fixed at mount.
67
+ */
68
+ disableClipboard?: boolean;
64
69
  /** Locale of editor. */
65
70
  locale?: string;
66
71
  /** On editor initialized. */
@@ -14,6 +14,7 @@ var useEditorOptions = require('./hooks/useEditorOptions.js');
14
14
  var monacoLanguage = require('./utils/monacoLanguage.js');
15
15
  var styles = require('./vendors/monaco-collab-ext/styles.js');
16
16
  var useMonacoOptions = require('./editor-hooks/useMonacoOptions.js');
17
+ var useMonacoClipboardGuard = require('./editor-hooks/useMonacoClipboardGuard.js');
17
18
  var useMonacoTheme = require('./editor-hooks/useMonacoTheme.js');
18
19
  var preferences = require('./constants/monaco/preferences.js');
19
20
  var useMonacoEventChange = require('./editor-hooks/useMonacoEventChange.js');
@@ -86,6 +87,8 @@ var MonacoEditor = React.forwardRef(function (_ref, ref) {
86
87
  height = _ref$height === void 0 ? '100%' : _ref$height,
87
88
  _ref$noLanguageIntell = _ref.noLanguageIntellisense,
88
89
  noLanguageIntellisense = _ref$noLanguageIntell === void 0 ? false : _ref$noLanguageIntell,
90
+ _ref$disableClipboard = _ref.disableClipboard,
91
+ disableClipboard = _ref$disableClipboard === void 0 ? false : _ref$disableClipboard,
89
92
  onLoad = _ref.onLoad,
90
93
  onChange = _ref.onChange,
91
94
  onSave = _ref.onSave,
@@ -103,7 +106,8 @@ var MonacoEditor = React.forwardRef(function (_ref, ref) {
103
106
  width: width,
104
107
  height: height,
105
108
  preference: preference,
106
- noLanguageIntellisense: noLanguageIntellisense
109
+ noLanguageIntellisense: noLanguageIntellisense,
110
+ disableClipboard: disableClipboard
107
111
  });
108
112
  /** Ref for preventing change event. */
109
113
  var suppress = React__default.default.useRef(false);
@@ -292,6 +296,7 @@ var MonacoEditor = React.forwardRef(function (_ref, ref) {
292
296
  // Editor hooks.
293
297
  //
294
298
  useMonacoOptions.useMonacoOptions(editor, editorOptions);
299
+ useMonacoClipboardGuard.useMonacoClipboardGuard(editor, disableClipboard, [isReady]);
295
300
  useMonacoTheme.useMonacoTheme(preference.theme, onThemeChange);
296
301
  useMonacoEventChange.useMonacoEventChange(editor, onChange, suppress, [isReady]);
297
302
  useMonacoEventCursor.useMonacoEventCursor(editor, onCursor, [isReady]);
@@ -1,3 +1,4 @@
1
+ export * from './useMonacoClipboardGuard';
1
2
  export * from './useMonacoEventChange';
2
3
  export * from './useMonacoEventCursor';
3
4
  export * from './useMonacoEventScroll';
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var useMonacoClipboardGuard = require('./useMonacoClipboardGuard.js');
3
4
  var useMonacoEventChange = require('./useMonacoEventChange.js');
4
5
  var useMonacoEventCursor = require('./useMonacoEventCursor.js');
5
6
  var useMonacoEventScroll = require('./useMonacoEventScroll.js');
@@ -9,6 +10,7 @@ var useMonacoTheme = require('./useMonacoTheme.js');
9
10
 
10
11
 
11
12
 
13
+ exports.useMonacoClipboardGuard = useMonacoClipboardGuard.useMonacoClipboardGuard;
12
14
  exports.useMonacoEventChange = useMonacoEventChange.useMonacoEventChange;
13
15
  exports.useMonacoEventCursor = useMonacoEventCursor.useMonacoEventCursor;
14
16
  exports.useMonacoEventScroll = useMonacoEventScroll.useMonacoEventScroll;
@@ -0,0 +1,15 @@
1
+ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
2
+ import type React from 'react';
3
+ type Monaco = React.MutableRefObject<monaco.editor.IStandaloneCodeEditor | null>;
4
+ /**
5
+ * Hook for blocking copy/cut/paste of monaco editor in exam environment.
6
+ *
7
+ * Blocks every entry point:
8
+ * - keyboard shortcuts (Ctrl/Cmd+C/V/X, Shift+Insert, Ctrl+Insert, Shift+Delete)
9
+ * - native DOM clipboard/drag events (mouse, right-click, browser edit menu)
10
+ * - command palette clipboard actions (async-clipboard path that skips DOM events)
11
+ *
12
+ * @note `disabled` is expected to be fixed at mount.
13
+ */
14
+ export declare const useMonacoClipboardGuard: (monaco: Monaco, disabled: boolean, deps?: unknown[]) => void;
15
+ export {};
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+
3
+ var _rollupPluginBabelHelpers = require('../../../../_virtual/_rollupPluginBabelHelpers.js');
4
+ var React = require('react');
5
+ var monaco = require('monaco-editor/esm/vs/editor/editor.api');
6
+
7
+ function _interopNamespaceCompat(e) {
8
+ if (e && typeof e === 'object' && 'default' in e) return e;
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n.default = e;
22
+ return Object.freeze(n);
23
+ }
24
+
25
+ var monaco__namespace = /*#__PURE__*/_interopNamespaceCompat(monaco);
26
+
27
+ var EMPTY_DEPS = [];
28
+ /** Keyboard shortcuts that copy/cut/paste, neutralized in exam environment. */
29
+ var BLOCKED_KEYBINDINGS = [monaco__namespace.KeyMod.CtrlCmd | monaco__namespace.KeyCode.KeyC,
30
+ // copy
31
+ monaco__namespace.KeyMod.CtrlCmd | monaco__namespace.KeyCode.KeyX,
32
+ // cut
33
+ monaco__namespace.KeyMod.CtrlCmd | monaco__namespace.KeyCode.KeyV,
34
+ // paste
35
+ monaco__namespace.KeyMod.CtrlCmd | monaco__namespace.KeyCode.Insert,
36
+ // copy (win)
37
+ monaco__namespace.KeyMod.Shift | monaco__namespace.KeyCode.Insert,
38
+ // paste (win)
39
+ monaco__namespace.KeyMod.Shift | monaco__namespace.KeyCode.Delete // cut (win)
40
+ ];
41
+ /**
42
+ * Built-in clipboard actions reachable from the command palette. These run
43
+ * through the async-clipboard path which bypasses the native DOM events below,
44
+ * so they must be neutralized separately (re-registering the same id overrides
45
+ * the built-in action for this editor instance).
46
+ */
47
+ var BLOCKED_ACTIONS = [{
48
+ id: 'editor.action.clipboardCopyAction',
49
+ label: 'Copy'
50
+ }, {
51
+ id: 'editor.action.clipboardCutAction',
52
+ label: 'Cut'
53
+ }, {
54
+ id: 'editor.action.clipboardPasteAction',
55
+ label: 'Paste'
56
+ }];
57
+ /** Native DOM events fired through the editor's hidden textarea. */
58
+ var BLOCKED_DOM_EVENTS = ['copy', 'cut', 'paste', 'contextmenu', 'dragstart', 'drop'];
59
+ /** `beforeinput` types that smuggle clipboard/drag content into the editor. */
60
+ var BLOCKED_INPUT_TYPES = ['insertFromPaste', 'insertFromDrop', 'deleteByCut'];
61
+ var noop = function noop() {
62
+ // intentionally do nothing.
63
+ };
64
+ /**
65
+ * Hook for blocking copy/cut/paste of monaco editor in exam environment.
66
+ *
67
+ * Blocks every entry point:
68
+ * - keyboard shortcuts (Ctrl/Cmd+C/V/X, Shift+Insert, Ctrl+Insert, Shift+Delete)
69
+ * - native DOM clipboard/drag events (mouse, right-click, browser edit menu)
70
+ * - command palette clipboard actions (async-clipboard path that skips DOM events)
71
+ *
72
+ * @note `disabled` is expected to be fixed at mount.
73
+ */
74
+ var useMonacoClipboardGuard = function useMonacoClipboardGuard(monaco, disabled) {
75
+ var deps = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : EMPTY_DEPS;
76
+ React.useEffect(function () {
77
+ var editor = monaco.current;
78
+ if (!disabled || !editor) {
79
+ return;
80
+ }
81
+ // 1. neutralize clipboard keyboard shortcuts.
82
+ BLOCKED_KEYBINDINGS.forEach(function (keybinding) {
83
+ return editor.addCommand(keybinding, noop);
84
+ });
85
+ // 2. neutralize clipboard actions reachable from the command palette.
86
+ BLOCKED_ACTIONS.forEach(function (_ref) {
87
+ var id = _ref.id,
88
+ label = _ref.label;
89
+ return editor.addAction({
90
+ id: id,
91
+ label: label,
92
+ run: noop
93
+ });
94
+ });
95
+ // 3. block native clipboard/drag DOM events at the editor container.
96
+ var node = editor.getContainerDomNode();
97
+ var blockEvent = function blockEvent(event) {
98
+ event.preventDefault();
99
+ event.stopPropagation();
100
+ };
101
+ var blockBeforeInput = function blockBeforeInput(event) {
102
+ if (BLOCKED_INPUT_TYPES.includes(event.inputType)) {
103
+ event.preventDefault();
104
+ event.stopPropagation();
105
+ }
106
+ };
107
+ BLOCKED_DOM_EVENTS.forEach(function (type) {
108
+ return node.addEventListener(type, blockEvent, true);
109
+ });
110
+ node.addEventListener('beforeinput', blockBeforeInput, true);
111
+ return function () {
112
+ BLOCKED_DOM_EVENTS.forEach(function (type) {
113
+ return node.removeEventListener(type, blockEvent, true);
114
+ });
115
+ node.removeEventListener('beforeinput', blockBeforeInput, true);
116
+ };
117
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps
118
+ [monaco, disabled].concat(_rollupPluginBabelHelpers.toConsumableArray(deps)));
119
+ };
120
+
121
+ exports.useMonacoClipboardGuard = useMonacoClipboardGuard;
@@ -1,7 +1,7 @@
1
1
  import type monaco from 'monaco-editor/esm/vs/editor/editor.api';
2
2
  import type { MonacoEditorProps } from '../MonacoEditor';
3
3
  export type EditorOptions = Parameters<monaco.editor.IStandaloneCodeEditor['updateOptions']>[0];
4
- export type UseEditorOptionsProps = Required<Pick<MonacoEditorProps, 'width' | 'height' | 'preference' | 'noLanguageIntellisense'>>;
4
+ export type UseEditorOptionsProps = Required<Pick<MonacoEditorProps, 'width' | 'height' | 'preference' | 'noLanguageIntellisense' | 'disableClipboard'>>;
5
5
  /**
6
6
  * Hook to get editor options from props.
7
7
  */
@@ -67,7 +67,12 @@ var getEditorOptions = function getEditorOptions(props) {
67
67
  wordBasedSuggestions: true,
68
68
  wordBasedSuggestionsOnlySameLanguage: true,
69
69
  // etc
70
- automaticLayout: props.width === '100%' || props.height === '100%'
70
+ automaticLayout: props.width === '100%' || props.height === '100%',
71
+ // exam: disable clipboard-related affordances.
72
+ // right-click menu, text drag&drop, and linux middle-click (primary selection) paste.
73
+ contextmenu: !props.disableClipboard,
74
+ dragAndDrop: !props.disableClipboard,
75
+ selectionClipboard: !props.disableClipboard
71
76
  });
72
77
  };
73
78
  /**
@@ -29,6 +29,7 @@ import { checkExerciseFileResettable } from '../../../utils/exerciseFile.js';
29
29
  */
30
30
  var ExerciseFileEditor = function ExerciseFileEditor(_ref) {
31
31
  var __intl = _ref.__intl;
32
+ var _a, _b, _c;
32
33
  var _React$useContext = React.useContext(ExerciseContext),
33
34
  materialExerciseId = _React$useContext.materialExerciseId,
34
35
  exerciseRoomId = _React$useContext.exerciseRoomId,
@@ -42,6 +43,8 @@ var ExerciseFileEditor = function ExerciseFileEditor(_ref) {
42
43
  var preference = useRecoilValue(exerciseEditorPreferenceState);
43
44
  var activeFilename = useRecoilValue(exerciseActiveFilenameState);
44
45
  var readOnly = readOnlyEditor || readOnlyActiveFile;
46
+ // Block clipboard when the lecture's cheat config requires it (server-driven).
47
+ var disableClipboard = (_c = (_b = (_a = lecture === null || lecture === void 0 ? void 0 : lecture.cheatInfo) === null || _a === void 0 ? void 0 : _a.detectionInfo) === null || _b === void 0 ? void 0 : _b.isCopyAndPasteBlocked) !== null && _c !== void 0 ? _c : false;
45
48
  var setUsercodeWebSocketState = useSetRecoilState(exerciseWebsocketQuery('usercodeEdit'));
46
49
  var _React$useState = React.useState(null),
47
50
  _React$useState2 = _slicedToArray(_React$useState, 2),
@@ -456,6 +459,7 @@ var ExerciseFileEditor = function ExerciseFileEditor(_ref) {
456
459
  preference: Object.assign(Object.assign({}, preference), {
457
460
  readOnly: readOnly
458
461
  }),
462
+ disableClipboard: disableClipboard,
459
463
  noLanguageIntellisense: (lecture === null || lecture === void 0 ? void 0 : lecture.lectureType) === enums.LectureType.Test,
460
464
  locale: locale,
461
465
  ref: editorApis,
@@ -61,6 +61,11 @@ export interface MonacoEditorProps {
61
61
  height?: React.CSSProperties['height'];
62
62
  /** Disable intellisense of editor. */
63
63
  noLanguageIntellisense?: boolean;
64
+ /**
65
+ * Block copy/cut/paste via keyboard, mouse (right-click), drag&drop and
66
+ * command palette. For exam environment. Expected to be fixed at mount.
67
+ */
68
+ disableClipboard?: boolean;
64
69
  /** Locale of editor. */
65
70
  locale?: string;
66
71
  /** On editor initialized. */
@@ -10,6 +10,7 @@ import { useEditorOptions } from './hooks/useEditorOptions.js';
10
10
  import { getLanguageFromFilename } from './utils/monacoLanguage.js';
11
11
  import { cssRemoteMarker } from './vendors/monaco-collab-ext/styles.js';
12
12
  import { useMonacoOptions } from './editor-hooks/useMonacoOptions.js';
13
+ import { useMonacoClipboardGuard } from './editor-hooks/useMonacoClipboardGuard.js';
13
14
  import { useMonacoTheme } from './editor-hooks/useMonacoTheme.js';
14
15
  import { DEFAULT_MONACO_EDITOR_PREFERENCE } from './constants/monaco/preferences.js';
15
16
  import { useMonacoEventChange } from './editor-hooks/useMonacoEventChange.js';
@@ -58,6 +59,8 @@ var MonacoEditor = forwardRef(function (_ref, ref) {
58
59
  height = _ref$height === void 0 ? '100%' : _ref$height,
59
60
  _ref$noLanguageIntell = _ref.noLanguageIntellisense,
60
61
  noLanguageIntellisense = _ref$noLanguageIntell === void 0 ? false : _ref$noLanguageIntell,
62
+ _ref$disableClipboard = _ref.disableClipboard,
63
+ disableClipboard = _ref$disableClipboard === void 0 ? false : _ref$disableClipboard,
61
64
  onLoad = _ref.onLoad,
62
65
  onChange = _ref.onChange,
63
66
  onSave = _ref.onSave,
@@ -75,7 +78,8 @@ var MonacoEditor = forwardRef(function (_ref, ref) {
75
78
  width: width,
76
79
  height: height,
77
80
  preference: preference,
78
- noLanguageIntellisense: noLanguageIntellisense
81
+ noLanguageIntellisense: noLanguageIntellisense,
82
+ disableClipboard: disableClipboard
79
83
  });
80
84
  /** Ref for preventing change event. */
81
85
  var suppress = React.useRef(false);
@@ -264,6 +268,7 @@ var MonacoEditor = forwardRef(function (_ref, ref) {
264
268
  // Editor hooks.
265
269
  //
266
270
  useMonacoOptions(editor, editorOptions);
271
+ useMonacoClipboardGuard(editor, disableClipboard, [isReady]);
267
272
  useMonacoTheme(preference.theme, onThemeChange);
268
273
  useMonacoEventChange(editor, onChange, suppress, [isReady]);
269
274
  useMonacoEventCursor(editor, onCursor, [isReady]);
@@ -1,3 +1,4 @@
1
+ export * from './useMonacoClipboardGuard';
1
2
  export * from './useMonacoEventChange';
2
3
  export * from './useMonacoEventCursor';
3
4
  export * from './useMonacoEventScroll';
@@ -1,3 +1,4 @@
1
+ export { useMonacoClipboardGuard } from './useMonacoClipboardGuard.js';
1
2
  export { useMonacoEventChange } from './useMonacoEventChange.js';
2
3
  export { useMonacoEventCursor } from './useMonacoEventCursor.js';
3
4
  export { useMonacoEventScroll } from './useMonacoEventScroll.js';
@@ -0,0 +1,15 @@
1
+ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
2
+ import type React from 'react';
3
+ type Monaco = React.MutableRefObject<monaco.editor.IStandaloneCodeEditor | null>;
4
+ /**
5
+ * Hook for blocking copy/cut/paste of monaco editor in exam environment.
6
+ *
7
+ * Blocks every entry point:
8
+ * - keyboard shortcuts (Ctrl/Cmd+C/V/X, Shift+Insert, Ctrl+Insert, Shift+Delete)
9
+ * - native DOM clipboard/drag events (mouse, right-click, browser edit menu)
10
+ * - command palette clipboard actions (async-clipboard path that skips DOM events)
11
+ *
12
+ * @note `disabled` is expected to be fixed at mount.
13
+ */
14
+ export declare const useMonacoClipboardGuard: (monaco: Monaco, disabled: boolean, deps?: unknown[]) => void;
15
+ export {};
@@ -0,0 +1,99 @@
1
+ import { toConsumableArray as _toConsumableArray } from '../../../../_virtual/_rollupPluginBabelHelpers.js';
2
+ import { useEffect } from 'react';
3
+ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
4
+
5
+ var EMPTY_DEPS = [];
6
+ /** Keyboard shortcuts that copy/cut/paste, neutralized in exam environment. */
7
+ var BLOCKED_KEYBINDINGS = [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyC,
8
+ // copy
9
+ monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyX,
10
+ // cut
11
+ monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyV,
12
+ // paste
13
+ monaco.KeyMod.CtrlCmd | monaco.KeyCode.Insert,
14
+ // copy (win)
15
+ monaco.KeyMod.Shift | monaco.KeyCode.Insert,
16
+ // paste (win)
17
+ monaco.KeyMod.Shift | monaco.KeyCode.Delete // cut (win)
18
+ ];
19
+ /**
20
+ * Built-in clipboard actions reachable from the command palette. These run
21
+ * through the async-clipboard path which bypasses the native DOM events below,
22
+ * so they must be neutralized separately (re-registering the same id overrides
23
+ * the built-in action for this editor instance).
24
+ */
25
+ var BLOCKED_ACTIONS = [{
26
+ id: 'editor.action.clipboardCopyAction',
27
+ label: 'Copy'
28
+ }, {
29
+ id: 'editor.action.clipboardCutAction',
30
+ label: 'Cut'
31
+ }, {
32
+ id: 'editor.action.clipboardPasteAction',
33
+ label: 'Paste'
34
+ }];
35
+ /** Native DOM events fired through the editor's hidden textarea. */
36
+ var BLOCKED_DOM_EVENTS = ['copy', 'cut', 'paste', 'contextmenu', 'dragstart', 'drop'];
37
+ /** `beforeinput` types that smuggle clipboard/drag content into the editor. */
38
+ var BLOCKED_INPUT_TYPES = ['insertFromPaste', 'insertFromDrop', 'deleteByCut'];
39
+ var noop = function noop() {
40
+ // intentionally do nothing.
41
+ };
42
+ /**
43
+ * Hook for blocking copy/cut/paste of monaco editor in exam environment.
44
+ *
45
+ * Blocks every entry point:
46
+ * - keyboard shortcuts (Ctrl/Cmd+C/V/X, Shift+Insert, Ctrl+Insert, Shift+Delete)
47
+ * - native DOM clipboard/drag events (mouse, right-click, browser edit menu)
48
+ * - command palette clipboard actions (async-clipboard path that skips DOM events)
49
+ *
50
+ * @note `disabled` is expected to be fixed at mount.
51
+ */
52
+ var useMonacoClipboardGuard = function useMonacoClipboardGuard(monaco, disabled) {
53
+ var deps = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : EMPTY_DEPS;
54
+ useEffect(function () {
55
+ var editor = monaco.current;
56
+ if (!disabled || !editor) {
57
+ return;
58
+ }
59
+ // 1. neutralize clipboard keyboard shortcuts.
60
+ BLOCKED_KEYBINDINGS.forEach(function (keybinding) {
61
+ return editor.addCommand(keybinding, noop);
62
+ });
63
+ // 2. neutralize clipboard actions reachable from the command palette.
64
+ BLOCKED_ACTIONS.forEach(function (_ref) {
65
+ var id = _ref.id,
66
+ label = _ref.label;
67
+ return editor.addAction({
68
+ id: id,
69
+ label: label,
70
+ run: noop
71
+ });
72
+ });
73
+ // 3. block native clipboard/drag DOM events at the editor container.
74
+ var node = editor.getContainerDomNode();
75
+ var blockEvent = function blockEvent(event) {
76
+ event.preventDefault();
77
+ event.stopPropagation();
78
+ };
79
+ var blockBeforeInput = function blockBeforeInput(event) {
80
+ if (BLOCKED_INPUT_TYPES.includes(event.inputType)) {
81
+ event.preventDefault();
82
+ event.stopPropagation();
83
+ }
84
+ };
85
+ BLOCKED_DOM_EVENTS.forEach(function (type) {
86
+ return node.addEventListener(type, blockEvent, true);
87
+ });
88
+ node.addEventListener('beforeinput', blockBeforeInput, true);
89
+ return function () {
90
+ BLOCKED_DOM_EVENTS.forEach(function (type) {
91
+ return node.removeEventListener(type, blockEvent, true);
92
+ });
93
+ node.removeEventListener('beforeinput', blockBeforeInput, true);
94
+ };
95
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps
96
+ [monaco, disabled].concat(_toConsumableArray(deps)));
97
+ };
98
+
99
+ export { useMonacoClipboardGuard };
@@ -1,7 +1,7 @@
1
1
  import type monaco from 'monaco-editor/esm/vs/editor/editor.api';
2
2
  import type { MonacoEditorProps } from '../MonacoEditor';
3
3
  export type EditorOptions = Parameters<monaco.editor.IStandaloneCodeEditor['updateOptions']>[0];
4
- export type UseEditorOptionsProps = Required<Pick<MonacoEditorProps, 'width' | 'height' | 'preference' | 'noLanguageIntellisense'>>;
4
+ export type UseEditorOptionsProps = Required<Pick<MonacoEditorProps, 'width' | 'height' | 'preference' | 'noLanguageIntellisense' | 'disableClipboard'>>;
5
5
  /**
6
6
  * Hook to get editor options from props.
7
7
  */
@@ -65,7 +65,12 @@ var getEditorOptions = function getEditorOptions(props) {
65
65
  wordBasedSuggestions: true,
66
66
  wordBasedSuggestionsOnlySameLanguage: true,
67
67
  // etc
68
- automaticLayout: props.width === '100%' || props.height === '100%'
68
+ automaticLayout: props.width === '100%' || props.height === '100%',
69
+ // exam: disable clipboard-related affordances.
70
+ // right-click menu, text drag&drop, and linux middle-click (primary selection) paste.
71
+ contextmenu: !props.disableClipboard,
72
+ dragAndDrop: !props.disableClipboard,
73
+ selectionClipboard: !props.disableClipboard
69
74
  });
70
75
  };
71
76
  /**
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@elice/material-exercise",
3
- "version": "1.260529.0",
3
+ "version": "1.260608.0",
4
4
  "description": "User view and editing components of Elice material exercise",
5
- "repository": "https://git.elicer.io/elice/frontend/library/elice-material",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://git.elicer.io/elice/frontend/library/elice-material"
8
+ },
6
9
  "license": "UNLICENSED",
7
10
  "main": "./cjs/index.js",
8
11
  "module": "./es/index.js",
@@ -39,8 +42,8 @@
39
42
  "overlay-kit": "^1.8.0",
40
43
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
41
44
  "react-use": "^17.0.0",
42
- "@elice/material-shared-types": "1.260529.0",
43
- "@elice/material-shared-utils": "1.260529.0"
45
+ "@elice/material-shared-types": "1.260608.0",
46
+ "@elice/material-shared-utils": "1.260608.0"
44
47
  },
45
48
  "dependencies": {
46
49
  "@novnc/novnc": "^1.3.0",
@@ -80,7 +83,7 @@
80
83
  "@elice/mui-elements": "5.251204.0",
81
84
  "@elice/mui-system": "5.251204.0",
82
85
  "@elice/rollup-config": "^1.260406.0",
83
- "@elice/types": "1.260527.0",
86
+ "@elice/types": "1.260608.0",
84
87
  "@elice/utils": "^1.250930.0",
85
88
  "@elice/websocket": "^1.220815.0",
86
89
  "@emotion/babel-plugin": "^11.13.5",
@@ -115,8 +118,8 @@
115
118
  "rollup": "^4.0.0",
116
119
  "typescript": "~5.9.3",
117
120
  "vite": "^4.4.9",
118
- "@elice/material-shared-types": "1.260529.0",
119
- "@elice/material-shared-utils": "1.260529.0"
121
+ "@elice/material-shared-types": "1.260608.0",
122
+ "@elice/material-shared-utils": "1.260608.0"
120
123
  },
121
124
  "scripts": {
122
125
  "start": "run-s watch",