mirror of https://github.com/gchq/CyberChef.git
Merge 03f5dc62ff
into bbebba6481
This commit is contained in:
commit
68ef0103d4
|
@ -39,7 +39,7 @@ class HTMLCategory {
|
|||
*/
|
||||
toHtml() {
|
||||
const catName = "cat" + this.name.replace(/[\s/\-:_]/g, "");
|
||||
let html = `<div class="panel category">
|
||||
let html = `<div class="panel category" tabIndex="0">
|
||||
<a class="category-title" data-toggle="collapse" data-target="#${catName}">
|
||||
${this.name}
|
||||
</a>
|
||||
|
|
|
@ -46,20 +46,20 @@ class HTMLOperation {
|
|||
* @returns {string}
|
||||
*/
|
||||
toStubHtml(removeIcon) {
|
||||
let html = "<li class='operation'";
|
||||
let html = "<li tabIndex='0' class='operation'";
|
||||
|
||||
if (this.description) {
|
||||
const infoLink = this.infoURL ? `<hr>${titleFromWikiLink(this.infoURL)}` : "";
|
||||
|
||||
html += ` data-container='body' data-toggle='popover' data-placement='right'
|
||||
data-content="${this.description}${infoLink}" data-html='true' data-trigger='hover'
|
||||
data-content="${this.description}${infoLink}" data-html='true' data-trigger='hover focus'
|
||||
data-boundary='viewport'`;
|
||||
}
|
||||
|
||||
html += ">" + this.name;
|
||||
|
||||
if (removeIcon) {
|
||||
html += "<i class='material-icons remove-icon op-icon'>delete</i>";
|
||||
html += "<i class='material-icons remove-icon op-icon' tabindex='0'>delete</i>";
|
||||
}
|
||||
|
||||
html += "</li>";
|
||||
|
|
|
@ -148,6 +148,9 @@ class Manager {
|
|||
this.addDynamicListener(".op-list li.operation", "dblclick", this.ops.operationDblclick, this.ops);
|
||||
document.getElementById("edit-favourites").addEventListener("click", this.ops.editFavouritesClick.bind(this.ops));
|
||||
document.getElementById("save-favourites").addEventListener("click", this.ops.saveFavouritesClick.bind(this.ops));
|
||||
document.getElementById("edit-favourites").addEventListener("keydown", this.ops.editFavouritesKeyPress.bind(this.ops));
|
||||
document.getElementById("categories").addEventListener("keydown", this.ops.onKeyPress.bind(this.ops));
|
||||
this.addDynamicListener(".op-list li.operation", "keydown", this.ops.keyboardPopulateRecipe.bind(this.ops));
|
||||
document.getElementById("reset-favourites").addEventListener("click", this.ops.resetFavouritesClick.bind(this.ops));
|
||||
this.addDynamicListener(".op-list", "oplistcreate", this.ops.opListCreate, this.ops);
|
||||
this.addDynamicListener("li.operation", "operationadd", this.recipe.opAdd, this.recipe);
|
||||
|
|
|
@ -539,7 +539,7 @@
|
|||
<div class="modal-body" id="favourites-body">
|
||||
<ul>
|
||||
<li><span style="font-weight: bold">To add:</span> drag the operation over the favourites category and drop it</li>
|
||||
<li><span style="font-weight: bold">To reorder:</span> drag up and down in the list below</li>
|
||||
<li><span style="font-weight: bold">To reorder:</span> drag up and down in the list below or focus on operation and press Ctrl + Up/Down Arrow to reorder using keyboard</li>
|
||||
<li><span style="font-weight: bold">To remove:</span> hit the delete button or drag out of the list below</li>
|
||||
</ul>
|
||||
<br>
|
||||
|
|
|
@ -8,7 +8,6 @@ import HTMLOperation from "../HTMLOperation.mjs";
|
|||
import Sortable from "sortablejs";
|
||||
import {fuzzyMatch, calcMatchRanges} from "../../core/lib/FuzzyMatch.mjs";
|
||||
|
||||
|
||||
/**
|
||||
* Waiter to handle events related to the operations.
|
||||
*/
|
||||
|
@ -237,9 +236,16 @@ class OperationsWaiter {
|
|||
}
|
||||
|
||||
const editFavouritesList = document.getElementById("edit-favourites-list");
|
||||
const editFavouritesListElements = editFavouritesList.getElementsByTagName("li");
|
||||
editFavouritesList.innerHTML = html;
|
||||
this.removeIntent = false;
|
||||
|
||||
for (let i = 0; i < editFavouritesListElements.length; i++) {
|
||||
editFavouritesListElements[i].setAttribute("tabindex", "0");
|
||||
editFavouritesListElements[i].addEventListener("keydown", this.ArrowNavFavourites.bind(this), false);
|
||||
editFavouritesListElements[i].firstElementChild.addEventListener("keydown", this.deleteFavourite.bind(this), false);
|
||||
}
|
||||
|
||||
const editableList = Sortable.create(editFavouritesList, {
|
||||
filter: ".remove-icon",
|
||||
onFilter: function (evt) {
|
||||
|
@ -270,6 +276,66 @@ class OperationsWaiter {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for navigation key press events.
|
||||
* Navigates through the favourites list and corresponding delete buttons.
|
||||
* Move favourites elements up and down with Ctrl + Arrow keys to imitate drag and drop mouse functionality.
|
||||
*/
|
||||
ArrowNavFavourites(event) {
|
||||
const currentElement = event.target;
|
||||
const nextElement = currentElement.nextElementSibling;
|
||||
const prevElement = currentElement.previousElementSibling;
|
||||
const favouritesList = currentElement.parentNode;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (event.key === "ArrowDown" && !event.ctrlKey) {
|
||||
if (nextElement === null) {
|
||||
currentElement.parentElement.firstElementChild.focus();
|
||||
} else {
|
||||
nextElement.focus();
|
||||
}
|
||||
} else if (event.key === "ArrowUp" && !event.ctrlKey) {
|
||||
if (prevElement === null) {
|
||||
currentElement.parentElement.lastElementChild.focus();
|
||||
} else {
|
||||
prevElement.focus();
|
||||
}
|
||||
} else if (event.key === "Tab") {
|
||||
currentElement.parentElement.closest(".modal-body").nextElementSibling.getElementsByTagName("Button")[0].focus();
|
||||
} else if (event.key === "ArrowRight") {
|
||||
if (currentElement.firstElementChild !== null) {
|
||||
currentElement.firstElementChild.focus();
|
||||
}
|
||||
} else if (event.key === "ArrowLeft" && (currentElement.classList.contains("remove-icon"))) {
|
||||
currentElement.parentElement.focus();
|
||||
} else if (event.ctrlKey && event.key === "ArrowDown") {
|
||||
if (nextElement === null) {
|
||||
favouritesList.insertBefore(currentElement, currentElement.parentElement.firstElementChild);
|
||||
} else {
|
||||
favouritesList.insertBefore(currentElement, nextElement.nextElementSibling);
|
||||
}
|
||||
currentElement.focus();
|
||||
} else if (event.ctrlKey && event.key === "ArrowUp") {
|
||||
favouritesList.insertBefore(currentElement, prevElement);
|
||||
currentElement.focus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for delete favourites keydown events.
|
||||
* delete the selected favourite from the list.
|
||||
*/
|
||||
deleteFavourite(event) {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
const el = event.target;
|
||||
if (el && el.parentNode) {
|
||||
el.parentNode.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for save favourites click events.
|
||||
* Saves the selected favourites and reloads them.
|
||||
|
@ -284,7 +350,6 @@ class OperationsWaiter {
|
|||
this.manager.recipe.initialiseOperationDragNDrop();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for reset favourites click events.
|
||||
* Resets favourites to their defaults.
|
||||
|
@ -293,6 +358,119 @@ class OperationsWaiter {
|
|||
this.app.resetFavourites();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler that allows users to open favourite modal by "Enter/Space".
|
||||
* This codes mimics editFavouritesClick event handler.
|
||||
* @param {Event} ev
|
||||
*/
|
||||
editFavouritesKeyPress(ev) {
|
||||
if (ev.key === "Enter" || ev.key === "Space" || ev.key === " ") {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const favCat = this.app.categories.filter(function (c) {
|
||||
return c.name === "Favourites";
|
||||
})[0];
|
||||
|
||||
let html = "";
|
||||
for (let i = 0; i < favCat.ops.length; i++) {
|
||||
const opName = favCat.ops[i];
|
||||
const operation = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
|
||||
html += operation.toStubHtml(true);
|
||||
}
|
||||
|
||||
const editFavouritesList = document.getElementById("edit-favourites-list");
|
||||
const editFavouritesListElements = editFavouritesList.getElementsByTagName("li");
|
||||
editFavouritesList.innerHTML = html;
|
||||
this.removeIntent = false;
|
||||
|
||||
for (let i = 0; i < editFavouritesListElements.length; i++) {
|
||||
editFavouritesListElements[i].setAttribute("tabindex", "0");
|
||||
editFavouritesListElements[i].addEventListener("keydown", this.ArrowNavFavourites.bind(this), false);
|
||||
editFavouritesListElements[i].firstElementChild.addEventListener("keydown", this.deleteFavourite.bind(this), false);
|
||||
}
|
||||
|
||||
const editableList = Sortable.create(editFavouritesList, {
|
||||
filter: ".remove-icon",
|
||||
onFilter: function (evt) {
|
||||
const el = editableList.closest(evt.item);
|
||||
if (el && el.parentNode) {
|
||||
$(el).popover("dispose");
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
},
|
||||
onEnd: function (evt) {
|
||||
if (this.removeIntent) {
|
||||
$(evt.item).popover("dispose");
|
||||
evt.item.remove();
|
||||
}
|
||||
}.bind(this),
|
||||
});
|
||||
|
||||
$("#edit-favourites-list [data-toggle=popover]").popover();
|
||||
$("#favourites-modal").modal();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for on key press events.
|
||||
* Get the children of categories and add event listener to them.
|
||||
*/
|
||||
onKeyPress() {
|
||||
const cat = document.getElementById("categories");
|
||||
for (let i = 0; i < cat.children.length; i++) {
|
||||
cat.children[i].addEventListener("keydown", this.keyboardEventHandler, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for keyboard enter/space events.
|
||||
* Uses "Enter" or "Space" to mimic the click function and open the operations panels .
|
||||
* @param {Event} ev
|
||||
*/
|
||||
keyboardEventHandler(ev) {
|
||||
if (ev.key === "Enter" || ev.key === "Space" || ev.key === " ") {
|
||||
ev.preventDefault();
|
||||
for (let i = 0; i < ev.target.childNodes.length; i++) {
|
||||
const targetChild = ev.target.childNodes[i].classList;
|
||||
if (targetChild !== undefined && targetChild.value.includes("panel-collapse collapse")) {
|
||||
if (!targetChild.contains("show")) {
|
||||
targetChild.add("show");
|
||||
} else if (targetChild.contains("show")) {
|
||||
targetChild.remove("show");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler to populate recipe.
|
||||
* Get the children of op-list and add event listener to them.
|
||||
*/
|
||||
operationPopulateRecipe() {
|
||||
const cat = document.querySelectorAll(".op-list li.operation");
|
||||
for (let i = 0; i < cat.children.length; i++) {
|
||||
cat.children[i].addEventListener("keydown", this.keyboardPopulateRecipe, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler to add operators to recipe with keyboard.
|
||||
* Uses keyboard shortcut "CTRl + Enter" to mimic operationDblClick handler function
|
||||
* @param {Event} ev
|
||||
*/
|
||||
keyboardPopulateRecipe(ev) {
|
||||
if (ev.ctrlKey && ev.key === "Enter") {
|
||||
const li = ev.target;
|
||||
this.manager.recipe.addOperation(li.textContent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default OperationsWaiter;
|
||||
|
|
Loading…
Reference in New Issue