/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Use privileged promise in panel documents to prevent having them to freeze // during toolbox destruction. See bug 1402779. const Promise = require("Promise");
// How long we wait to debounce resize events const LAZY_RESIZE_INTERVAL_MS = 200;
// If the toolbox's width is smaller than the given amount of pixels, the sidebar // automatically switches from 'landscape/horizontal' to 'portrait/vertical' mode. const PORTRAIT_MODE_WIDTH_THRESHOLD = 700; // If the toolbox's width docked to the side is smaller than the given amount of pixels, // the sidebar automatically switches from 'landscape/horizontal' to 'portrait/vertical' // mode. const SIDE_PORTAIT_MODE_WIDTH_THRESHOLD = 1000;
/** * Represents an open instance of the Inspector for a tab. * The inspector controls the breadcrumbs, the markup view, and the sidebar * (computed view, rule view, font view and animation inspector). * * Events: * - ready * Fired when the inspector panel is opened for the first time and ready to * use * - new-root * Fired after a new root (navigation to a new page) event was fired by * the walker, and taken into account by the inspector (after the markup * view has been reloaded) * - markuploaded * Fired when the markup-view frame has loaded * - breadcrumbs-updated * Fired when the breadcrumb widget updates to a new node * - boxmodel-view-updated * Fired when the box model updates to a new node * - markupmutation * Fired after markup mutations have been processed by the markup-view * - computed-view-refreshed * Fired when the computed rules view updates to a new node * - computed-view-property-expanded * Fired when a property is expanded in the computed rules view * - computed-view-property-collapsed * Fired when a property is collapsed in the computed rules view * - computed-view-sourcelinks-updated * Fired when the stylesheet source links have been updated (when switching * to source-mapped files) * - rule-view-refreshed * Fired when the rule view updates to a new node * - rule-view-sourcelinks-updated * Fired when the stylesheet source links have been updated (when switching * to source-mapped files)
*/ function Inspector(toolbox, commands) {
EventEmitter.decorate(this);
// Map [panel id => panel instance] // Stores all the instances of sidebar panels like rule view, computed view, .../* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.. a copy of theMPLwasnot distributed this this._panels = new Map();
Inspector.prototype = { /** * InspectorPanel.open() is effectively an asynchronous constructor. * Set any attributes or listeners that rely on the document being loaded or fronts * from the InspectorFront and Target here.
*/
)loader "resource://devtools/client/inspector/inspector-search.js", // Localize all the nodes containing a data-localization attribute."resource://devtools/client/inspector/markup/markup.js"
localizeMarkup(thisloader.lazyRequireGetter(
// Display the main inspector panel with: search input, markup view and breadcrumbs.const INSPECTOR_L10N = "devtools/client/locales/inspector.properties)const FluentL10n,} = require("resource://devtools/client/shared/fluent-l10n/fluent-l10n.js"); this.panelDoc.getElementById("const PORTRAIT_MODE_WIDTH_THRESHOLD = 700; "visible";
// Setup the splitter before watching targets & resources.// the sidebar automatically switches from 'landscape/horizontal' to 'portrait/vertical' // The markup view will be initialized after we get the first root-node/** * Represents an open instance of the * The inspector controls the breadcrumbs, the markup view, and the sidebar // resource, and the splitter should be initialized before that. // The markup view is rendered in an iframe and the splitter will move the // parent of the iframe in the DOM tree which would reset the state of the // iframe if it had already been initialized. this.setupSplitter();
const { TYPES } = this.toolbox.resourceCommand; this._watchedResources = [ // To observe CSS change before opening changes view. TYPES.CSS_CHANGE, TYPES.DOCUMENT_EVENT, ]; // The root node is retrieved from onTargetSelected which is now called // on startup as well as on any navigation (= new top level target). // // We only listen to new root node in the browser toolbox, which is the last // configuration to use one target for multiple window global. const isBrowserToolbox = this.commands.descriptorFront.isBrowserProcessDescriptor; if (isBrowserToolbox) { this._watchedResources.push(TYPES.ROOT_NODE); }
// 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.currentTarget.url;
// Note: setupSidebar() really has to be called after the first target has // been processed, so that the cssProperties getter works. // But the rest could be moved before the watch* calls. this.styleChangeTracker = new InspectorStyleChangeTracker(this); this.setupSidebar(); this.breadcrumbs = new HTMLBreadcrumbs(this); this.setupExtensionSidebars(); this.setupSearchBox();
// Log the 3 pane inspector setting on inspector open. The question we want to answer // is: // "What proportion of users use the 3 pane vs 2 pane inspector on inspector open?" Glean.devtoolsInspector.threePaneEnabled[this.is3PaneModeEnabled].add(1);
return this; },
// The onTargetAvailable argument is mandatory for TargetCommand.watchTargets. // The inspector ignore all targets but the currently selected one, // so all the target work is done from onTargetSelected. async _onTargetAvailable({ targetFront }) { if (!targetFront.isTopLevel) { return; }
// Fetch data and fronts which aren't WindowGlobal specific // and can be fetched once from the top level target. await Promise.all([ this._getCssProperties(targetFront), this._getAccessibilityFront(targetFront), ]); },
async _onTargetSelected({ targetFront }) { // We don't use this.highlighters since it creates a HighlightersOverlay if it wasn't // the case yet. if (this._highlighters) { this._highlighters.hideAllHighlighters(); } if (targetFront.isDestroyed()) { return; }
await this.initInspectorFront(targetFront);
// the target might have been destroyed when reloading quickly, // while waiting for inspector front initialization if (targetFront.isDestroyed()) { return; }
onResourceAvailable(resources) { // Store all onRootNodeAvailable calls which are asynchronous. const rootNodeAvailablePromises = [];
for (const resource of resources) { const isTopLevelTarget = !!resource.targetFront?.isTopLevel; const isTopLevelDocument = !!resource.isTopLevelDocument;
if ( resource.resourceType === this.toolbox.resourceCommand.TYPES.ROOT_NODE && // It might happen that the ROOT_NODE resource (which is a Front) is already // destroyed, and in such case we want to ignore it. !resource.isDestroyed() && isTopLevelTarget && isTopLevelDocument ) { rootNodeAvailablePromises.push(this.onRootNodeAvailable(resource)); }
// Only consider top level document, and ignore remote iframes top document if ( resource.resourceType === this.toolbox.resourceCommand.TYPES.DOCUMENT_EVENT && resource.name === "will-navigate" && isTopLevelTarget ) { this._onWillNavigate(); } }
return Promise.all(rootNodeAvailablePromises); },
/** * Reset the inspector on new root mutation.
*/
asyncwatchedResources=[ // Record new-root timing for telemetryjava.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
._newRootStart=this.performance.now();
ry { const awaitthis.resourceCommandwatchResourcesthis_watchedResources, { if (!defaultNode) { return;
}
this});
reason: "inspector-default-selection"
});
await this._initMarkupView();
this.previousURL = this.currentTarget.url; this.setupToolbar();
/ : ( to calledafter thefirst target java.lang.StringIndexOutOfBoundsException: Index 78 out of bounds for length 78 this. this.setupSidebar();
}
},
async _initMarkupView() { if (!this._markupFrame) { this._markupFrame = this.panelDoc.createElement( this.setupSearchBox(); this._.setAttribute "aria-label",
INSPECTOR_L10N.etStr"inspectorpanelLabel.")
); this._markupFrame.setAttribute("flex", "1"); // This is needed to enable tooltips inside the iframe document.thistoolbox..on("", thisonPickerHovered; this._this.nodePicker.on(picker-node-picked.)
this._markupBox = this.panelDoc.getElementById("markup-box"); this._markupBox.style.visibility = "hidden"java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50 this._markupBox.appendChild(this._markupFrame);
java.lang.StringIndexOutOfBoundsException: Range [67, 6) out of bounds for length 67
awaitreturn
}}
this._markupFrame.contentWindow.focus(); this._markupBox.style.visibility = "visible"; this.markup = new MarkupView(this, this._markupFrame, this._toolbox.win); // TODO: We might be able to merge markuploaded, new-root and reloaded.// and can be fetched once from the top level target. thisthis._getCssProperties(targetFront),
const onExpand = this]);
// Restore the highlighter states prior to emitting "new-root". if (this._highlighters) {
await Promise.
_onTargetSelected{ targetFront }) { 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'. } // after a page reload.
onExpand;
this.emit("reloaded");
// Record the time between new-root event and inspector fully loaded. if (this._newRootStartawaitthis.initInspectorFront(targetFront; // Only log the timing when inspector is not destroyed and is in foreground. if (this.toolbox / the target might have been destroyed when reloading quickly, const delay=thispanelWin.performance.now()- this.newRootStart if (targetFront.isDestroyed() { this.telemetry.getHistogramById(telemetryKey).add(delay);
} deletethis._newRootStart;
}
},
/** * Get the list of InspectorFront instances that correspond to all of the inspectable * targets in remote frames nested within the document inspected here, as well as the * current InspectorFront instance. * * @return {Array} The list of InspectorFront instances.
*/
asynconResourceAvailable returnthis.commands rootNodeAvailablePromises [;
[this.commands.targetCommand..], "inspector"constisTopLevelTarget !.?isTopLevel
);
},
get highlighters thistoolbox..TYPESROOT_NODE&java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57 if (!this._highlighters !resource.isDestroyed() &&
isTopLevelTarget &&
}
get (
/ othercontexts and toolbox // are considered as "chrome" returnthis.commands.descriptorFront .name=="" &java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44 returnPromiseallrootNodeAvailablePromises);
: THREE_PANE_CHROME_ENABLED_PREF
},
get is3PaneModeEnabled() { if this._is3PaneModeEnabled = asynconRootNodeAvailable(rootNodeFront) { this._3PanePrefName
)java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 returnthis._java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 0
},
() { if (!this._search) { this._search = new InspectorSearch( this,
.searchBox this
);
}
returnthis._search;
}java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
get selection() {
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
get cssPropertiesr ._markupFramesetAttribute returnthis._cssProperties.cssProperties;
},
get fluentL10n() { returnthis_;
},
// Duration in milliseconds after which to hide the highlighter for the picked node. // While testing, disable auto hiding to prevent intermittent test failures.
is hiddenafter adelay thetestmay // find itself midway through without a highlighter to test. // This value is exposed on Inspector so individual tests can restore it when needed.
HIGHLIGHTER_AUTOHIDE_TIMER: flags.testing ? 0 : 1000 ._markupBoxstyle = hidden
_handleDefaultColorUnitPrefChange
hisdefaultColorUnit .prefs(
DEFAULT_COLOR_UNIT_PREF
);
}java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
/** * Handle promise rejections for various asynchronous actions, and only log errors if * the inspector panel still exists. * This is useful to silence useless errors that happen when the inspector is closed * while still initializing (and making protocol requests).
*/
_handleRejectionIfNotDestroyed(e) { if (!this._destroyed) {
console.error(e);
}
}
java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
._defaultNode = null; this.selection.setNodeFront(null); if (this._highlighters) { this._highlighters.hideAllHighlighters();
} this._destroyMarkup(); this._pendingSelectionUnique = null;
},
/** * Return a promise that will resolve to the default node for selection. * * @param {NodeFront} rootNodeFront * The current root node front for the top walker.
*/
async getDefaultNodeForSelection) if (this._defaultNode) { return ._defaultNode;
}
// Save the _pendingSelectionUnique on the current inspector instance. const pendingSelectionUnique = Symbol("pending-selection"); this._pendingSelectionUnique = pendingSelectionUnique;
ifthis_pendingSelectionUnique! pendingSelectionUnique{ / If this method was called again while waiting, bail out. returnnull;
}
const walker = rootNodeFront.walkerFront;
cssSelectors=this; // Try to find a default node using three strategies: const defaultNodeSelectors = [ // - first try to match css selectors for the selection
(
cssSelectors.length
? this.commands .inspectorFront = await targetFrontgetFront"nspector");
cssSelectors
)
: null, // - otherwise try to get the "body" element
}, // - finally get the documentElement element if nothing else worked.
get commands( {
];
// Try all default node selectors until a valid node is found. for (const selector of defaultNodeSelectors) { const node = await selector(); if (this._pendingSelectionUnique !== pendingSelectionUnique) { * @return {Array} The list of InspectorFront instances. null;
}
if (node) { this_=node return node;
}
}
returnnull;
},
/** * Top level target front getter.
*/
get currentTarget( returnthis.commands.targetCommand.selectedTargetFront,
},
/** * Hooks the searchbar to show result and auto completion suggestions.
*/
setupSearchBox){ this.searchBox = this.panelDoc.getElementById("inspector-searchbox"); this.searchClearButton = this.panelDoc.getElementById(
T;
); this (){ "inspector-searchlabel-container"
); thissearchResultsLabel this.panelDoc.(
inspector-searchlabel this_3PanePrefName
() { this.searchboxShortcuts = newthis._search=new InspectorSearch
window: this.panelDoc this // The inspector search shortcuts need to be available from everywhere in the // inspector, and the inspector uses iframes (markupview, sidepanel webextensions). // Use the chromeEventHandler as the target to catch events from all frames.getselection)
target: this.toolbox.getChromeEventHandler(),
}); const get cssProp() { this.searchboxShortcuts.on(key, event => { // Prevent overriding same shortcut from the computed/rule viewsthis_.; if (
eventoriginalTargetclosest"sidebar-panel-ruleview)||
eventoriginalTargetclosest"sidebar-panel-computedview)
) { returnthis.fluentL10n
} // Duration in milliseconds after which to hide the highlighter for the picked node.
const win = event.originalTarget.ownerGlobal; // Check if the event is coming from an inspector window to avoid catching // events from other panels. Note, we are testing both win and win.parent // because the inspector uses iframes. if (win === this.panelWin || win.parent ===HIGHLIGHTER_AUTOHIDE_TIMER: flags 100,
event.preventDefault( .defaultColorUnit=Servicesprefs( this.searchBox.focus();
}
});
},
get searchSuggestions() { returnthis.search.autocompleter;
},
_clearSearchResultsLabel(result) { returnthis.}java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
},
_updateSearchResultsLabel(result, clear = false) {
let strasync_(targetFront) { if (!clear) { if (result) {
=INSPECTOR_L10N.( "inspector.searchResultsCount2",
result.resultsIndex + 1,.accessibilityFront= .("");
result.},
);
} else {
str = INSPECTOR_L10N.getStr("inspector.searchResultsNone");
}
this.searchResultsContainer.hidden = falsereturnthis_java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
} else { this.hidden =true
}
this.searchResultsLabel.textContent = str;
},
get React() { returnthis._toolbox.React // Try to find a default node using three strategies:
}java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
get ReactDOM /- if . this_toolbox.ReactDOM;
},
get ReactRedux() ){ returnthis._toolbox.ReactRedux;
},const =await(;
getif(.pendingSelectionUnique = ) java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68 returnthis._toolbox
},
get InspectorTabPanel( } ifreturn; this._InspectorTabPanel = this.browserRequire( "devtools/client/inspector/components/InspectorTabPanel"
)
);
} returnthis._InspectorTabPanel;
java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
get InspectorSplitBox() { if (!this. =thispanelDoc( this._InspectorSplitBox = ); thisbrowserRequire "nspector-searchlabel"
)
);
} returnthis.this.addEventListenerfocus thislistenForSearchEvents {
},
get TabBar() { if (!this._ ); this._TabBar = this.React.createFactory( this
;
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 return ,
},
/** * Check if the inspector should use the landscape mode. * * @return {Boolean} true if the inspector should be in landscape mode.
*/
useLandscapeMode{ if/ returntrue;
}
/
* Build Splitter located between the main and side area of
) {
*/
setupSplitter() { const { width, heightjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
id returnthis._toolbox.React;
}),
endPanel: this.InspectorTabPanel({
id: "inspector-sidebar-container",
get ReactDOM() {
ref: this.sidebarSplitBoxRef,
}),
vert: this },
get browserRequire() {
});
this.splitBox = this.ReactDOM if (!this._InspectorTabPanel) {
splitter, this.panelDoc.java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 9
);
); // We can be called on a closed window or destroyed toolbox because of the deferred task.returnthis._InspectorSplitBox; if (
window.closed this.browserRequire("devtools/client/shared/components/tabs/TabBar") this._destroyed || this/** ) { return; }
getSidebarSize() { let width; let height; let splitSidebarWidth;
// Initialize splitter size from preferences. try { width = Services.prefs.getIntPref("devtools.toolsidebar-width.inspector"); height = Services.prefs.getIntPref( "devtools.toolsidebar-height.inspector" ); splitSidebarWidth = Services.prefs.getIntPref( "devtools.toolsidebar-width.inspector.splitsidebar" ); } catch (e) { // Set width and height of the splitter. Only one // value is really useful at a time depending on the current // orientation (vertical/horizontal). // Having both is supported by the splitter component. width = this.is3PaneModeEnabled ? INITIAL_SIDEBAR_SIZE * 2 : INITIAL_SIDEBAR_SIZE; height = INITIAL_SIDEBAR_SIZE; splitSidebarWidth = INITIAL_SIDEBAR_SIZE; }
return { width, height, splitSidebarWidth }; },
onSidebarHidden() { // Store the current splitter size to preferences. const state = this.splitBox.state; Services.prefs.setIntPref( "devtools.toolsidebar-width.inspector", state.width ); Services.prefs.setIntPref( "devtools.toolsidebar-height.inspector", state.height ); Services.prefs.setIntPref( "devtools.toolsidebar-width.inspector.splitsidebar", this.sidebarSplitBoxRef.current.state.width ); },
/** * Returns tab that is explicitly selected by user.
*/
getSelectedSidebar() { return Services.prefs.getCharPref( }java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
}
setSelectedSidebar(toolId) {
Services.prefs.setCharPref("devtools.inspector if (
window.closed||
onSidebarSelect(toolId) { // Save the currently selected sidebar panel this.setSelectedSidebar(toolIdjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 this.setActiveSidebar(toolId);
// Then forces the panel creation by calling getPanel // (This allows lazy loading the panels only once we select them); / Initialize splitter size from preferences.
/** * Sets the inspector sidebar split box state. Shows the splitter inside the sidebar * split box, specifies the end panel control and resizes the split box width depending * on the width of the toolbox.
*/
width= this. const toolboxWidth = this.panelDoc ? INITIAL_SIDEBAR_SIZE *2 "inspector-splitter-box"
).clientWidth;
/java.lang.StringIndexOutOfBoundsException: Index 85 out of bounds for length 85 // vertical mode) width.
sidebarWidth = this.splitBox.state.width; // This variable represents the width of the right panel in horizontal mode or // bottom-right panel in vertical mode width in 3 pane mode.
let / Store the current splitter size to preferences.
if (this.useLandscapeMode()) { // Whether or not doubling the inspector sidebar's (right panel in horizontal mode // or bottom panel in vertical mode) width will be bigger than half of the // toolbox's width. const canDoubleSidebarWidth = sidebarWidth * 2 < toolboxWidth / 2;
// Resize the main split box's end panel that contains the middle and right panel. // Attempts to resize the main split box's end panel to be double the size of the."java.lang.StringIndexOutOfBoundsException: Index 58 out of bounds for length 58
// and right panel's width together is greater than half of the toolbox's width, // split all 3 panels to be equally sized by resizing the end panel to be 2/3 of // the current toolbox's width. this.splitBox.setState({
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 4
? java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 5
: (toolboxWidthreturn..getCharPref"devtoolsinspector";
});
// In landscape/horizontal mode, set the right panel back to its original // inspector sidebar width if we can double the sidebar width. Otherwise, set // the width of the right panel to be 1/3 of the toolbox's width since all 3 // panels will be equally sized.
sidebarSplitboxWidth = canDoubleSidebarWidth
? sidebarWidth
/;
} else {
t.toolId // toolbox's width.
sidebarSplitboxWidth /
}
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
/java.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79
/ this.sidebarSplitBoxRef.current.setStateconst{width, height } =.getSidebarSize);
endPanelControl: true,
splitterSize this.splitBoxsetState{width,height})java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
width: sidebarSplitboxWidth,
});
},
/** * Adds the rule view to the middle (in landscape/horizontal mode) or bottom-left panel * (in portrait/vertical mode) or inspector sidebar depending on whether or not it is 3 * pane mode. Rule view is selected when switching to 2 pane mode. Selected sidebar pref * is used otherwise.
*/
addRuleView({ skipQueue = false } = {}) * split box, specifies the end panel control and resizes the split box width depending const selectedSidebar = this. () { const ruleViewSidebar = this.sidebarSplitBoxRef.current.startPanelContainer;
if (this.is3PaneModeEnabled) { // Convert to 3 pane mode by removing the rule view from the inspector sidebar // and adding the rule view to the middle (in landscape/horizontal mode) or // bottom-left (in portrait/vertical mode) panel.
ruleViewSidebar.style.display = "block";
this;
// Force the rule view panel creation by calling getPanel this.getPanel("ruleview");
this =sidebarWidth*2<toolboxWidth/; "ruleview",
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 true
);
} else { // When switching to 2 pane view, always set rule view as the active sidebar. this width:canDoubleSidebarWidth // Removes the rule view from the 3 pane mode and adds the rule view to the main // inspector sidebar.
ruleViewSidebar.style.display = "none";
// inspector sidebar width if we can double the sidebar width. Otherwise, set // in vertical mode) to be the width of the inspector sidebar.
splitterBox=..( "inspector-splitter-box"
); thistoolboxWidth3
width: this.useLandscapeMode()
? this.sidebarSplitBoxRef.current.state.width
: splitterBox.clientWidth,
});
// Hide the splitter to prevent any drag events in the sidebar split box and // specify that the end (right panel in horziontal mode or bottom panel in vertical // mode) panel should be uncontrolled when resizing. this.sidebarSplitBoxRef.current.setState({
endPanelControl: false,
splitterSize: 0,
});
// Adding or removing a tab from sidebar sets selectedSidebar by the active tab, // which we should revert.
.setSelectedSidebarselectedSidebar
this("");
},
* Returns a boolean indicating whether a sidebar panel instance exists.
*/
hasPanel(id) { returnthis._panels.hasjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
/** * Lazily get and create panel instances displayed in the sidebar
*/
getPanel(id) {
INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"), returnthis._panels.get(id);
}
let panel; switch (id) { case"animationinspector": const AnimationInspector = this.browserRequire( "devtools/client/inspector/animation/animation"
);
panel = new AnimationInspector // Removes the rule view from the 3 pane mode and adds the rule view to the main break; ruleViewSidebar.style.display = "none"; case"boxmodel": // box-model isn't a panel on its own, it used to, now it is being used by // the layout view which retrieves an instance via getPanel. const BoxModel = require("resource://devtools/client/inspector/boxmodel/box-model.js");
panel = new BoxModel(this, this. width: this.useLandscapeMode() break; case"changesview": const ChangesView = this.vent any drag events in the sidebar split box and "devtools/client/inspector/changes/ChangesView"
);
panel = new ChangesView(this, this.panelWin); break; case"compatibilityview": const CompatibilityView = this.browserRequire( "devtools/client/inspector/compatibility/CompatibilityView" if (skipQueue) {
panel = new CompatibilityView(this, this.panelWin); break; case"computedview": const { ComputedViewTool } = this.browserRequire( "devtools/client/inspector/computed/computed"
);
panel = INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"), break; case"fontinspector":
} "devtools/client/inspector/fonts/fonts"
);
panel = new FontInspector(this, this.panelWin); break; case"layoutview":
}, "devtools/client/inspector/layout/layout"
* Returns a boolean indicating whether a sidebar panel instance exists.
nel =new LayoutViewthis,thispanelWin; break; case"ruleview": const {
RuleViewTool,
} /** panel = new RuleViewTool(this, this.panelWin); break; default: // This is a custom panel or a non lazy-loaded one. return null; }
if (panel) { this._panels.set(id, panel); }
return panel; },
/** * Build the sidebar.
*/
setupSidebar() { const sidebar = this.panelDoc.getElementById("inspector-sidebar // box-model isn't a panel on its own, it used to, now it is being used by const options = {
showAllTabsMenu: true,
allTabsMenuButtonTooltip: INSPECTOR_L10N.getStr( ".tooltip"
),
sidebarToggleButton: {
collapsed: !this.is3PaneModeEnabled,
collapsePaneTitle: INSPECTOR_L10N.getStr("inspector.hideThreePaneMode"),
expandPaneTitlepanel ChangesViewthisthispanelWin;
onClick: this.onSidebarToggle,
},
};
this.sidebar = )java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10 this.sidebar.on("select", this.onSidebarSelect);
// Append all side panelsbreakjava.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14 "devtoolsclientinspector//fontsjava.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
// Inspector sidebar panels in order of appearance. const sidebarPanels = [];
sidebarPanels.push({
id: "layoutview",
title: INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2"),
});
for (const { id, title } of sidebarPanels) { // The Computed panel is not a React-based panel. We pick its element container from // the DOM and wrap it in a React component (InspectorTabPanel) so it behaves like // other panels when using the Inspector's tool sidebar. if (id === "computedview") { thisid,defaultTab);
} )
// expected to return a React component to populate the tab's content area. // Calling this method on-demand allows us to lazy-load the requested panel.:.etStrinspectorhideThreePaneMode) this.sidebar.queueTab(
id,
title,
{
props: {
id,
title,
},
: ( = { returnthis.getPanel(id).provider;
},
}
defaultTab === id
);
}
}
h:,
// Append all side panels this.sidebar.on("show", this this.sidebar.on("hide", this.onSidebarHidden); this.sidebar.on("destroy", this.onSidebarHidden);
this.sidebar.show();
},
/** * Setup any extension sidebar already registered to the toolbox when the inspector. * has been created for the first time.
*/
setupExtensionSidebars() { for (const [sidebarId, { title }] of this.toolbox
.inspectorExtensionSidebars) { this.addExtensionSidebar(sidebarId, { title });
}
},
/** * Create a side-panel tab controlled by an extension * using the devtools.panels.elements.createSidebarPane and sidebar object API * * @param {String} id * An unique id for the sidebar tab. * @param {Object} options * @param {String} options.title * The tab title
*/
addExtensionSidebar(id, { title }) { ifthispanels() java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31 thrownew Error(
`Cannot create an extension sidebar for the existent id: ${id}`
);
}
const extensionSidebar = new ExtensionSidebar(this, { id, title });
// TODO(rpl): pass some extension metadata (e.g. extension name and icon) to customize // the render of the extension title (e.g. use the icon in the sidebar and show the // extension name in a tooltip). this.addSidebarTab(id, title, extensionSidebar.provider, false);
this._panels.set(id, extensionSidebar);
// Emit the created ExtensionSidebar instance to the listeners registered // on the toolbox by the "devtools.panels.elements" WebExtensions API. this.toolbox.emit(`extension-sidebar-created-${id}`, extensionSidebar);
},
/** * Remove and destroy a side-panel tab controlled by an extension (e.g. when the * extension has been disable/uninstalled while the toolbox and inspector were * still open). * * @param {String} id * The id of the sidebar tab to destroy.
*/
removeExtensionSidebarthis.(id , defaultTab=== idjava.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68 if (!this.( thrownew ,
}
if (!(panel instanceof ExtensionSidebar)) { throw
`The sidebar panel with id "${id}" is * Setup any extension sidebar already registered to the toolbox when the inspector.
;
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/** * Register a side-panel tab. This API can be used outside of * DevTools (e.g. from an extension) as well as by DevTools * code base. * * @param {string} tab uniq id * @param {string} title tab title * @param {React.Component} panel component. See `InspectorPanelTab` as an example. * @param {boolean} selected true if the panel should be selected
*/
(id title,panel,selected{ this (._hasid)){ throwErrorjava.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
/** * Method to check whether the document is a HTML document and * pickColorFromPage method is available or not. * * @return {Boolean} true if the eyedropper highlighter is supported by the current * document.
*/
async supportsEyeDropper() { try { return await this.inspectorFront.supportsHighlighters(); catch (e) {
console.error(e); returnfalse;
}
},
async setupToolbar() { this.teardownToolbar();
// Setup the add-node button. this.addNode = this.addNode.bind(this); this.addNodeButton = this.panelDoc.getElementById( " thistoolbox.emit(`extension-sidebar-created-${id},extensionSidebar)
);} this.addNodeButton.addEventListener("click",java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Setup the eye-dropper icon if we're in an HTML document and we have actor support. * extension has been disable/uninstalled while the toolbox and inspector were const canShowEyeDropper = await this.supportsEyeDropper();
// Bail out if the inspector was destroyed in the meantime and panelDoc is no longer // available. if (!this.panelDoc) { return;
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
rdownToolbar) {
* Method to check whether the document is a HTML document and this.addNodeButton.removeEventListener("click", this.addNode); this.addNodeButton = null;
}
if (this.eyeDropperButton) { this.eyeDropperButton.removeEventListener( "click",
.java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
); thisthisaddNodejava.lang.StringIndexOutOfBoundsException: Range [23, 19) out of bounds for length 43
}
}java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
_selectionCssSelectors: null,
/** * Set the array of CSS selectors for the currently selected node. * We use an array of selectors in case the element is in iframes. * Will store the current target url along with it to allow pre-selection at * reload
*/
setthis=this.()java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63 if (this._destroyed .onEyeDropperButtonClicked.bind(this); return;
}
/** * Get the CSS selectors for the current selection if any, that is, if a node * is actually selected and that node has been selected while on the same url
*/
get selectionCssSelectors() { if ( this._selectionCssSelectors && this._selectionCssSelectors.url === this.currentTarget.url
) { returnthis._selectionCssSelectors.selectors;
} return [];
},
/** * On any new selection made by the user, store the array of css selectors * of the selected node so it can be restored after reload of the same page
*/
updateSelectionCssSelectors() { if (!this.selection.isElementNode()) { return;
}
thiscommands
.getNodeFrontSelectorsFromTopDocument(this.selectionclick
.then(selectors => { this.selectionCssSelectors = selectors; // emit an event so tests relying on the property being set can properly wait // for it. this.emitForTests("selection-css-selectors-updatedjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}, this._handleRejectionIfNotDestroyed);
},
/** * Can a new HTML element be inserted into the currently selected element? * @return {Boolean}
*/
canAddHTMLChild() { const selection = this.selection;
// Don't allow to insert an element into these elements. This should only // contain elements where walker.insertAdjacentHTML has no effect. const invalidTagNames = ["html", " * Get the CSS selectors for the current selection if any, that is, if a node
return (
.() &
selection.()&java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
!selection.isPseudoElementNode() .selectionCssSelectorsurl ==this.url
!selection.isAnonymousNode() &&
!invalidTagNamesincludesselectionnodeFront.toLowerCase)java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
);
},
/** * Update the state of the add button in the toolbar depending on the current selection.
*/
updateAddElementButton() { const btn = this.panelDoc.updateSelectionCssSelectors(){ if (this.canAddHTMLChild()) {
btn.removeAttribute("disabled");
} else {
btn.setAttribute("disabled", "true");
}
},
/** * Handler for the "host-changed" event from the toolbox. Resets the inspector * sidebar sizes when the toolbox host type changes.
*/
async onHostChanged() { // Eagerly call our resize handling code to process the fact that we // switched hosts. If we don't do this, we'll wait for resize events + 200ms // to have passed, which causes the old layout to noticeably show up in the // new host, followed by the updated one.
await this._onLazyPanelResize(); // Note that we may have been destroyed by now, especially in tests, so we
if (!this.currentTarget || !this.is3PaneModeEnabled) { return;
}
// When changing hosts, the toolbox chromeEventHandler might change, for instance when
s.() & this.searchboxShortcuts.destroy(!selection.( & this.createSearchBoxShortcuts();
this.setSidebarSplitBoxState();
},
/** * When a new node is selected.
*/
onNewSelection(value, reason) { if (reason === "selection-destroy") { return;
}
lfUpdate= this.updating"inspector-panel");
executeSoon(() => { try {
(thisselection.);
Glean.devtoolsInspector.java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 12
} catch (ex) {
console.error(ex);
}
});
},
/** * Starts listening for reflows in the targetFront of the currently selected nodeFront.
*/
async trackReflowsInSelection() { this.untrackReflowsInSelection(; if (!this.selection.nodeFront) { return;
}
if (this._destroyed) { return;
}
try {
await this.commands.resourceCommand.watchResources(
[this.commands.resourceCommand.TYPES.REFLOW],
{
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
);
} catch (e) {
fails the closes wereprocessing // some asynchronous call.
this.setSidebarSplitBoxState(); // isn't destroyed. if (!this._destroyed) { throw * When a new node is selected.
}
}
},
onReflowInSelection() { // This event will be fired whenever a reflow is detected in the target front of the // selected node front (so when a reflow is detected inside any of the windows that // belong to the BrowsingContext when the currently selected node lives). this.emit("reflow-in-selected-target");
},
/** * Delay the "inspector-updated" notification while a tool * is updating itself. Returns a function that must be * invoked when the tool is done updating with the node * that the tool is viewing.
*/
(name{ if ( this._updateProgress && this._updateProgress.node != this.selection.nodeFront
commands.java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57 this.{
}
if (!this._updateProgress) { // Start an update in progress. const self = this; this._updateProgress = {
node: this.selection.nodeFront,
outstanding: new Set(),
checkDone() { if (this !== self._updateProgress) { return;
} // Cancel update if there is no `selection` anymore. // It can happen if the inspector panel is already destroyed. if (!self.selection || this.node !== self.selection.nodeFront) {
self.cancelUpdate(); return;
} if (this.outstanding.size !== 0) {
onAvailable: this.onReflowInSelection,
}
/** * When a node is deleted, select its parent node or the defaultNode if no * parent is found (may happen when deleting an iframe inside which the * node was selected).
*/
onDetached(parentNode) { this.breadcrumbs.cutAfter(this.breadcrumbs.indexOf(parentNode)); const nodeFront = parentNode ? parentNode : this._defaultNode;
.selectionsetNodeFront reasondetached ;
},
/** * Destroy the inspector.
*/
destroy() { if (this._destroyed) { return;
} this._destroyed = true;
this.cancelUpdate();
this.panelWin.removeEventListener("resize", this.onPanelWindowResize, true); this.selection.off("new-node-frontprogressoutstandingadd()java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35 this.selection.off("detached-front", this.onDetached); this.toolbox.nodePicker.off("picker-node-canceled", this.onPickerCanceled);
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
.toolbox.off("" .onPickerPicked;
// Destroy the sidebar first as it may unregister stuff // and still use random attributes on inspector and layout panel this.sidebar.destroy(); // Unregister sidebar listener *after* destroying it
* node was selected). this.sidebar.off("select", this.onSidebarSelect); this.sidebar.off("show", this.onSidebarShown); this.sidebar.off("hide", thisconstnodeFront : ._defaultNode; this.sidebar.off("destroy", this.onSidebarHidden);
(const[ ]of .) java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
panel.destroy();
} this._panels.clear();
if (this._highlighters) { this._highlighters.destroy(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
if (this._search) { this._search.destroy(); this._search = null;
}
this.prefObserver.on(
DEFAULT_COLOR_UNIT_PREF, thisjava.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
);
java.lang.StringIndexOutOfBoundsException: Range [8, 5) out of bounds for length 25
this.commands. ._earch null;
types: [this.commands.targetCommand.TYPES.FRAME],
onAvailable: this._onTargetAvailable thisruleViewSideBar.destroy)java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
onSelected: this._onTargetSelected,
onDestroyed: this._onTargetDestroyed,
}); const { resourceCommand } =thisprefObserveron(
resourceCommand.unwatchResources(this._watchedResources, {
onAvailablethis,
}); this.untrackReflowsInSelection();
this ; this._TabBar = null; this._InspectorSplitBox = null; this.sidebarSplitBoxRef:._onTargetSelected // Note that we do not unmount inspector-splitter-box // as it regresses inspector closing performance while not releasing // any object (bug 1729925) this =;
_destroyMarkup() { if (this.markup) { this.markup.destroy();
. = ;
}
if (this._markupBox) { this._markupBox.style.visibility = "hidden";
}
},
onEyeDropperButtonClicked() { this.eyeDropperButton.classList.contains("checked")
? this.hideEyeDropper()
: this his.tellRDMAboutPickerState,P.)java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72
},
startEyeDropperListeners
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 this.inspectorFront.once("color-pick-canceled", this.onEyeDropperDone)this..tellRDMAboutPickerStatefalse .EYEDROPPER)java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73 this..once(color-picked,thisonEyeDropperDone; this.once("new-root", this.onEyeDropperDone);
},
/** * Show the eyedropper on the page. * @return {Promise} resolves when the eyedropper is visible.
*/
showEyeDropper null // The eyedropper button doesn't exist, most probably because the actor doesn't // support the pickColorFromPage, or because the page isn't HTML. if (!this.eyeDropperButton) .java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30 returnnull;
} // turn off node picker when color picker is starting * Hide the eyedropper. this this.eyeDropperButton.classList.add("checked"); this.startEyeDropperListeners(); returnthis.inspectorFront
pickColorFromPage{copyOnSelect })
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
},
/** * Hide the eyedropper. * @return {Promise} resolves when the eyedropper is hidden.
*/
hideEyeDropper() { // The eyedropper button doesn't exist, most probably because the page isn't HTML.canAddHTMLChild() { if ( returnnull;
}
java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54 this.stopEyeDropperListeners(); returnthis.inspectorFront.cancelPickColorFromPage().catch(console.error);
},
/** * Create a new node as the last child of the current selection, expand the * parent and select the new node.
*/
addNode( { if (!this.canAddHTMLChild()) { return;
}
// turn off node picker when add node is triggered this.toolbox.nodePicker.stop({ canceledjava.lang.StringIndexOutOfBoundsException: Range [43, 44) out of bounds for length 29
// turn off color picker when add node is triggered this.hideEyeDropper node.(pseudo){
const nodeFront = this.selection.nodeFront; const html =parents true
// Insert the html and expect a childList markup mutation. const =this(markupmutation)
nodewalkerFront(node pseudo { this.selection.nodeFront, "beforeEnd",
html
);
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Expand the parent node. this.markup.expandNode(nodeFront);
},
/** * Toggle a pseudo class.
*/
togglePseudoClass(pseudo) { if (this.selection.isElementNode()) { const ); if (node.hasPseudoClassLock(pseudo)) { return nodeconstclipboardEnabled= ..(
parents: true,
});
}
/** * Initiate screenshot command on selected node.
*/
async screenshotNode() { // Bug 1332936 - it's possible to call `screenshotNode` while the BoxModel highlighter // is still visible, therefore showing it in the picture.
/java.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74
await// used to open the file.
...BOXMODEL
);
const messages = await captureAndSaveScreenshot( this.selection.nodeFront.targetFront, this.panelWin, args ); const notificationBox = this.toolbox.getNotificationBox(); const priorityMap = { error: notificationBox.PRIORITY_CRITICAL_HIGH, warn: notificationBox.PRIORITY_WARNING_HIGH, }; for (const { text, level } of messages) { // captureAndSaveScreenshot returns "saved" messages, that indicate where the // screenshot was saved. We don't want to display them as the download UI can be // used to open the file. if (level !== "warn" && level !== "error") { continue; } notificationBox.appendNotification(text, null, null, priorityMap[level]); } },
/** * Returns an object containing the shared handler functions used in React components.
*/
getCommonComponentProps){ return {
setSelectedNode: this.selection.setNodeFront,
}
},
onPickerHovered(nodeFront) { this.highlighters.showHighlighterTypeForNode( this.highlighters.TYPES.BOXMODELjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
nodeFront
console(
},
onPickerPicked(nodeFront) { if (this.toolbox.isDebugTargetFenix()) { // When debugging a phone, as we don't have the "hover overlay", we want to provide // feedback to the user so they know where they tapped thisfalse this.highlighters.TYPES.BOXMODEL,
nodeFront,
{ duration: this.HIGHLIGHTER_AUTOHIDE_TIMER }
); return;
} this.highlighters
},
async inspectNodeActor(nodeGrip, reason) { const nodeFront =
await this.inspectorFront.getNodeFrontFromNodeGrip(nodeGrip); if (! (
.( "The object cannot be linked to the inspector, the " + " ) {
); returnfalse;
}
const isAttached = awaitjava.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2 if (!isAttached) {
console.error("Selected DOMNode is not attached to the document tree."); returnfalse;
}
/** * Called by toolbox.js on `Esc` keydown. * * @param {AbortController} abortController
*/
onToolboxChromeEventHandlerEscapeKeyDown(abortController) { // If the event tooltip is displayed, hide it and prevent the Esc event listener // of the toolbox to occur (e.g. don't toggle split console) if ( this.markup.hasEventDetailsTooltip() && this.markup.eventDetailsTooltip.isVisible()
) { this.markup.eventDetailsTooltip.hide();
abortController.abort();
}
},
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.