mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:27:35 +00:00
Base+Ladybird: Move Ladybird-related HTML files to their own folder
Pages like the new tab page, error page, etc. all belong solely to Ladybird, but are scattered across a couple of subfolders in Base. This moves them all to Base/res/ladybird.
This commit is contained in:
parent
980e32b4fe
commit
05c8d5ba57
11 changed files with 12 additions and 12 deletions
375
Base/res/ladybird/inspector.js
Normal file
375
Base/res/ladybird/inspector.js
Normal file
|
@ -0,0 +1,375 @@
|
|||
let selectedTopTab = null;
|
||||
let selectedTopTabButton = null;
|
||||
|
||||
let selectedBottomTab = null;
|
||||
let selectedBottomTabButton = null;
|
||||
|
||||
let selectedDOMNode = null;
|
||||
|
||||
let consoleGroupStack = [];
|
||||
let consoleGroupNextID = 0;
|
||||
|
||||
let consoleHistory = [];
|
||||
let consoleHistoryIndex = 0;
|
||||
|
||||
const beginSplitViewDrag = () => {
|
||||
let inspectorTop = document.getElementById("inspector-top");
|
||||
let inspectorBottom = document.getElementById("inspector-bottom");
|
||||
let inspectorSeparator = document.getElementById("inspector-separator");
|
||||
|
||||
const windowHeight = window.innerHeight;
|
||||
const separatorHeight = inspectorSeparator.clientHeight;
|
||||
|
||||
const updateSplitView = event => {
|
||||
let position = Math.min(event.clientY, windowHeight - separatorHeight);
|
||||
position = Math.max(position, 0);
|
||||
|
||||
inspectorTop.style.height = `${position}px`;
|
||||
inspectorBottom.style.height = `${windowHeight - position - separatorHeight}px`;
|
||||
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
const endSplitViewDrag = () => {
|
||||
document.removeEventListener("mousemove", updateSplitView);
|
||||
document.removeEventListener("mouseup", endSplitViewDrag);
|
||||
document.body.style.cursor = "";
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", updateSplitView);
|
||||
document.addEventListener("mouseup", endSplitViewDrag);
|
||||
document.body.style.cursor = "row-resize";
|
||||
};
|
||||
|
||||
const selectTab = (tabButton, tabID, selectedTab, selectedTabButton) => {
|
||||
let tab = document.getElementById(tabID);
|
||||
|
||||
if (selectedTab === tab) {
|
||||
return selectedTab;
|
||||
}
|
||||
if (selectedTab !== null) {
|
||||
selectedTab.style.display = "none";
|
||||
selectedTabButton.classList.remove("active");
|
||||
}
|
||||
|
||||
tab.style.display = "block";
|
||||
tabButton.classList.add("active");
|
||||
|
||||
return tab;
|
||||
};
|
||||
|
||||
const selectTopTab = (tabButton, tabID) => {
|
||||
selectedTopTab = selectTab(tabButton, tabID, selectedTopTab, selectedTopTabButton);
|
||||
selectedTopTabButton = tabButton;
|
||||
};
|
||||
|
||||
const selectBottomTab = (tabButton, tabID) => {
|
||||
selectedBottomTab = selectTab(tabButton, tabID, selectedBottomTab, selectedBottomTabButton);
|
||||
selectedBottomTabButton = tabButton;
|
||||
};
|
||||
|
||||
let initialTopTabButton = document.getElementById("dom-tree-button");
|
||||
selectTopTab(initialTopTabButton, "dom-tree");
|
||||
|
||||
let initialBottomTabButton = document.getElementById("console-button");
|
||||
selectBottomTab(initialBottomTabButton, "console");
|
||||
|
||||
const scrollToElement = element => {
|
||||
// Include an offset to prevent the element being placed behind the fixed `tab-controls` header.
|
||||
const offset = 45;
|
||||
|
||||
let position = element.getBoundingClientRect().top;
|
||||
position += window.pageYOffset - offset;
|
||||
|
||||
window.scrollTo(0, position);
|
||||
};
|
||||
|
||||
inspector.loadDOMTree = tree => {
|
||||
let domTree = document.getElementById("dom-tree");
|
||||
domTree.innerHTML = atob(tree);
|
||||
|
||||
let domNodes = domTree.querySelectorAll(".hoverable");
|
||||
|
||||
for (let domNode of domNodes) {
|
||||
domNode.addEventListener("click", event => {
|
||||
inspectDOMNode(domNode);
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
domNodes = domTree.querySelectorAll(".editable");
|
||||
|
||||
for (let domNode of domNodes) {
|
||||
domNode.addEventListener("dblclick", event => {
|
||||
editDOMNode(domNode);
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
inspector.loadAccessibilityTree = tree => {
|
||||
let accessibilityTree = document.getElementById("accessibility-tree");
|
||||
accessibilityTree.innerHTML = atob(tree);
|
||||
};
|
||||
|
||||
inspector.inspectDOMNodeID = nodeID => {
|
||||
let domNodes = document.querySelectorAll(`[data-id="${nodeID}"]`);
|
||||
if (domNodes.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let domNode = domNodes[0]; domNode; domNode = domNode.parentNode) {
|
||||
if (domNode.tagName === "DETAILS") {
|
||||
domNode.setAttribute("open", "");
|
||||
}
|
||||
}
|
||||
|
||||
inspectDOMNode(domNodes[0]);
|
||||
scrollToElement(selectedDOMNode);
|
||||
};
|
||||
|
||||
inspector.clearInspectedDOMNode = () => {
|
||||
if (selectedDOMNode !== null) {
|
||||
selectedDOMNode.classList.remove("selected");
|
||||
selectedDOMNode = null;
|
||||
}
|
||||
};
|
||||
|
||||
inspector.createPropertyTables = (computedStyle, resolvedStyle, customProperties) => {
|
||||
const createPropertyTable = (tableID, properties) => {
|
||||
let oldTable = document.getElementById(tableID);
|
||||
|
||||
let newTable = document.createElement("tbody");
|
||||
newTable.setAttribute("id", tableID);
|
||||
|
||||
Object.keys(properties)
|
||||
.sort()
|
||||
.forEach(name => {
|
||||
let row = newTable.insertRow();
|
||||
|
||||
let nameColumn = row.insertCell();
|
||||
nameColumn.innerText = name;
|
||||
|
||||
let valueColumn = row.insertCell();
|
||||
valueColumn.innerText = properties[name];
|
||||
});
|
||||
|
||||
oldTable.parentNode.replaceChild(newTable, oldTable);
|
||||
};
|
||||
|
||||
createPropertyTable("computed-style-table", JSON.parse(computedStyle));
|
||||
createPropertyTable("resolved-style-table", JSON.parse(resolvedStyle));
|
||||
createPropertyTable("custom-properties-table", JSON.parse(customProperties));
|
||||
};
|
||||
|
||||
const inspectDOMNode = domNode => {
|
||||
if (selectedDOMNode === domNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
inspector.clearInspectedDOMNode();
|
||||
|
||||
domNode.classList.add("selected");
|
||||
selectedDOMNode = domNode;
|
||||
|
||||
inspector.inspectDOMNode(domNode.dataset.id, domNode.dataset.pseudoElement);
|
||||
};
|
||||
|
||||
const editDOMNode = domNode => {
|
||||
if (selectedDOMNode === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const domNodeID = selectedDOMNode.dataset.id;
|
||||
const type = domNode.dataset.nodeType;
|
||||
|
||||
selectedDOMNode.classList.remove("selected");
|
||||
|
||||
let input = document.createElement("input");
|
||||
input.classList.add("dom-editor");
|
||||
input.classList.add("selected");
|
||||
input.value = domNode.innerText;
|
||||
|
||||
const handleChange = () => {
|
||||
input.removeEventListener("change", handleChange);
|
||||
input.removeEventListener("blur", cancelChange);
|
||||
|
||||
if (type === "text" || type === "comment") {
|
||||
inspector.setDOMNodeText(domNodeID, input.value);
|
||||
} else if (type === "tag") {
|
||||
try {
|
||||
const element = document.createElement(input.value);
|
||||
inspector.setDOMNodeTag(domNodeID, input.value);
|
||||
} catch {
|
||||
cancelChange();
|
||||
}
|
||||
} else if (type === "attribute") {
|
||||
let element = document.createElement("div");
|
||||
element.innerHTML = `<div ${input.value}></div>`;
|
||||
|
||||
inspector.replaceDOMNodeAttribute(
|
||||
domNodeID,
|
||||
domNode.dataset.attributeName,
|
||||
element.children[0].attributes
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const cancelChange = () => {
|
||||
selectedDOMNode.classList.add("selected");
|
||||
input.parentNode.replaceChild(domNode, input);
|
||||
};
|
||||
|
||||
input.addEventListener("change", handleChange);
|
||||
input.addEventListener("blur", cancelChange);
|
||||
|
||||
domNode.parentNode.replaceChild(input, domNode);
|
||||
|
||||
setTimeout(() => {
|
||||
input.focus();
|
||||
|
||||
// FIXME: Invoke `select` when it isn't just stubbed out.
|
||||
// input.select();
|
||||
});
|
||||
};
|
||||
|
||||
const executeConsoleScript = consoleInput => {
|
||||
const script = consoleInput.value;
|
||||
|
||||
if (!/\S/.test(script)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (consoleHistory.length === 0 || consoleHistory[consoleHistory.length - 1] !== script) {
|
||||
consoleHistory.push(script);
|
||||
}
|
||||
|
||||
consoleHistoryIndex = consoleHistory.length;
|
||||
|
||||
inspector.executeConsoleScript(script);
|
||||
consoleInput.value = "";
|
||||
};
|
||||
|
||||
const setConsoleInputToPreviousHistoryItem = consoleInput => {
|
||||
if (consoleHistoryIndex === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
--consoleHistoryIndex;
|
||||
|
||||
const script = consoleHistory[consoleHistoryIndex];
|
||||
consoleInput.value = script;
|
||||
};
|
||||
|
||||
const setConsoleInputToNextHistoryItem = consoleInput => {
|
||||
if (consoleHistory.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastIndex = consoleHistory.length - 1;
|
||||
|
||||
if (consoleHistoryIndex < lastIndex) {
|
||||
++consoleHistoryIndex;
|
||||
|
||||
consoleInput.value = consoleHistory[consoleHistoryIndex];
|
||||
return;
|
||||
}
|
||||
|
||||
if (consoleHistoryIndex === lastIndex) {
|
||||
++consoleHistoryIndex;
|
||||
|
||||
consoleInput.value = "";
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const consoleParentGroup = () => {
|
||||
if (consoleGroupStack.length === 0) {
|
||||
return document.getElementById("console-output");
|
||||
}
|
||||
|
||||
const lastConsoleGroup = consoleGroupStack[consoleGroupStack.length - 1];
|
||||
return document.getElementById(`console-group-${lastConsoleGroup.id}`);
|
||||
};
|
||||
|
||||
const scrollConsoleToBottom = () => {
|
||||
let consoleOutput = document.getElementById("console-output");
|
||||
|
||||
// FIXME: It should be sufficient to scrollTo a y value of document.documentElement.offsetHeight,
|
||||
// but due to an unknown bug offsetHeight seems to not be properly updated after spamming
|
||||
// a lot of document changes.
|
||||
//
|
||||
// The setTimeout makes the scrollTo async and allows the DOM to be updated.
|
||||
setTimeout(function () {
|
||||
consoleOutput.scrollTo(0, 1_000_000_000);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
inspector.appendConsoleOutput = output => {
|
||||
let parent = consoleParentGroup();
|
||||
|
||||
let element = document.createElement("p");
|
||||
element.innerHTML = atob(output);
|
||||
|
||||
parent.appendChild(element);
|
||||
scrollConsoleToBottom();
|
||||
};
|
||||
|
||||
inspector.clearConsoleOutput = () => {
|
||||
let consoleOutput = document.getElementById("console-output");
|
||||
consoleOutput.innerHTML = "";
|
||||
|
||||
consoleGroupStack = [];
|
||||
};
|
||||
|
||||
inspector.beginConsoleGroup = (label, startExpanded) => {
|
||||
let parent = consoleParentGroup();
|
||||
|
||||
const group = {
|
||||
id: ++consoleGroupNextID,
|
||||
label: label,
|
||||
};
|
||||
consoleGroupStack.push(group);
|
||||
|
||||
let details = document.createElement("details");
|
||||
details.id = `console-group-${group.id}`;
|
||||
details.open = startExpanded;
|
||||
|
||||
let summary = document.createElement("summary");
|
||||
summary.innerHTML = atob(label);
|
||||
|
||||
details.appendChild(summary);
|
||||
parent.appendChild(details);
|
||||
scrollConsoleToBottom();
|
||||
};
|
||||
|
||||
inspector.endConsoleGroup = () => {
|
||||
consoleGroupStack.pop();
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
let inspectorSeparator = document.getElementById("inspector-separator");
|
||||
inspectorSeparator.addEventListener("mousedown", beginSplitViewDrag);
|
||||
|
||||
let consoleInput = document.getElementById("console-input");
|
||||
consoleInput.focus();
|
||||
|
||||
consoleInput.addEventListener("keydown", event => {
|
||||
const UP_ARROW_KEYCODE = 38;
|
||||
const DOWN_ARROW_KEYCODE = 40;
|
||||
const RETURN_KEYCODE = 13;
|
||||
|
||||
if (event.keyCode === UP_ARROW_KEYCODE) {
|
||||
setConsoleInputToPreviousHistoryItem(consoleInput);
|
||||
event.preventDefault();
|
||||
} else if (event.keyCode === DOWN_ARROW_KEYCODE) {
|
||||
setConsoleInputToNextHistoryItem(consoleInput);
|
||||
event.preventDefault();
|
||||
} else if (event.keyCode === RETURN_KEYCODE) {
|
||||
executeConsoleScript(consoleInput);
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
inspector.inspectorLoaded();
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue