Index: chrome/tools/test/reference_build/chrome_linux/resources/inspector/InjectedScript.js |
diff --git a/chrome/tools/test/reference_build/chrome_linux/resources/inspector/InjectedScript.js b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/InjectedScript.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1c029c3827a76e39a7c797fcd254446cba89a713 |
--- /dev/null |
+++ b/chrome/tools/test/reference_build/chrome_linux/resources/inspector/InjectedScript.js |
@@ -0,0 +1,988 @@ |
+/* |
+ * Copyright (C) 2007 Apple Inc. 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. |
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
+ * its contributors may be used to endorse or promote products derived |
+ * from this software without specific prior written permission. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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. |
+ */ |
+ |
+var InjectedScript = {}; |
+ |
+// Called from within InspectorController on the 'inspected page' side. |
+InjectedScript.reset = function() |
+{ |
+ InjectedScript._styles = {}; |
+ InjectedScript._styleRules = {}; |
+ InjectedScript._lastStyleId = 0; |
+ InjectedScript._lastStyleRuleId = 0; |
+ InjectedScript._searchResults = []; |
+ InjectedScript._includedInSearchResultsPropertyName = "__includedInInspectorSearchResults"; |
+} |
+ |
+InjectedScript.reset(); |
+ |
+InjectedScript.getStyles = function(nodeId, authorOnly) |
+{ |
+ var node = InjectedScript._nodeForId(nodeId); |
+ if (!node) |
+ return false; |
+ var matchedRules = InjectedScript._window().getMatchedCSSRules(node, "", authorOnly); |
+ var matchedCSSRules = []; |
+ for (var i = 0; matchedRules && i < matchedRules.length; ++i) |
+ matchedCSSRules.push(InjectedScript._serializeRule(matchedRules[i])); |
+ |
+ var styleAttributes = {}; |
+ var attributes = node.attributes; |
+ for (var i = 0; attributes && i < attributes.length; ++i) { |
+ if (attributes[i].style) |
+ styleAttributes[attributes[i].name] = InjectedScript._serializeStyle(attributes[i].style, true); |
+ } |
+ var result = {}; |
+ result.inlineStyle = InjectedScript._serializeStyle(node.style, true); |
+ result.computedStyle = InjectedScript._serializeStyle(InjectedScript._window().getComputedStyle(node)); |
+ result.matchedCSSRules = matchedCSSRules; |
+ result.styleAttributes = styleAttributes; |
+ return result; |
+} |
+ |
+InjectedScript.getComputedStyle = function(nodeId) |
+{ |
+ var node = InjectedScript._nodeForId(nodeId); |
+ if (!node) |
+ return false; |
+ return InjectedScript._serializeStyle(InjectedScript._window().getComputedStyle(node)); |
+} |
+ |
+InjectedScript.getInlineStyle = function(nodeId) |
+{ |
+ var node = InjectedScript._nodeForId(nodeId); |
+ if (!node) |
+ return false; |
+ return InjectedScript._serializeStyle(node.style, true); |
+} |
+ |
+InjectedScript.applyStyleText = function(styleId, styleText, propertyName) |
+{ |
+ var style = InjectedScript._styles[styleId]; |
+ if (!style) |
+ return false; |
+ |
+ var styleTextLength = styleText.length; |
+ |
+ // Create a new element to parse the user input CSS. |
+ var parseElement = document.createElement("span"); |
+ parseElement.setAttribute("style", styleText); |
+ |
+ var tempStyle = parseElement.style; |
+ if (tempStyle.length || !styleTextLength) { |
+ // The input was parsable or the user deleted everything, so remove the |
+ // original property from the real style declaration. If this represents |
+ // a shorthand remove all the longhand properties. |
+ if (style.getPropertyShorthand(propertyName)) { |
+ var longhandProperties = InjectedScript._getLonghandProperties(style, propertyName); |
+ for (var i = 0; i < longhandProperties.length; ++i) |
+ style.removeProperty(longhandProperties[i]); |
+ } else |
+ style.removeProperty(propertyName); |
+ } |
+ |
+ if (!tempStyle.length) |
+ return false; |
+ |
+ // Iterate of the properties on the test element's style declaration and |
+ // add them to the real style declaration. We take care to move shorthands. |
+ var foundShorthands = {}; |
+ var changedProperties = []; |
+ var uniqueProperties = InjectedScript._getUniqueStyleProperties(tempStyle); |
+ for (var i = 0; i < uniqueProperties.length; ++i) { |
+ var name = uniqueProperties[i]; |
+ var shorthand = tempStyle.getPropertyShorthand(name); |
+ |
+ if (shorthand && shorthand in foundShorthands) |
+ continue; |
+ |
+ if (shorthand) { |
+ var value = InjectedScript._getShorthandValue(tempStyle, shorthand); |
+ var priority = InjectedScript._getShorthandPriority(tempStyle, shorthand); |
+ foundShorthands[shorthand] = true; |
+ } else { |
+ var value = tempStyle.getPropertyValue(name); |
+ var priority = tempStyle.getPropertyPriority(name); |
+ } |
+ |
+ // Set the property on the real style declaration. |
+ style.setProperty((shorthand || name), value, priority); |
+ changedProperties.push(shorthand || name); |
+ } |
+ return [InjectedScript._serializeStyle(style, true), changedProperties]; |
+} |
+ |
+InjectedScript.setStyleText = function(style, cssText) |
+{ |
+ style.cssText = cssText; |
+} |
+ |
+InjectedScript.toggleStyleEnabled = function(styleId, propertyName, disabled) |
+{ |
+ var style = InjectedScript._styles[styleId]; |
+ if (!style) |
+ return false; |
+ |
+ if (disabled) { |
+ if (!style.__disabledPropertyValues || !style.__disabledPropertyPriorities) { |
+ var inspectedWindow = InjectedScript._window(); |
+ style.__disabledProperties = new inspectedWindow.Object; |
+ style.__disabledPropertyValues = new inspectedWindow.Object; |
+ style.__disabledPropertyPriorities = new inspectedWindow.Object; |
+ } |
+ |
+ style.__disabledPropertyValues[propertyName] = style.getPropertyValue(propertyName); |
+ style.__disabledPropertyPriorities[propertyName] = style.getPropertyPriority(propertyName); |
+ |
+ if (style.getPropertyShorthand(propertyName)) { |
+ var longhandProperties = InjectedScript._getLonghandProperties(style, propertyName); |
+ for (var i = 0; i < longhandProperties.length; ++i) { |
+ style.__disabledProperties[longhandProperties[i]] = true; |
+ style.removeProperty(longhandProperties[i]); |
+ } |
+ } else { |
+ style.__disabledProperties[propertyName] = true; |
+ style.removeProperty(propertyName); |
+ } |
+ } else if (style.__disabledProperties && style.__disabledProperties[propertyName]) { |
+ var value = style.__disabledPropertyValues[propertyName]; |
+ var priority = style.__disabledPropertyPriorities[propertyName]; |
+ |
+ style.setProperty(propertyName, value, priority); |
+ delete style.__disabledProperties[propertyName]; |
+ delete style.__disabledPropertyValues[propertyName]; |
+ delete style.__disabledPropertyPriorities[propertyName]; |
+ } |
+ return InjectedScript._serializeStyle(style, true); |
+} |
+ |
+InjectedScript.applyStyleRuleText = function(ruleId, newContent, selectedNodeId) |
+{ |
+ var rule = InjectedScript._styleRules[ruleId]; |
+ if (!rule) |
+ return false; |
+ |
+ var selectedNode = InjectedScript._nodeForId(selectedNodeId); |
+ |
+ try { |
+ var stylesheet = rule.parentStyleSheet; |
+ stylesheet.addRule(newContent); |
+ var newRule = stylesheet.cssRules[stylesheet.cssRules.length - 1]; |
+ newRule.style.cssText = rule.style.cssText; |
+ |
+ var parentRules = stylesheet.cssRules; |
+ for (var i = 0; i < parentRules.length; ++i) { |
+ if (parentRules[i] === rule) { |
+ rule.parentStyleSheet.removeRule(i); |
+ break; |
+ } |
+ } |
+ |
+ return [InjectedScript._serializeRule(newRule), InjectedScript._doesSelectorAffectNode(newContent, selectedNode)]; |
+ } catch(e) { |
+ // Report invalid syntax. |
+ return false; |
+ } |
+} |
+ |
+InjectedScript.addStyleSelector = function(newContent, selectedNodeId) |
+{ |
+ var stylesheet = InjectedScript.stylesheet; |
+ if (!stylesheet) { |
+ var inspectedDocument = InjectedScript._window().document; |
+ var head = inspectedDocument.getElementsByTagName("head")[0]; |
+ var styleElement = inspectedDocument.createElement("style"); |
+ styleElement.type = "text/css"; |
+ head.appendChild(styleElement); |
+ stylesheet = inspectedDocument.styleSheets[inspectedDocument.styleSheets.length - 1]; |
+ InjectedScript.stylesheet = stylesheet; |
+ } |
+ |
+ try { |
+ stylesheet.addRule(newContent); |
+ } catch (e) { |
+ // Invalid Syntax for a Selector |
+ return false; |
+ } |
+ |
+ var selectedNode = InjectedScript._nodeForId(selectedNodeId); |
+ var rule = stylesheet.cssRules[stylesheet.cssRules.length - 1]; |
+ rule.__isViaInspector = true; |
+ |
+ return [ InjectedScript._serializeRule(rule), InjectedScript._doesSelectorAffectNode(newContent, selectedNode) ]; |
+} |
+ |
+InjectedScript._doesSelectorAffectNode = function(selectorText, node) |
+{ |
+ if (!node) |
+ return false; |
+ var nodes = node.ownerDocument.querySelectorAll(selectorText); |
+ for (var i = 0; i < nodes.length; ++i) { |
+ if (nodes[i] === node) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+InjectedScript.setStyleProperty = function(styleId, name, value) |
+{ |
+ var style = InjectedScript._styles[styleId]; |
+ if (!style) |
+ return false; |
+ |
+ style.setProperty(name, value, ""); |
+ return true; |
+} |
+ |
+InjectedScript._serializeRule = function(rule) |
+{ |
+ var parentStyleSheet = rule.parentStyleSheet; |
+ |
+ var ruleValue = {}; |
+ ruleValue.selectorText = rule.selectorText; |
+ if (parentStyleSheet) { |
+ ruleValue.parentStyleSheet = {}; |
+ ruleValue.parentStyleSheet.href = parentStyleSheet.href; |
+ } |
+ ruleValue.isUserAgent = parentStyleSheet && !parentStyleSheet.ownerNode && !parentStyleSheet.href; |
+ ruleValue.isUser = parentStyleSheet && parentStyleSheet.ownerNode && parentStyleSheet.ownerNode.nodeName == "#document"; |
+ ruleValue.isViaInspector = !!rule.__isViaInspector; |
+ |
+ // Bind editable scripts only. |
+ var doBind = !ruleValue.isUserAgent && !ruleValue.isUser; |
+ ruleValue.style = InjectedScript._serializeStyle(rule.style, doBind); |
+ |
+ if (doBind) { |
+ if (!rule.id) { |
+ rule.id = InjectedScript._lastStyleRuleId++; |
+ InjectedScript._styleRules[rule.id] = rule; |
+ } |
+ ruleValue.id = rule.id; |
+ } |
+ return ruleValue; |
+} |
+ |
+InjectedScript._serializeStyle = function(style, doBind) |
+{ |
+ var result = {}; |
+ result.width = style.width; |
+ result.height = style.height; |
+ result.__disabledProperties = style.__disabledProperties; |
+ result.__disabledPropertyValues = style.__disabledPropertyValues; |
+ result.__disabledPropertyPriorities = style.__disabledPropertyPriorities; |
+ result.properties = []; |
+ result.shorthandValues = {}; |
+ var foundShorthands = {}; |
+ for (var i = 0; i < style.length; ++i) { |
+ var property = {}; |
+ var name = style[i]; |
+ property.name = name; |
+ property.priority = style.getPropertyPriority(name); |
+ property.implicit = style.isPropertyImplicit(name); |
+ var shorthand = style.getPropertyShorthand(name); |
+ property.shorthand = shorthand; |
+ if (shorthand && !(shorthand in foundShorthands)) { |
+ foundShorthands[shorthand] = true; |
+ result.shorthandValues[shorthand] = InjectedScript._getShorthandValue(style, shorthand); |
+ } |
+ property.value = style.getPropertyValue(name); |
+ result.properties.push(property); |
+ } |
+ result.uniqueStyleProperties = InjectedScript._getUniqueStyleProperties(style); |
+ |
+ if (doBind) { |
+ if (!style.id) { |
+ style.id = InjectedScript._lastStyleId++; |
+ InjectedScript._styles[style.id] = style; |
+ } |
+ result.id = style.id; |
+ } |
+ return result; |
+} |
+ |
+InjectedScript._getUniqueStyleProperties = function(style) |
+{ |
+ var properties = []; |
+ var foundProperties = {}; |
+ |
+ for (var i = 0; i < style.length; ++i) { |
+ var property = style[i]; |
+ if (property in foundProperties) |
+ continue; |
+ foundProperties[property] = true; |
+ properties.push(property); |
+ } |
+ |
+ return properties; |
+} |
+ |
+ |
+InjectedScript._getLonghandProperties = function(style, shorthandProperty) |
+{ |
+ var properties = []; |
+ var foundProperties = {}; |
+ |
+ for (var i = 0; i < style.length; ++i) { |
+ var individualProperty = style[i]; |
+ if (individualProperty in foundProperties || style.getPropertyShorthand(individualProperty) !== shorthandProperty) |
+ continue; |
+ foundProperties[individualProperty] = true; |
+ properties.push(individualProperty); |
+ } |
+ |
+ return properties; |
+} |
+ |
+InjectedScript._getShorthandValue = function(style, shorthandProperty) |
+{ |
+ var value = style.getPropertyValue(shorthandProperty); |
+ if (!value) { |
+ // Some shorthands (like border) return a null value, so compute a shorthand value. |
+ // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15823 is fixed. |
+ |
+ var foundProperties = {}; |
+ for (var i = 0; i < style.length; ++i) { |
+ var individualProperty = style[i]; |
+ if (individualProperty in foundProperties || style.getPropertyShorthand(individualProperty) !== shorthandProperty) |
+ continue; |
+ |
+ var individualValue = style.getPropertyValue(individualProperty); |
+ if (style.isPropertyImplicit(individualProperty) || individualValue === "initial") |
+ continue; |
+ |
+ foundProperties[individualProperty] = true; |
+ |
+ if (!value) |
+ value = ""; |
+ else if (value.length) |
+ value += " "; |
+ value += individualValue; |
+ } |
+ } |
+ return value; |
+} |
+ |
+InjectedScript._getShorthandPriority = function(style, shorthandProperty) |
+{ |
+ var priority = style.getPropertyPriority(shorthandProperty); |
+ if (!priority) { |
+ for (var i = 0; i < style.length; ++i) { |
+ var individualProperty = style[i]; |
+ if (style.getPropertyShorthand(individualProperty) !== shorthandProperty) |
+ continue; |
+ priority = style.getPropertyPriority(individualProperty); |
+ break; |
+ } |
+ } |
+ return priority; |
+} |
+ |
+InjectedScript.getPrototypes = function(nodeId) |
+{ |
+ var node = InjectedScript._nodeForId(nodeId); |
+ if (!node) |
+ return false; |
+ |
+ var result = []; |
+ for (var prototype = node; prototype; prototype = prototype.__proto__) { |
+ var title = Object.describe(prototype); |
+ if (title.match(/Prototype$/)) { |
+ title = title.replace(/Prototype$/, ""); |
+ } |
+ result.push(title); |
+ } |
+ return result; |
+} |
+ |
+InjectedScript.getProperties = function(objectProxy, ignoreHasOwnProperty) |
+{ |
+ var object = InjectedScript._resolveObject(objectProxy); |
+ if (!object) |
+ return false; |
+ |
+ var properties = []; |
+ |
+ // Go over properties, prepare results. |
+ for (var propertyName in object) { |
+ if (!ignoreHasOwnProperty && "hasOwnProperty" in object && !object.hasOwnProperty(propertyName)) |
+ continue; |
+ |
+ var property = {}; |
+ property.name = propertyName; |
+ property.parentObjectProxy = objectProxy; |
+ var isGetter = object["__lookupGetter__"] && object.__lookupGetter__(propertyName); |
+ if (!property.isGetter) { |
+ var childObject = object[propertyName]; |
+ var childObjectProxy = new InjectedScript.createProxyObject(childObject, objectProxy.objectId, true); |
+ childObjectProxy.path = objectProxy.path ? objectProxy.path.slice() : []; |
+ childObjectProxy.path.push(propertyName); |
+ childObjectProxy.protoDepth = objectProxy.protoDepth || 0; |
+ property.value = childObjectProxy; |
+ } else { |
+ // FIXME: this should show something like "getter" (bug 16734). |
+ property.value = { description: "\u2014" }; // em dash |
+ property.isGetter = true; |
+ } |
+ properties.push(property); |
+ } |
+ return properties; |
+} |
+ |
+InjectedScript.setPropertyValue = function(objectProxy, propertyName, expression) |
+{ |
+ var object = InjectedScript._resolveObject(objectProxy); |
+ if (!object) |
+ return false; |
+ |
+ var expressionLength = expression.length; |
+ if (!expressionLength) { |
+ delete object[propertyName]; |
+ return !(propertyName in object); |
+ } |
+ |
+ try { |
+ // Surround the expression in parenthesis so the result of the eval is the result |
+ // of the whole expression not the last potential sub-expression. |
+ |
+ // There is a regression introduced here: eval is now happening against global object, |
+ // not call frame while on a breakpoint. |
+ // TODO: bring evaluation against call frame back. |
+ var result = InjectedScript._window().eval("(" + expression + ")"); |
+ // Store the result in the property. |
+ object[propertyName] = result; |
+ return true; |
+ } catch(e) { |
+ try { |
+ var result = InjectedScript._window().eval("\"" + expression.escapeCharacters("\"") + "\""); |
+ object[propertyName] = result; |
+ return true; |
+ } catch(e) { |
+ return false; |
+ } |
+ } |
+} |
+ |
+InjectedScript.evaluate = function(expression) |
+{ |
+ return InjectedScript._evaluateOn(InjectedScript._window().eval, InjectedScript._window(), expression); |
+} |
+ |
+InjectedScript._evaluateOn = function(evalFunction, object, expression) |
+{ |
+ InjectedScript._ensureCommandLineAPIInstalled(); |
+ // Surround the expression in with statements to inject our command line API so that |
+ // the window object properties still take more precedent than our API functions. |
+ expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }"; |
+ |
+ var result = {}; |
+ try { |
+ var value = evalFunction.call(object, expression); |
+ if (value === null) |
+ return { value: null }; |
+ var value = evalFunction.call(object, expression); |
+ var wrapper = InspectorController.wrapObject(value); |
+ if (typeof wrapper === "object" && wrapper.exception) { |
+ result.value = wrapper.exception; |
+ result.isException = true; |
+ } else { |
+ result.value = wrapper; |
+ } |
+ } catch (e) { |
+ result.value = e.toString(); |
+ result.isException = true; |
+ } |
+ return result; |
+} |
+ |
+InjectedScript.addInspectedNode = function(nodeId) |
+{ |
+ var node = InjectedScript._nodeForId(nodeId); |
+ if (!node) |
+ return false; |
+ |
+ InjectedScript._ensureCommandLineAPIInstalled(); |
+ var inspectedNodes = InjectedScript._window()._inspectorCommandLineAPI._inspectedNodes; |
+ inspectedNodes.unshift(node); |
+ if (inspectedNodes.length >= 5) |
+ inspectedNodes.pop(); |
+ return true; |
+} |
+ |
+InjectedScript.performSearch = function(whitespaceTrimmedQuery) |
+{ |
+ var tagNameQuery = whitespaceTrimmedQuery; |
+ var attributeNameQuery = whitespaceTrimmedQuery; |
+ var startTagFound = (tagNameQuery.indexOf("<") === 0); |
+ var endTagFound = (tagNameQuery.lastIndexOf(">") === (tagNameQuery.length - 1)); |
+ |
+ if (startTagFound || endTagFound) { |
+ var tagNameQueryLength = tagNameQuery.length; |
+ tagNameQuery = tagNameQuery.substring((startTagFound ? 1 : 0), (endTagFound ? (tagNameQueryLength - 1) : tagNameQueryLength)); |
+ } |
+ |
+ // Check the tagNameQuery is it is a possibly valid tag name. |
+ if (!/^[a-zA-Z0-9\-_:]+$/.test(tagNameQuery)) |
+ tagNameQuery = null; |
+ |
+ // Check the attributeNameQuery is it is a possibly valid tag name. |
+ if (!/^[a-zA-Z0-9\-_:]+$/.test(attributeNameQuery)) |
+ attributeNameQuery = null; |
+ |
+ const escapedQuery = whitespaceTrimmedQuery.escapeCharacters("'"); |
+ const escapedTagNameQuery = (tagNameQuery ? tagNameQuery.escapeCharacters("'") : null); |
+ const escapedWhitespaceTrimmedQuery = whitespaceTrimmedQuery.escapeCharacters("'"); |
+ const searchResultsProperty = InjectedScript._includedInSearchResultsPropertyName; |
+ |
+ function addNodesToResults(nodes, length, getItem) |
+ { |
+ if (!length) |
+ return; |
+ |
+ var nodeIds = []; |
+ for (var i = 0; i < length; ++i) { |
+ var node = getItem.call(nodes, i); |
+ // Skip this node if it already has the property. |
+ if (searchResultsProperty in node) |
+ continue; |
+ |
+ if (!InjectedScript._searchResults.length) { |
+ InjectedScript._currentSearchResultIndex = 0; |
+ } |
+ |
+ node[searchResultsProperty] = true; |
+ InjectedScript._searchResults.push(node); |
+ var nodeId = InspectorController.pushNodePathToFrontend(node, false); |
+ nodeIds.push(nodeId); |
+ } |
+ InspectorController.addNodesToSearchResult(nodeIds.join(",")); |
+ } |
+ |
+ function matchExactItems(doc) |
+ { |
+ matchExactId.call(this, doc); |
+ matchExactClassNames.call(this, doc); |
+ matchExactTagNames.call(this, doc); |
+ matchExactAttributeNames.call(this, doc); |
+ } |
+ |
+ function matchExactId(doc) |
+ { |
+ const result = doc.__proto__.getElementById.call(doc, whitespaceTrimmedQuery); |
+ addNodesToResults.call(this, result, (result ? 1 : 0), function() { return this }); |
+ } |
+ |
+ function matchExactClassNames(doc) |
+ { |
+ const result = doc.__proto__.getElementsByClassName.call(doc, whitespaceTrimmedQuery); |
+ addNodesToResults.call(this, result, result.length, result.item); |
+ } |
+ |
+ function matchExactTagNames(doc) |
+ { |
+ if (!tagNameQuery) |
+ return; |
+ const result = doc.__proto__.getElementsByTagName.call(doc, tagNameQuery); |
+ addNodesToResults.call(this, result, result.length, result.item); |
+ } |
+ |
+ function matchExactAttributeNames(doc) |
+ { |
+ if (!attributeNameQuery) |
+ return; |
+ const result = doc.__proto__.querySelectorAll.call(doc, "[" + attributeNameQuery + "]"); |
+ addNodesToResults.call(this, result, result.length, result.item); |
+ } |
+ |
+ function matchPartialTagNames(doc) |
+ { |
+ if (!tagNameQuery) |
+ return; |
+ const result = doc.__proto__.evaluate.call(doc, "//*[contains(name(), '" + escapedTagNameQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); |
+ addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); |
+ } |
+ |
+ function matchStartOfTagNames(doc) |
+ { |
+ if (!tagNameQuery) |
+ return; |
+ const result = doc.__proto__.evaluate.call(doc, "//*[starts-with(name(), '" + escapedTagNameQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); |
+ addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); |
+ } |
+ |
+ function matchPartialTagNamesAndAttributeValues(doc) |
+ { |
+ if (!tagNameQuery) { |
+ matchPartialAttributeValues.call(this, doc); |
+ return; |
+ } |
+ |
+ const result = doc.__proto__.evaluate.call(doc, "//*[contains(name(), '" + escapedTagNameQuery + "') or contains(@*, '" + escapedQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); |
+ addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); |
+ } |
+ |
+ function matchPartialAttributeValues(doc) |
+ { |
+ const result = doc.__proto__.evaluate.call(doc, "//*[contains(@*, '" + escapedQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); |
+ addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); |
+ } |
+ |
+ function matchStyleSelector(doc) |
+ { |
+ const result = doc.__proto__.querySelectorAll.call(doc, whitespaceTrimmedQuery); |
+ addNodesToResults.call(this, result, result.length, result.item); |
+ } |
+ |
+ function matchPlainText(doc) |
+ { |
+ const result = doc.__proto__.evaluate.call(doc, "//text()[contains(., '" + escapedQuery + "')] | //comment()[contains(., '" + escapedQuery + "')]", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); |
+ addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); |
+ } |
+ |
+ function matchXPathQuery(doc) |
+ { |
+ const result = doc.__proto__.evaluate.call(doc, whitespaceTrimmedQuery, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); |
+ addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem); |
+ } |
+ |
+ function finishedSearching() |
+ { |
+ // Remove the searchResultsProperty now that the search is finished. |
+ for (var i = 0; i < InjectedScript._searchResults.length; ++i) |
+ delete InjectedScript._searchResults[i][searchResultsProperty]; |
+ } |
+ |
+ const mainFrameDocument = InjectedScript._window().document; |
+ const searchDocuments = [mainFrameDocument]; |
+ var searchFunctions; |
+ if (tagNameQuery && startTagFound && endTagFound) |
+ searchFunctions = [matchExactTagNames, matchPlainText]; |
+ else if (tagNameQuery && startTagFound) |
+ searchFunctions = [matchStartOfTagNames, matchPlainText]; |
+ else if (tagNameQuery && endTagFound) { |
+ // FIXME: we should have a matchEndOfTagNames search function if endTagFound is true but not startTagFound. |
+ // This requires ends-with() support in XPath, WebKit only supports starts-with() and contains(). |
+ searchFunctions = [matchPartialTagNames, matchPlainText]; |
+ } else if (whitespaceTrimmedQuery === "//*" || whitespaceTrimmedQuery === "*") { |
+ // These queries will match every node. Matching everything isn't useful and can be slow for large pages, |
+ // so limit the search functions list to plain text and attribute matching. |
+ searchFunctions = [matchPartialAttributeValues, matchPlainText]; |
+ } else |
+ searchFunctions = [matchExactItems, matchStyleSelector, matchPartialTagNamesAndAttributeValues, matchPlainText, matchXPathQuery]; |
+ |
+ // Find all frames, iframes and object elements to search their documents. |
+ const querySelectorAllFunction = InjectedScript._window().Document.prototype.querySelectorAll; |
+ const subdocumentResult = querySelectorAllFunction.call(mainFrameDocument, "iframe, frame, object"); |
+ |
+ for (var i = 0; i < subdocumentResult.length; ++i) { |
+ var element = subdocumentResult.item(i); |
+ if (element.contentDocument) |
+ searchDocuments.push(element.contentDocument); |
+ } |
+ |
+ const panel = InjectedScript; |
+ var documentIndex = 0; |
+ var searchFunctionIndex = 0; |
+ var chunkIntervalIdentifier = null; |
+ |
+ // Split up the work into chunks so we don't block the UI thread while processing. |
+ |
+ function processChunk() |
+ { |
+ var searchDocument = searchDocuments[documentIndex]; |
+ var searchFunction = searchFunctions[searchFunctionIndex]; |
+ |
+ if (++searchFunctionIndex > searchFunctions.length) { |
+ searchFunction = searchFunctions[0]; |
+ searchFunctionIndex = 0; |
+ |
+ if (++documentIndex > searchDocuments.length) { |
+ if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier) |
+ delete panel._currentSearchChunkIntervalIdentifier; |
+ clearInterval(chunkIntervalIdentifier); |
+ finishedSearching.call(panel); |
+ return; |
+ } |
+ |
+ searchDocument = searchDocuments[documentIndex]; |
+ } |
+ |
+ if (!searchDocument || !searchFunction) |
+ return; |
+ |
+ try { |
+ searchFunction.call(panel, searchDocument); |
+ } catch(err) { |
+ // ignore any exceptions. the query might be malformed, but we allow that. |
+ } |
+ } |
+ |
+ processChunk(); |
+ |
+ chunkIntervalIdentifier = setInterval(processChunk, 25); |
+ InjectedScript._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier; |
+ return true; |
+} |
+ |
+InjectedScript.searchCanceled = function() |
+{ |
+ if (InjectedScript._searchResults) { |
+ const searchResultsProperty = InjectedScript._includedInSearchResultsPropertyName; |
+ for (var i = 0; i < this._searchResults.length; ++i) { |
+ var node = this._searchResults[i]; |
+ |
+ // Remove the searchResultsProperty since there might be an unfinished search. |
+ delete node[searchResultsProperty]; |
+ } |
+ } |
+ |
+ if (InjectedScript._currentSearchChunkIntervalIdentifier) { |
+ clearInterval(InjectedScript._currentSearchChunkIntervalIdentifier); |
+ delete InjectedScript._currentSearchChunkIntervalIdentifier; |
+ } |
+ InjectedScript._searchResults = []; |
+ return true; |
+} |
+ |
+InjectedScript.openInInspectedWindow = function(url) |
+{ |
+ InjectedScript._window().open(url); |
+} |
+ |
+InjectedScript.getCallFrames = function() |
+{ |
+ var callFrame = InspectorController.currentCallFrame(); |
+ if (!callFrame) |
+ return false; |
+ |
+ var result = []; |
+ var depth = 0; |
+ do { |
+ result.push(new InjectedScript.CallFrameProxy(depth++, callFrame)); |
+ callFrame = callFrame.caller; |
+ } while (callFrame); |
+ return result; |
+} |
+ |
+InjectedScript.evaluateInCallFrame = function(callFrameId, code) |
+{ |
+ var callFrame = InjectedScript._callFrameForId(callFrameId); |
+ if (!callFrame) |
+ return false; |
+ return InjectedScript._evaluateOn(callFrame.evaluate, callFrame, code); |
+} |
+ |
+InjectedScript._callFrameForId = function(id) |
+{ |
+ var callFrame = InspectorController.currentCallFrame(); |
+ while (--id >= 0 && callFrame) |
+ callFrame = callFrame.caller; |
+ return callFrame; |
+} |
+ |
+InjectedScript._ensureCommandLineAPIInstalled = function(inspectedWindow) |
+{ |
+ var inspectedWindow = InjectedScript._window(); |
+ if (inspectedWindow._inspectorCommandLineAPI) |
+ return; |
+ |
+ inspectedWindow.eval("window._inspectorCommandLineAPI = { \ |
+ $: function() { return document.getElementById.apply(document, arguments) }, \ |
+ $$: function() { return document.querySelectorAll.apply(document, arguments) }, \ |
+ $x: function(xpath, context) { \ |
+ var nodes = []; \ |
+ try { \ |
+ var doc = context || document; \ |
+ var results = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); \ |
+ var node; \ |
+ while (node = results.iterateNext()) nodes.push(node); \ |
+ } catch (e) {} \ |
+ return nodes; \ |
+ }, \ |
+ dir: function() { return console.dir.apply(console, arguments) }, \ |
+ dirxml: function() { return console.dirxml.apply(console, arguments) }, \ |
+ keys: function(o) { var a = []; for (var k in o) a.push(k); return a; }, \ |
+ values: function(o) { var a = []; for (var k in o) a.push(o[k]); return a; }, \ |
+ profile: function() { return console.profile.apply(console, arguments) }, \ |
+ profileEnd: function() { return console.profileEnd.apply(console, arguments) }, \ |
+ _inspectedNodes: [], \ |
+ get $0() { return _inspectorCommandLineAPI._inspectedNodes[0] }, \ |
+ get $1() { return _inspectorCommandLineAPI._inspectedNodes[1] }, \ |
+ get $2() { return _inspectorCommandLineAPI._inspectedNodes[2] }, \ |
+ get $3() { return _inspectorCommandLineAPI._inspectedNodes[3] }, \ |
+ get $4() { return _inspectorCommandLineAPI._inspectedNodes[4] } \ |
+ };"); |
+ |
+ inspectedWindow._inspectorCommandLineAPI.clear = InspectorController.wrapCallback(InspectorController.clearMessages.bind(InspectorController, true)); |
+ inspectedWindow._inspectorCommandLineAPI.inspect = InspectorController.wrapCallback(inspectObject.bind(this)); |
+ |
+ function inspectObject(o) |
+ { |
+ if (arguments.length === 0) |
+ return; |
+ |
+ inspectedWindow.console.log(o); |
+ if (Object.type(o, inspectedWindow) === "node") { |
+ InspectorController.pushNodePathToFrontend(o, true); |
+ } else { |
+ switch (Object.describe(o)) { |
+ case "Database": |
+ InspectorController.selectDatabase(o); |
+ break; |
+ case "Storage": |
+ InspectorController.selectDOMStorage(o); |
+ break; |
+ } |
+ } |
+ } |
+} |
+ |
+InjectedScript._resolveObject = function(objectProxy) |
+{ |
+ var object = InjectedScript._objectForId(objectProxy.objectId); |
+ var path = objectProxy.path; |
+ var protoDepth = objectProxy.protoDepth; |
+ |
+ // Follow the property path. |
+ for (var i = 0; object && path && i < path.length; ++i) |
+ object = object[path[i]]; |
+ |
+ // Get to the necessary proto layer. |
+ for (var i = 0; object && protoDepth && i < protoDepth; ++i) |
+ object = object.__proto__; |
+ |
+ return object; |
+} |
+ |
+InjectedScript._window = function() |
+{ |
+ // TODO: replace with 'return window;' once this script is injected into |
+ // the page's context. |
+ return InspectorController.inspectedWindow(); |
+} |
+ |
+InjectedScript._nodeForId = function(nodeId) |
+{ |
+ if (!nodeId) |
+ return null; |
+ return InspectorController.nodeForId(nodeId); |
+} |
+ |
+InjectedScript._objectForId = function(objectId) |
+{ |
+ // There are three types of object ids used: |
+ // - numbers point to DOM Node via the InspectorDOMAgent mapping |
+ // - strings point to console objects cached in InspectorController for lazy evaluation upon them |
+ // - objects contain complex ids and are currently used for scoped objects |
+ if (typeof objectId === "number") { |
+ return InjectedScript._nodeForId(objectId); |
+ } else if (typeof objectId === "string") { |
+ return InspectorController.unwrapObject(objectId); |
+ } else if (typeof objectId === "object") { |
+ var callFrame = InjectedScript._callFrameForId(objectId.callFrame); |
+ if (objectId.thisObject) |
+ return callFrame.thisObject; |
+ else |
+ return callFrame.scopeChain[objectId.chainIndex]; |
+ } |
+ return objectId; |
+} |
+ |
+InjectedScript.pushNodeToFrontend = function(objectProxy) |
+{ |
+ var object = InjectedScript._resolveObject(objectProxy); |
+ if (!object || Object.type(object, InjectedScript._window()) !== "node") |
+ return false; |
+ return InspectorController.pushNodePathToFrontend(object, false); |
+} |
+ |
+// Called from within InspectorController on the 'inspected page' side. |
+InjectedScript.createProxyObject = function(object, objectId, abbreviate) |
+{ |
+ var result = {}; |
+ result.objectId = objectId; |
+ result.type = Object.type(object, InjectedScript._window()); |
+ |
+ var type = typeof object; |
+ if (type === "object" || type === "function") { |
+ for (var subPropertyName in object) { |
+ result.hasChildren = true; |
+ break; |
+ } |
+ } |
+ try { |
+ result.description = Object.describe(object, abbreviate, InjectedScript._window()); |
+ } catch (e) { |
+ result.exception = e.toString(); |
+ } |
+ return result; |
+} |
+ |
+InjectedScript.CallFrameProxy = function(id, callFrame) |
+{ |
+ this.id = id; |
+ this.type = callFrame.type; |
+ this.functionName = callFrame.functionName; |
+ this.sourceID = callFrame.sourceID; |
+ this.line = callFrame.line; |
+ this.scopeChain = this._wrapScopeChain(callFrame); |
+} |
+ |
+InjectedScript.CallFrameProxy.prototype = { |
+ _wrapScopeChain: function(callFrame) |
+ { |
+ var foundLocalScope = false; |
+ var scopeChain = callFrame.scopeChain; |
+ var scopeChainProxy = []; |
+ for (var i = 0; i < scopeChain.length; ++i) { |
+ var scopeObject = scopeChain[i]; |
+ var scopeObjectProxy = InjectedScript.createProxyObject(scopeObject, { callFrame: this.id, chainIndex: i }); |
+ if (Object.prototype.toString.call(scopeObject) === "[object JSActivation]") { |
+ if (!foundLocalScope) |
+ scopeObjectProxy.thisObject = InjectedScript.createProxyObject(callFrame.thisObject, { callFrame: this.id, thisObject: true }); |
+ else |
+ scopeObjectProxy.isClosure = true; |
+ foundLocalScope = true; |
+ scopeObjectProxy.isLocal = true; |
+ } else if (foundLocalScope && scopeObject instanceof InjectedScript._window().Element) |
+ scopeObjectProxy.isElement = true; |
+ else if (foundLocalScope && scopeObject instanceof InjectedScript._window().Document) |
+ scopeObjectProxy.isDocument = true; |
+ else if (!foundLocalScope && !localScope) |
+ scopeObjectProxy.isWithBlock = true; |
+ scopeObjectProxy.properties = []; |
+ try { |
+ for (var propertyName in scopeObject) |
+ scopeObjectProxy.properties.push(propertyName); |
+ } catch (e) { |
+ } |
+ scopeChainProxy.push(scopeObjectProxy); |
+ } |
+ return scopeChainProxy; |
+ } |
+} |