| /* |
| * Copyright (C) 2016 Devin Rousso <webkit@devinrousso.com>. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| WI.appendContextMenuItemsForSourceCode = function(contextMenu, sourceCodeOrLocation) |
| { |
| console.assert(contextMenu instanceof WI.ContextMenu); |
| if (!(contextMenu instanceof WI.ContextMenu)) |
| return; |
| |
| let sourceCode = sourceCodeOrLocation; |
| let location = null; |
| if (sourceCodeOrLocation instanceof WI.SourceCodeLocation) { |
| sourceCode = sourceCodeOrLocation.sourceCode; |
| location = sourceCodeOrLocation; |
| } |
| |
| console.assert(sourceCode instanceof WI.SourceCode); |
| if (!(sourceCode instanceof WI.SourceCode)) |
| return; |
| |
| contextMenu.appendSeparator(); |
| |
| WI.appendContextMenuItemsForURL(contextMenu, sourceCode.url, {sourceCode, location}); |
| |
| if (sourceCode instanceof WI.Resource) { |
| if (sourceCode.urlComponents.scheme !== "data") { |
| contextMenu.appendItem(WI.UIString("Copy as cURL"), () => { |
| InspectorFrontendHost.copyText(sourceCode.generateCURLCommand()); |
| }); |
| |
| contextMenu.appendSeparator(); |
| |
| contextMenu.appendItem(WI.UIString("Copy HTTP Request"), () => { |
| InspectorFrontendHost.copyText(sourceCode.stringifyHTTPRequest()); |
| }); |
| |
| if (sourceCode.hasResponse()) { |
| contextMenu.appendItem(WI.UIString("Copy HTTP Response"), () => { |
| InspectorFrontendHost.copyText(sourceCode.stringifyHTTPResponse()); |
| }); |
| } |
| |
| contextMenu.appendSeparator(); |
| } |
| } |
| |
| contextMenu.appendItem(WI.UIString("Save File"), () => { |
| sourceCode.requestContent().then(() => { |
| const forceSaveAs = true; |
| WI.FileUtilities.save({ |
| url: sourceCode.url || "", |
| content: sourceCode.content |
| }, forceSaveAs); |
| }); |
| }); |
| |
| contextMenu.appendSeparator(); |
| |
| if (location && (sourceCode instanceof WI.Script || (sourceCode instanceof WI.Resource && sourceCode.type === WI.Resource.Type.Script))) { |
| let existingBreakpoint = WI.debuggerManager.breakpointForSourceCodeLocation(location); |
| if (existingBreakpoint) { |
| contextMenu.appendItem(WI.UIString("Delete Breakpoint"), () => { |
| WI.debuggerManager.removeBreakpoint(existingBreakpoint); |
| }); |
| } else { |
| contextMenu.appendItem(WI.UIString("Add Breakpoint"), () => { |
| WI.debuggerManager.addBreakpoint(new WI.Breakpoint(location)); |
| }); |
| } |
| |
| contextMenu.appendSeparator(); |
| } |
| }; |
| |
| WI.appendContextMenuItemsForURL = function(contextMenu, url, options = {}) |
| { |
| if (!url) |
| return; |
| |
| function showResourceWithOptions(options) { |
| if (options.location) |
| WI.showSourceCodeLocation(options.location, options); |
| else if (options.sourceCode) |
| WI.showSourceCode(options.sourceCode, options); |
| else |
| WI.openURL(url, options.frame, options); |
| } |
| |
| if (!url.startsWith("javascript:") && !url.startsWith("data:")) { |
| contextMenu.appendItem(WI.UIString("Open in New Tab"), () => { |
| const frame = null; |
| WI.openURL(url, frame, {alwaysOpenExternally: true}); |
| }); |
| } |
| |
| if (WI.networkManager.resourceForURL(url)) { |
| if (WI.settings.experimentalEnableSourcesTab.value) { |
| if (!WI.isShowingSourcesTab()) { |
| contextMenu.appendItem(WI.UIString("Reveal in Sources Tab"), () => { |
| showResourceWithOptions({preferredTabType: WI.SourcesTabContentView.Type}); |
| }); |
| } |
| } else { |
| if (!WI.isShowingResourcesTab()) { |
| contextMenu.appendItem(WI.UIString("Reveal in Resources Tab"), () => { |
| showResourceWithOptions({preferredTabType: WI.ResourcesTabContentView.Type}); |
| }); |
| } |
| } |
| if (!WI.isShowingNetworkTab()) { |
| contextMenu.appendItem(WI.UIString("Reveal in Network Tab"), () => { |
| showResourceWithOptions({preferredTabType: WI.NetworkTabContentView.Type}); |
| }); |
| } |
| } |
| |
| contextMenu.appendSeparator(); |
| |
| contextMenu.appendItem(WI.UIString("Copy Link"), () => { |
| InspectorFrontendHost.copyText(url); |
| }); |
| }; |
| |
| WI.appendContextMenuItemsForDOMNode = function(contextMenu, domNode, options = {}) |
| { |
| console.assert(contextMenu instanceof WI.ContextMenu); |
| if (!(contextMenu instanceof WI.ContextMenu)) |
| return; |
| |
| console.assert(domNode instanceof WI.DOMNode); |
| if (!(domNode instanceof WI.DOMNode)) |
| return; |
| |
| let copySubMenu = options.copySubMenu || contextMenu.appendSubMenuItem(WI.UIString("Copy")); |
| |
| let isElement = domNode.nodeType() === Node.ELEMENT_NODE; |
| let attached = domNode.attached; |
| |
| if (isElement && attached) { |
| copySubMenu.appendItem(WI.UIString("Selector Path"), () => { |
| let cssPath = WI.cssPath(domNode); |
| InspectorFrontendHost.copyText(cssPath); |
| }); |
| } |
| |
| if (!domNode.isPseudoElement() && attached) { |
| copySubMenu.appendItem(WI.UIString("XPath"), () => { |
| let xpath = WI.xpath(domNode); |
| InspectorFrontendHost.copyText(xpath); |
| }); |
| } |
| |
| contextMenu.appendSeparator(); |
| |
| if (domNode.isCustomElement()) { |
| contextMenu.appendItem(WI.UIString("Jump to Definition"), () => { |
| function didGetFunctionDetails(error, response) { |
| if (error) |
| return; |
| |
| let location = response.location; |
| let sourceCode = WI.debuggerManager.scriptForIdentifier(location.scriptId, WI.mainTarget); |
| if (!sourceCode) |
| return; |
| |
| let sourceCodeLocation = sourceCode.createSourceCodeLocation(location.lineNumber, location.columnNumber || 0); |
| WI.showSourceCodeLocation(sourceCodeLocation, { |
| ignoreNetworkTab: true, |
| ignoreSearchTab: true, |
| }); |
| } |
| |
| WI.RemoteObject.resolveNode(domNode).then((remoteObject) => { |
| remoteObject.getProperty("constructor", (error, result, wasThrown) => { |
| if (error) |
| return; |
| if (result.type === "function") |
| remoteObject.target.DebuggerAgent.getFunctionDetails(result.objectId, didGetFunctionDetails); |
| result.release(); |
| }); |
| remoteObject.release(); |
| }); |
| }); |
| |
| contextMenu.appendSeparator(); |
| } |
| |
| if (WI.domDebuggerManager.supported && isElement && !domNode.isPseudoElement() && attached) { |
| contextMenu.appendSeparator(); |
| |
| WI.appendContextMenuItemsForDOMNodeBreakpoints(contextMenu, domNode); |
| } |
| |
| contextMenu.appendSeparator(); |
| |
| if (!options.excludeLogElement && !domNode.isInUserAgentShadowTree() && !domNode.isPseudoElement()) { |
| let label = isElement ? WI.UIString("Log Element") : WI.UIString("Log Node"); |
| contextMenu.appendItem(label, () => { |
| WI.RemoteObject.resolveNode(domNode, WI.RuntimeManager.ConsoleObjectGroup).then((remoteObject) => { |
| let text = isElement ? WI.UIString("Selected Element") : WI.UIString("Selected Node"); |
| const addSpecialUserLogClass = true; |
| WI.consoleLogViewController.appendImmediateExecutionWithResult(text, remoteObject, addSpecialUserLogClass); |
| }); |
| }); |
| } |
| |
| if (!options.excludeRevealElement && window.DOMAgent && attached) { |
| contextMenu.appendItem(WI.UIString("Reveal in DOM Tree"), () => { |
| WI.domManager.inspectElement(domNode.id); |
| }); |
| } |
| |
| if (WI.settings.experimentalEnableLayersTab.value && window.LayerTreeAgent && attached) { |
| contextMenu.appendItem(WI.UIString("Reveal in Layers Tab"), () => { |
| WI.showLayersTab({nodeToSelect: domNode}); |
| }); |
| } |
| |
| if (window.PageAgent && attached) { |
| contextMenu.appendItem(WI.UIString("Capture Screenshot"), () => { |
| PageAgent.snapshotNode(domNode.id, (error, dataURL) => { |
| if (error) { |
| const target = WI.mainTarget; |
| const source = WI.ConsoleMessage.MessageSource.Other; |
| const level = WI.ConsoleMessage.MessageLevel.Error; |
| let consoleMessage = new WI.ConsoleMessage(target, source, level, error); |
| consoleMessage.shouldRevealConsole = true; |
| |
| WI.consoleLogViewController.appendConsoleMessage(consoleMessage); |
| return; |
| } |
| |
| WI.FileUtilities.save({ |
| url: WI.FileUtilities.inspectorURLForFilename(WI.FileUtilities.screenshotString() + ".png"), |
| content: parseDataURL(dataURL).data, |
| base64Encoded: true, |
| }); |
| }); |
| }); |
| } |
| |
| if (isElement && attached) { |
| contextMenu.appendItem(WI.UIString("Scroll Into View"), () => { |
| domNode.scrollIntoView(); |
| }); |
| } |
| |
| contextMenu.appendSeparator(); |
| }; |
| |
| WI.appendContextMenuItemsForDOMNodeBreakpoints = function(contextMenu, domNode, {allowEditing} = {}) |
| { |
| if (contextMenu.__domBreakpointItemsAdded) |
| return; |
| |
| contextMenu.__domBreakpointItemsAdded = true; |
| |
| let subMenu = contextMenu.appendSubMenuItem(WI.UIString("Break on\u2026")); |
| |
| let breakpoints = WI.domDebuggerManager.domBreakpointsForNode(domNode); |
| let keyValuePairs = breakpoints.map((breakpoint) => [breakpoint.type, breakpoint]); |
| let breakpointsByType = new Map(keyValuePairs); |
| |
| for (let type of Object.values(WI.DOMBreakpoint.Type)) { |
| let label = WI.DOMBreakpointTreeElement.displayNameForType(type); |
| let breakpoint = breakpointsByType.get(type); |
| |
| subMenu.appendCheckboxItem(label, function() { |
| if (breakpoint) |
| WI.domDebuggerManager.removeDOMBreakpoint(breakpoint); |
| else |
| WI.domDebuggerManager.addDOMBreakpoint(new WI.DOMBreakpoint(domNode, type)); |
| }, !!breakpoint, false); |
| } |
| |
| if (allowEditing) { |
| contextMenu.appendSeparator(); |
| |
| let shouldEnable = breakpoints.some((breakpoint) => breakpoint.disabled); |
| let label = shouldEnable ? WI.UIString("Enable Breakpoints") : WI.UIString("Disable Breakpoints"); |
| contextMenu.appendItem(label, () => { |
| breakpoints.forEach((breakpoint) => breakpoint.disabled = !shouldEnable); |
| }); |
| |
| contextMenu.appendItem(WI.UIString("Delete Breakpoints"), function() { |
| WI.domDebuggerManager.removeDOMBreakpointsForNode(domNode); |
| WI.domManager.removeEventListenerBreakpointsForNode(domNode); |
| }); |
| } |
| }; |