diff options
Diffstat (limited to 'WebCore/inspector/front-end/ElementsPanel.js')
-rw-r--r-- | WebCore/inspector/front-end/ElementsPanel.js | 434 |
1 files changed, 77 insertions, 357 deletions
diff --git a/WebCore/inspector/front-end/ElementsPanel.js b/WebCore/inspector/front-end/ElementsPanel.js index ffa0000..1748159 100644 --- a/WebCore/inspector/front-end/ElementsPanel.js +++ b/WebCore/inspector/front-end/ElementsPanel.js @@ -61,7 +61,8 @@ WebInspector.ElementsPanel = function() InspectorController.toggleNodeSearch(); this.panel.nodeSearchButton.removeStyleClass("toggled-on"); } - WebInspector.console.addInspectedNode(this._focusedDOMNode); + if (this._focusedDOMNode) + InspectorController.addInspectedNode(this._focusedDOMNode.id, function() {}); }; this.contentElement.appendChild(this.treeOutline.element); @@ -97,10 +98,7 @@ WebInspector.ElementsPanel = function() this.sidebarResizeElement.className = "sidebar-resizer-vertical"; this.sidebarResizeElement.addEventListener("mousedown", this.rightSidebarResizerDragStart.bind(this), false); - this.nodeSearchButton = this.createStatusBarButton(); - this.nodeSearchButton.title = WebInspector.UIString("Select an element in the page to inspect it."); - this.nodeSearchButton.id = "node-search-status-bar-item"; - this.nodeSearchButton.className = "status-bar-item"; + this.nodeSearchButton = new WebInspector.StatusBarButton(WebInspector.UIString("Select an element in the page to inspect it."), "node-search-status-bar-item"); this.nodeSearchButton.addEventListener("click", this._nodeSearchButtonClicked.bind(this), false); this.searchingForNode = false; @@ -109,13 +107,7 @@ WebInspector.ElementsPanel = function() this.element.appendChild(this.sidebarElement); this.element.appendChild(this.sidebarResizeElement); - this._mutationMonitoredWindows = []; - this._nodeInsertedEventListener = InspectorController.wrapCallback(this._nodeInserted.bind(this)); - this._nodeRemovedEventListener = InspectorController.wrapCallback(this._nodeRemoved.bind(this)); - this._contentLoadedEventListener = InspectorController.wrapCallback(this._contentLoaded.bind(this)); - - this.stylesheet = null; - this.styles = {}; + this._changedStyles = {}; this.reset(); } @@ -130,7 +122,7 @@ WebInspector.ElementsPanel.prototype = { get statusBarItems() { - return [this.nodeSearchButton, this.crumbsElement]; + return [this.nodeSearchButton.element, this.crumbsElement]; }, updateStatusBarItems: function() @@ -156,7 +148,7 @@ WebInspector.ElementsPanel.prototype = { if (InspectorController.searchingForNode()) { InspectorController.toggleNodeSearch(); - this.nodeSearchButton.removeStyleClass("toggled-on"); + this.nodeSearchButton.toggled = false; } }, @@ -175,40 +167,27 @@ WebInspector.ElementsPanel.prototype = { if (InspectorController.searchingForNode()) { InspectorController.toggleNodeSearch(); - this.nodeSearchButton.removeStyleClass("toggled-on"); + this.nodeSearchButton.toggled = false; } this.recentlyModifiedNodes = []; - this.unregisterAllMutationEventListeners(); delete this.currentQuery; this.searchCanceled(); - var inspectedWindow = Preferences.useDOMAgent ? WebInspector.domAgent.inspectedWindow : InspectorController.inspectedWindow(); - if (!inspectedWindow || !inspectedWindow.document) + var inspectedWindow = WebInspector.domAgent.inspectedWindow; + if (!inspectedWindow || !inspectedWindow.document || !inspectedWindow.document.firstChild) return; - if (!inspectedWindow.document.firstChild) { - function contentLoaded() - { - inspectedWindow.document.removeEventListener("DOMContentLoaded", contentLoadedCallback, false); - - this.reset(); - } - - var contentLoadedCallback = InspectorController.wrapCallback(contentLoaded.bind(this)); - inspectedWindow.document.addEventListener("DOMContentLoaded", contentLoadedCallback, false); - return; - } - // If the window isn't visible, return early so the DOM tree isn't built // and mutation event listeners are not added. if (!InspectorController.isWindowVisible()) return; - this.registerMutationEventListeners(inspectedWindow); - var inspectedRootDocument = inspectedWindow.document; + inspectedRootDocument.addEventListener("DOMNodeInserted", this._nodeInserted.bind(this)); + inspectedRootDocument.addEventListener("DOMNodeRemoved", this._nodeRemoved.bind(this)); + this.rootDOMNode = inspectedRootDocument; var canidateFocusNode = inspectedRootDocument.body || inspectedRootDocument.documentElement; @@ -222,19 +201,11 @@ WebInspector.ElementsPanel.prototype = { } }, - includedInSearchResultsPropertyName: "__includedInInspectorSearchResults", - searchCanceled: function() { if (this._searchResults) { - const searchResultsProperty = this.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]; - - var treeElement = this.treeOutline.findTreeElement(node); + var treeElement = this.treeOutline.findTreeElement(this._searchResults[i]); if (treeElement) treeElement.highlighted = false; } @@ -242,13 +213,9 @@ WebInspector.ElementsPanel.prototype = { WebInspector.updateSearchMatchesCount(0, this); - if (this._currentSearchChunkIntervalIdentifier) { - clearInterval(this._currentSearchChunkIntervalIdentifier); - delete this._currentSearchChunkIntervalIdentifier; - } - this._currentSearchResultIndex = 0; this._searchResults = []; + InspectorController.searchCanceled(function() {}); }, performSearch: function(query) @@ -260,241 +227,56 @@ WebInspector.ElementsPanel.prototype = { if (!whitespaceTrimmedQuery.length) return; - 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 = query.escapeCharacters("'"); - const escapedTagNameQuery = (tagNameQuery ? tagNameQuery.escapeCharacters("'") : null); - const escapedWhitespaceTrimmedQuery = whitespaceTrimmedQuery.escapeCharacters("'"); - const searchResultsProperty = this.includedInSearchResultsPropertyName; - - var updatedMatchCountOnce = false; - var matchesCountUpdateTimeout = null; - - function updateMatchesCount() - { - WebInspector.updateSearchMatchesCount(this._searchResults.length, this); - matchesCountUpdateTimeout = null; - updatedMatchCountOnce = true; - } - - function updateMatchesCountSoon() - { - if (!updatedMatchCountOnce) - return updateMatchesCount.call(this); - if (matchesCountUpdateTimeout) - return; - // Update the matches count every half-second so it doesn't feel twitchy. - matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500); - } - - function addNodesToResults(nodes, length, getItem) - { - if (!length) - return; - - 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 (!this._searchResults.length) { - this._currentSearchResultIndex = 0; - this.focusedDOMNode = node; - } - - node[searchResultsProperty] = true; - this._searchResults.push(node); - - // Highlight the tree element to show it matched the search. - // FIXME: highlight the substrings in text nodes and attributes. - var treeElement = this.treeOutline.findTreeElement(node); - if (treeElement) - treeElement.highlighted = true; - } - - updateMatchesCountSoon.call(this); - } - - 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); - } + this._updatedMatchCountOnce = false; + this._matchesCountUpdateTimeout = null; - 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 < this._searchResults.length; ++i) - delete this._searchResults[i][searchResultsProperty]; - } + InspectorController.performSearch(whitespaceTrimmedQuery, function() {}); + }, - const mainFrameDocument = InspectorController.inspectedWindow().document; - const searchDocuments = [mainFrameDocument]; - - if (tagNameQuery && startTagFound && endTagFound) - const searchFunctions = [matchExactTagNames, matchPlainText]; - else if (tagNameQuery && startTagFound) - const 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(). - const 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. - const searchFunctions = [matchPartialAttributeValues, matchPlainText]; - } else - const searchFunctions = [matchExactItems, matchStyleSelector, matchPartialTagNamesAndAttributeValues, matchPlainText, matchXPathQuery]; - - // Find all frames, iframes and object elements to search their documents. - const querySelectorAllFunction = InspectorController.inspectedWindow().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); - } + _updateMatchesCount: function() + { + WebInspector.updateSearchMatchesCount(this._searchResults.length, this); + this._matchesCountUpdateTimeout = null; + this._updatedMatchCountOnce = true; + }, - const panel = this; - var documentIndex = 0; - var searchFunctionIndex = 0; - var chunkIntervalIdentifier = null; + _updateMatchesCountSoon: function() + { + if (!this._updatedMatchCountOnce) + return this._updateMatchesCount(); + if (this._matchesCountUpdateTimeout) + return; + // Update the matches count every half-second so it doesn't feel twitchy. + this._matchesCountUpdateTimeout = setTimeout(this._updateMatchesCount.bind(this), 500); + }, - // Split up the work into chunks so we don't block the UI thread while processing. + addNodesToSearchResult: function(nodeIds) + { + if (!nodeIds) + return; - 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; - } + var nodeIdsArray = nodeIds.split(","); + for (var i = 0; i < nodeIdsArray.length; ++i) { + var nodeId = nodeIdsArray[i]; + var node = WebInspector.domAgent.nodeForId(nodeId); + if (!node) + continue; - searchDocument = searchDocuments[documentIndex]; + if (!this._searchResults.length) { + this._currentSearchResultIndex = 0; + this.focusedDOMNode = node; } - if (!searchDocument || !searchFunction) - return; + this._searchResults.push(node); - try { - searchFunction.call(panel, searchDocument); - } catch(err) { - // ignore any exceptions. the query might be malformed, but we allow that. - } + // Highlight the tree element to show it matched the search. + // FIXME: highlight the substrings in text nodes and attributes. + var treeElement = this.treeOutline.findTreeElement(node); + if (treeElement) + treeElement.highlighted = true; } - processChunk(); - - chunkIntervalIdentifier = setInterval(processChunk, 25); - this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier; + this._updateMatchesCountSoon(); }, jumpToNextSearchResult: function() @@ -515,12 +297,6 @@ WebInspector.ElementsPanel.prototype = { this.focusedDOMNode = this._searchResults[this._currentSearchResultIndex]; }, - inspectedWindowCleared: function(window) - { - if (InspectorController.isWindowVisible()) - this.updateMutationEventListeners(window); - }, - renameSelector: function(oldIdentifier, newIdentifier, oldSelector, newSelector) { // TODO: Implement Shifting the oldSelector, and its contents to a newSelector @@ -532,16 +308,16 @@ WebInspector.ElementsPanel.prototype = { return; var selector = style.parentRule.selectorText; - if (!this.styles[identifier]) - this.styles[identifier] = {}; + if (!this._changedStyles[identifier]) + this._changedStyles[identifier] = {}; - if (!this.styles[identifier][selector]) - this.styles[identifier][selector] = {}; + if (!this._changedStyles[identifier][selector]) + this._changedStyles[identifier][selector] = {}; - if (!this.styles[identifier][selector][property]) + if (!this._changedStyles[identifier][selector][property]) WebInspector.styleChanges += 1; - this.styles[identifier][selector][property] = style.getPropertyValue(property); + this._changedStyles[identifier][selector][property] = style.getPropertyValue(property); }, removeStyleChange: function(identifier, style, property) @@ -550,11 +326,11 @@ WebInspector.ElementsPanel.prototype = { return; var selector = style.parentRule.selectorText; - if (!this.styles[identifier] || !this.styles[identifier][selector]) + if (!this._changedStyles[identifier] || !this._changedStyles[identifier][selector]) return; - if (this.styles[identifier][selector][property]) { - delete this.styles[identifier][selector][property]; + if (this._changedStyles[identifier][selector][property]) { + delete this._changedStyles[identifier][selector][property]; WebInspector.styleChanges -= 1; } }, @@ -566,20 +342,20 @@ WebInspector.ElementsPanel.prototype = { // Merge Down to Just Selectors var mergedSelectors = {}; - for (var identifier in this.styles) { - for (var selector in this.styles[identifier]) { + for (var identifier in this._changedStyles) { + for (var selector in this._changedStyles[identifier]) { if (!mergedSelectors[selector]) - mergedSelectors[selector] = this.styles[identifier][selector]; + mergedSelectors[selector] = this._changedStyles[identifier][selector]; else { // merge on selector var merge = {}; for (var property in mergedSelectors[selector]) merge[property] = mergedSelectors[selector][property]; - for (var property in this.styles[identifier][selector]) { + for (var property in this._changedStyles[identifier][selector]) { if (!merge[property]) - merge[property] = this.styles[identifier][selector][property]; + merge[property] = this._changedStyles[identifier][selector][property]; else { // merge on property within a selector, include comment to notify user var value1 = merge[property]; - var value2 = this.styles[identifier][selector][property]; + var value2 = this._changedStyles[identifier][selector][property]; if (value1 === value2) merge[property] = [value1]; @@ -636,53 +412,6 @@ WebInspector.ElementsPanel.prototype = { InspectorController.inspectedWindow().console.log(result); }, - _addMutationEventListeners: function(monitoredWindow) - { - monitoredWindow.document.addEventListener("DOMNodeInserted", this._nodeInsertedEventListener, true); - monitoredWindow.document.addEventListener("DOMNodeRemoved", this._nodeRemovedEventListener, true); - if (monitoredWindow.frameElement) - monitoredWindow.addEventListener("DOMContentLoaded", this._contentLoadedEventListener, true); - }, - - _removeMutationEventListeners: function(monitoredWindow) - { - if (monitoredWindow.frameElement) - monitoredWindow.removeEventListener("DOMContentLoaded", this._contentLoadedEventListener, true); - if (!monitoredWindow.document) - return; - monitoredWindow.document.removeEventListener("DOMNodeInserted", this._nodeInsertedEventListener, true); - monitoredWindow.document.removeEventListener("DOMNodeRemoved", this._nodeRemovedEventListener, true); - }, - - updateMutationEventListeners: function(monitoredWindow) - { - this._addMutationEventListeners(monitoredWindow); - }, - - registerMutationEventListeners: function(monitoredWindow) - { - if (!monitoredWindow || this._mutationMonitoredWindows.indexOf(monitoredWindow) !== -1) - return; - this._mutationMonitoredWindows.push(monitoredWindow); - if (InspectorController.isWindowVisible()) - this._addMutationEventListeners(monitoredWindow); - }, - - unregisterMutationEventListeners: function(monitoredWindow) - { - if (!monitoredWindow || this._mutationMonitoredWindows.indexOf(monitoredWindow) === -1) - return; - this._mutationMonitoredWindows.remove(monitoredWindow); - this._removeMutationEventListeners(monitoredWindow); - }, - - unregisterAllMutationEventListeners: function() - { - for (var i = 0; i < this._mutationMonitoredWindows.length; ++i) - this._removeMutationEventListeners(this._mutationMonitoredWindows[i]); - this._mutationMonitoredWindows = []; - }, - get rootDOMNode() { return this.treeOutline.rootDOMNode; @@ -703,13 +432,6 @@ WebInspector.ElementsPanel.prototype = { this.treeOutline.focusedDOMNode = x; }, - _contentLoaded: function(event) - { - this.recentlyModifiedNodes.push({node: event.target, parent: event.target.defaultView.frameElement, replaced: true}); - if (this.visible) - this._updateModifiedNodesSoon(); - }, - _nodeInserted: function(event) { this.recentlyModifiedNodes.push({node: event.target, parent: event.relatedNode, inserted: true}); @@ -747,14 +469,14 @@ WebInspector.ElementsPanel.prototype = { if (!parent) continue; - var parentNodeItem = this.treeOutline.findTreeElement(parent, null, null, objectsAreSame); + var parentNodeItem = this.treeOutline.findTreeElement(parent); if (parentNodeItem && !parentNodeItem.alreadyUpdatedChildren) { parentNodeItem.updateChildren(replaced); parentNodeItem.alreadyUpdatedChildren = true; updatedParentTreeElements.push(parentNodeItem); } - if (!updateBreadcrumbs && (objectsAreSame(this.focusedDOMNode, parent) || isAncestorIncludingParentFrames(this.focusedDOMNode, parent))) + if (!updateBreadcrumbs && (this.focusedDOMNode === parent || isAncestorIncludingParentFrames(this.focusedDOMNode, parent))) updateBreadcrumbs = true; } @@ -814,7 +536,7 @@ WebInspector.ElementsPanel.prototype = { var foundRoot = false; var crumb = crumbs.firstChild; while (crumb) { - if (objectsAreSame(crumb.representedObject, this.rootDOMNode)) + if (crumb.representedObject === this.rootDOMNode) foundRoot = true; if (foundRoot) @@ -822,7 +544,7 @@ WebInspector.ElementsPanel.prototype = { else crumb.removeStyleClass("dimmed"); - if (objectsAreSame(crumb.representedObject, this.focusedDOMNode)) { + if (crumb.representedObject === this.focusedDOMNode) { crumb.addStyleClass("selected"); handled = true; } else { @@ -879,7 +601,7 @@ WebInspector.ElementsPanel.prototype = { if (current.nodeType === Node.DOCUMENT_NODE) continue; - if (objectsAreSame(current, this.rootDOMNode)) + if (current === this.rootDOMNode) foundRoot = true; var crumb = document.createElement("span"); @@ -962,7 +684,7 @@ WebInspector.ElementsPanel.prototype = { if (foundRoot) crumb.addStyleClass("dimmed"); - if (objectsAreSame(current, this.focusedDOMNode)) + if (current === this.focusedDOMNode) crumb.addStyleClass("selected"); if (!crumbs.childNodes.length) crumb.addStyleClass("end"); @@ -1269,7 +991,8 @@ WebInspector.ElementsPanel.prototype = { switch (this.focusedDOMNode.nodeType) { case Node.ELEMENT_NODE: - var data = this.focusedDOMNode.outerHTML; + // TODO: Introduce InspectorController.copyEvent that pushes appropriate markup into the clipboard. + var data = null; break; case Node.COMMENT_NODE: @@ -1316,10 +1039,7 @@ WebInspector.ElementsPanel.prototype = { { InspectorController.toggleNodeSearch(); - if (InspectorController.searchingForNode()) - this.nodeSearchButton.addStyleClass("toggled-on"); - else - this.nodeSearchButton.removeStyleClass("toggled-on"); + this.nodeSearchButton.toggled = InspectorController.searchingForNode(); } } |