mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-08 23:35:01 -04:00
ccessible user experience
This commit is contained in:
parent
7c66dacc40
commit
eb04145a62
9 changed files with 127 additions and 6 deletions
|
@ -48,7 +48,7 @@
|
|||
"autoprefixer": "^10.4.4",
|
||||
"babel-loader": "^8.2.4",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"chromedriver": "^99.0.0",
|
||||
"chromedriver": "^101.0.0",
|
||||
"cli-progress": "^3.10.0",
|
||||
"colors": "^1.4.0",
|
||||
"copy-webpack-plugin": "^10.2.4",
|
||||
|
|
|
@ -46,7 +46,7 @@ class HTMLOperation {
|
|||
* @returns {string}
|
||||
*/
|
||||
toStubHtml(removeIcon) {
|
||||
let html = "<li class='operation'";
|
||||
let html = `<li class='operation' data-opName="${this.name}"`;
|
||||
|
||||
if (this.description) {
|
||||
const infoLink = this.infoURL ? `<hr>${titleFromWikiLink(this.infoURL)}` : "";
|
||||
|
@ -58,6 +58,12 @@ class HTMLOperation {
|
|||
|
||||
html += ">" + this.name;
|
||||
|
||||
html += `<span class='float-right'>
|
||||
<button type="button" class="btn btn-primary bmd-btn-icon accessibleUX" data-toggle="tooltip" data-original-title="Add to recipe">
|
||||
<i class='material-icons'>add_box</i>
|
||||
</button>
|
||||
</span>`;
|
||||
|
||||
if (removeIcon) {
|
||||
html += "<i class='material-icons remove-icon op-icon'>delete</i>";
|
||||
}
|
||||
|
@ -83,6 +89,9 @@ class HTMLOperation {
|
|||
|
||||
html += `</div>
|
||||
<div class="recip-icons">
|
||||
<i class="material-icons move-down accessibleUX" title="Move down">arrow_downward</i>
|
||||
<i class="material-icons move-up accessibleUX">arrow_upward</i>
|
||||
<i class="material-icons remove-icon accessibleUX" title="Delete operation">delete</i>
|
||||
<i class="material-icons breakpoint" title="Set breakpoint" break="false">pause</i>
|
||||
<i class="material-icons disable-icon" title="Disable operation" disabled="false">not_interested</i>
|
||||
</div>
|
||||
|
|
|
@ -93,6 +93,7 @@ class Manager {
|
|||
this.bindings.updateKeybList();
|
||||
this.background.registerChefWorker();
|
||||
this.seasonal.load();
|
||||
this.options.load();
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,6 +127,7 @@ class Manager {
|
|||
// Operations
|
||||
this.addMultiEventListener("#search", "keyup paste search", this.ops.searchOperations, this.ops);
|
||||
this.addDynamicListener(".op-list li.operation", "dblclick", this.ops.operationDblclick, this.ops);
|
||||
this.addDynamicListener(".op-list li.operation button i", "click", this.ops.operationAdd, 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("reset-favourites").addEventListener("click", this.ops.resetFavouritesClick.bind(this.ops));
|
||||
|
@ -137,6 +139,9 @@ class Manager {
|
|||
this.addDynamicListener(".arg[type=checkbox], .arg[type=radio], select.arg", "change", this.recipe.ingChange, this.recipe);
|
||||
this.addDynamicListener(".disable-icon", "click", this.recipe.disableClick, this.recipe);
|
||||
this.addDynamicListener(".breakpoint", "click", this.recipe.breakpointClick, this.recipe);
|
||||
this.addDynamicListener(".remove-icon", "click", this.recipe.removeClick, this.recipe);
|
||||
this.addDynamicListener(".move-down", "click", this.recipe.moveDownClick, this.recipe);
|
||||
this.addDynamicListener(".move-up", "click", this.recipe.moveUpClick, this.recipe);
|
||||
this.addDynamicListener("#rec-list li.operation", "dblclick", this.recipe.operationDblclick, this.recipe);
|
||||
this.addDynamicListener("#rec-list li.operation > div", "dblclick", this.recipe.operationChildDblclick, this.recipe);
|
||||
this.addDynamicListener("#rec-list .dropdown-menu.toggle-dropdown a", "click", this.recipe.dropdownToggleClick, this.recipe);
|
||||
|
@ -233,6 +238,7 @@ class Manager {
|
|||
document.getElementById("theme").addEventListener("change", this.options.themeChange.bind(this.options));
|
||||
document.getElementById("logLevel").addEventListener("change", this.options.logLevelChange.bind(this.options));
|
||||
document.getElementById("imagePreview").addEventListener("change", this.input.renderFileThumb.bind(this.input));
|
||||
document.getElementById("accessibleUX").addEventListener("change", this.options.uxChange.bind(this.options));
|
||||
|
||||
// Misc
|
||||
window.addEventListener("keydown", this.bindings.parseInput.bind(this.bindings));
|
||||
|
|
|
@ -584,6 +584,13 @@
|
|||
Keep the current tab in sync between the input and output
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox option-item">
|
||||
<label for="accessibleUX">
|
||||
<input type="checkbox" option="accessibleUX" id="accessibleUX">
|
||||
Accessible user experience, buttons for drag-and-drop operations
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" id="reset-options">Reset options to default</button>
|
||||
|
|
|
@ -54,7 +54,8 @@ function main() {
|
|||
autoMagic: true,
|
||||
imagePreview: true,
|
||||
syncTabs: true,
|
||||
preserveCR: "entropy"
|
||||
preserveCR: "entropy",
|
||||
accessibleUX: false
|
||||
};
|
||||
|
||||
document.removeEventListener("DOMContentLoaded", main, false);
|
||||
|
|
|
@ -205,8 +205,21 @@ class OperationsWaiter {
|
|||
*/
|
||||
operationDblclick(e) {
|
||||
const li = e.target;
|
||||
// get operation name from <li> data
|
||||
this.manager.recipe.addOperation($(li).data("opname"));
|
||||
}
|
||||
|
||||
this.manager.recipe.addOperation(li.textContent);
|
||||
/**
|
||||
* Handler for operation add events.
|
||||
* Adds the operation to the recipe and auto bakes.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
operationAdd(e) {
|
||||
log.info("add");
|
||||
const li = e.target.parentNode.parentNode.parentNode;
|
||||
// get operation name from <li> data
|
||||
this.manager.recipe.addOperation($(li).data("opname"));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@ class OptionsWaiter {
|
|||
for (i = 0; i < cboxes.length; i++) {
|
||||
cboxes[i].checked = this.app.options[cboxes[i].getAttribute("option")];
|
||||
}
|
||||
// init ux option - ux is last cbox
|
||||
cboxes[i-1].dispatchEvent(new Event("change"));
|
||||
|
||||
const nboxes = document.querySelectorAll("#options-body input[type=number]");
|
||||
for (i = 0; i < nboxes.length; i++) {
|
||||
|
@ -189,6 +191,18 @@ class OptionsWaiter {
|
|||
this.manager.worker.setLogLevel();
|
||||
this.manager.input.setLogLevel();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes the UX using CSS change so that actions can be managed
|
||||
* regardless of visibility
|
||||
*
|
||||
* @param {Event} e
|
||||
*/
|
||||
uxChange(e) {
|
||||
const checked = $("#accessibleUX").is(":checked");
|
||||
$(".accessibleUX").css("display", checked ? "block" : "none");
|
||||
}
|
||||
}
|
||||
|
||||
export default OptionsWaiter;
|
||||
|
|
|
@ -261,6 +261,43 @@ class RecipeWaiter {
|
|||
window.dispatchEvent(this.manager.statechange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for remove click events.
|
||||
* Removes the operation from the recipe and auto bakes.
|
||||
*
|
||||
* @fires Manager#statechange
|
||||
* @param {event} e
|
||||
*/
|
||||
removeClick(e) {
|
||||
e.target.parentNode.parentNode.remove();
|
||||
this.opRemove(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for remove click events.
|
||||
* Removes the operation from the recipe and auto bakes.
|
||||
*
|
||||
* @fires Manager#statechange
|
||||
* @param {event} e
|
||||
*/
|
||||
moveUpClick(e) {
|
||||
const li = $(e.target.parentNode.parentNode);
|
||||
li.prev().before(li);
|
||||
window.dispatchEvent(this.manager.statechange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for down click events.
|
||||
* Moves the operation in the recipe and auto bakes.
|
||||
*
|
||||
* @fires Manager#statechange
|
||||
* @param {event} e
|
||||
*/
|
||||
moveDownClick(e) {
|
||||
const li = $(e.target.parentNode.parentNode);
|
||||
li.next().after(li);
|
||||
window.dispatchEvent(this.manager.statechange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for operation doubleclick events.
|
||||
|
@ -368,7 +405,7 @@ class RecipeWaiter {
|
|||
* @param {element} el - The operation stub element from the operations pane
|
||||
*/
|
||||
buildRecipeOperation(el) {
|
||||
const opName = el.textContent;
|
||||
const opName = $(el).data('opname');
|
||||
const op = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
|
||||
el.innerHTML = op.toFullHtml();
|
||||
|
||||
|
@ -395,7 +432,7 @@ class RecipeWaiter {
|
|||
const item = document.createElement("li");
|
||||
|
||||
item.classList.add("operation");
|
||||
item.innerHTML = name;
|
||||
$(item).data("opname", name);
|
||||
this.buildRecipeOperation(item);
|
||||
document.getElementById("rec-list").appendChild(item);
|
||||
|
||||
|
|
|
@ -56,6 +56,40 @@ module.exports = {
|
|||
browser.expect.element("//li[contains(@class, 'operation') and text()='Register']").to.be.present;
|
||||
},
|
||||
|
||||
"Accessible user experience": browser => {
|
||||
const addOp = "#catFavourites li.operation";
|
||||
const recOp = "#rec-list li:nth-child(1)";
|
||||
const down = " i.move-down.accessibleUX";
|
||||
const remove = " i.remove-icon.accessibleUX";
|
||||
|
||||
// Switch UX on
|
||||
browser
|
||||
.useCss()
|
||||
.click("#options")
|
||||
.waitForElementVisible("#options-modal", 1000)
|
||||
.click("#reset-options")
|
||||
.pause(500)
|
||||
// Using label for checkbox click because nightwatch thinks #acessibleUX isn't visible
|
||||
.click('label[for="accessibleUX"]')
|
||||
.click("#options-modal .modal-footer button:last-child")
|
||||
.waitForElementNotVisible("#options-modal")
|
||||
.expect.element(addOp).to.be.visible;
|
||||
|
||||
// add Operations & move them
|
||||
browser
|
||||
.useCss()
|
||||
.click(addOp + ":nth-child(1) button")
|
||||
.click(addOp + ":nth-child(2) button")
|
||||
.click(recOp + down)
|
||||
.expect.element(recOp).text.to.contain("From Base64");
|
||||
|
||||
// delete operations
|
||||
browser
|
||||
.click(recOp + remove)
|
||||
.click(recOp + remove)
|
||||
.waitForElementNotPresent(recOp);
|
||||
},
|
||||
|
||||
"Recipe can be run": browser => {
|
||||
const toHex = "//li[contains(@class, 'operation') and text()='To Hex']";
|
||||
const op = "#rec-list .operation .op-title";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue