Bug 855544 - Implement a network monitor, r=dcamp,msucan

This commit is contained in:
Victor Porof 2013-03-11 23:50:42 -07:00
Родитель ea59580f90
Коммит 2253842238
66 изменённых файлов: 5675 добавлений и 340 удалений

Просмотреть файл

@ -1077,6 +1077,12 @@ pref("devtools.debugger.ui.variables-searchbox-visible", false);
// Enable the Profiler
pref("devtools.profiler.enabled", true);
// Enable the Network Monitor
pref("devtools.netmonitor.enabled", true);
// The default Network Monitor UI settings
pref("devtools.netmonitor.panes-network-details-width", 450);
// Enable the Tilt inspector
pref("devtools.tilt.enabled", true);
pref("devtools.tilt.intro_transition", true);

Просмотреть файл

@ -31,6 +31,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
Cu.import("resource:///modules/source-editor.jsm");
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
Cu.import("resource:///modules/devtools/BreadcrumbsWidget.jsm");
@ -38,12 +39,12 @@ Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
Cu.import("resource:///modules/devtools/VariablesView.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
XPCOMUtils.defineLazyModuleGetter(this, "Parser",
"resource:///modules/devtools/Parser.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
"resource://gre/modules/devtools/NetworkHelper.jsm");
/**
* Object defining the debugger controller components.
*/
@ -75,12 +76,12 @@ let DebuggerController = {
*/
startupDebugger: function DC_startupDebugger() {
if (this._isInitialized) {
return;
return this._startup.promise;
}
this._isInitialized = true;
window.removeEventListener("DOMContentLoaded", this.startupDebugger, true);
let deferred = Promise.defer();
let deferred = this._startup = Promise.defer();
DebuggerView.initialize(() => {
DebuggerView._isInitialized = true;
@ -103,13 +104,14 @@ let DebuggerController = {
* A promise that is resolved when the debugger finishes shutdown.
*/
shutdownDebugger: function DC__shutdownDebugger() {
if (this._isDestroyed || !DebuggerView._isInitialized) {
return;
if (this._isDestroyed) {
return this._shutdown.promise;
}
this._isDestroyed = true;
this._startup = null;
window.removeEventListener("unload", this.shutdownDebugger, true);
let deferred = Promise.defer();
let deferred = this._shutdown = Promise.defer();
DebuggerView.destroy(() => {
DebuggerView._isDestroyed = true;
@ -128,14 +130,21 @@ let DebuggerController = {
},
/**
* Initializes a debugger client and connects it to the debugger server,
* Initiates remote or chrome debugging based on the current target,
* wiring event handlers as necessary.
*
* In case of a chrome debugger living in a different process, a socket
* connection pipe is opened as well.
*
* @return object
* A promise that is resolved when the debugger finishes connecting.
*/
connect: function DC_connect() {
let deferred = Promise.defer();
if (this._connection) {
return this._connection.promise;
}
let deferred = this._connection = Promise.defer();
if (!window._isChromeDebugger) {
let target = this._target;
@ -181,12 +190,13 @@ let DebuggerController = {
this.client.removeListener("tabNavigated", this._onTabNavigated);
this.client.removeListener("tabDetached", this._onTabDetached);
// When debugging content or a remote instance, the connection is closed by
// When debugging local or a remote instance, the connection is closed by
// the RemoteTarget.
if (window._isChromeDebugger) {
this.client.close();
}
this._connection = null;
this.client = null;
this.tabClient = null;
this.activeThread = null;
@ -315,7 +325,16 @@ let DebuggerController = {
return;
}
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit);
}
},
_isInitialized: false,
_isDestroyed: false,
_startup: null,
_shutdown: null,
_connection: null,
client: null,
tabClient: null,
activeThread: null
};
/**
@ -911,7 +930,7 @@ StackFrames.prototype = {
_addFrame: function SF__addFrame(aFrame) {
let depth = aFrame.depth;
let { url, line } = aFrame.where;
let frameLocation = SourceUtils.convertToUnicode(window.unescape(url));
let frameLocation = NetworkHelper.convertToUnicode(unescape(url));
let frameTitle = StackFrameUtils.getFrameTitle(aFrame);
DebuggerView.StackFrames.addFrame(frameTitle, frameLocation, line, depth);
@ -1191,7 +1210,7 @@ SourceScripts.prototype = {
* Clears all the fetched sources from cache.
*/
clearCache: function SS_clearCache() {
this._cache = new Map();
this._cache.clear();
},
/**
@ -1631,100 +1650,31 @@ Breakpoints.prototype = {
/**
* Localization convenience methods.
*/
let L10N = {
/**
* L10N shortcut function.
*
* @param string aName
* @return string
*/
getStr: function L10N_getStr(aName) {
return this.stringBundle.GetStringFromName(aName);
},
/**
* L10N shortcut function.
*
* @param string aName
* @param array aArray
* @return string
*/
getFormatStr: function L10N_getFormatStr(aName, aArray) {
return this.stringBundle.formatStringFromName(aName, aArray, aArray.length);
}
};
XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
return Services.strings.createBundle(DBG_STRINGS_URI);
});
XPCOMUtils.defineLazyGetter(L10N, "ellipsis", function() {
return Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
});
let L10N = new ViewHelpers.L10N(DBG_STRINGS_URI);
/**
* Shortcuts for accessing various debugger preferences.
*/
let Prefs = {
/**
* Helper method for getting a pref value.
*
* @param string aType
* @param string aPrefName
* @return any
*/
_get: function P__get(aType, aPrefName) {
if (this[aPrefName] === undefined) {
this[aPrefName] = Services.prefs["get" + aType + "Pref"](aPrefName);
}
return this[aPrefName];
},
/**
* Helper method for setting a pref value.
*
* @param string aType
* @param string aPrefName
* @param any aValue
*/
_set: function P__set(aType, aPrefName, aValue) {
Services.prefs["set" + aType + "Pref"](aPrefName, aValue);
this[aPrefName] = aValue;
},
/**
* Maps a property name to a pref, defining lazy getters and setters.
*
* @param string aType
* @param string aPropertyName
* @param string aPrefName
*/
map: function P_map(aType, aPropertyName, aPrefName) {
Object.defineProperty(this, aPropertyName, {
get: function() this._get(aType, aPrefName),
set: function(aValue) this._set(aType, aPrefName, aValue)
});
}
};
Prefs.map("Char", "chromeDebuggingHost", "devtools.debugger.chrome-debugging-host");
Prefs.map("Int", "chromeDebuggingPort", "devtools.debugger.chrome-debugging-port");
Prefs.map("Int", "windowX", "devtools.debugger.ui.win-x");
Prefs.map("Int", "windowY", "devtools.debugger.ui.win-y");
Prefs.map("Int", "windowWidth", "devtools.debugger.ui.win-width");
Prefs.map("Int", "windowHeight", "devtools.debugger.ui.win-height");
Prefs.map("Int", "sourcesWidth", "devtools.debugger.ui.panes-sources-width");
Prefs.map("Int", "instrumentsWidth", "devtools.debugger.ui.panes-instruments-width");
Prefs.map("Bool", "pauseOnExceptions", "devtools.debugger.ui.pause-on-exceptions");
Prefs.map("Bool", "panesVisibleOnStartup", "devtools.debugger.ui.panes-visible-on-startup");
Prefs.map("Bool", "variablesSortingEnabled", "devtools.debugger.ui.variables-sorting-enabled");
Prefs.map("Bool", "variablesOnlyEnumVisible", "devtools.debugger.ui.variables-only-enum-visible");
Prefs.map("Bool", "variablesSearchboxVisible", "devtools.debugger.ui.variables-searchbox-visible");
Prefs.map("Char", "remoteHost", "devtools.debugger.remote-host");
Prefs.map("Int", "remotePort", "devtools.debugger.remote-port");
Prefs.map("Bool", "remoteAutoConnect", "devtools.debugger.remote-autoconnect");
Prefs.map("Int", "remoteConnectionRetries", "devtools.debugger.remote-connection-retries");
Prefs.map("Int", "remoteTimeout", "devtools.debugger.remote-timeout");
let Prefs = new ViewHelpers.Prefs("devtools.debugger", {
chromeDebuggingHost: ["Char", "chrome-debugging-host"],
chromeDebuggingPort: ["Int", "chrome-debugging-port"],
windowX: ["Int", "ui.win-x"],
windowY: ["Int", "ui.win-y"],
windowWidth: ["Int", "ui.win-width"],
windowHeight: ["Int", "ui.win-height"],
sourcesWidth: ["Int", "ui.panes-sources-width"],
instrumentsWidth: ["Int", "ui.panes-instruments-width"],
pauseOnExceptions: ["Bool", "ui.pause-on-exceptions"],
panesVisibleOnStartup: ["Bool", "ui.panes-visible-on-startup"],
variablesSortingEnabled: ["Bool", "ui.variables-sorting-enabled"],
variablesOnlyEnumVisible: ["Bool", "ui.variables-only-enum-visible"],
variablesSearchboxVisible: ["Bool", "ui.variables-searchbox-visible"],
remoteHost: ["Char", "remote-host"],
remotePort: ["Int", "remote-port"],
remoteAutoConnect: ["Bool", "remote-autoconnect"],
remoteConnectionRetries: ["Int", "remote-connection-retries"],
remoteTimeout: ["Int", "remote-timeout"]
});
/**
* Returns true if this is a remote debugger instance.

Просмотреть файл

@ -959,7 +959,7 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
* Utility functions for handling sources.
*/
let SourceUtils = {
_labelsCache: new Map(),
_labelsCache: new Map(), // Can't use WeakMaps because keys are strings.
_groupsCache: new Map(),
/**
@ -968,8 +968,8 @@ let SourceUtils = {
* This should be done every time the content location changes.
*/
clearCache: function SU_clearCache() {
this._labelsCache = new Map();
this._groupsCache = new Map();
this._labelsCache.clear();
this._groupsCache.clear();
},
/**
@ -987,7 +987,7 @@ let SourceUtils = {
}
let sourceLabel = this.trimUrl(aUrl);
let unicodeLabel = this.convertToUnicode(window.unescape(sourceLabel));
let unicodeLabel = NetworkHelper.convertToUnicode(unescape(sourceLabel));
this._labelsCache.set(aUrl, unicodeLabel);
return unicodeLabel;
},
@ -1036,7 +1036,7 @@ let SourceUtils = {
}
let groupLabel = group.join(" ");
let unicodeLabel = this.convertToUnicode(window.unescape(groupLabel));
let unicodeLabel = NetworkHelper.convertToUnicode(unescape(groupLabel));
this._groupsCache.set(aUrl, unicodeLabel)
return unicodeLabel;
},
@ -1181,31 +1181,6 @@ let SourceUtils = {
}
// Give up.
return aUrl.spec;
},
/**
* Convert a given string, encoded in a given character set, to unicode.
*
* @param string aString
* A string.
* @param string aCharset [optional]
* A character set.
* @return string
* A unicode string.
*/
convertToUnicode: function SU_convertToUnicode(aString, aCharset) {
// Decoding primitives.
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
try {
if (aCharset) {
converter.charset = aCharset;
}
return converter.ConvertToUnicode(aString);
} catch(e) {
return aString;
}
}
};

Просмотреть файл

@ -37,11 +37,11 @@ ToolbarView.prototype = {
let stepOverKey = LayoutHelpers.prettyKey(document.getElementById("stepOverKey"), true);
let stepInKey = LayoutHelpers.prettyKey(document.getElementById("stepInKey"), true);
let stepOutKey = LayoutHelpers.prettyKey(document.getElementById("stepOutKey"), true);
this._resumeTooltip = L10N.getFormatStr("resumeButtonTooltip", [resumeKey]);
this._pauseTooltip = L10N.getFormatStr("pauseButtonTooltip", [resumeKey]);
this._stepOverTooltip = L10N.getFormatStr("stepOverTooltip", [stepOverKey]);
this._stepInTooltip = L10N.getFormatStr("stepInTooltip", [stepInKey]);
this._stepOutTooltip = L10N.getFormatStr("stepOutTooltip", [stepOutKey]);
this._resumeTooltip = L10N.getFormatStr("resumeButtonTooltip", resumeKey);
this._pauseTooltip = L10N.getFormatStr("pauseButtonTooltip", resumeKey);
this._stepOverTooltip = L10N.getFormatStr("stepOverTooltip", stepOverKey);
this._stepInTooltip = L10N.getFormatStr("stepInTooltip", stepInKey);
this._stepOutTooltip = L10N.getFormatStr("stepOutTooltip", stepOutKey);
this._instrumentsPaneToggleButton.addEventListener("mousedown", this._onTogglePanesPressed, false);
this._resumeButton.addEventListener("mousedown", this._onResumePressed, false);
@ -645,7 +645,7 @@ let StackFrameUtils = {
name = aEnv.type.charAt(0).toUpperCase() + aEnv.type.slice(1);
}
let label = L10N.getFormatStr("scopeLabel", [name]);
let label = L10N.getFormatStr("scopeLabel", name);
switch (aEnv.type) {
case "with":
case "object":
@ -714,15 +714,15 @@ FilterView.prototype = {
this._variableOperatorButton.setAttribute("label", SEARCH_VARIABLE_FLAG);
this._globalOperatorLabel.setAttribute("value",
L10N.getFormatStr("searchPanelGlobal", [this._globalSearchKey]));
L10N.getFormatStr("searchPanelGlobal", this._globalSearchKey));
this._functionOperatorLabel.setAttribute("value",
L10N.getFormatStr("searchPanelFunction", [this._filteredFunctionsKey]));
L10N.getFormatStr("searchPanelFunction", this._filteredFunctionsKey));
this._tokenOperatorLabel.setAttribute("value",
L10N.getFormatStr("searchPanelToken", [this._tokenSearchKey]));
L10N.getFormatStr("searchPanelToken", this._tokenSearchKey));
this._lineOperatorLabel.setAttribute("value",
L10N.getFormatStr("searchPanelLine", [this._lineSearchKey]));
L10N.getFormatStr("searchPanelLine", this._lineSearchKey));
this._variableOperatorLabel.setAttribute("value",
L10N.getFormatStr("searchPanelVariable", [this._variableSearchKey]));
L10N.getFormatStr("searchPanelVariable", this._variableSearchKey));
// TODO: bug 806775
// if (window._isChromeDebugger) {
@ -753,10 +753,10 @@ FilterView.prototype = {
let placeholder = "";
switch (aView) {
case DebuggerView.ChromeGlobals:
placeholder = L10N.getFormatStr("emptyChromeGlobalsFilterText", [this._fileSearchKey]);
placeholder = L10N.getFormatStr("emptyChromeGlobalsFilterText", this._fileSearchKey);
break;
case DebuggerView.Sources:
placeholder = L10N.getFormatStr("emptyFilterText", [this._fileSearchKey]);
placeholder = L10N.getFormatStr("emptyFilterText", this._fileSearchKey);
break;
}
this._searchbox.setAttribute("placeholder", placeholder);

Просмотреть файл

@ -12,7 +12,6 @@ const STACK_FRAMES_SOURCE_URL_TRIM_SECTION = "center";
const STACK_FRAMES_POPUP_SOURCE_URL_MAX_LENGTH = 32; // chars
const STACK_FRAMES_POPUP_SOURCE_URL_TRIM_SECTION = "center";
const STACK_FRAMES_SCROLL_DELAY = 100; // ms
const PANES_APPEARANCE_DELAY = 50; // ms
const BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH = 1000; // chars
const BREAKPOINT_CONDITIONAL_POPUP_POSITION = "before_start";
const BREAKPOINT_CONDITIONAL_POPUP_OFFSET_X = 7; // px
@ -416,67 +415,30 @@ let DebuggerView = {
* @return boolean
*/
get instrumentsPaneHidden()
this._instrumentsPaneToggleButton.hasAttribute("toggled"),
this._instrumentsPane.hasAttribute("pane-collapsed"),
/**
* Sets the instruments pane hidden or visible.
*
* @param object aFlags [optional]
* An object containing some of the following boolean properties:
* - visible: true if the pane should be shown, false for hidden
* @param object aFlags
* An object containing some of the following properties:
* - visible: true if the pane should be shown, false to hide
* - animated: true to display an animation on toggle
* - delayed: true to wait a few cycles before toggle
* - callback: a function to invoke when the toggle finishes
*/
toggleInstrumentsPane: function DV__toggleInstrumentsPane(aFlags = {}) {
// Avoid useless toggles.
if (aFlags.visible == !this.instrumentsPaneHidden) {
if (aFlags.callback) aFlags.callback();
return;
}
toggleInstrumentsPane: function DV__toggleInstrumentsPane(aFlags) {
let pane = this._instrumentsPane;
let button = this._instrumentsPaneToggleButton;
// Computes and sets the pane margins in order to hide or show it.
function set() {
if (aFlags.visible) {
this._instrumentsPane.style.marginLeft = "0";
this._instrumentsPane.style.marginRight = "0";
this._instrumentsPaneToggleButton.removeAttribute("toggled");
this._instrumentsPaneToggleButton.setAttribute("tooltiptext", this._collapsePaneString);
} else {
let margin = ~~(this._instrumentsPane.getAttribute("width")) + 1;
this._instrumentsPane.style.marginLeft = -margin + "px";
this._instrumentsPane.style.marginRight = -margin + "px";
this._instrumentsPaneToggleButton.setAttribute("toggled", "true");
this._instrumentsPaneToggleButton.setAttribute("tooltiptext", this._expandPaneString);
}
ViewHelpers.togglePane(aFlags, pane);
if (aFlags.animated) {
// Displaying the panes may have the effect of triggering scrollbars to
// appear in the source editor, which would render the currently
// highlighted line to appear behind them in some cases.
window.addEventListener("transitionend", function onEvent() {
window.removeEventListener("transitionend", onEvent, false);
DebuggerView.updateEditor();
// Invoke the callback when the transition ended.
if (aFlags.callback) aFlags.callback();
}, false);
} else {
// Invoke the callback immediately since there's no transition.
if (aFlags.callback) aFlags.callback();
}
}
if (aFlags.animated) {
this._instrumentsPane.setAttribute("animated", "");
if (aFlags.visible) {
button.removeAttribute("pane-collapsed");
button.setAttribute("tooltiptext", this._collapsePaneString);
} else {
this._instrumentsPane.removeAttribute("animated");
}
if (aFlags.delayed) {
window.setTimeout(set.bind(this), PANES_APPEARANCE_DELAY);
} else {
set.call(this);
button.setAttribute("pane-collapsed", "");
button.setAttribute("tooltiptext", this._expandPaneString);
}
},

Просмотреть файл

@ -273,7 +273,7 @@
<splitter class="devtools-side-splitter"/>
<vbox id="editor" flex="1"/>
<splitter class="devtools-side-splitter"/>
<vbox id="instruments-pane">
<vbox id="instruments-pane" hidden="true">
<vbox id="expressions"/>
<splitter class="devtools-horizontal-splitter"/>
<vbox id="variables" flex="1"/>

Просмотреть файл

@ -28,10 +28,13 @@ function test() {
}
function testPanesState() {
let instrumentsPane =
gDebugger.document.getElementById("instruments-pane");
let instrumentsPaneToggleButton =
gDebugger.document.getElementById("instruments-pane-toggle");
ok(instrumentsPaneToggleButton.getAttribute("toggled"),
ok(instrumentsPane.hasAttribute("pane-collapsed") &&
instrumentsPaneToggleButton.hasAttribute("pane-collapsed"),
"The debugger view instruments pane should initially be hidden.");
is(gDebugger.Prefs.panesVisibleOnStartup, false,
"The debugger view instruments pane should initially be preffed as hidden.");
@ -54,7 +57,8 @@ function testInstrumentsPaneCollapse() {
"The instruments pane has an incorrect right margin.");
ok(!instrumentsPane.hasAttribute("animated"),
"The instruments pane has an incorrect animated attribute.");
ok(!instrumentsPaneToggleButton.getAttribute("toggled"),
ok(!instrumentsPane.hasAttribute("pane-collapsed") &&
!instrumentsPaneToggleButton.hasAttribute("pane-collapsed"),
"The instruments pane should at this point be visible.");
gView.toggleInstrumentsPane({ visible: false, animated: true });
@ -73,7 +77,8 @@ function testInstrumentsPaneCollapse() {
"The instruments pane has an incorrect right margin after collapsing.");
ok(instrumentsPane.hasAttribute("animated"),
"The instruments pane has an incorrect attribute after an animated collapsing.");
ok(instrumentsPaneToggleButton.hasAttribute("toggled"),
ok(instrumentsPane.hasAttribute("pane-collapsed") &&
instrumentsPaneToggleButton.hasAttribute("pane-collapsed"),
"The instruments pane should not be visible after collapsing.");
gView.toggleInstrumentsPane({ visible: true, animated: false });
@ -91,7 +96,8 @@ function testInstrumentsPaneCollapse() {
"The instruments pane has an incorrect right margin after uncollapsing.");
ok(!instrumentsPane.hasAttribute("animated"),
"The instruments pane has an incorrect attribute after an unanimated uncollapsing.");
ok(!instrumentsPaneToggleButton.getAttribute("toggled"),
ok(!instrumentsPane.hasAttribute("pane-collapsed") &&
!instrumentsPaneToggleButton.hasAttribute("pane-collapsed"),
"The instruments pane should be visible again after uncollapsing.");
}
@ -104,7 +110,8 @@ function testPanesStartupPref() {
is(gDebugger.Prefs.panesVisibleOnStartup, false,
"The debugger view panes should still initially be preffed as hidden.");
ok(!instrumentsPaneToggleButton.getAttribute("toggled"),
ok(!instrumentsPane.hasAttribute("pane-collapsed") &&
!instrumentsPaneToggleButton.hasAttribute("pane-collapsed"),
"The debugger instruments pane should at this point be visible.");
is(gDebugger.Prefs.panesVisibleOnStartup, false,
"The debugger view panes should initially be preffed as hidden.");
@ -115,7 +122,8 @@ function testPanesStartupPref() {
gDebugger.DebuggerView.Options._toggleShowPanesOnStartup();
executeSoon(function() {
ok(!instrumentsPaneToggleButton.getAttribute("toggled"),
ok(!instrumentsPane.hasAttribute("pane-collapsed") &&
!instrumentsPaneToggleButton.hasAttribute("pane-collapsed"),
"The debugger instruments pane should at this point be visible.");
is(gDebugger.Prefs.panesVisibleOnStartup, true,
"The debugger view panes should now be preffed as visible.");
@ -126,7 +134,8 @@ function testPanesStartupPref() {
gDebugger.DebuggerView.Options._toggleShowPanesOnStartup();
executeSoon(function() {
ok(!instrumentsPaneToggleButton.getAttribute("toggled"),
ok(!instrumentsPane.hasAttribute("pane-collapsed") &&
!instrumentsPaneToggleButton.hasAttribute("pane-collapsed"),
"The debugger instruments pane should at this point be visible.");
is(gDebugger.Prefs.panesVisibleOnStartup, false,
"The debugger view panes should now be preffed as hidden.");

Просмотреть файл

@ -30,8 +30,8 @@ function testPause() {
let button = gDebugger.document.getElementById("resume");
is(button.getAttribute("tooltiptext"),
gL10N.getFormatStr("pauseButtonTooltip", [
gLH.prettyKey(gDebugger.document.getElementById("resumeKey"))]),
gL10N.getFormatStr("pauseButtonTooltip",
gLH.prettyKey(gDebugger.document.getElementById("resumeKey"))),
"Button tooltip should be pause when running.");
gDebugger.DebuggerController.activeThread.addOneTimeListener("paused", function() {
@ -44,8 +44,8 @@ function testPause() {
"Should be paused after an interrupt request.");
is(button.getAttribute("tooltiptext"),
gL10N.getFormatStr("resumeButtonTooltip", [
gLH.prettyKey(gDebugger.document.getElementById("resumeKey"))]),
gL10N.getFormatStr("resumeButtonTooltip",
gLH.prettyKey(gDebugger.document.getElementById("resumeKey"))),
"Button tooltip should be resume when paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
@ -69,8 +69,8 @@ function testResume() {
let button = gDebugger.document.getElementById("resume");
is(button.getAttribute("tooltiptext"),
gL10N.getFormatStr("pauseButtonTooltip", [
gLH.prettyKey(gDebugger.document.getElementById("resumeKey"))]),
gL10N.getFormatStr("pauseButtonTooltip",
gLH.prettyKey(gDebugger.document.getElementById("resumeKey"))),
"Button tooltip should be pause when running.");
closeDebuggerAndFinish();

Просмотреть файл

@ -84,7 +84,7 @@ function testSourcesCache()
"There should be " + TOTAL_SOURCES + " groups cached");
gPrevLabelsCache = gDebugger.SourceUtils._labelsCache;
gPrevLabelsCache = gDebugger.SourceUtils._groupsCache;
gPrevGroupsCache = gDebugger.SourceUtils._groupsCache;
fetchSources(function() {
performReload(function() {
@ -142,10 +142,10 @@ function testStateBeforeReload() {
"There should be no sources present in the sources list during reload.");
is(gControllerSources.getCache().length, 0,
"The sources cache should be empty during reload.");
isnot(gDebugger.SourceUtils._labelsCache, gPrevLabelsCache,
"The labels cache has been refreshed during reload.")
isnot(gDebugger.SourceUtils._groupsCache, gPrevGroupsCache,
"The groups cache has been refreshed during reload.")
is(gDebugger.SourceUtils._labelsCache, gPrevLabelsCache,
"The labels cache has been refreshed during reload and no new objects were created.");
is(gDebugger.SourceUtils._groupsCache, gPrevGroupsCache,
"The groups cache has been refreshed during reload and no new objects were created.");
is(gDebugger.SourceUtils._labelsCache.size, 0,
"There should be no labels cached during reload");
is(gDebugger.SourceUtils._groupsCache.size, 0,

Просмотреть файл

@ -9,7 +9,8 @@ this.EXPORTED_SYMBOLS = [
"webConsoleDefinition",
"debuggerDefinition",
"inspectorDefinition",
"styleEditorDefinition"
"styleEditorDefinition",
"netMonitorDefinition"
];
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
@ -19,6 +20,7 @@ const debuggerProps = "chrome://browser/locale/devtools/debugger.properties";
const styleEditorProps = "chrome://browser/locale/devtools/styleeditor.properties";
const webConsoleProps = "chrome://browser/locale/devtools/webconsole.properties";
const profilerProps = "chrome://browser/locale/devtools/profiler.properties";
const netMonitorProps = "chrome://browser/locale/devtools/netmonitor.properties";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -43,6 +45,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "InspectorPanel",
XPCOMUtils.defineLazyModuleGetter(this, "ProfilerPanel",
"resource:///modules/devtools/ProfilerPanel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetMonitorPanel",
"resource:///modules/devtools/NetMonitorPanel.jsm");
// Strings
XPCOMUtils.defineLazyGetter(this, "webConsoleStrings",
function() Services.strings.createBundle(webConsoleProps));
@ -59,6 +64,9 @@ XPCOMUtils.defineLazyGetter(this, "inspectorStrings",
XPCOMUtils.defineLazyGetter(this, "profilerStrings",
function() Services.strings.createBundle(profilerProps));
XPCOMUtils.defineLazyGetter(this, "netMonitorStrings",
function() Services.strings.createBundle(netMonitorProps));
// Definitions
let webConsoleDefinition = {
id: "webconsole",
@ -129,9 +137,9 @@ let styleEditorDefinition = {
ordinal: 3,
accesskey: l10n("open.accesskey", styleEditorStrings),
modifiers: "shift",
label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
icon: "chrome://browser/skin/devtools/tool-styleeditor.png",
url: "chrome://browser/content/styleeditor.xul",
label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
tooltip: l10n("ToolboxStyleEditor.tooltip", styleEditorStrings),
isTargetSupported: function(target) {
@ -151,9 +159,9 @@ let profilerDefinition = {
ordinal: 4,
modifiers: "shift",
killswitch: "devtools.profiler.enabled",
icon: "chrome://browser/skin/devtools/tool-profiler.png",
url: "chrome://browser/content/profiler.xul",
label: l10n("profiler.label", profilerStrings),
icon: "chrome://browser/skin/devtools/tool-profiler.png",
tooltip: l10n("profiler.tooltip", profilerStrings),
isTargetSupported: function (target) {
@ -166,12 +174,34 @@ let profilerDefinition = {
}
};
let netMonitorDefinition = {
id: "netmonitor",
accesskey: l10n("netmonitor.accesskey", netMonitorStrings),
key: l10n("netmonitor.commandkey", netMonitorStrings),
ordinal: 5,
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
killswitch: "devtools.netmonitor.enabled",
icon: "chrome://browser/skin/devtools/tool-profiler.png",
url: "chrome://browser/content/devtools/netmonitor.xul",
label: l10n("netmonitor.label", netMonitorStrings),
tooltip: l10n("netmonitor.tooltip", netMonitorStrings),
isTargetSupported: function(target) {
return true;
},
build: function(iframeWindow, toolbox) {
let panel = new NetMonitorPanel(iframeWindow, toolbox);
return panel.open();
}
};
this.defaultTools = [
styleEditorDefinition,
webConsoleDefinition,
debuggerDefinition,
inspectorDefinition,
netMonitorDefinition
];
if (Services.prefs.getBoolPref("devtools.profiler.enabled")) {

Просмотреть файл

@ -6,6 +6,10 @@ browser.jar:
content/browser/devtools/widgets.css (shared/widgets/widgets.css)
content/browser/devtools/markup-view.xhtml (markupview/markup-view.xhtml)
content/browser/devtools/markup-view.css (markupview/markup-view.css)
content/browser/devtools/netmonitor.xul (netmonitor/netmonitor.xul)
content/browser/devtools/netmonitor.css (netmonitor/netmonitor.css)
content/browser/devtools/netmonitor-controller.js (netmonitor/netmonitor-controller.js)
content/browser/devtools/netmonitor-view.js (netmonitor/netmonitor-view.js)
content/browser/NetworkPanel.xhtml (webconsole/NetworkPanel.xhtml)
content/browser/devtools/webconsole.js (webconsole/webconsole.js)
content/browser/devtools/webconsole.xul (webconsole/webconsole.xul)

Просмотреть файл

@ -15,6 +15,7 @@ DIRS += [
'tilt',
'scratchpad',
'debugger',
'netmonitor',
'layoutview',
'shared',
'responsivedesign',

Просмотреть файл

@ -0,0 +1,15 @@
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
libs::
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools

Просмотреть файл

@ -0,0 +1,66 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* 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 strict";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
this.EXPORTED_SYMBOLS = ["NetMonitorPanel"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/devtools/EventEmitter.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
function NetMonitorPanel(iframeWindow, toolbox) {
this.panelWin = iframeWindow;
this._toolbox = toolbox;
this._view = this.panelWin.NetMonitorView;
this._controller = this.panelWin.NetMonitorController;
this._controller._target = this.target;
EventEmitter.decorate(this);
}
NetMonitorPanel.prototype = {
/**
* Open is effectively an asynchronous constructor.
*
* @return object
* A Promise that is resolved when the NetMonitor completes opening.
*/
open: function NetMonitorPanel_open() {
let promise;
// Local monitoring needs to make the target remote.
if (!this.target.isRemote) {
promise = this.target.makeRemote();
} else {
promise = Promise.resolve(this.target);
}
return promise
.then(() => this._controller.startupNetMonitor())
.then(() => this._controller.connect())
.then(() => {
this.isReady = true;
this.emit("ready");
return this;
})
.then(null, function onError(aReason) {
Cu.reportError("NetMonitorPanel open failed. " +
reason.error + ": " + reason.message);
});
},
// DevToolPanel API
get target() this._toolbox.target,
destroy: function() {
this._controller.shutdownNetMonitor().then(() => this.emit("destroyed"));
}
};

Просмотреть файл

@ -0,0 +1,6 @@
# vim: set filetype=python:
# 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/.
TEST_DIRS += ['test']

Просмотреть файл

@ -0,0 +1,514 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* 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 strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
Cu.import("resource:///modules/source-editor.jsm");
Cu.import("resource:///modules/devtools/EventEmitter.jsm");
Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
Cu.import("resource:///modules/devtools/VariablesView.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
"resource://gre/modules/devtools/NetworkHelper.jsm");
const NET_STRINGS_URI = "chrome://browser/locale/devtools/netmonitor.properties";
const LISTENERS = [ "NetworkActivity" ];
const NET_PREFS = { "NetworkMonitor.saveRequestAndResponseBodies": true };
/**
* Object defining the network monitor controller components.
*/
let NetMonitorController = {
/**
* Initializes the view.
*
* @return object
* A promise that is resolved when the monitor finishes startup.
*/
startupNetMonitor: function() {
if (this._isInitialized) {
return this._startup.promise;
}
this._isInitialized = true;
let deferred = this._startup = Promise.defer();
NetMonitorView.initialize(() => {
NetMonitorView._isInitialized = true;
deferred.resolve();
});
return deferred.promise;
},
/**
* Destroys the view and disconnects the monitor client from the server.
*
* @return object
* A promise that is resolved when the monitor finishes shutdown.
*/
shutdownNetMonitor: function() {
if (this._isDestroyed) {
return this._shutdown.promise;
}
this._isDestroyed = true;
this._startup = null;
let deferred = this._shutdown = Promise.defer();
NetMonitorView.destroy(() => {
NetMonitorView._isDestroyed = true;
this.TargetEventsHandler.disconnect();
this.NetworkEventsHandler.disconnect();
this.disconnect();
deferred.resolve();
});
return deferred.promise;
},
/**
* Initiates remote or chrome network monitoring based on the current target,
* wiring event handlers as necessary.
*
* @return object
* A promise that is resolved when the monitor finishes connecting.
*/
connect: function() {
if (this._connection) {
return this._connection.promise;
}
let deferred = this._connection = Promise.defer();
let target = this._target;
let { client, form } = target;
if (target.chrome) {
this._startChromeMonitoring(client, form.consoleActor, deferred.resolve);
} else {
this._startMonitoringTab(client, form, deferred.resolve);
}
return deferred.promise;
},
/**
* Disconnects the debugger client and removes event handlers as necessary.
*/
disconnect: function() {
// When debugging local or a remote instance, the connection is closed by
// the RemoteTarget.
this._connection = null;
this.client = null;
this.tabClient = null;
this.webConsoleClient = null;
},
/**
* Sets up a monitoring session.
*
* @param DebuggerClient aClient
* The debugger client.
* @param object aTabGrip
* The remote protocol grip of the tab.
* @param function aCallback
* A function to invoke once the client attached to the console client.
*/
_startMonitoringTab: function(aClient, aTabGrip, aCallback) {
if (!aClient) {
Cu.reportError("No client found!");
return;
}
this.client = aClient;
aClient.attachTab(aTabGrip.actor, (aResponse, aTabClient) => {
if (!aTabClient) {
Cu.reportError("No tab client found!");
return;
}
this.tabClient = aTabClient;
aClient.attachConsole(aTabGrip.consoleActor, LISTENERS, (aResponse, aWebConsoleClient) => {
if (!aWebConsoleClient) {
Cu.reportError("Couldn't attach to console: " + aResponse.error);
return;
}
this.webConsoleClient = aWebConsoleClient;
this.webConsoleClient.setPreferences(NET_PREFS, () => {
this.TargetEventsHandler.connect();
this.NetworkEventsHandler.connect();
if (aCallback) {
aCallback();
}
});
});
});
},
/**
* Sets up a chrome monitoring session.
*
* @param DebuggerClient aClient
* The debugger client.
* @param object aConsoleActor
* The remote protocol grip of the chrome debugger.
* @param function aCallback
* A function to invoke once the client attached to the console client.
*/
_startChromeMonitoring: function(aClient, aConsoleActor, aCallback) {
if (!aClient) {
Cu.reportError("No client found!");
return;
}
this.client = aClient;
aClient.attachConsole(aConsoleActor, LISTENERS, (aResponse, aWebConsoleClient) => {
if (!aWebConsoleClient) {
Cu.reportError("Couldn't attach to console: " + aResponse.error);
return;
}
this.webConsoleClient = aWebConsoleClient;
this.webConsoleClient.setPreferences(NET_PREFS, () => {
this.TargetEventsHandler.connect();
this.NetworkEventsHandler.connect();
if (aCallback) {
aCallback();
}
});
});
},
_isInitialized: false,
_isDestroyed: false,
_startup: null,
_shutdown: null,
_connection: null,
client: null,
tabClient: null,
webConsoleClient: null
};
/**
* Functions handling target-related lifetime events.
*/
function TargetEventsHandler() {
this._onTabNavigated = this._onTabNavigated.bind(this);
this._onTabDetached = this._onTabDetached.bind(this);
}
TargetEventsHandler.prototype = {
get target() NetMonitorController._target,
get webConsoleClient() NetMonitorController.webConsoleClient,
/**
* Listen for events emitted by the current tab target.
*/
connect: function() {
dumpn("TargetEventsHandler is connecting...");
this.target.on("close", this._onTabDetached);
this.target.on("navigate", this._onTabNavigated);
this.target.on("will-navigate", this._onTabNavigated);
},
/**
* Remove events emitted by the current tab target.
*/
disconnect: function() {
if (!this.target) {
return;
}
dumpn("TargetEventsHandler is disconnecting...");
this.target.off("close", this._onTabDetached);
this.target.off("navigate", this._onTabNavigated);
this.target.off("will-navigate", this._onTabNavigated);
},
/**
* Called for each location change in the monitored tab.
*
* @param string aType
* Packet type.
* @param object aPacket
* Packet received from the server.
*/
_onTabNavigated: function(aType, aPacket) {
if (aType == "will-navigate") {
NetMonitorView.RequestsMenu.reset();
NetMonitorView.NetworkDetails.toggle(false);
window.emit("NetMonitor:TargetWillNavigate");
}
if (aType == "navigate") {
window.emit("NetMonitor:TargetNavigate");
}
},
/**
* Called when the monitored tab is closed.
*/
_onTabDetached: function() {
NetMonitorController.shutdownNetMonitor();
}
};
/**
* Functions handling target network events.
*/
function NetworkEventsHandler() {
this._onNetworkEvent = this._onNetworkEvent.bind(this);
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
this._onRequestHeaders = this._onRequestHeaders.bind(this);
this._onRequestCookies = this._onRequestCookies.bind(this);
this._onRequestPostData = this._onRequestPostData.bind(this);
this._onResponseHeaders = this._onResponseHeaders.bind(this);
this._onResponseCookies = this._onResponseCookies.bind(this);
this._onResponseContent = this._onResponseContent.bind(this);
this._onEventTimings = this._onEventTimings.bind(this);
}
NetworkEventsHandler.prototype = {
get client() NetMonitorController._target.client,
get webConsoleClient() NetMonitorController.webConsoleClient,
/**
* Connect to the current target client.
*/
connect: function() {
dumpn("NetworkEventsHandler is connecting...");
this.client.addListener("networkEvent", this._onNetworkEvent);
this.client.addListener("networkEventUpdate", this._onNetworkEventUpdate);
},
/**
* Disconnect from the client.
*/
disconnect: function() {
if (!this.client) {
return;
}
dumpn("NetworkEventsHandler is disconnecting...");
this.client.removeListener("networkEvent", this._onNetworkEvent);
this.client.removeListener("networkEventUpdate", this._onNetworkEventUpdate);
},
/**
* The "networkEvent" message type handler.
*
* @param string aType
* Message type.
* @param object aPacket
* The message received from the server.
*/
_onNetworkEvent: function(aType, aPacket) {
let { actor, startedDateTime, method, url } = aPacket.eventActor;
NetMonitorView.RequestsMenu.addRequest(actor, startedDateTime, method, url);
window.emit("NetMonitor:NetworkEvent");
},
/**
* The "networkEventUpdate" message type handler.
*
* @param string aType
* Message type.
* @param object aPacket
* The message received from the server.
*/
_onNetworkEventUpdate: function(aType, aPacket) {
let actor = aPacket.from;
switch (aPacket.updateType) {
case "requestHeaders":
this.webConsoleClient.getRequestHeaders(actor, this._onRequestHeaders);
window.emit("NetMonitor:NetworkEventUpdating:RequestHeaders");
break;
case "requestCookies":
this.webConsoleClient.getRequestCookies(actor, this._onRequestCookies);
window.emit("NetMonitor:NetworkEventUpdating:RequestCookies");
break;
case "requestPostData":
this.webConsoleClient.getRequestPostData(actor, this._onRequestPostData);
window.emit("NetMonitor:NetworkEventUpdating:RequestPostData");
break;
case "responseHeaders":
this.webConsoleClient.getResponseHeaders(actor, this._onResponseHeaders);
window.emit("NetMonitor:NetworkEventUpdating:ResponseHeaders");
break;
case "responseCookies":
this.webConsoleClient.getResponseCookies(actor, this._onResponseCookies);
window.emit("NetMonitor:NetworkEventUpdating:ResponseCookies");
break;
case "responseStart":
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
httpVersion: aPacket.response.httpVersion,
status: aPacket.response.status,
statusText: aPacket.response.statusText,
headersSize: aPacket.response.headersSize
});
window.emit("NetMonitor:NetworkEventUpdating:ResponseStart");
break;
case "responseContent":
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
contentSize: aPacket.contentSize,
mimeType: aPacket.mimeType
});
this.webConsoleClient.getResponseContent(actor, this._onResponseContent);
window.emit("NetMonitor:NetworkEventUpdating:ResponseContent");
break;
case "eventTimings":
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
totalTime: aPacket.totalTime
});
this.webConsoleClient.getEventTimings(actor, this._onEventTimings);
window.emit("NetMonitor:NetworkEventUpdating:EventTimings");
break;
}
},
/**
* Handles additional information received for a "requestHeaders" packet.
*
* @param object aResponse
* The message received from the server.
*/
_onRequestHeaders: function(aResponse) {
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
requestHeaders: aResponse
});
window.emit("NetMonitor:NetworkEventUpdated:RequestHeaders");
},
/**
* Handles additional information received for a "requestCookies" packet.
*
* @param object aResponse
* The message received from the server.
*/
_onRequestCookies: function(aResponse) {
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
requestCookies: aResponse
});
window.emit("NetMonitor:NetworkEventUpdated:RequestCookies");
},
/**
* Handles additional information received for a "requestPostData" packet.
*
* @param object aResponse
* The message received from the server.
*/
_onRequestPostData: function(aResponse) {
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
requestPostData: aResponse
});
window.emit("NetMonitor:NetworkEventUpdated:RequestPostData");
},
/**
* Handles additional information received for a "responseHeaders" packet.
*
* @param object aResponse
* The message received from the server.
*/
_onResponseHeaders: function(aResponse) {
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
responseHeaders: aResponse
});
window.emit("NetMonitor:NetworkEventUpdated:ResponseHeaders");
},
/**
* Handles additional information received for a "responseCookies" packet.
*
* @param object aResponse
* The message received from the server.
*/
_onResponseCookies: function(aResponse) {
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
responseCookies: aResponse
});
window.emit("NetMonitor:NetworkEventUpdated:ResponseCookies");
},
/**
* Handles additional information received for a "responseContent" packet.
*
* @param object aResponse
* The message received from the server.
*/
_onResponseContent: function(aResponse) {
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
responseContent: aResponse
});
window.emit("NetMonitor:NetworkEventUpdated:ResponseContent");
},
/**
* Handles additional information received for a "eventTimings" packet.
*
* @param object aResponse
* The message received from the server.
*/
_onEventTimings: function NEH__onEventTimings(aResponse) {
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
eventTimings: aResponse
});
window.emit("NetMonitor:NetworkEventUpdated:EventTimings");
}
};
/**
* Localization convenience methods.
*/
let L10N = new ViewHelpers.L10N(NET_STRINGS_URI);
/**
* Shortcuts for accessing various network monitor preferences.
*/
let Prefs = new ViewHelpers.Prefs("devtools.netmonitor", {
networkDetailsWidth: ["Int", "panes-network-details-width"]
});
/**
* Convenient way of emitting events from the panel window.
*/
EventEmitter.decorate(this);
/**
* Preliminary setup for the NetMonitorController object.
*/
NetMonitorController.TargetEventsHandler = new TargetEventsHandler();
NetMonitorController.NetworkEventsHandler = new NetworkEventsHandler();
/**
* Export some properties to the global scope for easier access.
*/
Object.defineProperties(window, {
"create": {
get: function() ViewHelpers.create,
}
});
/**
* Helper method for debugging.
* @param string
*/
function dumpn(str) {
if (wantLogging) {
dump("NET-FRONTEND: " + str + "\n");
}
}
let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,8 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
#response-content-image-box {
overflow: auto;
}

Просмотреть файл

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/devtools/widgets.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/devtools/netmonitor.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/widgets.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/netmonitor.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % netmonitorDTD SYSTEM "chrome://browser/locale/devtools/netmonitor.dtd">
%netmonitorDTD;
]>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript" src="netmonitor-controller.js"/>
<script type="text/javascript" src="netmonitor-view.js"/>
<hbox id="body" flex="1">
<vbox id="network-table" flex="1">
<toolbar id="requests-menu-toolbar"
class="devtools-toolbar"
align="center">
<label id="requests-menu-status-and-method-label"
class="plain requests-menu-header requests-menu-status-and-method"
value="&netmonitorUI.toolbar.method;"
crop="end"/>
<label id="requests-menu-file-label"
class="plain requests-menu-header requests-menu-file"
value="&netmonitorUI.toolbar.file;"
crop="end"/>
<label id="requests-menu-domain-label"
class="plain requests-menu-header requests-menu-domain"
value="&netmonitorUI.toolbar.domain;"
crop="end"/>
<label id="requests-menu-type-label"
class="plain requests-menu-header requests-menu-type"
value="&netmonitorUI.toolbar.type;"
crop="end"/>
<label id="requests-menu-size-label"
class="plain requests-menu-header requests-menu-size"
value="&netmonitorUI.toolbar.size;"
crop="end"/>
<label id="requests-menu-waterfall-label"
class="plain requests-menu-header requests-menu-waterfall"
value="&netmonitorUI.toolbar.waterfall;"
crop="end"/>
<spacer flex="1"/>
<toolbarbutton id="details-pane-toggle"
class="devtools-toolbarbutton"
tooltiptext="&netmonitorUI.panesButton.tooltip;"
tabindex="0"/>
</toolbar>
<label class="plain requests-menu-empty-notice"
value="&netmonitorUI.emptyNotice;"/>
<vbox id="requests-menu-contents" flex="1">
<template id="requests-menu-item-template">
<hbox class="requests-menu-item">
<hbox class="requests-menu-subitem requests-menu-status-and-method"
align="center">
<hbox class="requests-menu-status"/>
<label class="plain requests-menu-method"
crop="end"
flex="1"/>
</hbox>
<label class="plain requests-menu-subitem requests-menu-file"
crop="end"/>
<label class="plain requests-menu-subitem requests-menu-domain"
crop="end"/>
<label class="plain requests-menu-subitem requests-menu-type"
crop="end"/>
<label class="plain requests-menu-subitem requests-menu-size"
crop="end"/>
<hbox class="requests-menu-subitem requests-menu-waterfall"
align="center"
flex="1">
<hbox class="requests-menu-timings"
align="center">
<hbox class="start requests-menu-timings-cap" hidden="true"/>
<hbox class="end requests-menu-timings-cap" hidden="true"/>
<label class="plain requests-menu-timings-total"/>
</hbox>
</hbox>
</hbox>
</template>
</vbox>
</vbox>
<splitter class="devtools-side-splitter"/>
<tabbox id="details-pane" class="devtools-sidebar-tabs" hidden="true">
<tabs>
<tab label="&netmonitorUI.tab.headers;"/>
<tab label="&netmonitorUI.tab.cookies;"/>
<tab label="&netmonitorUI.tab.params;"/>
<tab label="&netmonitorUI.tab.response;"/>
<tab label="&netmonitorUI.tab.timings;"/>
</tabs>
<tabpanels flex="1">
<tabpanel id="headers-tabppanel"
class="tabpanel-content">
<vbox flex="1">
<hbox id="headers-summary-url"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.summary.url;"/>
<label id="headers-summary-url-value"
class="plain tabpanel-summary-value"
crop="end"
flex="1"/>
</hbox>
<hbox id="headers-summary-method"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.summary.method;"/>
<label id="headers-summary-method-value"
class="plain tabpanel-summary-value"
crop="end"
flex="1"/>
</hbox>
<hbox id="headers-summary-status"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.summary.status;"/>
<hbox id="headers-summary-status-circle"
class="requests-menu-status"/>
<label id="headers-summary-status-value"
class="plain tabpanel-summary-value"
crop="end"
flex="1"/>
</hbox>
<hbox id="headers-summary-version"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.summary.version;"/>
<label id="headers-summary-version-value"
class="plain tabpanel-summary-value"
crop="end"
flex="1"/>
</hbox>
<vbox id="all-headers" flex="1"/>
</vbox>
</tabpanel>
<tabpanel id="cookies-tabpanel"
class="tabpanel-content">
<vbox flex="1">
<vbox id="all-cookies" flex="1"/>
</vbox>
</tabpanel>
<tabpanel id="params-tabpanel"
class="tabpanel-content">
<vbox flex="1">
<vbox id="request-params-box" flex="1" hidden="true">
<vbox id="request-params" flex="1"/>
</vbox>
<vbox id="request-post-data-textarea-box" flex="1" hidden="true">
<vbox id="request-post-data-textarea" flex="1"/>
</vbox>
</vbox>
</tabpanel>
<tabpanel id="response-tabpanel"
class="tabpanel-content">
<vbox flex="1">
<vbox id="response-content-json-box" flex="1" hidden="true">
<vbox id="response-content-json" flex="1"/>
</vbox>
<vbox id="response-content-textarea-box" flex="1" hidden="true">
<vbox id="response-content-textarea" flex="1"/>
</vbox>
<vbox id="response-content-image-box" flex="1" hidden="true">
<image id="response-content-image"/>
<hbox>
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.response.name;"/>
<label id="response-content-image-name-value"
class="plain tabpanel-summary-value"
crop="end"
flex="1"/>
</hbox>
<hbox>
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.response.dimensions;"/>
<label id="response-content-image-dimensions-value"
class="plain tabpanel-summary-value"
crop="end"
flex="1"/>
</hbox>
<hbox>
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.response.mime;"/>
<label id="response-content-image-mime-value"
class="plain tabpanel-summary-value"
crop="end"
flex="1"/>
</hbox>
<hbox>
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.response.encoding;"/>
<label id="response-content-image-encoding-value"
class="plain tabpanel-summary-value"
crop="end"
flex="1"/>
</hbox>
</vbox>
</vbox>
</tabpanel>
<tabpanel id="timings-tabpanel"
class="tabpanel-content">
<vbox flex="1">
<hbox id="timings-summary-blocked"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.timings.blocked;"/>
<hbox class="requests-menu-timings-box blocked"/>
<label class="plain requests-menu-timings-total"/>
</hbox>
<hbox id="timings-summary-dns"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.timings.dns;"/>
<hbox class="requests-menu-timings-box dns"/>
<label class="plain requests-menu-timings-total"/>
</hbox>
<hbox id="timings-summary-connect"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.timings.connect;"/>
<hbox class="requests-menu-timings-box connect"/>
<label class="plain requests-menu-timings-total"/>
</hbox>
<hbox id="timings-summary-send"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.timings.send;"/>
<hbox class="requests-menu-timings-box send"/>
<label class="plain requests-menu-timings-total"/>
</hbox>
<hbox id="timings-summary-wait"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.timings.wait;"/>
<hbox class="requests-menu-timings-box wait"/>
<label class="plain requests-menu-timings-total"/>
</hbox>
<hbox id="timings-summary-receive"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.timings.receive;"/>
<hbox class="requests-menu-timings-box receive"/>
<label class="plain requests-menu-timings-total"/>
</hbox>
</vbox>
</tabpanel>
</tabpanels>
</tabbox>
</hbox>
</window>

Просмотреть файл

@ -0,0 +1,43 @@
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
MOCHITEST_BROWSER_TESTS = \
browser_net_aaa_leaktest.js \
browser_net_simple-init.js \
browser_net_page-nav.js \
browser_net_prefs-and-l10n.js \
browser_net_prefs-reload.js \
browser_net_pane-collapse.js \
browser_net_simple-request.js \
browser_net_simple-request-data.js \
browser_net_simple-request-details.js \
browser_net_content-type.js \
browser_net_status-codes.js \
browser_net_post-data.js \
head.js \
$(NULL)
MOCHITEST_BROWSER_PAGES = \
test-image.png \
html_simple-test-page.html \
html_navigate-test-page.html \
html_content-type-test-page.html \
html_status-codes-test-page.html \
html_post-data-test-page.html \
sjs_simple-test-server.sjs \
sjs_content-type-test-server.sjs \
sjs_status-codes-test-server.sjs \
$(NULL)
MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,28 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the network monitor leaks on initialization and sudden destruction.
* You can also use this initialization format as a template for other tests.
*/
function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, NetMonitorView, NetMonitorController } = aMonitor.panelWin;
let { RequestsMenu, NetworkDetails } = NetMonitorView;
ok(aTab, "Should have a tab available.");
ok(aDebuggee, "Should have a debuggee available.");
ok(aMonitor, "Should have a network monitor pane available.");
ok(document, "Should have a document available.");
ok(NetMonitorView, "Should have a NetMonitorView object available.");
ok(NetMonitorController, "Should have a NetMonitorController object available.");
ok(RequestsMenu, "Should have a RequestsMenu object available.");
ok(NetworkDetails, "Should have a NetworkDetails object available.");
teardown(aMonitor).then(finish);
});
}

Просмотреть файл

@ -0,0 +1,214 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if different response content types are handled correctly.
*/
function test() {
initNetMonitor(CONTENT_TYPE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, SourceEditor, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 6).then(() => {
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"GET", CONTENT_TYPE_SJS + "?fmt=xml", {
status: 200,
type: "xml",
size: "0.04kb",
time: true
});
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
"GET", CONTENT_TYPE_SJS + "?fmt=css", {
status: 200,
type: "css",
size: "0.03kb",
time: true
});
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(2),
"GET", CONTENT_TYPE_SJS + "?fmt=js", {
status: 200,
type: "js",
size: "0.03kb",
time: true
});
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(3),
"GET", CONTENT_TYPE_SJS + "?fmt=json", {
status: 200,
type: "json",
size: "0.03kb",
time: true
});
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
"GET", CONTENT_TYPE_SJS + "?fmt=bogus", {
status: 404,
type: "html",
size: "0.02kb",
time: true
});
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(5),
"GET", TEST_IMAGE, {
status: 200,
type: "png",
size: "0.76kb",
time: true
});
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
testResponseTab("xml")
.then(() => {
RequestsMenu.selectedIndex = 1;
return testResponseTab("css");
})
.then(() => {
RequestsMenu.selectedIndex = 2;
return testResponseTab("js");
})
.then(() => {
RequestsMenu.selectedIndex = 3;
return testResponseTab("json");
})
.then(() => {
RequestsMenu.selectedIndex = 4;
return testResponseTab("html");
})
.then(() => {
RequestsMenu.selectedIndex = 5;
return testResponseTab("png");
})
.then(() => {
return teardown(aMonitor);
})
.then(finish);
function testResponseTab(aType) {
let tab = document.querySelectorAll("#details-pane tab")[3];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
function checkVisibility(aBox) {
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), aBox != "json",
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), aBox != "textarea",
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), aBox != "image",
"The response content image box doesn't have the intended visibility.");
}
switch (aType) {
case "xml": {
checkVisibility("textarea");
return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
is(aEditor.getText(), "<label value='greeting'>Hello XML!</label>",
"The text shown in the source editor is incorrect for the xml request.");
is(aEditor.getMode(), SourceEditor.MODES.HTML,
"The mode active in the source editor is incorrect for the xml request.");
});
}
case "css": {
checkVisibility("textarea");
return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
is(aEditor.getText(), "body:pre { content: 'Hello CSS!' }",
"The text shown in the source editor is incorrect for the xml request.");
is(aEditor.getMode(), SourceEditor.MODES.CSS,
"The mode active in the source editor is incorrect for the xml request.");
});
}
case "js": {
checkVisibility("textarea");
return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
is(aEditor.getText(), "function() { return 'Hello JS!'; }",
"The text shown in the source editor is incorrect for the xml request.");
is(aEditor.getMode(), SourceEditor.MODES.JAVASCRIPT,
"The mode active in the source editor is incorrect for the xml request.");
});
}
case "json": {
checkVisibility("json");
is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
"There should be 1 json scope displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-property").length, 2,
"There should be 2 json properties displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
"The empty notice should not be displayed in this tabpanel.");
let jsonScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
is(jsonScope.querySelector(".name").getAttribute("value"),
"JSON", "The json scope doesn't have the correct title.");
is(jsonScope.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
"greeting", "The first json property name was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .value")[0].getAttribute("value"),
"\"Hello JSON!\"", "The first json property value was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
"__proto__", "The second json property name was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .value")[1].getAttribute("value"),
"[object Object]", "The second json property value was incorrect.");
return Promise.resolve();
}
case "html": {
checkVisibility("textarea");
return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
is(aEditor.getText(), "<blink>Not Found</blink>",
"The text shown in the source editor is incorrect for the xml request.");
is(aEditor.getMode(), SourceEditor.MODES.HTML,
"The mode active in the source editor is incorrect for the xml request.");
});
}
case "png": {
checkVisibility("image");
let imageNode = tabpanel.querySelector("#response-content-image");
let deferred = Promise.defer();
imageNode.addEventListener("load", function onLoad() {
imageNode.removeEventListener("load", onLoad);
is(tabpanel.querySelector("#response-content-image-name-value")
.getAttribute("value"), "test-image.png",
"The image name info isn't correct.");
is(tabpanel.querySelector("#response-content-image-mime-value")
.getAttribute("value"), "image/png",
"The image mime info isn't correct.");
is(tabpanel.querySelector("#response-content-image-encoding-value")
.getAttribute("value"), "base64",
"The image encoding info isn't correct.");
is(tabpanel.querySelector("#response-content-image-dimensions-value")
.getAttribute("value"), "16 x 16",
"The image dimensions info isn't correct.");
deferred.resolve();
});
return deferred.promise;
}
}
}
});
aDebuggee.performRequests();
});
}

Просмотреть файл

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if page navigation ("close", "navigate", etc.) triggers an appropriate
* action in the network monitor.
*/
function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
testNavigate(() => testNavigateBack(() => testClose(() => finish())));
function testNavigate(aCallback) {
info("Navigating forward...");
aMonitor.panelWin.once("NetMonitor:TargetWillNavigate", () => {
is(aDebuggee.location, SIMPLE_URL,
"Target started navigating to the correct location.");
aMonitor.panelWin.once("NetMonitor:TargetNavigate", () => {
is(aDebuggee.location, NAVIGATE_URL,
"Target finished navigating to the correct location.");
aCallback();
});
});
aDebuggee.location = NAVIGATE_URL;
}
function testNavigateBack(aCallback) {
info("Navigating backward...");
aMonitor.panelWin.once("NetMonitor:TargetWillNavigate", () => {
is(aDebuggee.location, NAVIGATE_URL,
"Target started navigating back to the previous location.");
aMonitor.panelWin.once("NetMonitor:TargetNavigate", () => {
is(aDebuggee.location, SIMPLE_URL,
"Target finished navigating back to the previous location.");
aCallback();
});
});
aDebuggee.location = SIMPLE_URL;
}
function testClose(aCallback) {
info("Closing...");
aMonitor.once("destroyed", () => {
ok(!aMonitor._controller.client,
"There shouldn't be a client available after destruction.");
ok(!aMonitor._controller.tabClient,
"There shouldn't be a tabClient available after destruction.");
ok(!aMonitor._controller.webConsoleClient,
"There shouldn't be a webConsoleClient available after destruction.");
aCallback();
});
removeTab(aTab);
}
});
}

Просмотреть файл

@ -0,0 +1,66 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the network monitor panes collapse properly.
*/
function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, Prefs, NetMonitorView } = aMonitor.panelWin;
let detailsPane = document.getElementById("details-pane");
let detailsPaneToggleButton = document.getElementById("details-pane-toggle");
ok(detailsPane.hasAttribute("pane-collapsed") &&
detailsPaneToggleButton.hasAttribute("pane-collapsed"),
"The details pane should initially be hidden.");
NetMonitorView.toggleDetailsPane({ visible: true, animated: false });
let width = ~~(detailsPane.getAttribute("width"));
is(width, Prefs.networkDetailsWidth,
"The details pane has an incorrect width.");
is(detailsPane.style.marginLeft, "0px",
"The details pane has an incorrect left margin.");
is(detailsPane.style.marginRight, "0px",
"The details pane has an incorrect right margin.");
ok(!detailsPane.hasAttribute("animated"),
"The details pane has an incorrect animated attribute.");
ok(!detailsPane.hasAttribute("pane-collapsed") &&
!detailsPaneToggleButton.hasAttribute("pane-collapsed"),
"The details pane should at this point be visible.");
NetMonitorView.toggleDetailsPane({ visible: false, animated: true });
let margin = -(width + 1) + "px";
is(width, Prefs.networkDetailsWidth,
"The details pane has an incorrect width after collapsing.");
is(detailsPane.style.marginLeft, margin,
"The details pane has an incorrect left margin after collapsing.");
is(detailsPane.style.marginRight, margin,
"The details pane has an incorrect right margin after collapsing.");
ok(detailsPane.hasAttribute("animated"),
"The details pane has an incorrect attribute after an animated collapsing.");
ok(detailsPane.hasAttribute("pane-collapsed") &&
detailsPaneToggleButton.hasAttribute("pane-collapsed"),
"The details pane should not be visible after collapsing.");
NetMonitorView.toggleDetailsPane({ visible: true, animated: false });
is(width, Prefs.networkDetailsWidth,
"The details pane has an incorrect width after uncollapsing.");
is(detailsPane.style.marginLeft, "0px",
"The details pane has an incorrect left margin after uncollapsing.");
is(detailsPane.style.marginRight, "0px",
"The details pane has an incorrect right margin after uncollapsing.");
ok(!detailsPane.hasAttribute("animated"),
"The details pane has an incorrect attribute after an unanimated uncollapsing.");
ok(!detailsPane.hasAttribute("pane-collapsed") &&
!detailsPaneToggleButton.hasAttribute("pane-collapsed"),
"The details pane should be visible again after uncollapsing.");
teardown(aMonitor).then(finish);
});
}

