123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266 |
- /*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
- * Copyright (C) 2009 Joseph Pecoraro
- *
- * 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.
- */
- importScript("CSSNamedFlowCollectionsView.js");
- importScript("CSSNamedFlowView.js");
- importScript("EventListenersSidebarPane.js");
- importScript("MetricsSidebarPane.js");
- importScript("PlatformFontsSidebarPane.js");
- importScript("PropertiesSidebarPane.js");
- importScript("StylesSidebarPane.js");
- /**
- * @constructor
- * @extends {WebInspector.Panel}
- */
- WebInspector.ElementsPanel = function()
- {
- WebInspector.Panel.call(this, "elements");
- this.registerRequiredCSS("breadcrumbList.css");
- this.registerRequiredCSS("elementsPanel.css");
- this.registerRequiredCSS("textPrompt.css");
- this.setHideOnDetach();
- const initialSidebarWidth = 325;
- const minimumContentWidthPercent = 0.34;
- const initialSidebarHeight = 325;
- const minimumContentHeightPercent = 0.34;
- this.createSidebarView(this.element, WebInspector.SidebarView.SidebarPosition.End, initialSidebarWidth, initialSidebarHeight);
- this.splitView.setSidebarElementConstraints(Preferences.minElementsSidebarWidth, Preferences.minElementsSidebarHeight);
- this.splitView.setMainElementConstraints(minimumContentWidthPercent, minimumContentHeightPercent);
- this.splitView.addEventListener(WebInspector.SidebarView.EventTypes.Resized, this._updateTreeOutlineVisibleWidth.bind(this));
- this.contentElement = this.splitView.mainElement;
- this.contentElement.id = "elements-content";
- this.contentElement.addStyleClass("outline-disclosure");
- this.contentElement.addStyleClass("source-code");
- if (!WebInspector.settings.domWordWrap.get())
- this.contentElement.classList.add("nowrap");
- WebInspector.settings.domWordWrap.addChangeListener(this._domWordWrapSettingChanged.bind(this));
- this.contentElement.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true);
- this.splitView.sidebarElement.addEventListener("contextmenu", this._sidebarContextMenuEventFired.bind(this), false);
- this.treeOutline = new WebInspector.ElementsTreeOutline(true, true, this._populateContextMenu.bind(this), this._setPseudoClassForNodeId.bind(this));
- this.treeOutline.wireToDomAgent();
- this.treeOutline.addEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
- this.treeOutline.addEventListener(WebInspector.ElementsTreeOutline.Events.ElementsTreeUpdated, this._updateBreadcrumbIfNeeded, this);
- this.crumbsElement = document.createElement("div");
- this.crumbsElement.className = "crumbs";
- this.crumbsElement.addEventListener("mousemove", this._mouseMovedInCrumbs.bind(this), false);
- this.crumbsElement.addEventListener("mouseout", this._mouseMovedOutOfCrumbs.bind(this), false);
- this.sidebarPanes = {};
- this.sidebarPanes.platformFonts = new WebInspector.PlatformFontsSidebarPane();
- this.sidebarPanes.computedStyle = new WebInspector.ComputedStyleSidebarPane();
- this.sidebarPanes.styles = new WebInspector.StylesSidebarPane(this.sidebarPanes.computedStyle, this._setPseudoClassForNodeId.bind(this));
- this.sidebarPanes.metrics = new WebInspector.MetricsSidebarPane();
- this.sidebarPanes.properties = new WebInspector.PropertiesSidebarPane();
- this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane.createProxy(this);
- this.sidebarPanes.eventListeners = new WebInspector.EventListenersSidebarPane();
- this.sidebarPanes.styles.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateStyles.bind(this, false));
- this.sidebarPanes.metrics.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateMetrics.bind(this));
- this.sidebarPanes.platformFonts.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updatePlatformFonts.bind(this));
- this.sidebarPanes.properties.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateProperties.bind(this));
- this.sidebarPanes.eventListeners.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateEventListeners.bind(this));
- this.sidebarPanes.styles.addEventListener("style edited", this._stylesPaneEdited, this);
- this.sidebarPanes.styles.addEventListener("style property toggled", this._stylesPaneEdited, this);
- this.sidebarPanes.metrics.addEventListener("metrics edited", this._metricsPaneEdited, this);
- WebInspector.dockController.addEventListener(WebInspector.DockController.Events.DockSideChanged, this._dockSideChanged.bind(this));
- WebInspector.settings.splitVerticallyWhenDockedToRight.addChangeListener(this._dockSideChanged.bind(this));
- this._dockSideChanged();
- this._popoverHelper = new WebInspector.PopoverHelper(this.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
- this._popoverHelper.setTimeout(0);
- WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdatedEvent, this);
- WebInspector.settings.showShadowDOM.addChangeListener(this._showShadowDOMChanged.bind(this));
- if (WebInspector.domAgent.existingDocument())
- this._documentUpdated(WebInspector.domAgent.existingDocument());
- }
- WebInspector.ElementsPanel.prototype = {
- _updateTreeOutlineVisibleWidth: function()
- {
- if (!this.treeOutline)
- return;
- var width = this.splitView.element.offsetWidth;
- if (this.splitView.isVertical())
- width -= this.splitView.sidebarWidth();
- this.treeOutline.setVisibleWidth(width);
- },
- get statusBarItems()
- {
- return [this.crumbsElement];
- },
- defaultFocusedElement: function()
- {
- return this.treeOutline.element;
- },
- statusBarResized: function()
- {
- this.updateBreadcrumbSizes();
- },
- wasShown: function()
- {
- // Attach heavy component lazily
- if (this.treeOutline.element.parentElement !== this.contentElement)
- this.contentElement.appendChild(this.treeOutline.element);
- WebInspector.Panel.prototype.wasShown.call(this);
- this.updateBreadcrumb();
- this.treeOutline.updateSelection();
- this.treeOutline.setVisible(true);
- if (!this.treeOutline.rootDOMNode)
- WebInspector.domAgent.requestDocument();
- },
- willHide: function()
- {
- WebInspector.domAgent.hideDOMNodeHighlight();
- this.treeOutline.setVisible(false);
- this._popoverHelper.hidePopover();
- // Detach heavy component on hide
- this.contentElement.removeChild(this.treeOutline.element);
- WebInspector.Panel.prototype.willHide.call(this);
- },
- onResize: function()
- {
- this.treeOutline.updateSelection();
- this.updateBreadcrumbSizes();
- },
- /**
- * @param {DOMAgent.NodeId} nodeId
- * @param {string} pseudoClass
- * @param {boolean} enable
- */
- _setPseudoClassForNodeId: function(nodeId, pseudoClass, enable)
- {
- var node = WebInspector.domAgent.nodeForId(nodeId);
- if (!node)
- return;
- var pseudoClasses = node.getUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName);
- if (enable) {
- pseudoClasses = pseudoClasses || [];
- if (pseudoClasses.indexOf(pseudoClass) >= 0)
- return;
- pseudoClasses.push(pseudoClass);
- node.setUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName, pseudoClasses);
- } else {
- if (!pseudoClasses || pseudoClasses.indexOf(pseudoClass) < 0)
- return;
- pseudoClasses.remove(pseudoClass);
- if (!pseudoClasses.length)
- node.removeUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName);
- }
- this.treeOutline.updateOpenCloseTags(node);
- WebInspector.cssModel.forcePseudoState(node.id, node.getUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName));
- this._metricsPaneEdited();
- this._stylesPaneEdited();
- WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
- action: WebInspector.UserMetrics.UserActionNames.ForcedElementState,
- selector: node.appropriateSelectorFor(false),
- enabled: enable,
- state: pseudoClass
- });
- },
- _selectedNodeChanged: function()
- {
- var selectedNode = this.selectedDOMNode();
- if (!selectedNode && this._lastValidSelectedNode)
- this._selectedPathOnReset = this._lastValidSelectedNode.path();
- this.updateBreadcrumb(false);
- this._updateSidebars();
- if (selectedNode) {
- ConsoleAgent.addInspectedNode(selectedNode.id);
- this._lastValidSelectedNode = selectedNode;
- }
- WebInspector.notifications.dispatchEventToListeners(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged);
- },
- _updateSidebars: function()
- {
- for (var pane in this.sidebarPanes)
- this.sidebarPanes[pane].needsUpdate = true;
- this.updateStyles(true);
- this.updateMetrics();
- this.updatePlatformFonts();
- this.updateProperties();
- this.updateEventListeners();
- },
- _reset: function()
- {
- delete this.currentQuery;
- },
- _documentUpdatedEvent: function(event)
- {
- this._documentUpdated(event.data);
- },
- _documentUpdated: function(inspectedRootDocument)
- {
- this._reset();
- this.searchCanceled();
- this.treeOutline.rootDOMNode = inspectedRootDocument;
- if (!inspectedRootDocument) {
- if (this.isShowing())
- WebInspector.domAgent.requestDocument();
- return;
- }
- WebInspector.domBreakpointsSidebarPane.restoreBreakpoints();
- /**
- * @this {WebInspector.ElementsPanel}
- * @param {WebInspector.DOMNode=} candidateFocusNode
- */
- function selectNode(candidateFocusNode)
- {
- if (!candidateFocusNode)
- candidateFocusNode = inspectedRootDocument.body || inspectedRootDocument.documentElement;
- if (!candidateFocusNode)
- return;
- this.selectDOMNode(candidateFocusNode);
- if (this.treeOutline.selectedTreeElement)
- this.treeOutline.selectedTreeElement.expand();
- }
- /**
- * @param {?DOMAgent.NodeId} nodeId
- */
- function selectLastSelectedNode(nodeId)
- {
- if (this.selectedDOMNode()) {
- // Focused node has been explicitly set while reaching out for the last selected node.
- return;
- }
- var node = nodeId ? WebInspector.domAgent.nodeForId(nodeId) : null;
- selectNode.call(this, node);
- }
- if (this._selectedPathOnReset)
- WebInspector.domAgent.pushNodeByPathToFrontend(this._selectedPathOnReset, selectLastSelectedNode.bind(this));
- else
- selectNode.call(this);
- delete this._selectedPathOnReset;
- },
- searchCanceled: function()
- {
- delete this._searchQuery;
- this._hideSearchHighlights();
- WebInspector.searchController.updateSearchMatchesCount(0, this);
- delete this._currentSearchResultIndex;
- delete this._searchResults;
- WebInspector.domAgent.cancelSearch();
- },
- /**
- * @param {string} query
- * @param {boolean} shouldJump
- */
- performSearch: function(query, shouldJump)
- {
- // Call searchCanceled since it will reset everything we need before doing a new search.
- this.searchCanceled();
- const whitespaceTrimmedQuery = query.trim();
- if (!whitespaceTrimmedQuery.length)
- return;
- this._searchQuery = query;
- /**
- * @param {number} resultCount
- */
- function resultCountCallback(resultCount)
- {
- WebInspector.searchController.updateSearchMatchesCount(resultCount, this);
- if (!resultCount)
- return;
- this._searchResults = new Array(resultCount);
- this._currentSearchResultIndex = -1;
- if (shouldJump)
- this.jumpToNextSearchResult();
- }
- WebInspector.domAgent.performSearch(whitespaceTrimmedQuery, resultCountCallback.bind(this));
- },
- _contextMenuEventFired: function(event)
- {
- function toggleWordWrap()
- {
- WebInspector.settings.domWordWrap.set(!WebInspector.settings.domWordWrap.get());
- }
- var contextMenu = new WebInspector.ContextMenu(event);
- this.treeOutline.populateContextMenu(contextMenu, event);
- if (WebInspector.experimentsSettings.cssRegions.isEnabled()) {
- contextMenu.appendSeparator();
- contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "CSS named flows\u2026" : "CSS Named Flows\u2026"), this._showNamedFlowCollections.bind(this));
- }
- contextMenu.appendSeparator();
- contextMenu.appendCheckboxItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Word wrap" : "Word Wrap"), toggleWordWrap.bind(this), WebInspector.settings.domWordWrap.get());
- contextMenu.show();
- },
- _showNamedFlowCollections: function()
- {
- if (!WebInspector.cssNamedFlowCollectionsView)
- WebInspector.cssNamedFlowCollectionsView = new WebInspector.CSSNamedFlowCollectionsView();
- WebInspector.cssNamedFlowCollectionsView.showInDrawer();
- },
- _domWordWrapSettingChanged: function(event)
- {
- if (event.data)
- this.contentElement.removeStyleClass("nowrap");
- else
- this.contentElement.addStyleClass("nowrap");
- var selectedNode = this.selectedDOMNode();
- if (!selectedNode)
- return;
- var treeElement = this.treeOutline.findTreeElement(selectedNode);
- if (treeElement)
- treeElement.updateSelection(); // Recalculate selection highlight dimensions.
- },
- switchToAndFocus: function(node)
- {
- // Reset search restore.
- WebInspector.searchController.cancelSearch();
- WebInspector.inspectorView.setCurrentPanel(this);
- this.selectDOMNode(node, true);
- },
- _populateContextMenu: function(contextMenu, node)
- {
- // Add debbuging-related actions
- contextMenu.appendSeparator();
- var pane = WebInspector.domBreakpointsSidebarPane;
- pane.populateNodeContextMenu(node, contextMenu);
- },
- _getPopoverAnchor: function(element)
- {
- var anchor = element.enclosingNodeOrSelfWithClass("webkit-html-resource-link");
- if (anchor) {
- if (!anchor.href)
- return null;
- var resource = WebInspector.resourceTreeModel.resourceForURL(anchor.href);
- if (!resource || resource.type !== WebInspector.resourceTypes.Image)
- return null;
- anchor.removeAttribute("title");
- }
- return anchor;
- },
-
- _loadDimensionsForNode: function(treeElement, callback)
- {
- // We get here for CSS properties, too, so bail out early for non-DOM treeElements.
- if (treeElement.treeOutline !== this.treeOutline) {
- callback();
- return;
- }
-
- var node = /** @type {WebInspector.DOMNode} */ (treeElement.representedObject);
- if (!node.nodeName() || node.nodeName().toLowerCase() !== "img") {
- callback();
- return;
- }
- WebInspector.RemoteObject.resolveNode(node, "", resolvedNode);
- function resolvedNode(object)
- {
- if (!object) {
- callback();
- return;
- }
- object.callFunctionJSON(dimensions, undefined, callback);
- object.release();
- function dimensions()
- {
- return { offsetWidth: this.offsetWidth, offsetHeight: this.offsetHeight, naturalWidth: this.naturalWidth, naturalHeight: this.naturalHeight };
- }
- }
- },
- /**
- * @param {Element} anchor
- * @param {WebInspector.Popover} popover
- */
- _showPopover: function(anchor, popover)
- {
- var listItem = anchor.enclosingNodeOrSelfWithNodeName("li");
- if (listItem && listItem.treeElement)
- this._loadDimensionsForNode(listItem.treeElement, WebInspector.DOMPresentationUtils.buildImagePreviewContents.bind(WebInspector.DOMPresentationUtils, anchor.href, true, showPopover));
- else
- WebInspector.DOMPresentationUtils.buildImagePreviewContents(anchor.href, true, showPopover);
- /**
- * @param {Element=} contents
- */
- function showPopover(contents)
- {
- if (!contents)
- return;
- popover.setCanShrink(false);
- popover.show(contents, anchor);
- }
- },
- jumpToNextSearchResult: function()
- {
- if (!this._searchResults)
- return;
- this._hideSearchHighlights();
- if (++this._currentSearchResultIndex >= this._searchResults.length)
- this._currentSearchResultIndex = 0;
- this._highlightCurrentSearchResult();
- },
- jumpToPreviousSearchResult: function()
- {
- if (!this._searchResults)
- return;
- this._hideSearchHighlights();
- if (--this._currentSearchResultIndex < 0)
- this._currentSearchResultIndex = (this._searchResults.length - 1);
- this._highlightCurrentSearchResult();
- },
- _highlightCurrentSearchResult: function()
- {
- var index = this._currentSearchResultIndex;
- var searchResults = this._searchResults;
- var searchResult = searchResults[index];
- if (searchResult === null) {
- WebInspector.searchController.updateCurrentMatchIndex(index, this);
- return;
- }
- if (typeof searchResult === "undefined") {
- // No data for slot, request it.
- function callback(node)
- {
- searchResults[index] = node || null;
- this._highlightCurrentSearchResult();
- }
- WebInspector.domAgent.searchResult(index, callback.bind(this));
- return;
- }
- WebInspector.searchController.updateCurrentMatchIndex(index, this);
- var treeElement = this.treeOutline.findTreeElement(searchResult);
- if (treeElement) {
- treeElement.highlightSearchResults(this._searchQuery);
- treeElement.reveal();
- var matches = treeElement.listItemElement.getElementsByClassName("highlighted-search-result");
- if (matches.length)
- matches[0].scrollIntoViewIfNeeded();
- }
- },
- _hideSearchHighlights: function()
- {
- if (!this._searchResults)
- return;
- var searchResult = this._searchResults[this._currentSearchResultIndex];
- if (!searchResult)
- return;
- var treeElement = this.treeOutline.findTreeElement(searchResult);
- if (treeElement)
- treeElement.hideSearchHighlights();
- },
- /**
- * @return {WebInspector.DOMNode}
- */
- selectedDOMNode: function()
- {
- return this.treeOutline.selectedDOMNode();
- },
- /**
- * @param {boolean=} focus
- */
- selectDOMNode: function(node, focus)
- {
- this.treeOutline.selectDOMNode(node, focus);
- },
- /**
- * @param {WebInspector.Event} event
- */
- _updateBreadcrumbIfNeeded: function(event)
- {
- var nodes = /** @type {!Array.<!WebInspector.DOMNode>} */ (event.data || []);
- if (!nodes.length)
- return;
- var crumbs = this.crumbsElement;
- for (var crumb = crumbs.firstChild; crumb; crumb = crumb.nextSibling) {
- if (nodes.indexOf(crumb.representedObject) !== -1) {
- this.updateBreadcrumb(true);
- return;
- }
- }
- },
- _stylesPaneEdited: function()
- {
- // Once styles are edited, the Metrics pane should be updated.
- this.sidebarPanes.metrics.needsUpdate = true;
- this.updateMetrics();
- this.sidebarPanes.platformFonts.needsUpdate = true;
- this.updatePlatformFonts();
- },
- _metricsPaneEdited: function()
- {
- // Once metrics are edited, the Styles pane should be updated.
- 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.domAgent.highlightDOMNode(crumbElement ? crumbElement.representedObject.id : 0);
- if ("_mouseOutOfCrumbsTimeout" in this) {
- clearTimeout(this._mouseOutOfCrumbsTimeout);
- delete this._mouseOutOfCrumbsTimeout;
- }
- },
- _mouseMovedOutOfCrumbs: function(event)
- {
- var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
- if (nodeUnderMouse && nodeUnderMouse.isDescendant(this.crumbsElement))
- return;
- WebInspector.domAgent.hideDOMNodeHighlight();
- this._mouseOutOfCrumbsTimeout = setTimeout(this.updateBreadcrumbSizes.bind(this), 1000);
- },
- /**
- * @param {boolean=} forceUpdate
- */
- updateBreadcrumb: function(forceUpdate)
- {
- if (!this.isShowing())
- return;
- var crumbs = this.crumbsElement;
- var handled = false;
- var crumb = crumbs.firstChild;
- while (crumb) {
- if (crumb.representedObject === this.selectedDOMNode()) {
- 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
- panel.selectDOMNode(crumb.representedObject, true);
- event.preventDefault();
- }
- for (var current = this.selectedDOMNode(); current; current = current.parentNode) {
- if (current.nodeType() === Node.DOCUMENT_NODE)
- continue;
- crumb = document.createElement("span");
- crumb.className = "crumb";
- crumb.representedObject = current;
- crumb.addEventListener("mousedown", selectCrumbFunction, false);
- var crumbTitle = "";
- switch (current.nodeType()) {
- case Node.ELEMENT_NODE:
- WebInspector.DOMPresentationUtils.decorateNodeLabel(current, crumb);
- break;
- case Node.TEXT_NODE:
- crumbTitle = WebInspector.UIString("(text)");
- break;
- case Node.COMMENT_NODE:
- crumbTitle = "<!-->";
- break;
- case Node.DOCUMENT_TYPE_NODE:
- crumbTitle = "<!DOCTYPE>";
- break;
- default:
- crumbTitle = current.nodeNameInCorrectCase();
- }
- if (!crumb.childNodes.length) {
- var nameElement = document.createElement("span");
- nameElement.textContent = crumbTitle;
- crumb.appendChild(nameElement);
- crumb.title = crumbTitle;
- }
- if (current === this.selectedDOMNode())
- crumb.addStyleClass("selected");
- if (!crumbs.childNodes.length)
- crumb.addStyleClass("end");
- crumbs.appendChild(crumb);
- }
- if (crumbs.hasChildNodes())
- crumbs.lastChild.addStyleClass("start");
- this.updateBreadcrumbSizes();
- },
- /**
- * @param {Element=} focusedCrumb
- */
- updateBreadcrumbSizes: function(focusedCrumb)
- {
- if (!this.isShowing())
- return;
- if (document.body.offsetWidth <= 0) {
- // The stylesheet hasn't loaded yet or the window is closed,
- // so we can't calculate what is need. Return early.
- return;
- }
- var crumbs = this.crumbsElement;
- if (!crumbs.childNodes.length || crumbs.offsetWidth <= 0)
- return; // No crumbs, do nothing.
- // A Zero index is the right most child crumb in the breadcrumb.
- var selectedIndex = 0;
- var focusedIndex = 0;
- var selectedCrumb;
- var i = 0;
- var crumb = crumbs.firstChild;
- while (crumb) {
- // Find the selected crumb and index.
- if (!selectedCrumb && crumb.hasStyleClass("selected")) {
- selectedCrumb = crumb;
- selectedIndex = i;
- }
- // Find the focused crumb index.
- if (crumb === focusedCrumb)
- focusedIndex = i;
- // Remove any styles that affect size before
- // deciding to shorten any crumbs.
- if (crumb !== crumbs.lastChild)
- crumb.removeStyleClass("start");
- if (crumb !== crumbs.firstChild)
- crumb.removeStyleClass("end");
- crumb.removeStyleClass("compact");
- crumb.removeStyleClass("collapsed");
- crumb.removeStyleClass("hidden");
- crumb = crumb.nextSibling;
- ++i;
- }
- // Restore the start and end crumb classes in case they got removed in coalesceCollapsedCrumbs().
- // The order of the crumbs in the document is opposite of the visual order.
- crumbs.firstChild.addStyleClass("end");
- crumbs.lastChild.addStyleClass("start");
- var rightPadding = 20;
- var crumbsTotalOffsetLeft = crumbs.totalOffsetLeft();
- var windowInnerWidth = window.innerWidth;
- var errorWarningElement = document.getElementById("error-warning-count");
- if (!WebInspector.drawer.visible) {
- if (errorWarningElement)
- rightPadding += errorWarningElement.offsetWidth;
- rightPadding += WebInspector.settingsController.statusBarItem.offsetWidth;
- }
- function crumbsAreSmallerThanContainer()
- {
- return (crumbsTotalOffsetLeft + crumbs.offsetWidth + rightPadding) < windowInnerWidth;
- }
- if (crumbsAreSmallerThanContainer())
- return; // No need to compact the crumbs, they all fit at full size.
- var BothSides = 0;
- var AncestorSide = -1;
- var ChildSide = 1;
- /**
- * @param {boolean=} significantCrumb
- */
- function makeCrumbsSmaller(shrinkingFunction, direction, significantCrumb)
- {
- if (!significantCrumb)
- significantCrumb = (focusedCrumb || selectedCrumb);
- if (significantCrumb === selectedCrumb)
- var significantIndex = selectedIndex;
- else if (significantCrumb === focusedCrumb)
- var significantIndex = focusedIndex;
- else {
- var significantIndex = 0;
- for (var i = 0; i < crumbs.childNodes.length; ++i) {
- if (crumbs.childNodes[i] === significantCrumb) {
- significantIndex = i;
- break;
- }
- }
- }
- function shrinkCrumbAtIndex(index)
- {
- var shrinkCrumb = crumbs.childNodes[index];
- if (shrinkCrumb && shrinkCrumb !== significantCrumb)
- shrinkingFunction(shrinkCrumb);
- if (crumbsAreSmallerThanContainer())
- return true; // No need to compact the crumbs more.
- return false;
- }
- // Shrink crumbs one at a time by applying the shrinkingFunction until the crumbs
- // fit in the container or we run out of crumbs to shrink.
- if (direction) {
- // Crumbs are shrunk on only one side (based on direction) of the signifcant crumb.
- var index = (direction > 0 ? 0 : crumbs.childNodes.length - 1);
- while (index !== significantIndex) {
- if (shrinkCrumbAtIndex(index))
- return true;
- index += (direction > 0 ? 1 : -1);
- }
- } else {
- // Crumbs are shrunk in order of descending distance from the signifcant crumb,
- // with a tie going to child crumbs.
- var startIndex = 0;
- var endIndex = crumbs.childNodes.length - 1;
- while (startIndex != significantIndex || endIndex != significantIndex) {
- var startDistance = significantIndex - startIndex;
- var endDistance = endIndex - significantIndex;
- if (startDistance >= endDistance)
- var index = startIndex++;
- else
- var index = endIndex--;
- if (shrinkCrumbAtIndex(index))
- return true;
- }
- }
- // We are not small enough yet, return false so the caller knows.
- return false;
- }
- function coalesceCollapsedCrumbs()
- {
- var crumb = crumbs.firstChild;
- var collapsedRun = false;
- var newStartNeeded = false;
- var newEndNeeded = false;
- while (crumb) {
- var hidden = crumb.hasStyleClass("hidden");
- if (!hidden) {
- var collapsed = crumb.hasStyleClass("collapsed");
- if (collapsedRun && collapsed) {
- crumb.addStyleClass("hidden");
- crumb.removeStyleClass("compact");
- crumb.removeStyleClass("collapsed");
- if (crumb.hasStyleClass("start")) {
- crumb.removeStyleClass("start");
- newStartNeeded = true;
- }
- if (crumb.hasStyleClass("end")) {
- crumb.removeStyleClass("end");
- newEndNeeded = true;
- }
- continue;
- }
- collapsedRun = collapsed;
- if (newEndNeeded) {
- newEndNeeded = false;
- crumb.addStyleClass("end");
- }
- } else
- collapsedRun = true;
- crumb = crumb.nextSibling;
- }
- if (newStartNeeded) {
- crumb = crumbs.lastChild;
- while (crumb) {
- if (!crumb.hasStyleClass("hidden")) {
- crumb.addStyleClass("start");
- break;
- }
- crumb = crumb.previousSibling;
- }
- }
- }
- function compact(crumb)
- {
- if (crumb.hasStyleClass("hidden"))
- return;
- crumb.addStyleClass("compact");
- }
- function collapse(crumb, dontCoalesce)
- {
- if (crumb.hasStyleClass("hidden"))
- return;
- crumb.addStyleClass("collapsed");
- crumb.removeStyleClass("compact");
- if (!dontCoalesce)
- coalesceCollapsedCrumbs();
- }
- if (!focusedCrumb) {
- // When not focused on a crumb we can be biased and collapse less important
- // crumbs that the user might not care much about.
- // Compact child crumbs.
- if (makeCrumbsSmaller(compact, ChildSide))
- return;
- // Collapse child crumbs.
- if (makeCrumbsSmaller(collapse, ChildSide))
- return;
- }
- // Compact ancestor crumbs, or from both sides if focused.
- if (makeCrumbsSmaller(compact, (focusedCrumb ? BothSides : AncestorSide)))
- return;
- // Collapse ancestor crumbs, or from both sides if focused.
- if (makeCrumbsSmaller(collapse, (focusedCrumb ? BothSides : AncestorSide)))
- return;
- if (!selectedCrumb)
- return;
- // Compact the selected crumb.
- compact(selectedCrumb);
- if (crumbsAreSmallerThanContainer())
- return;
- // Collapse the selected crumb as a last resort. Pass true to prevent coalescing.
- collapse(selectedCrumb, true);
- },
- /**
- * @param {boolean=} forceUpdate
- */
- updateStyles: function(forceUpdate)
- {
- var stylesSidebarPane = this.sidebarPanes.styles;
- var computedStylePane = this.sidebarPanes.computedStyle;
- if ((!stylesSidebarPane.isShowing() && !computedStylePane.isShowing()) || !stylesSidebarPane.needsUpdate)
- return;
- stylesSidebarPane.update(this.selectedDOMNode(), forceUpdate);
- stylesSidebarPane.needsUpdate = false;
- },
- updateMetrics: function()
- {
- var metricsSidebarPane = this.sidebarPanes.metrics;
- if (!metricsSidebarPane.isShowing() || !metricsSidebarPane.needsUpdate)
- return;
- metricsSidebarPane.update(this.selectedDOMNode());
- metricsSidebarPane.needsUpdate = false;
- },
- updatePlatformFonts: function()
- {
- var platformFontsSidebar = this.sidebarPanes.platformFonts;
- if (!platformFontsSidebar.isShowing() || !platformFontsSidebar.needsUpdate)
- return;
- platformFontsSidebar.update(this.selectedDOMNode());
- platformFontsSidebar.needsUpdate = false;
- },
- updateProperties: function()
- {
- var propertiesSidebarPane = this.sidebarPanes.properties;
- if (!propertiesSidebarPane.isShowing() || !propertiesSidebarPane.needsUpdate)
- return;
- propertiesSidebarPane.update(this.selectedDOMNode());
- propertiesSidebarPane.needsUpdate = false;
- },
- updateEventListeners: function()
- {
- var eventListenersSidebarPane = this.sidebarPanes.eventListeners;
- if (!eventListenersSidebarPane.isShowing() || !eventListenersSidebarPane.needsUpdate)
- return;
- eventListenersSidebarPane.update(this.selectedDOMNode());
- eventListenersSidebarPane.needsUpdate = false;
- },
- handleShortcut: function(event)
- {
- function handleUndoRedo()
- {
- if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && !event.shiftKey && event.keyIdentifier === "U+005A") { // Z key
- WebInspector.domAgent.undo(this._updateSidebars.bind(this));
- event.handled = true;
- return;
- }
- var isRedoKey = WebInspector.isMac() ? event.metaKey && event.shiftKey && event.keyIdentifier === "U+005A" : // Z key
- event.ctrlKey && event.keyIdentifier === "U+0059"; // Y key
- if (isRedoKey) {
- DOMAgent.redo(this._updateSidebars.bind(this));
- event.handled = true;
- }
- }
- if (!this.treeOutline.editing()) {
- handleUndoRedo.call(this);
- if (event.handled)
- return;
- }
- this.treeOutline.handleShortcut(event);
- },
- handleCopyEvent: function(event)
- {
- var currentFocusElement = WebInspector.currentFocusElement();
- if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElement))
- return;
- // Don't prevent the normal copy if the user has a selection.
- if (!window.getSelection().isCollapsed)
- return;
- event.clipboardData.clearData();
- event.preventDefault();
- this.selectedDOMNode().copyNode();
- },
- sidebarResized: function(event)
- {
- this.treeOutline.updateSelection();
- },
- revealAndSelectNode: function(nodeId)
- {
- WebInspector.inspectorView.setCurrentPanel(this);
- var node = WebInspector.domAgent.nodeForId(nodeId);
- if (!node)
- return;
- while (!WebInspector.ElementsTreeOutline.showShadowDOM() && node && node.isInShadowTree())
- node = node.parentNode;
- WebInspector.domAgent.highlightDOMNodeForTwoSeconds(nodeId);
- this.selectDOMNode(node, true);
- },
- /**
- * @param {WebInspector.ContextMenu} contextMenu
- * @param {Object} target
- */
- appendApplicableItems: function(event, contextMenu, target)
- {
- /**
- * @param {?DOMAgent.NodeId} nodeId
- */
- function selectNode(nodeId)
- {
- if (nodeId)
- WebInspector.domAgent.inspectElement(nodeId);
- }
- /**
- * @param {WebInspector.RemoteObject} remoteObject
- */
- function revealElement(remoteObject)
- {
- remoteObject.pushNodeToFrontend(selectNode);
- }
- var commandCallback;
- if (target instanceof WebInspector.RemoteObject) {
- var remoteObject = /** @type {WebInspector.RemoteObject} */ (target);
- if (remoteObject.subtype === "node")
- commandCallback = revealElement.bind(this, remoteObject);
- } else if (target instanceof WebInspector.DOMNode) {
- var domNode = /** @type {WebInspector.DOMNode} */ (target);
- if (domNode.id)
- commandCallback = WebInspector.domAgent.inspectElement.bind(WebInspector.domAgent, domNode.id);
- }
- if (!commandCallback)
- return;
- // Skip adding "Reveal..." menu item for our own tree outline.
- if (this.treeOutline.element.isAncestor(event.target))
- return;
- contextMenu.appendItem(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Elements panel" : "Reveal in Elements Panel", commandCallback);
- },
- _sidebarContextMenuEventFired: function(event)
- {
- var contextMenu = new WebInspector.ContextMenu(event);
- contextMenu.show();
- },
- _dockSideChanged: function()
- {
- var dockSide = WebInspector.dockController.dockSide();
- var vertically = dockSide === WebInspector.DockController.State.DockedToRight && WebInspector.settings.splitVerticallyWhenDockedToRight.get();
- this._splitVertically(vertically);
- },
- _showShadowDOMChanged: function()
- {
- this.treeOutline.update();
- },
- /**
- * @param {boolean} vertically
- */
- _splitVertically: function(vertically)
- {
- if (this.sidebarPaneView && vertically === !this.splitView.isVertical())
- return;
- if (this.sidebarPaneView)
- this.sidebarPaneView.detach();
- this.splitView.setVertical(!vertically);
- var computedPane = new WebInspector.SidebarPane(WebInspector.UIString("Computed"));
- computedPane.element.addStyleClass("composite");
- computedPane.element.addStyleClass("fill");
- var expandComputed = computedPane.expand.bind(computedPane);
- computedPane.bodyElement.appendChild(this.sidebarPanes.computedStyle.titleElement);
- computedPane.bodyElement.addStyleClass("metrics-and-computed");
- this.sidebarPanes.computedStyle.show(computedPane.bodyElement);
- this.sidebarPanes.computedStyle.setExpandCallback(expandComputed);
- this.sidebarPanes.platformFonts.show(computedPane.bodyElement);
- if (vertically) {
- this.sidebarPanes.metrics.show(computedPane.bodyElement, this.sidebarPanes.computedStyle.element);
- this.sidebarPanes.metrics.setExpandCallback(expandComputed);
- this.sidebarPaneView = new WebInspector.SidebarTabbedPane();
- var compositePane = new WebInspector.SidebarPane(this.sidebarPanes.styles.title());
- compositePane.element.addStyleClass("composite");
- compositePane.element.addStyleClass("fill");
- var expandComposite = compositePane.expand.bind(compositePane);
- var splitView = new WebInspector.SplitView(true, "StylesPaneSplitRatio", 0.5);
- splitView.show(compositePane.bodyElement);
- this.sidebarPanes.styles.show(splitView.firstElement());
- splitView.firstElement().appendChild(this.sidebarPanes.styles.titleElement);
- this.sidebarPanes.styles.setExpandCallback(expandComposite);
- computedPane.show(splitView.secondElement());
- computedPane.setExpandCallback(expandComposite);
- this.sidebarPaneView.addPane(compositePane);
- this.sidebarPaneView.addPane(this.sidebarPanes.properties);
- this.sidebarPaneView.addPane(this.sidebarPanes.domBreakpoints);
- this.sidebarPaneView.addPane(this.sidebarPanes.eventListeners);
- } else {
- this.sidebarPaneView = new WebInspector.SidebarTabbedPane();
- var stylesPane = new WebInspector.SidebarPane(this.sidebarPanes.styles.title());
- stylesPane.element.addStyleClass("composite");
- stylesPane.element.addStyleClass("fill");
- var expandStyles = stylesPane.expand.bind(stylesPane);
- stylesPane.bodyElement.addStyleClass("metrics-and-styles");
- this.sidebarPanes.styles.show(stylesPane.bodyElement);
- this.sidebarPanes.styles.setExpandCallback(expandStyles);
- this.sidebarPanes.metrics.setExpandCallback(expandStyles);
- stylesPane.bodyElement.appendChild(this.sidebarPanes.styles.titleElement);
- /**
- * @param {WebInspector.SidebarPane} pane
- * @param {Element=} beforeElement
- */
- function showMetrics(pane, beforeElement)
- {
- this.sidebarPanes.metrics.show(pane.bodyElement, beforeElement);
- }
- /**
- * @param {WebInspector.Event} event
- */
- function tabSelected(event)
- {
- var tabId = /** @type {string} */ (event.data.tabId);
- if (tabId === computedPane.title())
- showMetrics.call(this, computedPane, this.sidebarPanes.computedStyle.element);
- if (tabId === stylesPane.title())
- showMetrics.call(this, stylesPane);
- }
- this.sidebarPaneView.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, tabSelected, this);
- showMetrics.call(this, stylesPane);
- this.sidebarPaneView.addPane(stylesPane);
- this.sidebarPaneView.addPane(computedPane);
- this.sidebarPaneView.addPane(this.sidebarPanes.eventListeners);
- this.sidebarPaneView.addPane(this.sidebarPanes.domBreakpoints);
- this.sidebarPaneView.addPane(this.sidebarPanes.properties);
- }
- this.sidebarPaneView.show(this.splitView.sidebarElement);
- this.sidebarPanes.styles.expand();
- },
- /**
- * @param {string} id
- * @param {WebInspector.SidebarPane} pane
- */
- addExtensionSidebarPane: function(id, pane)
- {
- this.sidebarPanes[id] = pane;
- this.sidebarPaneView.addPane(pane);
- },
- __proto__: WebInspector.Panel.prototype
- }
|