📄 elementspanel.js
字号:
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]; } 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); } const panel = this; 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); this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier; }, jumpToNextSearchResult: function() { if (!this._searchResults || !this._searchResults.length) return; if (++this._currentSearchResultIndex >= this._searchResults.length) this._currentSearchResultIndex = 0; this.focusedDOMNode = this._searchResults[this._currentSearchResultIndex]; }, jumpToPreviousSearchResult: function() { if (!this._searchResults || !this._searchResults.length) return; if (--this._currentSearchResultIndex < 0) this._currentSearchResultIndex = (this._searchResults.length - 1); this.focusedDOMNode = this._searchResults[this._currentSearchResultIndex]; }, inspectedWindowCleared: function(window) { if (InspectorController.isWindowVisible()) this.updateMutationEventListeners(window); }, _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; }, set rootDOMNode(x) { this.treeOutline.rootDOMNode = x; }, get focusedDOMNode() { return this.treeOutline.focusedDOMNode; }, set focusedDOMNode(x) { 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}); if (this.visible) this._updateModifiedNodesSoon(); }, _nodeRemoved: function(event) { this.recentlyModifiedNodes.push({node: event.target, parent: event.relatedNode, removed: true}); if (this.visible) this._updateModifiedNodesSoon(); }, _updateModifiedNodesSoon: function() { if ("_updateModifiedNodesTimeout" in this) return; this._updateModifiedNodesTimeout = setTimeout(this._updateModifiedNodes.bind(this), 0); }, _updateModifiedNodes: function() { if ("_updateModifiedNodesTimeout" in this) { clearTimeout(this._updateModifiedNodesTimeout); delete this._updateModifiedNodesTimeout; } var updatedParentTreeElements = []; var updateBreadcrumbs = false; for (var i = 0; i < this.recentlyModifiedNodes.length; ++i) { var replaced = this.recentlyModifiedNodes[i].replaced; var parent = this.recentlyModifiedNodes[i].parent; if (!parent) continue; var parentNodeItem = this.treeOutline.findTreeElement(parent, null, null, objectsAreSame); if (parentNodeItem && !parentNodeItem.alreadyUpdatedChildren) { parentNodeItem.updateChildren(replaced); parentNodeItem.alreadyUpdatedChildren = true; updatedParentTreeElements.push(parentNodeItem); } if (!updateBreadcrumbs && (objectsAreSame(this.focusedDOMNode, parent) || isAncestorIncludingParentFrames(this.focusedDOMNode, parent))) updateBreadcrumbs = true; } for (var i = 0; i < updatedParentTreeElements.length; ++i) delete updatedParentTreeElements[i].alreadyUpdatedChildren; this.recentlyModifiedNodes = []; if (updateBreadcrumbs) this.updateBreadcrumb(true); }, _stylesPaneEdited: function() { this.sidebarPanes.metrics.needsUpdate = true; this.updateMetrics(); }, _metricsPaneEdited: function() { this.sidebarPanes.styles.needsUpdate = true; this.updateStyles(true); }, _mouseMovedInCrumbs: function(event) { var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); var crumbElement = nodeUnderMouse.enclosingNodeOrSelfWithClass("crumb"); WebInspector.hoveredDOMNode = (crumbElement ? crumbElement.representedObject : null); if ("_mouseOutOfCrumbsTimeout" in this) { clearTimeout(this._mouseOutOfCrumbsTimeout); delete this._mouseOutOfCrumbsTimeout; } }, _mouseMovedOutOfCrumbs: function(event) { var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); if (nodeUnderMouse.isDescendant(this.crumbsElement)) return; WebInspector.hoveredDOMNode = null; this._mouseOutOfCrumbsTimeout = setTimeout(this.updateBreadcrumbSizes.bind(this), 1000); }, updateBreadcrumb: function(forceUpdate) { if (!this.visible) return; var crumbs = this.crumbsElement; var handled = false; var foundRoot = false; var crumb = crumbs.firstChild; while (crumb) { if (objectsAreSame(crumb.representedObject, this.rootDOMNode)) foundRoot = true; if (foundRoot) crumb.addStyleClass("dimmed"); else crumb.removeStyleClass("dimmed"); if (objectsAreSame(crumb.representedObject, this.focusedDOMNode)) { crumb.addStyleClass("selected"); handled = true; } else { crumb.removeStyleClass("selected"); } crumb = crumb.nextSibling; } if (handled && !forceUpdate) { // We don't need to rebuild the crumbs, but we need to adjust sizes // to reflect the new focused or root node. this.updateBreadcrumbSizes(); return; } crumbs.removeChildren(); var panel = this; function selectCrumbFunction(event) { var crumb = event.currentTarget; if (crumb.hasStyleClass("collapsed")) { // Clicking a collapsed crumb will expose the hidden crumbs. if (crumb === panel.crumbsElement.firstChild) { // If the focused crumb is the first child, pick the farthest crumb // that is still hidden. This allows the user to expose every crumb. var currentCrumb = crumb; while (currentCrumb) { var hidden = currentCrumb.hasStyleClass("hidden"); var collapsed = currentCrumb.hasStyleClass("collapsed"); if (!hidden && !collapsed) break; crumb = currentCrumb; currentCrumb = currentCrumb.nextSibling; } } panel.updateBreadcrumbSizes(crumb); } else { // Clicking a dimmed crumb or double clicking (event.detail >= 2) // will change the root node in addition to the focused node. if (event.detail >= 2 || crumb.hasStyleClass("dimmed")) panel.rootDOMNode = crumb.representedObject.parentNode; panel.focusedDOMNode = crumb.representedObject; } event.preventDefault(); } foundRoot = false; for (var current = this.focusedDOMNode; current; current = parentNodeOrFrameElement(current)) { if (current.nodeType === Node.DOCUMENT_NODE) continue; if (objectsAreSame(current, this.rootDOMNode)) foundRoot = true; var crumb = document.createElement("span"); crumb.className = "crumb"; crumb.representedObject = current; crumb.addEventListener("mousedown", selectCrumbFunction, false); var crumbTitle; switch (current.nodeType) { case Node.ELEMENT_NODE: crumbTitle = current.nodeName.toLowerCase(); var nameElement = document.createElement("span"); nameElement.textContent = crumbTitle; crumb.appendChild(nameElement); var idAttribute = current.getAttribute("id"); if (idAttribute) { var idElement = document.createElement("span"); crumb.appendChild(idElement); var part = "#" + idAttribute; crumbTitle += part; idElement.appendChild(document.createTextNode(part)); // Mark the name as extra, since the ID is more important. nameElement.className = "extra"; } var classAttribute = current.getAttribute("class"); if (classAttribute) { var classes = classAttribute.split(/\s+/); var foundClasses = {}; if (classes.length) { var classesElement = document.createElement("span"); classesElement.className = "extra"; crumb.appendChild(classesElement); for (var i = 0; i < classes.length; ++i) { var className = classes[i]; if (className && !(className in foundClasses)) { var part = "." + className; crumbTitle += part;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -