Skip to content

Commit

Permalink
Merge pull request #162 from DigiKlausur/authoring_toolbar
Browse files Browse the repository at this point in the history
Authoring toolbar
  • Loading branch information
tmetzl authored Sep 1, 2023
2 parents f193007 + c615801 commit 87499af
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 62 deletions.
4 changes: 3 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/notebook-extensions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"@e2xgrader/restricted-assignment-notebook": "0.1.1",
"@e2xgrader/restricted-exam-notebook": "0.1.1",
"@e2xgrader/exam-menubar": "0.1.1",
"@e2xgrader/authoring-menubar": "0.1.1"
"@e2xgrader/authoring-menubar": "0.1.1",
"@e2xgrader/utils": "0.1.1"
},
"devDependencies": {
"@babel/preset-env": "^7.16.11",
Expand Down
19 changes: 19 additions & 0 deletions packages/notebook-extensions/src/teacher-extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@ import events from "base/js/events";
import { initialize_cell_extension } from "@e2xgrader/cell-extension";
import { CreateAssignmentToolbar } from "@e2xgrader/create-assignment-celltoolbar";
import { TaskMenubar, TemplateMenubar } from "@e2xgrader/authoring-menubar";
import { shortcuts, utils } from "@e2xgrader/utils";

export function remove_empty_cells() {
let to_remove = [];
for (const [index, cell] of Jupyter.notebook.get_cells().entries()) {
if (
!utils.is_nbgrader(cell) &&
cell.get_text().trim().length === 0 &&
Object.keys(cell.attachments).length === 0
) {
to_remove.push(index);
}
}
Jupyter.notebook.delete_cells(to_remove);
}

function is_taskbook() {
let metadata = Jupyter.notebook.metadata;
Expand Down Expand Up @@ -35,9 +50,13 @@ function initialize() {
if (is_taskbook()) {
celltoolbar.activate();
new TaskMenubar().activate();
shortcuts.disable_add_cell_on_execute();
events.on("before_save.Notebook", remove_empty_cells);
} else if (is_templatebook()) {
celltoolbar.activate();
new TemplateMenubar().activate();
shortcuts.disable_add_cell_on_execute();
events.on("before_save.Notebook", remove_empty_cells);
}
}

Expand Down
70 changes: 11 additions & 59 deletions packages/restricted-exam-notebook/src/disable-shortcuts.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Jupyter from "base/js/namespace";
import { shortcuts as utils } from "@e2xgrader/utils";

export function disable_shortcuts() {
const shortcuts = [
Expand All @@ -12,72 +12,24 @@ export function disable_shortcuts() {
"y",
"m",
"r",
"shift-enter",
"alt-enter",
"ctrl-shift-f",
"ctrl-shift-p",
"p",
"d,d",
];

for (let i in shortcuts) {
try {
Jupyter.keyboard_manager.command_shortcuts.remove_shortcut(shortcuts[i]);
Jupyter.keyboard_manager.edit_shortcuts.remove_shortcut(shortcuts[i]);
} catch (e) {
// Shortcut does not exist
}
}
utils.remove_shortcuts("command", shortcuts);
utils.remove_shortcuts("edit", shortcuts);

try {
Jupyter.keyboard_manager.command_shortcuts.remove_shortcut("ctrl-v");
} catch (e) {
console.log("Command shortcut " + "ctrl-v" + " does not exist.");
}
utils.remove_shortcuts("command", "crtl-v");

// Bind all execute cell shortcuts to run cell

Jupyter.keyboard_manager.command_shortcuts.add_shortcut("alt-enter", {
help: "run cell",
help_index: "zz",
handler: function (event) {
IPython.notebook.execute_cell();
return false;
},
});

Jupyter.keyboard_manager.command_shortcuts.add_shortcut("shift-enter", {
help: "run cell",
help_index: "zz",
handler: function (event) {
IPython.notebook.execute_cell();
return false;
},
});

Jupyter.keyboard_manager.edit_shortcuts.add_shortcut("alt-enter", {
help: "run cell",
help_index: "zz",
handler: function (event) {
IPython.notebook.execute_cell();
return false;
},
});

Jupyter.keyboard_manager.edit_shortcuts.add_shortcut("shift-enter", {
help: "run cell",
help_index: "zz",
handler: function (event) {
IPython.notebook.execute_cell();
return false;
},
});

Jupyter.keyboard_manager.command_shortcuts.add_shortcut("ctrl-v", {
help: "no action",
help_index: "zz",
handler: function (event) {
utils.disable_add_cell_on_execute();
utils.add_shortcut(
"command",
"ctrl-v",
function (event) {
return false;
},
});
"no action"
);
}
1 change: 1 addition & 0 deletions packages/utils/src/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * as utils from "./utils";
export * as shortcuts from "./shortcuts";
99 changes: 99 additions & 0 deletions packages/utils/src/shortcuts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import Jupyter from "base/js/namespace";
import { Notebook } from "notebook/js/notebook";

/**
* Defines a new method `execute_cell_and_select_below_without_insert()` for the `Notebook` prototype object,
* which executes the currently selected cell and then selects the cell below it.
*/
function add_Notebook_execute_cell_and_select() {
Notebook.prototype.execute_cell_and_select_below_without_insert =
function () {
let indices = this.get_selected_cells_indices();
let cell_index;
if (indices.length > 1) {
this.execute_cells(indices);
cell_index = Math.max(...indices);
} else {
let cell = this.get_selected_cell();
cell_index = this.find_cell_index(cell);
cell.execute();
}

// If we are at the end do not insert a new cell
cell_index = Math.min(cell_index + 1, this.ncells() - 1);
this.select(cell_index);
this.focus_cell();
};
}

/**
* Returns the keyboard manager object for the specified mode.
* @param {string} mode - The keyboard manager mode to get ("command" or "edit").
* @throws {Error} If the mode is not "command" or "edit".
* @returns {object} The keyboard manager object for the specified mode.
*/
function get_manager(mode) {
if (mode === "command") {
return Jupyter.keyboard_manager.command_shortcuts;
} else if (mode === "edit") {
return Jupyter.keyboard_manager.edit_shortcuts;
} else {
throw new Error("Mode needs to be either 'command' or 'edit'");
}
}

/**
* Removes the specified shortcuts from the keyboard manager for the specified mode.
* @param {string} mode - The keyboard manager mode to remove shortcuts from ("command" or "edit").
* @param {...string} shortcuts - The shortcut keys to remove.
*/
export function remove_shortcuts(mode, ...shortcuts) {
const manager = get_manager(mode);
for (const shortcut of shortcuts) {
try {
manager.remove_shortcut(shortcut);
} catch (e) {
// Shortcut does not exist and can't be removed;
}
}
}

/**
* Adds a new shortcut to the keyboard manager for the specified mode.
* @param {string} mode - The keyboard manager mode to add the shortcut to ("command" or "edit").
* @param {string} key - The key combination for the shortcut.
* @param {function} handler - The function to be called when the shortcut is activated.
* @param {string} help - The help text for the shortcut.
* @param {string} [help_index="zz"] - The help index for the shortcut.
*/
export function add_shortcut(mode, key, handler, help, help_index = "zz") {
const manager = get_manager(mode);
manager.add_shortcut(key, {
help: help,
help_index: help_index,
handler: handler,
});
}

/**
* Disables the default behavior of adding a new cell after executing a cell by removing the "alt-enter" and "shift-enter"
* shortcuts for both the command and edit modes, and adding new shortcuts that execute the current cell and select
* the cell below it using the `execute_cell_and_select_below_without_insert()` method.
*/
export function disable_add_cell_on_execute() {
add_Notebook_execute_cell_and_select();
const shortcut_keys = ["alt-enter", "shift-enter"];
remove_shortcuts("edit", shortcut_keys);
remove_shortcuts("command", shortcut_keys);

const help = "run cell";
const handler = function (event) {
Jupyter.notebook.execute_cell_and_select_below_without_insert();
return false;
};

for (const key of shortcut_keys) {
add_shortcut("edit", key, handler, help);
add_shortcut("command", key, handler, help);
}
}
2 changes: 1 addition & 1 deletion packages/utils/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = {
filename: "[name].js",
libraryTarget: "commonjs-module",
},
externals: {},
externals: [/^base\/js*/, /^notebook\/js*/],
optimization: {
minimize: false,
},
Expand Down

0 comments on commit 87499af

Please sign in to comment.