--- a/devtools/client/inspector/boxmodel/box-model.js
+++ b/devtools/client/inspector/boxmodel/box-model.js
@@ -21,17 +21,16 @@ const NUMERIC = /^-?[\d\.]+$/;
*
* @param {Inspector} inspector
* An instance of the Inspector currently loaded in the toolbox.
* @param {Window} window
* The document window of the toolbox.
*/
function BoxModel(inspector, window) {
this.document = window.document;
- this.highlighters = inspector.highlighters;
this.inspector = inspector;
this.store = inspector.store;
this.updateBoxModel = this.updateBoxModel.bind(this);
this.onHideBoxModelHighlighter = this.onHideBoxModelHighlighter.bind(this);
this.onHideGeometryEditor = this.onHideGeometryEditor.bind(this);
this.onMarkupViewLeave = this.onMarkupViewLeave.bind(this);
@@ -53,22 +52,29 @@ BoxModel.prototype = {
* and cleans up references.
*/
destroy() {
this.inspector.selection.off("new-node-front", this.onNewSelection);
this.inspector.sidebar.off("select", this.onSidebarSelect);
this.untrackReflows();
+ this._highlighters = null;
this.document = null;
- this.highlighters = null;
this.inspector = null;
this.walker = null;
},
+ get highlighters() {
+ if (!this._highlighters) {
+ // highlighters is a lazy getter in the inspector.
+ this._highlighters = this.inspector.highlighters;
+ }
+ },
+
/**
* Returns an object containing the box model's handler functions used in the box
* model's React component props.
*/
getComponentProps() {
return {
onHideBoxModelHighlighter: this.onHideBoxModelHighlighter,
onShowBoxModelEditor: this.onShowBoxModelEditor,
--- a/devtools/client/inspector/computed/computed.js
+++ b/devtools/client/inspector/computed/computed.js
@@ -145,49 +145,51 @@ UpdateProcess.prototype = {
* @param {Document} document
* The document that will contain the computed view.
* @param {PageStyleFront} pageStyle
* Front for the page style actor that will be providing
* the style information.
*/
function CssComputedView(inspector, document, pageStyle) {
this.inspector = inspector;
- this.highlighters = inspector.highlighters;
this.styleDocument = document;
this.styleWindow = this.styleDocument.defaultView;
this.pageStyle = pageStyle;
this.propertyViews = [];
let cssProperties = getCssProperties(inspector.toolbox);
this._outputParser = new OutputParser(document, cssProperties);
// Create bound methods.
this.focusWindow = this.focusWindow.bind(this);
+ this._onClearSearch = this._onClearSearch.bind(this);
+ this._onClick = this._onClick.bind(this);
this._onContextMenu = this._onContextMenu.bind(this);
- this._onClick = this._onClick.bind(this);
this._onCopy = this._onCopy.bind(this);
this._onFilterStyles = this._onFilterStyles.bind(this);
- this._onClearSearch = this._onClearSearch.bind(this);
this._onIncludeBrowserStyles = this._onIncludeBrowserStyles.bind(this);
let doc = this.styleDocument;
this.element = doc.getElementById("computed-property-container");
this.searchField = doc.getElementById("computed-searchbox");
this.searchClearButton = doc.getElementById("computed-searchinput-clear");
this.includeBrowserStylesCheckbox = doc.getElementById("browser-style-checkbox");
this.shortcuts = new KeyShortcuts({ window: this.styleWindow });
this._onShortcut = this._onShortcut.bind(this);
this.shortcuts.on("CmdOrCtrl+F", event => this._onShortcut("CmdOrCtrl+F", event));
this.shortcuts.on("Escape", event => this._onShortcut("Escape", event));
this.styleDocument.addEventListener("copy", this._onCopy);
this.styleDocument.addEventListener("mousedown", this.focusWindow);
this.element.addEventListener("click", this._onClick);
this.element.addEventListener("contextmenu", this._onContextMenu);
+ this.element.addEventListener("mousemove", () => {
+ this.addHighlightersToView();
+ }, { once: true });
this.searchField.addEventListener("input", this._onFilterStyles);
this.searchClearButton.addEventListener("click", this._onClearSearch);
this.includeBrowserStylesCheckbox.addEventListener("input",
this._onIncludeBrowserStyles);
this.searchClearButton.hidden = true;
// No results text.
@@ -201,18 +203,16 @@ function CssComputedView(inspector, docu
// The element that we're inspecting, and the document that it comes from.
this._viewedElement = null;
this.createStyleViews();
// Add the tooltips and highlightersoverlay
this.tooltips = new TooltipsOverlay(this);
-
- this.highlighters.addToView(this);
}
/**
* Lookup a l10n string in the shared styleinspector string bundle.
*
* @param {String} name
* The key to lookup.
* @returns {String} localized version of the given key.
@@ -245,16 +245,26 @@ CssComputedView.prototype = {
get contextMenu() {
if (!this._contextMenu) {
this._contextMenu = new StyleInspectorMenu(this, { isRuleView: false });
}
return this._contextMenu;
},
+ // Get the highlighters overlay from the Inspector.
+ get highlighters() {
+ if (!this._highlighters) {
+ // highlighters is a lazy getter in the inspector.
+ this._highlighters = this.inspector.highlighters;
+ }
+
+ return this._highlighters;
+ },
+
setPageStyle: function(pageStyle) {
this.pageStyle = pageStyle;
},
get includeBrowserStyles() {
return this.includeBrowserStylesCheckbox.checked;
},
@@ -718,16 +728,24 @@ CssComputedView.prototype = {
clipboardHelper.copyString(text);
} catch (e) {
console.error(e);
}
},
/**
+ * Adds the highlighters overlay to the computed view. This is called by the "mousemove"
+ * event handler and in shared-head.js when opening and selecting the computed view.
+ */
+ addHighlightersToView() {
+ this.highlighters.addToView(this);
+ },
+
+ /**
* Destructor for CssComputedView.
*/
destroy: function() {
this._viewedElement = null;
this._outputParser = null;
this._prefObserver.off("devtools.defaultColorUnit", this._handlePrefChange);
this._prefObserver.destroy();
@@ -740,43 +758,46 @@ CssComputedView.prototype = {
this._refreshProcess.cancel();
}
if (this._contextMenu) {
this._contextMenu.destroy();
this._contextMenu = null;
}
+ if (this._highlighters) {
+ this._highlighters.removeFromView(this);
+ this._highlighters = null;
+ }
+
this.tooltips.destroy();
- this.highlighters.removeFromView(this);
// Remove bound listeners
- this.styleDocument.removeEventListener("mousedown", this.focusWindow);
this.element.removeEventListener("click", this._onClick);
- this.styleDocument.removeEventListener("copy", this._onCopy);
this.element.removeEventListener("contextmenu", this._onContextMenu);
this.searchField.removeEventListener("input", this._onFilterStyles);
this.searchClearButton.removeEventListener("click", this._onClearSearch);
+ this.styleDocument.removeEventListener("copy", this._onCopy);
+ this.styleDocument.removeEventListener("mousedown", this.focusWindow);
this.includeBrowserStylesCheckbox.removeEventListener("input",
this._onIncludeBrowserStyles);
// Nodes used in templating
this.element = null;
this.searchField = null;
this.searchClearButton = null;
this.includeBrowserStylesCheckbox = null;
// Property views
for (let propView of this.propertyViews) {
propView.destroy();
}
this.propertyViews = null;
this.inspector = null;
- this.highlighters = null;
this.styleDocument = null;
this.styleWindow = null;
this._isDestroyed = true;
}
};
function PropertyInfo(tree, name) {
--- a/devtools/client/inspector/flexbox/flexbox.js
+++ b/devtools/client/inspector/flexbox/flexbox.js
@@ -10,64 +10,79 @@ const {
clearFlexbox,
updateFlexbox,
updateFlexboxHighlighted,
} = require("./actions/flexbox");
class FlexboxInspector {
constructor(inspector, window) {
this.document = window.document;
- this.highlighters = inspector.highlighters;
this.inspector = inspector;
this.store = inspector.store;
this.walker = inspector.walker;
this.onHighlighterShown = this.onHighlighterShown.bind(this);
this.onHighlighterHidden = this.onHighlighterHidden.bind(this);
this.onReflow = throttle(this.onReflow, 500, this);
this.onSidebarSelect = this.onSidebarSelect.bind(this);
this.onToggleFlexboxHighlighter = this.onToggleFlexboxHighlighter.bind(this);
this.onUpdatePanel = this.onUpdatePanel.bind(this);
this.init();
}
+ // Get the highlighters overlay from the Inspector.
+ get highlighters() {
+ if (!this._highlighters) {
+ // highlighters is a lazy getter in the inspector.
+ this._highlighters = this.inspector.highlighters;
+ }
+
+ return this._highlighters;
+ }
+
async init() {
if (!this.inspector) {
return;
}
try {
this.hasGetCurrentFlexbox = await this.inspector.target.actorHasMethod("layout",
"getCurrentFlexbox");
this.layoutInspector = await this.walker.getLayoutInspector();
} catch (e) {
// These calls might fail if called asynchrously after the toolbox is finished
// closing.
return;
}
- this.highlighters.on("flexbox-highlighter-hidden", this.onHighlighterHidden);
- this.highlighters.on("flexbox-highlighter-shown", this.onHighlighterShown);
+ this.document.addEventListener("mousemove", () => {
+ this.highlighters.on("flexbox-highlighter-hidden", this.onHighlighterHidden);
+ this.highlighters.on("flexbox-highlighter-shown", this.onHighlighterShown);
+ }, { once: true });
+
this.inspector.sidebar.on("select", this.onSidebarSelect);
this.onSidebarSelect();
}
destroy() {
- this.highlighters.off("flexbox-highlighter-hidden", this.onHighlighterHidden);
- this.highlighters.off("flexbox-highlighter-shown", this.onHighlighterShown);
+ if (this._highlighters) {
+ this.highlighters.off("flexbox-highlighter-hidden", this.onHighlighterHidden);
+ this.highlighters.off("flexbox-highlighter-shown", this.onHighlighterShown);
+ }
+
this.inspector.selection.off("new-node-front", this.onUpdatePanel);
this.inspector.sidebar.off("select", this.onSidebarSelect);
this.inspector.off("new-root", this.onUpdatePanel);
this.inspector.reflowTracker.untrackReflows(this, this.onReflow);
+ this._highlighters = null;
this.document = null;
this.hasGetCurrentFlexbox = null;
- this.highlighters = null;
this.inspector = null;
this.layoutInspector = null;
this.store = null;
this.walker = null;
}
getComponentProps() {
return {
@@ -269,17 +284,20 @@ class FlexboxInspector {
["containerEl"]);
} catch (e) {
// This call might fail if called asynchrously after the toolbox is finished
// closing.
return;
}
}
+ let highlighted = this._highlighters &&
+ nodeFront == this.highlighters.flexboxHighlighterShown;
+
this.store.dispatch(updateFlexbox({
actorID: flexboxFront.actorID,
- highlighted: nodeFront == this.highlighters.flexboxHighlighterShown,
+ highlighted,
nodeFront,
}));
}
}
module.exports = FlexboxInspector;
--- a/devtools/client/inspector/grids/grid-inspector.js
+++ b/devtools/client/inspector/grids/grid-inspector.js
@@ -47,17 +47,16 @@ const GRID_COLORS = [
"#058B00",
"#A47F00",
"#005A71"
];
class GridInspector {
constructor(inspector, window) {
this.document = window.document;
- this.highlighters = inspector.highlighters;
this.inspector = inspector;
this.store = inspector.store;
this.telemetry = inspector.telemetry;
this.walker = this.inspector.walker;
this.getSwatchColorPickerTooltip = this.getSwatchColorPickerTooltip.bind(this);
this.updateGridPanel = this.updateGridPanel.bind(this);
@@ -71,16 +70,24 @@ class GridInspector {
this.onToggleGridHighlighter = this.onToggleGridHighlighter.bind(this);
this.onToggleShowGridAreas = this.onToggleShowGridAreas.bind(this);
this.onToggleShowGridLineNumbers = this.onToggleShowGridLineNumbers.bind(this);
this.onToggleShowInfiniteLines = this.onToggleShowInfiniteLines.bind(this);
this.init();
}
+ get highlighters() {
+ if (!this._highlighters) {
+ this._highlighters = this.inspector.highlighters;
+ }
+
+ return this._highlighters;
+ }
+
/**
* Initializes the grid inspector by fetching the LayoutFront from the walker, loading
* the highlighter settings and initalizing the SwatchColorPicker instance.
*/
async init() {
if (!this.inspector) {
return;
}
@@ -97,44 +104,50 @@ class GridInspector {
this.swatchColorPickerTooltip = new SwatchColorPickerTooltip(
this.inspector.toolbox.doc,
this.inspector,
{
supportsCssColor4ColorFunction: () => false
}
);
- this.highlighters.on("grid-highlighter-hidden", this.onHighlighterHidden);
- this.highlighters.on("grid-highlighter-shown", this.onHighlighterShown);
+ this.document.addEventListener("mousemove", () => {
+ this.highlighters.on("grid-highlighter-hidden", this.onHighlighterHidden);
+ this.highlighters.on("grid-highlighter-shown", this.onHighlighterShown);
+ }, { once: true });
+
this.inspector.sidebar.on("select", this.onSidebarSelect);
this.inspector.on("new-root", this.onNavigate);
this.onSidebarSelect();
}
/**
* Destruction function called when the inspector is destroyed. Removes event listeners
* and cleans up references.
*/
destroy() {
- this.highlighters.off("grid-highlighter-hidden", this.onHighlighterHidden);
- this.highlighters.off("grid-highlighter-shown", this.onHighlighterShown);
+ if (this._highlighters) {
+ this.highlighters.off("grid-highlighter-hidden", this.onHighlighterHidden);
+ this.highlighters.off("grid-highlighter-shown", this.onHighlighterShown);
+ }
+
this.inspector.sidebar.off("select", this.onSidebarSelect);
this.inspector.off("new-root", this.onNavigate);
this.inspector.reflowTracker.untrackReflows(this, this.onReflow);
// The color picker may not be ready as `init` function is async,
// and we do not wait for its completion before calling destroy in tests
if (this.swatchColorPickerTooltip) {
this.swatchColorPickerTooltip.destroy();
}
+ this._highlighters = null;
this.document = null;
- this.highlighters = null;
this.inspector = null;
this.layoutInspector = null;
this.store = null;
this.swatchColorPickerTooltip = null;
this.walker = null;
}
getComponentProps() {
@@ -158,17 +171,18 @@ class GridInspector {
* @param {String} customColor
* The color fetched from the custom palette, if it exists.
* @param {String} fallbackColor
* The color to use if no color could be found for the node front.
* @return {String} color
* The color to use.
*/
getInitialGridColor(nodeFront, customColor, fallbackColor) {
- let highlighted = nodeFront == this.highlighters.gridHighlighterShown;
+ let highlighted = this._highlighters &&
+ nodeFront == this.highlighters.gridHighlighterShown;
let color;
if (customColor) {
color = customColor;
} else if (highlighted && this.highlighters.state.grid.options) {
// If the node front is currently highlighted, use the color from the highlighter
// options.
color = this.highlighters.state.grid.options.color;
@@ -290,24 +304,26 @@ class GridInspector {
// closing.
return;
}
}
let colorForHost = customColors[hostname] ? customColors[hostname][i] : undefined;
let fallbackColor = GRID_COLORS[i % GRID_COLORS.length];
let color = this.getInitialGridColor(nodeFront, colorForHost, fallbackColor);
+ let highlighted = this._highlighters &&
+ nodeFront == this.highlighters.gridHighlighterShown;
grids.push({
id: i,
actorID: grid.actorID,
color,
direction: grid.direction,
gridFragments: grid.gridFragments,
- highlighted: nodeFront == this.highlighters.gridHighlighterShown,
+ highlighted,
nodeFront,
writingMode: grid.writingMode,
});
}
this.store.dispatch(updateGrids(grids));
this.inspector.emit("grid-panel-updated");
}
@@ -422,17 +438,18 @@ class GridInspector {
// Otherwise, continue comparing with the new grids.
const newNodeFronts = newGridFronts.filter(grid => grid.containerNodeFront)
.map(grid => grid.containerNodeFront.actorID);
if (grids.length === newGridFronts.length &&
oldNodeFronts.sort().join(",") == newNodeFronts.sort().join(",")) {
// Same list of containers, but let's check if the geometry of the current grid has
// changed, if it hasn't we can safely abort.
- if (!this.highlighters.gridHighlighterShown ||
+ if (!this._highlighters ||
+ !this.highlighters.gridHighlighterShown ||
(this.highlighters.gridHighlighterShown &&
!this.haveCurrentFragmentsChanged(newGridFronts))) {
return;
}
}
// Either the list of containers or the current fragments have changed, do update.
this.updateGridPanel(newGridFronts);
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -8,32 +8,32 @@
"use strict";
const Services = require("Services");
const promise = require("promise");
const EventEmitter = require("devtools/shared/event-emitter");
const {executeSoon} = require("devtools/shared/DevToolsUtils");
const {Toolbox} = require("devtools/client/framework/toolbox");
-const HighlightersOverlay = require("devtools/client/inspector/shared/highlighters-overlay");
const ReflowTracker = require("devtools/client/inspector/shared/reflow-tracker");
const Store = require("devtools/client/inspector/store");
const InspectorStyleChangeTracker = require("devtools/client/inspector/shared/style-change-tracker");
// Use privileged promise in panel documents to prevent having them to freeze
// during toolbox destruction. See bug 1402779.
const Promise = require("Promise");
loader.lazyRequireGetter(this, "initCssProperties", "devtools/shared/fronts/css-properties", true);
loader.lazyRequireGetter(this, "HTMLBreadcrumbs", "devtools/client/inspector/breadcrumbs", true);
loader.lazyRequireGetter(this, "ThreePaneOnboardingTooltip", "devtools/client/inspector/shared/three-pane-onboarding-tooltip");
loader.lazyRequireGetter(this, "KeyShortcuts", "devtools/client/shared/key-shortcuts");
loader.lazyRequireGetter(this, "InspectorSearch", "devtools/client/inspector/inspector-search", true);
loader.lazyRequireGetter(this, "ToolSidebar", "devtools/client/inspector/toolsidebar", true);
loader.lazyRequireGetter(this, "MarkupView", "devtools/client/inspector/markup/markup");
+loader.lazyRequireGetter(this, "HighlightersOverlay", "devtools/client/inspector/shared/highlighters-overlay");
loader.lazyRequireGetter(this, "nodeConstants", "devtools/shared/dom-node-constants");
loader.lazyRequireGetter(this, "Menu", "devtools/client/framework/menu");
loader.lazyRequireGetter(this, "MenuItem", "devtools/client/framework/menu-item");
loader.lazyRequireGetter(this, "ExtensionSidebar", "devtools/client/inspector/extensions/extension-sidebar");
loader.lazyRequireGetter(this, "CommandUtils", "devtools/client/shared/developer-toolbar", true);
loader.lazyRequireGetter(this, "clipboardHelper", "devtools/shared/platform/clipboard");
const {LocalizationHelper, localizeMarkup} = require("devtools/shared/l10n");
@@ -107,17 +107,16 @@ function Inspector(toolbox) {
this.telemetry = toolbox.telemetry;
this.store = Store();
// Map [panel id => panel instance]
// Stores all the instances of sidebar panels like rule view, computed view, ...
this._panels = new Map();
- this.highlighters = new HighlightersOverlay(this);
this.reflowTracker = new ReflowTracker(this._target);
this.styleChangeTracker = new InspectorStyleChangeTracker(this);
// Store the URL of the target page prior to navigation in order to ensure
// telemetry counts in the Grid Inspector are not double counted on reload.
this.previousURL = this.target.url;
this.is3PaneModeEnabled = Services.prefs.getBoolPref(THREE_PANE_ENABLED_PREF);
@@ -184,16 +183,24 @@ Inspector.prototype = {
get selection() {
return this.toolbox.selection;
},
get highlighter() {
return this.toolbox.highlighter;
},
+ get highlighters() {
+ if (!this._highlighters) {
+ this._highlighters = new HighlightersOverlay(this);
+ }
+
+ return this._highlighters;
+ },
+
// Added in 53.
get canGetCssPath() {
return this._target.client.traits.getCssPath;
},
// Added in 56.
get canGetXPath() {
return this._target.client.traits.getXPath;
@@ -1085,20 +1092,22 @@ Inspector.prototype = {
async onMarkupLoaded() {
if (!this.markup) {
return;
}
let onExpand = this.markup.expandNode(this.selection.nodeFront);
// Restore the highlighter states prior to emitting "new-root".
- await Promise.all([
- this.highlighters.restoreFlexboxState(),
- this.highlighters.restoreGridState()
- ]);
+ if (this._highlighters) {
+ await Promise.all([
+ this.highlighters.restoreFlexboxState(),
+ this.highlighters.restoreGridState()
+ ]);
+ }
this.emit("new-root");
// Wait for full expand of the selected node in order to ensure
// the markup view is fully emitted before firing 'reloaded'.
// 'reloaded' is used to know when the panel is fully updated
// after a page reload.
await onExpand;
@@ -1309,51 +1318,53 @@ Inspector.prototype = {
if (this.animationinspector) {
this.animationinspector.destroy();
}
if (this.threePaneTooltip) {
this.threePaneTooltip.destroy();
}
+ if (this._highlighters) {
+ this._highlighters.destroy();
+ this._highlighters = null;
+ }
+
let cssPropertiesDestroyer = this._cssProperties.front.destroy();
let sidebarDestroyer = this.sidebar.destroy();
let ruleViewSideBarDestroyer = this.ruleViewSideBar ?
this.ruleViewSideBar.destroy() : null;
let markupDestroyer = this._destroyMarkup();
- let highlighterDestroyer = this.highlighters.destroy();
this.teardownSplitter();
this.teardownToolbar();
this.breadcrumbs.destroy();
this.reflowTracker.destroy();
this.styleChangeTracker.destroy();
this.search.destroy();
this._notificationBox = null;
this._target = null;
this._toolbox = null;
this.breadcrumbs = null;
- this.highlighters = null;
this.is3PaneModeEnabled = null;
this.panelDoc = null;
this.panelWin.inspector = null;
this.panelWin = null;
this.resultsLength = null;
this.search = null;
this.searchBox = null;
this.show3PaneTooltip = null;
this.sidebar = null;
this.store = null;
this.telemetry = null;
this.threePaneTooltip = null;
this._panelDestroyer = promise.all([
- highlighterDestroyer,
cssPropertiesDestroyer,
markupDestroyer,
sidebarDestroyer,
ruleViewSideBarDestroyer
]);
return this._panelDestroyer;
},
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -99,17 +99,16 @@ const INSET_POINT_TYPES = ["top", "right
* set of disabled properties.
* @param {PageStyleFront} pageStyle
* The PageStyleFront for communicating with the remote server.
*/
function CssRuleView(inspector, document, store, pageStyle) {
EventEmitter.decorate(this);
this.inspector = inspector;
- this.highlighters = inspector.highlighters;
this.styleDocument = document;
this.styleWindow = this.styleDocument.defaultView;
this.store = store || {};
// References to rules marked by various editors where they intend to write changes.
// @see selectRule(), unselectRule()
this.selectedRules = new Map();
this.pageStyle = pageStyle;
@@ -147,16 +146,19 @@ function CssRuleView(inspector, document
this.shortcuts = new KeyShortcuts({ window: this.styleWindow });
this._onShortcut = this._onShortcut.bind(this);
this.shortcuts.on("Escape", event => this._onShortcut("Escape", event));
this.shortcuts.on("Return", event => this._onShortcut("Return", event));
this.shortcuts.on("Space", event => this._onShortcut("Space", event));
this.shortcuts.on("CmdOrCtrl+F", event => this._onShortcut("CmdOrCtrl+F", event));
this.element.addEventListener("copy", this._onCopy);
this.element.addEventListener("contextmenu", this._onContextMenu);
+ this.element.addEventListener("mousemove", () => {
+ this.addHighlightersToView();
+ }, { once: true });
this.addRuleButton.addEventListener("click", this._onAddRule);
this.searchField.addEventListener("input", this._onFilterStyles);
this.searchClearButton.addEventListener("click", this._onClearSearch);
this.pseudoClassToggle.addEventListener("click", this._onTogglePseudoClassPanel);
this.classToggle.addEventListener("click", this._onToggleClassPanel);
this.hoverCheckbox.addEventListener("click", this._onTogglePseudoClass);
this.activeCheckbox.addEventListener("click", this._onTogglePseudoClass);
this.focusCheckbox.addEventListener("click", this._onTogglePseudoClass);
@@ -171,18 +173,16 @@ function CssRuleView(inspector, document
this._prefObserver.on(PREF_DEFAULT_COLOR_UNIT, this._handleDefaultColorUnitPrefChange);
this.showUserAgentStyles = Services.prefs.getBoolPref(PREF_UA_STYLES);
this._showEmpty();
// Add the tooltips and highlighters to the view
this.tooltips = new TooltipsOverlay(this);
-
- this.highlighters.addToView(this);
}
CssRuleView.prototype = {
// The element that we're inspecting.
_viewedElement: null,
// Used for cancelling timeouts in the style filter.
_filterChangedTimeout: null,
@@ -219,16 +219,26 @@ CssRuleView.prototype = {
return this._contextMenu;
},
// Get the dummy elemenet.
get dummyElement() {
return this._dummyElement;
},
+ // Get the highlighters overlay from the Inspector.
+ get highlighters() {
+ if (!this._highlighters) {
+ // highlighters is a lazy getter in the inspector.
+ this._highlighters = this.inspector.highlighters;
+ }
+
+ return this._highlighters;
+ },
+
// Get the filter search value.
get searchValue() {
return this.searchField.value.toLowerCase();
},
get rules() {
return this._elementStyle ? this._elementStyle.rules : [];
},
@@ -740,18 +750,23 @@ CssRuleView.prototype = {
this._classListPreviewer = null;
}
if (this._contextMenu) {
this._contextMenu.destroy();
this._contextMenu = null;
}
+ if (this._highlighters) {
+ this._highlighters.removeFromView(this);
+ this._highlighters = null;
+ }
+
this.tooltips.destroy();
- this.highlighters.removeFromView(this);
+
this.unselectAllRules();
// Remove bound listeners
this.shortcuts.destroy();
this.element.removeEventListener("copy", this._onCopy);
this.element.removeEventListener("contextmenu", this._onContextMenu);
this.addRuleButton.removeEventListener("click", this._onAddRule);
this.searchField.removeEventListener("input", this._onFilterStyles);
@@ -768,17 +783,16 @@ CssRuleView.prototype = {
this.pseudoClassToggle = null;
this.classPanel = null;
this.classToggle = null;
this.hoverCheckbox = null;
this.activeCheckbox = null;
this.focusCheckbox = null;
this.inspector = null;
- this.highlighters = null;
this.styleDocument = null;
this.styleWindow = null;
if (this.element.parentNode) {
this.element.remove();
}
if (this._elementStyle) {
@@ -1618,18 +1632,25 @@ CssRuleView.prototype = {
} else if (name === "Escape" &&
event.target === this.searchField &&
this._onClearSearch()) {
// Handle the search box's keypress event. If the escape key is pressed,
// clear the search box field.
event.preventDefault();
event.stopPropagation();
}
- }
+ },
+ /**
+ * Adds the highlighters overlay to the rule view. This is called by the "mousemove"
+ * event handler and in shared-head.js when opening and selecting the rule view.
+ */
+ addHighlightersToView() {
+ this.highlighters.addToView(this);
+ },
};
/**
* Helper functions
*/
/**
* Walk up the DOM from a given node until a parent property holder is found.
--- a/devtools/client/inspector/rules/views/rule-editor.js
+++ b/devtools/client/inspector/rules/views/rule-editor.js
@@ -169,20 +169,21 @@ RuleEditor.prototype = {
// This is an inline style from an inherited rule. Need to resolve the unique
// selector from the node which rule this is inherited from.
selector = await this.rule.inherited.getUniqueSelector();
} else {
// This is an inline style from the current node.
selector = this.ruleView.inspector.selectionCssSelector;
}
+ let isHighlighted = this.ruleView._highlighters &&
+ this.ruleView.highlighters.selectorHighlighterShown === selector;
let selectorHighlighter = createChild(header, "span", {
class: "ruleview-selectorhighlighter" +
- (this.ruleView.highlighters.selectorHighlighterShown === selector ?
- " highlighted" : ""),
+ (isHighlighted ? " highlighted" : ""),
title: l10n("rule.selectorHighlighter.tooltip")
});
selectorHighlighter.addEventListener("click", () => {
this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
});
this.uniqueSelector = selector;
this.emit("selector-icon-created");
--- a/devtools/client/inspector/shared/highlighters-overlay.js
+++ b/devtools/client/inspector/shared/highlighters-overlay.js
@@ -967,17 +967,17 @@ class HighlightersOverlay {
this.highlighters = null;
}
/**
* Destroy this overlay instance, removing it from the view and destroying
* all initialized highlighters.
*/
- async destroy() {
+ destroy() {
this.destroyHighlighters();
this.destroyEditors();
// Remove inspector events.
this.inspector.off("markupmutation", this.onMarkupMutation);
this.inspector.target.off("will-navigate", this.onWillNavigate);
this._lastHovered = null;
--- a/devtools/client/inspector/test/shared-head.js
+++ b/devtools/client/inspector/test/shared-head.js
@@ -74,43 +74,52 @@ var openInspectorSidebarTab = async func
* Open the toolbox, with the inspector tool visible, and the rule-view
* sidebar tab selected.
*
* @return a promise that resolves when the inspector is ready and the rule view
* is visible and ready
*/
function openRuleView() {
return openInspector().then(data => {
+ let view = data.inspector.getPanel("ruleview").view;
+
// Replace the view to use a custom debounce function that can be triggered manually
// through an additional ".flush()" property.
- data.inspector.getPanel("ruleview").view.debounce = manualDebounce();
+ view.debounce = manualDebounce();
+
+ // Adds the highlighters overlay in the rule view.
+ view.addHighlightersToView();
return {
toolbox: data.toolbox,
inspector: data.inspector,
testActor: data.testActor,
- view: data.inspector.getPanel("ruleview").view
+ view,
};
});
}
/**
* Open the toolbox, with the inspector tool visible, and the computed-view
* sidebar tab selected.
*
* @return a promise that resolves when the inspector is ready and the computed
* view is visible and ready
*/
function openComputedView() {
return openInspectorSidebarTab("computedview").then(data => {
+ let view = data.inspector.getPanel("computedview").computedView;
+ // Adds the highlighters overlay in the computed view.
+ view.addHighlightersToView();
+
return {
toolbox: data.toolbox,
inspector: data.inspector,
testActor: data.testActor,
- view: data.inspector.getPanel("computedview").computedView
+ view,
};
});
}
/**
* Open the toolbox, with the inspector tool visible, and the layout view
* sidebar tab selected to display the box model view with properties.
*
@@ -144,29 +153,33 @@ function openLayoutView() {
/**
* Select the rule view sidebar tab on an already opened inspector panel.
*
* @param {InspectorPanel} inspector
* The opened inspector panel
* @return {CssRuleView} the rule view
*/
function selectRuleView(inspector) {
- return inspector.getPanel("ruleview").view;
+ let view = inspector.getPanel("ruleview").view;
+ view.addHighlightersToView();
+ return view;
}
/**
* Select the computed view sidebar tab on an already opened inspector panel.
*
* @param {InspectorPanel} inspector
* The opened inspector panel
* @return {CssComputedView} the computed view
*/
function selectComputedView(inspector) {
inspector.sidebar.select("computedview");
- return inspector.getPanel("computedview").computedView;
+ let view = inspector.getPanel("computedview").computedView;
+ view.addHighlightersToView();
+ return view;
}
/**
* Select the layout view sidebar tab on an already opened inspector panel.
*
* @param {InspectorPanel} inspector
* @return {BoxModel} the box model
*/