Migrate code and utilize api/modifiers endpoint
This commit is contained in:
365
handlers/playground-script.js
Normal file
365
handlers/playground-script.js
Normal file
@@ -0,0 +1,365 @@
|
||||
// Export button
|
||||
// TODO: Parse JSON to YAML
|
||||
// TODO: Download YAML
|
||||
// Injection scripts
|
||||
// TODO: Javascript syntax highlighting within textarea layout, styling and event listeners
|
||||
// TODO: Textarea handlers and logic for javascript (e.g. tab, newline)
|
||||
// TODO: Javascript escaping/unescaping as required
|
||||
// TODO: remove tailwind play cdn script in head of playground.html after syntax highlighting work complete
|
||||
// Ninja Keys improvements
|
||||
// TODO: Group related items for Ninja Keys
|
||||
// TODO: Untoggle related items that may be toggled (e.g. should only have one masquerade as bot toggled)
|
||||
// Testing
|
||||
// TODO: Testing
|
||||
|
||||
const modifierContainer = document.getElementById("modifierContainer");
|
||||
const modalContainer = document.getElementById("modalContainer");
|
||||
const modalBody = document.getElementById("modal-body");
|
||||
const modalContent = document.getElementById("modal-content");
|
||||
const modalSubmitButton = document.getElementById("modal-submit");
|
||||
const modalClose = document.getElementById("modal-close");
|
||||
|
||||
let hasFetched = false;
|
||||
let payload = {
|
||||
requestmodifications: [],
|
||||
responsemodifications: [],
|
||||
};
|
||||
let ninjaData = [];
|
||||
|
||||
initialize();
|
||||
|
||||
// Rerun handleThemeChange() so style is applied to Ninja Keys
|
||||
handleThemeChange();
|
||||
|
||||
// Add event listener to the iframe so it closes dropdown when clicked
|
||||
closeDropdownOnClickWithinIframe();
|
||||
|
||||
async function initialize() {
|
||||
if (!hasFetched) {
|
||||
try {
|
||||
await fetchPayload();
|
||||
hasFetched = true;
|
||||
} catch (error) {
|
||||
console.error("Fetch error:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closeDropdownOnClickWithinIframe() {
|
||||
const iframe = document.getElementById("resultIframe");
|
||||
iframe.contentWindow.document.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
if (
|
||||
!document.getElementById("dropdown_panel").classList.contains("hidden")
|
||||
) {
|
||||
toggleDropdown();
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
async function fetchPayload() {
|
||||
try {
|
||||
const response = await fetch("/api/modifiers");
|
||||
const data = await response.json();
|
||||
|
||||
Object.entries(data.result.requestmodifiers ?? {}).forEach(([_, value]) => {
|
||||
addModifierToNinjaData(
|
||||
value.name,
|
||||
value.description,
|
||||
value.params,
|
||||
"requestmodifications"
|
||||
);
|
||||
});
|
||||
|
||||
Object.entries(data.result.responsemodifiers ?? {}).forEach(
|
||||
([_, value]) => {
|
||||
addModifierToNinjaData(
|
||||
value.name,
|
||||
value.description,
|
||||
value.params,
|
||||
"responsemodifications"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Fetch error:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function submitForm() {
|
||||
if (!document.getElementById("inputForm").checkValidity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch("/playground/" + inputField.value, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Request failed");
|
||||
}
|
||||
|
||||
const result = await response.text();
|
||||
updateResultIframe(result);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function updateResultIframe(result) {
|
||||
const resultIframe = parent.document.getElementById("resultIframe");
|
||||
resultIframe.contentDocument.open();
|
||||
resultIframe.contentDocument.write(result);
|
||||
closeDropdownOnClickWithinIframe();
|
||||
resultIframe.contentDocument.close();
|
||||
}
|
||||
|
||||
document.getElementById("inputForm").addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
submitForm();
|
||||
});
|
||||
|
||||
if (navigator.userAgent.includes("Mac")) {
|
||||
document.getElementById("ninjaKey").innerHTML = "⌘";
|
||||
} else {
|
||||
document.getElementById("ninjaKey").innerHTML = "Ctrl";
|
||||
}
|
||||
|
||||
function downloadYaml() {
|
||||
function parseYaml() {
|
||||
//* PARSE PAYLOAD TO YAML
|
||||
return payload;
|
||||
}
|
||||
|
||||
const yamlData = parseYaml();
|
||||
const blob = new Blob([yamlData], { type: "text/yaml;charset=utf-8" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
//* CONSTRUCT FILENAME FROM HOSTNAME
|
||||
link.download = `name_of_report.yaml`;
|
||||
link.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
function getValues(id, description, params) {
|
||||
const focusTrap = trap(modalBody);
|
||||
let values = [];
|
||||
const inputs = [];
|
||||
const inputEventListeners = [];
|
||||
|
||||
function closeModal() {
|
||||
focusTrap.destroy();
|
||||
modalBody.removeEventListener("keydown", handleEscapeKey);
|
||||
modalBody.removeEventListener("keydown", handleEnterKey);
|
||||
modalContainer.removeEventListener("click", handleClickOutside);
|
||||
modalSubmitButton.removeEventListener("click", closeModal);
|
||||
modalClose.removeEventListener("click", closeModal);
|
||||
inputEventListeners.forEach((listener, index) => {
|
||||
inputs[index].removeEventListener("input", listener);
|
||||
});
|
||||
inputEventListeners.length = 0;
|
||||
inputs.length = 0;
|
||||
values = [];
|
||||
modalContainer.classList.add("hidden");
|
||||
modalContent.innerHTML = "";
|
||||
}
|
||||
|
||||
function handleClickOutside(e) {
|
||||
if (modalBody !== null && !modalBody.contains(e.target)) {
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
|
||||
function handleEscapeKey(e) {
|
||||
if (e.key === "Escape") {
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
|
||||
function handleEnterKey(e) {
|
||||
if (e.key === "Enter") {
|
||||
if (e.target.tagName.toLowerCase() === "textarea") {
|
||||
return;
|
||||
} else {
|
||||
modalSubmitButton.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("modal-title").innerHTML = id;
|
||||
document.getElementById("modal-description").innerHTML = description;
|
||||
|
||||
params.map((param, i) => {
|
||||
function textareaEventListener(event) {
|
||||
codeElement = document.querySelector("code");
|
||||
codeElement.innerText = event.target.value;
|
||||
Prism.highlightElement(codeElement);
|
||||
values[i] = "|" + " " + event.target.value;
|
||||
}
|
||||
function inputEventListener(event) {
|
||||
values[i] = event.target.value;
|
||||
}
|
||||
|
||||
const label = document.createElement("label");
|
||||
label.innerHTML = param.name;
|
||||
label.setAttribute("for", `input-${i}`);
|
||||
let input;
|
||||
if (param.name === "js") {
|
||||
input = document.createElement("textarea");
|
||||
input.type = "textarea";
|
||||
input.classList.add(
|
||||
"min-h-[200px]",
|
||||
"font-mono",
|
||||
"whitespace-break-spaces",
|
||||
"font-semibold"
|
||||
);
|
||||
} else {
|
||||
input = document.createElement("input");
|
||||
input.type = "text";
|
||||
}
|
||||
input.id = `input-${i}`;
|
||||
input.classList.add(
|
||||
"w-full",
|
||||
"text-sm",
|
||||
"leading-6",
|
||||
"text-slate-400",
|
||||
"rounded-md",
|
||||
"ring-1",
|
||||
"ring-slate-900/10",
|
||||
"shadow-sm",
|
||||
"py-1.5",
|
||||
"pl-2",
|
||||
"pr-3",
|
||||
"hover:ring-slate-300",
|
||||
"dark:bg-slate-800",
|
||||
"dark:highlight-white/5"
|
||||
);
|
||||
modalContent.appendChild(label);
|
||||
modalContent.appendChild(input);
|
||||
if (input.type === "textarea") {
|
||||
preElement = document.createElement("pre");
|
||||
codeElement = document.createElement("code");
|
||||
preElement.setAttribute("aria-hidden", "true");
|
||||
preElement.setAttribute("tabindex", "-1");
|
||||
codeElement.classList.add("language-javascript");
|
||||
preElement.appendChild(codeElement);
|
||||
modalContent.appendChild(preElement);
|
||||
input.addEventListener("input", textareaEventListener);
|
||||
inputEventListeners.push(textareaEventListener);
|
||||
} else {
|
||||
input.addEventListener("input", inputEventListener);
|
||||
inputEventListeners.push(inputEventListener);
|
||||
}
|
||||
inputs.push(input);
|
||||
});
|
||||
|
||||
modalContainer.classList.remove("hidden");
|
||||
document.getElementById("input-0").focus();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
modalBody.addEventListener("keydown", handleEscapeKey);
|
||||
modalBody.addEventListener("keydown", handleEnterKey);
|
||||
modalContainer.addEventListener("click", handleClickOutside);
|
||||
modalClose.addEventListener("click", () => {
|
||||
closeModal();
|
||||
});
|
||||
modalSubmitButton.addEventListener("click", () => {
|
||||
resolve(values);
|
||||
closeModal();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function toggleModifier(type, id, params = []) {
|
||||
function pillClickHandler(pill) {
|
||||
toggleModifier(pill.getAttribute("type"), pill.id);
|
||||
pill.removeEventListener("click", () => pillClickHandler(pill));
|
||||
pill.remove();
|
||||
}
|
||||
|
||||
function createPill(type, id) {
|
||||
const pill = document.createElement("span");
|
||||
pill.classList.add(
|
||||
"inline-flex",
|
||||
"items-center",
|
||||
"rounded-md",
|
||||
"bg-slate-100",
|
||||
"dark:bg-slate-800",
|
||||
"px-2",
|
||||
"py-1",
|
||||
"h-4",
|
||||
"text-xs",
|
||||
"font-medium",
|
||||
"border",
|
||||
"border-slate-400",
|
||||
"dark:border-slate-700",
|
||||
"cursor-pointer"
|
||||
);
|
||||
pill.id = id;
|
||||
pill.setAttribute("type", type);
|
||||
pill.textContent = id;
|
||||
modifierContainer.appendChild(pill);
|
||||
pill.addEventListener("click", () => pillClickHandler(pill));
|
||||
}
|
||||
|
||||
if (payload[type].some((modifier) => modifier.name === id)) {
|
||||
payload[type] = payload[type].filter((modifier) => modifier.name !== id);
|
||||
const existingPill = document.getElementById(id);
|
||||
if (existingPill !== null) {
|
||||
existingPill.removeEventListener("click", () => pillClickHandler(pill));
|
||||
existingPill.remove();
|
||||
}
|
||||
} else {
|
||||
payload[type].push({ name: id, params: params });
|
||||
createPill(type, id);
|
||||
}
|
||||
|
||||
submitForm();
|
||||
}
|
||||
|
||||
function addModifierToNinjaData(id, description, params, type) {
|
||||
const section =
|
||||
type === "requestmodifications"
|
||||
? "Request Modifiers"
|
||||
: "Response Modifiers";
|
||||
const modifier = {
|
||||
id: id,
|
||||
title: id,
|
||||
section: section,
|
||||
|
||||
handler: () => {
|
||||
if (Object.keys(params).length === 0) {
|
||||
toggleModifier(type, id);
|
||||
} else {
|
||||
if (params[0].name === "_") {
|
||||
toggleModifier(type, id, (params = [""]));
|
||||
} else {
|
||||
getValues(id, description, params).then((values) => {
|
||||
if (Object.keys(values).length === 0) return;
|
||||
toggleModifier(type, id, values);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
ninjaData.push(modifier);
|
||||
}
|
||||
|
||||
const ninja = document.querySelector("ninja-keys");
|
||||
ninja.data = ninjaData;
|
||||
document.getElementById("btnNinja").addEventListener("click", () => {
|
||||
ninja.open();
|
||||
});
|
||||
Reference in New Issue
Block a user