mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-08 07:21:02 -04:00
restore recipe on refresh
This commit is contained in:
parent
21ed26e104
commit
4a07d52230
11 changed files with 215 additions and 217 deletions
|
@ -792,13 +792,12 @@ class App {
|
||||||
* Fires whenever the input or recipe changes in any way.
|
* Fires whenever the input or recipe changes in any way.
|
||||||
*
|
*
|
||||||
* @listens Manager#statechange
|
* @listens Manager#statechange
|
||||||
* @param {Event} e
|
|
||||||
*/
|
*/
|
||||||
stateChange(e) {
|
stateChange() {
|
||||||
debounce(function() {
|
debounce(() => {
|
||||||
this.progress = 0;
|
this.progress = 0;
|
||||||
this.autoBake();
|
this.autoBake();
|
||||||
this.updateURL(true, null, true);
|
this.updateURL(true);
|
||||||
}, 20, "stateChange", this, [])();
|
}, 20, "stateChange", this, [])();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -905,7 +904,7 @@ class App {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fires Manager#oplistcreate from nested c-category-li > c-operation-list build() function
|
* Build a CCategoryList element and append it to #categories
|
||||||
*/
|
*/
|
||||||
buildCategoryList() {
|
buildCategoryList() {
|
||||||
// double-check if the c-category-list already exists,
|
// double-check if the c-category-list already exists,
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
/**
|
|
||||||
* @author n1474335 [n1474335@gmail.com]
|
|
||||||
* @copyright Crown Copyright 2016
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object to handle the creation of operation categories.
|
|
||||||
*/
|
|
||||||
class HTMLCategory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTMLCategory constructor.
|
|
||||||
*
|
|
||||||
* @param {string} name - The name of the category.
|
|
||||||
* @param {boolean} selected - Whether this category is pre-selected or not.
|
|
||||||
*/
|
|
||||||
constructor(name, selected) {
|
|
||||||
this.name = name;
|
|
||||||
this.selected = selected;
|
|
||||||
this.opList = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an operation to this category.
|
|
||||||
*
|
|
||||||
* @param {HTMLOperation} operation - The operation to add.
|
|
||||||
*/
|
|
||||||
addOperation(operation) {
|
|
||||||
this.opList.push(operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the category and all operations within it in HTML.
|
|
||||||
*
|
|
||||||
* @returns {HTMLElement}
|
|
||||||
*/
|
|
||||||
toHtml() {
|
|
||||||
const catName = "cat" + this.name.replace(/[\s/\-:_]/g, "");
|
|
||||||
|
|
||||||
let html = `<div class="panel category">
|
|
||||||
<a class="category-title" data-toggle="collapse" data-target="#${catName}">
|
|
||||||
${this.name}
|
|
||||||
</a>
|
|
||||||
<div id="${catName}" class="panel-collapse collapse ${this.selected && "show"}" data-parent="#categories">
|
|
||||||
<ul class="op-list">`;
|
|
||||||
|
|
||||||
for (let i = 0; i < this.opList.length; i++) {
|
|
||||||
html += this.opList[i].toStubHtml();
|
|
||||||
}
|
|
||||||
|
|
||||||
html += "</ul></div></div>";
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HTMLCategory;
|
|
|
@ -8,6 +8,9 @@ import Utils from "../core/Utils.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object to handle the creation of operation ingredients.
|
* Object to handle the creation of operation ingredients.
|
||||||
|
*
|
||||||
|
* @TODO: would be nice to refactor this. Move everything to c-ingredient-li and
|
||||||
|
* implement there accordingly, delete this file
|
||||||
*/
|
*/
|
||||||
class HTMLIngredient {
|
class HTMLIngredient {
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,6 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import HTMLIngredient from "./HTMLIngredient.mjs";
|
|
||||||
import Utils from "../core/Utils.mjs";
|
|
||||||
import url from "url";
|
|
||||||
import {COperationLi} from "./components/c-operation-li.mjs";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object to handle the creation of operations.
|
* Object to handle the creation of operations.
|
||||||
*/
|
*/
|
||||||
|
@ -32,36 +26,6 @@ class HTMLOperation {
|
||||||
this.infoURL = config.infoURL;
|
this.infoURL = config.infoURL;
|
||||||
this.manualBake = config.manualBake || false;
|
this.manualBake = config.manualBake || false;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.ingList = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < config.args.length; i++) {
|
|
||||||
const ing = new HTMLIngredient(config.args[i], this.app, this.manager);
|
|
||||||
this.ingList.push(ing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the operation in HTML as a full operation with ingredients.
|
|
||||||
*
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
toFullHtml() {
|
|
||||||
let html = `<div class="op-title">${Utils.escapeHtml(this.name)}</div>
|
|
||||||
<div class="ingredients">`;
|
|
||||||
|
|
||||||
for (let i = 0; i < this.ingList.length; i++) {
|
|
||||||
html += this.ingList[i].toHtml();
|
|
||||||
}
|
|
||||||
|
|
||||||
html += `</div>
|
|
||||||
<div class="recip-icons">
|
|
||||||
<i class="material-icons breakpoint" title="Set breakpoint" break="false" data-help-title="Setting breakpoints" data-help="Setting a breakpoint on an operation will cause execution of the Recipe to pause when it reaches that operation.">pause</i>
|
|
||||||
<i class="material-icons disable-icon" title="Disable operation" disabled="false" data-help-title="Disabling operations" data-help="Disabling an operation will prevent it from being executed when the Recipe is baked. Execution will skip over the disabled operation and continue with subsequent operations.">not_interested</i>
|
|
||||||
</div>
|
|
||||||
<div class="clearfix"> </div>`;
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -50,10 +50,6 @@ class Manager {
|
||||||
* @event Manager#operationremove
|
* @event Manager#operationremove
|
||||||
*/
|
*/
|
||||||
this.operationremove = new CustomEvent("operationremove", {bubbles: true});
|
this.operationremove = new CustomEvent("operationremove", {bubbles: true});
|
||||||
/**
|
|
||||||
* @event Manager#oplistcreate
|
|
||||||
*/
|
|
||||||
this.oplistcreate = new CustomEvent("oplistcreate", {bubbles: true});
|
|
||||||
/**
|
/**
|
||||||
* @event Manager#statechange
|
* @event Manager#statechange
|
||||||
*/
|
*/
|
||||||
|
@ -89,7 +85,7 @@ class Manager {
|
||||||
this.input.setupInputWorker();
|
this.input.setupInputWorker();
|
||||||
this.input.addInput(true);
|
this.input.addInput(true);
|
||||||
this.worker.setupChefWorker();
|
this.worker.setupChefWorker();
|
||||||
this.recipe.initialiseOperationDragNDrop();
|
this.recipe.initDragAndDrop();
|
||||||
this.controls.initComponents();
|
this.controls.initComponents();
|
||||||
this.controls.autoBakeChange();
|
this.controls.autoBakeChange();
|
||||||
this.bindings.updateKeybList();
|
this.bindings.updateKeybList();
|
||||||
|
@ -152,7 +148,7 @@ class Manager {
|
||||||
document.getElementById("close-ops-dropdown-icon").addEventListener("click", this.ops.closeOpsDropdown.bind(this.ops));
|
document.getElementById("close-ops-dropdown-icon").addEventListener("click", this.ops.closeOpsDropdown.bind(this.ops));
|
||||||
document.getElementById("save-favourites").addEventListener("click", this.ops.saveFavouritesClick.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));
|
document.getElementById("reset-favourites").addEventListener("click", this.ops.resetFavouritesClick.bind(this.ops));
|
||||||
this.addDynamicListener("li.operation", "operationadd", this.recipe.opAdd, this.recipe);
|
this.addDynamicListener("c-operation-li", "operationadd", this.recipe.opAdd, this.recipe);
|
||||||
|
|
||||||
// Recipe
|
// Recipe
|
||||||
this.addDynamicListener(".arg:not(select)", "input", this.recipe.ingChange, this.recipe);
|
this.addDynamicListener(".arg:not(select)", "input", this.recipe.ingChange, this.recipe);
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
- ignore dropped item outside of rec-list
|
||||||
|
- search-results dropdown
|
||||||
|
|
||||||
|
- reordering recipe list
|
||||||
|
- stupid popovers on deleting favs for instance ( dont always close nicely )
|
||||||
|
|
||||||
|
- UI tests etc.
|
72
src/web/components/c-ingredient-li.mjs
Normal file
72
src/web/components/c-ingredient-li.mjs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import Utils from "../../core/Utils.mjs";
|
||||||
|
import HTMLIngredient from "../HTMLIngredient.mjs";
|
||||||
|
|
||||||
|
export class CIngredientLi extends HTMLElement {
|
||||||
|
constructor(app, name, args) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.app = app;
|
||||||
|
this.name = name;
|
||||||
|
this.args = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
const ing = new HTMLIngredient(args[i], this.app, this.app.manager);
|
||||||
|
this.args.push(ing);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.classList.add("operation");
|
||||||
|
li.setAttribute("data-name", this.name);
|
||||||
|
|
||||||
|
const titleDiv = document.createElement("div");
|
||||||
|
titleDiv.classList.add("op-title");
|
||||||
|
titleDiv.innerText = this.name;
|
||||||
|
|
||||||
|
const ingredientDiv = document.createElement("div");
|
||||||
|
ingredientDiv.classList.add("ingredients");
|
||||||
|
|
||||||
|
li.appendChild(titleDiv);
|
||||||
|
li.appendChild(ingredientDiv)
|
||||||
|
|
||||||
|
for (let i = 0; i < this.args.length; i++) {
|
||||||
|
ingredientDiv.innerHTML += (this.args[i].toHtml());
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconsDiv = document.createElement("div");
|
||||||
|
iconsDiv.classList.add("recipe-icons");
|
||||||
|
|
||||||
|
const breakPointIcon = document.createElement("i");
|
||||||
|
breakPointIcon.classList.add("material-icons");
|
||||||
|
breakPointIcon.classList.add("breakpoint");
|
||||||
|
breakPointIcon.setAttribute("title", "Set breakpoint");
|
||||||
|
breakPointIcon.setAttribute("break", "false");
|
||||||
|
breakPointIcon.setAttribute("data-help-title", "Setting breakpoints");
|
||||||
|
breakPointIcon.setAttribute("data-help", "Setting a breakpoint on an operation will cause execution of the Recipe to pause when it reaches that operation.");
|
||||||
|
breakPointIcon.innerText = "pause";
|
||||||
|
|
||||||
|
const disableIcon = document.createElement("i");
|
||||||
|
disableIcon.classList.add("material-icons");
|
||||||
|
disableIcon.classList.add("disable-icon");
|
||||||
|
disableIcon.setAttribute("title", "Disable operation");
|
||||||
|
disableIcon.setAttribute("disabled", "false");
|
||||||
|
disableIcon.setAttribute("data-help-title", "Disabling operations");
|
||||||
|
disableIcon.setAttribute("data-help", "Disabling an operation will prevent it from being executed when the Recipe is baked. Execution will skip over the disabled operation and continue with subsequent operations.");
|
||||||
|
disableIcon.innerText = "not_interested";
|
||||||
|
|
||||||
|
iconsDiv.appendChild(breakPointIcon);
|
||||||
|
iconsDiv.appendChild(disableIcon);
|
||||||
|
|
||||||
|
const clearfixDiv = document.createElement("div");
|
||||||
|
|
||||||
|
li.appendChild(iconsDiv);
|
||||||
|
li.appendChild(clearfixDiv);
|
||||||
|
|
||||||
|
this.appendChild(li);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("c-ingredient-li", CIngredientLi);
|
|
@ -24,7 +24,6 @@ export class COperationLi extends HTMLElement {
|
||||||
this.includeStarIcon = includeStarIcon;
|
this.includeStarIcon = includeStarIcon;
|
||||||
|
|
||||||
this.config = this.app.operations[name];
|
this.config = this.app.operations[name];
|
||||||
// this.ingList = [];
|
|
||||||
|
|
||||||
this.isFavourite = this.app.isLocalStorageAvailable() && JSON.parse(localStorage.favourites).indexOf(name) >= 0;
|
this.isFavourite = this.app.isLocalStorageAvailable() && JSON.parse(localStorage.favourites).indexOf(name) >= 0;
|
||||||
|
|
||||||
|
@ -37,11 +36,6 @@ export class COperationLi extends HTMLElement {
|
||||||
this.observer = new MutationObserver(this.updateFavourite.bind(this));
|
this.observer = new MutationObserver(this.updateFavourite.bind(this));
|
||||||
this.observer.observe(this.querySelector("li"), { attributes: true });
|
this.observer.observe(this.querySelector("li"), { attributes: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (let i = 0; i < this.config.args.length; i++) {
|
|
||||||
// const ing = new HTMLIngredient(this.config.args[i], this.app, this.manager);
|
|
||||||
// this.ingList.push(ing);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -249,6 +243,15 @@ export class COperationLi extends HTMLElement {
|
||||||
this.querySelector("i.star-icon").innerText = "star_outline";
|
this.querySelector("i.star-icon").innerText = "star_outline";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override native cloneNode method so we can clone c-operation-li properly
|
||||||
|
* with constructor arguments for sortable and cloneable lists
|
||||||
|
*/
|
||||||
|
cloneNode() {
|
||||||
|
const { app, name, icon, includeStarIcon } = this;
|
||||||
|
return new COperationLi( app, name, icon, includeStarIcon );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ export class COperationList extends HTMLElement {
|
||||||
ul.classList.add("op-list");
|
ul.classList.add("op-list");
|
||||||
|
|
||||||
this.opNames.forEach((opName => {
|
this.opNames.forEach((opName => {
|
||||||
const li = new COperationLi(
|
const cOpLi = new COperationLi(
|
||||||
this.app,
|
this.app,
|
||||||
opName,
|
opName,
|
||||||
{
|
{
|
||||||
|
@ -47,10 +47,24 @@ export class COperationList extends HTMLElement {
|
||||||
this.includeStarIcon
|
this.includeStarIcon
|
||||||
);
|
);
|
||||||
|
|
||||||
ul.appendChild(li);
|
ul.appendChild(cOpLi);
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if (this.isSortable) {
|
if (this.isSortable) {
|
||||||
|
this.createSortableList(ul);
|
||||||
|
} else if (!this.app.isMobileView() && this.isCloneable) {
|
||||||
|
this.createCloneableList(ul, "recipe", "rec-list"); // target name and id can be component params if needed to make it reusable
|
||||||
|
}
|
||||||
|
|
||||||
|
this.append(ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a sortable ( not cloneable ) list
|
||||||
|
*
|
||||||
|
* @param { HTMLElement } ul
|
||||||
|
* */
|
||||||
|
createSortableList(ul) {
|
||||||
const sortableList = Sortable.create(ul, {
|
const sortableList = Sortable.create(ul, {
|
||||||
group: "sorting",
|
group: "sorting",
|
||||||
sort: true,
|
sort: true,
|
||||||
|
@ -63,24 +77,60 @@ export class COperationList extends HTMLElement {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onEnd: function(e) {
|
onEnd: function(e) {
|
||||||
if (this.removeIntent) {
|
if (this.app.manager.recipe.removeIntent) {
|
||||||
$(e.item).popover("dispose");
|
$(e.item).popover("dispose");
|
||||||
e.item.remove();
|
e.item.remove();
|
||||||
}
|
}
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
});
|
});
|
||||||
} else if (!this.app.isMobileView() && this.isCloneable) {
|
|
||||||
const cloneableList = Sortable.create(ul, {
|
|
||||||
group: {
|
|
||||||
name: "recipe",
|
|
||||||
pull: "clone",
|
|
||||||
},
|
|
||||||
draggable: "c-operation-li",
|
|
||||||
sort: false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.append(ul);
|
/**
|
||||||
|
* Create a cloneable ( not sortable ) list
|
||||||
|
*
|
||||||
|
* @param { HTMLElement } ul
|
||||||
|
* @param { string } targetListName
|
||||||
|
* @param { string } targetListId
|
||||||
|
* */
|
||||||
|
createCloneableList(ul, targetListName, targetListId) {
|
||||||
|
Sortable.create(ul, {
|
||||||
|
group: {
|
||||||
|
name: targetListName,
|
||||||
|
pull: "clone",
|
||||||
|
put: false,
|
||||||
|
},
|
||||||
|
draggable: "c-operation-li",
|
||||||
|
sort: false,
|
||||||
|
setData: function(dataTransfer, dragEl) {
|
||||||
|
dataTransfer.setData("Text", dragEl.querySelector("li").getAttribute("data-name"));
|
||||||
|
},
|
||||||
|
onStart: function(e) {
|
||||||
|
// Removes popover element and event bindings from the dragged operation but not the
|
||||||
|
// event bindings from the one left in the operations list. Without manually removing
|
||||||
|
// these bindings, we cannot re-initialise the popover on the stub operation.
|
||||||
|
$(e.item)
|
||||||
|
.popover("dispose")
|
||||||
|
.removeData("bs.popover")
|
||||||
|
.off("mouseenter")
|
||||||
|
.off("mouseleave")
|
||||||
|
.attr("data-toggle", "popover-disabled");
|
||||||
|
$(e.clone)
|
||||||
|
.off(".popover")
|
||||||
|
.removeData("bs.popover");
|
||||||
|
},
|
||||||
|
// @todo: popovers dont display anymore after dragging into recipe list and then hovering the op
|
||||||
|
onEnd: ({item}) => {
|
||||||
|
if (item.parentNode.id === targetListId) {
|
||||||
|
this.app.manager.recipe.addOperation(item.name);
|
||||||
|
item.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.parentNode.id !== targetListId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
border-top: none;
|
border-top: none;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
cursor: pointer;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (min-width: 768px){
|
@media only screen and (min-width: 768px){
|
||||||
|
@ -272,14 +272,14 @@ input.toggle-string {
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.recip-icons {
|
.recipe-icons {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 13px;
|
top: 13px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.recip-icons i {
|
.recipe-icons i {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
float: right;
|
float: right;
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HTMLOperation from "../HTMLOperation.mjs";
|
||||||
import Sortable from "sortablejs";
|
import Sortable from "sortablejs";
|
||||||
import Utils from "../../core/Utils.mjs";
|
import Utils from "../../core/Utils.mjs";
|
||||||
import {escapeControlChars} from "../utils/editorUtils.mjs";
|
import {escapeControlChars} from "../utils/editorUtils.mjs";
|
||||||
|
import {CIngredientLi} from "../components/c-ingredient-li.mjs";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,30 +32,30 @@ class RecipeWaiter {
|
||||||
/**
|
/**
|
||||||
* Sets up the drag and drop capability for operations in the operations and recipe areas.
|
* Sets up the drag and drop capability for operations in the operations and recipe areas.
|
||||||
*/
|
*/
|
||||||
initialiseOperationDragNDrop() {
|
initDragAndDrop() {
|
||||||
const recList = document.getElementById("rec-list");
|
const recList = document.getElementById("rec-list");
|
||||||
const isMobileView = this.app.isMobileView();
|
|
||||||
|
|
||||||
// Recipe list
|
// Recipe list
|
||||||
Sortable.create(recList, {
|
Sortable.create(recList, {
|
||||||
group: "recipe",
|
group: "recipe",
|
||||||
sort: true,
|
sort: true,
|
||||||
swapThreshold: isMobileView ? 0.60 : 0.3,
|
draggable: "c-ingredient-li",
|
||||||
animation: isMobileView ? 400 : 200,
|
swapThreshold: this.app.isMobileView ? 0.60 : 0.3,
|
||||||
delay: isMobileView ? 200 : 0,
|
animation: this.app.isMobileView ? 400 : 200,
|
||||||
|
delay: this.app.isMobileView ? 200 : 0,
|
||||||
filter: ".arg",
|
filter: ".arg",
|
||||||
preventOnFilter: false,
|
preventOnFilter: false,
|
||||||
setData: function(dataTransfer, dragEl) {
|
setData: function(dataTransfer, dragEl) {
|
||||||
dataTransfer.setData("Text", dragEl.getAttribute("data-name"));
|
dataTransfer.setData("Text", dragEl.querySelector("li").getAttribute("data-name"));
|
||||||
},
|
},
|
||||||
onEnd: function(evt) {
|
onEnd: function(e) {
|
||||||
if (this.removeIntent) {
|
if (this.removeIntent) {
|
||||||
evt.item.remove();
|
e.item.remove();
|
||||||
evt.target.dispatchEvent(this.manager.operationremove);
|
e.target.dispatchEvent(this.manager.operationremove);
|
||||||
}
|
}
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
onSort: function(evt) {
|
onSort: function(e) {
|
||||||
if (evt.from.id === "rec-list") {
|
if (e.from.id === "rec-list") {
|
||||||
document.dispatchEvent(this.manager.statechange);
|
document.dispatchEvent(this.manager.statechange);
|
||||||
}
|
}
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
|
@ -83,42 +84,6 @@ class RecipeWaiter {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a drag-n-droppable seed list of operations.
|
|
||||||
*
|
|
||||||
* @param {element} listEl - The list to initialise
|
|
||||||
*/
|
|
||||||
createSortableSeedList(listEl) {
|
|
||||||
Sortable.create(listEl, {
|
|
||||||
group: {
|
|
||||||
name: "recipe",
|
|
||||||
pull: "clone",
|
|
||||||
put: false,
|
|
||||||
},
|
|
||||||
draggable: ".operation",
|
|
||||||
sort: false,
|
|
||||||
setData: function(dataTransfer, dragEl) {
|
|
||||||
dataTransfer.setData("Text", dragEl.getAttribute("data-name"));
|
|
||||||
},
|
|
||||||
onStart: function(evt) {
|
|
||||||
// Removes popover element and event bindings from the dragged operation but not the
|
|
||||||
// event bindings from the one left in the operations list. Without manually removing
|
|
||||||
// these bindings, we cannot re-initialise the popover on the stub operation.
|
|
||||||
$(evt.item)
|
|
||||||
.popover("dispose")
|
|
||||||
.removeData("bs.popover")
|
|
||||||
.off("mouseenter")
|
|
||||||
.off("mouseleave")
|
|
||||||
.attr("data-toggle", "popover-disabled");
|
|
||||||
$(evt.clone)
|
|
||||||
.off(".popover")
|
|
||||||
.removeData("bs.popover");
|
|
||||||
},
|
|
||||||
onEnd: this.opSortEnd.bind(this)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for operation sort end events.
|
* Handler for operation sort end events.
|
||||||
* Removes the operation from the list if it has been dropped outside. If not, adds it to the list
|
* Removes the operation from the list if it has been dropped outside. If not, adds it to the list
|
||||||
|
@ -128,6 +93,7 @@ class RecipeWaiter {
|
||||||
* @param {Event} evt
|
* @param {Event} evt
|
||||||
*/
|
*/
|
||||||
opSortEnd(evt) {
|
opSortEnd(evt) {
|
||||||
|
console.log(evt);
|
||||||
if (this.removeIntent && evt.item.parentNode.id === "rec-list") {
|
if (this.removeIntent && evt.item.parentNode.id === "rec-list") {
|
||||||
evt.item.remove();
|
evt.item.remove();
|
||||||
return;
|
return;
|
||||||
|
@ -135,21 +101,22 @@ class RecipeWaiter {
|
||||||
|
|
||||||
// Reinitialise the popover on the original element in the ops list because for some reason it
|
// Reinitialise the popover on the original element in the ops list because for some reason it
|
||||||
// gets destroyed and recreated. If the clone isn't in the ops list, we use the original item instead.
|
// gets destroyed and recreated. If the clone isn't in the ops list, we use the original item instead.
|
||||||
let enableOpsElement;
|
// let enableOpsElement;
|
||||||
if (evt.clone?.parentNode?.classList?.contains("op-list")) {
|
// if (evt.clone?.parentNode?.classList?.contains("op-list")) {
|
||||||
enableOpsElement = evt.clone;
|
// enableOpsElement = evt.clone;
|
||||||
} else {
|
// } else {
|
||||||
enableOpsElement = evt.item;
|
// enableOpsElement = evt.item;
|
||||||
$(evt.item).attr("data-toggle", "popover");
|
// $(evt.item).attr("data-toggle", "popover");
|
||||||
}
|
// }
|
||||||
this.manager.ops.enableOpPopover(enableOpsElement);
|
|
||||||
|
// this.manager.ops.enableOpPopover(enableOpsElement);
|
||||||
|
|
||||||
if (evt.item.parentNode.id !== "rec-list") {
|
if (evt.item.parentNode.id !== "rec-list") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buildRecipeOperation(evt.item);
|
this.buildRecipeOperation(evt.item.name);
|
||||||
evt.item.dispatchEvent(this.manager.operationadd);
|
// evt.item.dispatchEvent(this.manager.operationadd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -369,15 +336,13 @@ class RecipeWaiter {
|
||||||
* Given an operation stub element, this function converts it into a full recipe element with
|
* Given an operation stub element, this function converts it into a full recipe element with
|
||||||
* arguments.
|
* arguments.
|
||||||
*
|
*
|
||||||
* @param {element} el - The operation stub element from the operations pane
|
* @param {string} name - The operation stub element from the operations pane
|
||||||
*/
|
*/
|
||||||
buildRecipeOperation(el) {
|
buildRecipeOperation(name) {
|
||||||
const opName = el.textContent;
|
const op = new CIngredientLi(this.app, name, this.app.operations[name].args);
|
||||||
const op = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
|
|
||||||
el.innerHTML = op.toFullHtml();
|
|
||||||
|
|
||||||
if (this.app.operations[opName].flowControl) {
|
if (this.app.operations[name].flowControl) {
|
||||||
el.classList.add("flow-control-op");
|
op.classList.add("flow-control-op");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable auto-bake if this is a manual op
|
// Disable auto-bake if this is a manual op
|
||||||
|
@ -385,6 +350,8 @@ class RecipeWaiter {
|
||||||
this.manager.controls.setAutoBake(false);
|
this.manager.controls.setAutoBake(false);
|
||||||
this.app.alert("Auto-Bake is disabled by default when using this operation.", 5000);
|
this.app.alert("Auto-Bake is disabled by default when using this operation.", 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -392,24 +359,19 @@ class RecipeWaiter {
|
||||||
* Adds the specified operation to the recipe
|
* Adds the specified operation to the recipe
|
||||||
*
|
*
|
||||||
* @fires Manager#operationadd
|
* @fires Manager#operationadd
|
||||||
|
* @fires Manager#statechange
|
||||||
* @param {string} name - The name of the operation to add
|
* @param {string} name - The name of the operation to add
|
||||||
* @returns {element}
|
|
||||||
*/
|
*/
|
||||||
addOperation(name) {
|
addOperation(name) {
|
||||||
const item = document.createElement("li");
|
let item = this.buildRecipeOperation(name);
|
||||||
item.setAttribute("data-name", name);
|
|
||||||
|
|
||||||
item.classList.add("operation");
|
|
||||||
item.innerText = name;
|
|
||||||
this.buildRecipeOperation(item);
|
|
||||||
document.getElementById("rec-list").appendChild(item);
|
document.getElementById("rec-list").appendChild(item);
|
||||||
|
|
||||||
$(item).find("[data-toggle='tooltip']").tooltip();
|
$(item).find("[data-toggle='tooltip']").tooltip();
|
||||||
|
|
||||||
item.dispatchEvent(this.manager.operationadd);
|
item.dispatchEvent(this.manager.operationadd);
|
||||||
|
document.dispatchEvent(this.app.manager.statechange);
|
||||||
|
|
||||||
this.manager.ops.updateListItemsClasses("#rec-list", "selected");
|
this.manager.ops.updateListItemsClasses("#rec-list", "selected");
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,7 +433,9 @@ class RecipeWaiter {
|
||||||
* @param {Event} e
|
* @param {Event} e
|
||||||
*/
|
*/
|
||||||
opAdd(e) {
|
opAdd(e) {
|
||||||
log.debug(`'${e.target.getAttribute("data-name")}' added to recipe`);
|
console.log(e);
|
||||||
|
log.debug(`'${e.target.querySelector("li").getAttribute("data-name")}' added to recipe`);
|
||||||
|
console.log(e.target.querySelector("li").getAttribute("data-name"));
|
||||||
this.triggerArgEvents(e.target);
|
this.triggerArgEvents(e.target);
|
||||||
window.dispatchEvent(this.manager.statechange);
|
window.dispatchEvent(this.manager.statechange);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue