From 810d04b3f4bf19430f2dbfac37608aede43bc4d7 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 14 Mar 2025 16:22:16 -0400 Subject: [PATCH] LibWeb+LibWebView+WebContent: Remove the built-in Inspector --- Base/res/ladybird/inspector.css | 383 -------- Base/res/ladybird/inspector.html | 114 --- Base/res/ladybird/inspector.js | 866 ------------------ Libraries/LibWeb/CMakeLists.txt | 1 - Libraries/LibWeb/Forward.h | 1 - Libraries/LibWeb/HTML/Window.cpp | 9 - Libraries/LibWeb/HTML/Window.h | 1 - Libraries/LibWeb/Internals/Inspector.cpp | 108 --- Libraries/LibWeb/Internals/Inspector.h | 48 - Libraries/LibWeb/Internals/Inspector.idl | 23 - Libraries/LibWeb/Page/Page.h | 19 - Libraries/LibWeb/idl_files.cmake | 1 - Libraries/LibWebView/CMakeLists.txt | 1 - Libraries/LibWebView/Forward.h | 1 - Libraries/LibWebView/HelperProcess.cpp | 3 - Libraries/LibWebView/InspectorClient.cpp | 809 ---------------- Libraries/LibWebView/InspectorClient.h | 98 -- Libraries/LibWebView/ViewImplementation.cpp | 5 - Libraries/LibWebView/ViewImplementation.h | 17 +- Libraries/LibWebView/WebContentClient.cpp | 120 +-- Libraries/LibWebView/WebContentClient.h | 15 +- .../Userland/Libraries/LibWeb/idl_files.gni | 1 - Services/WebContent/CMakeLists.txt | 1 - Services/WebContent/ConnectionFromClient.cpp | 7 +- Services/WebContent/ConnectionFromClient.h | 2 - Services/WebContent/Forward.h | 1 - .../WebContent/InspectorConsoleClient.cpp | 252 ----- Services/WebContent/InspectorConsoleClient.h | 65 -- Services/WebContent/PageClient.cpp | 90 +- Services/WebContent/PageClient.h | 13 - Services/WebContent/WebContentClient.ipc | 15 +- Services/WebContent/WebContentServer.ipc | 2 - Services/WebContent/main.cpp | 3 - UI/cmake/ResourceFiles.cmake | 11 - 34 files changed, 24 insertions(+), 3082 deletions(-) delete mode 100644 Base/res/ladybird/inspector.css delete mode 100644 Base/res/ladybird/inspector.html delete mode 100644 Base/res/ladybird/inspector.js delete mode 100644 Libraries/LibWeb/Internals/Inspector.cpp delete mode 100644 Libraries/LibWeb/Internals/Inspector.h delete mode 100644 Libraries/LibWeb/Internals/Inspector.idl delete mode 100644 Libraries/LibWebView/InspectorClient.cpp delete mode 100644 Libraries/LibWebView/InspectorClient.h delete mode 100644 Services/WebContent/InspectorConsoleClient.cpp delete mode 100644 Services/WebContent/InspectorConsoleClient.h diff --git a/Base/res/ladybird/inspector.css b/Base/res/ladybird/inspector.css deleted file mode 100644 index 176999b5c2b..00000000000 --- a/Base/res/ladybird/inspector.css +++ /dev/null @@ -1,383 +0,0 @@ -:root { - --code-font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: rgb(23, 23, 23); - --separator: dimgray; - --separator-accent: rgb(57, 57, 57); - --tab-controls: rgb(57, 57, 57); - --tab-button-background: rgb(43, 42, 50); - --text-color: white; - --tab-button-active-background: rgb(22 100 219); - --tab-button-active-color: var(--text-color); - --tab-button-border: rgb(96, 96, 96); - --hoverable-background: #31383e; - --selected-border: cyan; - --console-prompt-color: cyan; - --console-message-color: lightskyblue; - --console-warning-color: orange; - --console-input-color: rgb(57, 57, 57); - --console-input-focus-color: cyan; - --console-table-row-odd: rgb(57, 57, 57); - --console-table-row-hover: rgb(80, 79, 79); - --console-table-border: gray; - --property-table-head: rgb(57, 57, 57); - --property-table-row: rgb(45, 45, 45); - } -} - -@media (prefers-color-scheme: light) { - :root { - --background: white; - --separator: lightgray; - --separator-accent: white; - --tab-controls: rgb(229, 229, 229); - --tab-button-background: white; - --text-color: black; - --tab-button-active: rgb(22 100 219); - --tab-button-border: rgb(242, 242, 242); - --hoverable-background: rgb(236, 236, 236); - --selected-border: blue; - --console-prompt-color: blue; - --console-message-color: blue; - --console-warning-color: darkorange; - --console-input-color: rgb(229, 229, 229); - --console-input-focus-color: blue; - --console-table-row-odd: rgb(229, 229, 229); - --console-table-row-hover: rgb(199, 198, 198); - --console-table-border: gray; - --property-table-head: rgb(229, 229, 229); - --property-table-row: rgb(240, 240, 240); - } -} - -html { - background-color: var(--background); -} - -body { - font-family: system-ui, sans-serif; - font-size: 10pt; - - margin: 0; -} - -.split-view { - width: 100vw; - height: 100vh; - - overflow: hidden; -} - -.split-view-container { - max-height: calc(100% - 40px); - min-height: 40px; -} - -.split-view-separator { - background-color: var(--separator); - - width: 100%; - height: 5px; - - display: flex; - justify-content: center; - - cursor: row-resize; - user-select: none; - - z-index: 100; -} - -.split-view-separator circle { - fill: var(--separator-accent); -} - -.tab-controls-container { - background-color: var(--tab-controls); - - width: 100%; - - padding: 4px; - - display: flex; - align-items: center; - justify-content: space-between; - - z-index: 100; -} - -.tab-controls { - overflow: hidden; - flex-shrink: 0; -} - -.tab-controls button { - color: var(--text-color); - background-color: var(--tab-button-background); - - font-size: 12px; - font-weight: 600; - - float: left; - border: none; - outline: none; - cursor: pointer; - - padding: 4px 8px; -} - -.tab-controls :first-child { - border-radius: 0.5rem 0 0 0.5rem; -} - -.tab-controls :last-child { - border-radius: 0 0.5rem 0.5rem 0; -} - -.tab-controls button.active { - background-color: var(--tab-button-active-background); - color: var(--tab-button-active-color); -} - -.tab-controls button + button { - border-left: 1px solid var(--tab-button-border); -} - -.global-controls { - margin: 0 8px 0 8px; -} - -.global-controls button { - width: 24px; - height: 24px; - - border: none; - outline: none; - cursor: pointer; -} - -#export-inspector-button { - background-image: url("resource://icons/16x16/download.png"); - background-position: center; - background-repeat: no-repeat; - background-color: var(--tab-controls); -} - -#export-inspector-button:hover { - background-color: var(--tab-button-background); -} - -.tab-content { - height: calc(100% - 40px); - - display: none; - - padding: 8px 0px 0px 4px; - - overflow: auto scroll; -} - -.tab-header { - position: sticky; - top: 2px; /* FIXME: Remove this when https://github.com/LadybirdBrowser/ladybird/issues/1245 is resolved. */ - left: 0; - right: 0; - background-color: var(--tab-controls); - border-top: 2px solid var(--background); - display: flex; - padding: 0.5em; -} - -details > :not(:first-child) { - display: list-item; - list-style: none inside; - margin-left: 1em; -} - -.hoverable { - display: block; - padding: 1px; -} - -.dom-editor { - width: fit-content; - outline: none; -} - -.hoverable:hover { - background-color: var(--hoverable-background); -} - -.selected { - border: 1px dashed var(--selected-border); - padding: 0; -} - -#console { - overflow: unset; -} - -.console { - font-family: var(--code-font-family); - width: 100%; - height: 100%; -} - -.console-output { - height: calc(100% - 32px); - overflow: auto scroll; -} - -.console-input { - background-color: var(--console-input-color); - width: 100%; - height: 24px; - padding: 4px; - position: absolute; - bottom: 0; - left: 0; -} - -.console-input input { - width: calc(100% - 60px); -} - -.console-input input:focus { - outline: 1px dashed var(--console-input-focus-color); -} - -.console-prompt { - color: var(--console-prompt-color); -} - -.console-message { - color: var(--console-message-color); -} - -.console-warning { - color: var(--console-warning-color); -} - -.property-filter { - display: block; - width: calc(100% - 10px); - height: 20px; - padding: 4px; - position: sticky; - top: 0; - border: 1px solid var(--console-table-border); - background-color: var(--console-input-color); - color: var(--text-color); -} - -.property-table { - width: 100%; - - table-layout: fixed; - border-collapse: collapse; -} - -.property-table th { - background-color: var(--property-table-head); - position: sticky; - top: 30px; -} - -.property-table th, -.property-table td { - padding: 4px; - text-align: left; - - overflow: hidden; - text-overflow: ellipsis; -} - -.hidden-row { - display: none; -} - -.property-table tr:nth-child(even of :not(.hidden-row)) { - background-color: var(--property-table-row); -} - -#fonts { - display: flex; - flex-direction: row; -} - -#fonts-list { - display: flex; - flex-direction: column; -} - -#fonts-list .font { - display: flex; - flex-direction: row; -} - -#fonts-list .font div { - padding: 4px; -} - -#fonts-list .font div.name { - background-color: var(--property-table-head); - font-weight: bold; - padding-left: 10px; - padding-right: 10px; -} - -.console-log-table { - width: 100%; - padding: 0 10px; - box-sizing: border-box; -} - -.console-log-table table { - width: 100%; - table-layout: fixed; - border-collapse: collapse; - border: 1px solid var(--console-table-border); -} - -.console-log-table thead { - border-bottom: 1px solid var(--console-table-border); -} - -.console-log-table th { - position: sticky; - top: 0px; - border: 1px solid var(--console-table-border); -} - -.console-log-table td { - border-left: 1px solid var(--console-table-border); - border-right: 1px solid var(--console-table-border); -} - -.console-log-table tbody tr:nth-of-type(2n + 1) { - background-color: var(--console-table-row-odd); -} - -.console-log-table tbody tr:hover { - background-color: var(--console-table-row-hover); -} - -.console-log-table th, -.console-log-table td { - padding: 4px; - text-align: left; -} - -#style-sheet-picker { - flex-grow: 1; -} - -#style-sheet-source { - font-size: 10pt; - font-family: var(--code-font-family); - white-space: pre; - padding: 0.5em; -} diff --git a/Base/res/ladybird/inspector.html b/Base/res/ladybird/inspector.html deleted file mode 100644 index decc53c00fe..00000000000 --- a/Base/res/ladybird/inspector.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - Inspector - - - - - -
-
-
-
- -
- - - - -
- -
- -
-
- -
-
- -
-
- -
- - -
- -
-
- -
- -
-
-
- -
- - - - - -
- -
-
-
- -
- - - - - -
- -
-
- -
-
-
-
- - - -
-
-
- - @COMPUTED_STYLE@ - @RESOVLED_STYLE@ - @CUSTOM_PROPERTIES@ - -
-
-
-
-
- - - - diff --git a/Base/res/ladybird/inspector.js b/Base/res/ladybird/inspector.js deleted file mode 100644 index 2eab1728410..00000000000 --- a/Base/res/ladybird/inspector.js +++ /dev/null @@ -1,866 +0,0 @@ -let selectedTopTab = null; -let selectedTopTabButton = null; - -let selectedBottomTab = null; -let selectedBottomTabButton = null; - -let selectedDOMNode = null; -let pendingEditDOMNode = null; - -let visibleDOMNodes = []; - -let consoleGroupStack = []; -let consoleGroupNextID = 0; - -let consoleHistory = []; -let consoleHistoryIndex = 0; - -const decodeBase64 = encoded => { - return new TextDecoder().decode(Uint8Array.from(atob(encoded), c => c.charCodeAt(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"); - - // Apply any filtering if we have it - let filterInput = tab.querySelector(".property-filter"); - let propertyTable = tab.querySelector(".property-table"); - if (filterInput && propertyTable) { - filterInput.value = inspector.propertyFilterText || ""; - filterInput.dispatchEvent(new InputEvent("input")); - } - - 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.exportInspector = () => { - const html = `\n${document.documentElement.outerHTML}`; - inspector.exportInspectorHTML(html); -}; - -inspector.reset = () => { - let domTree = document.getElementById("dom-tree"); - domTree.innerHTML = ""; - - let accessibilityTree = document.getElementById("accessibility-tree"); - accessibilityTree.innerHTML = ""; - - let cookieTable = document.getElementById("cookie-table"); - cookieTable.innerHTML = ""; - - let styleSheetPicker = document.getElementById("style-sheet-picker"); - styleSheetPicker.replaceChildren(); - - let styleSheetSource = document.getElementById("style-sheet-source"); - styleSheetSource.innerHTML = ""; - - let fontsList = document.getElementById("fonts-list"); - fontsList.innerHTML = ""; - - selectedDOMNode = null; - pendingEditDOMNode = null; - - inspector.clearConsoleOutput(); -}; - -inspector.loadDOMTree = tree => { - let domTree = document.getElementById("dom-tree"); - domTree.innerHTML = decodeBase64(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 => { - const type = domNode.dataset.nodeType; - const text = event.target.innerText; - - if (type === "attribute" && event.target.classList.contains("attribute-value")) { - text = text.substring(1, text.length - 1); - } - - editDOMNode(domNode, text); - event.preventDefault(); - }); - } - - domNodes = domTree.querySelectorAll("details"); - - for (let domNode of domNodes) { - domNode.addEventListener("toggle", event => { - updateVisibleDOMNodes(); - }); - } - - updateVisibleDOMNodes(); -}; - -inspector.loadAccessibilityTree = tree => { - let accessibilityTree = document.getElementById("accessibility-tree"); - accessibilityTree.innerHTML = decodeBase64(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.editDOMNodeID = nodeID => { - if (pendingEditDOMNode === null) { - return; - } - - inspector.inspectDOMNodeID(nodeID); - editDOMNode(pendingEditDOMNode); - - pendingEditDOMNode = null; -}; - -inspector.addAttributeToDOMNodeID = nodeID => { - if (pendingEditDOMNode === null) { - return; - } - - inspector.inspectDOMNodeID(nodeID); - addAttributeToDOMNode(pendingEditDOMNode); - - pendingEditDOMNode = null; -}; - -inspector.setCookies = cookies => { - let oldTable = document.getElementById("cookie-table"); - - let newTable = document.createElement("tbody"); - newTable.setAttribute("id", oldTable.id); - - const addColumn = (row, value) => { - let column = row.insertCell(); - column.innerText = value; - column.title = value; - }; - - cookies - .sort((lhs, rhs) => lhs.name.localeCompare(rhs.name)) - .forEach(cookie => { - let row = newTable.insertRow(); - - addColumn(row, cookie.name); - addColumn(row, cookie.value); - addColumn(row, cookie.domain); - addColumn(row, cookie.path); - addColumn(row, new Date(cookie.creationTime).toLocaleString()); - addColumn(row, new Date(cookie.lastAccessTime).toLocaleString()); - addColumn(row, new Date(cookie.expiryTime).toLocaleString()); - - row.addEventListener("contextmenu", event => { - inspector.requestCookieContextMenu(cookie.index, event.clientX, event.clientY); - event.preventDefault(); - }); - }); - - oldTable.parentNode.replaceChild(newTable, oldTable); -}; - -inspector.setStyleSheets = styleSheets => { - const styleSheetPicker = document.getElementById("style-sheet-picker"); - const styleSheetSource = document.getElementById("style-sheet-source"); - styleSheetPicker.replaceChildren(); - styleSheetSource.innerHTML = ""; - - function addOption(styleSheet, text) { - const option = document.createElement("option"); - option.innerText = text; - if (styleSheet.type) { - option.dataset["type"] = styleSheet.type; - } - if (styleSheet.domNodeId) { - option.dataset["domNodeId"] = styleSheet.domNodeId; - } - if (styleSheet.url) { - option.dataset["url"] = styleSheet.url; - } - styleSheetPicker.add(option); - } - - if (styleSheets.length > 0) { - let styleElementIndex = 1; - for (const styleSheet of styleSheets) { - switch (styleSheet.type) { - case "StyleElement": - addOption(styleSheet, `Style element #${styleElementIndex++}`); - break; - case "LinkElement": - addOption(styleSheet, styleSheet.url); - break; - case "ImportRule": - addOption(styleSheet, styleSheet.url); - break; - case "UserAgent": - addOption(styleSheet, `User agent: ${styleSheet.url}`); - break; - case "UserStyle": - addOption(styleSheet, "User style"); - break; - } - } - styleSheetPicker.disabled = false; - } else { - addOption({}, "No style sheets found"); - styleSheetPicker.disabled = true; - } - - styleSheetPicker.selectedIndex = 0; - - if (!styleSheetPicker.disabled) { - loadStyleSheet(); - } -}; - -const loadStyleSheet = () => { - const styleSheetPicker = document.getElementById("style-sheet-picker"); - const styleSheetSource = document.getElementById("style-sheet-source"); - const selectedOption = styleSheetPicker.selectedOptions[0]; - - styleSheetSource.innerHTML = "Loading..."; - inspector.requestStyleSheetSource( - selectedOption.dataset["type"], - selectedOption.dataset["domNodeId"], - selectedOption.dataset["url"] - ); -}; - -inspector.setStyleSheetSource = (identifier, sourceBase64) => { - const styleSheetPicker = document.getElementById("style-sheet-picker"); - const styleSheetSource = document.getElementById("style-sheet-source"); - const selectedOption = styleSheetPicker.selectedOptions[0]; - - // Make sure this is the source for the currently-selected style sheet. - // NOTE: These are != not !== intentionally. - if ( - identifier.type != selectedOption.dataset["type"] || - identifier.domNodeId != selectedOption.dataset["domNodeId"] || - identifier.url != selectedOption.dataset["url"] - ) { - console.log( - JSON.stringify(identifier), - "doesn't match", - JSON.stringify(selectedOption.dataset) - ); - return; - } - - styleSheetSource.innerHTML = decodeBase64(sourceBase64); -}; - -const applyPropertyFilter = (row, searchText) => { - let matches = false; - if (searchText) { - for (let cell of row.cells) { - if (cell.textContent.toLowerCase().includes(searchText)) { - matches = true; - break; - } - } - } else { - // Empty searchText matches everything, so skip the checks. - matches = true; - } - - if (matches) { - row.classList.remove("hidden-row"); - } else { - row.classList.add("hidden-row"); - } -}; - -const setupPropertyFilter = inputId => { - const filterInput = document.getElementById(`${inputId}-filter`); - - filterInput.addEventListener("input", event => { - inspector.propertyFilterText = event.target.value.toLowerCase(); - const tbody = document.getElementById(`${inputId}-table`); - const rows = tbody.getElementsByTagName("tr"); - - for (let row of rows) { - applyPropertyFilter(row, inspector.propertyFilterText); - } - }); -}; - -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((a, b) => { - let baseResult = a.localeCompare(b); - // Manually move vendor-prefixed items after non-prefixed ones. - if (a[0] === "-") { - if (b[0] === "-") { - return baseResult; - } - return 1; - } - if (b[0] === "-") { - return -1; - } - return baseResult; - }) - .forEach(name => { - let row = newTable.insertRow(); - - let nameColumn = row.insertCell(); - nameColumn.innerText = name; - - let valueColumn = row.insertCell(); - valueColumn.innerText = properties[name]; - - if (inspector.propertyFilterText) { - applyPropertyFilter(row, inspector.propertyFilterText); - } - }); - - 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)); -}; - -inspector.createFontList = fonts => { - let fontsJSON = JSON.parse(fonts); - if (!Array.isArray(fontsJSON)) return; - - const listId = "fonts-list"; - let oldList = document.getElementById(listId); - - let newList = document.createElement("div"); - newList.setAttribute("id", listId); - const createFontEntry = (listContainer, font) => { - let fontEntry = document.createElement("div"); - fontEntry.classList.add("font"); - - let fontName = document.createElement("div"); - fontName.classList.add("name"); - fontName.innerText = font.name; - fontEntry.appendChild(fontName); - - let fontSize = document.createElement("div"); - fontSize.classList.add("size"); - fontSize.innerText = font.size; - fontEntry.appendChild(fontSize); - - let fontWeight = document.createElement("div"); - fontWeight.classList.add("Weight"); - fontWeight.innerText = font.weight; - fontEntry.appendChild(fontWeight); - - let fontVariant = document.createElement("div"); - fontVariant.classList.add("Variant"); - fontVariant.innerText = font.variant; - fontEntry.appendChild(fontVariant); - - listContainer.appendChild(fontEntry); - }; - - for (let font of fontsJSON) createFontEntry(newList, font); - - oldList.parentNode.replaceChild(newList, oldList); -}; - -const inspectDOMNode = domNode => { - if (selectedDOMNode === domNode) { - return; - } - - inspector.clearInspectedDOMNode(); - - domNode.classList.add("selected"); - selectedDOMNode = domNode; - - inspector.inspectDOMNode(domNode.dataset.id, domNode.dataset.pseudoElement); -}; - -const createDOMEditor = (onHandleChange, onCancelChange) => { - selectedDOMNode.classList.remove("selected"); - - let input = document.createElement("input"); - input.classList.add("dom-editor"); - input.classList.add("selected"); - - const handleChange = () => { - input.removeEventListener("change", handleChange); - input.removeEventListener("blur", cancelChange); - input.removeEventListener("keydown", handleInput); - - try { - onHandleChange(input.value); - } catch { - cancelChange(); - } - }; - - const cancelChange = () => { - input.removeEventListener("change", handleChange); - input.removeEventListener("blur", cancelChange); - input.removeEventListener("keydown", handleInput); - - selectedDOMNode.classList.add("selected"); - onCancelChange(input); - }; - - const handleInput = event => { - const ESCAPE_KEYCODE = 27; - - if (event.keyCode === ESCAPE_KEYCODE) { - cancelChange(); - event.preventDefault(); - } - }; - - input.addEventListener("change", handleChange); - input.addEventListener("blur", cancelChange); - input.addEventListener("keydown", handleInput); - - setTimeout(() => { - input.focus(); - }); - - return input; -}; - -const parseDOMAttributes = value => { - let element = document.createElement("div"); - element.innerHTML = `
`; - - return element.children[0].attributes; -}; - -const editDOMNode = (domNode, textToSelect) => { - if (selectedDOMNode === null) { - return; - } - - const domNodeID = selectedDOMNode.dataset.id; - const type = domNode.dataset.nodeType; - - const handleChange = value => { - if (type === "text" || type === "comment") { - inspector.setDOMNodeText(domNodeID, value); - } else if (type === "tag") { - const element = document.createElement(value); - inspector.setDOMNodeTag(domNodeID, value); - } else if (type === "attribute") { - const attributeIndex = domNode.dataset.attributeIndex; - const attributes = parseDOMAttributes(value); - - inspector.replaceDOMNodeAttribute(domNodeID, attributeIndex, attributes); - } - }; - - const cancelChange = editor => { - editor.parentNode.replaceChild(domNode, editor); - }; - - let editor = createDOMEditor(handleChange, cancelChange); - - if (type === "text") { - let emptyTextSpan = domNode.querySelector(".internal"); - - if (emptyTextSpan === null) { - editor.value = domNode.innerText; - } - } else { - editor.value = domNode.innerText; - } - - setTimeout(() => { - if (typeof textToSelect !== "undefined") { - const index = editor.value.indexOf(textToSelect); - if (index !== -1) { - editor.setSelectionRange(index, index + textToSelect.length); - return; - } - } - - editor.select(); - }); - - domNode.parentNode.replaceChild(editor, domNode); -}; - -const addAttributeToDOMNode = domNode => { - if (selectedDOMNode === null) { - return; - } - - const domNodeID = selectedDOMNode.dataset.id; - - const handleChange = value => { - const attributes = parseDOMAttributes(value); - inspector.addDOMNodeAttributes(domNodeID, attributes); - }; - - const cancelChange = () => { - container.remove(); - }; - - let editor = createDOMEditor(handleChange, cancelChange); - editor.placeholder = 'name="value"'; - - let nbsp = document.createElement("span"); - nbsp.innerHTML = " "; - - let container = document.createElement("span"); - container.appendChild(nbsp); - container.appendChild(editor); - - domNode.parentNode.insertBefore(container, domNode.parentNode.lastChild); -}; - -const updateVisibleDOMNodes = () => { - let domTree = document.getElementById("dom-tree"); - - visibleDOMNodes = []; - - function recurseDOMNodes(node) { - for (let child of node.children) { - if (child.classList.contains("hoverable")) { - visibleDOMNodes.push(child); - } - - if (child.tagName === "DIV") { - if (node.open) { - recurseDOMNodes(child); - } - } else { - recurseDOMNodes(child); - } - } - } - - recurseDOMNodes(domTree); -}; - -const requestContextMenu = (clientX, clientY, domNode) => { - pendingEditDOMNode = null; - - if (typeof domNode.dataset.nodeType === "undefined") { - if (domNode.parentNode !== null) { - domNode = domNode.parentNode; - } - } - - const domNodeID = domNode.closest(".hoverable")?.dataset.id; - const type = domNode.dataset.nodeType; - - if (typeof domNodeID === "undefined" || typeof type === "undefined") { - return; - } - - let tag = null; - let attributeIndex = null; - - if (type === "tag") { - tag = domNode.dataset.tag; - } else if (type === "attribute") { - tag = domNode.dataset.tag; - attributeIndex = domNode.dataset.attributeIndex; - } - - pendingEditDOMNode = domNode; - inspector.requestDOMTreeContextMenu(domNodeID, clientX, clientY, type, tag, attributeIndex); -}; - -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 = decodeBase64(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 = decodeBase64(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(); - } - }); - - document.addEventListener("contextmenu", event => { - requestContextMenu(event.clientX, event.clientY, event.target); - event.preventDefault(); - }); - - document.addEventListener("keydown", event => { - const UP_ARROW_KEYCODE = 38; - const DOWN_ARROW_KEYCODE = 40; - const RIGHT_ARROW_KEYCODE = 39; - const LEFT_ARROW_KEYCODE = 37; - const RETURN_KEYCODE = 13; - const SPACE_KEYCODE = 32; - - const move = delta => { - let selectedIndex = visibleDOMNodes.indexOf(selectedDOMNode); - if (selectedIndex < 0) { - return; - } - - let newIndex = selectedIndex + delta; - - if (visibleDOMNodes[newIndex]) { - inspectDOMNode(visibleDOMNodes[newIndex]); - } - }; - - if (document.activeElement.tagName !== "INPUT") { - const isSummary = selectedDOMNode.parentNode.tagName === "SUMMARY"; - const isDiv = selectedDOMNode.parentNode.tagName === "DIV"; - - if (event.keyCode == UP_ARROW_KEYCODE) { - move(-1); - } else if (event.keyCode == DOWN_ARROW_KEYCODE) { - move(1); - } else if (event.keyCode == RETURN_KEYCODE || event.keyCode == SPACE_KEYCODE) { - if (isSummary) { - selectedDOMNode.parentNode.click(); - } - } else if (event.keyCode == RIGHT_ARROW_KEYCODE) { - if (isSummary && selectedDOMNode.parentNode.parentNode.open === false) { - selectedDOMNode.parentNode.click(); - } else if (selectedDOMNode.parentNode.parentNode.open === true && !isDiv) { - move(1); - } - } else if (event.keyCode == LEFT_ARROW_KEYCODE) { - if (isSummary && selectedDOMNode.parentNode.parentNode.open === true) { - selectedDOMNode.parentNode.click(); - } else if (selectedDOMNode.parentNode.parentNode.open === false || isDiv) { - move(-1); - } - } - } - }); - - // Setup filters for property tables - ["computed-style", "resolved-style", "custom-properties"].forEach(setupPropertyFilter); - - inspector.inspectorLoaded(); -}); diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 97dcd2497eb..1f7b520878b 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -555,7 +555,6 @@ set(SOURCES IndexedDB/Internal/Database.cpp IndexedDB/Internal/Key.cpp IndexedDB/Internal/RequestList.cpp - Internals/Inspector.cpp Internals/InternalAnimationTimeline.cpp Internals/Internals.cpp IntersectionObserver/IntersectionObserver.cpp diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index a4a2a106cf8..8389057b448 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -621,7 +621,6 @@ class RequestList; } namespace Web::Internals { -class Inspector; class Internals; } diff --git a/Libraries/LibWeb/HTML/Window.cpp b/Libraries/LibWeb/HTML/Window.cpp index 8f805567d51..8be002b9b77 100644 --- a/Libraries/LibWeb/HTML/Window.cpp +++ b/Libraries/LibWeb/HTML/Window.cpp @@ -60,7 +60,6 @@ #include #include #include -#include #include #include #include @@ -716,14 +715,8 @@ Vector> Window::pdf_viewer_mime_type_objects() return m_pdf_viewer_mime_type_objects; } -static bool s_inspector_object_exposed = false; static bool s_internals_object_exposed = false; -void Window::set_inspector_object_exposed(bool exposed) -{ - s_inspector_object_exposed = exposed; -} - void Window::set_internals_object_exposed(bool exposed) { s_internals_object_exposed = exposed; @@ -739,8 +732,6 @@ WebIDL::ExceptionOr Window::initialize_web_interfaces(Badge(realm), JS::default_attributes); if (s_internals_object_exposed) define_direct_property("internals", realm.create(realm), JS::default_attributes); diff --git a/Libraries/LibWeb/HTML/Window.h b/Libraries/LibWeb/HTML/Window.h index cc3b2c93ace..4a8645973c0 100644 --- a/Libraries/LibWeb/HTML/Window.h +++ b/Libraries/LibWeb/HTML/Window.h @@ -247,7 +247,6 @@ public: void consume_history_action_user_activation(); - static void set_inspector_object_exposed(bool); static void set_internals_object_exposed(bool); [[nodiscard]] OrderedHashMap> document_tree_child_navigable_target_name_property_set(); diff --git a/Libraries/LibWeb/Internals/Inspector.cpp b/Libraries/LibWeb/Internals/Inspector.cpp deleted file mode 100644 index f29e6e09672..00000000000 --- a/Libraries/LibWeb/Internals/Inspector.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2023-2024, Tim Flynn - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Web::Internals { - -GC_DEFINE_ALLOCATOR(Inspector); - -Inspector::Inspector(JS::Realm& realm) - : Bindings::PlatformObject(realm) -{ -} - -Inspector::~Inspector() = default; - -void Inspector::initialize(JS::Realm& realm) -{ - Base::initialize(realm); - WEB_SET_PROTOTYPE_FOR_INTERFACE(Inspector); -} - -PageClient& Inspector::inspector_page_client() const -{ - return as(HTML::relevant_global_object(*this)).page().client(); -} - -void Inspector::inspector_loaded() -{ - inspector_page_client().inspector_did_load(); -} - -void Inspector::inspect_dom_node(i64 node_id, Optional const& pseudo_element) -{ - inspector_page_client().inspector_did_select_dom_node(node_id, pseudo_element.map([](auto value) { - VERIFY(value < to_underlying(Web::CSS::Selector::PseudoElement::Type::KnownPseudoElementCount)); - return static_cast(value); - })); -} - -void Inspector::set_dom_node_text(i64 node_id, String const& text) -{ - inspector_page_client().inspector_did_set_dom_node_text(node_id, text); -} - -void Inspector::set_dom_node_tag(i64 node_id, String const& tag) -{ - inspector_page_client().inspector_did_set_dom_node_tag(node_id, tag); -} - -void Inspector::add_dom_node_attributes(i64 node_id, GC::Ref attributes) -{ - inspector_page_client().inspector_did_add_dom_node_attributes(node_id, attributes); -} - -void Inspector::replace_dom_node_attribute(i64 node_id, WebIDL::UnsignedLongLong attribute_index, GC::Ref replacement_attributes) -{ - inspector_page_client().inspector_did_replace_dom_node_attribute(node_id, static_cast(attribute_index), replacement_attributes); -} - -void Inspector::request_dom_tree_context_menu(i64 node_id, i32 client_x, i32 client_y, String const& type, Optional const& tag, Optional const& attribute_index) -{ - inspector_page_client().inspector_did_request_dom_tree_context_menu(node_id, { client_x, client_y }, type, tag, attribute_index.map([](auto index) { return static_cast(index); })); -} - -void Inspector::request_cookie_context_menu(WebIDL::UnsignedLongLong cookie_index, i32 client_x, i32 client_y) -{ - inspector_page_client().inspector_did_request_cookie_context_menu(cookie_index, { client_x, client_y }); -} - -void Inspector::request_style_sheet_source(String const& type_string, Optional const& dom_node_unique_id, Optional const& url) -{ - auto type = CSS::style_sheet_identifier_type_from_string(type_string); - VERIFY(type.has_value()); - - Optional dom_node_unique_id_opt; - if (dom_node_unique_id.has_value()) - dom_node_unique_id_opt = dom_node_unique_id.value(); - - inspector_page_client().inspector_did_request_style_sheet_source({ - .type = type.value(), - .dom_element_unique_id = dom_node_unique_id_opt, - .url = url, - }); -} - -void Inspector::execute_console_script(String const& script) -{ - inspector_page_client().inspector_did_execute_console_script(script); -} - -void Inspector::export_inspector_html(String const& html) -{ - inspector_page_client().inspector_did_export_inspector_html(html); -} - -} diff --git a/Libraries/LibWeb/Internals/Inspector.h b/Libraries/LibWeb/Internals/Inspector.h deleted file mode 100644 index f888feb702c..00000000000 --- a/Libraries/LibWeb/Internals/Inspector.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2023-2024, Tim Flynn - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Web::Internals { - -class Inspector final : public Bindings::PlatformObject { - WEB_PLATFORM_OBJECT(Inspector, Bindings::PlatformObject); - GC_DECLARE_ALLOCATOR(Inspector); - -public: - virtual ~Inspector() override; - - void inspector_loaded(); - void inspect_dom_node(i64 node_id, Optional const& pseudo_element); - - void set_dom_node_text(i64 node_id, String const& text); - void set_dom_node_tag(i64 node_id, String const& tag); - void add_dom_node_attributes(i64 node_id, GC::Ref attributes); - void replace_dom_node_attribute(i64 node_id, WebIDL::UnsignedLongLong attribute_index, GC::Ref replacement_attributes); - - void request_dom_tree_context_menu(i64 node_id, i32 client_x, i32 client_y, String const& type, Optional const& tag, Optional const& attribute_index); - - void request_cookie_context_menu(WebIDL::UnsignedLongLong cookie_index, i32 client_x, i32 client_y); - - void request_style_sheet_source(String const& type, Optional const& dom_node_unique_id, Optional const& url); - - void execute_console_script(String const& script); - - void export_inspector_html(String const& html); - -private: - explicit Inspector(JS::Realm&); - - PageClient& inspector_page_client() const; - - virtual void initialize(JS::Realm&) override; -}; - -} diff --git a/Libraries/LibWeb/Internals/Inspector.idl b/Libraries/LibWeb/Internals/Inspector.idl deleted file mode 100644 index ded57e5f7d9..00000000000 --- a/Libraries/LibWeb/Internals/Inspector.idl +++ /dev/null @@ -1,23 +0,0 @@ -#import - -[Exposed=Nobody] interface Inspector { - - undefined inspectorLoaded(); - undefined inspectDOMNode(long long nodeID, optional long pseudoElement); - - undefined setDOMNodeText(long long nodeID, DOMString text); - undefined setDOMNodeTag(long long nodeID, DOMString tag); - undefined addDOMNodeAttributes(long long nodeID, NamedNodeMap attributes); - undefined replaceDOMNodeAttribute(long long nodeID, unsigned long long attributeIndex, NamedNodeMap replacementAttributes); - - undefined requestDOMTreeContextMenu(long long nodeID, long clientX, long clientY, DOMString type, DOMString? tag, unsigned long long? attributeIndex); - - undefined requestCookieContextMenu(unsigned long long cookieIndex, long clientX, long clientY); - - undefined requestStyleSheetSource(DOMString type, long long? domNodeID, DOMString? url); - - undefined executeConsoleScript(DOMString script); - - undefined exportInspectorHTML(DOMString html); - -}; diff --git a/Libraries/LibWeb/Page/Page.h b/Libraries/LibWeb/Page/Page.h index 9704c71b046..8be7d715384 100644 --- a/Libraries/LibWeb/Page/Page.h +++ b/Libraries/LibWeb/Page/Page.h @@ -9,12 +9,7 @@ #pragma once -#include -#include -#include #include -#include -#include #include #include #include @@ -28,8 +23,6 @@ #include #include #include -#include -#include #include #include #include @@ -407,18 +400,6 @@ public: virtual void page_did_mutate_dom([[maybe_unused]] FlyString const& type, [[maybe_unused]] DOM::Node const& target, [[maybe_unused]] DOM::NodeList& added_nodes, [[maybe_unused]] DOM::NodeList& removed_nodes, [[maybe_unused]] GC::Ptr previous_sibling, [[maybe_unused]] GC::Ptr next_sibling, [[maybe_unused]] Optional const& attribute_name) { } - virtual void inspector_did_load() { } - virtual void inspector_did_select_dom_node([[maybe_unused]] UniqueNodeID node_id, [[maybe_unused]] Optional const& pseudo_element) { } - virtual void inspector_did_set_dom_node_text([[maybe_unused]] UniqueNodeID node_id, [[maybe_unused]] String const& text) { } - virtual void inspector_did_set_dom_node_tag([[maybe_unused]] UniqueNodeID node_id, [[maybe_unused]] String const& tag) { } - virtual void inspector_did_add_dom_node_attributes([[maybe_unused]] UniqueNodeID node_id, [[maybe_unused]] GC::Ref attributes) { } - virtual void inspector_did_replace_dom_node_attribute([[maybe_unused]] UniqueNodeID node_id, [[maybe_unused]] size_t attribute_index, [[maybe_unused]] GC::Ref replacement_attributes) { } - virtual void inspector_did_request_dom_tree_context_menu([[maybe_unused]] UniqueNodeID node_id, [[maybe_unused]] CSSPixelPoint position, [[maybe_unused]] String const& type, [[maybe_unused]] Optional const& tag, [[maybe_unused]] Optional const& attribute_index) { } - virtual void inspector_did_request_cookie_context_menu([[maybe_unused]] size_t cookie_index, [[maybe_unused]] CSSPixelPoint position) { } - virtual void inspector_did_request_style_sheet_source([[maybe_unused]] CSS::StyleSheetIdentifier const& identifier) { } - virtual void inspector_did_execute_console_script([[maybe_unused]] String const& script) { } - virtual void inspector_did_export_inspector_html([[maybe_unused]] String const& html) { } - virtual bool is_ready_to_paint() const = 0; virtual DisplayListPlayerType display_list_player_type() const = 0; diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake index 1ab0f4d7ed2..487a78ef9d4 100644 --- a/Libraries/LibWeb/idl_files.cmake +++ b/Libraries/LibWeb/idl_files.cmake @@ -262,7 +262,6 @@ libweb_js_bindings(IndexedDB/IDBOpenDBRequest) libweb_js_bindings(IndexedDB/IDBRequest) libweb_js_bindings(IndexedDB/IDBTransaction) libweb_js_bindings(IndexedDB/IDBVersionChangeEvent) -libweb_js_bindings(Internals/Inspector) libweb_js_bindings(Internals/InternalAnimationTimeline) libweb_js_bindings(Internals/Internals) libweb_js_bindings(IntersectionObserver/IntersectionObserver) diff --git a/Libraries/LibWebView/CMakeLists.txt b/Libraries/LibWebView/CMakeLists.txt index acd6e5c8ac3..f0c7d7a79c9 100644 --- a/Libraries/LibWebView/CMakeLists.txt +++ b/Libraries/LibWebView/CMakeLists.txt @@ -8,7 +8,6 @@ set(SOURCES CookieJar.cpp Database.cpp HelperProcess.cpp - InspectorClient.cpp Mutation.cpp Plugins/FontPlugin.cpp Plugins/ImageCodecPlugin.cpp diff --git a/Libraries/LibWebView/Forward.h b/Libraries/LibWebView/Forward.h index 242796bcfc7..f5d98001318 100644 --- a/Libraries/LibWebView/Forward.h +++ b/Libraries/LibWebView/Forward.h @@ -13,7 +13,6 @@ namespace WebView { class Application; class CookieJar; class Database; -class InspectorClient; class OutOfProcessWebView; class ProcessManager; class ViewImplementation; diff --git a/Libraries/LibWebView/HelperProcess.cpp b/Libraries/LibWebView/HelperProcess.cpp index 597b2a85ae7..5e4ea9b1a8b 100644 --- a/Libraries/LibWebView/HelperProcess.cpp +++ b/Libraries/LibWebView/HelperProcess.cpp @@ -85,7 +85,6 @@ static ErrorOr> launch_web_content_proc Optional request_server_socket, ClientArguments&&... client_arguments) { - auto const& chrome_options = WebView::Application::chrome_options(); auto const& web_content_options = WebView::Application::web_content_options(); Vector arguments { @@ -95,8 +94,6 @@ static ErrorOr> launch_web_content_proc web_content_options.executable_path.to_byte_string(), }; - if (chrome_options.devtools_port.has_value()) - arguments.append("--devtools"sv); if (web_content_options.config_path.has_value()) { arguments.append("--config-path"sv); arguments.append(web_content_options.config_path.value()); diff --git a/Libraries/LibWebView/InspectorClient.cpp b/Libraries/LibWebView/InspectorClient.cpp deleted file mode 100644 index c27f02c8ee6..00000000000 --- a/Libraries/LibWebView/InspectorClient.cpp +++ /dev/null @@ -1,809 +0,0 @@ -/* - * Copyright (c) 2023-2024, Tim Flynn - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace WebView { - -static constexpr auto INSPECTOR_HTML = "resource://ladybird/inspector.html"sv; -static constexpr auto INSPECTOR_CSS = "resource://ladybird/inspector.css"sv; -static constexpr auto INSPECTOR_JS = "resource://ladybird/inspector.js"sv; - -static String style_sheet_identifier_to_json(Web::CSS::StyleSheetIdentifier const& identifier) -{ - return MUST(String::formatted("{{ type: '{}', domNodeId: {}, url: '{}' }}"sv, - Web::CSS::style_sheet_identifier_type_to_string(identifier.type), - identifier.dom_element_unique_id.map([](auto& it) { return String::number(it.value()); }).value_or("undefined"_string), - identifier.url.value_or("undefined"_string))); -} - -InspectorClient::InspectorClient(ViewImplementation& content_web_view, ViewImplementation& inspector_web_view) - : m_content_web_view(content_web_view) - , m_inspector_web_view(inspector_web_view) -{ - m_content_web_view.on_received_dom_tree = [this](auto const& dom_tree) { - auto dom_tree_html = generate_dom_tree(dom_tree); - auto dom_tree_base64 = MUST(encode_base64(dom_tree_html.bytes())); - - auto script = MUST(String::formatted("inspector.loadDOMTree(\"{}\");", dom_tree_base64)); - m_inspector_web_view.run_javascript(script); - - m_dom_tree_loaded = true; - - if (m_pending_selection.has_value()) - select_node(m_pending_selection.release_value()); - else - select_default_node(); - }; - - m_content_web_view.on_received_dom_node_properties = [this](auto const& properties) { - StringBuilder builder; - - // FIXME: Support box model metrics and ARIA properties. - builder.append("inspector.createPropertyTables(\""sv); - builder.append_escaped_for_json(properties.computed_style.serialized()); - builder.append("\", \""sv); - builder.append_escaped_for_json(properties.resolved_style.serialized()); - builder.append("\", \""sv); - builder.append_escaped_for_json(properties.custom_properties.serialized()); - builder.append("\");"sv); - - builder.append("inspector.createFontList(\""sv); - builder.append_escaped_for_json(properties.fonts.serialized()); - builder.append("\");"sv); - - m_inspector_web_view.run_javascript(MUST(builder.to_string())); - }; - - m_content_web_view.on_received_accessibility_tree = [this](auto const& accessibility_tree) { - auto accessibility_tree_html = generate_accessibility_tree(accessibility_tree); - auto accessibility_tree_base64 = MUST(encode_base64(accessibility_tree_html.bytes())); - - auto script = MUST(String::formatted("inspector.loadAccessibilityTree(\"{}\");", accessibility_tree_base64)); - m_inspector_web_view.run_javascript(script); - }; - - m_content_web_view.on_received_hovered_node_id = [this](auto node_id) { - select_node(node_id); - }; - - m_content_web_view.on_received_style_sheet_list = [this](auto const& style_sheets) { - StringBuilder builder; - builder.append("inspector.setStyleSheets(["sv); - for (auto& style_sheet : style_sheets) { - builder.appendff("{}, "sv, style_sheet_identifier_to_json(style_sheet)); - } - builder.append("]);"sv); - - m_inspector_web_view.run_javascript(MUST(builder.to_string())); - }; - - m_content_web_view.on_received_style_sheet_source = [this](Web::CSS::StyleSheetIdentifier const& identifier, URL::URL const& base_url, String const& source) { - auto html = highlight_source(URL::Parser::basic_parse(identifier.url.value_or({})), base_url, source, Syntax::Language::CSS, HighlightOutputMode::SourceOnly); - auto script = MUST(String::formatted("inspector.setStyleSheetSource({}, \"{}\");", - style_sheet_identifier_to_json(identifier), - MUST(encode_base64(html.bytes())))); - m_inspector_web_view.run_javascript(script); - }; - - m_content_web_view.on_finshed_editing_dom_node = [this](auto const& node_id) { - m_pending_selection = node_id; - m_dom_tree_loaded = false; - m_dom_node_attributes.clear(); - - inspect(); - }; - - m_content_web_view.on_received_dom_node_html = [this](auto const& html) { - if (m_content_web_view.on_insert_clipboard_entry) - m_content_web_view.on_insert_clipboard_entry(html, "unspecified"_string, "text/plain"_string); - }; - - m_content_web_view.on_console_message_available = [this](auto message_index) { - console_message_available(message_index); - }; - - m_content_web_view.on_received_styled_console_messages = [this](auto start_index, auto const& message_types, auto const& messages) { - console_messages_received(start_index, message_types, messages); - }; - - m_inspector_web_view.enable_inspector_prototype(); - m_inspector_web_view.use_native_user_style_sheet(); - - m_inspector_web_view.on_inspector_loaded = [this]() { - m_inspector_loaded = true; - inspect(); - - m_content_web_view.js_console_request_messages(0); - }; - - m_inspector_web_view.on_inspector_requested_dom_tree_context_menu = [this](auto node_id, auto position, auto const& type, auto const& tag, auto const& attribute_index) { - Optional attribute; - if (attribute_index.has_value()) - attribute = m_dom_node_attributes.get(node_id)->at(*attribute_index); - - m_context_menu_data = ContextMenuData { node_id, tag, attribute }; - - if (type.is_one_of("text"sv, "comment"sv)) { - if (on_requested_dom_node_text_context_menu) - on_requested_dom_node_text_context_menu(position); - } else if (type == "tag"sv) { - VERIFY(tag.has_value()); - - if (on_requested_dom_node_tag_context_menu) - on_requested_dom_node_tag_context_menu(position, *tag); - } else if (type == "attribute"sv) { - VERIFY(tag.has_value()); - VERIFY(attribute.has_value()); - - if (on_requested_dom_node_attribute_context_menu) - on_requested_dom_node_attribute_context_menu(position, *tag, *attribute); - } - }; - - m_inspector_web_view.on_inspector_selected_dom_node = [this](auto node_id, auto const& pseudo_element) { - m_content_web_view.highlight_dom_node(node_id, pseudo_element); - m_content_web_view.inspect_dom_node(node_id, pseudo_element); - }; - - m_inspector_web_view.on_inspector_set_dom_node_text = [this](auto node_id, auto const& text) { - m_content_web_view.set_dom_node_text(node_id, text); - }; - - m_inspector_web_view.on_inspector_set_dom_node_tag = [this](auto node_id, auto const& tag) { - m_content_web_view.set_dom_node_tag(node_id, tag); - }; - - m_inspector_web_view.on_inspector_added_dom_node_attributes = [this](auto node_id, auto const& attributes) { - m_content_web_view.add_dom_node_attributes(node_id, attributes); - }; - - m_inspector_web_view.on_inspector_replaced_dom_node_attribute = [this](auto node_id, u32 attribute_index, auto const& replacement_attributes) { - auto const& attribute = m_dom_node_attributes.get(node_id)->at(attribute_index); - m_content_web_view.replace_dom_node_attribute(node_id, attribute.name, replacement_attributes); - }; - - m_inspector_web_view.on_inspector_requested_cookie_context_menu = [this](auto cookie_index, auto position) { - if (cookie_index >= m_cookies.size()) - return; - - m_cookie_context_menu_index = cookie_index; - - if (on_requested_cookie_context_menu) - on_requested_cookie_context_menu(position, m_cookies[cookie_index]); - }; - - m_inspector_web_view.on_inspector_requested_style_sheet_source = [this](auto const& identifier) { - m_content_web_view.request_style_sheet_source(identifier); - }; - - m_inspector_web_view.on_inspector_executed_console_script = [this](auto const& script) { - append_console_source(script); - - m_content_web_view.js_console_input(script); - }; - - m_inspector_web_view.on_inspector_exported_inspector_html = [this](String const& html) { - auto maybe_inspector_path = Application::the().path_for_downloaded_file("inspector"sv); - - if (maybe_inspector_path.is_error()) { - append_console_warning(MUST(String::formatted("Unable to select a download location: {}", maybe_inspector_path.error()))); - return; - } - - auto inspector_path = maybe_inspector_path.release_value(); - - if (auto result = Core::Directory::create(inspector_path.string(), Core::Directory::CreateDirectories::Yes); result.is_error()) { - append_console_warning(MUST(String::formatted("Unable to create {}: {}", inspector_path, result.error()))); - return; - } - - auto export_file = [&](auto name, auto const& contents) { - auto path = inspector_path.append(name); - - auto file = Core::File::open(path.string(), Core::File::OpenMode::Write); - if (file.is_error()) { - append_console_warning(MUST(String::formatted("Unable to open {}: {}", path, file.error()))); - return false; - } - - if (auto result = file.value()->write_until_depleted(contents); result.is_error()) { - append_console_warning(MUST(String::formatted("Unable to save {}: {}", path, result.error()))); - return false; - } - - return true; - }; - - auto inspector_css = MUST(Core::Resource::load_from_uri(INSPECTOR_CSS)); - auto inspector_js = MUST(Core::Resource::load_from_uri(INSPECTOR_JS)); - - auto inspector_html = MUST(html.replace(INSPECTOR_CSS, "inspector.css"sv, ReplaceMode::All)); - inspector_html = MUST(inspector_html.replace(INSPECTOR_JS, "inspector.js"sv, ReplaceMode::All)); - - if (!export_file("inspector.html"sv, inspector_html)) - return; - if (!export_file("inspector.css"sv, inspector_css->data())) - return; - if (!export_file("inspector.js"sv, inspector_js->data())) - return; - - append_console_message(MUST(String::formatted("Exported Inspector files to {}", inspector_path))); - }; - - load_inspector(); -} - -InspectorClient::~InspectorClient() -{ - m_content_web_view.on_finshed_editing_dom_node = nullptr; - m_content_web_view.on_received_accessibility_tree = nullptr; - m_content_web_view.on_console_message_available = nullptr; - m_content_web_view.on_received_styled_console_messages = nullptr; - m_content_web_view.on_received_dom_node_html = nullptr; - m_content_web_view.on_received_dom_node_properties = nullptr; - m_content_web_view.on_received_dom_tree = nullptr; - m_content_web_view.on_received_hovered_node_id = nullptr; - m_content_web_view.on_received_style_sheet_list = nullptr; - m_content_web_view.on_inspector_requested_style_sheet_source = nullptr; -} - -void InspectorClient::inspect() -{ - if (!m_inspector_loaded) - return; - - m_content_web_view.inspect_dom_tree(); - m_content_web_view.inspect_accessibility_tree(); - m_content_web_view.list_style_sheets(); - load_cookies(); -} - -void InspectorClient::reset() -{ - static auto script = "inspector.reset();"_string; - m_inspector_web_view.run_javascript(script); - - m_body_or_frameset_node_id.clear(); - m_pending_selection.clear(); - m_dom_tree_loaded = false; - - m_dom_node_attributes.clear(); - - m_highest_notified_message_index = -1; - m_highest_received_message_index = -1; - m_waiting_for_messages = false; -} - -void InspectorClient::select_hovered_node() -{ - m_content_web_view.get_hovered_node_id(); -} - -void InspectorClient::select_default_node() -{ - if (m_body_or_frameset_node_id.has_value()) - select_node(*m_body_or_frameset_node_id); -} - -void InspectorClient::clear_selection() -{ - m_content_web_view.clear_highlighted_dom_node(); - m_content_web_view.clear_inspected_dom_node(); - - static auto script = "inspector.clearInspectedDOMNode();"_string; - m_inspector_web_view.run_javascript(script); -} - -void InspectorClient::select_node(Web::UniqueNodeID node_id) -{ - if (!m_dom_tree_loaded) { - m_pending_selection = node_id; - return; - } - - auto script = MUST(String::formatted("inspector.inspectDOMNodeID({});", node_id.value())); - m_inspector_web_view.run_javascript(script); -} - -void InspectorClient::load_cookies() -{ - m_cookies = Application::cookie_jar().get_all_cookies(m_content_web_view.url()); - JsonArray json_cookies; - - for (auto const& [index, cookie] : enumerate(m_cookies)) { - JsonObject json_cookie; - - json_cookie.set("index"sv, JsonValue { index }); - json_cookie.set("name"sv, JsonValue { cookie.name }); - json_cookie.set("value"sv, JsonValue { cookie.value }); - json_cookie.set("domain"sv, JsonValue { cookie.domain }); - json_cookie.set("path"sv, JsonValue { cookie.path }); - json_cookie.set("creationTime"sv, JsonValue { cookie.creation_time.milliseconds_since_epoch() }); - json_cookie.set("lastAccessTime"sv, JsonValue { cookie.last_access_time.milliseconds_since_epoch() }); - json_cookie.set("expiryTime"sv, JsonValue { cookie.expiry_time.milliseconds_since_epoch() }); - - MUST(json_cookies.append(move(json_cookie))); - } - - StringBuilder builder; - builder.append("inspector.setCookies("sv); - json_cookies.serialize(builder); - builder.append(");"sv); - - m_inspector_web_view.run_javascript(MUST(builder.to_string())); -} - -void InspectorClient::context_menu_edit_dom_node() -{ - VERIFY(m_context_menu_data.has_value()); - - auto script = MUST(String::formatted("inspector.editDOMNodeID({});", m_context_menu_data->dom_node_id)); - m_inspector_web_view.run_javascript(script); - - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_copy_dom_node() -{ - VERIFY(m_context_menu_data.has_value()); - - m_content_web_view.get_dom_node_outer_html(m_context_menu_data->dom_node_id); - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_screenshot_dom_node() -{ - VERIFY(m_context_menu_data.has_value()); - - m_content_web_view.take_dom_node_screenshot(m_context_menu_data->dom_node_id) - ->when_resolved([this](auto const& path) { - append_console_message(MUST(String::formatted("Screenshot saved to: {}", path))); - }) - .when_rejected([this](auto const& error) { - append_console_warning(MUST(String::formatted("Warning: {}", error))); - }); - - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_create_child_element() -{ - VERIFY(m_context_menu_data.has_value()); - - m_content_web_view.create_child_element(m_context_menu_data->dom_node_id); - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_create_child_text_node() -{ - VERIFY(m_context_menu_data.has_value()); - - m_content_web_view.create_child_text_node(m_context_menu_data->dom_node_id); - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_clone_dom_node() -{ - VERIFY(m_context_menu_data.has_value()); - - m_content_web_view.clone_dom_node(m_context_menu_data->dom_node_id); - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_remove_dom_node() -{ - VERIFY(m_context_menu_data.has_value()); - - m_content_web_view.remove_dom_node(m_context_menu_data->dom_node_id); - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_add_dom_node_attribute() -{ - VERIFY(m_context_menu_data.has_value()); - - auto script = MUST(String::formatted("inspector.addAttributeToDOMNodeID({});", m_context_menu_data->dom_node_id)); - m_inspector_web_view.run_javascript(script); - - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_remove_dom_node_attribute() -{ - VERIFY(m_context_menu_data.has_value()); - VERIFY(m_context_menu_data->attribute.has_value()); - - m_content_web_view.replace_dom_node_attribute(m_context_menu_data->dom_node_id, m_context_menu_data->attribute->name, {}); - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_copy_dom_node_attribute_value() -{ - VERIFY(m_context_menu_data.has_value()); - VERIFY(m_context_menu_data->attribute.has_value()); - - if (m_content_web_view.on_insert_clipboard_entry) - m_content_web_view.on_insert_clipboard_entry(m_context_menu_data->attribute->value, "unspecified"_string, "text/plain"_string); - - m_context_menu_data.clear(); -} - -void InspectorClient::context_menu_delete_cookie() -{ - VERIFY(m_cookie_context_menu_index.has_value()); - VERIFY(*m_cookie_context_menu_index < m_cookies.size()); - - auto& cookie = m_cookies[*m_cookie_context_menu_index]; - cookie.expiry_time = UnixDateTime::earliest(); - - Application::cookie_jar().update_cookie(move(cookie)); - load_cookies(); - - m_cookie_context_menu_index.clear(); -} - -void InspectorClient::context_menu_delete_all_cookies() -{ - for (auto& cookie : m_cookies) { - cookie.expiry_time = UnixDateTime::earliest(); - - Application::cookie_jar().update_cookie(move(cookie)); - } - - load_cookies(); - - m_cookie_context_menu_index.clear(); -} - -void InspectorClient::load_inspector() -{ - auto inspector_html = MUST(Core::Resource::load_from_uri(INSPECTOR_HTML)); - - auto generate_property_table = [&](auto name) { - return MUST(String::formatted(R"~~~( -
- - - - - - - - - - -
NameValue
-
-)~~~", - name)); - }; - - StringBuilder builder; - - SourceGenerator generator { builder }; - generator.set("INSPECTOR_CSS"sv, INSPECTOR_CSS); - generator.set("INSPECTOR_JS"sv, INSPECTOR_JS); - generator.set("INSPECTOR_STYLE"sv, HTML_HIGHLIGHTER_STYLE); - generator.set("COMPUTED_STYLE"sv, generate_property_table("computed-style"sv)); - generator.set("RESOVLED_STYLE"sv, generate_property_table("resolved-style"sv)); - generator.set("CUSTOM_PROPERTIES"sv, generate_property_table("custom-properties"sv)); - generator.append(inspector_html->data()); - - m_inspector_web_view.load_html(generator.as_string_view()); -} - -template -static void generate_tree(StringBuilder& builder, JsonObject const& node, Generator&& generator) -{ - if (auto children = node.get_array("children"sv); children.has_value() && !children->is_empty()) { - auto name = node.get_string("name"sv).value_or({}); - builder.append("
"sv); - - builder.append(""sv); - generator(node); - builder.append(""sv); - - children->for_each([&](auto const& child) { - builder.append("
"sv); - generate_tree(builder, child.as_object(), generator); - builder.append("
"sv); - }); - - builder.append("
"sv); - } else { - generator(node); - } -} - -String InspectorClient::generate_dom_tree(JsonObject const& dom_tree) -{ - StringBuilder builder; - - generate_tree(builder, dom_tree, [&](JsonObject const& node) { - auto type = node.get_string("type"sv).value_or("unknown"_string); - auto name = node.get_string("name"sv).value_or({}); - - StringBuilder data_attributes; - auto append_data_attribute = [&](auto name, auto value) { - if (!data_attributes.is_empty()) - data_attributes.append(' '); - data_attributes.appendff("data-{}=\"{}\"", name, value); - }; - - i32 node_id = 0; - - if (auto pseudo_element = node.get_integer("pseudo-element"sv); pseudo_element.has_value()) { - node_id = node.get_integer("parent-id"sv).value(); - append_data_attribute("pseudo-element"sv, *pseudo_element); - } else { - node_id = node.get_integer("id"sv).value(); - } - - append_data_attribute("id"sv, node_id); - - if (type == "text"sv) { - auto deprecated_text = escape_html_entities(*node.get_string("text"sv)); - auto text = MUST(Web::Infra::strip_and_collapse_whitespace(deprecated_text)); - - builder.appendff("", data_attributes.string_view()); - - if (text.is_empty()) - builder.appendff("{}", name); - else - builder.append(text); - - builder.append(""sv); - return; - } - - if (type == "comment"sv) { - auto comment = escape_html_entities(*node.get_string("data"sv)); - - builder.appendff("", data_attributes.string_view()); - builder.append("<!--"sv); - builder.appendff("{}", comment); - builder.append("-->"sv); - builder.append(""sv); - return; - } - - if (type == "shadow-root"sv) { - auto mode = node.get_string("mode"sv).release_value(); - - builder.appendff("", data_attributes.string_view()); - builder.appendff("{} ({})", name, mode); - builder.append(""sv); - return; - } - - if (type != "element"sv) { - builder.appendff("", data_attributes.string_view()); - builder.appendff(name); - } else { - if (name.equals_ignoring_ascii_case("BODY"sv) || name.equals_ignoring_ascii_case("FRAMESET"sv)) - m_body_or_frameset_node_id = node_id; - - auto tag = name; - if (node.get_string("namespace"sv) == Web::Namespace::HTML.bytes_as_string_view()) - tag = MUST(tag.to_lowercase()); - - builder.appendff("", data_attributes.string_view()); - builder.append("<"sv); - builder.appendff("{0}", tag); - - if (auto attributes = node.get_object("attributes"sv); attributes.has_value()) { - attributes->for_each_member([&](auto const& name, auto const& value) { - auto& dom_node_attributes = m_dom_node_attributes.ensure(node_id); - auto value_string = value.as_string(); - - builder.append(" "sv); - builder.appendff("", tag, dom_node_attributes.size()); - builder.appendff("{}", escape_html_entities(name)); - builder.append('='); - builder.appendff("\"{}\"", escape_html_entities(value_string)); - builder.append(""sv); - - dom_node_attributes.empend(name, value_string); - }); - } - - builder.append(">"sv); - } - - // display miscellaneous extra bits of info about the element - Vector extra; - if (node.get_bool("scrollable"sv).value_or(false)) { - extra.append("scrollable"_string); - } - if (node.get_bool("invisible"sv).value_or(false)) { - extra.append("invisible"_string); - } - if (node.get_bool("stackingContext"sv).value_or(false)) { - extra.append("isolated"_string); - } - if (!extra.is_empty()) { - builder.append(" ("sv); - builder.append(extra[0]); - for (size_t i = 1; i < extra.size(); i++) { - builder.appendff(", {}", extra[i]); - } - builder.append(")"sv); - } - - builder.append(""sv); - }); - - return MUST(builder.to_string()); -} - -String InspectorClient::generate_accessibility_tree(JsonObject const& accessibility_tree) -{ - StringBuilder builder; - - generate_tree(builder, accessibility_tree, [&](JsonObject const& node) { - auto type = node.get_string("type"sv).value_or("unknown"_string); - auto role = node.get_string("role"sv).value_or({}); - - if (type == "text"sv) { - auto text = escape_html_entities(*node.get_string("text"sv)); - - builder.appendff(""); - builder.append(MUST(Web::Infra::strip_and_collapse_whitespace(text))); - builder.append(""sv); - return; - } - - if (type != "element"sv) { - builder.appendff(""); - builder.appendff(MUST(role.to_lowercase())); - builder.append(""sv); - return; - } - - auto name = node.get_string("name"sv).value_or({}); - auto description = node.get_string("description"sv).value_or({}); - - builder.appendff(""); - builder.append(MUST(role.to_lowercase())); - builder.appendff(" name: \"{}\", description: \"{}\"", name, description); - builder.append(""sv); - }); - - return MUST(builder.to_string()); -} - -void InspectorClient::request_console_messages() -{ - VERIFY(!m_waiting_for_messages); - - m_content_web_view.js_console_request_messages(m_highest_received_message_index + 1); - m_waiting_for_messages = true; -} - -void InspectorClient::console_message_available(i32 message_index) -{ - if (message_index <= m_highest_received_message_index) { - dbgln("Notified about console message we already have"); - return; - } - if (message_index <= m_highest_notified_message_index) { - dbgln("Notified about console message we're already aware of"); - return; - } - - m_highest_notified_message_index = message_index; - - if (!m_waiting_for_messages) - request_console_messages(); -} - -void InspectorClient::console_messages_received(i32 start_index, ReadonlySpan message_types, ReadonlySpan messages) -{ - auto end_index = start_index + static_cast(message_types.size()) - 1; - if (end_index <= m_highest_received_message_index) { - dbgln("Received old console messages"); - return; - } - - for (size_t i = 0; i < message_types.size(); ++i) { - auto const& type = message_types[i]; - auto const& message = messages[i]; - - if (type == "html"sv) - append_console_output(message); - else if (type == "clear"sv) - clear_console_output(); - else if (type == "group"sv) - begin_console_group(message, true); - else if (type == "groupCollapsed"sv) - begin_console_group(message, false); - else if (type == "groupEnd"sv) - end_console_group(); - else - VERIFY_NOT_REACHED(); - } - - m_highest_received_message_index = end_index; - m_waiting_for_messages = false; - - if (m_highest_received_message_index < m_highest_notified_message_index) - request_console_messages(); -} - -void InspectorClient::append_console_source(StringView source) -{ - StringBuilder builder; - builder.append(""sv); - builder.append(MUST(JS::MarkupGenerator::html_from_source(source))); - - append_console_output(builder.string_view()); -} - -void InspectorClient::append_console_message(StringView message) -{ - StringBuilder builder; - builder.append(""sv); - builder.appendff("{}", message); - - append_console_output(builder.string_view()); -} - -void InspectorClient::append_console_warning(StringView warning) -{ - StringBuilder builder; - builder.append(""sv); - builder.appendff("{}", warning); - - append_console_output(builder.string_view()); -} - -void InspectorClient::append_console_output(StringView html) -{ - auto html_base64 = MUST(encode_base64(html.bytes())); - - auto script = MUST(String::formatted("inspector.appendConsoleOutput(\"{}\");", html_base64)); - m_inspector_web_view.run_javascript(script); -} - -void InspectorClient::clear_console_output() -{ - static auto script = "inspector.clearConsoleOutput();"_string; - m_inspector_web_view.run_javascript(script); -} - -void InspectorClient::begin_console_group(StringView label, bool start_expanded) -{ - auto label_base64 = MUST(encode_base64(label.bytes())); - - auto script = MUST(String::formatted("inspector.beginConsoleGroup(\"{}\", {});", label_base64, start_expanded)); - m_inspector_web_view.run_javascript(script); -} - -void InspectorClient::end_console_group() -{ - static auto script = "inspector.endConsoleGroup();"_string; - m_inspector_web_view.run_javascript(script); -} - -} diff --git a/Libraries/LibWebView/InspectorClient.h b/Libraries/LibWebView/InspectorClient.h deleted file mode 100644 index 2216bacd743..00000000000 --- a/Libraries/LibWebView/InspectorClient.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2023, Tim Flynn - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#pragma once - -namespace WebView { - -class InspectorClient { -public: - InspectorClient(ViewImplementation& content_web_view, ViewImplementation& inspector_web_view); - ~InspectorClient(); - - void inspect(); - void reset(); - - void select_hovered_node(); - void select_default_node(); - void clear_selection(); - - void context_menu_edit_dom_node(); - void context_menu_copy_dom_node(); - void context_menu_screenshot_dom_node(); - void context_menu_create_child_element(); - void context_menu_create_child_text_node(); - void context_menu_clone_dom_node(); - void context_menu_remove_dom_node(); - void context_menu_add_dom_node_attribute(); - void context_menu_remove_dom_node_attribute(); - void context_menu_copy_dom_node_attribute_value(); - void context_menu_delete_cookie(); - void context_menu_delete_all_cookies(); - - Function on_requested_dom_node_text_context_menu; - Function on_requested_dom_node_tag_context_menu; - Function on_requested_dom_node_attribute_context_menu; - Function on_requested_cookie_context_menu; - -private: - void load_inspector(); - - String generate_dom_tree(JsonObject const&); - String generate_accessibility_tree(JsonObject const&); - void select_node(Web::UniqueNodeID); - - void load_cookies(); - - void request_console_messages(); - void console_message_available(i32 message_index); - void console_messages_received(i32 start_index, ReadonlySpan message_types, ReadonlySpan messages); - - void append_console_source(StringView); - void append_console_message(StringView); - void append_console_warning(StringView); - void append_console_output(StringView); - void clear_console_output(); - - void begin_console_group(StringView label, bool start_expanded); - void end_console_group(); - - ViewImplementation& m_content_web_view; - ViewImplementation& m_inspector_web_view; - - Optional m_body_or_frameset_node_id; - Optional m_pending_selection; - - bool m_inspector_loaded { false }; - bool m_dom_tree_loaded { false }; - - struct ContextMenuData { - Web::UniqueNodeID dom_node_id; - Optional tag; - Optional attribute; - }; - Optional m_context_menu_data; - - HashMap> m_dom_node_attributes; - - Vector m_cookies; - Optional m_cookie_context_menu_index; - - i32 m_highest_notified_message_index { -1 }; - i32 m_highest_received_message_index { -1 }; - bool m_waiting_for_messages { false }; -}; - -} diff --git a/Libraries/LibWebView/ViewImplementation.cpp b/Libraries/LibWebView/ViewImplementation.cpp index 3f6eb244da0..d16bc92ff33 100644 --- a/Libraries/LibWebView/ViewImplementation.cpp +++ b/Libraries/LibWebView/ViewImplementation.cpp @@ -779,9 +779,4 @@ void ViewImplementation::use_native_user_style_sheet() set_user_style_sheet(native_stylesheet_source); } -void ViewImplementation::enable_inspector_prototype() -{ - client().async_enable_inspector_prototype(page_id()); -} - } diff --git a/Libraries/LibWebView/ViewImplementation.h b/Libraries/LibWebView/ViewImplementation.h index f7bda02a300..c282e4806cf 100644 --- a/Libraries/LibWebView/ViewImplementation.h +++ b/Libraries/LibWebView/ViewImplementation.h @@ -180,8 +180,6 @@ public: // native GUI widgets as possible. void use_native_user_style_sheet(); - void enable_inspector_prototype(); - Function on_ready_to_paint; Function)> on_new_web_view; Function on_activate_tab; @@ -215,13 +213,12 @@ public: Function on_received_dom_tree; Function on_received_dom_node_properties; Function on_received_accessibility_tree; - Function)> on_received_style_sheet_list; - Function on_inspector_requested_style_sheet_source; - Function on_received_style_sheet_source; Function on_received_hovered_node_id; Function on_dom_mutation_received; Function const& node_id)> on_finshed_editing_dom_node; Function on_received_dom_node_html; + Function)> on_received_style_sheet_list; + Function on_received_style_sheet_source; Function on_received_js_console_result; Function on_console_message_available; Function const& message_types, Vector const& messages)> on_received_styled_console_messages; @@ -246,16 +243,6 @@ public: Function on_insert_clipboard_entry; Function on_audio_play_state_changed; Function on_navigation_buttons_state_changed; - Function on_inspector_loaded; - Function const&)> on_inspector_selected_dom_node; - Function on_inspector_set_dom_node_text; - Function on_inspector_set_dom_node_tag; - Function const&)> on_inspector_added_dom_node_attributes; - Function const&)> on_inspector_replaced_dom_node_attribute; - Function const&, Optional const&)> on_inspector_requested_dom_tree_context_menu; - Function on_inspector_requested_cookie_context_menu; - Function on_inspector_executed_console_script; - Function on_inspector_exported_inspector_html; Function on_web_content_crashed; virtual Web::DevicePixelSize viewport_size() const = 0; diff --git a/Libraries/LibWebView/WebContentClient.cpp b/Libraries/LibWebView/WebContentClient.cpp index 146140b2f06..d1fc80efa75 100644 --- a/Libraries/LibWebView/WebContentClient.cpp +++ b/Libraries/LibWebView/WebContentClient.cpp @@ -375,6 +375,22 @@ void WebContentClient::did_get_dom_node_html(u64 page_id, String html) } } +void WebContentClient::did_list_style_sheets(u64 page_id, Vector stylesheets) +{ + if (auto view = view_for_page_id(page_id); view.has_value()) { + if (view->on_received_style_sheet_list) + view->on_received_style_sheet_list(stylesheets); + } +} + +void WebContentClient::did_get_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier, URL::URL base_url, String source) +{ + if (auto view = view_for_page_id(page_id); view.has_value()) { + if (view->on_received_style_sheet_source) + view->on_received_style_sheet_source(identifier, base_url, source); + } +} + void WebContentClient::did_take_screenshot(u64 page_id, Gfx::ShareableBitmap screenshot) { if (auto view = view_for_page_id(page_id); view.has_value()) @@ -664,86 +680,6 @@ void WebContentClient::did_allocate_backing_stores(u64 page_id, i32 front_bitmap view->did_allocate_backing_stores({}, front_bitmap_id, front_bitmap, back_bitmap_id, back_bitmap); } -void WebContentClient::inspector_did_load(u64 page_id) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_loaded) - view->on_inspector_loaded(); - } -} - -void WebContentClient::inspector_did_select_dom_node(u64 page_id, Web::UniqueNodeID node_id, Optional pseudo_element) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_selected_dom_node) - view->on_inspector_selected_dom_node(node_id, pseudo_element); - } -} - -void WebContentClient::inspector_did_set_dom_node_text(u64 page_id, Web::UniqueNodeID node_id, String text) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_set_dom_node_text) - view->on_inspector_set_dom_node_text(node_id, text); - } -} - -void WebContentClient::inspector_did_set_dom_node_tag(u64 page_id, Web::UniqueNodeID node_id, String tag) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_set_dom_node_tag) - view->on_inspector_set_dom_node_tag(node_id, tag); - } -} - -void WebContentClient::inspector_did_add_dom_node_attributes(u64 page_id, Web::UniqueNodeID node_id, Vector attributes) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_added_dom_node_attributes) - view->on_inspector_added_dom_node_attributes(node_id, attributes); - } -} - -void WebContentClient::inspector_did_replace_dom_node_attribute(u64 page_id, Web::UniqueNodeID node_id, size_t attribute_index, Vector replacement_attributes) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_replaced_dom_node_attribute) - view->on_inspector_replaced_dom_node_attribute(node_id, attribute_index, replacement_attributes); - } -} - -void WebContentClient::inspector_did_request_dom_tree_context_menu(u64 page_id, Web::UniqueNodeID node_id, Gfx::IntPoint position, String type, Optional tag, Optional attribute_index) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_requested_dom_tree_context_menu) - view->on_inspector_requested_dom_tree_context_menu(node_id, view->to_widget_position(position), type, tag, attribute_index); - } -} - -void WebContentClient::inspector_did_request_cookie_context_menu(u64 page_id, size_t cookie_index, Gfx::IntPoint position) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_requested_cookie_context_menu) - view->on_inspector_requested_cookie_context_menu(cookie_index, view->to_widget_position(position)); - } -} - -void WebContentClient::inspector_did_execute_console_script(u64 page_id, String script) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_executed_console_script) - view->on_inspector_executed_console_script(script); - } -} - -void WebContentClient::inspector_did_export_inspector_html(u64 page_id, String html) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_exported_inspector_html) - view->on_inspector_exported_inspector_html(html); - } -} - Messages::WebContentClient::RequestWorkerAgentResponse WebContentClient::request_worker_agent(u64 page_id) { if (auto view = view_for_page_id(page_id); view.has_value()) { @@ -754,30 +690,6 @@ Messages::WebContentClient::RequestWorkerAgentResponse WebContentClient::request return IPC::File {}; } -void WebContentClient::inspector_did_list_style_sheets(u64 page_id, Vector stylesheets) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_received_style_sheet_list) - view->on_received_style_sheet_list(stylesheets); - } -} - -void WebContentClient::inspector_did_request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_inspector_requested_style_sheet_source) - view->on_inspector_requested_style_sheet_source(identifier); - } -} - -void WebContentClient::did_get_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier, URL::URL base_url, String source) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) { - if (view->on_received_style_sheet_source) - view->on_received_style_sheet_source(identifier, base_url, source); - } -} - Optional WebContentClient::view_for_page_id(u64 page_id, SourceLocation location) { // Don't bother logging anything for the spare WebContent process. It will only receive a load notification for about:blank. diff --git a/Libraries/LibWebView/WebContentClient.h b/Libraries/LibWebView/WebContentClient.h index 05d9ddecb6a..8cc8cfef325 100644 --- a/Libraries/LibWebView/WebContentClient.h +++ b/Libraries/LibWebView/WebContentClient.h @@ -83,6 +83,8 @@ private: virtual void did_finish_editing_dom_node(u64 page_id, Optional node_id) override; virtual void did_mutate_dom(u64 page_id, Mutation) override; virtual void did_get_dom_node_html(u64 page_id, String html) override; + virtual void did_list_style_sheets(u64 page_id, Vector stylesheets) override; + virtual void did_get_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier, URL::URL, String source) override; virtual void did_take_screenshot(u64 page_id, Gfx::ShareableBitmap screenshot) override; virtual void did_get_internal_page_info(u64 page_id, PageInfoType, String) override; virtual void did_execute_js_console_input(u64 page_id, JsonValue) override; @@ -126,20 +128,7 @@ private: virtual void did_change_audio_play_state(u64 page_id, Web::HTML::AudioPlayState) override; virtual void did_update_navigation_buttons_state(u64 page_id, bool back_enabled, bool forward_enabled) override; virtual void did_allocate_backing_stores(u64 page_id, i32 front_bitmap_id, Gfx::ShareableBitmap, i32 back_bitmap_id, Gfx::ShareableBitmap) override; - virtual void inspector_did_load(u64 page_id) override; - virtual void inspector_did_select_dom_node(u64 page_id, Web::UniqueNodeID node_id, Optional pseudo_element) override; - virtual void inspector_did_set_dom_node_text(u64 page_id, Web::UniqueNodeID node_id, String text) override; - virtual void inspector_did_set_dom_node_tag(u64 page_id, Web::UniqueNodeID node_id, String tag) override; - virtual void inspector_did_add_dom_node_attributes(u64 page_id, Web::UniqueNodeID node_id, Vector attributes) override; - virtual void inspector_did_replace_dom_node_attribute(u64 page_id, Web::UniqueNodeID node_id, size_t attribute_index, Vector replacement_attributes) override; - virtual void inspector_did_request_dom_tree_context_menu(u64 page_id, Web::UniqueNodeID node_id, Gfx::IntPoint position, String type, Optional tag, Optional attribute_index) override; - virtual void inspector_did_request_cookie_context_menu(u64 page_id, size_t cookie_index, Gfx::IntPoint position) override; - virtual void inspector_did_execute_console_script(u64 page_id, String script) override; - virtual void inspector_did_export_inspector_html(u64 page_id, String html) override; virtual Messages::WebContentClient::RequestWorkerAgentResponse request_worker_agent(u64 page_id) override; - virtual void inspector_did_list_style_sheets(u64 page_id, Vector stylesheets) override; - virtual void inspector_did_request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier) override; - virtual void did_get_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier, URL::URL, String source) override; Optional view_for_page_id(u64, SourceLocation = SourceLocation::current()); diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni index 2a80b1bf467..988a00992f0 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni @@ -261,7 +261,6 @@ standard_idl_files = [ "//Userland/Libraries/LibWeb/IndexedDB/IDBFactory.idl", "//Userland/Libraries/LibWeb/IndexedDB/IDBOpenDBRequest.idl", "//Userland/Libraries/LibWeb/IndexedDB/IDBRequest.idl", - "//Userland/Libraries/LibWeb/Internals/Inspector.idl", "//Userland/Libraries/LibWeb/Internals/InternalAnimationTimeline.idl", "//Userland/Libraries/LibWeb/Internals/Internals.idl", "//Userland/Libraries/LibWeb/IntersectionObserver/IntersectionObserver.idl", diff --git a/Services/WebContent/CMakeLists.txt b/Services/WebContent/CMakeLists.txt index 9da574227e3..652ddc009bc 100644 --- a/Services/WebContent/CMakeLists.txt +++ b/Services/WebContent/CMakeLists.txt @@ -5,7 +5,6 @@ set(SOURCES ConnectionFromClient.cpp ConsoleGlobalEnvironmentExtensions.cpp DevToolsConsoleClient.cpp - InspectorConsoleClient.cpp PageClient.cpp PageHost.cpp WebContentConsoleClient.cpp diff --git a/Services/WebContent/ConnectionFromClient.cpp b/Services/WebContent/ConnectionFromClient.cpp index 7be9cae59c3..f8c1a510acb 100644 --- a/Services/WebContent/ConnectionFromClient.cpp +++ b/Services/WebContent/ConnectionFromClient.cpp @@ -652,7 +652,7 @@ void ConnectionFromClient::list_style_sheets(u64 page_id) if (!page.has_value()) return; - async_inspector_did_list_style_sheets(page_id, page->list_style_sheets()); + async_did_list_style_sheets(page_id, page->list_style_sheets()); } void ConnectionFromClient::request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier) @@ -1323,11 +1323,6 @@ void ConnectionFromClient::set_user_style(u64 page_id, String source) page->page().set_user_style(move(source)); } -void ConnectionFromClient::enable_inspector_prototype(u64) -{ - Web::HTML::Window::set_inspector_object_exposed(true); -} - void ConnectionFromClient::system_time_zone_changed() { JS::clear_system_time_zone_cache(); diff --git a/Services/WebContent/ConnectionFromClient.h b/Services/WebContent/ConnectionFromClient.h index 9fa9b7c8f14..33688ecae18 100644 --- a/Services/WebContent/ConnectionFromClient.h +++ b/Services/WebContent/ConnectionFromClient.h @@ -135,8 +135,6 @@ private: virtual void set_user_style(u64 page_id, String) override; - virtual void enable_inspector_prototype(u64 page_id) override; - virtual void take_document_screenshot(u64 page_id) override; virtual void take_dom_node_screenshot(u64 page_id, Web::UniqueNodeID node_id) override; diff --git a/Services/WebContent/Forward.h b/Services/WebContent/Forward.h index b960f641806..215a41e60ef 100644 --- a/Services/WebContent/Forward.h +++ b/Services/WebContent/Forward.h @@ -11,7 +11,6 @@ namespace WebContent { class ConnectionFromClient; class ConsoleGlobalEnvironmentExtensions; class DevToolsConsoleClient; -class InspectorConsoleClient; class PageHost; class PageClient; class WebContentConsoleClient; diff --git a/Services/WebContent/InspectorConsoleClient.cpp b/Services/WebContent/InspectorConsoleClient.cpp deleted file mode 100644 index 92f5179fda9..00000000000 --- a/Services/WebContent/InspectorConsoleClient.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2021, Brandon Scott - * Copyright (c) 2020, Hunter Salyer - * Copyright (c) 2021-2022, Sam Atkins - * Copyright (c) 2024, Gasim Gasimzada - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace WebContent { - -GC_DEFINE_ALLOCATOR(InspectorConsoleClient); - -GC::Ref InspectorConsoleClient::create(JS::Realm& realm, JS::Console& console, PageClient& client) -{ - auto& window = as(realm.global_object()); - auto console_global_environment_extensions = realm.create(realm, window); - - return realm.heap().allocate(realm, console, client, console_global_environment_extensions); -} - -InspectorConsoleClient::InspectorConsoleClient(JS::Realm& realm, JS::Console& console, PageClient& client, ConsoleGlobalEnvironmentExtensions& console_global_environment_extensions) - : WebContentConsoleClient(realm, console, client, console_global_environment_extensions) -{ -} - -InspectorConsoleClient::~InspectorConsoleClient() = default; - -void InspectorConsoleClient::handle_result(JS::Value result) -{ - print_html(JS::MarkupGenerator::html_from_value(result).release_value_but_fixme_should_propagate_errors()); -} - -void InspectorConsoleClient::report_exception(JS::Error const& exception, bool in_promise) -{ - print_html(JS::MarkupGenerator::html_from_error(exception, in_promise).release_value_but_fixme_should_propagate_errors()); -} - -void InspectorConsoleClient::begin_group(String const& label, bool start_expanded) -{ - m_message_log.append({ .type = start_expanded ? ConsoleOutput::Type::BeginGroup : ConsoleOutput::Type::BeginGroupCollapsed, .data = label }); - m_client->did_output_js_console_message(m_message_log.size() - 1); -} - -void InspectorConsoleClient::end_group() -{ - m_message_log.append({ .type = ConsoleOutput::Type::EndGroup, .data = String {} }); - m_client->did_output_js_console_message(m_message_log.size() - 1); -} - -void InspectorConsoleClient::clear() -{ - m_message_log.append({ .type = ConsoleOutput::Type::Clear, .data = String {} }); - m_client->did_output_js_console_message(m_message_log.size() - 1); -} - -void InspectorConsoleClient::print_html(String const& line) -{ - m_message_log.append({ .type = ConsoleOutput::Type::HTML, .data = line }); - m_client->did_output_js_console_message(m_message_log.size() - 1); -} - -void InspectorConsoleClient::send_messages(i32 start_index) -{ - auto messages_to_send = m_message_log.size() - start_index; - if (messages_to_send < 1) { - // When the console is first created, it requests any messages that happened before then, by requesting with - // start_index=0. If we don't have any messages at all, that is still a valid request, and we can just ignore it. - if (start_index != 0) - m_client->console_peer_did_misbehave("Requested non-existent console message index"); - return; - } - - // FIXME: Replace with a single Vector of message structs - Vector message_types; - Vector messages; - message_types.ensure_capacity(messages_to_send); - messages.ensure_capacity(messages_to_send); - - for (size_t i = start_index; i < m_message_log.size(); i++) { - auto& message = m_message_log[i]; - switch (message.type) { - case ConsoleOutput::Type::HTML: - message_types.append("html"_string); - break; - case ConsoleOutput::Type::Clear: - message_types.append("clear"_string); - break; - case ConsoleOutput::Type::BeginGroup: - message_types.append("group"_string); - break; - case ConsoleOutput::Type::BeginGroupCollapsed: - message_types.append("groupCollapsed"_string); - break; - case ConsoleOutput::Type::EndGroup: - message_types.append("groupEnd"_string); - break; - } - - messages.append(message.data); - } - - m_client->did_get_styled_js_console_messages(start_index, message_types, messages); -} - -// 2.3. Printer(logLevel, args[, options]), https://console.spec.whatwg.org/#printer -JS::ThrowCompletionOr InspectorConsoleClient::printer(JS::Console::LogLevel log_level, PrinterArguments arguments) -{ - auto styling = escape_html_entities(m_current_message_style.string_view()); - m_current_message_style.clear(); - - if (log_level == JS::Console::LogLevel::Table) { - auto& vm = m_console->realm().vm(); - - auto table_args = arguments.get>(); - auto& table = table_args.at(0).as_object(); - auto& columns = TRY(table.get(vm.names.columns)).as_array().indexed_properties(); - auto& rows = TRY(table.get(vm.names.rows)).as_array().indexed_properties(); - - StringBuilder html; - - html.appendff("
"); - html.appendff(""); - html.appendff(""); - html.appendff(""); - for (auto const& col : columns) { - auto index = col.index(); - auto value = columns.storage()->get(index).value().value; - html.appendff("", value); - } - - html.appendff(""); - html.appendff(""); - html.appendff(""); - - for (auto const& row : rows) { - auto row_index = row.index(); - auto& row_obj = rows.storage()->get(row_index).value().value.as_object(); - html.appendff(""); - - for (auto const& col : columns) { - auto col_index = col.index(); - auto col_name = columns.storage()->get(col_index).value().value; - - auto property_key = TRY(JS::PropertyKey::from_value(vm, col_name)); - auto cell = TRY(row_obj.get(property_key)); - html.appendff(""); - } - - html.appendff(""); - } - - html.appendff(""); - html.appendff("
{}
"); - if (TRY(cell.is_array(vm))) { - AllocatingMemoryStream stream; - JS::PrintContext ctx { vm, stream, true }; - TRY_OR_THROW_OOM(vm, stream.write_until_depleted(" "sv.bytes())); - TRY_OR_THROW_OOM(vm, JS::print(cell, ctx)); - auto output = TRY_OR_THROW_OOM(vm, String::from_stream(stream, stream.used_buffer_size())); - - auto size = cell.as_array().indexed_properties().array_like_size(); - html.appendff("
Array({}){}
", size, output); - - } else if (cell.is_object()) { - AllocatingMemoryStream stream; - JS::PrintContext ctx { vm, stream, true }; - TRY_OR_THROW_OOM(vm, stream.write_until_depleted(" "sv.bytes())); - TRY_OR_THROW_OOM(vm, JS::print(cell, ctx)); - auto output = TRY_OR_THROW_OOM(vm, String::from_stream(stream, stream.used_buffer_size())); - - html.appendff("
Object({{...}}){}
", output); - } else if (cell.is_function() || cell.is_constructor()) { - html.appendff("ƒ"); - } else if (!cell.is_undefined()) { - html.appendff("{}", cell); - } - html.appendff("
"); - html.appendff("
"); - print_html(MUST(html.to_string())); - - auto output = TRY(generically_format_values(table_args)); - m_console->output_debug_message(log_level, output); - - return JS::js_undefined(); - } - - if (log_level == JS::Console::LogLevel::Trace) { - auto trace = arguments.get(); - StringBuilder html; - if (!trace.label.is_empty()) - html.appendff("{}
", styling, escape_html_entities(trace.label)); - - html.append(""sv); - for (auto& function_name : trace.stack) - html.appendff("-> {}
", escape_html_entities(function_name)); - html.append("
"sv); - - print_html(MUST(html.to_string())); - return JS::js_undefined(); - } - - if (log_level == JS::Console::LogLevel::Group || log_level == JS::Console::LogLevel::GroupCollapsed) { - auto group = arguments.get(); - begin_group(MUST(String::formatted("{}", styling, escape_html_entities(group.label))), log_level == JS::Console::LogLevel::Group); - return JS::js_undefined(); - } - - auto output = TRY(generically_format_values(arguments.get>())); - m_console->output_debug_message(log_level, output); - - StringBuilder html; - switch (log_level) { - case JS::Console::LogLevel::Debug: - html.appendff("(d) "sv, styling); - break; - case JS::Console::LogLevel::Error: - html.appendff("(e) "sv, styling); - break; - case JS::Console::LogLevel::Info: - html.appendff("(i) "sv, styling); - break; - case JS::Console::LogLevel::Log: - html.appendff(" "sv, styling); - break; - case JS::Console::LogLevel::Warn: - case JS::Console::LogLevel::CountReset: - html.appendff("(w) "sv, styling); - break; - default: - html.appendff(""sv, styling); - break; - } - - html.append(escape_html_entities(output)); - html.append(""sv); - print_html(MUST(html.to_string())); - - return JS::js_undefined(); -} - -} diff --git a/Services/WebContent/InspectorConsoleClient.h b/Services/WebContent/InspectorConsoleClient.h deleted file mode 100644 index b81b747de38..00000000000 --- a/Services/WebContent/InspectorConsoleClient.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2021, Brandon Scott - * Copyright (c) 2020, Hunter Salyer - * Copyright (c) 2021-2022, Sam Atkins - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace WebContent { - -class InspectorConsoleClient final : public WebContentConsoleClient { - GC_CELL(InspectorConsoleClient, WebContentConsoleClient); - GC_DECLARE_ALLOCATOR(InspectorConsoleClient); - -public: - static GC::Ref create(JS::Realm&, JS::Console&, PageClient&); - virtual ~InspectorConsoleClient() override; - -private: - InspectorConsoleClient(JS::Realm&, JS::Console&, PageClient&, ConsoleGlobalEnvironmentExtensions&); - - virtual void handle_result(JS::Value) override; - virtual void report_exception(JS::Error const&, bool) override; - - void begin_group(String const& label, bool start_expanded); - virtual void end_group() override; - virtual void clear() override; - - void print_html(String const& line); - - virtual void send_messages(i32 start_index) override; - virtual JS::ThrowCompletionOr printer(JS::Console::LogLevel log_level, PrinterArguments) override; - - virtual void add_css_style_to_current_message(StringView style) override - { - m_current_message_style.append(style); - m_current_message_style.append(';'); - } - - struct ConsoleOutput { - enum class Type { - HTML, - Clear, - BeginGroup, - BeginGroupCollapsed, - EndGroup, - }; - Type type; - String data; - }; - - Vector m_message_log; - StringBuilder m_current_message_style; -}; - -} diff --git a/Services/WebContent/PageClient.cpp b/Services/WebContent/PageClient.cpp index 3513357160b..60b095c71bb 100644 --- a/Services/WebContent/PageClient.cpp +++ b/Services/WebContent/PageClient.cpp @@ -9,30 +9,25 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include #include -#include #include #include -#include #include #include #include #include -#include -#include #include #include #include -#include #include #include #include @@ -42,7 +37,6 @@ namespace WebContent { static PageClient::UseSkiaPainter s_use_skia_painter = PageClient::UseSkiaPainter::GPUBackendIfAvailable; static bool s_is_headless { false }; -static bool s_devtools_enabled { false }; GC_DEFINE_ALLOCATOR(PageClient); @@ -61,11 +55,6 @@ void PageClient::set_is_headless(bool is_headless) s_is_headless = is_headless; } -void PageClient::set_devtools_enabled(bool devtools_enabled) -{ - s_devtools_enabled = devtools_enabled; -} - GC::Ref PageClient::create(JS::VM& vm, PageHost& page_host, u64 id) { return vm.heap().allocate(page_host, id); @@ -710,76 +699,6 @@ void PageClient::page_did_mutate_dom(FlyString const& type, Web::DOM::Node const client().async_did_mutate_dom(m_id, { type.to_string(), target.unique_id(), move(serialized_target), mutation.release_value() }); } -void PageClient::inspector_did_load() -{ - client().async_inspector_did_load(m_id); -} - -void PageClient::inspector_did_select_dom_node(Web::UniqueNodeID node_id, Optional const& pseudo_element) -{ - client().async_inspector_did_select_dom_node(m_id, node_id, pseudo_element); -} - -void PageClient::inspector_did_set_dom_node_text(Web::UniqueNodeID node_id, String const& text) -{ - client().async_inspector_did_set_dom_node_text(m_id, node_id, text); -} - -void PageClient::inspector_did_set_dom_node_tag(Web::UniqueNodeID node_id, String const& tag) -{ - client().async_inspector_did_set_dom_node_tag(m_id, node_id, tag); -} - -static Vector named_node_map_to_vector(GC::Ref map) -{ - Vector attributes; - attributes.ensure_capacity(map->length()); - - for (size_t i = 0; i < map->length(); ++i) { - auto const* attribute = map->item(i); - VERIFY(attribute); - - attributes.empend(attribute->name().to_string(), attribute->value()); - } - - return attributes; -} - -void PageClient::inspector_did_add_dom_node_attributes(Web::UniqueNodeID node_id, GC::Ref attributes) -{ - client().async_inspector_did_add_dom_node_attributes(m_id, node_id, named_node_map_to_vector(attributes)); -} - -void PageClient::inspector_did_replace_dom_node_attribute(Web::UniqueNodeID node_id, size_t attribute_index, GC::Ref replacement_attributes) -{ - client().async_inspector_did_replace_dom_node_attribute(m_id, node_id, attribute_index, named_node_map_to_vector(replacement_attributes)); -} - -void PageClient::inspector_did_request_dom_tree_context_menu(Web::UniqueNodeID node_id, Web::CSSPixelPoint position, String const& type, Optional const& tag, Optional const& attribute_index) -{ - client().async_inspector_did_request_dom_tree_context_menu(m_id, node_id, page().css_to_device_point(position).to_type(), type, tag, attribute_index); -} - -void PageClient::inspector_did_request_cookie_context_menu(size_t cookie_index, Web::CSSPixelPoint position) -{ - client().async_inspector_did_request_cookie_context_menu(m_id, cookie_index, page().css_to_device_point(position).to_type()); -} - -void PageClient::inspector_did_request_style_sheet_source(Web::CSS::StyleSheetIdentifier const& identifier) -{ - client().async_inspector_did_request_style_sheet_source(m_id, identifier); -} - -void PageClient::inspector_did_execute_console_script(String const& script) -{ - client().async_inspector_did_execute_console_script(m_id, script); -} - -void PageClient::inspector_did_export_inspector_html(String const& html) -{ - client().async_inspector_did_export_inspector_html(m_id, html); -} - ErrorOr PageClient::connect_to_webdriver(ByteString const& webdriver_ipc_path) { VERIFY(!m_webdriver); @@ -796,12 +715,7 @@ void PageClient::initialize_js_console(Web::DOM::Document& document) auto& realm = document.realm(); auto console_object = realm.intrinsics().console_object(); - GC::Ptr console_client; - if (s_devtools_enabled) - console_client = DevToolsConsoleClient::create(document.realm(), console_object->console(), *this); - else - console_client = InspectorConsoleClient::create(document.realm(), console_object->console(), *this); - + auto console_client = DevToolsConsoleClient::create(document.realm(), console_object->console(), *this); document.set_console_client(console_client); } diff --git a/Services/WebContent/PageClient.h b/Services/WebContent/PageClient.h index f3ea3df8a35..88a49d40b2c 100644 --- a/Services/WebContent/PageClient.h +++ b/Services/WebContent/PageClient.h @@ -38,8 +38,6 @@ public: virtual bool is_headless() const override; static void set_is_headless(bool); - static void set_devtools_enabled(bool); - virtual bool is_ready_to_paint() const override; virtual Web::Page& page() override { return *m_page; } @@ -176,17 +174,6 @@ private: virtual void page_did_allocate_backing_stores(i32 front_bitmap_id, Gfx::ShareableBitmap front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap back_bitmap) override; virtual IPC::File request_worker_agent() override; virtual void page_did_mutate_dom(FlyString const& type, Web::DOM::Node const& target, Web::DOM::NodeList& added_nodes, Web::DOM::NodeList& removed_nodes, GC::Ptr previous_sibling, GC::Ptr next_sibling, Optional const& attribute_name) override; - virtual void inspector_did_load() override; - virtual void inspector_did_select_dom_node(Web::UniqueNodeID, Optional const& pseudo_element) override; - virtual void inspector_did_set_dom_node_text(Web::UniqueNodeID, String const& text) override; - virtual void inspector_did_set_dom_node_tag(Web::UniqueNodeID, String const& tag) override; - virtual void inspector_did_add_dom_node_attributes(Web::UniqueNodeID, GC::Ref attributes) override; - virtual void inspector_did_replace_dom_node_attribute(Web::UniqueNodeID, size_t attribute_index, GC::Ref replacement_attributes) override; - virtual void inspector_did_request_dom_tree_context_menu(Web::UniqueNodeID, Web::CSSPixelPoint position, String const& type, Optional const& tag, Optional const& attribute_index) override; - virtual void inspector_did_request_cookie_context_menu(size_t cookie_index, Web::CSSPixelPoint position) override; - virtual void inspector_did_request_style_sheet_source(Web::CSS::StyleSheetIdentifier const& stylesheet_source) override; - virtual void inspector_did_execute_console_script(String const& script) override; - virtual void inspector_did_export_inspector_html(String const& script) override; Web::Layout::Viewport* layout_root(); void setup_palette(); diff --git a/Services/WebContent/WebContentClient.ipc b/Services/WebContent/WebContentClient.ipc index 42e71257772..fdbe8317a9c 100644 --- a/Services/WebContent/WebContentClient.ipc +++ b/Services/WebContent/WebContentClient.ipc @@ -59,8 +59,7 @@ endpoint WebContentClient did_mutate_dom(u64 page_id, WebView::Mutation mutation) =| did_get_dom_node_html(u64 page_id, String html) =| - inspector_did_list_style_sheets(u64 page_id, Vector style_sheets) =| - inspector_did_request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier) =| + did_list_style_sheets(u64 page_id, Vector style_sheets) =| did_get_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier, URL::URL base_url, String source) =| did_take_screenshot(u64 page_id, Gfx::ShareableBitmap screenshot) =| @@ -109,16 +108,4 @@ endpoint WebContentClient did_find_in_page(u64 page_id, size_t current_match_index, Optional total_match_count) =| request_worker_agent(u64 page_id) => (IPC::File socket) // FIXME: Add required attributes to select a SharedWorker Agent - - inspector_did_load(u64 page_id) =| - inspector_did_select_dom_node(u64 page_id, Web::UniqueNodeID node_id, Optional pseudo_element) =| - inspector_did_set_dom_node_text(u64 page_id, Web::UniqueNodeID node_id, String text) =| - inspector_did_set_dom_node_tag(u64 page_id, Web::UniqueNodeID node_id, String tag) =| - inspector_did_add_dom_node_attributes(u64 page_id, Web::UniqueNodeID node_id, Vector attributes) =| - inspector_did_replace_dom_node_attribute(u64 page_id, Web::UniqueNodeID node_id, size_t attribute_index, Vector replacement_attributes) =| - inspector_did_request_dom_tree_context_menu(u64 page_id, Web::UniqueNodeID node_id, Gfx::IntPoint position, String type, Optional tag, Optional attribute_index) =| - inspector_did_request_cookie_context_menu(u64 page_id, size_t cookie_index, Gfx::IntPoint position) =| - inspector_did_execute_console_script(u64 page_id, String script) =| - inspector_did_export_inspector_html(u64 page_id, String html) =| - } diff --git a/Services/WebContent/WebContentServer.ipc b/Services/WebContent/WebContentServer.ipc index 16d8ffd7d45..19f9d3fdf07 100644 --- a/Services/WebContent/WebContentServer.ipc +++ b/Services/WebContent/WebContentServer.ipc @@ -123,7 +123,5 @@ endpoint WebContentServer set_user_style(u64 page_id, String source) =| - enable_inspector_prototype(u64 page_id) =| - system_time_zone_changed() =| } diff --git a/Services/WebContent/main.cpp b/Services/WebContent/main.cpp index 07bfbff0397..16a7f9119e5 100644 --- a/Services/WebContent/main.cpp +++ b/Services/WebContent/main.cpp @@ -109,7 +109,6 @@ ErrorOr serenity_main(Main::Arguments arguments) bool collect_garbage_on_every_allocation = false; bool is_headless = false; bool disable_scrollbar_painting = false; - bool devtools = false; StringView echo_server_port_string_view {}; Core::ArgsParser args_parser; @@ -133,7 +132,6 @@ ErrorOr serenity_main(Main::Arguments arguments) args_parser.add_option(disable_scrollbar_painting, "Don't paint horizontal or vertical viewport scrollbars", "disable-scrollbar-painting"); args_parser.add_option(echo_server_port_string_view, "Echo server port used in test internals", "echo-server-port", 0, "echo_server_port"); args_parser.add_option(is_headless, "Report that the browser is running in headless mode", "headless"); - args_parser.add_option(devtools, "Report that the browser is running with Firefox DevTools support", "devtools"); args_parser.parse(arguments); @@ -160,7 +158,6 @@ ErrorOr serenity_main(Main::Arguments arguments) WebContent::PageClient::set_use_skia_painter(force_cpu_painting ? WebContent::PageClient::UseSkiaPainter::CPUBackend : WebContent::PageClient::UseSkiaPainter::GPUBackendIfAvailable); WebContent::PageClient::set_is_headless(is_headless); - WebContent::PageClient::set_devtools_enabled(devtools); if (disable_site_isolation) WebView::disable_site_isolation(); diff --git a/UI/cmake/ResourceFiles.cmake b/UI/cmake/ResourceFiles.cmake index eda7661aa5a..1447fe40223 100644 --- a/UI/cmake/ResourceFiles.cmake +++ b/UI/cmake/ResourceFiles.cmake @@ -61,11 +61,6 @@ list(TRANSFORM 48x48_ICONS PREPEND "${LADYBIRD_SOURCE_DIR}/Base/res/icons/48x48/ list(TRANSFORM 128x128_ICONS PREPEND "${LADYBIRD_SOURCE_DIR}/Base/res/icons/128x128/") list(TRANSFORM BROWSER_ICONS PREPEND "${LADYBIRD_SOURCE_DIR}/Base/res/icons/browser/") -set(WEB_RESOURCES - inspector.css - inspector.html - inspector.js -) set(ABOUT_PAGES about.html newtab.html @@ -75,7 +70,6 @@ set(WEB_TEMPLATES error.html version.html ) -list(TRANSFORM WEB_RESOURCES PREPEND "${LADYBIRD_SOURCE_DIR}/Base/res/ladybird/") list(TRANSFORM ABOUT_PAGES PREPEND "${LADYBIRD_SOURCE_DIR}/Base/res/ladybird/about-pages/") list(TRANSFORM WEB_TEMPLATES PREPEND "${LADYBIRD_SOURCE_DIR}/Base/res/ladybird/templates/") @@ -161,10 +155,6 @@ function(copy_resources_to_build base_directory bundle_target) DESTINATION ${base_directory} TARGET ${bundle_target} ) - copy_resource_set(ladybird RESOURCES ${WEB_RESOURCES} - DESTINATION ${base_directory} TARGET ${bundle_target} - ) - copy_resource_set(ladybird/about-pages RESOURCES ${ABOUT_PAGES} DESTINATION ${base_directory} TARGET ${bundle_target} ) @@ -191,7 +181,6 @@ function(install_ladybird_resources destination component) install(FILES ${128x128_ICONS} DESTINATION "${destination}/icons/128x128" COMPONENT ${component}) install(FILES ${BROWSER_ICONS} DESTINATION "${destination}/icons/browser" COMPONENT ${component}) install(FILES ${THEMES} DESTINATION "${destination}/themes" COMPONENT ${component}) - install(FILES ${WEB_RESOURCES} DESTINATION "${destination}/ladybird" COMPONENT ${component}) install(FILES ${ABOUT_PAGES} DESTINATION "${destination}/ladybird/about-pages" COMPONENT ${component}) install(FILES ${WEB_TEMPLATES} DESTINATION "${destination}/ladybird/templates" COMPONENT ${component}) install(FILES ${CONFIG_RESOURCES} DESTINATION "${destination}/ladybird/default-config" COMPONENT ${component})