[#181] update README, run / fix lint

This commit is contained in:
Robin Scholtes 2023-05-10 21:53:29 +12:00
parent 997f26e4f8
commit a7a76ec7ef
10 changed files with 72 additions and 70 deletions

View file

@ -27,7 +27,7 @@ There are four main areas in CyberChef:
1. The **input** box in the top right, where you can paste, type or drag the text or file you want to operate on. 1. The **input** box in the top right, where you can paste, type or drag the text or file you want to operate on.
2. The **output** box in the bottom right, where the outcome of your processing will be displayed. 2. The **output** box in the bottom right, where the outcome of your processing will be displayed.
3. The **operations** list on the far left, where you can find all the operations that CyberChef is capable of in categorised lists, or by searching. 3. The **operations** list on the far left ( or in the dropdown at the top on mobile ), where you can find all the operations that CyberChef is capable of in categorised lists, or by searching.
4. The **recipe** area in the middle, where you can drag the operations that you want to use and specify arguments and options. 4. The **recipe** area in the middle, where you can drag the operations that you want to use and specify arguments and options.
You can use as many operations as you like in simple or complex ways. Some examples are as follows: You can use as many operations as you like in simple or complex ways. Some examples are as follows:
@ -49,6 +49,7 @@ You can use as many operations as you like in simple or complex ways. Some examp
- Drag and drop - Drag and drop
- Operations can be dragged in and out of the recipe list, or reorganised. - Operations can be dragged in and out of the recipe list, or reorganised.
- Files up to 2GB can be dragged over the input box to load them directly into the browser. - Files up to 2GB can be dragged over the input box to load them directly into the browser.
- On mobile devices, double-click the operations to add them to the recipe list.
- Auto Bake - Auto Bake
- Whenever you modify the input or the recipe, CyberChef will automatically "bake" for you and produce the output immediately. - Whenever you modify the input or the recipe, CyberChef will automatically "bake" for you and produce the output immediately.
- This can be turned off and operated manually if it is affecting performance (if the input is very large, for instance). - This can be turned off and operated manually if it is affecting performance (if the input is very large, for instance).

View file

@ -298,7 +298,7 @@ class App {
* @param {boolean} [minimise=false] - Set this flag if attempting to minimise frames to 0 width * @param {boolean} [minimise=false] - Set this flag if attempting to minimise frames to 0 width
*/ */
initialiseUI() { initialiseUI() {
if ( window.innerWidth < this.breakpoint ){ if (window.innerWidth < this.breakpoint) {
this.setMobileUI(); this.setMobileUI();
} else { } else {
this.setDesktopUI(false); this.setDesktopUI(false);
@ -308,7 +308,7 @@ class App {
/** /**
* Set desktop splitters * Set desktop splitters
*/ */
setDesktopSplitter(minimise){ setDesktopSplitter(minimise) {
if (this.columnSplitter) this.columnSplitter.destroy(); if (this.columnSplitter) this.columnSplitter.destroy();
if (this.ioSplitter) this.ioSplitter.destroy(); if (this.ioSplitter) this.ioSplitter.destroy();
@ -864,16 +864,16 @@ class App {
* @param {boolean} isVisible * @param {boolean} isVisible
* *
*/ */
updateVisibility( elm, isVisible ){ updateVisibility(elm, isVisible) {
isVisible ? elm.classList.remove("hidden") : elm.classList.add("hidden"); return isVisible ? elm.classList.remove("hidden") : elm.classList.add("hidden");
}h }
/** /**
* Set desktop UI ( on init and on window resize events ) * Set desktop UI ( on init and on window resize events )
* *
* @param {boolean} minimise * @param {boolean} minimise
*/ */
setDesktopUI(minimise){ setDesktopUI(minimise) {
$("[data-toggle=tooltip]").tooltip("enable"); $("[data-toggle=tooltip]").tooltip("enable");
this.setDesktopSplitter(minimise); this.setDesktopSplitter(minimise);
this.adjustComponentSizes(); this.adjustComponentSizes();
@ -884,7 +884,7 @@ class App {
/** /**
* Set mobile UI ( on init and on window resize events ) * Set mobile UI ( on init and on window resize events )
*/ */
setMobileUI(){ setMobileUI() {
$("[data-toggle=tooltip]").tooltip("disable"); $("[data-toggle=tooltip]").tooltip("disable");
this.setMobileSplitter(); this.setMobileSplitter();
this.assignAvailableHeight(); this.assignAvailableHeight();
@ -901,7 +901,7 @@ class App {
* Be mindful to update these fixed numbers accordingly in the stylesheets * Be mindful to update these fixed numbers accordingly in the stylesheets
* ( themes/_structure ) if you make changes to those elements' height. * ( themes/_structure ) if you make changes to those elements' height.
*/ */
assignAvailableHeight(){ assignAvailableHeight() {
const bannerHeight = 40; const bannerHeight = 40;
const controlsHeight = 50; const controlsHeight = 50;
const operationsHeight = 80; const operationsHeight = 80;
@ -909,7 +909,7 @@ class App {
const remainingSpace = window.innerHeight - (bannerHeight+controlsHeight+operationsHeight - 1); // - 1 is accounting for a border const remainingSpace = window.innerHeight - (bannerHeight+controlsHeight+operationsHeight - 1); // - 1 is accounting for a border
// equally divide among recipe, input and output // equally divide among recipe, input and output
["recipe", "input", "output"].forEach(( div ) => { ["recipe", "input", "output"].forEach((div) => {
document.getElementById(div).style.height = `${remainingSpace/3}px`; document.getElementById(div).style.height = `${remainingSpace/3}px`;
}); });

View file

@ -64,17 +64,17 @@ class HTMLOperation {
if (removeIcon) { if (removeIcon) {
html += "<i class='material-icons remove-icon op-icon'>delete</i>"; html += "<i class='material-icons remove-icon op-icon'>delete</i>";
} else if (!removeIcon && window.innerWidth < this.app.breakpoint ){ } else if (!removeIcon && window.innerWidth < this.app.breakpoint) {
html += "<i class='material-icons check-icon op-icon'>check</i>"; html += "<i class='material-icons check-icon op-icon'>check</i>";
} }
const favourites = JSON.parse(localStorage.favourites); const favourites = JSON.parse(localStorage.favourites);
const isFavourite = favourites.includes(this.name); const isFavourite = favourites.includes(this.name);
if ( window.innerWidth < this.app.breakpoint ){ if (window.innerWidth < this.app.breakpoint) {
html += `<i title="${this.name}" class='material-icons icon-add-favourite star-icon op-icon ${isFavourite ? "fav-op" : ""}'> html += `<i title="${this.name}" class='material-icons icon-add-favourite star-icon op-icon ${isFavourite ? "fav-op" : ""}'>
${isFavourite ? "star" : "star_outline"} ${isFavourite ? "star" : "star_outline"}
</i>` </i>`;
} }
html += "</li>"; html += "</li>";

View file

@ -142,9 +142,9 @@ class Manager {
document.getElementById("support").addEventListener("click", this.controls.supportButtonClick.bind(this.controls)); document.getElementById("support").addEventListener("click", this.controls.supportButtonClick.bind(this.controls));
this.addMultiEventListeners("#save-texts textarea", "keyup paste", this.controls.saveTextChange, this.controls); this.addMultiEventListeners("#save-texts textarea", "keyup paste", this.controls.saveTextChange, this.controls);
// A note for the Maximise Controls listeners below: click events via addDynamicListener don't properly bubble and the hit box to maximise is unacceptably tiny, hence this solution // A note for the Maximise Controls listeners below: click events via addDynamicListener don't properly bubble and the hit box to maximise is unacceptably tiny, hence this solution
document.getElementById("maximise-recipe").addEventListener("click", this.controls.onMaximiseButtonClick.bind(this.controls)) document.getElementById("maximise-recipe").addEventListener("click", this.controls.onMaximiseButtonClick.bind(this.controls));
document.getElementById("maximise-input").addEventListener("click", this.controls.onMaximiseButtonClick.bind(this.controls)) document.getElementById("maximise-input").addEventListener("click", this.controls.onMaximiseButtonClick.bind(this.controls));
document.getElementById("maximise-output").addEventListener("click", this.controls.onMaximiseButtonClick.bind(this.controls)) document.getElementById("maximise-output").addEventListener("click", this.controls.onMaximiseButtonClick.bind(this.controls));
// Operations // Operations
this.addMultiEventListener("#search", "keyup paste search click", this.ops.searchOperations, this.ops); this.addMultiEventListener("#search", "keyup paste search click", this.ops.searchOperations, this.ops);

View file

@ -4,17 +4,14 @@
--- ---
#### Mobile UI ( on real device ): #### Mobile UI ( on real device ):
- shannon entropy thingies
- maybe a bit annoying that the fav cat opens whenever you add a new fav via icon-fav-click on mobile - maybe a bit annoying that the fav cat opens whenever you add a new fav via icon-fav-click on mobile
- backspace on fs view should close max view. Keep making the same mistake and navigating away when for instance recipe is expanded and double click the window to fs > resolve. Reset layout - backspace on fs view should close max view. Keep making the same mistake and navigating away when for instance recipe
- remove tabs on window resizing large to small? is expanded and double click the window to fs > resolve. Reset layout
- drag and drop from op to rec on desktop only working once
### JS: ### JS:
- `core/Recipe.mjs`, `core/lib/Magic.js` return imports to original - `core/Recipe.mjs`, `core/lib/Magic.js` return imports to original
### Misc: ### Misc:
- Gruntfile revert dev config - Gruntfile revert dev config
- Update README instructions per Mobile UI
- delete this file when done :) - delete this file when done :)

View file

@ -292,7 +292,7 @@ class StatusBarPanel {
this.dom.querySelectorAll(".cm-status-bar-select-scroll").forEach( this.dom.querySelectorAll(".cm-status-bar-select-scroll").forEach(
el => { el => {
el.style.maxHeight = window.innerWidth >= 768 ? (viewHeight - 50) + "px" : '250px'; el.style.maxHeight = window.innerWidth >= 768 ? (viewHeight - 50) + "px" : "250px";
} }
); );
} }
@ -476,7 +476,7 @@ function makePanel(opts) {
sbPanel.updateSelection(update.state, update.selectionSet); sbPanel.updateSelection(update.state, update.selectionSet);
sbPanel.updateTiming(); sbPanel.updateTiming();
sbPanel.monitorHTMLOutput(); sbPanel.monitorHTMLOutput();
if ( update.geometryChanged) { if (update.geometryChanged) {
sbPanel.updateSizing(update.view); sbPanel.updateSizing(update.view);
} }
if (update.docChanged) { if (update.docChanged) {

View file

@ -429,8 +429,8 @@ ${navigator.userAgent}
*/ */
onMaximiseButtonClick(e) { onMaximiseButtonClick(e) {
// the target pane is not already maximised because it does not have the 'maximised-pane' class.. // the target pane is not already maximised because it does not have the 'maximised-pane' class..
const maximise = !document.getElementById(e.currentTarget.id.replace('maximise-', '')).classList.contains("maximised-pane"); const maximise = !document.getElementById(e.currentTarget.id.replace("maximise-", "")).classList.contains("maximised-pane");
this.setPaneMaximised(e.currentTarget.id.replace('maximise-', ''), maximise); this.setPaneMaximised(e.currentTarget.id.replace("maximise-", ""), maximise);
} }
/** /**
@ -440,17 +440,17 @@ ${navigator.userAgent}
* @param {string} paneId * @param {string} paneId
* @param {boolean} maximise * @param {boolean} maximise
*/ */
setPaneMaximised( paneId, maximise ){ setPaneMaximised(paneId, maximise) {
const pane = document.getElementById( paneId ); const pane = document.getElementById(paneId);
const btn = document.getElementById( `maximise-${paneId}` ); const btn = document.getElementById(`maximise-${paneId}`);
this.setMaximiseControlButton(btn, maximise); this.setMaximiseControlButton(btn, maximise);
this.setPaneMaximisedClasses(pane, maximise); this.setPaneMaximisedClasses(pane, maximise);
if ( maximise ) { if (maximise) {
pane.style.height = `${window.innerHeight - 40}px`; pane.style.height = `${window.innerHeight - 40}px`;
} else { } else {
if ( window.innerWidth < this.app.breakpoint ){ if (window.innerWidth < this.app.breakpoint) {
this.app.assignAvailableHeight(); this.app.assignAvailableHeight();
} }
} }
@ -463,7 +463,7 @@ ${navigator.userAgent}
* @param {boolean} maximise * @param {boolean} maximise
*/ */
setPaneMaximisedClasses(pane, maximise) { setPaneMaximisedClasses(pane, maximise) {
if ( maximise ) { if (maximise) {
pane.classList.add("top-zindex"); pane.classList.add("top-zindex");
pane.classList.add("maximised-pane"); pane.classList.add("maximised-pane");
} else { } else {
@ -480,8 +480,8 @@ ${navigator.userAgent}
* @param {HTMLElement} btn * @param {HTMLElement} btn
* @param {boolean} maximise * @param {boolean} maximise
*/ */
setMaximiseControlButton(btn, maximise ) { setMaximiseControlButton(btn, maximise) {
if ( maximise ) { if (maximise) {
btn.querySelector("i").innerHTML = "fullscreen_exit"; btn.querySelector("i").innerHTML = "fullscreen_exit";
btn.setAttribute("data-original-title", "Reset pane"); btn.setAttribute("data-original-title", "Reset pane");
} else { } else {

View file

@ -39,13 +39,13 @@ class OperationsWaiter {
searchOperations(e) { searchOperations(e) {
let ops, selected; let ops, selected;
if (e.type === "keyup"){ if (e.type === "keyup") {
const searchResults = document.getElementById("search-results"); const searchResults = document.getElementById("search-results");
this.openOperationsDropdown(); this.openOperationsDropdown();
if ( e.target.value.length !== 0 ){ if (e.target.value.length !== 0) {
this.app.updateVisibility(searchResults, true ); this.app.updateVisibility(searchResults, true);
} }
} }
@ -60,9 +60,9 @@ class OperationsWaiter {
} }
} }
if (e.type === "click" && !e.target.value.length){ if (e.type === "click" && !e.target.value.length) {
this.openOperationsDropdown(); this.openOperationsDropdown();
} else if (e.keyCode === 27 ) { // Escape } else if (e.keyCode === 27) { // Escape
this.closeOperationsDropdown(); this.closeOperationsDropdown();
} else if (e.keyCode === 40) { // Down } else if (e.keyCode === 40) { // Down
e.preventDefault(); e.preventDefault();
@ -184,7 +184,7 @@ class OperationsWaiter {
* @param {event} e * @param {event} e
*/ */
opListCreate(e) { opListCreate(e) {
if ( window.innerWidth < this.app.breakpoint ){ if (window.innerWidth < this.app.breakpoint) {
this.mobileOpListCreate(e); this.mobileOpListCreate(e);
} else { } else {
this.desktopOpListCreate(e); this.desktopOpListCreate(e);
@ -197,7 +197,7 @@ class OperationsWaiter {
* *
* @param {event} e * @param {event} e
*/ */
desktopOpListCreate(e){ desktopOpListCreate(e) {
this.manager.recipe.createSortableSeedList(e.target); this.manager.recipe.createSortableSeedList(e.target);
this.enableOpPopover(e.target); this.enableOpPopover(e.target);
} }
@ -208,7 +208,7 @@ class OperationsWaiter {
* *
* @param {event} e * @param {event} e
*/ */
mobileOpListCreate(e){ mobileOpListCreate(e) {
this.manager.recipe.createSortableSeedList(e.target, false); this.manager.recipe.createSortableSeedList(e.target, false);
this.disableOpsListPopovers(); this.disableOpsListPopovers();
} }
@ -324,7 +324,7 @@ class OperationsWaiter {
/** /**
* Open operations dropdown * Open operations dropdown
*/ */
openOperationsDropdown(){ openOperationsDropdown() {
// the 'close' ( dropdown ) icon in Operations component mobile UI // the 'close' ( dropdown ) icon in Operations component mobile UI
const closeOperationsDropdown = document.getElementById("close-operations-dropdown"); const closeOperationsDropdown = document.getElementById("close-operations-dropdown");
const categories = document.getElementById("categories"); const categories = document.getElementById("categories");
@ -338,12 +338,12 @@ class OperationsWaiter {
* Hide any operation lists ( #categories or #search-results ) and the close-operations-dropdown * Hide any operation lists ( #categories or #search-results ) and the close-operations-dropdown
* icon itself, clear any search input * icon itself, clear any search input
*/ */
closeOperationsDropdown(){ closeOperationsDropdown() {
const search = document.getElementById("search"); const search = document.getElementById("search");
// if any input remains in #search, clear it // if any input remains in #search, clear it
if (search.value.length) { if (search.value.length) {
search.value = ''; search.value = "";
} }
this.app.updateVisibility(document.getElementById("categories"), false); this.app.updateVisibility(document.getElementById("categories"), false);
@ -380,7 +380,7 @@ class OperationsWaiter {
* *
* @param {Event} e * @param {Event} e
*/ */
onIconFavouriteClick(e){ onIconFavouriteClick(e) {
this.app.addFavourite(e.target.getAttribute("title")); this.app.addFavourite(e.target.getAttribute("title"));
} }
} }

View file

@ -595,14 +595,14 @@ class RecipeWaiter {
* This hides all the checkmark icons of previously added ( selected ) * This hides all the checkmark icons of previously added ( selected )
* operations to the recipe list * operations to the recipe list
*/ */
clearAllSelectedClasses(){ clearAllSelectedClasses() {
const list = document.querySelectorAll(".operation.selected"); const list = document.querySelectorAll(".operation.selected");
// check if any operations are selected at all to prevent errors // check if any operations are selected at all to prevent errors
if (list.length){ if (list.length) {
list.forEach((item) => { list.forEach((item) => {
item.classList.remove("selected"); item.classList.remove("selected");
}) });
} }
} }
@ -613,15 +613,15 @@ class RecipeWaiter {
* *
* @param {string} opDataName the data-name of the target operation * @param {string} opDataName the data-name of the target operation
*/ */
addSelectedClass(opDataName){ addSelectedClass(opDataName) {
const list = document.querySelectorAll(".operation"); const list = document.querySelectorAll(".operation");
const item = Array.from(list).filter((item) => item.getAttribute("data-name") === opDataName ); const item = Array.from(list).filter((item) => item.getAttribute("data-name") === opDataName);
// when an item is listed in favourites, there are 2 of // when an item is listed in favourites, there are 2 of
// them and both need the 'selected' class ( checkmark ) // them and both need the 'selected' class ( checkmark )
item.forEach((op) => { item.forEach((op) => {
op.classList.add("selected"); op.classList.add("selected");
}) });
} }
/** /**
@ -636,24 +636,22 @@ class RecipeWaiter {
* code ), I'd recommend to refactor this at one point, but that would mean a huge code * code ), I'd recommend to refactor this at one point, but that would mean a huge code
* overhaul for another time / issue. * overhaul for another time / issue.
*/ */
updateSelectedOperations(){ updateSelectedOperations() {
let recipeList, operations; const recipeList = document.querySelectorAll("#rec-list > li");
const operations = document.querySelectorAll(".operation");
recipeList = document.querySelectorAll("#rec-list > li");
operations = document.querySelectorAll(".operation");
this.clearAllSelectedClasses(); this.clearAllSelectedClasses();
if ( recipeList.length ){ if (recipeList.length) {
recipeList.forEach((ingredient) => { recipeList.forEach((ingredient) => {
const ingredientName = ingredient.getAttribute("data-name"); const ingredientName = ingredient.getAttribute("data-name");
operations.forEach((operation) => { operations.forEach((operation) => {
if ( ingredientName === operation.getAttribute("data-name")){ if (ingredientName === operation.getAttribute("data-name")) {
this.addSelectedClass(ingredientName); this.addSelectedClass(ingredientName);
} }
}) });
}) });
} }
} }
} }

View file

@ -30,7 +30,7 @@ class WindowWaiter {
* continuous resetting). * continuous resetting).
*/ */
windowResize() { windowResize() {
if ( window.innerWidth >= this.app.breakpoint ) { if (window.innerWidth >= this.app.breakpoint) {
this.onResizeToDesktop(); this.onResizeToDesktop();
} else { } else {
this.onResizeToMobile(); this.onResizeToMobile();
@ -38,35 +38,41 @@ class WindowWaiter {
// #output can be maximised on all screen sizes, so if it was open while resizing, // #output can be maximised on all screen sizes, so if it was open while resizing,
// it can be kept maximised until minimised manually // it can be kept maximised until minimised manually
if ( document.getElementById("output").classList.contains("maximised-pane") ) { if (document.getElementById("output").classList.contains("maximised-pane")) {
this.manager.controls.setPaneMaximised( "output", true ); this.manager.controls.setPaneMaximised("output", true);
} }
debounce(this.app.adjustComponentSizes, 200, "windowResize", this.app, [])(); debounce(this.app.adjustComponentSizes, 200, "windowResize", this.app, [])();
} }
onResizeToDesktop(){ /**
* Set desktop UI and close #recipe / #input maximised panes if there were any.
* Correct the height of #recipe
*/
onResizeToDesktop() {
this.app.setDesktopUI(false); this.app.setDesktopUI(false);
// if a window is resized past breakpoint while #recipe or #input is maximised, // if a window is resized past breakpoint while #recipe or #input is maximised,
// the maximised pane is set to its default ( non-maximised ) state // the maximised pane is set to its default ( non-maximised ) state
["recipe", "input"].forEach( paneId => this.manager.controls.setPaneMaximised(paneId, false)); ["recipe", "input"].forEach(paneId => this.manager.controls.setPaneMaximised(paneId, false));
// to prevent #recipe from keeping the height set in divideAvailableSpace // to prevent #recipe from keeping the height set in divideAvailableSpace
document.getElementById("recipe").style.height = "100%"; document.getElementById("recipe").style.height = "100%";
} }
/**
onResizeToMobile(){ * Set mobile UI and close any maximised panes if there were any
*/
onResizeToMobile() {
this.app.setMobileUI(); this.app.setMobileUI();
// when mobile devices' keyboards pop up, it triggers a window resize event. Here // when mobile devices' keyboards pop up, it triggers a window resize event. Here
// we keep the maximised panes open until the minimise button is clicked / tapped // we keep the maximised panes open until the minimise button is clicked / tapped
["recipe", "input", "output"] ["recipe", "input", "output"]
.map( paneId => document.getElementById(paneId)) .map(paneId => document.getElementById(paneId))
.filter( pane => pane.classList.contains("maximised-pane")) .filter(pane => pane.classList.contains("maximised-pane"))
.forEach( pane => this.manager.controls.setPaneMaximised(pane.id, true)); .forEach(pane => this.manager.controls.setPaneMaximised(pane.id, true));
} }