Просмотреть файл

@ -0,0 +1,150 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the POST requests display the correct information in the UI.
*/
function test() {
initNetMonitor(POST_DATA_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu, NetworkDetails } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
NetworkDetails._params.lazyEmpty = false;
waitForNetworkEvents(aMonitor, 0, 2).then(() => {
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"POST", SIMPLE_SJS + "?foo=bar&baz=42&type=urlencoded", {
status: 200,
type: "plain",
size: "0.01kb",
time: true
});
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
"POST", SIMPLE_SJS + "?foo=bar&baz=42&type=multipart", {
status: 200,
type: "plain",
size: "0.01kb",
time: true
});
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[2]);
testParamsTab("urlencoded")
.then(() => {
RequestsMenu.selectedIndex = 1;
return testParamsTab("multipart");
})
.then(() => {
return teardown(aMonitor);
})
.then(finish);
function testParamsTab(aType) {
let tab = document.querySelectorAll("#details-pane tab")[2];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
is(tab.getAttribute("selected"), "true",
"The params tab in the network details pane should be selected.");
function checkVisibility(aBox) {
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), !aBox.contains("params"),
"The request params box doesn't have the indended visibility.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), !aBox.contains("textarea"),
"The request post data textarea box doesn't have the indended visibility.");
}
is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
"There should be 2 param scopes displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
"The empty notice should not be displayed in this tabpanel.");
let queryScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
let postScope = tabpanel.querySelectorAll(".variables-view-scope")[1];
is(queryScope.querySelector(".name").getAttribute("value"),
L10N.getStr("paramsQueryString"),
"The query scope doesn't have the correct title.");
is(postScope.querySelector(".name").getAttribute("value"),
L10N.getStr(aType == "urlencoded" ? "paramsFormData" : "paramsPostPayload"),
"The post scope doesn't have the correct title.");
is(queryScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
"foo", "The first query param name was incorrect.");
is(queryScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
"\"bar\"", "The first query param value was incorrect.");
is(queryScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
"baz", "The second query param name was incorrect.");
is(queryScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
"\"42\"", "The second query param value was incorrect.");
is(queryScope.querySelectorAll(".variables-view-variable .name")[2].getAttribute("value"),
"type", "The third query param name was incorrect.");
is(queryScope.querySelectorAll(".variables-view-variable .value")[2].getAttribute("value"),
"\"" + aType + "\"", "The third query param value was incorrect.");
if (aType == "urlencoded") {
checkVisibility("params");
is(tabpanel.querySelectorAll(".variables-view-variable").length, 5,
"There should be 6 param values displayed in this tabpanel.");
is(queryScope.querySelectorAll(".variables-view-variable").length, 3,
"There should be 3 param values displayed in the query scope.");
is(postScope.querySelectorAll(".variables-view-variable").length, 2,
"There should be 3 param values displayed in the post scope.");
is(postScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
"foo", "The first post param name was incorrect.");
is(postScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
"\"bar\"", "The first post param value was incorrect.");
is(postScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
"baz", "The second post param name was incorrect.");
is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
"\"123\"", "The second post param value was incorrect.");
return Promise.resolve();
}
else {
checkVisibility("params textarea");
is(tabpanel.querySelectorAll(".variables-view-variable").length, 3,
"There should be 3 param values displayed in this tabpanel.");
is(queryScope.querySelectorAll(".variables-view-variable").length, 3,
"There should be 3 param values displayed in the query scope.");
is(postScope.querySelectorAll(".variables-view-variable").length, 0,
"There should be 0 param values displayed in the post scope.");
return NetMonitorView.editor("#request-post-data-textarea").then((aEditor) => {
ok(aEditor.getText().contains("Content-Disposition: form-data; name=\"text\""),
"The text shown in the source editor is incorrect (1.1).");
ok(aEditor.getText().contains("Content-Disposition: form-data; name=\"email\""),
"The text shown in the source editor is incorrect (2.1).");
ok(aEditor.getText().contains("Content-Disposition: form-data; name=\"range\""),
"The text shown in the source editor is incorrect (3.1).");
ok(aEditor.getText().contains("Content-Disposition: form-data; name=\"Custom field\""),
"The text shown in the source editor is incorrect (4.1).");
ok(aEditor.getText().contains("Some text..."),
"The text shown in the source editor is incorrect (2.2).");
ok(aEditor.getText().contains("42"),
"The text shown in the source editor is incorrect (3.2).");
ok(aEditor.getText().contains("Extra data"),
"The text shown in the source editor is incorrect (4.2).");
is(aEditor.getMode(), SourceEditor.MODES.TEXT,
"The mode active in the source editor is incorrect.");
});
}
}
});
aDebuggee.performRequests();
});
}

Просмотреть файл

@ -0,0 +1,67 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the preferences and localization objects work correctly.
*/
function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
ok(aMonitor.panelWin.L10N,
"Should have a localization object available on the panel window.");
ok(aMonitor.panelWin.Prefs,
"Should have a preferences object available on the panel window.");
function testL10N() {
let { L10N } = aMonitor.panelWin;
ok(L10N.stringBundle,
"The localization object should have a string bundle available.");
let bundleName = "chrome://browser/locale/devtools/netmonitor.properties";
let stringBundle = Services.strings.createBundle(bundleName);
is(L10N.getStr("netmonitor.label"),
stringBundle.GetStringFromName("netmonitor.label"),
"The getStr() method didn't return the expected string.");
is(L10N.getFormatStr("networkMenu.total", "foo"),
stringBundle.formatStringFromName("networkMenu.total", ["foo"], 1),
"The getFormatStr() method didn't return the expected string.");
}
function testPrefs() {
let { Prefs } = aMonitor.panelWin;
is(Prefs.root, "devtools.netmonitor",
"The preferences object should have a correct root path.");
is(Prefs.networkDetailsWidth,
Services.prefs.getIntPref("devtools.netmonitor.panes-network-details-width"),
"Getting a pref should work correctly.");
let previousValue = Prefs.networkDetailsWidth;
let bogusValue = ~~(Math.random() * 100);
Prefs.networkDetailsWidth = bogusValue;
is(Prefs.networkDetailsWidth,
Services.prefs.getIntPref("devtools.netmonitor.panes-network-details-width"),
"Getting a pref after it has been modified should work correctly.");
is(Prefs.networkDetailsWidth, bogusValue,
"The pref wasn't updated correctly in the preferences object.");
Prefs.networkDetailsWidth = previousValue;
is(Prefs.networkDetailsWidth,
Services.prefs.getIntPref("devtools.netmonitor.panes-network-details-width"),
"Getting a pref after it has been modified again should work correctly.");
is(Prefs.networkDetailsWidth, previousValue,
"The pref wasn't updated correctly again in the preferences object.");
}
testL10N();
testPrefs();
teardown(aMonitor).then(finish);
});
}

Просмотреть файл

@ -0,0 +1,130 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the prefs that should survive across tool reloads work.
*/
function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let prefsToCheck = {
networkDetailsWidth: {
newValue: ~~(Math.random() * 200 + 100),
validate: () =>
~~aMonitor._view._detailsPane.getAttribute("width"),
modifyFrontend: (aValue) =>
aMonitor._view._detailsPane.setAttribute("width", aValue)
},
/* add more prefs here... */
};
function storeFirstPrefValues() {
info("Caching initial pref values.");
for (let name in prefsToCheck) {
let currentValue = aMonitor.panelWin.Prefs[name];
prefsToCheck[name].firstValue = currentValue;
}
}
function validateFirstPrefValues() {
info("Validating current pref values to the UI elements.");
for (let name in prefsToCheck) {
let currentValue = aMonitor.panelWin.Prefs[name];
let firstValue = prefsToCheck[name].firstValue;
let validate = prefsToCheck[name].validate;
is(currentValue, firstValue,
"Pref " + name + " should be equal to first value: " + firstValue);
is(currentValue, validate(),
"Pref " + name + " should validate: " + currentValue);
}
}
function modifyFrontend() {
info("Modifying UI elements to the specified new values.");
for (let name in prefsToCheck) {
let currentValue = aMonitor.panelWin.Prefs[name];
let firstValue = prefsToCheck[name].firstValue;
let newValue = prefsToCheck[name].newValue;
let validate = prefsToCheck[name].validate;
let modifyFrontend = prefsToCheck[name].modifyFrontend;
modifyFrontend(newValue);
info("Modified UI element affecting " + name + " to: " + newValue);
is(currentValue, firstValue,
"Pref " + name + " should still be equal to first value: " + firstValue);
isnot(currentValue, newValue,
"Pref " + name + " should't yet be equal to second value: " + newValue);
is(newValue, validate(),
"The UI element affecting " + name + " should validate: " + newValue);
}
}
function validateNewPrefValues() {
info("Invalidating old pref values to the modified UI elements.");
for (let name in prefsToCheck) {
let currentValue = aMonitor.panelWin.Prefs[name];
let firstValue = prefsToCheck[name].firstValue;
let newValue = prefsToCheck[name].newValue;
let validate = prefsToCheck[name].validate;
let modifyFrontend = prefsToCheck[name].modifyFrontend;
isnot(currentValue, firstValue,
"Pref " + name + " should't be equal to first value: " + firstValue);
is(currentValue, newValue,
"Pref " + name + " should now be equal to second value: " + newValue);
is(newValue, validate(),
"The UI element affecting " + name + " should validate: " + newValue);
}
}
function resetFrontend() {
info("Resetting UI elements to the cached initial pref values.");
for (let name in prefsToCheck) {
let currentValue = aMonitor.panelWin.Prefs[name];
let firstValue = prefsToCheck[name].firstValue;
let newValue = prefsToCheck[name].newValue;
let validate = prefsToCheck[name].validate;
let modifyFrontend = prefsToCheck[name].modifyFrontend;
modifyFrontend(firstValue);
info("Modified UI element affecting " + name + " to: " + firstValue);
isnot(currentValue, firstValue,
"Pref " + name + " should't yet be equal to first value: " + firstValue);
is(currentValue, newValue,
"Pref " + name + " should still be equal to second value: " + newValue);
is(firstValue, validate(),
"The UI element affecting " + name + " should validate: " + firstValue);
}
}
storeFirstPrefValues();
// Validate and modify.
validateFirstPrefValues();
modifyFrontend();
restartNetMonitor(aMonitor).then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
// Revalidate and reset.
validateNewPrefValues();
resetFrontend();
restartNetMonitor(aMonitor).then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
// Revalidate and finish.
validateFirstPrefValues();
teardown(aMonitor).then(finish);
});
});
});
}

Просмотреть файл

@ -0,0 +1,84 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Simple check if the network monitor starts up and shuts down properly.
*/
function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
is(aTab.linkedBrowser.contentWindow.wrappedJSObject.location, SIMPLE_URL,
"The current tab's location is the correct one.");
is(aDebuggee.location, SIMPLE_URL,
"The current debuggee's location is the correct one.");
function checkIfInitialized(aTag) {
info("Checking if initialization is ok (" + aTag + ").");
ok(aMonitor._view,
"The network monitor view object exists (" + aTag + ").");
ok(aMonitor._view._isInitialized,
"The network monitor view object exists and is initialized (" + aTag + ").");
ok(aMonitor._controller,
"The network monitor controller object exists (" + aTag + ").");
ok(aMonitor._controller._isInitialized,
"The network monitor controller object exists and is initialized (" + aTag + ").");
ok(aMonitor.isReady,
"The network monitor panel appears to be ready (" + aTag + ").");
ok(aMonitor._controller.client,
"There should be a client available at this point (" + aTag + ").");
ok(aMonitor._controller.tabClient,
"There should be a tabClient available at this point (" + aTag + ").");
ok(aMonitor._controller.webConsoleClient,
"There should be a webConsoleClient available at this point (" + aTag + ").");
}
function checkIfDestroyed(aTag) {
info("Checking if destruction is ok.");
ok(!aMonitor._controller.client,
"There shouldn't be a client available after destruction (" + aTag + ").");
ok(!aMonitor._controller.tabClient,
"There shouldn't be a tabClient available after destruction (" + aTag + ").");
ok(!aMonitor._controller.webConsoleClient,
"There shouldn't be a webConsoleClient available after destruction (" + aTag + ").");
}
executeSoon(() => {
checkIfInitialized(1);
aMonitor._controller.startupNetMonitor()
.then(() => {
info("Starting up again shouldn't do anything special.");
checkIfInitialized(2);
return aMonitor._controller.connect();
})
.then(() => {
info("Connecting again shouldn't do anything special.");
checkIfInitialized(3);
return teardown(aMonitor);
})
.then(finish);
});
registerCleanupFunction(() => {
checkIfDestroyed(1);
aMonitor._controller.shutdownNetMonitor()
.then(() => {
info("Shutting down again shouldn't do anything special.");
checkIfDestroyed(2);
return aMonitor._controller.disconnect();
})
.then(() => {
info("Disconnecting again shouldn't do anything special.");
checkIfDestroyed(3);
});
});
});
}

Просмотреть файл

@ -0,0 +1,232 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if requests render correct information in the menu UI.
*/
function test() {
initNetMonitor(SIMPLE_SJS).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 1)
.then(() => teardown(aMonitor))
.then(finish);
aMonitor.panelWin.once("NetMonitor:NetworkEvent", () => {
is(RequestsMenu.selectedItem, null,
"There shouldn't be any selected item in the requests menu.");
is(RequestsMenu.itemCount, 1,
"The requests menu should not be empty after the first request.");
is(NetMonitorView.detailsPaneHidden, true,
"The details pane should still be hidden after the first request.");
let requestItem = RequestsMenu.getItemAtIndex(0);
let target = requestItem.target;
is(typeof requestItem.attachment.id, "string",
"The attached id is incorrect.");
isnot(requestItem.attachment.id, "",
"The attached id should not be empty.");
is(typeof requestItem.attachment.startedDeltaMillis, "number",
"The attached startedDeltaMillis is incorrect.");
is(requestItem.attachment.startedDeltaMillis, 0,
"The attached startedDeltaMillis should be zero.");
is(typeof requestItem.attachment.startedMillis, "number",
"The attached startedMillis is incorrect.");
isnot(requestItem.attachment.startedMillis, 0,
"The attached startedMillis should not be zero.");
is(requestItem.attachment.requestHeaders, undefined,
"The requestHeaders should not yet be set.");
is(requestItem.attachment.requestCookies, undefined,
"The requestCookies should not yet be set.");
is(requestItem.attachment.requestPostData, undefined,
"The requestPostData should not yet be set.");
is(requestItem.attachment.responseHeaders, undefined,
"The responseHeaders should not yet be set.");
is(requestItem.attachment.responseCookies, undefined,
"The responseCookies should not yet be set.");
is(requestItem.attachment.httpVersion, undefined,
"The httpVersion should not yet be set.");
is(requestItem.attachment.status, undefined,
"The status should not yet be set.");
is(requestItem.attachment.statusText, undefined,
"The statusText should not yet be set.");
is(requestItem.attachment.headersSize, undefined,
"The headersSize should not yet be set.");
is(requestItem.attachment.contentSize, undefined,
"The contentSize should not yet be set.");
is(requestItem.attachment.mimeType, undefined,
"The mimeType should not yet be set.");
is(requestItem.attachment.responseContent, undefined,
"The responseContent should not yet be set.");
is(requestItem.attachment.totalTime, undefined,
"The totalTime should not yet be set.");
is(requestItem.attachment.eventTimings, undefined,
"The eventTimings should not yet be set.");
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:RequestHeaders", () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
ok(requestItem.attachment.requestHeaders,
"There should be a requestHeaders attachment available.");
is(requestItem.attachment.requestHeaders.headers.length, 7,
"The requestHeaders attachment has an incorrect |headers| property.");
isnot(requestItem.attachment.requestHeaders.headersSize, 0,
"The requestHeaders attachment has an incorrect |headersSize| property.");
// Can't test for the exact request headers size because the value may
// vary across platforms ("User-Agent" header differs).
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:RequestCookies", () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
ok(requestItem.attachment.requestCookies,
"There should be a requestCookies attachment available.");
is(requestItem.attachment.requestCookies.cookies.length, 0,
"The requestCookies attachment has an incorrect |cookies| property.");
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:RequestPostData", () => {
ok(false, "Trap listener: this request doesn't have any post data.")
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:ResponseHeaders", () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
ok(requestItem.attachment.responseHeaders,
"There should be a responseHeaders attachment available.");
is(requestItem.attachment.responseHeaders.headers.length, 6,
"The responseHeaders attachment has an incorrect |headers| property.");
is(requestItem.attachment.responseHeaders.headersSize, 173,
"The responseHeaders attachment has an incorrect |headersSize| property.");
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:ResponseCookies", () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
ok(requestItem.attachment.responseCookies,
"There should be a responseCookies attachment available.");
is(requestItem.attachment.responseCookies.cookies.length, 0,
"The responseCookies attachment has an incorrect |cookies| property.");
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdating:ResponseStart", () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
is(requestItem.attachment.httpVersion, "HTTP/1.1",
"The httpVersion attachment has an incorrect value.");
is(requestItem.attachment.status, "200",
"The status attachment has an incorrect value.");
is(requestItem.attachment.statusText, "Och Aye",
"The statusText attachment has an incorrect value.");
is(requestItem.attachment.headersSize, 173,
"The headersSize attachment has an incorrect value.");
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
status: "200"
});
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdating:ResponseContent", () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
is(requestItem.attachment.contentSize, "12",
"The contentSize attachment has an incorrect value.");
is(requestItem.attachment.mimeType, "text/plain; charset=utf-8",
"The mimeType attachment has an incorrect value.");
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
type: "plain",
size: "0.01kb"
});
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:ResponseContent", () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
ok(requestItem.attachment.responseContent,
"There should be a responseContent attachment available.");
is(requestItem.attachment.responseContent.content.mimeType, "text/plain; charset=utf-8",
"The responseContent attachment has an incorrect |content.mimeType| property.");
is(requestItem.attachment.responseContent.content.text, "Hello world!",
"The responseContent attachment has an incorrect |content.text| property.");
is(requestItem.attachment.responseContent.content.size, 12,
"The responseContent attachment has an incorrect |content.size| property.");
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
type: "plain",
size: "0.01kb"
});
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdating:EventTimings", () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
is(typeof requestItem.attachment.totalTime, "number",
"The attached totalTime is incorrect.");
ok(requestItem.attachment.totalTime >= 0,
"The attached totalTime should be positive.");
is(typeof requestItem.attachment.endedMillis, "number",
"The attached endedMillis is incorrect.");
ok(requestItem.attachment.endedMillis >= 0,
"The attached endedMillis should be positive.");
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
time: true
});
});
aMonitor.panelWin.once("NetMonitor:NetworkEventUpdated:EventTimings", () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
ok(requestItem.attachment.eventTimings,
"There should be a eventTimings attachment available.");
is(typeof requestItem.attachment.eventTimings.timings.blocked, "number",
"The eventTimings attachment has an incorrect |timings.blocked| property.");
is(typeof requestItem.attachment.eventTimings.timings.dns, "number",
"The eventTimings attachment has an incorrect |timings.dns| property.");
is(typeof requestItem.attachment.eventTimings.timings.connect, "number",
"The eventTimings attachment has an incorrect |timings.connect| property.");
is(typeof requestItem.attachment.eventTimings.timings.send, "number",
"The eventTimings attachment has an incorrect |timings.send| property.");
is(typeof requestItem.attachment.eventTimings.timings.wait, "number",
"The eventTimings attachment has an incorrect |timings.wait| property.");
is(typeof requestItem.attachment.eventTimings.timings.receive, "number",
"The eventTimings attachment has an incorrect |timings.receive| property.");
is(typeof requestItem.attachment.eventTimings.totalTime, "number",
"The eventTimings attachment has an incorrect |totalTime| property.");
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
time: true
});
});
aDebuggee.location.reload();
});
}

Просмотреть файл

@ -0,0 +1,225 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if requests render correct information in the details UI.
*/
function test() {
initNetMonitor(SIMPLE_SJS).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu, NetworkDetails } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 1).then(() => {
is(RequestsMenu.selectedItem, null,
"There shouldn't be any selected item in the requests menu.");
is(RequestsMenu.itemCount, 1,
"The requests menu should not be empty after the first request.");
is(NetMonitorView.detailsPaneHidden, true,
"The details pane should still be hidden after the first request.");
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
isnot(RequestsMenu.selectedItem, null,
"There should be a selected item in the requests menu.");
is(RequestsMenu.selectedIndex, 0,
"The first item should be selected in the requests menu.");
is(NetMonitorView.detailsPaneHidden, false,
"The details pane should not be hidden after toggle button was pressed.");
testHeadersTab();
testCookiesTab();
testParamsTab();
testResponseTab()
.then(() => {
testTimingsTab();
return teardown(aMonitor);
})
.then(finish);
});
function testHeadersTab() {
let tab = document.querySelectorAll("#details-pane tab")[0];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[0];
is(tab.getAttribute("selected"), "true",
"The headers tab in the network details pane should be selected.");
is(tabpanel.querySelector("#headers-summary-url-value").getAttribute("value"),
SIMPLE_SJS, "The url summary value is incorrect.");
is(tabpanel.querySelector("#headers-summary-method-value").getAttribute("value"),
"GET", "The method summary value is incorrect.");
is(tabpanel.querySelector("#headers-summary-status-circle").getAttribute("code"),
"200", "The status summary code is incorrect.");
is(tabpanel.querySelector("#headers-summary-status-value").getAttribute("value"),
"200 Och Aye", "The status summary value is incorrect.");
is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
"There should be 2 header scopes displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variable-or-property").length, 13,
"There should be 13 header values displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
"The empty notice should not be displayed in this tabpanel.");
let responseScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
let requestScope = tabpanel.querySelectorAll(".variables-view-scope")[1];
is(responseScope.querySelector(".name").getAttribute("value"),
L10N.getStr("responseHeaders") + " (" +
L10N.getFormatStr("networkMenu.size", "0.169") + ")",
"The response headers scope doesn't have the correct title.");
ok(requestScope.querySelector(".name").getAttribute("value").contains(
L10N.getStr("requestHeaders") + " (0."),
// Can't test for full request headers title because the size may
// vary across platforms ("User-Agent" header differs).
"The request headers scope doesn't have the correct title.");
is(responseScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
"Connection", "The first response header name was incorrect.");
is(responseScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
"\"close\"", "The first response header value was incorrect.");
is(responseScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
"Content-Length", "The second response header name was incorrect.");
is(responseScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
"\"12\"", "The second response header value was incorrect.");
is(responseScope.querySelectorAll(".variables-view-variable .name")[2].getAttribute("value"),
"Content-Type", "The third response header name was incorrect.");
is(responseScope.querySelectorAll(".variables-view-variable .value")[2].getAttribute("value"),
"\"text/plain; charset=utf-8\"", "The third response header value was incorrect.");
is(responseScope.querySelectorAll(".variables-view-variable .name")[5].getAttribute("value"),
"foo-bar", "The last response header name was incorrect.");
is(responseScope.querySelectorAll(".variables-view-variable .value")[5].getAttribute("value"),
"\"baz\"", "The last response header value was incorrect.");
is(requestScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
"Host", "The first request header name was incorrect.");
is(requestScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
"\"example.com\"", "The first request header value was incorrect.");
is(requestScope.querySelectorAll(".variables-view-variable .name")[5].getAttribute("value"),
"Connection", "The penultimate request header name was incorrect.");
is(requestScope.querySelectorAll(".variables-view-variable .value")[5].getAttribute("value"),
"\"keep-alive\"", "The penultimate request header value was incorrect.");
is(requestScope.querySelectorAll(".variables-view-variable .name")[6].getAttribute("value"),
"Cache-Control", "The last request header name was incorrect.");
is(requestScope.querySelectorAll(".variables-view-variable .value")[6].getAttribute("value"),
"\"max-age=0\"", "The last request header value was incorrect.");
}
function testCookiesTab() {
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[1]);
let tab = document.querySelectorAll("#details-pane tab")[1];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[1];
is(tab.getAttribute("selected"), "true",
"The cookies tab in the network details pane should be selected.");
is(tabpanel.querySelectorAll(".variables-view-scope").length, 0,
"There should be no cookie scopes displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variable-or-property").length, 0,
"There should be no cookie values displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 1,
"The empty notice should be displayed in this tabpanel.");
}
function testParamsTab() {
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[2]);
let tab = document.querySelectorAll("#details-pane tab")[2];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
is(tab.getAttribute("selected"), "true",
"The params tab in the network details pane should be selected.");
is(tabpanel.querySelectorAll(".variables-view-scope").length, 0,
"There should be no param scopes displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variable-or-property").length, 0,
"There should be no param values displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 1,
"The empty notice should be displayed in this tabpanel.");
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), false,
"The request params box should not be hidden.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), true,
"The request post data textarea box should be hidden.");
}
function testResponseTab() {
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
let tab = document.querySelectorAll("#details-pane tab")[3];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), true,
"The response content json box should be hidden.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), false,
"The response content textarea box should not be hidden.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box should be hidden.");
return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
is(aEditor.getText(), "Hello world!",
"The text shown in the source editor is incorrect.");
is(aEditor.getMode(), SourceEditor.MODES.TEXT,
"The mode active in the source editor is incorrect.");
});
}
function testTimingsTab() {
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[4]);
let tab = document.querySelectorAll("#details-pane tab")[4];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[4];
is(tab.getAttribute("selected"), "true",
"The timings tab in the network details pane should be selected.");
ok(tabpanel.querySelector("#timings-summary-blocked .requests-menu-timings-total")
.getAttribute("value").match(/[0-9]+ms$/),
"The blocked timing info does not appear to be correct.");
ok(tabpanel.querySelector("#timings-summary-dns .requests-menu-timings-total")
.getAttribute("value").match(/[0-9]+ms$/),
"The dns timing info does not appear to be correct.");
ok(tabpanel.querySelector("#timings-summary-connect .requests-menu-timings-total")
.getAttribute("value").match(/[0-9]+ms$/),
"The connect timing info does not appear to be correct.");
ok(tabpanel.querySelector("#timings-summary-send .requests-menu-timings-total")
.getAttribute("value").match(/[0-9]+ms$/),
"The send timing info does not appear to be correct.");
ok(tabpanel.querySelector("#timings-summary-wait .requests-menu-timings-total")
.getAttribute("value").match(/[0-9]+ms$/),
"The wait timing info does not appear to be correct.");
ok(tabpanel.querySelector("#timings-summary-receive .requests-menu-timings-total")
.getAttribute("value").match(/[0-9]+ms$/),
"The receive timing info does not appear to be correct.");
}
aDebuggee.location.reload();
});
}

Просмотреть файл

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if requests are handled correctly.
*/
function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
is(document.querySelector(".requests-menu-empty-notice")
.hasAttribute("hidden"), false,
"An empty notice should be displayed when the frontend is opened.");
is(RequestsMenu.itemCount, 0,
"The requests menu should be empty when the frontend is opened.");
is(NetMonitorView.detailsPaneHidden, true,
"The details pane should be hidden when the frontend is opened.");
aMonitor.panelWin.once("NetMonitor:NetworkEvent", () => {
is(document.querySelector(".requests-menu-empty-notice")
.hasAttribute("hidden"), true,
"The empty notice should be hidden after the first request.");
is(RequestsMenu.itemCount, 1,
"The requests menu should not be empty after the first request.");
is(NetMonitorView.detailsPaneHidden, true,
"The details pane should still be hidden after the first request.");
aMonitor.panelWin.once("NetMonitor:NetworkEvent", () => {
is(document.querySelector(".requests-menu-empty-notice")
.hasAttribute("hidden"), true,
"The empty notice should be still hidden after a reload.");
is(RequestsMenu.itemCount, 1,
"The requests menu should not be empty after a reload.");
is(NetMonitorView.detailsPaneHidden, true,
"The details pane should still be hidden after a reload.");
teardown(aMonitor).then(finish);
});
aDebuggee.location.reload();
});
aDebuggee.location.reload();
});
}

Просмотреть файл

@ -0,0 +1,146 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if requests display the correct status code and text in the UI.
*/
function test() {
initNetMonitor(STATUS_CODES_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, L10N, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu, NetworkDetails } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
NetworkDetails._params.lazyEmpty = false;
waitForNetworkEvents(aMonitor, 5).then(() => {
let requestItems = [];
verifyRequestItemTarget(requestItems[0] = RequestsMenu.getItemAtIndex(0),
"GET", STATUS_CODES_SJS + "?sts=100", {
status: 101,
type: "plain",
size: "0.00kb",
time: true
});
verifyRequestItemTarget(requestItems[1] = RequestsMenu.getItemAtIndex(1),
"GET", STATUS_CODES_SJS + "?sts=200", {
status: 202,
type: "plain",
size: "0.02kb",
time: true
});
verifyRequestItemTarget(requestItems[2] = RequestsMenu.getItemAtIndex(2),
"GET", STATUS_CODES_SJS + "?sts=300", {
status: 303,
type: "plain",
size: "0.00kb",
time: true
});
verifyRequestItemTarget(requestItems[3] = RequestsMenu.getItemAtIndex(3),
"GET", STATUS_CODES_SJS + "?sts=400", {
status: 404,
type: "plain",
size: "0.02kb",
time: true
});
verifyRequestItemTarget(requestItems[4] = RequestsMenu.getItemAtIndex(4),
"GET", STATUS_CODES_SJS + "?sts=500", {
status: 501,
type: "plain",
size: "0.02kb",
time: true
});
// Test summaries...
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[0]);
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[0].target);
testSummary("GET", STATUS_CODES_SJS + "?sts=100", "101", "Switching Protocols");
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[1].target);
testSummary("GET", STATUS_CODES_SJS + "?sts=200", "202", "Created");
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[2].target);
testSummary("GET", STATUS_CODES_SJS + "?sts=300", "303", "See Other");
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[3].target);
testSummary("GET", STATUS_CODES_SJS + "?sts=400", "404", "Not Found");
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[4].target);
testSummary("GET", STATUS_CODES_SJS + "?sts=500", "501", "Not Implemented");
// Test params...
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[2]);
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[0].target);
testParamsTab("\"100\"");
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[1].target);
testParamsTab("\"200\"");
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[2].target);
testParamsTab("\"300\"");
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[3].target);
testParamsTab("\"400\"");
EventUtils.sendMouseEvent({ type: "mousedown" }, requestItems[4].target);
testParamsTab("\"500\"");
// We're done here.
teardown(aMonitor).then(finish);
function testSummary(aMethod, aUrl, aStatus, aStatusText) {
let tab = document.querySelectorAll("#details-pane tab")[0];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[0];
is(tabpanel.querySelector("#headers-summary-url-value").getAttribute("value"),
aUrl, "The url summary value is incorrect.");
is(tabpanel.querySelector("#headers-summary-method-value").getAttribute("value"),
aMethod, "The method summary value is incorrect.");
is(tabpanel.querySelector("#headers-summary-status-circle").getAttribute("code"),
aStatus, "The status summary code is incorrect.");
is(tabpanel.querySelector("#headers-summary-status-value").getAttribute("value"),
aStatus + " " + aStatusText, "The status summary value is incorrect.");
}
function testParamsTab(aStatusParamValue) {
let tab = document.querySelectorAll("#details-pane tab")[2];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
"There should be 1 param scope displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variable-or-property").length, 1,
"There should be 1 param value displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
"The empty notice should not be displayed in this tabpanel.");
let paramsScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
is(paramsScope.querySelector(".name").getAttribute("value"),
L10N.getStr("paramsQueryString"),
"The params scope doesn't have the correct title.");
is(paramsScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
"sts", "The param name was incorrect.");
is(paramsScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
aStatusParamValue, "The param value was incorrect.");
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), false,
"The request params box should not be hidden.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), true,
"The request post data textarea box should be hidden.");
}
});
aDebuggee.performRequests();
});
}

Просмотреть файл

@ -0,0 +1,224 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
let { Promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
let { TargetFactory } = Cu.import("resource:///modules/devtools/Target.jsm", {});
let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/";
const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs";
const CONTENT_TYPE_SJS = EXAMPLE_URL + "sjs_content-type-test-server.sjs";
const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
// All tests are asynchronous.
waitForExplicitFinish();
// Enable logging for all the relevant tests.
let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
Services.prefs.setBoolPref("devtools.debugger.log", true);
registerCleanupFunction(() => {
info("finish() was called, cleaning up...");
Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
});
function addTab(aUrl, aWindow) {
info("Adding tab: " + aUrl);
let deferred = Promise.defer();
let targetWindow = aWindow || window;
let targetBrowser = targetWindow.gBrowser;
targetWindow.focus();
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
tab.addEventListener("load", function onLoad() {
tab.removeEventListener("load", onLoad, true);
deferred.resolve(tab);
}, true);
return deferred.promise;
}
function removeTab(aTab, aWindow) {
info("Removing tab.");
let targetWindow = aWindow || window;
let targetBrowser = targetWindow.gBrowser;
targetBrowser.removeTab(aTab);
}
function initNetMonitor(aUrl, aWindow) {
info("Initializing a network monitor pane.");
return addTab(aUrl).then((aTab) => {
info("Net tab added successfully: " + aUrl);
let deferred = Promise.defer();
let debuggee = aTab.linkedBrowser.contentWindow.wrappedJSObject;
let target = TargetFactory.forTab(aTab);
gDevTools.showToolbox(target, "netmonitor").then((aToolbox) => {
info("Netork monitor pane shown successfully.");
let monitor = aToolbox.getCurrentPanel();
deferred.resolve([aTab, debuggee, monitor]);
});
return deferred.promise;
});
}
function restartNetMonitor(aMonitor, aNewUrl) {
info("Restarting the specified network monitor.");
let deferred = Promise.defer();
let tab = aMonitor.target.tab;
let url = aNewUrl || tab.linkedBrowser.contentWindow.wrappedJSObject.location.href;
aMonitor.once("destroyed", () => initNetMonitor(url).then(deferred.resolve));
removeTab(tab);
return deferred.promise;
}
function teardown(aMonitor) {
info("Destroying the specified network monitor.");
let deferred = Promise.defer();
let tab = aMonitor.target.tab;
aMonitor.once("destroyed", deferred.resolve);
removeTab(tab);
return deferred.promise;
}
function waitForNetworkEvents(aMonitor, aGetRequests, aPostRequests = 0) {
let deferred = Promise.defer();
let panel = aMonitor.panelWin;
let genericEvents = 0;
let postEvents = 0;
function onGenericEvent() {
genericEvents++;
maybeResolve();
}
function onPostEvent() {
postEvents++;
maybeResolve();
}
function maybeResolve() {
info("> Network events progress: " +
genericEvents + "/" + ((aGetRequests + aPostRequests) * 13) + ", " +
postEvents + "/" + (aPostRequests * 2));
// There are 15 updates which need to be fired for a request to be
// considered finished. RequestPostData isn't fired for non-POST requests.
if (genericEvents == (aGetRequests + aPostRequests) * 13 &&
postEvents == aPostRequests * 2) {
panel.off("NetMonitor:NetworkEventUpdating:RequestHeaders", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdated:RequestHeaders", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdating:RequestCookies", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdating:RequestPostData", onPostEvent);
panel.off("NetMonitor:NetworkEventUpdated:RequestPostData", onPostEvent);
panel.off("NetMonitor:NetworkEventUpdated:RequestCookies", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdating:ResponseHeaders", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdated:ResponseHeaders", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdating:ResponseCookies", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdated:ResponseCookies", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdating:ResponseStart", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdating:ResponseContent", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdated:ResponseContent", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdating:EventTimings", onGenericEvent);
panel.off("NetMonitor:NetworkEventUpdated:EventTimings", onGenericEvent);
executeSoon(deferred.resolve);
}
}
panel.on("NetMonitor:NetworkEventUpdating:RequestHeaders", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdated:RequestHeaders", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdating:RequestCookies", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdating:RequestPostData", onPostEvent);
panel.on("NetMonitor:NetworkEventUpdated:RequestPostData", onPostEvent);
panel.on("NetMonitor:NetworkEventUpdated:RequestCookies", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdating:ResponseHeaders", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdated:ResponseHeaders", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdating:ResponseCookies", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdated:ResponseCookies", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdating:ResponseStart", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdating:ResponseContent", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdated:ResponseContent", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdating:EventTimings", onGenericEvent);
panel.on("NetMonitor:NetworkEventUpdated:EventTimings", onGenericEvent);
return deferred.promise;
}
function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
info("> Verifying: " + aMethod + " " + aUrl + " " + aData.toSource());
info("> Request: " + aRequestItem.attachment.toSource());
let { status, type, size, time } = aData;
let { attachment, target } = aRequestItem
let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
let name = uri.fileName || "/";
let query = uri.query;
let hostPort = uri.hostPort;
is(attachment.method, aMethod,
"The attached method is incorrect.");
is(attachment.url, aUrl,
"The attached url is incorrect.");
is(target.querySelector(".requests-menu-method").getAttribute("value"),
aMethod, "The displayed method is incorrect.");
is(target.querySelector(".requests-menu-file").getAttribute("value"),
name + (query ? "?" + query : ""), "The displayed file is incorrect.");
is(target.querySelector(".requests-menu-domain").getAttribute("value"),
hostPort, "The displayed domain is incorrect.");
if (status !== undefined) {
let value = target.querySelector(".requests-menu-status").getAttribute("code");
info("Displayed status: " + value);
is(value, status, "The displayed status is incorrect.");
}
if (type !== undefined) {
let value = target.querySelector(".requests-menu-type").getAttribute("value");
info("Displayed type: " + value);
is(value, type, "The displayed type is incorrect.");
}
if (size !== undefined) {
let value = target.querySelector(".requests-menu-size").getAttribute("value");
info("Displayed size: " + value);
is(value, size, "The displayed size is incorrect.");
}
if (time !== undefined) {
let value = target.querySelector(".requests-menu-timings-total").getAttribute("value");
info("Displayed time: " + value);
ok(~~(value.match(/[0-9]+/)) >= 0, "The displayed time is incorrect.");
}
}

Просмотреть файл

@ -0,0 +1,43 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
</head>
<body>
<p>Content type test</p>
<script type="text/javascript">
function get(aAddress, aCallback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", aAddress, true);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
aCallback();
}
};
xhr.send(null);
}
function performRequests() {
get("sjs_content-type-test-server.sjs?fmt=xml", function() {
get("sjs_content-type-test-server.sjs?fmt=css", function() {
get("sjs_content-type-test-server.sjs?fmt=js", function() {
get("sjs_content-type-test-server.sjs?fmt=json", function() {
get("sjs_content-type-test-server.sjs?fmt=bogus", function() {
get("test-image.png", function() {
// Done.
});
});
});
});
});
});
}
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
</head>
<body>
<p>Navigation test</p>
</body>
</html>

Просмотреть файл

@ -0,0 +1,72 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
<style>
input {
display: block;
margin: 12px;
}
</style>
</head>
<body>
<p>POST data test</p>
<form enctype="multipart/form-data" method="post" name="form-name">
<input type="text" name="text" placeholder="text" value="Some text..."/>
<input type="email" name="email" placeholder="email"/>
<input type="range" name="range" value="42"/>
<input type="button" value="Post me!" onclick="window.form()">
</form>
<script type="text/javascript">
function post(aAddress, aMessage, aCallback) {
var xhr = new XMLHttpRequest();
xhr.open("POST", aAddress, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var data = "";
for (var i in aMessage) {
data += "&" + i + "=" + aMessage[i];
}
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
aCallback();
}
};
xhr.send(data);
}
function form(aAddress, aForm, aCallback) {
var formData = new FormData(document.forms.namedItem(aForm));
formData.append("Custom field", "Extra data");
var xhr = new XMLHttpRequest();
xhr.open("POST", aAddress, true);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
aCallback();
}
};
xhr.send(formData);
}
function performRequests() {
var url = "sjs_simple-test-server.sjs";
var url1 = url + "?foo=bar&baz=42&type=urlencoded";
var url2 = url + "?foo=bar&baz=42&type=multipart";
post(url1, { foo: "bar", baz: 123 }, function() {
form(url2, "form-name", function() {
// Done.
});
});
}
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
</head>
<body>
<p>Simple test</p>
</body>
</html>

Просмотреть файл

@ -0,0 +1,41 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
</head>
<body>
<p>Status codes test</p>
<script type="text/javascript">
function get(aAddress, aCallback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", aAddress, true);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
aCallback();
}
};
xhr.send(null);
}
function performRequests() {
get("sjs_status-codes-test-server.sjs?sts=100", function() {
get("sjs_status-codes-test-server.sjs?sts=200", function() {
get("sjs_status-codes-test-server.sjs?sts=300", function() {
get("sjs_status-codes-test-server.sjs?sts=400", function() {
get("sjs_status-codes-test-server.sjs?sts=500", function() {
// Done.
});
});
});
});
});
}
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,5 @@
# vim: set filetype=python:
# 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/.

Просмотреть файл

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const { classes: Cc, interfaces: Ci } = Components;
function handleRequest(request, response) {
response.processAsync();
let params = request.queryString.split("&");
let format = params.filter((s) => s.contains("fmt="))[0].split("=")[1];
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).initWithCallback(() => {
switch (format) {
case "xml":
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/xml; charset=utf-8", false);
response.write("<label value='greeting'>Hello XML!</label>");
response.finish();
break;
case "css":
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/css; charset=utf-8", false);
response.write("body:pre { content: 'Hello CSS!' }");
response.finish();
break;
case "js":
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "application/javascript; charset=utf-8", false);
response.write("function() { return 'Hello JS!'; }");
response.finish();
break;
case "json":
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "application/json; charset=utf-8", false);
response.write("{ \"greeting\": \"Hello JSON!\" }");
response.finish();
break;
default:
response.setStatusLine(request.httpVersion, 404, "Not Found");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write("<blink>Not Found</blink>");
response.finish();
break;
}
}, 10, Ci.nsITimer.TYPE_ONE_SHOT); // Make sure this request takes a few ms.
}

Просмотреть файл

@ -0,0 +1,9 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function handleRequest(request, response) {
response.setStatusLine(request.httpVersion, 200, "Och Aye");
response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
response.setHeader("Foo-Bar", "baz", false);
response.write("Hello world!");
}

Просмотреть файл

@ -0,0 +1,27 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function handleRequest(request, response) {
let params = request.queryString.split("&");
let status = params.filter((s) => s.contains("sts="))[0].split("=")[1];
switch (status) {
case "100":
response.setStatusLine(request.httpVersion, 101, "Switching Protocols");
break;
case "200":
response.setStatusLine(request.httpVersion, 202, "Created");
break;
case "300":
response.setStatusLine(request.httpVersion, 303, "See Other");
break;
case "400":
response.setStatusLine(request.httpVersion, 404, "Not Found");
break;
case "500":
response.setStatusLine(request.httpVersion, 501, "Not Implemented");
break;
}
response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
response.write("Hello status code " + status + "!");
}

Двоичные данные
browser/devtools/netmonitor/test/test-image.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 580 B

Просмотреть файл

@ -90,7 +90,7 @@ Parser.prototype = {
* Clears all the parsed sources from cache.
*/
clearCache: function P_clearCache() {
this._cache = new Map();
this._cache.clear();
},
_cache: null

Просмотреть файл

@ -81,6 +81,7 @@ SideMenuWidget.prototype = {
*/
insertItemAt: function SMW_insertItemAt(aIndex, aContents, aTooltip = "", aGroup = "") {
this.ensureSelectionIsVisible(true, true); // Don't worry, it's delayed.
let group = this._getGroupForName(aGroup);
return group.insertItemAt(aIndex, aContents, aTooltip);
},
@ -126,7 +127,7 @@ SideMenuWidget.prototype = {
}
this._selectedItem = null;
this._groupsByName = new Map();
this._groupsByName.clear();
this._orderedGroupElementsArray.length = 0;
this._orderedMenuElementsArray.length = 0;
},
@ -404,6 +405,9 @@ SideMenuGroup.prototype = {
let menuArray = this._menuElementsArray;
let item = new SideMenuItem(this, aContents, aTooltip);
// Invalidate any notices set on the owner widget.
this.ownerView.removeAttribute("notice");
if (aIndex >= 0) {
list.insertBefore(item._container, list.childNodes[aIndex]);
menuArray.splice(aIndex, 0, item._target);
@ -411,6 +415,7 @@ SideMenuGroup.prototype = {
list.appendChild(item._container);
menuArray.push(item._target);
}
return item._target;
},

Просмотреть файл

@ -9,6 +9,7 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
const LAZY_EMPTY_DELAY = 150; // ms
const LAZY_EXPAND_DELAY = 50; // ms
const LAZY_APPEND_DELAY = 100; // ms
const LAZY_APPEND_BATCH = 100; // nodes
@ -20,8 +21,11 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
XPCOMUtils.defineLazyModuleGetter(this,
"WebConsoleUtils", "resource://gre/modules/devtools/WebConsoleUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
"resource://gre/modules/devtools/NetworkHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
this.EXPORTED_SYMBOLS = ["VariablesView"];
@ -42,8 +46,11 @@ const STR = Services.strings.createBundle(DBG_STRINGS_URI);
*
* @param nsIDOMNode aParentNode
* The parent node to hold this view.
* @param object aFlags [optional]
* An object contaning initialization options for this view.
* e.g. { lazyEmpty: true, searchEnabled: true ... }
*/
this.VariablesView = function VariablesView(aParentNode) {
this.VariablesView = function VariablesView(aParentNode, aFlags = {}) {
this._store = new Map();
this._itemsByElement = new WeakMap();
this._prevHierarchy = new Map();
@ -63,6 +70,10 @@ this.VariablesView = function VariablesView(aParentNode) {
this._list.addEventListener("keypress", this._onViewKeyPress, false);
this._parent.appendChild(this._list);
this._boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
for (let name in aFlags) {
this[name] = aFlags[name];
}
};
VariablesView.prototype = {
@ -123,8 +134,8 @@ VariablesView.prototype = {
list.removeChild(firstChild);
}
this._store = new Map();
this._itemsByElement = new WeakMap();
this._store.clear();
this._itemsByElement.clear();
this._appendEmptyNotice();
this._toggleSearchVisibility(false);
@ -149,8 +160,8 @@ VariablesView.prototype = {
let prevList = this._list;
let currList = this._list = this.document.createElement("scrollbox");
this._store = new Map();
this._itemsByElement = new WeakMap();
this._store.clear();
this._itemsByElement.clear();
this._emptyTimeout = this.window.setTimeout(function() {
this._emptyTimeout = null;
@ -173,7 +184,7 @@ VariablesView.prototype = {
/**
* The amount of time (in milliseconds) it takes to empty this view lazily.
*/
lazyEmptyDelay: 150,
lazyEmptyDelay: LAZY_EMPTY_DELAY,
/**
* Specifies if this view may be emptied lazily.
@ -214,6 +225,12 @@ VariablesView.prototype = {
*/
delete: null,
/**
* Specifies if after an eval or switch operation, the variable or property
* which has been edited should be disabled.
*/
preventDisableOnChage: false,
/**
* The tooltip text shown on a variable or property's value if an |eval|
* function is provided, in order to change the variable or property's value.
@ -1083,11 +1100,13 @@ Scope.prototype = {
* - { value: { type: "object", class: "Object" } }
* - { get: { type: "object", class: "Function" },
* set: { type: "undefined" } }
* @param boolean aRelaxed
* True if name duplicates should be allowed.
* @return Variable
* The newly created Variable instance, null if it already exists.
*/
addVar: function S_addVar(aName = "", aDescriptor = {}) {
if (this._store.has(aName)) {
addVar: function S_addVar(aName = "", aDescriptor = {}, aRelaxed = false) {
if (this._store.has(aName) && !aRelaxed) {
return null;
}
@ -1855,11 +1874,13 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
* - { value: { type: "object", class: "Object" } }
* - { get: { type: "object", class: "Function" },
* set: { type: "undefined" } }
* @param boolean aRelaxed
* True if name duplicates should be allowed.
* @return Property
* The newly created Property instance, null if it already exists.
*/
addProperty: function V_addProperty(aName = "", aDescriptor = {}) {
if (this._store.has(aName)) {
addProperty: function V_addProperty(aName = "", aDescriptor = {}, aRelaxed = false) {
if (this._store.has(aName) && !aRelaxed) {
return null;
}
@ -1918,6 +1939,7 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
* @param object aOptions [optional]
* Additional options for adding the properties. Supported options:
* - sorted: true to sort all the properties before adding them
* - expanded: true to expand all the properties after adding them
*/
populate: function V_populate(aObject, aOptions = {}) {
// Retrieve the properties only once.
@ -1937,9 +1959,15 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
for (let name of propertyNames) {
let descriptor = Object.getOwnPropertyDescriptor(aObject, name);
if (descriptor.get || descriptor.set) {
this._addRawNonValueProperty(name, descriptor);
let prop = this._addRawNonValueProperty(name, descriptor);
if (aOptions.expanded) {
prop.expanded = true;
}
} else {
this._addRawValueProperty(name, descriptor, aObject[name]);
let prop = this._addRawValueProperty(name, descriptor, aObject[name]);
if (aOptions.expanded) {
prop.expanded = true;
}
}
}
// Add the variable's __proto__.
@ -1972,6 +2000,8 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
* Object.getOwnPropertyDescriptor.
* @param object aValue
* The raw property value you want to display.
* @return Property
* The newly added property instance.
*/
_addRawValueProperty: function V__addRawValueProperty(aName, aDescriptor, aValue) {
let descriptor = Object.create(aDescriptor);
@ -1985,6 +2015,7 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
if (!VariablesView.isPrimitive(descriptor)) {
propertyItem.onexpand = this._populateTarget;
}
return propertyItem;
},
/**
@ -1995,13 +2026,15 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
* @param object aDescriptor
* Specifies the exact property descriptor as returned by a call to
* Object.getOwnPropertyDescriptor.
* @return Property
* The newly added property instance.
*/
_addRawNonValueProperty: function V__addRawNonValueProperty(aName, aDescriptor) {
let descriptor = Object.create(aDescriptor);
descriptor.get = VariablesView.getGrip(aDescriptor.get);
descriptor.set = VariablesView.getGrip(aDescriptor.set);
this.addProperty(aName, descriptor);
return this.addProperty(aName, descriptor);
},
/**
@ -2048,7 +2081,7 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
*/
setGrip: function V_setGrip(aGrip) {
// Don't allow displaying grip information if there's no name available.
if (!this._nameString) {
if (!this._nameString || aGrip === undefined || aGrip === null) {
return;
}
// Getters and setters should display grip information in sub-properties.
@ -2057,11 +2090,9 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
return;
}
if (aGrip === undefined) {
aGrip = { type: "undefined" };
}
if (aGrip === null) {
aGrip = { type: "null" };
// Make sure the value is escaped unicode if it's a string.
if (typeof aGrip == "string") {
aGrip = NetworkHelper.convertToUnicode(unescape(aGrip));
}
let prevGrip = this._valueGrip;
@ -2256,13 +2287,13 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
if (this.ownerView.eval) {
this._target.setAttribute("editable", "");
}
if (!descriptor.configurable) {
if (!descriptor.null && !descriptor.configurable) {
this._target.setAttribute("non-configurable", "");
}
if (!descriptor.enumerable) {
if (!descriptor.null && !descriptor.enumerable) {
this._target.setAttribute("non-enumerable", "");
}
if (!descriptor.writable && !this.ownerView.getter && !this.ownerView.setter) {
if (!descriptor.null && !descriptor.writable && !this.ownerView.getter && !this.ownerView.setter) {
this._target.setAttribute("non-writable", "");
}
if (name == "this") {
@ -2341,6 +2372,8 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
*/
_deactivateInput: function V__deactivateInput(aLabel, aInput, aCallbacks) {
aInput.parentNode.replaceChild(aLabel, aInput);
this._variablesView._boxObject.scrollBy(-this._target.clientWidth, 0);
aInput.removeEventListener("keypress", aCallbacks.onKeypress, false);
aInput.removeEventListener("blur", aCallbacks.onBlur, false);
@ -2454,8 +2487,10 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
this._deactivateNameInput(e);
if (initialString != currentString) {
this._disable();
this._name.value = currentString;
if (!this._variablesView.preventDisableOnChage) {
this._disable();
this._name.value = currentString;
}
this.ownerView.switch(this, currentString);
}
},
@ -2470,7 +2505,9 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
this._deactivateValueInput(e);
if (initialString != currentString) {
this._disable();
if (!this._variablesView.preventDisableOnChage) {
this._disable();
}
this.ownerView.eval(this.evaluationMacro(this, currentString.trim()));
}
},
@ -2635,8 +2672,8 @@ Property.prototype.__iterator__ = function VV_iterator() {
* @see VariablesView.createHierarchy
*/
VariablesView.prototype.clearHierarchy = function VV_clearHierarchy() {
this._prevHierarchy = new Map();
this._currHierarchy = new Map();
this._prevHierarchy.clear();
this._currHierarchy.clear();
};
/**
@ -2645,7 +2682,7 @@ VariablesView.prototype.clearHierarchy = function VV_clearHierarchy() {
*/
VariablesView.prototype.createHierarchy = function VV_createHierarchy() {
this._prevHierarchy = this._currHierarchy;
this._currHierarchy = new Map();
this._currHierarchy = new Map(); // Don't clear, this is just simple swapping.
};
/**

Просмотреть файл

@ -5,9 +5,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const PANE_APPEARANCE_DELAY = 50;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
this.EXPORTED_SYMBOLS = ["ViewHelpers", "MenuItem", "MenuContainer"];
/**
@ -69,7 +75,7 @@ this.ViewHelpers = {
* @param nsIDOMNode aNode
* A node to delegate the methods to.
*/
delegateWidgetAttributeMethods: function MC_delegateWidgetAttributeMethods(aWidget, aNode) {
delegateWidgetAttributeMethods: function VH_delegateWidgetAttributeMethods(aWidget, aNode) {
aWidget.getAttribute = aNode.getAttribute.bind(aNode);
aWidget.setAttribute = aNode.setAttribute.bind(aNode);
aWidget.removeAttribute = aNode.removeAttribute.bind(aNode);
@ -84,9 +90,185 @@ this.ViewHelpers = {
* @param nsIDOMNode aNode
* A node to delegate the methods to.
*/
delegateWidgetEventMethods: function MC_delegateWidgetEventMethods(aWidget, aNode) {
delegateWidgetEventMethods: function VH_delegateWidgetEventMethods(aWidget, aNode) {
aWidget.addEventListener = aNode.addEventListener.bind(aNode);
aWidget.removeEventListener = aNode.removeEventListener.bind(aNode);
},
/**
* Sets a side pane hidden or visible.
*
* @param object aFlags
* An object containing some of the following properties:
* - visible: true if the pane should be shown, false to hide
* - animated: true to display an animation on toggle
* - delayed: true to wait a few cycles before toggle
* - callback: a function to invoke when the toggle finishes
* @param nsIDOMNode aPane
* The element representing the pane to toggle.
*/
togglePane: function VH_togglePane(aFlags, aPane) {
// Avoid useless toggles.
if (aFlags.visible == !aPane.hasAttribute("pane-collapsed")) {
if (aFlags.callback) aFlags.callback();
return;
}
// Computes and sets the pane margins in order to hide or show it.
function set() {
if (aFlags.visible) {
aPane.style.marginLeft = "0";
aPane.style.marginRight = "0";
aPane.removeAttribute("pane-collapsed");
} else {
let margin = ~~(aPane.getAttribute("width")) + 1;
aPane.style.marginLeft = -margin + "px";
aPane.style.marginRight = -margin + "px";
aPane.setAttribute("pane-collapsed", "");
}
// Invoke the callback when the transition ended.
if (aFlags.animated) {
aPane.addEventListener("transitionend", function onEvent() {
aPane.removeEventListener("transitionend", onEvent, false);
if (aFlags.callback) aFlags.callback();
}, false);
}
// Invoke the callback immediately since there's no transition.
else {
if (aFlags.callback) aFlags.callback();
}
}
// Add a class to the pane to handle min-widths, margins and animations.
if (!aPane.classList.contains("generic-toggled-side-pane")) {
aPane.classList.add("generic-toggled-side-pane");
}
// Hiding is always handled via margins, not the hidden attribute.
aPane.removeAttribute("hidden");
// The "animated" attributes enables animated toggles (slide in-out).
if (aFlags.animated) {
aPane.setAttribute("animated", "");
} else {
aPane.removeAttribute("animated");
}
// Sometimes it's useful delaying the toggle a few ticks to ensure
// a smoother slide in-out animation.
if (aFlags.delayed) {
aPane.ownerDocument.defaultView.setTimeout(set.bind(this), PANE_APPEARANCE_DELAY);
} else {
set.call(this);
}
}
};
/**
* Localization convenience methods.
*
* @param string aStringBundleName
* The desired string bundle's name.
*/
ViewHelpers.L10N = function L10N(aStringBundleName) {
XPCOMUtils.defineLazyGetter(this, "stringBundle", () =>
Services.strings.createBundle(aStringBundleName));
XPCOMUtils.defineLazyGetter(this, "ellipsis", () =>
Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data);
};
ViewHelpers.L10N.prototype = {
stringBundle: null,
/**
* L10N shortcut function.
*
* @param string aName
* @return string
*/
getStr: function L10N_getStr(aName) {
return this.stringBundle.GetStringFromName(aName);
},
/**
* L10N shortcut function.
*
* @param string aName
* @param array aArgs
* @return string
*/
getFormatStr: function L10N_getFormatStr(aName, ...aArgs) {
return this.stringBundle.formatStringFromName(aName, aArgs, aArgs.length);
}
};
/**
* Shortcuts for lazily accessing and setting various preferences.
* Usage:
* let prefs = new ViewHelpers.Prefs("root.path.to.branch", {
* myIntPref: ["Int", "leaf.path.to.my-int-pref"],
* myCharPref: ["Char", "leaf.path.to.my-char-pref"],
* ...
* });
*
* prefs.myCharPref = "foo";
* let aux = prefs.myCharPref;
*
* @param string aPrefsRoot
* The root path to the required preferences branch.
* @param object aPrefsObject
* An object containing { accessorName: [prefType, prefName] } keys.
*/
ViewHelpers.Prefs = function Prefs(aPrefsRoot = "", aPrefsObject = {}) {
this.root = aPrefsRoot;
for (let accessorName in aPrefsObject) {
let [prefType, prefName] = aPrefsObject[accessorName];
this.map(accessorName, prefType, prefName);
}
};
ViewHelpers.Prefs.prototype = {
/**
* Helper method for getting a pref value.
*
* @param string aType
* @param string aPrefName
* @return any
*/
_get: function P__get(aType, aPrefName) {
if (this[aPrefName] === undefined) {
this[aPrefName] = Services.prefs["get" + aType + "Pref"](aPrefName);
}
return this[aPrefName];
},
/**
* Helper method for setting a pref value.
*
* @param string aType
* @param string aPrefName
* @param any aValue
*/
_set: function P__set(aType, aPrefName, aValue) {
Services.prefs["set" + aType + "Pref"](aPrefName, aValue);
this[aPrefName] = aValue;
},
/**
* Maps a property name to a pref, defining lazy getters and setters.
*
* @param string aAccessorName
* @param string aType
* @param string aPrefName
*/
map: function P_map(aAccessorName, aType, aPrefName) {
Object.defineProperty(this, aAccessorName, {
get: () => this._get(aType, [this.root, aPrefName].join(".")),
set: (aValue) => this._set(aType, [this.root, aPrefName].join("."), aValue)
});
}
};
@ -219,7 +401,7 @@ MenuItem.prototype = {
*/
_entangleItem: function MI__entangleItem(aItem, aElement) {
if (!this._itemsByElement) {
this._itemsByElement = new Map();
this._itemsByElement = new Map(); // This needs to be iterable.
}
this._itemsByElement.set(aElement, aItem);
@ -249,7 +431,13 @@ MenuItem.prototype = {
* @return string
*/
toString: function MI_toString() {
return this._label + " -> " + this._value;
if (this._label && this._value) {
return this._label + " -> " + this._value;
}
if (this.attachment) {
return this.attachment.toString();
}
return "(null)";
},
_label: "",
@ -345,7 +533,7 @@ MenuContainer.prototype = {
aContents instanceof Ci.nsIDOMElement) {
// Allow the insertion of prebuilt nodes.
aOptions.node = aContents;
aContents = [];
aContents = ["", "", ""];
}
let [label, value, description] = aContents;
@ -435,9 +623,9 @@ MenuContainer.prototype = {
this._untangleItem(item);
}
this._itemsByLabel = new Map();
this._itemsByValue = new Map();
this._itemsByElement = new Map();
this._itemsByLabel.clear();
this._itemsByValue.clear();
this._itemsByElement.clear();
this._stagedItems.length = 0;
},
@ -517,7 +705,7 @@ MenuContainer.prototype = {
if (selectedElement) {
return this._itemsByElement.get(selectedElement);
}
return -1;
return null;
},
/**

Просмотреть файл

@ -0,0 +1,130 @@
<!-- 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/. -->
<!-- LOCALIZATION NOTE : FILE This file contains the Network Monitor strings -->
<!-- LOCALIZATION NOTE : FILE Do not translate commandkey -->
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
- keep it in English, or another language commonly spoken among web developers.
- You want to make that choice consistent across the developer tools.
- A good criteria is the language in which you'd find the best
- documentation on web development on the web. -->
<!-- LOCALIZATION NOTE (netmonitorUI.emptyNotice): This is the label displayed
- in the network table when empty. -->
<!ENTITY netmonitorUI.emptyNotice "Reload the page to see detailed information about network activity.">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.method): This is the label displayed
- in the network table toolbar, above the "method" column. -->
<!ENTITY netmonitorUI.toolbar.method "Method">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.file): This is the label displayed
- in the network table toolbar, above the "file" column. -->
<!ENTITY netmonitorUI.toolbar.file "File">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.domain): This is the label displayed
- in the network table toolbar, above the "domain" column. -->
<!ENTITY netmonitorUI.toolbar.domain "Domain">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.type): This is the label displayed
- in the network table toolbar, above the "type" column. -->
<!ENTITY netmonitorUI.toolbar.type "Type">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.size): This is the label displayed
- in the network table toolbar, above the "size" column. -->
<!ENTITY netmonitorUI.toolbar.size "Size">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.waterfall): This is the label displayed
- in the network table toolbar, above the "waterfall" column. -->
<!ENTITY netmonitorUI.toolbar.waterfall "Timeline">
<!-- LOCALIZATION NOTE (debuggerUI.tab.headers): This is the label displayed
- in the network details pane identifying the headers tab. -->
<!ENTITY netmonitorUI.tab.headers "Headers">
<!-- LOCALIZATION NOTE (debuggerUI.tab.cookies): This is the label displayed
- in the network details pane identifying the cookies tab. -->
<!ENTITY netmonitorUI.tab.cookies "Cookies">
<!-- LOCALIZATION NOTE (debuggerUI.tab.params): This is the label displayed
- in the network details pane identifying the params tab. -->
<!ENTITY netmonitorUI.tab.params "Params">
<!-- LOCALIZATION NOTE (debuggerUI.tab.response): This is the label displayed
- in the network details pane identifying the response tab. -->
<!ENTITY netmonitorUI.tab.response "Response">
<!-- LOCALIZATION NOTE (debuggerUI.tab.timings): This is the label displayed
- in the network details pane identifying the timings tab. -->
<!ENTITY netmonitorUI.tab.timings "Timings">
<!-- LOCALIZATION NOTE (debuggerUI.panesButton.tooltip): This is the tooltip for
- the button that toggles the panes visible or hidden in the netmonitor UI. -->
<!ENTITY netmonitorUI.panesButton.tooltip "Toggle network info">
<!-- LOCALIZATION NOTE (debuggerUI.summary.url): This is the label displayed
- in the network details headers tab identifying the URL. -->
<!ENTITY netmonitorUI.summary.url "Request URL:">
<!-- LOCALIZATION NOTE (debuggerUI.summary.method): This is the label displayed
- in the network details headers tab identifying the method. -->
<!ENTITY netmonitorUI.summary.method "Request method:">
<!-- LOCALIZATION NOTE (debuggerUI.summary.status): This is the label displayed
- in the network details headers tab identifying the status code. -->
<!ENTITY netmonitorUI.summary.status "Status code:">
<!-- LOCALIZATION NOTE (debuggerUI.summary.version): This is the label displayed
- in the network details headers tab identifying the http version. -->
<!ENTITY netmonitorUI.summary.version "Version:">
<!-- LOCALIZATION NOTE (debuggerUI.summary.size): This is the label displayed
- in the network details headers tab identifying the headers size. -->
<!ENTITY netmonitorUI.summary.size "Headers size:">
<!-- LOCALIZATION NOTE (debuggerUI.response.name): This is the label displayed
- in the network details response tab identifying an image's file name. -->
<!ENTITY netmonitorUI.response.name "Name:">
<!-- LOCALIZATION NOTE (debuggerUI.response.dimensions): This is the label displayed
- in the network details response tab identifying an image's dimensions. -->
<!ENTITY netmonitorUI.response.dimensions "Dimensions:">
<!-- LOCALIZATION NOTE (debuggerUI.response.mime): This is the label displayed
- in the network details response tab identifying an image's mime. -->
<!ENTITY netmonitorUI.response.mime "MIME Type:">
<!-- LOCALIZATION NOTE (debuggerUI.response.encoding): This is the label displayed
- in the network details response tab identifying an image's encoding. -->
<!ENTITY netmonitorUI.response.encoding "Encoding:">
<!-- LOCALIZATION NOTE (debuggerUI.timings.blocked): This is the label displayed
- in the network details timings tab identifying the amount of time spent
- in a "blocked" state. -->
<!ENTITY netmonitorUI.timings.blocked "Blocked:">
<!-- LOCALIZATION NOTE (debuggerUI.timings.dns): This is the label displayed
- in the network details timings tab identifying the amount of time spent
- in a "dns" state. -->
<!ENTITY netmonitorUI.timings.dns "DNS resolution:">
<!-- LOCALIZATION NOTE (debuggerUI.timings.connect): This is the label displayed
- in the network details timings tab identifying the amount of time spent
- in a "connect" state. -->
<!ENTITY netmonitorUI.timings.connect "Connecting:">
<!-- LOCALIZATION NOTE (debuggerUI.timings.send): This is the label displayed
- in the network details timings tab identifying the amount of time spent
- in a "send" state. -->
<!ENTITY netmonitorUI.timings.send "Sending:">
<!-- LOCALIZATION NOTE (debuggerUI.timings.wait): This is the label displayed
- in the network details timings tab identifying the amount of time spent
- in a "wait" state. -->
<!ENTITY netmonitorUI.timings.wait "Waiting:">
<!-- LOCALIZATION NOTE (debuggerUI.timings.receive): This is the label displayed
- in the network details timings tab identifying the amount of time spent
- in a "receive" state. -->
<!ENTITY netmonitorUI.timings.receive "Receiving:">

Просмотреть файл

@ -0,0 +1,98 @@
# 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/.
# LOCALIZATION NOTE These strings are used inside the Network Monitor
# which is available from the Web Developer sub-menu -> 'Network Monitor'.
# The correct localization of this file might be to keep it in
# English, or another language commonly spoken among web developers.
# You want to make that choice consistent across the developer tools.
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (netmonitor.label):
# This string is displayed in the title of the tab when the Network Monitor is
# displayed inside the developer tools window and in the Developer Tools Menu.
netmonitor.label=Network
# LOCALIZATION NOTE (netmonitor.commandkey, netmonitor.accesskey)
# Used for the menuitem in the tool menu
netmonitor.commandkey=Q
netmonitor.accesskey=N
# LOCALIZATION NOTE (netmonitor.tooltip):
# This string is displayed in the tooltip of the tab when the Network Monitor is
# displayed inside the developer tools window.
netmonitor.tooltip=Network Monitor
# LOCALIZATION NOTE (collapseDetailsPane): This is the tooltip for the button
# that collapses the network details pane in the UI.
collapseDetailsPane=Hide request details
# LOCALIZATION NOTE (expandDetailsPane): This is the tooltip for the button
# that expands the network details pane in the UI.
expandDetailsPane=Show request details
# LOCALIZATION NOTE (headersEmptyText): This is the text displayed in the
# headers tab of the network details pane when there are no headers available.
headersEmptyText=No headers for this request
# LOCALIZATION NOTE (headersFilterText): This is the text displayed in the
# headers tab of the network details pane for the filtering input.
headersFilterText=Filter headers
# LOCALIZATION NOTE (cookiesEmptyText): This is the text displayed in the
# cookies tab of the network details pane when there are no cookies available.
cookiesEmptyText=No cookies for this request
# LOCALIZATION NOTE (cookiesFilterText): This is the text displayed in the
# cookies tab of the network details pane for the filtering input.
cookiesFilterText=Filter cookies
# LOCALIZATION NOTE (paramsEmptyText): This is the text displayed in the
# params tab of the network details pane when there are no params available.
paramsEmptyText=No parameters for this request
# LOCALIZATION NOTE (paramsFilterText): This is the text displayed in the
# params tab of the network details pane for the filtering input.
paramsFilterText=Filter request parameters
# LOCALIZATION NOTE (paramsQueryString): This is the label displayed
# in the network details params tab identifying the query string.
paramsQueryString=Query string
# LOCALIZATION NOTE (paramsFormData): This is the label displayed
# in the network details params tab identifying the form data.
paramsFormData=Form data
# LOCALIZATION NOTE (paramsPostPayload): This is the label displayed
# in the network details params tab identifying the request payload.
paramsPostPayload=Request payload
# LOCALIZATION NOTE (requestHeaders): This is the label displayed
# in the network details headers tab identifying the request headers.
requestHeaders=Request headers
# LOCALIZATION NOTE (responseHeaders): This is the label displayed
# in the network details headers tab identifying the response headers.
responseHeaders=Response headers
# LOCALIZATION NOTE (requestCookies): This is the label displayed
# in the network details params tab identifying the request cookies.
requestCookies=Request cookies
# LOCALIZATION NOTE (responseCookies): This is the label displayed
# in the network details params tab identifying the response cookies.
responseCookies=Response cookies
# LOCALIZATION NOTE (jsonFilterText): This is the text displayed
# in the response tab of the network details pane for the JSON filtering input.
jsonFilterText=Filter properties
# LOCALIZATION NOTE (networkMenu.size): This is the label displayed
# in the network menu specifying the size of a request (in kb).
networkMenu.size=%Skb
# LOCALIZATION NOTE (networkMenu.total): This is the label displayed
# in the network menu specifying the time for a request to finish (in ms).
networkMenu.total=→ %Sms

Просмотреть файл

@ -24,6 +24,8 @@
locale/browser/browser.properties (%chrome/browser/browser.properties)
locale/browser/devtools/debugger.dtd (%chrome/browser/devtools/debugger.dtd)
locale/browser/devtools/debugger.properties (%chrome/browser/devtools/debugger.properties)
locale/browser/devtools/netmonitor.dtd (%chrome/browser/devtools/netmonitor.dtd)
locale/browser/devtools/netmonitor.properties (%chrome/browser/devtools/netmonitor.properties)
locale/browser/devtools/gcli.properties (%chrome/browser/devtools/gcli.properties)
locale/browser/devtools/gclicommands.properties (%chrome/browser/devtools/gclicommands.properties)
locale/browser/devtools/webconsole.properties (%chrome/browser/devtools/webconsole.properties)

Просмотреть файл

@ -256,7 +256,7 @@
.devtools-sidebar-tabs > tabs > tab {
-moz-appearance: none;
/* We want to match the height of a toolbar with a toolbarbutton
/* We want to match the height of a toolbar with a toolbarbutton
* First, we need to replicated the padding of toolbar (4px),
* then, the padding of the button itself from toolbarbutton.css (3px),
* Also, we need to take the border of the buttons into accout (1px).

Просмотреть файл

@ -17,20 +17,6 @@
-moz-border-start-color: transparent;
}
/* Watch expressions, variables and other instruments pane */
#instruments-pane {
min-width: 50px;
-moz-margin-start: 0px !important;
/* Unfortunately, transitions don't work properly with locale-aware properties,
so both the left and right margins are set via js, while the start margin
is always overridden here. */
}
#instruments-pane[animated] {
transition: margin 0.25s ease-in-out;
}
/* ListWidget items */
.list-widget-item {
@ -310,12 +296,12 @@
background: none;
box-shadow: none;
border: none;
list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
-moz-image-region: rect(0px,16px,16px,0px);
}
#instruments-pane-toggle:not([toggled]) {
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
#instruments-pane-toggle[pane-collapsed] {
list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
}
#instruments-pane-toggle:active {

Просмотреть файл

@ -0,0 +1,304 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/* Network requests table */
#body {
background: url(background-noise-toolbar.png), hsl(208,11%,27%);
}
.requests-menu-empty-notice {
background: url(background-noise-toolbar.png), hsl(208,11%,27%);
padding: 12px;
font-size: 110%;
color: #fff;
}
#requests-menu-toolbar {
-moz-padding-start: 4px;
}
.requests-menu-header {
text-align: center;
}
.requests-menu-subitem {
padding: 0 4px;
}
.requests-menu-header:not(:last-of-type),
.requests-menu-subitem:not(:last-child) {
-moz-border-end: 1px solid hsla(210,8%,5%,.25);
box-shadow: 1px 0 0 hsla(210,16%,76%,.1);
}
.requests-menu-status-and-method {
width: 6em;
}
.requests-menu-status {
background: #fff;
width: 10px;
height: 10px;
-moz-margin-start: 4px;
-moz-margin-end: 2px;
border-radius: 20px;
box-shadow:
0 0 0 1px rgba(255,255,255,0.4) inset,
0 -6px 4px 0 rgba(32,32,32,1.0) inset,
0 0 8px 0 rgba(32,0,0,0.4);
transition: box-shadow 0.5s ease-in-out;
}
.requests-menu-status[code^="1"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(0,0,64,1.0) inset,
0 0 8px 0 rgba(0,0,128,1.0);
}
.requests-menu-status[code^="2"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(0,64,0,1.0) inset,
0 0 8px 0 rgba(0,128,0,1.0);
}
.requests-menu-status[code^="3"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(64,32,0,1.0) inset,
0 0 8px 0 rgba(128,128,0,1.0);
}
.requests-menu-status[code^="4"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(64,0,0,1.0) inset,
0 0 8px 0 rgba(128,0,0,1.0);
}
.requests-menu-status[code^="5"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(64,0,64,1.0) inset,
0 0 8px 0 rgba(128,0,128,1.0);
}
.requests-menu-method {
text-align: center;
font-weight: 600;
}
.requests-menu-file {
width: 14em;
}
.requests-menu-domain {
width: 14em;
}
.requests-menu-type {
text-align: center;
width: 4em;
}
.requests-menu-size {
text-align: center;
width: 6em;
}
.requests-menu-header.requests-menu-waterfall {
-moz-padding-start: 8px;
-moz-padding-end: 8px;
text-align: center;
}
/* Network request waterfall */
.requests-menu-subitem.requests-menu-waterfall {
-moz-padding-start: 4px;
-moz-padding-end: 4px;
background-size: 5px;
background-image:
-moz-linear-gradient(left,
transparent 25%,
rgba(255,255,255,0.02) 25%,
rgba(255,255,255,0.02) 75%,
transparent 75%);
}
.requests-menu-timings {
transform-origin: left center;
}
.requests-menu-timings-total {
-moz-padding-start: 4px;
font-size: 85%;
font-weight: 600;
transform-origin: -4px center; /* negative cap size */
}
.requests-menu-timings-cap {
width: 4px;
height: 10px;
border: 1px solid #fff;
}
.requests-menu-timings-cap.start {
-moz-border-end: none;
border-radius: 4px 0 0 4px;
transform-origin: right center;
}
.requests-menu-timings-cap.end {
-moz-border-start: none;
border-radius: 0 4px 4px 0;
transform-origin: left center;
}
.requests-menu-timings-box {
height: 10px;
border-top: 1px solid #fff;
border-bottom: 1px solid #fff;
}
.requests-menu-timings-box.blocked,
.requests-menu-timings-cap.blocked {
background-color: rgba(255,32,32,0.8);
box-shadow: 0 0 8px 0 rgba(128,32,32,0.8),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.dns,
.requests-menu-timings-cap.dns {
background-color: rgba(255,128,255,0.6);
box-shadow: 0 0 8px 0 rgba(128,128,255,1.0),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.connect,
.requests-menu-timings-cap.connect {
background-color: rgba(255,128,16,0.4);
box-shadow: 0 0 8px 0 rgba(128,128,16,0.8),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.send,
.requests-menu-timings-cap.send {
background-color: rgba(255,255,128,0.4);
box-shadow: 0 0 8px 0 rgba(128,255,128,0.8),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.wait,
.requests-menu-timings-cap.wait {
background-color: rgba(255,255,255,0.2);
box-shadow: 0 0 8px 0 rgba(128,255,255,0.4),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.receive,
.requests-menu-timings-cap.receive {
background-color: rgba(255,255,255,1.0);
box-shadow: 0 0 8px 0 rgba(128,255,255,1.0),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.side-menu-widget-container,
.side-menu-widget-item-or-group {
box-shadow: none !important;
}
.side-menu-widget-item:nth-child(even) {
background: rgba(255,255,255,0.05);
}
/* Network request details */
#details-pane {
background: hsl(208,11%,27%);
max-width: 500px;
}
#details-pane-toggle {
background: none;
box-shadow: none;
border-color: transparent;
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
-moz-image-region: rect(0px,16px,16px,0px);
}
#details-pane-toggle[pane-collapsed] {
list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
}
#details-pane-toggle:active {
-moz-image-region: rect(0px,32px,16px,16px);
}
/* Network request details tabpanels */
.tabpanel-content {
background: url(background-noise-toolbar.png), #3e4750;
box-shadow: 0 1px 0 hsla(204,45%,98%,.05) inset;
color: #fff;
}
.tabpanel-summary-container {
padding: 1px;
}
.tabpanel-summary-label {
-moz-padding-start: 4px;
-moz-padding-end: 3px;
font-weight: 600;
text-shadow: 0 1px 0 #000;
color: hsl(210,30%,85%);
}
.tabpanel-summary-value {
-moz-padding-start: 3px;
font-family: Menlo, Monaco, monospace;
}
/* Headers tabpanel */
#headers-summary-status,
#headers-summary-version {
padding-bottom: 2px;
}
#headers-summary-size {
padding-top: 2px;
}
/* Response tabpanel */
#response-content-image-box {
padding-top: 10px;
padding-bottom: 10px;
}
#response-content-image {
background: #fff;
border: 1px dashed GrayText;
margin-bottom: 10px;
}
/* Timings tabpanel */
#timings-tabpanel .tabpanel-summary-label {
width: 10em;
}
#timings-tabpanel .requests-menu-timings-box {
transition: transform 0.2s ease-out;
min-width: 1px;
}
#timings-tabpanel .requests-menu-timings-total {
transition: transform 0.2s ease-out;
}

Просмотреть файл

@ -3,6 +3,20 @@
* 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/. */
/* Generic pane helpers */
.generic-toggled-side-pane {
min-width: 50px;
-moz-margin-start: 0px !important;
/* Unfortunately, transitions don't work properly with locale-aware properties,
so both the left and right margins are set via js, while the start margin
is always overridden here. */
}
.generic-toggled-side-pane[animated] {
transition: margin 0.25s ease-in-out;
}
/* BreacrumbsWidget */
.breadcrumbs-widget-container {
@ -298,7 +312,7 @@
}
.side-menu-widget-item.selected {
background: -moz-linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%)) repeat-x top left;
background: -moz-linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%)) repeat-x top left !important;
box-shadow: inset 0 1px 0 hsla(210,40%,83%,.15),
inset 0 -1px 0 hsla(210,40%,83%,.05);
border-top: 0;
@ -330,7 +344,7 @@
padding: 4px;
}
.side-menu-widget-item-label {
.side-menu-widget-item label {
cursor: inherit;
}
@ -360,7 +374,6 @@
}
.side-menu-widget-item-other > label {
cursor: inherit;
color: #f5f7fa;
text-shadow: 0 1px 1px #111;
}
@ -398,14 +411,15 @@
-moz-margin-end: 1px;
}
.variables-view-scope > .variables-view-element-details.nonenum:not(:empty) {
border-top: 1px solid #ddd;
.variables-view-scope > .variables-view-element-details.enum:not(:empty) {
border-bottom: 1px solid #ddd;
}
/* Generic traits applied to both variables and properties */
.variable-or-property {
transition: background 1s ease-in-out;
color: #000;
}
.variable-or-property[changed] {
@ -471,7 +485,6 @@
}
.variable-or-property:not(:focus) > .title > .token-string {
max-width: 30em;
color: #1c00cf;
}

Просмотреть файл

@ -165,6 +165,7 @@ browser.jar:
skin/classic/browser/devtools/splitview.css (devtools/splitview.css)
skin/classic/browser/devtools/styleeditor.css (devtools/styleeditor.css)
skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/browser/devtools/option-icon.png (devtools/option-icon.png)
skin/classic/browser/devtools/itemToggle.png (devtools/itemToggle.png)

Просмотреть файл

@ -269,7 +269,7 @@
.devtools-sidebar-tabs > tabs > tab {
-moz-appearance: none;
/* We want to match the height of a toolbar with a toolbarbutton
/* We want to match the height of a toolbar with a toolbarbutton
* First, we need to replicated the padding of toolbar (4px),
* then, the padding of the button itself from toolbarbutton.css (3px),
* Also, we need to take the border of the buttons into accout (1px).

Просмотреть файл

@ -19,20 +19,6 @@
-moz-border-start-color: transparent;
}
/* Watch expressions, variables and other instruments pane */
#instruments-pane {
min-width: 50px;
-moz-margin-start: 0px !important;
/* Unfortunately, transitions don't work properly with locale-aware properties,
so both the left and right margins are set via js, while the start margin
is always overridden here. */
}
#instruments-pane[animated] {
transition: margin 0.25s ease-in-out;
}
/* ListWidget items */
.list-widget-item {
@ -312,12 +298,12 @@
background: none;
box-shadow: none;
border: none;
list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
-moz-image-region: rect(0px,16px,16px,0px);
}
#instruments-pane-toggle:not([toggled]) {
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
#instruments-pane-toggle[pane-collapsed] {
list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
}
#instruments-pane-toggle:active {

Просмотреть файл

@ -0,0 +1,304 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/* Network requests table */
#body {
background: url(background-noise-toolbar.png), hsl(208,11%,27%);
}
.requests-menu-empty-notice {
background: url(background-noise-toolbar.png), hsl(208,11%,27%);
padding: 12px;
font-size: 110%;
color: #fff;
}
#requests-menu-toolbar {
-moz-padding-start: 4px;
}
.requests-menu-header {
text-align: center;
}
.requests-menu-subitem {
padding: 0 4px;
}
.requests-menu-header:not(:last-of-type),
.requests-menu-subitem:not(:last-child) {
-moz-border-end: 1px solid hsla(210,8%,5%,.25);
box-shadow: 1px 0 0 hsla(210,16%,76%,.1);
}
.requests-menu-status-and-method {
width: 8em;
}
.requests-menu-status {
background: #fff;
width: 10px;
height: 10px;
-moz-margin-start: 4px;
-moz-margin-end: 2px;
border-radius: 20px;
box-shadow:
0 0 0 1px rgba(255,255,255,0.4) inset,
0 -6px 4px 0 rgba(32,32,32,1.0) inset,
0 0 8px 0 rgba(32,0,0,0.4);
transition: box-shadow 0.5s ease-in-out;
}
.requests-menu-status[code^="1"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(0,0,64,1.0) inset,
0 0 8px 0 rgba(0,0,128,1.0);
}
.requests-menu-status[code^="2"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(0,64,0,1.0) inset,
0 0 8px 0 rgba(0,128,0,1.0);
}
.requests-menu-status[code^="3"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(64,32,0,1.0) inset,
0 0 8px 0 rgba(128,128,0,1.0);
}
.requests-menu-status[code^="4"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(64,0,0,1.0) inset,
0 0 8px 0 rgba(128,0,0,1.0);
}
.requests-menu-status[code^="5"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(64,0,64,1.0) inset,
0 0 8px 0 rgba(128,0,128,1.0);
}
.requests-menu-method {
text-align: center;
font-weight: 600;
}
.requests-menu-file {
width: 16em;
}
.requests-menu-domain {
width: 16em;
}
.requests-menu-type {
text-align: center;
width: 4em;
}
.requests-menu-size {
text-align: center;
width: 8em;
}
.requests-menu-header.requests-menu-waterfall {
-moz-padding-start: 8px;
-moz-padding-end: 8px;
text-align: center;
}
/* Network request waterfall */
.requests-menu-subitem.requests-menu-waterfall {
-moz-padding-start: 4px;
-moz-padding-end: 4px;
background-size: 5px;
background-image:
-moz-linear-gradient(left,
transparent 25%,
rgba(255,255,255,0.02) 25%,
rgba(255,255,255,0.02) 75%,
transparent 75%);
}
.requests-menu-timings {
transform-origin: left center;
}
.requests-menu-timings-total {
-moz-padding-start: 4px;
font-size: 85%;
font-weight: 600;
transform-origin: -4px center; /* negative cap size */
}
.requests-menu-timings-cap {
width: 4px;
height: 10px;
border: 1px solid #fff;
}
.requests-menu-timings-cap.start {
-moz-border-end: none;
border-radius: 4px 0 0 4px;
transform-origin: right center;
}
.requests-menu-timings-cap.end {
-moz-border-start: none;
border-radius: 0 4px 4px 0;
transform-origin: left center;
}
.requests-menu-timings-box {
height: 10px;
border-top: 1px solid #fff;
border-bottom: 1px solid #fff;
}
.requests-menu-timings-box.blocked,
.requests-menu-timings-cap.blocked {
background-color: rgba(255,32,32,0.8);
box-shadow: 0 0 8px 0 rgba(128,32,32,0.8),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.dns,
.requests-menu-timings-cap.dns {
background-color: rgba(255,128,255,0.6);
box-shadow: 0 0 8px 0 rgba(128,128,255,1.0),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.connect,
.requests-menu-timings-cap.connect {
background-color: rgba(255,128,16,0.4);
box-shadow: 0 0 8px 0 rgba(128,128,16,0.8),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.send,
.requests-menu-timings-cap.send {
background-color: rgba(255,255,128,0.4);
box-shadow: 0 0 8px 0 rgba(128,255,128,0.8),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.wait,
.requests-menu-timings-cap.wait {
background-color: rgba(255,255,255,0.2);
box-shadow: 0 0 8px 0 rgba(128,255,255,0.4),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.receive,
.requests-menu-timings-cap.receive {
background-color: rgba(255,255,255,1.0);
box-shadow: 0 0 8px 0 rgba(128,255,255,1.0),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.side-menu-widget-container,
.side-menu-widget-item-or-group {
box-shadow: none !important;
}
.side-menu-widget-item:nth-child(even) {
background: rgba(255,255,255,0.05);
}
/* Network request details */
#details-pane {
background: hsl(208,11%,27%);
max-width: 500px;
}
#details-pane-toggle {
background: none;
box-shadow: none;
border-color: transparent;
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
-moz-image-region: rect(0px,16px,16px,0px);
}
#details-pane-toggle[pane-collapsed] {
list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
}
#details-pane-toggle:active {
-moz-image-region: rect(0px,32px,16px,16px);
}
/* Network request details tabpanels */
.tabpanel-content {
background: url(background-noise-toolbar.png), #3e4750;
box-shadow: 0 1px 0 hsla(204,45%,98%,.05) inset;
color: #fff;
}
.tabpanel-summary-container {
padding: 1px;
}
.tabpanel-summary-label {
-moz-padding-start: 4px;
-moz-padding-end: 3px;
font-weight: 600;
text-shadow: 0 1px 0 #000;
color: hsl(210,30%,85%);
}
.tabpanel-summary-value {
-moz-padding-start: 3px;
font-family: Menlo, Monaco, monospace;
}
/* Headers tabpanel */
#headers-summary-status,
#headers-summary-version {
padding-bottom: 2px;
}
#headers-summary-size {
padding-top: 2px;
}
/* Response tabpanel */
#response-content-image-box {
padding-top: 10px;
padding-bottom: 10px;
}
#response-content-image {
background: #fff;
border: 1px dashed GrayText;
margin-bottom: 10px;
}
/* Timings tabpanel */
#timings-tabpanel .tabpanel-summary-label {
width: 10em;
}
#timings-tabpanel .requests-menu-timings-box {
transition: transform 0.2s ease-out;
min-width: 1px;
}
#timings-tabpanel .requests-menu-timings-total {
transition: transform 0.2s ease-out;
}

Просмотреть файл

@ -3,6 +3,20 @@
* 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/. */
/* Generic pane helpers */
.generic-toggled-side-pane {
min-width: 50px;
-moz-margin-start: 0px !important;
/* Unfortunately, transitions don't work properly with locale-aware properties,
so both the left and right margins are set via js, while the start margin
is always overridden here. */
}
.generic-toggled-side-pane[animated] {
transition: margin 0.25s ease-in-out;
}
/* BreacrumbsWidget */
.breadcrumbs-widget-container {
@ -298,7 +312,7 @@
}
.side-menu-widget-item.selected {
background: -moz-linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%)) repeat-x top left;
background: -moz-linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%)) repeat-x top left !important;
box-shadow: inset 0 1px 0 hsla(210,40%,83%,.15),
inset 0 -1px 0 hsla(210,40%,83%,.05);
border-top: 0;
@ -330,7 +344,7 @@
padding: 4px;
}
.side-menu-widget-item-label {
.side-menu-widget-item label {
cursor: inherit;
}
@ -360,7 +374,6 @@
}
.side-menu-widget-item-other > label {
cursor: inherit;
color: #f5f7fa;
text-shadow: 0 1px 1px #111;
}
@ -398,14 +411,15 @@
-moz-margin-end: 1px;
}
.variables-view-scope > .variables-view-element-details.nonenum:not(:empty) {
border-top: 1px solid #ddd;
.variables-view-scope > .variables-view-element-details.enum:not(:empty) {
border-bottom: 1px solid #ddd;
}
/* Generic traits applied to both variables and properties */
.variable-or-property {
transition: background 1s ease-in-out;
color: #000;
}
.variable-or-property[changed] {
@ -471,7 +485,6 @@
}
.variable-or-property:not(:focus) > .title > .token-string {
max-width: 30em;
color: #1c00cf;
}

Просмотреть файл

@ -250,6 +250,7 @@ browser.jar:
skin/classic/browser/devtools/splitview.css (devtools/splitview.css)
skin/classic/browser/devtools/styleeditor.css (devtools/styleeditor.css)
* skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/browser/devtools/option-icon.png (devtools/option-icon.png)
skin/classic/browser/devtools/itemToggle.png (devtools/itemToggle.png)

Просмотреть файл

@ -276,7 +276,7 @@
.devtools-sidebar-tabs > tabs > tab {
-moz-appearance: none;
/* We want to match the height of a toolbar with a toolbarbutton
/* We want to match the height of a toolbar with a toolbarbutton
* First, we need to replicated the padding of toolbar (4px),
* then, the padding of the button itself from toolbarbutton.css (3px),
* Also, we need to take the border of the buttons into accout (1px).

Просмотреть файл

@ -17,20 +17,6 @@
-moz-border-start-color: transparent;
}
/* Watch expressions, variables and other instruments pane */
#instruments-pane {
min-width: 50px;
-moz-margin-start: 0px !important;
/* Unfortunately, transitions don't work properly with locale-aware properties,
so both the left and right margins are set via js, while the start margin
is always overridden here. */
}
#instruments-pane[animated] {
transition: margin 0.25s ease-in-out;
}
/* ListWidget items */
.list-widget-item {
@ -311,12 +297,12 @@
background: none;
box-shadow: none;
border: none;
list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
-moz-image-region: rect(0px,16px,16px,0px);
}
#instruments-pane-toggle:not([toggled]) {
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
#instruments-pane-toggle[pane-collapsed] {
list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
}
#instruments-pane-toggle:hover {

Просмотреть файл

@ -0,0 +1,304 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/* Network requests table */
#body {
background: url(background-noise-toolbar.png), hsl(208,11%,27%);
}
.requests-menu-empty-notice {
background: url(background-noise-toolbar.png), hsl(208,11%,27%);
padding: 12px;
font-size: 110%;
color: #fff;
}
#requests-menu-toolbar {
-moz-padding-start: 4px;
}
.requests-menu-header {
text-align: center;
}
.requests-menu-subitem {
padding: 0 4px;
}
.requests-menu-header:not(:last-of-type),
.requests-menu-subitem:not(:last-child) {
-moz-border-end: 1px solid hsla(210,8%,5%,.25);
box-shadow: 1px 0 0 hsla(210,16%,76%,.1);
}
.requests-menu-status-and-method {
width: 8em;
}
.requests-menu-status {
background: #fff;
width: 10px;
height: 10px;
-moz-margin-start: 4px;
-moz-margin-end: 2px;
border-radius: 20px;
box-shadow:
0 0 0 1px rgba(255,255,255,0.4) inset,
0 -6px 4px 0 rgba(32,32,32,1.0) inset,
0 0 8px 0 rgba(32,0,0,0.4);
transition: box-shadow 0.5s ease-in-out;
}
.requests-menu-status[code^="1"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(0,0,64,1.0) inset,
0 0 8px 0 rgba(0,0,128,1.0);
}
.requests-menu-status[code^="2"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(0,64,0,1.0) inset,
0 0 8px 0 rgba(0,128,0,1.0);
}
.requests-menu-status[code^="3"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(64,32,0,1.0) inset,
0 0 8px 0 rgba(128,128,0,1.0);
}
.requests-menu-status[code^="4"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(64,0,0,1.0) inset,
0 0 8px 0 rgba(128,0,0,1.0);
}
.requests-menu-status[code^="5"] {
box-shadow:
0 0 2px 1px rgba(255,255,255,0.8) inset,
0 -6px 4px 0 rgba(64,0,64,1.0) inset,
0 0 8px 0 rgba(128,0,128,1.0);
}
.requests-menu-method {
text-align: center;
font-weight: 600;
}
.requests-menu-file {
width: 16em;
}
.requests-menu-domain {
width: 16em;
}
.requests-menu-type {
text-align: center;
width: 4em;
}
.requests-menu-size {
text-align: center;
width: 8em;
}
.requests-menu-header.requests-menu-waterfall {
-moz-padding-start: 8px;
-moz-padding-end: 8px;
text-align: center;
}
/* Network request waterfall */
.requests-menu-subitem.requests-menu-waterfall {
-moz-padding-start: 4px;
-moz-padding-end: 4px;
background-size: 5px;
background-image:
-moz-linear-gradient(left,
transparent 25%,
rgba(255,255,255,0.02) 25%,
rgba(255,255,255,0.02) 75%,
transparent 75%);
}
.requests-menu-timings {
transform-origin: left center;
}
.requests-menu-timings-total {
-moz-padding-start: 4px;
font-size: 85%;
font-weight: 600;
transform-origin: -4px center; /* negative cap size */
}
.requests-menu-timings-cap {
width: 4px;
height: 10px;
border: 1px solid #fff;
}
.requests-menu-timings-cap.start {
-moz-border-end: none;
border-radius: 4px 0 0 4px;
transform-origin: right center;
}
.requests-menu-timings-cap.end {
-moz-border-start: none;
border-radius: 0 4px 4px 0;
transform-origin: left center;
}
.requests-menu-timings-box {
height: 10px;
border-top: 1px solid #fff;
border-bottom: 1px solid #fff;
}
.requests-menu-timings-box.blocked,
.requests-menu-timings-cap.blocked {
background-color: rgba(255,32,32,0.8);
box-shadow: 0 0 8px 0 rgba(128,32,32,0.8),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.dns,
.requests-menu-timings-cap.dns {
background-color: rgba(255,128,255,0.6);
box-shadow: 0 0 8px 0 rgba(128,128,255,1.0),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.connect,
.requests-menu-timings-cap.connect {
background-color: rgba(255,128,16,0.4);
box-shadow: 0 0 8px 0 rgba(128,128,16,0.8),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.send,
.requests-menu-timings-cap.send {
background-color: rgba(255,255,128,0.4);
box-shadow: 0 0 8px 0 rgba(128,255,128,0.8),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.wait,
.requests-menu-timings-cap.wait {
background-color: rgba(255,255,255,0.2);
box-shadow: 0 0 8px 0 rgba(128,255,255,0.4),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.requests-menu-timings-box.receive,
.requests-menu-timings-cap.receive {
background-color: rgba(255,255,255,1.0);
box-shadow: 0 0 8px 0 rgba(128,255,255,1.0),
0 0 4px 0 rgba(255,255,255,1.0) inset;
}
.side-menu-widget-container,
.side-menu-widget-item-or-group {
box-shadow: none !important;
}
.side-menu-widget-item:nth-child(even) {
background: rgba(255,255,255,0.05);
}
/* Network request details */
#details-pane {
background: hsl(208,11%,27%);
max-width: 500px;
}
#details-pane-toggle {
background: none;
box-shadow: none;
border-color: transparent;
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
-moz-image-region: rect(0px,16px,16px,0px);
}
#details-pane-toggle[pane-collapsed] {
list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
}
#details-pane-toggle:active {
-moz-image-region: rect(0px,32px,16px,16px);
}
/* Network request details tabpanels */
.tabpanel-content {
background: url(background-noise-toolbar.png), #3e4750;
box-shadow: 0 1px 0 hsla(204,45%,98%,.05) inset;
color: #fff;
}
.tabpanel-summary-container {
padding: 1px;
}
.tabpanel-summary-label {
-moz-padding-start: 4px;
-moz-padding-end: 3px;
font-weight: 600;
text-shadow: 0 1px 0 #000;
color: hsl(210,30%,85%);
}
.tabpanel-summary-value {
-moz-padding-start: 3px;
font-family: Menlo, Monaco, monospace;
}
/* Headers tabpanel */
#headers-summary-status,
#headers-summary-version {
padding-bottom: 2px;
}
#headers-summary-size {
padding-top: 2px;
}
/* Response tabpanel */
#response-content-image-box {
padding-top: 10px;
padding-bottom: 10px;
}
#response-content-image {
background: #fff;
border: 1px dashed GrayText;
margin-bottom: 10px;
}
/* Timings tabpanel */
#timings-tabpanel .tabpanel-summary-label {
width: 10em;
}
#timings-tabpanel .requests-menu-timings-box {
transition: transform 0.2s ease-out;
min-width: 1px;
}
#timings-tabpanel .requests-menu-timings-total {
transition: transform 0.2s ease-out;
}

Просмотреть файл

@ -3,6 +3,20 @@
* 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/. */
/* Generic pane helpers */
.generic-toggled-side-pane {
min-width: 50px;
-moz-margin-start: 0px !important;
/* Unfortunately, transitions don't work properly with locale-aware properties,
so both the left and right margins are set via js, while the start margin
is always overridden here. */
}
.generic-toggled-side-pane[animated] {
transition: margin 0.25s ease-in-out;
}
/* BreacrumbsWidget */
.breadcrumbs-widget-container {
@ -302,7 +316,7 @@
}
.side-menu-widget-item.selected {
background: -moz-linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%)) repeat-x top left;
background: -moz-linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%)) repeat-x top left !important;
box-shadow: inset 0 1px 0 hsla(210,40%,83%,.15),
inset 0 -1px 0 hsla(210,40%,83%,.05);
border-top: 0;
@ -334,7 +348,7 @@
padding: 4px;
}
.side-menu-widget-item-label {
.side-menu-widget-item label {
cursor: inherit;
}
@ -364,9 +378,7 @@
}
.side-menu-widget-item-other > label {
cursor: inherit;
color: #f5f7fa;
text-shadow: 0 1px 1px #111;
}
.side-menu-widget-empty-notice-container {
@ -402,14 +414,15 @@
-moz-margin-end: 1px;
}
.variables-view-scope > .variables-view-element-details.nonenum:not(:empty) {
border-top: 1px solid #ddd;
.variables-view-scope > .variables-view-element-details.enum:not(:empty) {
border-bottom: 1px solid #ddd;
}
/* Generic traits applied to both variables and properties */
.variable-or-property {
transition: background 1s ease-in-out;
color: #000;
}
.variable-or-property[changed] {
@ -475,7 +488,6 @@
}
.variable-or-property:not(:focus) > .title > .token-string {
max-width: 30em;
color: #1c00cf;
}

Просмотреть файл

@ -192,6 +192,7 @@ browser.jar:
skin/classic/browser/devtools/splitview.css (devtools/splitview.css)
skin/classic/browser/devtools/styleeditor.css (devtools/styleeditor.css)
skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/browser/devtools/option-icon.png (devtools/option-icon.png)
skin/classic/browser/devtools/itemToggle.png (devtools/itemToggle.png)
@ -432,6 +433,7 @@ browser.jar:
skin/classic/aero/browser/devtools/splitview.css (devtools/splitview.css)
skin/classic/aero/browser/devtools/styleeditor.css (devtools/styleeditor.css)
skin/classic/aero/browser/devtools/debugger.css (devtools/debugger.css)
skin/classic/aero/browser/devtools/netmonitor.css (devtools/netmonitor.css)
skin/classic/aero/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/aero/browser/devtools/option-icon.png (devtools/option-icon.png)
skin/classic/aero/browser/devtools/itemToggle.png (devtools/itemToggle.png)

Просмотреть файл

@ -87,14 +87,11 @@ this.NetworkHelper =
*/
convertToUnicode: function NH_convertToUnicode(aText, aCharset)
{
if (!aCharset) {
return aText;
}
let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Ci.nsIScriptableUnicodeConverter);
conv.charset = aCharset;
if (aCharset) {
conv.charset = aCharset;
}
try {
return conv.ConvertToUnicode(aText);
}