This commit is contained in:
Panos Astithas 2012-10-08 16:26:41 +03:00
Родитель ad52ccae25 eaffb91259
Коммит 096e1d6297
89 изменённых файлов: 9447 добавлений и 10729 удалений

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

@ -1010,7 +1010,7 @@ pref("devtools.inspector.htmlHeight", 112);
pref("devtools.inspector.htmlPanelOpen", false);
pref("devtools.inspector.sidebarOpen", false);
pref("devtools.inspector.activeSidebar", "ruleview");
pref("devtools.inspector.markupPreview", true);
pref("devtools.inspector.markupPreview", false);
// Enable the Layout View
pref("devtools.layoutview.enabled", true);

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

@ -28,79 +28,82 @@ gcli.addCommand({
description: gcli.lookup('jsbUrlDesc')
},
{
name: 'indentSize',
type: 'number',
description: gcli.lookup('jsbIndentSizeDesc'),
manual: gcli.lookup('jsbIndentSizeManual'),
defaultValue: 2
},
{
name: 'indentChar',
type: {
name: 'selection',
lookup: [
{ name: "space", value: " " },
{ name: "tab", value: "\t" }
]
},
description: gcli.lookup('jsbIndentCharDesc'),
manual: gcli.lookup('jsbIndentCharManual'),
defaultValue: ' ',
},
{
name: 'preserveNewlines',
type: 'boolean',
description: gcli.lookup('jsbPreserveNewlinesDesc'),
manual: gcli.lookup('jsbPreserveNewlinesManual')
},
{
name: 'preserveMaxNewlines',
type: 'number',
description: gcli.lookup('jsbPreserveMaxNewlinesDesc'),
manual: gcli.lookup('jsbPreserveMaxNewlinesManual'),
defaultValue: -1
},
{
name: 'jslintHappy',
type: 'boolean',
description: gcli.lookup('jsbJslintHappyDesc'),
manual: gcli.lookup('jsbJslintHappyManual')
},
{
name: 'braceStyle',
type: {
name: 'selection',
data: ['collapse', 'expand', 'end-expand', 'expand-strict']
},
description: gcli.lookup('jsbBraceStyleDesc'),
manual: gcli.lookup('jsbBraceStyleManual'),
defaultValue: "collapse"
},
{
name: 'spaceBeforeConditional',
type: 'boolean',
description: gcli.lookup('jsbSpaceBeforeConditionalDesc'),
manual: gcli.lookup('jsbSpaceBeforeConditionalManual')
},
{
name: 'unescapeStrings',
type: 'boolean',
description: gcli.lookup('jsbUnescapeStringsDesc'),
manual: gcli.lookup('jsbUnescapeStringsManual')
group: gcli.lookup("jsbOptionsDesc"),
params: [
{
name: 'indentSize',
type: 'number',
description: gcli.lookup('jsbIndentSizeDesc'),
manual: gcli.lookup('jsbIndentSizeManual'),
defaultValue: 2
},
{
name: 'indentChar',
type: {
name: 'selection',
lookup: [
{ name: "space", value: " " },
{ name: "tab", value: "\t" }
]
},
description: gcli.lookup('jsbIndentCharDesc'),
manual: gcli.lookup('jsbIndentCharManual'),
defaultValue: ' ',
},
{
name: 'doNotPreserveNewlines',
type: 'boolean',
description: gcli.lookup('jsbDoNotPreserveNewlinesDesc')
},
{
name: 'preserveMaxNewlines',
type: 'number',
description: gcli.lookup('jsbPreserveMaxNewlinesDesc'),
manual: gcli.lookup('jsbPreserveMaxNewlinesManual'),
defaultValue: -1
},
{
name: 'jslintHappy',
type: 'boolean',
description: gcli.lookup('jsbJslintHappyDesc'),
manual: gcli.lookup('jsbJslintHappyManual')
},
{
name: 'braceStyle',
type: {
name: 'selection',
data: ['collapse', 'expand', 'end-expand', 'expand-strict']
},
description: gcli.lookup('jsbBraceStyleDesc'),
manual: gcli.lookup('jsbBraceStyleManual'),
defaultValue: "collapse"
},
{
name: 'noSpaceBeforeConditional',
type: 'boolean',
description: gcli.lookup('jsbNoSpaceBeforeConditionalDesc')
},
{
name: 'unescapeStrings',
type: 'boolean',
description: gcli.lookup('jsbUnescapeStringsDesc'),
manual: gcli.lookup('jsbUnescapeStringsManual')
}
]
}
],
exec: function(args, context) {
let opts = {
indent_size: args.indentSize,
indent_char: args.indentChar,
preserve_newlines: args.preserveNewlines,
preserve_newlines: !args.doNotPreserveNewlines,
max_preserve_newlines: args.preserveMaxNewlines == -1 ?
undefined : args.preserveMaxNewlines,
jslint_happy: args.jslintHappy,
brace_style: args.braceStyle,
space_before_conditional: args.spaceBeforeConditional,
space_before_conditional: !args.noSpaceBeforeConditional,
unescape_strings: args.unescapeStrings
}
};
let xhr = new XMLHttpRequest();
@ -117,13 +120,13 @@ gcli.addCommand({
if (xhr.status == 200 || xhr.status == 0) {
let browserDoc = context.environment.chromeDocument;
let browserWindow = browserDoc.defaultView;
let browser = browserWindow.gBrowser;
browser.selectedTab = browser.addTab("data:text/plain;base64," +
browserWindow.btoa(js_beautify(xhr.responseText, opts)));
let gBrowser = browserWindow.gBrowser;
let result = js_beautify(xhr.responseText, opts);
browserWindow.Scratchpad.ScratchpadManager.openScratchpad({text: result});
promise.resolve();
}
else {
} else {
promise.resolve("Unable to load page to beautify: " + args.url + " " +
xhr.status + " " + xhr.statusText);
}

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

@ -34,3 +34,6 @@
direction: ltr;
}
.gcli-row-out .nowrap {
white-space: nowrap;
}

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

@ -3056,7 +3056,10 @@ exports.setContents = function(elem, contents) {
return;
}
if (exports.isXmlDocument(elem.ownerDocument)) {
if ('innerHTML' in elem) {
elem.innerHTML = contents;
}
else {
try {
var ns = elem.ownerDocument.documentElement.namespaceURI;
if (!ns) {
@ -3076,9 +3079,6 @@ exports.setContents = function(elem, contents) {
throw ex;
}
}
else {
elem.innerHTML = contents;
}
};
/**
@ -5469,7 +5469,7 @@ function Requisition(environment, doc) {
// The command that we are about to execute.
// @see setCommandConversion()
this.commandAssignment = new CommandAssignment();
this._setAssignment(this.commandAssignment, null, true);
this.setAssignment(this.commandAssignment, null);
// The object that stores of Assignment objects that we are filling out.
// The Assignment objects are stored under their param.name for named
@ -5556,7 +5556,7 @@ Requisition.prototype._commandAssignmentChanged = function(ev) {
for (var i = 0; i < command.params.length; i++) {
var param = command.params[i];
var assignment = new Assignment(param, i);
this._setAssignment(assignment, null, true);
this.setAssignment(assignment, null);
assignment.onAssignmentChange.add(this._assignmentChanged, this);
this._assignments[param.name] = assignment;
}
@ -5678,27 +5678,23 @@ Requisition.prototype.getAssignments = function(includeCommand) {
return assignments;
};
/**
* Alter the given assignment using the given arg.
* @param assignment The assignment to alter
* @param arg The new value for the assignment. An instance of Argument, or an
* instance of Conversion, or null to set the blank value.
*/
Requisition.prototype.setAssignment = function(assignment, arg) {
this._setAssignment(assignment, arg, false);
};
/**
* Internal function to alter the given assignment using the given arg.
* @param assignment The assignment to alter
* @param arg The new value for the assignment. An instance of Argument, or an
* instance of Conversion, or null to set the blank value.
* @param skipArgUpdate (default=false) Adjusts the args in this requisition to
* keep things up to date. Args should only be skipped when setAssignment is
* being called as part of the update process.
* @param options There are a number of ways to customize how the assignment
* is made, including:
* - argUpdate: (default:false) Adjusts the args in this requisition to keep
* things up to date. Args should only be skipped when setAssignment is being
* called as part of the update process.
* - matchPadding: (default:false) If argUpdate=true, and matchPadding=true
* then further take the step of altering the whitespace on the prefix and
* suffix of the new argument to match that of the old argument.
*/
Requisition.prototype._setAssignment = function(assignment, arg, skipArgUpdate) {
if (!skipArgUpdate) {
Requisition.prototype.setAssignment = function(assignment, arg, options) {
options = options || {};
if (options.argUpdate) {
var originalArgs = assignment.arg.getArgs();
// Update the args array
@ -5724,6 +5720,16 @@ Requisition.prototype._setAssignment = function(assignment, arg, skipArgUpdate)
this._args.splice(index, 1);
}
else {
if (options.matchPadding) {
if (replacementArgs[i].prefix.length === 0 &&
this._args[index].prefix.length !== 0) {
replacementArgs[i].prefix = this._args[index].prefix;
}
if (replacementArgs[i].suffix.length === 0 &&
this._args[index].suffix.length !== 0) {
replacementArgs[i].suffix = this._args[index].suffix;
}
}
this._args[index] = replacementArgs[i];
}
}
@ -5761,7 +5767,7 @@ Requisition.prototype._setAssignment = function(assignment, arg, skipArgUpdate)
*/
Requisition.prototype.setBlankArguments = function() {
this.getAssignments().forEach(function(assignment) {
this._setAssignment(assignment, null, true);
this.setAssignment(assignment, null);
}, this);
};
@ -5801,13 +5807,13 @@ Requisition.prototype.complete = function(cursor, predictionChoice) {
// logic, so we don't use addSpace
if (assignment.isInName()) {
var newArg = assignment.conversion.arg.beget({ prefixPostSpace: true });
this.setAssignment(assignment, newArg);
this.setAssignment(assignment, newArg, { argUpdate: true });
}
}
else {
// Mutate this argument to hold the completion
var arg = assignment.arg.beget({ text: prediction.name });
this.setAssignment(assignment, arg);
this.setAssignment(assignment, arg, { argUpdate: true });
if (!prediction.incomplete) {
// The prediction is complete, add a space to let the user move-on
@ -5832,7 +5838,7 @@ Requisition.prototype.complete = function(cursor, predictionChoice) {
Requisition.prototype._addSpace = function(assignment) {
var arg = assignment.conversion.arg.beget({ suffixSpace: true });
if (arg !== assignment.conversion.arg) {
this.setAssignment(assignment, arg);
this.setAssignment(assignment, arg, { argUpdate: true });
}
};
@ -5844,7 +5850,7 @@ Requisition.prototype.decrement = function(assignment) {
if (replacement != null) {
var str = assignment.param.type.stringify(replacement);
var arg = assignment.conversion.arg.beget({ text: str });
this.setAssignment(assignment, arg);
this.setAssignment(assignment, arg, { argUpdate: true });
}
};
@ -5856,7 +5862,7 @@ Requisition.prototype.increment = function(assignment) {
if (replacement != null) {
var str = assignment.param.type.stringify(replacement);
var arg = assignment.conversion.arg.beget({ text: str });
this.setAssignment(assignment, arg);
this.setAssignment(assignment, arg, { argUpdate: true });
}
};
@ -6514,7 +6520,7 @@ Requisition.prototype._split = function(args) {
// Special case: if the user enters { console.log('foo'); } then we need to
// use the hidden 'eval' command
conversion = new Conversion(evalCommand, new ScriptArgument());
this._setAssignment(this.commandAssignment, conversion, true);
this.setAssignment(this.commandAssignment, conversion);
return;
}
@ -6541,7 +6547,7 @@ Requisition.prototype._split = function(args) {
argsUsed++;
}
this._setAssignment(this.commandAssignment, conversion, true);
this.setAssignment(this.commandAssignment, conversion);
for (var i = 0; i < argsUsed; i++) {
args.shift();
@ -6588,7 +6594,7 @@ Requisition.prototype._assign = function(args) {
var assignment = this.getAssignment(0);
if (assignment.param.type instanceof StringType) {
var arg = (args.length === 1) ? args[0] : new MergedArgument(args);
this._setAssignment(assignment, arg, true);
this.setAssignment(assignment, arg);
return;
}
}
@ -6633,7 +6639,7 @@ Requisition.prototype._assign = function(args) {
arrayArg.addArgument(arg);
}
else {
this._setAssignment(assignment, arg, true);
this.setAssignment(assignment, arg);
}
}
else {
@ -6650,7 +6656,7 @@ Requisition.prototype._assign = function(args) {
// If not set positionally, and we can't set it non-positionally,
// we have to default it to prevent previous values surviving
if (!assignment.param.isPositionalAllowed) {
this._setAssignment(assignment, null, true);
this.setAssignment(assignment, null);
return;
}
@ -6667,7 +6673,7 @@ Requisition.prototype._assign = function(args) {
}
else {
if (args.length === 0) {
this._setAssignment(assignment, null, true);
this.setAssignment(assignment, null);
}
else {
var arg = args.splice(0, 1)[0];
@ -6681,7 +6687,7 @@ Requisition.prototype._assign = function(args) {
this._unassigned.push(new UnassignedAssignment(this, arg));
}
else {
this._setAssignment(assignment, arg, true);
this.setAssignment(assignment, arg);
}
}
}
@ -6690,7 +6696,7 @@ Requisition.prototype._assign = function(args) {
// Now we need to assign the array argument (if any)
Object.keys(arrayArgs).forEach(function(name) {
var assignment = this.getAssignment(name);
this._setAssignment(assignment, arrayArgs[name], true);
this.setAssignment(assignment, arrayArgs[name]);
}, this);
// What's left is can't be assigned, but we need to extract
@ -8066,8 +8072,10 @@ JavascriptField.prototype.setConversion = function(conversion) {
};
JavascriptField.prototype.itemClicked = function(ev) {
this.onFieldChange(ev);
this.setMessage(ev.conversion.message);
var conversion = this.type.parse(ev.arg);
this.onFieldChange({ conversion: conversion });
this.setMessage(conversion.message);
};
JavascriptField.prototype.onInputChange = function(ev) {
@ -8180,12 +8188,11 @@ Menu.prototype.destroy = function() {
* @param ev The click event from the browser
*/
Menu.prototype.onItemClickInternal = function(ev) {
var name = ev.currentTarget.querySelector('.gcli-menu-name').innerHTML;
var name = ev.currentTarget.querySelector('.gcli-menu-name').textContent;
var arg = new Argument(name);
arg.suffix = ' ';
var conversion = this.type.parse(arg);
this.onItemClick({ conversion: conversion });
this.onItemClick({ arg: arg });
};
/**
@ -8201,7 +8208,7 @@ Menu.prototype.show = function(items, match) {
if (match) {
this.items = this.items.map(function(item) {
return gethighlightingProxy(item, match, this.template.ownerDocument);
return getHighlightingProxy(item, match, this.template.ownerDocument);
}.bind(this));
}
@ -8227,7 +8234,7 @@ Menu.prototype.show = function(items, match) {
/**
* Create a proxy around an item that highlights matching text
*/
function gethighlightingProxy(item, match, document) {
function getHighlightingProxy(item, match, document) {
if (typeof Proxy === 'undefined') {
return item;
}
@ -8289,12 +8296,12 @@ Menu.prototype.selectChoice = function() {
return false;
}
var name = selected.innerHTML;
var name = selected.textContent;
var arg = new Argument(name);
arg.suffix = ' ';
arg.prefix = ' ';
var conversion = this.type.parse(arg);
this.onItemClick({ conversion: conversion });
this.onItemClick({ arg: arg });
return true;
};
@ -8498,8 +8505,10 @@ SelectionTooltipField.prototype.setConversion = function(conversion) {
};
SelectionTooltipField.prototype.itemClicked = function(ev) {
this.onFieldChange(ev);
this.setMessage(ev.conversion.message);
var conversion = this.type.parse(ev.arg);
this.onFieldChange({ conversion: conversion });
this.setMessage(conversion.message);
};
SelectionTooltipField.prototype.onInputChange = function(ev) {
@ -10340,7 +10349,8 @@ Tooltip.prototype.selectChoice = function(ev) {
* Called by the onFieldChange event on the current Field
*/
Tooltip.prototype.fieldChanged = function(ev) {
this.requisition.setAssignment(this.assignment, ev.conversion.arg);
var options = { argUpdate: true, matchPadding: true };
this.requisition.setAssignment(this.assignment, ev.conversion.arg, options);
var isError = ev.conversion.message != null && ev.conversion.message !== '';
this.focusManager.setError(isError);

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

@ -6,52 +6,68 @@
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
"test/browser_cmd_jsb_script.jsi";
let scratchpadWin = null;
let Scratchpad = null;
function test() {
DeveloperToolbarTest.test("about:blank", [ /*GJT_test*/ ]);
DeveloperToolbarTest.test("about:blank", [ GJT_test ]);
}
function GJT_test() {
helpers.setInput('jsb');
helpers.check({
input: 'jsb',
hints: ' <url> [indentSize] [indentChar] [preserveNewlines] [preserveMaxNewlines] [jslintHappy] [braceStyle] [spaceBeforeConditional] [unescapeStrings]',
hints: ' <url> [options]',
markup: 'VVV',
status: 'ERROR'
});
DeveloperToolbarTest.exec({ completed: false });
gBrowser.addTabsProgressListener({
onProgressChange: DeveloperToolbarTest.checkCalled(function GJT_onProgressChange(aBrowser) {
gBrowser.removeTabsProgressListener(this);
Services.ww.registerNotification(function(aSubject, aTopic, aData) {
if (aTopic == "domwindowopened") {
Services.ww.unregisterNotification(arguments.callee);
let win = aBrowser._contentWindow;
let uri = win.document.location.href;
let result = win.atob(uri.replace(/.*,/, ""));
scratchpadWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
scratchpadWin.addEventListener("load", function GDT_onLoad() {
scratchpadWin.removeEventListener("load", GDT_onLoad, false);
Scratchpad = scratchpadWin.Scratchpad;
result = result.replace(/[\r\n]]/g, "\n");
let observer = {
onReady: function GJT_onReady() {
Scratchpad.removeObserver(observer);
let correct = "function somefunc() {\n" +
" for (let n = 0; n < 500; n++) {\n" +
" if (n % 2 == 1) {\n" +
" console.log(n);\n" +
" console.log(n + 1);\n" +
" }\n" +
" }\n" +
"}";
is(result, correct, "JS has been correctly prettified");
})
});
let result = Scratchpad.getText();
result = result.replace(/[\r\n]]*/g, "\n");
let correct = "function somefunc() {\n" +
" if (true) // Some comment\n" +
" doSomething();\n" +
" for (let n = 0; n < 500; n++) {\n" +
" if (n % 2 == 1) {\n" +
" console.log(n);\n" +
" console.log(n + 1);\n" +
" }\n" +
" }\n" +
"}";
is(result, correct, "JS has been correctly prettified");
finishUp();
},
};
Scratchpad.addObserver(observer);
}, false);
}
});
info("Checking beautification");
helpers.setInput('jsb ' + TEST_URI);
/*
helpers.check({
input: 'jsb',
hints: ' [options]',
markup: 'VVV',
status: 'VALID'
DeveloperToolbarTest.exec({
typed: "jsb " + TEST_URI,
completed: false
});
*/
DeveloperToolbarTest.exec({ completed: false });
}
let finishUp = DeveloperToolbarTest.checkCalled(function GJT_finishUp() {
if (scratchpadWin) {
scratchpadWin.close();
scratchpadWin = null;
}
});

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

@ -1 +1,2 @@
function somefunc(){for(let n=0;n<500;n++){if(n%2==1){console.log(n);console.log(n+1);}}}
function somefunc(){if (true) // Some comment
doSomething();for(let n=0;n<500;n++){if(n%2==1){console.log(n);console.log(n+1);}}}

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

@ -1,804 +0,0 @@
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2007, Parakey Inc.
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* * Neither the name of Parakey Inc. nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior
* written permission of Parakey Inc.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Creator:
* Joe Hewitt
* Contributors
* John J. Barton (IBM Almaden)
* Jan Odvarko (Mozilla Corp.)
* Max Stepanov (Aptana Inc.)
* Rob Campbell (Mozilla Corp.)
* Hans Hillen (Paciello Group, Mozilla)
* Curtis Bartley (Mozilla Corp.)
* Mike Collins (IBM Almaden)
* Kevin Decker
* Mike Ratcliffe (Comartis AG)
* Hernan Rodríguez Colmeiro
* Austin Andrews
* Christoph Dorn
* Steven Roussey (AppCenter Inc, Network54)
*/
///////////////////////////////////////////////////////////////////////////
//// InsideOutBox
/**
* InsideOutBoxView is a simple interface definition for views implementing
* InsideOutBox controls. All implementors must define these methods.
* Implemented in InspectorUI.
*/
/*
InsideOutBoxView = {
//
* Retrieves the parent object for a given child object.
* @param aChild
* The child node to retrieve the parent object for.
* @returns a DOM node | null
//
getParentObject: function(aChild) {},
//
* Retrieves a given child node.
*
* If both index and previousSibling are passed, the implementation
* may assume that previousSibling will be the return for getChildObject
* with index-1.
* @param aParent
* The parent object of the child object to retrieve.
* @param aIndex
* The index of the child object to retrieve from aParent.
* @param aPreviousSibling
* The previous sibling of the child object to retrieve.
* Supercedes aIndex.
* @returns a DOM object | null
//
getChildObject: function(aParent, aIndex, aPreviousSibling) {},
//
* Renders the HTML representation of the object. Should return an HTML
* object which will be displayed to the user.
* @param aObject
* The object to create the box object for.
* @param aIsRoot
* Is the object the root object. May not be used in all
* implementations.
* @returns an object box | null
//
createObjectBox: function(aObject, aIsRoot) {},
//
* Convenience wrappers for classList API.
* @param aObject
* DOM node to query/set.
* @param aClassName
* String containing the class name to query/set.
//
hasClass: function(aObject, aClassName) {},
addClass: function(aObject, aClassName) {},
removeClass: function(aObject, aClassName) {}
};
*/
/**
* Creates a tree based on objects provided by a separate "view" object.
*
* Construction uses an "inside-out" algorithm, meaning that the view's job is
* first to tell us the ancestry of each object, and secondarily its
* descendants.
*
* Constructor
* @param aView
* The view requiring the InsideOutBox.
* @param aBox
* The box object containing the InsideOutBox. Required to add/remove
* children during box manipulation (toggling opened or closed).
*/
var EXPORTED_SYMBOLS = ["InsideOutBox"];
const Cu = Components.utils;
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
function InsideOutBox(aView, aBox)
{
this.view = aView;
this.box = aBox;
this.rootObject = null;
this.rootObjectBox = null;
this.selectedObjectBox = null;
this.highlightedObjectBox = null;
this.scrollIntoView = false;
};
InsideOutBox.prototype =
{
/**
* Highlight the given object node in the tree.
* @param aObject
* the object to highlight.
* @returns objectBox
*/
highlight: function IOBox_highlight(aObject)
{
let objectBox = this.createObjectBox(aObject);
this.highlightObjectBox(objectBox);
return objectBox;
},
/**
* Open the given object node in the tree.
* @param aObject
* The object node to open.
* @returns objectBox
*/
openObject: function IOBox_openObject(aObject)
{
let object = aObject;
let firstChild = this.view.getChildObject(object, 0);
if (firstChild)
object = firstChild;
return this.openToObject(object);
},
/**
* Open the tree up to the given object node.
* @param aObject
* The object in the tree to open to.
* @returns objectBox
*/
openToObject: function IOBox_openToObject(aObject)
{
let objectBox = this.createObjectBox(aObject);
this.openObjectBox(objectBox);
return objectBox;
},
/**
* Select the given object node in the tree.
* @param aObject
* The object node to select.
* @param makeBoxVisible
* Boolean. Open the object box in the tree?
* @param forceOpen
* Force the object box open by expanding all elements in the tree?
* @param scrollIntoView
* Scroll the objectBox into view?
* @returns nsIDOMNode|null
* A DOM node that represents the "object box", the element that
* holds/displays the given aObject representation in the tree. If
* the object cannot be selected, if it is a stale object, null is
* returned.
*/
select:
function IOBox_select(aObject, makeBoxVisible, forceOpen, scrollIntoView)
{
let objectBox = this.createObjectBox(aObject);
if (!objectBox) {
return null;
}
this.selectObjectBox(objectBox, forceOpen);
if (makeBoxVisible) {
this.openObjectBox(objectBox);
}
if (scrollIntoView) {
// We want to center the label of the element, not the whole tag
// (which includes all of its children, and is vertically huge).
LayoutHelpers.scrollIntoViewIfNeeded(objectBox.firstElementChild);
}
return objectBox;
},
/**
* Expands/contracts the given object, depending on its state.
* @param aObject
* The tree node to expand/contract.
*/
toggleObject: function IOBox_toggleObject(aObject)
{
let box = this.createObjectBox(aObject);
if (!(this.view.hasClass(box, "open")))
this.expandObjectBox(box);
else
this.contractObjectBox(box);
},
/**
* Expand the given object in the tree.
* @param aObject
* The tree node to expand.
*/
expandObject: function IOBox_expandObject(aObject)
{
let objectBox = this.createObjectBox(aObject);
if (objectBox)
this.expandObjectBox(objectBox);
},
/**
* Contract the given object in the tree.
* @param aObject
* The tree node to contract.
*/
contractObject: function IOBox_contractObject(aObject)
{
let objectBox = this.createObjectBox(aObject);
if (objectBox)
this.contractObjectBox(objectBox);
},
/**
* General method for iterating over an object's ancestors and performing
* some function.
* @param aObject
* The object whose ancestors we wish to iterate over.
* @param aCallback
* The function to call with the object as argument.
*/
iterateObjectAncestors: function IOBox_iterateObjectAncesors(aObject, aCallback)
{
let object = aObject;
if (!(aCallback && typeof(aCallback) == "function")) {
this.view._log("Illegal argument in IOBox.iterateObjectAncestors");
return;
}
while ((object = this.getParentObjectBox(object)))
aCallback(object);
},
/**
* Highlight the given objectBox in the tree.
* @param aObjectBox
* The objectBox to highlight.
*/
highlightObjectBox: function IOBox_highlightObjectBox(aObjectBox)
{
let self = this;
if (!aObjectBox)
return;
if (this.highlightedObjectBox) {
this.view.removeClass(this.highlightedObjectBox, "highlighted");
this.iterateObjectAncestors(this.highlightedObjectBox, function (box) {
self.view.removeClass(box, "highlightOpen");
});
}
this.highlightedObjectBox = aObjectBox;
this.view.addClass(aObjectBox, "highlighted");
this.iterateObjectAncestors(this.highlightedObjectBox, function (box) {
self.view.addClass(box, "highlightOpen");
});
aObjectBox.scrollIntoView(true);
},
/**
* Select the given objectBox in the tree, forcing it to be open if necessary.
* @param aObjectBox
* The objectBox to select.
* @param forceOpen
* Force the box (subtree) to be open?
*/
selectObjectBox: function IOBox_selectObjectBox(aObjectBox, forceOpen)
{
let isSelected = this.selectedObjectBox &&
aObjectBox == this.selectedObjectBox;
// aObjectBox is already selected, return
if (isSelected)
return;
if (this.selectedObjectBox)
this.view.removeClass(this.selectedObjectBox, "selected");
this.selectedObjectBox = aObjectBox;
if (aObjectBox) {
this.view.addClass(aObjectBox, "selected");
// Force it open the first time it is selected
if (forceOpen)
this.expandObjectBox(aObjectBox, true);
}
},
/**
* Returns the next object box in the tree for navigation purposes.
*/
nextObjectBox: function IOBox_nextObjectBox(aBoxObject)
{
let candidate;
let boxObject = aBoxObject || this.selectedObjectBox;
if (!boxObject)
return this.rootObjectBox;
// If expanded, return the first child.
let isOpen = this.view.hasClass(boxObject, "open");
let childObjectBox = this.getChildObjectBox(boxObject);
if (isOpen && childObjectBox && childObjectBox.firstChild) {
candidate = childObjectBox.firstChild;
} else {
// Otherwise we get the next available sibling.
while (boxObject) {
if (boxObject.nextSibling) {
boxObject = boxObject.nextSibling;
break;
}
boxObject = this.getParentObjectBox(boxObject);
}
candidate = boxObject;
}
// If the node is not an element (comments or text nodes), we
// jump to the next line.
if (candidate &&
candidate.repObject.nodeType != candidate.repObject.ELEMENT_NODE) {
return this.nextObjectBox(candidate);
}
return candidate;
},
/**
* Returns the next object in the tree for navigation purposes.
*/
nextObject: function IOBox_nextObject()
{
let next = this.nextObjectBox();
return next ? next.repObject : null;
},
/**
* Returns the object that is below the selection.
*
* @param aDistance Number of lines to jump.
*/
farNextObject: function IOBox_farPreviousProject(aDistance)
{
let boxObject = this.selectedObjectBox;
while (aDistance-- > 0) {
let newBoxObject = this.nextObjectBox(boxObject);
if (!newBoxObject) {
break;
}
boxObject = newBoxObject;
}
return boxObject ? boxObject.repObject : null;
},
/**
* Returns the last visible child box of an object box.
*/
lastVisible: function IOBox_lastVisibleChild(aNode)
{
if (!this.view.hasClass(aNode, "open"))
return aNode;
let childBox = this.getChildObjectBox(aNode);
if (!childBox || !childBox.lastChild)
return aNode;
return this.lastVisible(childBox.lastChild);
},
/**
* Returns the previous object box in the tree for navigation purposes.
*/
previousObjectBox: function IOBox_previousObjectBox(aBoxObject)
{
let boxObject = aBoxObject || this.selectedObjectBox;
if (!boxObject)
return this.rootObjectBox;
let candidate;
let sibling = boxObject.previousSibling;
if (sibling) {
candidate = this.lastVisible(sibling);
} else {
candidate = this.getParentObjectBox(boxObject);
}
// If the node is not an element (comments or text nodes), we
// jump to the previous line.
if (candidate &&
candidate.repObject.nodeType != candidate.repObject.ELEMENT_NODE) {
return this.previousObjectBox(candidate);
}
return candidate;
},
/**
* Returns the previous object in the tree for navigation purposes.
*/
previousObject: function IOBox_previousObject()
{
let boxObject = this.previousObjectBox();
return boxObject ? boxObject.repObject : null;
},
/**
* Returns the object that is above the selection.
*
* @param aDistance Number of lines to jump.
*/
farPreviousObject: function IOBox_farPreviousProject(aDistance)
{
let boxObject = this.selectedObjectBox;
while (aDistance-- > 0) {
let newBoxObject = this.previousObjectBox(boxObject);
if (!newBoxObject) {
break;
}
boxObject = newBoxObject;
if (boxObject === this.rootObjectBox)
break;
}
return boxObject ? boxObject.repObject : null;
},
/**
* Open the ancestors of the given object box.
* @param aObjectBox
* The object box to open.
*/
openObjectBox: function IOBox_openObjectBox(aObjectBox)
{
if (!aObjectBox)
return;
let self = this;
this.iterateObjectAncestors(aObjectBox, function (box) {
self.view.addClass(box, "open");
let labelBox = box.querySelector(".nodeLabelBox");
if (labelBox)
labelBox.setAttribute("aria-expanded", "true");
});
},
/**
* Expand the given object box.
* @param aObjectBox
* The object box to expand.
*/
expandObjectBox: function IOBox_expandObjectBox(aObjectBox)
{
let nodeChildBox = this.getChildObjectBox(aObjectBox);
// no children means nothing to expand, return
if (!nodeChildBox)
return;
if (!aObjectBox.populated) {
let firstChild = this.view.getChildObject(aObjectBox.repObject, 0);
this.populateChildBox(firstChild, nodeChildBox);
}
let labelBox = aObjectBox.querySelector(".nodeLabelBox");
if (labelBox)
labelBox.setAttribute("aria-expanded", "true");
this.view.addClass(aObjectBox, "open");
},
/**
* Contract the given object box.
* @param aObjectBox
* The object box to contract.
*/
contractObjectBox: function IOBox_contractObjectBox(aObjectBox)
{
this.view.removeClass(aObjectBox, "open");
let nodeLabel = aObjectBox.querySelector(".nodeLabel");
let labelBox = nodeLabel.querySelector(".nodeLabelBox");
if (labelBox)
labelBox.setAttribute("aria-expanded", "false");
},
/**
* Toggle the given object box, forcing open if requested.
* @param aObjectBox
* The object box to toggle.
* @param forceOpen
* Force the objectbox open?
*/
toggleObjectBox: function IOBox_toggleObjectBox(aObjectBox, forceOpen)
{
let isOpen = this.view.hasClass(aObjectBox, "open");
if (!forceOpen && isOpen)
this.contractObjectBox(aObjectBox);
else if (!isOpen)
this.expandObjectBox(aObjectBox);
},
/**
* Creates all of the boxes for an object, its ancestors, and siblings.
* @param aObject
* The tree node to create the object boxes for.
* @returns anObjectBox or null
*/
createObjectBox: function IOBox_createObjectBox(aObject)
{
if (!aObject)
return null;
this.rootObject = this.getRootNode(aObject) || aObject;
// Get or create all of the boxes for the target and its ancestors
let objectBox = this.createObjectBoxes(aObject, this.rootObject);
if (!objectBox)
return null;
if (aObject == this.rootObject)
return objectBox;
return this.populateChildBox(aObject, objectBox.parentNode);
},
/**
* Creates all of the boxes for an object, its ancestors, and siblings up to
* a root.
* @param aObject
* The tree's object node to create the object boxes for.
* @param aRootObject
* The root object at which to stop building object boxes.
* @returns an object box or null
*/
createObjectBoxes: function IOBox_createObjectBoxes(aObject, aRootObject)
{
if (!aObject)
return null;
if (aObject == aRootObject) {
if (!this.rootObjectBox || this.rootObjectBox.repObject != aRootObject) {
if (this.rootObjectBox) {
try {
this.box.removeChild(this.rootObjectBox);
} catch (exc) {
this.view._log("this.box.removeChild(this.rootObjectBox) FAILS " +
this.box + " must not contain " + this.rootObjectBox);
}
}
this.highlightedObjectBox = null;
this.selectedObjectBox = null;
this.rootObjectBox = this.view.createObjectBox(aObject, true);
this.box.appendChild(this.rootObjectBox);
}
return this.rootObjectBox;
}
let parentNode = this.view.getParentObject(aObject);
let parentObjectBox = this.createObjectBoxes(parentNode, aRootObject);
if (!parentObjectBox)
return null;
let parentChildBox = this.getChildObjectBox(parentObjectBox);
if (!parentChildBox)
return null;
let childObjectBox = this.findChildObjectBox(parentChildBox, aObject);
return childObjectBox ? childObjectBox
: this.populateChildBox(aObject, parentChildBox);
},
/**
* Locate the object box for a given object node.
* @param aObject
* The given object node in the tree.
* @returns an object box or null.
*/
findObjectBox: function IOBox_findObjectBox(aObject)
{
if (!aObject)
return null;
if (aObject == this.rootObject)
return this.rootObjectBox;
let parentNode = this.view.getParentObject(aObject);
let parentObjectBox = this.findObjectBox(parentNode);
if (!parentObjectBox)
return null;
let parentChildBox = this.getChildObjectBox(parentObjectBox);
if (!parentChildBox)
return null;
return this.findChildObjectBox(parentChildBox, aObject);
},
getAncestorByClass: function IOBox_getAncestorByClass(node, className)
{
for (let parent = node; parent; parent = parent.parentNode) {
if (this.view.hasClass(parent, className))
return parent;
}
return null;
},
/**
* We want all children of the parent of repObject.
*/
populateChildBox: function IOBox_populateChildBox(repObject, nodeChildBox)
{
if (!repObject)
return null;
let parentObjectBox = this.getAncestorByClass(nodeChildBox, "nodeBox");
if (parentObjectBox.populated)
return this.findChildObjectBox(nodeChildBox, repObject);
let lastSiblingBox = this.getChildObjectBox(nodeChildBox);
let siblingBox = nodeChildBox.firstChild;
let targetBox = null;
let view = this.view;
let targetSibling = null;
let parentNode = view.getParentObject(repObject);
for (let i = 0; 1; ++i) {
targetSibling = view.getChildObject(parentNode, i, targetSibling);
if (!targetSibling)
break;
// Check if we need to start appending, or continue to insert before
if (lastSiblingBox && lastSiblingBox.repObject == targetSibling)
lastSiblingBox = null;
if (!siblingBox || siblingBox.repObject != targetSibling) {
let newBox = view.createObjectBox(targetSibling);
if (newBox) {
if (lastSiblingBox)
nodeChildBox.insertBefore(newBox, lastSiblingBox);
else
nodeChildBox.appendChild(newBox);
}
siblingBox = newBox;
}
if (targetSibling == repObject)
targetBox = siblingBox;
if (siblingBox && siblingBox.repObject == targetSibling)
siblingBox = siblingBox.nextSibling;
}
if (targetBox)
parentObjectBox.populated = true;
return targetBox;
},
/**
* Get the parent object box of a given object box.
* @params aObjectBox
* The object box of the parent.
* @returns an object box or null
*/
getParentObjectBox: function IOBox_getParentObjectBox(aObjectBox)
{
let parent = aObjectBox.parentNode ? aObjectBox.parentNode.parentNode : null;
return parent && parent.repObject ? parent : null;
},
/**
* Get the child object box of a given object box.
* @param aObjectBox
* The object box whose child you want.
* @returns an object box or null
*/
getChildObjectBox: function IOBox_getChildObjectBox(aObjectBox)
{
return aObjectBox.querySelector(".nodeChildBox");
},
/**
* Find the child object box for a given repObject within the subtree
* rooted at aParentNodeBox.
* @param aParentNodeBox
* root of the subtree in which to search for repObject.
* @param aRepObject
* The object you wish to locate in the subtree.
* @returns an object box or null
*/
findChildObjectBox: function IOBox_findChildObjectBox(aParentNodeBox, aRepObject)
{
let childBox = aParentNodeBox.firstChild;
while (childBox) {
if (childBox.repObject == aRepObject)
return childBox;
childBox = childBox.nextSibling;
}
return null; // not found
},
/**
* Determines if the given node is an ancestor of the current root.
* @param aNode
* The node to look for within the tree.
* @returns boolean
*/
isInExistingRoot: function IOBox_isInExistingRoot(aNode)
{
let parentNode = aNode;
while (parentNode && parentNode != this.rootObject) {
parentNode = this.view.getParentObject(parentNode);
}
return parentNode == this.rootObject;
},
/**
* Get the root node of a given node.
* @param aNode
* The node whose root you wish to retrieve.
* @returns a root node or null
*/
getRootNode: function IOBox_getRootNode(aNode)
{
let node = aNode;
let tmpNode;
while ((tmpNode = this.view.getParentObject(node)))
node = tmpNode;
return node;
},
/**
* Clean up our mess.
*/
destroy: function IOBox_destroy()
{
delete this.view;
delete this.box;
delete this.rootObject;
delete this.rootObjectBox;
delete this.selectedObjectBox;
delete this.highlightedObjectBox;
delete this.scrollIntoView;
}
};

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

@ -11,9 +11,6 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
EXTRA_JS_MODULES = \
domplate.jsm \
InsideOutBox.jsm \
TreePanel.jsm \
highlighter.jsm \
$(NULL)

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

@ -1,844 +0,0 @@
/* -*- Mode: C++; tab-width: 8; 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/. */
const Cu = Components.utils;
const Ci = Components.interfaces;
Cu.import("resource:///modules/domplate.jsm");
Cu.import("resource:///modules/InsideOutBox.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/inspector.jsm");
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
var EXPORTED_SYMBOLS = ["TreePanel", "DOMHelpers"];
const INSPECTOR_URI = "chrome://browser/content/inspector.html";
/**
* TreePanel
* A container for the Inspector's HTML Tree Panel widget constructor function.
* @param aContext nsIDOMWindow (xulwindow)
* @param aIUI global InspectorUI object
*/
function TreePanel(aContext, aIUI) {
this._init(aContext, aIUI);
};
TreePanel.prototype = {
showTextNodesWithWhitespace: false,
id: "treepanel", // DO NOT LOCALIZE
_open: false,
/**
* The tree panel container element.
* @returns xul:panel|xul:vbox|null
* xul:panel is returned when the tree panel is not docked, or
* xul:vbox when when the tree panel is docked.
* null is returned when no container is available.
*/
get container()
{
return this.document.getElementById("inspector-tree-box");
},
/**
* Main TreePanel boot-strapping method. Initialize the TreePanel with the
* originating context and the InspectorUI global.
* @param aContext nsIDOMWindow (xulwindow)
* @param aIUI global InspectorUI object
*/
_init: function TP__init(aContext, aIUI)
{
this.IUI = aIUI;
this.window = aContext;
this.document = this.window.document;
this.button =
this.IUI.chromeDoc.getElementById("inspector-treepanel-toolbutton");
domplateUtils.setDOM(this.window);
this.DOMHelpers = new DOMHelpers(this.window);
let isOpen = this.isOpen.bind(this);
this.editingEvents = {};
},
/**
* Initialization function for the TreePanel.
*/
initializeIFrame: function TP_initializeIFrame()
{
if (!this.initializingTreePanel || this.treeLoaded) {
return;
}
this.treeBrowserDocument = this.treeIFrame.contentDocument;
this.treePanelDiv = this.treeBrowserDocument.createElement("div");
this.treeBrowserDocument.body.appendChild(this.treePanelDiv);
this.treePanelDiv.ownerPanel = this;
this.ioBox = new InsideOutBox(this, this.treePanelDiv);
this.ioBox.createObjectBox(this.IUI.win.document.documentElement);
this.treeLoaded = true;
this._boundTreeKeyPress = this.onTreeKeyPress.bind(this);
this.treeIFrame.addEventListener("keypress", this._boundTreeKeyPress.bind(this), true);
this.treeIFrame.addEventListener("click", this.onTreeClick.bind(this), false);
this.treeIFrame.addEventListener("dblclick", this.onTreeDblClick.bind(this), false);
this.treeIFrame.focus();
delete this.initializingTreePanel;
Services.obs.notifyObservers(null,
this.IUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, null);
if (this.pendingSelection) {
this.select(this.pendingSelection.node, this.pendingSelection.scroll);
delete this.pendingSelection;
}
},
/**
* Open the inspector's tree panel and initialize it.
*/
open: function TP_open()
{
if (this._open) {
return;
}
this._open = true;
this.button.setAttribute("checked", true);
this.initializingTreePanel = true;
this.treeIFrame = this.document.getElementById("inspector-tree-iframe");
if (!this.treeIFrame) {
this.treeIFrame = this.document.createElement("iframe");
this.treeIFrame.setAttribute("id", "inspector-tree-iframe");
this.treeIFrame.flex = 1;
this.treeIFrame.setAttribute("type", "content");
this.treeIFrame.setAttribute("context", "inspector-node-popup");
}
let treeBox = null;
treeBox = this.document.createElement("vbox");
treeBox.id = "inspector-tree-box";
treeBox.state = "open";
try {
treeBox.height =
Services.prefs.getIntPref("devtools.inspector.htmlHeight");
} catch(e) {
treeBox.height = 112;
}
treeBox.minHeight = 64;
this.splitter = this.document.createElement("splitter");
this.splitter.id = "inspector-tree-splitter";
this.splitter.className = "devtools-horizontal-splitter";
let container = this.document.getElementById("appcontent");
container.appendChild(this.splitter);
container.appendChild(treeBox);
treeBox.appendChild(this.treeIFrame);
this._boundLoadedInitializeTreePanel = function loadedInitializeTreePanel()
{
this.treeIFrame.removeEventListener("load",
this._boundLoadedInitializeTreePanel, true);
delete this._boundLoadedInitializeTreePanel;
this.initializeIFrame();
}.bind(this);
this.treeIFrame.addEventListener("load",
this._boundLoadedInitializeTreePanel, true);
let src = this.treeIFrame.getAttribute("src");
if (src != INSPECTOR_URI) {
this.treeIFrame.setAttribute("src", INSPECTOR_URI);
} else {
this.treeIFrame.contentWindow.location.reload();
}
},
/**
* Close the TreePanel.
*/
close: function TP_close()
{
this._open = false;
// Stop caring about the tree iframe load if it's in progress.
if (this._boundLoadedInitializeTreePanel) {
this.treeIFrame.removeEventListener("load",
this._boundLoadedInitializeTreePanel, true);
delete this._boundLoadedInitializeTreePanel;
}
this.button.removeAttribute("checked");
let treeBox = this.container;
Services.prefs.setIntPref("devtools.inspector.htmlHeight", treeBox.height);
let treeBoxParent = treeBox.parentNode;
treeBoxParent.removeChild(this.splitter);
treeBoxParent.removeChild(treeBox);
if (this.treePanelDiv) {
this.treePanelDiv.ownerPanel = null;
let parent = this.treePanelDiv.parentNode;
parent.removeChild(this.treePanelDiv);
this.treeIFrame.removeEventListener("keypress", this._boundTreeKeyPress, true);
delete this.treePanelDiv;
delete this.treeBrowserDocument;
}
if (this.ioBox) {
this.ioBox.destroy();
delete this.ioBox;
}
this.treeLoaded = false;
},
/**
* Is the TreePanel open?
* @returns boolean
*/
isOpen: function TP_isOpen()
{
return this._open;
},
/**
* Toggle the TreePanel.
*/
toggle: function TP_toggle()
{
this.isOpen() ? this.close() : this.open();
},
/**
* Create the ObjectBox for the given object.
* @param object nsIDOMNode
* @param isRoot boolean - Is this the root object?
* @returns InsideOutBox
*/
createObjectBox: function TP_createObjectBox(object, isRoot)
{
let tag = domplateUtils.getNodeTag(object);
if (tag)
return tag.replace({object: object}, this.treeBrowserDocument);
},
getParentObject: function TP_getParentObject(node)
{
return this.DOMHelpers.getParentObject(node);
},
getChildObject: function TP_getChildObject(node, index, previousSibling)
{
return this.DOMHelpers.getChildObject(node, index, previousSibling,
this.showTextNodesWithWhitespace);
},
getFirstChild: function TP_getFirstChild(node)
{
return this.DOMHelpers.getFirstChild(node);
},
getNextSibling: function TP_getNextSibling(node)
{
return this.DOMHelpers.getNextSibling(node);
},
/////////////////////////////////////////////////////////////////////
// Event Handling
/**
* Handle click events in the html tree panel.
* @param aEvent
* The mouse event.
*/
onTreeClick: function TP_onTreeClick(aEvent)
{
let node;
let target = aEvent.target;
let hitTwisty = false;
if (this.hasClass(target, "twisty")) {
node = this.getRepObject(aEvent.target.nextSibling);
hitTwisty = true;
} else {
node = this.getRepObject(aEvent.target);
}
if (node) {
if (hitTwisty) {
this.ioBox.toggleObject(node);
} else {
if (this.IUI.inspecting) {
this.IUI.stopInspecting(true);
} else {
this.navigate(node);
}
}
}
},
/**
* Handle double-click events in the html tree panel.
* Double-clicking an attribute name or value allows it to be edited.
* @param aEvent
* The mouse event.
*/
onTreeDblClick: function TP_onTreeDblClick(aEvent)
{
// if already editing an attribute value, double-clicking elsewhere
// in the tree is the same as a click, which dismisses the editor
if (this.editingContext)
this.closeEditor();
let target = aEvent.target;
if (!this.hasClass(target, "editable")) {
return;
}
let repObj = this.getRepObject(target);
if (this.hasClass(target, "nodeValue")) {
let attrName = target.getAttribute("data-attributeName");
let attrVal = target.innerHTML;
this.editAttribute(target, repObj, attrName, attrVal);
}
if (this.hasClass(target, "nodeName")) {
let attrName = target.innerHTML;
let attrValNode = target.nextSibling.nextSibling; // skip 2 (=)
if (attrValNode)
this.editAttribute(target, repObj, attrName, attrValNode.innerHTML);
}
},
navigate: function TP_navigate(node)
{
if (!node)
return;
this.ioBox.select(node, false, false, true);
if (this.IUI.highlighter.isNodeHighlightable(node)) {
this.IUI.select(node, true, false, "treepanel");
this.IUI.highlighter.highlight(node);
}
},
onTreeKeyPress: function TP_onTreeKeyPress(aEvent)
{
let handled = true;
switch(aEvent.keyCode) {
case Ci.nsIDOMKeyEvent.DOM_VK_LEFT:
this.ioBox.contractObjectBox(this.ioBox.selectedObjectBox);
break;
case Ci.nsIDOMKeyEvent.DOM_VK_RIGHT:
this.ioBox.expandObjectBox(this.ioBox.selectedObjectBox);
break;
case Ci.nsIDOMKeyEvent.DOM_VK_UP:
this.navigate(this.ioBox.previousObject());
break;
case Ci.nsIDOMKeyEvent.DOM_VK_DOWN:
this.navigate(this.ioBox.nextObject());
break;
case Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP:
this.navigate(this.ioBox.farPreviousObject(10));
break;
case Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN:
this.navigate(this.ioBox.farNextObject(10));
break;
case Ci.nsIDOMKeyEvent.DOM_VK_HOME:
this.navigate(this.ioBox.rootObject);
break;
default:
handled = false;
}
if (handled) {
aEvent.stopPropagation();
aEvent.preventDefault();
}
},
/**
* Starts the editor for an attribute name or value.
* @param aAttrObj
* The DOM object representing the attribute name or value in the HTML
* Tree.
* @param aRepObj
* The original DOM (target) object being inspected/edited
* @param aAttrName
* The name of the attribute being edited
* @param aAttrVal
* The current value of the attribute being edited
*/
editAttribute:
function TP_editAttribute(aAttrObj, aRepObj, aAttrName, aAttrVal)
{
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
let editorInput =
this.treeBrowserDocument.getElementById("attribute-editor-input");
let attrDims = aAttrObj.getBoundingClientRect();
// figure out actual viewable viewport dimensions (sans scrollbars)
let viewportWidth = this.treeBrowserDocument.documentElement.clientWidth;
let viewportHeight = this.treeBrowserDocument.documentElement.clientHeight;
// saves the editing context for use when the editor is saved/closed
this.editingContext = {
attrObj: aAttrObj,
repObj: aRepObj,
attrName: aAttrName,
attrValue: aAttrVal
};
// highlight attribute-value node in tree while editing
this.addClass(aAttrObj, "editingAttributeValue");
// show the editor
this.addClass(editor, "editing");
// offset the editor below the attribute-value node being edited
let editorVerticalOffset = 2;
// keep the editor comfortably within the bounds of the viewport
let editorViewportBoundary = 5;
// outer editor is sized based on the <input> box inside it
editorInput.style.width = Math.min(attrDims.width, viewportWidth -
editorViewportBoundary) + "px";
editorInput.style.height = Math.min(attrDims.height, viewportHeight -
editorViewportBoundary) + "px";
let editorDims = editor.getBoundingClientRect();
// calculate position for the editor according to the attribute node
let editorLeft = attrDims.left + this.treeIFrame.contentWindow.scrollX -
// center the editor against the attribute value
((editorDims.width - attrDims.width) / 2);
let editorTop = attrDims.top + this.treeIFrame.contentWindow.scrollY +
attrDims.height + editorVerticalOffset;
// but, make sure the editor stays within the visible viewport
editorLeft = Math.max(0, Math.min(
(this.treeIFrame.contentWindow.scrollX +
viewportWidth - editorDims.width),
editorLeft)
);
editorTop = Math.max(0, Math.min(
(this.treeIFrame.contentWindow.scrollY +
viewportHeight - editorDims.height),
editorTop)
);
// position the editor
editor.style.left = editorLeft + "px";
editor.style.top = editorTop + "px";
// set and select the text
if (this.hasClass(aAttrObj, "nodeValue")) {
editorInput.value = aAttrVal;
editorInput.select();
} else {
editorInput.value = aAttrName;
editorInput.select();
}
// listen for editor specific events
this.bindEditorEvent(editor, "click", function(aEvent) {
aEvent.stopPropagation();
});
this.bindEditorEvent(editor, "dblclick", function(aEvent) {
aEvent.stopPropagation();
});
this.bindEditorEvent(editor, "keypress",
this.handleEditorKeypress.bind(this));
// event notification
Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED,
null);
},
/**
* Handle binding an event handler for the editor.
* (saves the callback for easier unbinding later)
* @param aEditor
* The DOM object for the editor
* @param aEventName
* The name of the event to listen for
* @param aEventCallback
* The callback to bind to the event (and also to save for later
* unbinding)
*/
bindEditorEvent:
function TP_bindEditorEvent(aEditor, aEventName, aEventCallback)
{
this.editingEvents[aEventName] = aEventCallback;
aEditor.addEventListener(aEventName, aEventCallback, false);
},
/**
* Handle unbinding an event handler from the editor.
* (unbinds the previously bound and saved callback)
* @param aEditor
* The DOM object for the editor
* @param aEventName
* The name of the event being listened for
*/
unbindEditorEvent: function TP_unbindEditorEvent(aEditor, aEventName)
{
aEditor.removeEventListener(aEventName, this.editingEvents[aEventName],
false);
this.editingEvents[aEventName] = null;
},
/**
* Handle keypress events in the editor.
* @param aEvent
* The keyboard event.
*/
handleEditorKeypress: function TP_handleEditorKeypress(aEvent)
{
if (aEvent.which == this.window.KeyEvent.DOM_VK_RETURN) {
this.saveEditor();
aEvent.preventDefault();
aEvent.stopPropagation();
} else if (aEvent.keyCode == this.window.KeyEvent.DOM_VK_ESCAPE) {
this.closeEditor();
aEvent.preventDefault();
aEvent.stopPropagation();
}
},
/**
* Close the editor and cleanup.
*/
closeEditor: function TP_closeEditor()
{
if (!this.treeBrowserDocument) // already closed, bug 706092
return;
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
let editorInput =
this.treeBrowserDocument.getElementById("attribute-editor-input");
// remove highlight from attribute-value node in tree
this.removeClass(this.editingContext.attrObj, "editingAttributeValue");
// hide editor
this.removeClass(editor, "editing");
// stop listening for editor specific events
this.unbindEditorEvent(editor, "click");
this.unbindEditorEvent(editor, "dblclick");
this.unbindEditorEvent(editor, "keypress");
// clean up after the editor
editorInput.value = "";
editorInput.blur();
this.editingContext = null;
this.editingEvents = {};
// event notification
Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED,
null);
},
/**
* Commit the edits made in the editor, then close it.
*/
saveEditor: function TP_saveEditor()
{
let editorInput =
this.treeBrowserDocument.getElementById("attribute-editor-input");
let dirty = false;
if (this.hasClass(this.editingContext.attrObj, "nodeValue")) {
// set the new attribute value on the original target DOM element
this.editingContext.repObj.setAttribute(this.editingContext.attrName,
editorInput.value);
// update the HTML tree attribute value
this.editingContext.attrObj.innerHTML = editorInput.value;
dirty = true;
}
if (this.hasClass(this.editingContext.attrObj, "nodeName")) {
// remove the original attribute from the original target DOM element
this.editingContext.repObj.removeAttribute(this.editingContext.attrName);
// set the new attribute value on the original target DOM element
this.editingContext.repObj.setAttribute(editorInput.value,
this.editingContext.attrValue);
// update the HTML tree attribute value
this.editingContext.attrObj.innerHTML = editorInput.value;
dirty = true;
}
this.IUI.isDirty = dirty;
this.IUI.nodeChanged("treepanel");
// event notification
Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
null);
this.closeEditor();
},
/**
* Simple tree select method.
* @param aNode the DOM node in the content document to select.
* @param aScroll boolean scroll to the visible node?
*/
select: function TP_select(aNode, aScroll, aFrom)
{
if (this.ioBox) {
this.ioBox.select(aNode, true, aFrom != "treepanel", aScroll);
} else {
this.pendingSelection = { node: aNode, scroll: aScroll };
}
},
///////////////////////////////////////////////////////////////////////////
//// Utility functions
/**
* Does the given object have a class attribute?
* @param aNode
* the DOM node.
* @param aClass
* The class string.
* @returns boolean
*/
hasClass: function TP_hasClass(aNode, aClass)
{
if (!(aNode instanceof this.window.Element))
return false;
return aNode.classList.contains(aClass);
},
/**
* Add the class name to the given object.
* @param aNode
* the DOM node.
* @param aClass
* The class string.
*/
addClass: function TP_addClass(aNode, aClass)
{
if (aNode instanceof this.window.Element)
aNode.classList.add(aClass);
},
/**
* Remove the class name from the given object
* @param aNode
* the DOM node.
* @param aClass
* The class string.
*/
removeClass: function TP_removeClass(aNode, aClass)
{
if (aNode instanceof this.window.Element)
aNode.classList.remove(aClass);
},
/**
* Get the "repObject" from the HTML panel's domplate-constructed DOM node.
* In this system, a "repObject" is the Object being Represented by the box
* object. It is the "real" object that we're building our facade around.
*
* @param element
* The element in the HTML panel the user clicked.
* @returns either a real node or null
*/
getRepObject: function TP_getRepObject(element)
{
let target = null;
for (let child = element; child; child = child.parentNode) {
if (this.hasClass(child, "repTarget"))
target = child;
if (child.repObject) {
if (!target && this.hasClass(child.repObject, "repIgnore"))
break;
else
return child.repObject;
}
}
return null;
},
/**
* Remove a node box from the tree view.
* @param aElement
* The DOM node to remove from the HTML IOBox.
*/
deleteChildBox: function TP_deleteChildBox(aElement)
{
let childBox = this.ioBox.findObjectBox(aElement);
if (!childBox) {
return;
}
childBox.parentNode.removeChild(childBox);
},
/**
* Destructor function. Cleanup.
*/
destroy: function TP_destroy()
{
if (this.isOpen()) {
this.close();
}
domplateUtils.setDOM(null);
if (this.DOMHelpers) {
this.DOMHelpers.destroy();
delete this.DOMHelpers;
}
if (this.treePanelDiv) {
this.treePanelDiv.ownerPanel = null;
let parent = this.treePanelDiv.parentNode;
parent.removeChild(this.treePanelDiv);
delete this.treePanelDiv;
delete this.treeBrowserDocument;
}
if (this.treeIFrame) {
this.treeIFrame.removeEventListener("dblclick", this.onTreeDblClick, false);
this.treeIFrame.removeEventListener("click", this.onTreeClick, false);
let parent = this.treeIFrame.parentNode;
parent.removeChild(this.treeIFrame);
delete this.treeIFrame;
}
}
};
/**
* DOMHelpers
* Makes DOM traversal easier. Goes through iframes.
*
* @constructor
* @param nsIDOMWindow aWindow
* The content window, owning the document to traverse.
*/
function DOMHelpers(aWindow) {
this.window = aWindow;
};
DOMHelpers.prototype = {
getParentObject: function Helpers_getParentObject(node)
{
let parentNode = node ? node.parentNode : null;
if (!parentNode) {
// Documents have no parentNode; Attr, Document, DocumentFragment, Entity,
// and Notation. top level windows have no parentNode
if (node && node == this.window.Node.DOCUMENT_NODE) {
// document type
if (node.defaultView) {
let embeddingFrame = node.defaultView.frameElement;
if (embeddingFrame)
return embeddingFrame.parentNode;
}
}
// a Document object without a parentNode or window
return null; // top level has no parent
}
if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) {
if (parentNode.defaultView) {
return parentNode.defaultView.frameElement;
}
// parent is document element, but no window at defaultView.
return null;
}
if (!parentNode.localName)
return null;
return parentNode;
},
getChildObject: function Helpers_getChildObject(node, index, previousSibling,
showTextNodesWithWhitespace)
{
if (!node)
return null;
if (node.contentDocument) {
// then the node is a frame
if (index == 0) {
return node.contentDocument.documentElement; // the node's HTMLElement
}
return null;
}
if (node instanceof this.window.GetSVGDocument) {
let svgDocument = node.getSVGDocument();
if (svgDocument) {
// then the node is a frame
if (index == 0) {
return svgDocument.documentElement; // the node's SVGElement
}
return null;
}
}
let child = null;
if (previousSibling) // then we are walking
child = this.getNextSibling(previousSibling);
else
child = this.getFirstChild(node);
if (showTextNodesWithWhitespace)
return child;
for (; child; child = this.getNextSibling(child)) {
if (!this.isWhitespaceText(child))
return child;
}
return null; // we have no children worth showing.
},
getFirstChild: function Helpers_getFirstChild(node)
{
let SHOW_ALL = Components.interfaces.nsIDOMNodeFilter.SHOW_ALL;
this.treeWalker = node.ownerDocument.createTreeWalker(node,
SHOW_ALL, null, false);
return this.treeWalker.firstChild();
},
getNextSibling: function Helpers_getNextSibling(node)
{
let next = this.treeWalker.nextSibling();
if (!next)
delete this.treeWalker;
return next;
},
isWhitespaceText: function Helpers_isWhitespaceText(node)
{
return node.nodeType == this.window.Node.TEXT_NODE &&
!/[^\s]/.exec(node.nodeValue);
},
destroy: function Helpers_destroy()
{
delete this.window;
delete this.treeWalker;
}
};

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

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

@ -1,18 +0,0 @@
<!-- 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/. -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="chrome://browser/skin/devtools/htmlpanel.css" type="text/css"/>
</head>
<body role="application">
<div id="attribute-editor">
<input id="attribute-editor-input" />
</div>
</body>
</html>

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

@ -13,12 +13,12 @@ var EXPORTED_SYMBOLS = ["InspectorUI"];
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/TreePanel.jsm");
Cu.import("resource:///modules/devtools/MarkupView.jsm");
Cu.import("resource:///modules/highlighter.jsm");
Cu.import("resource:///modules/devtools/LayoutView.jsm");
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
Cu.import("resource:///modules/devtools/EventEmitter.jsm");
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
// Inspector notifications dispatched through the nsIObserverService.
const INSPECTOR_NOTIFICATIONS = {

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

@ -3,11 +3,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
content/browser/inspector.html (highlighter/inspector.html)
content/browser/devtools/markup-view.xhtml (markupview/markup-view.xhtml)
content/browser/devtools/markup-view.css (markupview/markup-view.css)
content/browser/NetworkPanel.xhtml (webconsole/NetworkPanel.xhtml)
content/browser/devtools/HUDService-content.js (webconsole/HUDService-content.js)
content/browser/devtools/webconsole.js (webconsole/webconsole.js)
* content/browser/devtools/webconsole.xul (webconsole/webconsole.xul)
* content/browser/scratchpad.xul (scratchpad/scratchpad.xul)

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

@ -129,6 +129,8 @@ LayoutView.prototype = {
this.iframe.removeEventListener("keypress", this.bound_handleKeypress, true);
this.inspector.chromeWindow.removeEventListener("message", this.onMessage, true);
this.close();
this.sizeHeadingLabel = null;
this.sizeLabel = null;
this.iframe = null;
this.view.parentNode.removeChild(this.view);
},
@ -159,6 +161,10 @@ LayoutView.prototype = {
this.documentReady = true;
this.doc = this.iframe.contentDocument;
// Save reference to the labels displaying size of the node.
this.sizeLabel = this.doc.querySelector(".size > span");
this.sizeHeadingLabel = this.doc.getElementById("element-size");
// We can't do that earlier because open() and close() need to do stuff
// inside the iframe.
@ -299,10 +305,9 @@ LayoutView.prototype = {
let width = Math.round(clientRect.width);
let height = Math.round(clientRect.height);
let elt = this.doc.querySelector("#element-size");
let newLabel = width + "x" + height;
if (elt.textContent != newLabel) {
elt.textContent = newLabel;
if (this.sizeHeadingLabel.textContent != newLabel) {
this.sizeHeadingLabel.textContent = newLabel;
}
// If the view is closed, no need to do anything more.
@ -312,7 +317,6 @@ LayoutView.prototype = {
let style = this.browser.contentWindow.getComputedStyle(node);;
for (let i in this.map) {
let selector = this.map[i].selector;
let property = this.map[i].property;
this.map[i].value = parseInt(style.getPropertyValue(property));
}
@ -326,6 +330,10 @@ LayoutView.prototype = {
for (let i in this.map) {
let selector = this.map[i].selector;
let span = this.doc.querySelector(selector);
if (span.textContent.length > 0 &&
span.textContent == this.map[i].value) {
continue;
}
span.textContent = this.map[i].value;
}
@ -335,7 +343,10 @@ LayoutView.prototype = {
height -= this.map.borderTop.value + this.map.borderBottom.value +
this.map.paddingTop.value + this.map.paddingBottom.value;
this.doc.querySelector(".size > span").textContent = width + "x" + height;
let newValue = width + "x" + height;
if (this.sizeLabel.textContent != newValue) {
this.sizeLabel.textContent = newValue;
}
},
/**

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

@ -10,6 +10,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/devtools/FloatingScrollbars.jsm");
Cu.import("resource:///modules/devtools/EventEmitter.jsm");
var EXPORTED_SYMBOLS = ["ResponsiveUIManager"];
@ -67,6 +68,13 @@ let ResponsiveUIManager = {
default:
}
},
get events() {
if (!this._eventEmitter) {
this._eventEmitter = new EventEmitter();
}
return this._eventEmitter;
},
}
let presets = [
@ -162,6 +170,7 @@ function ResponsiveUI(aWindow, aTab)
} catch(e) {}
switchToFloatingScrollbars(this.tab);
ResponsiveUIManager.events.emit("on", this.tab, this);
}
ResponsiveUI.prototype = {
@ -215,6 +224,7 @@ ResponsiveUI.prototype = {
this.stack.removeAttribute("responsivemode");
delete this.tab.__responsiveUI;
ResponsiveUIManager.events.emit("off", this.tab, this);
},
/**

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

@ -45,15 +45,23 @@ include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_responsiveui.js \
browser_responsiveruleview.js \
browser_responsive_cmd.js \
browser_responsivecomputedview.js \
browser_responsiveuiaddcustompreset.js \
head.js \
helpers.js \
$(NULL)
# Disabled on Mac for frequent intermittent failures
ifneq ($(OS_ARCH), Darwin)
_BROWSER_FILES += \
browser_responsiveui.js \
browser_responsiveuiaddcustompreset.js \
$(NULL)
else
$(warning browser_responsiveui.js is disabled on OS X for intermittent failures. Bug 798772) \
$(warning browser_responsiveuiaddcustompreset.js is disabled on OS X for intermittent failures. Bugs 798775, 798777)
endif
libs:: $(_BROWSER_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

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

@ -3,6 +3,7 @@
function test() {
let instance, widthBeforeClose, heightBeforeClose;
let events = ResponsiveUI.ResponsiveUIManager.events;
waitForExplicitFinish();
@ -16,8 +17,8 @@ function test() {
function startTest() {
document.getElementById("Tools:ResponsiveUI").removeAttribute("disabled");
events.once("on", function() {executeSoon(onUIOpen)});
synthesizeKeyFromKeyTag("key_responsiveUI");
executeSoon(onUIOpen);
}
function onUIOpen() {
@ -118,14 +119,13 @@ function test() {
widthBeforeClose = content.innerWidth;
heightBeforeClose = content.innerHeight;
events.once("off", function() {executeSoon(restart)});
EventUtils.synthesizeKey("VK_ESCAPE", {});
executeSoon(restart);
}
function restart() {
events.once("on", function() {executeSoon(onUIOpen2)});
synthesizeKeyFromKeyTag("key_responsiveUI");
executeSoon(onUIOpen2);
}
function onUIOpen2() {
@ -138,8 +138,8 @@ function test() {
is(content.innerWidth, widthBeforeClose, "width restored.");
is(content.innerHeight, heightBeforeClose, "height restored.");
events.once("off", function() {executeSoon(finishUp)});
EventUtils.synthesizeKey("VK_ESCAPE", {});
executeSoon(finishUp);
}
function finishUp() {

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

@ -0,0 +1,124 @@
/* 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/. */
const EXPORTED_SYMBOLS = ["DOMHelpers"];
/**
* DOMHelpers
* Makes DOM traversal easier. Goes through iframes.
*
* @constructor
* @param nsIDOMWindow aWindow
* The content window, owning the document to traverse.
*/
function DOMHelpers(aWindow) {
this.window = aWindow;
};
DOMHelpers.prototype = {
getParentObject: function Helpers_getParentObject(node)
{
let parentNode = node ? node.parentNode : null;
if (!parentNode) {
// Documents have no parentNode; Attr, Document, DocumentFragment, Entity,
// and Notation. top level windows have no parentNode
if (node && node == this.window.Node.DOCUMENT_NODE) {
// document type
if (node.defaultView) {
let embeddingFrame = node.defaultView.frameElement;
if (embeddingFrame)
return embeddingFrame.parentNode;
}
}
// a Document object without a parentNode or window
return null; // top level has no parent
}
if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) {
if (parentNode.defaultView) {
return parentNode.defaultView.frameElement;
}
// parent is document element, but no window at defaultView.
return null;
}
if (!parentNode.localName)
return null;
return parentNode;
},
getChildObject: function Helpers_getChildObject(node, index, previousSibling,
showTextNodesWithWhitespace)
{
if (!node)
return null;
if (node.contentDocument) {
// then the node is a frame
if (index == 0) {
return node.contentDocument.documentElement; // the node's HTMLElement
}
return null;
}
if (node instanceof this.window.GetSVGDocument) {
let svgDocument = node.getSVGDocument();
if (svgDocument) {
// then the node is a frame
if (index == 0) {
return svgDocument.documentElement; // the node's SVGElement
}
return null;
}
}
let child = null;
if (previousSibling) // then we are walking
child = this.getNextSibling(previousSibling);
else
child = this.getFirstChild(node);
if (showTextNodesWithWhitespace)
return child;
for (; child; child = this.getNextSibling(child)) {
if (!this.isWhitespaceText(child))
return child;
}
return null; // we have no children worth showing.
},
getFirstChild: function Helpers_getFirstChild(node)
{
let SHOW_ALL = Components.interfaces.nsIDOMNodeFilter.SHOW_ALL;
this.treeWalker = node.ownerDocument.createTreeWalker(node,
SHOW_ALL, null, false);
return this.treeWalker.firstChild();
},
getNextSibling: function Helpers_getNextSibling(node)
{
let next = this.treeWalker.nextSibling();
if (!next)
delete this.treeWalker;
return next;
},
isWhitespaceText: function Helpers_isWhitespaceText(node)
{
return node.nodeType == this.window.Node.TEXT_NODE &&
!/[^\s]/.exec(node.nodeValue);
},
destroy: function Helpers_destroy()
{
delete this.window;
delete this.treeWalker;
}
};

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

@ -7,9 +7,7 @@
const EXPORTED_SYMBOLS = [ "DeveloperToolbar" ];
const NS_XHTML = "http://www.w3.org/1999/xhtml";
const WEBCONSOLE_CONTENT_SCRIPT_URL =
"chrome://browser/content/devtools/HUDService-content.js";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
@ -26,6 +24,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "gcli",
XPCOMUtils.defineLazyModuleGetter(this, "CmdCommands",
"resource:///modules/devtools/CmdCmd.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PageErrorListener",
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
/**
* Due to a number of panel bugs we need a way to check if we are running on
* Linux. See the comments for TooltipPanel and OutputPanel for further details.
@ -56,7 +57,8 @@ function DeveloperToolbar(aChromeWindow, aToolbarElement)
this._lastState = NOTIFICATIONS.HIDE;
this._pendingShowCallback = undefined;
this._pendingHide = false;
this._errorsCount = {};
this._errorsCount = Object.create(null);
this._errorListeners = Object.create(null);
this._webConsoleButton = this._doc
.getElementById("developer-toolbar-webconsole");
@ -88,9 +90,6 @@ const NOTIFICATIONS = {
*/
DeveloperToolbar.prototype.NOTIFICATIONS = NOTIFICATIONS;
DeveloperToolbar.prototype._contentMessageListeners =
["WebConsole:CachedMessages", "WebConsole:PageError"];
/**
* Is the toolbar open?
*/
@ -285,21 +284,18 @@ DeveloperToolbar.prototype._initErrorsCount = function DT__initErrorsCount(aTab)
return;
}
let messageManager = aTab.linkedBrowser.messageManager;
messageManager.loadFrameScript(WEBCONSOLE_CONTENT_SCRIPT_URL, true);
let window = aTab.linkedBrowser.contentWindow;
let listener = new PageErrorListener(window, {
onPageError: this._onPageError.bind(this, tabId),
});
listener.init();
this._errorListeners[tabId] = listener;
this._errorsCount[tabId] = 0;
this._contentMessageListeners.forEach(function(aName) {
messageManager.addMessageListener(aName, this);
}, this);
let messages = listener.getCachedMessages();
messages.forEach(this._onPageError.bind(this, tabId));
let message = {
features: ["PageError"],
cachedMessages: ["PageError"],
};
this.sendMessageToTab(aTab, "WebConsole:Init", message);
this._updateErrorsCount();
};
@ -319,14 +315,10 @@ DeveloperToolbar.prototype._stopErrorsCount = function DT__stopErrorsCount(aTab)
return;
}
this.sendMessageToTab(aTab, "WebConsole:Destroy", {});
let messageManager = aTab.linkedBrowser.messageManager;
this._contentMessageListeners.forEach(function(aName) {
messageManager.removeMessageListener(aName, this);
}, this);
this._errorListeners[tabId].destroy();
delete this._errorListeners[tabId];
delete this._errorsCount[tabId];
this._updateErrorsCount();
};
@ -434,61 +426,13 @@ DeveloperToolbar.prototype.handleEvent = function DT_handleEvent(aEvent)
};
/**
* The handler of messages received from the nsIMessageManager.
*
* @param object aMessage the message received from the content process.
*/
DeveloperToolbar.prototype.receiveMessage = function DT_receiveMessage(aMessage)
{
if (!aMessage.json || !(aMessage.json.hudId in this._errorsCount)) {
return;
}
let tabId = aMessage.json.hudId;
let errors = this._errorsCount[tabId];
switch (aMessage.name) {
case "WebConsole:PageError":
this._onPageError(tabId, aMessage.json.pageError);
break;
case "WebConsole:CachedMessages":
aMessage.json.messages.forEach(this._onPageError.bind(this, tabId));
break;
}
if (errors != this._errorsCount[tabId]) {
this._updateErrorsCount(tabId);
}
};
/**
* Send a message to the content process using the nsIMessageManager of the
* given tab.
*
* @param nsIDOMNode aTab the tab you want to send a message to.
* @param string aName the name of the message you want to send.
* @param object aMessage the message to send.
*/
DeveloperToolbar.prototype.sendMessageToTab =
function DT_sendMessageToTab(aTab, aName, aMessage)
{
let tabId = aTab.linkedPanel;
aMessage.hudId = tabId;
if (!("id" in aMessage)) {
aMessage.id = "DevToolbar-" + this.sequenceId;
}
aTab.linkedBrowser.messageManager.sendAsyncMessage(aName, aMessage);
};
/**
* Process a "WebConsole:PageError" message received from the given tab. This
* method counts the JavaScript exceptions received.
* Count a page error received for the currently selected tab. This
* method counts the JavaScript exceptions received and CSS errors/warnings.
*
* @private
* @param string aTabId the ID of the tab from where the page error comes.
* @param object aPageError the page error object received from the content
* process.
* @param object aPageError the page error object received from the
* PageErrorListener.
*/
DeveloperToolbar.prototype._onPageError =
function DT__onPageError(aTabId, aPageError)
@ -501,6 +445,7 @@ function DT__onPageError(aTabId, aPageError)
}
this._errorsCount[aTabId]++;
this._updateErrorsCount(aTabId);
};
/**
@ -638,7 +583,6 @@ function OutputPanel(aChromeDoc, aInput, aLoadCallback)
this._frame = aChromeDoc.createElementNS(NS_XHTML, "iframe");
this._frame.id = "gcli-output-frame";
this._frame.setAttribute("src", "chrome://browser/content/devtools/commandlineoutput.xhtml");
this._frame.setAttribute("flex", "1");
this._panel.appendChild(this._frame);
this.displayedOutput = undefined;
@ -674,6 +618,33 @@ OutputPanel.prototype._onload = function OP_onload()
}
};
/**
* Determine the scrollbar width in the current document.
*
* @private
*/
Object.defineProperty(OutputPanel.prototype, 'scrollbarWidth', {
get: function() {
if (this.__scrollbarWidth) {
return this.__scrollbarWidth;
}
let hbox = this.document.createElementNS(XUL_NS, "hbox");
hbox.setAttribute("style", "height: 0%; overflow: hidden");
let scrollbar = this.document.createElementNS(XUL_NS, "scrollbar");
scrollbar.setAttribute("orient", "vertical");
hbox.appendChild(scrollbar);
this.document.documentElement.appendChild(hbox);
this.__scrollbarWidth = scrollbar.clientWidth;
this.document.documentElement.removeChild(hbox);
return this.__scrollbarWidth;
},
enumerable: true
});
/**
* Prevent the popup from hiding if it is not permitted via this.canHide.
*/
@ -691,17 +662,15 @@ OutputPanel.prototype._onpopuphiding = function OP_onpopuphiding(aEvent)
*/
OutputPanel.prototype.show = function OP_show()
{
// This is nasty, but displaying the panel causes it to re-flow, which can
// change the size it should be, so we need to resize the iframe after the
// panel has displayed
this._panel.ownerDocument.defaultView.setTimeout(function() {
this._resize();
}.bind(this), 0);
if (isLinux) {
this.canHide = false;
}
// We need to reset the iframe size in order for future size calculations to
// be correct
this._frame.style.minHeight = this._frame.style.maxHeight = 0;
this._frame.style.minWidth = 0;
this._panel.openPopup(this._input, "before_start", 0, 0, false, false, null);
this._resize();
@ -718,8 +687,38 @@ OutputPanel.prototype._resize = function CLP_resize()
return
}
this._frame.height = this.document.body.scrollHeight;
this._frame.width = this._input.clientWidth + 2;
// Set max panel width to match any content with a max of the width of the
// browser window.
let maxWidth = this._panel.ownerDocument.documentElement.clientWidth;
let width = Math.min(maxWidth, this.document.documentElement.scrollWidth);
// Add scrollbar width to content size in case a scrollbar is needed.
width += this.scrollbarWidth;
// Set the width of the iframe.
this._frame.style.minWidth = width + "px";
// browserAdjustment is used to correct the panel height according to the
// browsers borders etc.
const browserAdjustment = 15;
// Set max panel height to match any content with a max of the height of the
// browser window.
let maxHeight =
this._panel.ownerDocument.documentElement.clientHeight - browserAdjustment;
let height = Math.min(maxHeight, this.document.documentElement.scrollHeight);
// Set the height of the iframe. Setting iframe.height does not work.
this._frame.style.minHeight = this._frame.style.maxHeight = height + "px";
// Set the height and width of the panel to match the iframe.
this._panel.sizeTo(width, height);
// Move the panel to the correct position in the case that it has been
// positioned incorrectly.
let screenX = this._input.boxObject.screenX;
let screenY = this._toolbar.boxObject.screenY;
this._panel.moveTo(screenX, screenY - height);
};
/**

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

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

@ -47,8 +47,11 @@ function test() {
function addErrors() {
expectUncaughtException();
let button = content.document.querySelector("button");
EventUtils.synthesizeMouse(button, 2, 2, {}, content);
waitForFocus(function() {
let button = content.document.querySelector("button");
EventUtils.synthesizeMouse(button, 2, 2, {}, content);
}, content);
waitForValue({
name: "button shows one more error after click in page",

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

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

@ -18,12 +18,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
"resource:///modules/WebConsoleUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "l10n", function() {
return WebConsoleUtils.l10n;
});
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
var EXPORTED_SYMBOLS = ["HUDService"];
@ -59,9 +57,6 @@ const MINIMUM_PAGE_HEIGHT = 50;
// The default console height, as a ratio from the content window inner height.
const DEFAULT_CONSOLE_HEIGHT = 0.33;
// This script is inserted into the content process.
const CONTENT_SCRIPT_URL = "chrome://browser/content/devtools/HUDService-content.js";
// points to the file to load in the Web Console iframe.
const UI_IFRAME_URL = "chrome://browser/content/devtools/webconsole.xul";
@ -172,7 +167,10 @@ HUD_SERVICE.prototype =
let hud = this.getHudReferenceById(hudId);
let document = hud.chromeDocument;
hud.destroy();
hud.destroy(function() {
let id = WebConsoleUtils.supportsString(hudId);
Services.obs.notifyObservers(id, "web-console-destroyed", null);
});
delete this.hudReferences[hudId];
@ -199,9 +197,6 @@ HUD_SERVICE.prototype =
contentWindow.focus();
HeadsUpDisplayUICommands.refreshCommand();
let id = WebConsoleUtils.supportsString(hudId);
Services.obs.notifyObservers(id, "web-console-destroyed", null);
},
/**
@ -502,9 +497,11 @@ HUD_SERVICE.prototype =
function WebConsole(aTab)
{
this.tab = aTab;
this.chromeDocument = this.tab.ownerDocument;
this.chromeWindow = this.chromeDocument.defaultView;
this.hudId = "hud_" + this.tab.linkedPanel;
this._onIframeLoad = this._onIframeLoad.bind(this);
this._asyncRequests = {};
this._init();
this._initUI();
}
WebConsole.prototype = {
@ -514,6 +511,9 @@ WebConsole.prototype = {
*/
tab: null,
chromeWindow: null,
chromeDocument: null,
/**
* Getter for HUDService.lastFinishedRequestCallback.
*
@ -522,41 +522,12 @@ WebConsole.prototype = {
*/
get lastFinishedRequestCallback() HUDService.lastFinishedRequestCallback,
/**
* Track callback functions registered for specific async requests sent to
* the content process.
*
* @private
* @type object
*/
_asyncRequests: null,
/**
* Message names that the HUD listens for. These messages come from the remote
* Web Console content script.
*
* @private
* @type array
*/
_messageListeners: ["JSTerm:EvalObject", "WebConsole:ConsoleAPI",
"WebConsole:CachedMessages", "WebConsole:PageError", "JSTerm:EvalResult",
"JSTerm:AutocompleteProperties", "JSTerm:ClearOutput",
"JSTerm:InspectObject", "WebConsole:NetworkActivity",
"WebConsole:FileActivity", "WebConsole:LocationChange",
"JSTerm:NonNativeConsoleAPI"],
/**
* The xul:panel that holds the Web Console when it is positioned as a window.
* @type nsIDOMElement
*/
consolePanel: null,
/**
* The current tab location.
* @type string
*/
contentLocation: "",
/**
* Getter for the xul:popupset that holds any popups we open.
* @type nsIDOMElement
@ -577,22 +548,6 @@ WebConsole.prototype = {
get gViewSourceUtils() this.chromeWindow.gViewSourceUtils,
/**
* Initialize the Web Console instance.
* @private
*/
_init: function WC__init()
{
this.chromeDocument = this.tab.ownerDocument;
this.chromeWindow = this.chromeDocument.defaultView;
this.messageManager = this.tab.linkedBrowser.messageManager;
this.hudId = "hud_" + this.tab.linkedPanel;
this.notificationBox = this.chromeDocument
.getElementById(this.tab.linkedPanel);
this._initUI();
},
/**
* Initialize the Web Console UI. This method sets up the iframe.
* @private
@ -627,7 +582,6 @@ WebConsole.prototype = {
this.iframeWindow = this.iframe.contentWindow.wrappedJSObject;
this.ui = new this.iframeWindow.WebConsoleFrame(this, position);
this._setupMessageManager();
},
/**
@ -772,8 +726,8 @@ WebConsole.prototype = {
*/
getPanelTitle: function WC_getPanelTitle()
{
return l10n.getFormatStr("webConsoleWindowTitleAndURL",
[this.contentLocation]);
let url = this.ui ? this.ui.contentLocation : "";
return l10n.getFormatStr("webConsoleWindowTitleAndURL", [url]);
},
positions: {
@ -806,7 +760,7 @@ WebConsole.prototype = {
// get the node position index
let nodeIdx = this.positions[aPosition];
let nBox = this.notificationBox;
let nBox = this.chromeDocument.getElementById(this.tab.linkedPanel);
let node = nBox.childNodes[nodeIdx];
// check to see if console is already positioned in aPosition
@ -903,126 +857,24 @@ WebConsole.prototype = {
/**
* The clear output button handler.
* @private
*/
onClearButton: function WC_onClearButton()
_onClearButton: function WC__onClearButton()
{
this.ui.jsterm.clearOutput(true);
this.chromeWindow.DeveloperToolbar.resetErrorsCount(this.tab);
},
/**
* Setup the message manager used to communicate with the Web Console content
* script. This method loads the content script, adds the message listeners
* and initializes the connection to the content script.
*
* @private
*/
_setupMessageManager: function WC__setupMessageManager()
{
this.messageManager.loadFrameScript(CONTENT_SCRIPT_URL, true);
this._messageListeners.forEach(function(aName) {
this.messageManager.addMessageListener(aName, this.ui);
}, this);
let message = {
features: ["ConsoleAPI", "JSTerm", "PageError", "NetworkMonitor",
"LocationChange"],
cachedMessages: ["ConsoleAPI", "PageError"],
NetworkMonitor: { monitorFileActivity: true },
JSTerm: { notifyNonNativeConsoleAPI: true },
preferences: {
"NetworkMonitor.saveRequestAndResponseBodies":
this.ui.saveRequestAndResponseBodies,
},
};
this.sendMessageToContent("WebConsole:Init", message);
},
/**
* Callback method for when the Web Console initialization is complete. For
* now this method sends the web-console-created notification using the
* nsIObserverService.
*
* @private
*/
_onInitComplete: function WC__onInitComplete()
{
let id = WebConsoleUtils.supportsString(this.hudId);
Services.obs.notifyObservers(id, "web-console-created", null);
},
/**
* Handler for messages that have an associated callback function. The
* this.sendMessageToContent() allows one to provide a function to be invoked
* when the content script replies to the message previously sent. This is the
* method that invokes the callback.
*
* @see this.sendMessageToContent
* @private
* @param object aResponse
* Message object received from the content script.
*/
_receiveMessageWithCallback:
function WC__receiveMessageWithCallback(aResponse)
{
if (aResponse.id in this._asyncRequests) {
let request = this._asyncRequests[aResponse.id];
request.callback(aResponse, request.message);
delete this._asyncRequests[aResponse.id];
}
else {
Cu.reportError("receiveMessageWithCallback response for stale request " +
"ID " + aResponse.id);
}
},
/**
* Send a message to the content script.
*
* @param string aName
* The name of the message you want to send.
*
* @param object aMessage
* The message object you want to send. This object needs to have no
* cyclic references and it needs to be JSON-stringifiable.
*
* @param function [aCallback]
* Optional function you want to have called when the content script
* replies to your message. Your callback receives two arguments:
* (1) the response object from the content script and (2) the message
* you sent to the content script (which is aMessage here).
*/
sendMessageToContent:
function WC_sendMessageToContent(aName, aMessage, aCallback)
{
aMessage.hudId = this.hudId;
if (!("id" in aMessage)) {
aMessage.id = "HUDChrome-" + HUDService.sequenceId();
}
if (aCallback) {
this._asyncRequests[aMessage.id] = {
name: aName,
message: aMessage,
callback: aCallback,
};
}
this.messageManager.sendAsyncMessage(aName, aMessage);
},
/**
* Handler for the "WebConsole:LocationChange" message. If the Web Console is
* Handler for page location changes. If the Web Console is
* opened in a panel the panel title is updated.
*
* @param object aMessage
* The message received from the content script. It needs to hold two
* properties: location and title.
* @param string aURI
* New page location.
* @param string aTitle
* New page title.
*/
onLocationChange: function WC_onLocationChange(aMessage)
onLocationChange: function WC_onLocationChange(aURI, aTitle)
{
this.contentLocation = aMessage.location;
if (this.consolePanel) {
this.consolePanel.label = this.getPanelTitle();
}
@ -1051,15 +903,13 @@ WebConsole.prototype = {
/**
* Destroy the object. Call this method to avoid memory leaks when the Web
* Console is closed.
*
* @param function [aOnDestroy]
* Optional function to invoke when the Web Console instance is
* destroyed.
*/
destroy: function WC_destroy()
destroy: function WC_destroy(aOnDestroy)
{
this.sendMessageToContent("WebConsole:Destroy", {});
this._messageListeners.forEach(function(aName) {
this.messageManager.removeMessageListener(aName, this.ui);
}, this);
// Make sure that the console panel does not try to call
// deactivateHUDForContext() again.
this.consoleWindowUnregisterOnHide = false;
@ -1072,24 +922,31 @@ WebConsole.prototype = {
}
}
let onDestroy = function WC_onDestroyUI() {
// Remove the iframe and the consolePanel if the Web Console is inside a
// floating panel.
if (this.consolePanel && this.consolePanel.parentNode) {
this.consolePanel.hidePopup();
this.consolePanel.parentNode.removeChild(this.consolePanel);
this.consolePanel = null;
}
if (this.iframe.parentNode) {
this.iframe.parentNode.removeChild(this.iframe);
}
if (this.splitter.parentNode) {
this.splitter.parentNode.removeChild(this.splitter);
}
aOnDestroy && aOnDestroy();
}.bind(this);
if (this.ui) {
this.ui.destroy();
this.ui.destroy(onDestroy);
}
// Remove the iframe and the consolePanel if the Web Console is inside a
// floating panel.
if (this.consolePanel && this.consolePanel.parentNode) {
this.consolePanel.hidePopup();
this.consolePanel.parentNode.removeChild(this.consolePanel);
this.consolePanel = null;
}
if (this.iframe.parentNode) {
this.iframe.parentNode.removeChild(this.iframe);
}
if (this.splitter.parentNode) {
this.splitter.parentNode.removeChild(this.splitter);
else {
onDestroy();
}
},
};

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

@ -13,10 +13,8 @@ include $(DEPTH)/config/autoconf.mk
EXTRA_JS_MODULES = \
HUDService.jsm \
PropertyPanel.jsm \
NetworkHelper.jsm \
NetworkPanel.jsm \
AutocompletePopup.jsm \
WebConsoleUtils.jsm \
$(NULL)
TEST_DIRS = test

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

@ -16,17 +16,16 @@ XPCOMUtils.defineLazyServiceGetter(this, "mimeService", "@mozilla.org/mime;1",
"nsIMIMEService");
XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
"resource:///modules/NetworkHelper.jsm");
"resource://gre/modules/devtools/NetworkHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
"resource:///modules/WebConsoleUtils.jsm");
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "l10n", function() {
return WebConsoleUtils.l10n;
});
const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
var EXPORTED_SYMBOLS = ["NetworkPanel"];
@ -67,7 +66,6 @@ function NetworkPanel(aParent, aHttpActivity)
self.panel.parentNode.removeChild(self.panel);
self.panel = null;
self.iframe = null;
self.document = null;
self.httpActivity = null;
if (self.linkNode) {
@ -77,9 +75,17 @@ function NetworkPanel(aParent, aHttpActivity)
}, false);
// Set the document object and update the content once the panel is loaded.
this.panel.addEventListener("load", function onLoad() {
self.panel.removeEventListener("load", onLoad, true);
self.document = self.iframe.contentWindow.document;
this.iframe.addEventListener("load", function onLoad() {
if (!self.iframe) {
return;
}
self.iframe.removeEventListener("load", onLoad, true);
self.update();
}, true);
this.panel.addEventListener("popupshown", function onPopupShown() {
self.panel.removeEventListener("popupshown", onPopupShown, true);
self.update();
}, true);
@ -95,12 +101,6 @@ function NetworkPanel(aParent, aHttpActivity)
NetworkPanel.prototype =
{
/**
* Callback is called once the NetworkPanel is processed completely. Used by
* unit tests.
*/
isDoneCallback: null,
/**
* The current state of the output.
*/
@ -119,6 +119,20 @@ NetworkPanel.prototype =
_contentType: null,
/**
* Function callback invoked whenever the panel content is updated. This is
* used only by tests.
*
* @private
* @type function
*/
_onUpdate: null,
get document() {
return this.iframe && this.iframe.contentWindow ?
this.iframe.contentWindow.document : null;
},
/**
* Small helper function that is nearly equal to l10n.getFormatStr
* except that it prefixes aName with "NetworkPanel.".
@ -151,9 +165,8 @@ NetworkPanel.prototype =
return this._contentType;
}
let entry = this.httpActivity.log.entries[0];
let request = entry.request;
let response = entry.response;
let request = this.httpActivity.request;
let response = this.httpActivity.response;
let contentType = "";
let types = response.content ?
@ -237,7 +250,7 @@ NetworkPanel.prototype =
*/
get _isResponseCached()
{
return this.httpActivity.log.entries[0].response.status == 304;
return this.httpActivity.response.status == 304;
},
/**
@ -248,7 +261,7 @@ NetworkPanel.prototype =
*/
get _isRequestBodyFormData()
{
let requestBody = this.httpActivity.log.entries[0].request.postData.text;
let requestBody = this.httpActivity.request.postData.text;
return this._fromDataRegExp.test(requestBody);
},
@ -342,9 +355,8 @@ NetworkPanel.prototype =
*/
_displayRequestHeader: function NP__displayRequestHeader()
{
let entry = this.httpActivity.log.entries[0];
let request = entry.request;
let requestTime = new Date(entry.startedDateTime);
let request = this.httpActivity.request;
let requestTime = new Date(this.httpActivity.startedDateTime);
this._appendTextNode("headUrl", request.url);
this._appendTextNode("headMethod", request.method);
@ -365,8 +377,9 @@ NetworkPanel.prototype =
*
* @returns void
*/
_displayRequestBody: function NP__displayRequestBody() {
let postData = this.httpActivity.log.entries[0].request.postData;
_displayRequestBody: function NP__displayRequestBody()
{
let postData = this.httpActivity.request.postData;
this._displayNode("requestBody");
this._appendTextNode("requestBodyContent", postData.text);
},
@ -377,8 +390,9 @@ NetworkPanel.prototype =
*
* @returns void
*/
_displayRequestForm: function NP__processRequestForm() {
let postData = this.httpActivity.log.entries[0].request.postData.text;
_displayRequestForm: function NP__processRequestForm()
{
let postData = this.httpActivity.request.postData.text;
let requestBodyLines = postData.split("\n");
let formData = requestBodyLines[requestBodyLines.length - 1].
replace(/\+/g, " ").split("&");
@ -418,9 +432,8 @@ NetworkPanel.prototype =
*/
_displayResponseHeader: function NP__displayResponseHeader()
{
let entry = this.httpActivity.log.entries[0];
let timing = entry.timings;
let response = entry.response;
let timing = this.httpActivity.timings;
let response = this.httpActivity.response;
this._appendTextNode("headStatus",
[response.httpVersion, response.status,
@ -454,16 +467,16 @@ NetworkPanel.prototype =
_displayResponseImage: function NP__displayResponseImage()
{
let self = this;
let entry = this.httpActivity.log.entries[0];
let timing = entry.timings;
let request = entry.request;
let timing = this.httpActivity.timings;
let request = this.httpActivity.request;
let cached = "";
if (this._isResponseCached) {
cached = "Cached";
}
let imageNode = this.document.getElementById("responseImage" + cached +"Node");
let imageNode = this.document.getElementById("responseImage" +
cached + "Node");
imageNode.setAttribute("src", request.url);
// This function is called to set the imageInfo.
@ -499,9 +512,8 @@ NetworkPanel.prototype =
*/
_displayResponseBody: function NP__displayResponseBody()
{
let entry = this.httpActivity.log.entries[0];
let timing = entry.timings;
let response = entry.response;
let timing = this.httpActivity.timings;
let response = this.httpActivity.response;
let cached = this._isResponseCached ? "Cached" : "";
this._appendTextNode("responseBody" + cached + "Info",
@ -520,7 +532,7 @@ NetworkPanel.prototype =
*/
_displayResponseBodyUnknownType: function NP__displayResponseBodyUnknownType()
{
let timing = this.httpActivity.log.entries[0].timings;
let timing = this.httpActivity.timings;
this._displayNode("responseBodyUnknownType");
this._appendTextNode("responseBodyUnknownTypeInfo",
@ -538,7 +550,7 @@ NetworkPanel.prototype =
*/
_displayNoResponseBody: function NP_displayNoResponseBody()
{
let timing = this.httpActivity.log.entries[0].timings;
let timing = this.httpActivity.timings;
this._displayNode("responseNoBody");
this._appendTextNode("responseNoBodyInfo",
@ -554,15 +566,14 @@ NetworkPanel.prototype =
{
// After the iframe's contentWindow is ready, the document object is set.
// If the document object is not available yet nothing needs to be updated.
if (!this.document) {
if (!this.document || !this.document.getElementById("headUrl")) {
return;
}
let stages = this.httpActivity.meta.stages;
let entry = this.httpActivity.log.entries[0];
let timing = entry.timings;
let request = entry.request;
let response = entry.response;
let updates = this.httpActivity.updates;
let timing = this.httpActivity.timings;
let request = this.httpActivity.request;
let response = this.httpActivity.response;
switch (this._state) {
case this._INIT:
@ -572,7 +583,7 @@ NetworkPanel.prototype =
case this._DISPLAYED_REQUEST_HEADER:
// Process the request body if there is one.
if (!this.httpActivity.meta.discardRequestBody && request.postData) {
if (!this.httpActivity.discardRequestBody && request.postData.text) {
// Check if we send some form data. If so, display the form data special.
if (this._isRequestBodyFormData) {
this._displayRequestForm();
@ -585,9 +596,6 @@ NetworkPanel.prototype =
// FALL THROUGH
case this._DISPLAYED_REQUEST_BODY:
// There is always a response header. Therefore we can skip here if
// we don't have a response header yet and don't have to try updating
// anything else in the NetworkPanel.
if (!response.headers.length || !Object.keys(timing).length) {
break;
}
@ -596,13 +604,13 @@ NetworkPanel.prototype =
// FALL THROUGH
case this._DISPLAYED_RESPONSE_HEADER:
if (stages.indexOf("REQUEST_STOP") == -1 ||
stages.indexOf("TRANSACTION_CLOSE") == -1) {
if (updates.indexOf("responseContent") == -1 ||
updates.indexOf("eventTimings") == -1) {
break;
}
this._state = this._TRANSITION_CLOSED;
if (this.httpActivity.meta.discardResponseBody) {
if (this.httpActivity.discardResponseBody) {
break;
}
@ -618,9 +626,12 @@ NetworkPanel.prototype =
else if (response.content.text) {
this._displayResponseBody();
}
break;
}
if (this._onUpdate) {
this._onUpdate();
}
}
}

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

@ -13,7 +13,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
"resource:///modules/WebConsoleUtils.jsm");
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
var EXPORTED_SYMBOLS = ["PropertyPanel", "PropertyTreeView"];
@ -27,7 +27,7 @@ var EXPORTED_SYMBOLS = ["PropertyPanel", "PropertyTreeView"];
*/
var PropertyTreeView = function() {
this._rows = [];
this._objectCache = {};
this._objectActors = [];
};
PropertyTreeView.prototype = {
@ -44,10 +44,24 @@ PropertyTreeView.prototype = {
_treeBox: null,
/**
* Stores cached information about local objects being inspected.
* Track known object actor IDs. We clean these when the panel is
* destroyed/cleaned up.
*
* @private
* @type array
*/
_objectCache: null,
_objectActors: null,
/**
* Map fake object actors to their IDs. This is used when we inspect local
* objects.
* @private
* @type Object
*/
_localObjectActors: null,
_releaseObject: null,
_objectPropertiesProvider: null,
/**
* Use this setter to update the content of the tree.
@ -58,54 +72,47 @@ PropertyTreeView.prototype = {
* - object:
* This is the raw object you want to display. You can only provide
* this object if you want the property panel to work in sync mode.
* - remoteObject:
* - objectProperties:
* An array that holds information on the remote object being
* inspected. Each element in this array describes each property in the
* remote object. See WebConsoleUtils.namesAndValuesOf() for details.
* - rootCacheId:
* The cache ID where the objects referenced in remoteObject are found.
* - panelCacheId:
* The cache ID where any object retrieved by this property panel
* instance should be stored into.
* - remoteObjectProvider:
* remote object. See WebConsoleUtils.inspectObject() for details.
* - objectPropertiesProvider:
* A function that is invoked when a new object is needed. This is
* called when the user tries to expand an inspectable property. The
* callback must take four arguments:
* - fromCacheId:
* Tells from where to retrieve the object the user picked (from
* which cache ID).
* - objectId:
* The object ID the user wants.
* - panelCacheId:
* Tells in which cache ID to store the objects referenced by
* objectId so they can be retrieved later.
* - actorID:
* The object actor ID from which we request the properties.
* - callback:
* The callback function to be invoked when the remote object is
* received. This function takes one argument: the raw message
* received from the Web Console content script.
* received. This function takes one argument: the array of
* descriptors for each property in the object represented by the
* actor.
* - releaseObject:
* Function to invoke when an object actor should be released. The
* function must take one argument: the object actor ID.
*/
set data(aData) {
let oldLen = this._rows.length;
this._cleanup();
this.cleanup();
if (!aData) {
return;
}
if (aData.remoteObject) {
this._rootCacheId = aData.rootCacheId;
this._panelCacheId = aData.panelCacheId;
this._remoteObjectProvider = aData.remoteObjectProvider;
this._rows = [].concat(aData.remoteObject);
this._updateRemoteObject(this._rows, 0);
if (aData.objectPropertiesProvider) {
this._objectPropertiesProvider = aData.objectPropertiesProvider;
this._releaseObject = aData.releaseObject;
this._propertiesToRows(aData.objectProperties, 0);
this._rows = aData.objectProperties;
}
else if (aData.object) {
this._localObjectActors = Object.create(null);
this._rows = this._inspectObject(aData.object);
}
else {
throw new Error("First argument must have a .remoteObject or " +
"an .object property!");
throw new Error("First argument must have an objectActor or an " +
"object property!");
}
if (this._treeBox) {
@ -128,13 +135,22 @@ PropertyTreeView.prototype = {
* @param number aLevel
* The level you want to give to each property in the remote object.
*/
_updateRemoteObject: function PTV__updateRemoteObject(aObject, aLevel)
_propertiesToRows: function PTV__propertiesToRows(aObject, aLevel)
{
aObject.forEach(function(aElement) {
aElement.level = aLevel;
aElement.isOpened = false;
aElement.children = null;
});
aObject.forEach(function(aItem) {
aItem._level = aLevel;
aItem._open = false;
aItem._children = null;
if (this._releaseObject) {
["value", "get", "set"].forEach(function(aProp) {
let val = aItem[aProp];
if (val && val.actor) {
this._objectActors.push(val.actor);
}
}, this);
}
}, this);
},
/**
@ -143,42 +159,53 @@ PropertyTreeView.prototype = {
* @private
* @param object aObject
* The object you want to inspect.
* @return array
* The array of properties, each being described in a way that is
* usable by the tree view.
*/
_inspectObject: function PTV__inspectObject(aObject)
{
this._objectCache = {};
this._remoteObjectProvider = this._localObjectProvider.bind(this);
let children = WebConsoleUtils.namesAndValuesOf(aObject, this._objectCache);
this._updateRemoteObject(children, 0);
this._objectPropertiesProvider = this._localPropertiesProvider.bind(this);
let children =
WebConsoleUtils.inspectObject(aObject, this._localObjectGrip.bind(this));
this._propertiesToRows(children, 0);
return children;
},
/**
* An object provider for when the user inspects local objects (not remote
* Make a local fake object actor for the given object.
*
* @private
* @param object aObject
* The object to make an actor for.
* @return object
* The fake actor grip that represents the given object.
*/
_localObjectGrip: function PTV__localObjectGrip(aObject)
{
let grip = WebConsoleUtils.getObjectGrip(aObject);
grip.actor = "obj" + gSequenceId();
this._localObjectActors[grip.actor] = aObject;
return grip;
},
/**
* A properties provider for when the user inspects local objects (not remote
* ones).
*
* @private
* @param string aFromCacheId
* The cache ID from where to retrieve the desired object.
* @param string aObjectId
* The ID of the object you want.
* @param string aDestCacheId
* The ID of the cache where to store any objects referenced by the
* desired object.
* @param string aActor
* The ID of the object actor you want.
* @param function aCallback
* The function you want to receive the object.
* The function you want to receive the list of properties.
*/
_localObjectProvider:
function PTV__localObjectProvider(aFromCacheId, aObjectId, aDestCacheId,
aCallback)
_localPropertiesProvider:
function PTV__localPropertiesProvider(aActor, aCallback)
{
let object = WebConsoleUtils.namesAndValuesOf(this._objectCache[aObjectId],
this._objectCache);
aCallback({cacheId: aFromCacheId,
objectId: aObjectId,
object: object,
childrenCacheId: aDestCacheId || aFromCacheId,
});
let object = this._localObjectActors[aActor];
let properties =
WebConsoleUtils.inspectObject(object, this._localObjectGrip.bind(this));
aCallback(properties);
},
/** nsITreeView interface implementation **/
@ -187,18 +214,20 @@ PropertyTreeView.prototype = {
get rowCount() { return this._rows.length; },
setTree: function(treeBox) { this._treeBox = treeBox; },
getCellText: function(idx, column) {
getCellText: function PTV_getCellText(idx, column)
{
let row = this._rows[idx];
return row.name + ": " + row.value;
return row.name + ": " + WebConsoleUtils.getPropertyPanelValue(row);
},
getLevel: function(idx) {
return this._rows[idx].level;
return this._rows[idx]._level;
},
isContainer: function(idx) {
return !!this._rows[idx].inspectable;
return typeof this._rows[idx].value == "object" && this._rows[idx].value &&
this._rows[idx].value.inspectable;
},
isContainerOpen: function(idx) {
return this._rows[idx].isOpened;
return this._rows[idx]._open;
},
isContainerEmpty: function(idx) { return false; },
isSeparator: function(idx) { return false; },
@ -221,22 +250,22 @@ PropertyTreeView.prototype = {
hasNextSibling: function(idx, after)
{
var thisLevel = this.getLevel(idx);
return this._rows.slice(after + 1).some(function (r) r.level == thisLevel);
let thisLevel = this.getLevel(idx);
return this._rows.slice(after + 1).some(function (r) r._level == thisLevel);
},
toggleOpenState: function(idx)
{
let item = this._rows[idx];
if (!item.inspectable) {
if (!this.isContainer(idx)) {
return;
}
if (item.isOpened) {
if (item._open) {
this._treeBox.beginUpdateBatch();
item.isOpened = false;
item._open = false;
var thisLevel = item.level;
var thisLevel = item._level;
var t = idx + 1, deleteCount = 0;
while (t < this._rows.length && this.getLevel(t++) > thisLevel) {
deleteCount++;
@ -251,31 +280,27 @@ PropertyTreeView.prototype = {
}
else {
let levelUpdate = true;
let callback = function _onRemoteResponse(aResponse) {
let callback = function _onRemoteResponse(aProperties) {
this._treeBox.beginUpdateBatch();
item.isOpened = true;
if (levelUpdate) {
this._updateRemoteObject(aResponse.object, item.level + 1);
item.children = aResponse.object;
this._propertiesToRows(aProperties, item._level + 1);
item._children = aProperties;
}
this._rows.splice.apply(this._rows, [idx + 1, 0].concat(item.children));
this._rows.splice.apply(this._rows, [idx + 1, 0].concat(item._children));
this._treeBox.rowCountChanged(idx + 1, item.children.length);
this._treeBox.rowCountChanged(idx + 1, item._children.length);
this._treeBox.invalidateRow(idx);
this._treeBox.endUpdateBatch();
item._open = true;
}.bind(this);
if (!item.children) {
let fromCacheId = item.level > 0 ? this._panelCacheId :
this._rootCacheId;
this._remoteObjectProvider(fromCacheId, item.objectId,
this._panelCacheId, callback);
if (!item._children) {
this._objectPropertiesProvider(item.value.actor, callback);
}
else {
levelUpdate = false;
callback({object: item.children});
callback(item._children);
}
}
},
@ -298,18 +323,23 @@ PropertyTreeView.prototype = {
drop: function(index, orientation, dataTransfer) { },
canDrop: function(index, orientation, dataTransfer) { return false; },
_cleanup: function PTV__cleanup()
/**
* Cleanup the property tree view.
*/
cleanup: function PTV_cleanup()
{
if (this._rows.length) {
// Reset the existing _rows children to the initial state.
this._updateRemoteObject(this._rows, 0);
this._rows = [];
if (this._releaseObject) {
this._objectActors.forEach(this._releaseObject);
delete this._objectPropertiesProvider;
delete this._releaseObject;
}
if (this._localObjectActors) {
delete this._localObjectActors;
delete this._objectPropertiesProvider;
}
delete this._objectCache;
delete this._rootCacheId;
delete this._panelCacheId;
delete this._remoteObjectProvider;
this._rows = [];
this._objectActors = [];
},
};
@ -459,3 +489,9 @@ PropertyPanel.prototype.destroy = function PP_destroy()
this.tree = null;
}
function gSequenceId()
{
return gSequenceId.n++;
}
gSequenceId.n = 0;

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

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

@ -8,7 +8,7 @@ function test()
{
waitForExplicitFinish();
addTab("data:text/html,test for bug 676722 - inspectable objects for window.console");
addTab("data:text/html;charset=utf8,test for bug 676722 - inspectable objects for window.console");
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);

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

@ -21,7 +21,7 @@ function test() {
browser.removeEventListener("DOMContentLoaded", testTimestamp, false);
const TEST_TIMESTAMP = 12345678;
let date = new Date(TEST_TIMESTAMP);
let localizedString = WebConsoleUtils.l10n.timestampString(TEST_TIMESTAMP);
let localizedString = WCU_l10n.timestampString(TEST_TIMESTAMP);
isnot(localizedString.indexOf(date.getHours()), -1, "the localized " +
"timestamp contains the hours");
isnot(localizedString.indexOf(date.getMinutes()), -1, "the localized " +

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

@ -81,7 +81,7 @@ function testContextMenuCopy() {
}
function getExpectedClipboardText(aItem) {
return "[" + WebConsoleUtils.l10n.timestampString(aItem.timestamp) + "] " +
return "[" + WCU_l10n.timestampString(aItem.timestamp) + "] " +
aItem.clipboardText;
}

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

@ -37,14 +37,14 @@ function test() {
let uri = Services.io.newFileURI(dir);
addTab(uri.spec);
addTab("data:text/html;charset=utf8,<p>test file URI");
browser.addEventListener("load", function tabLoad() {
browser.removeEventListener("load", tabLoad, true);
openConsole(null, function(aHud) {
hud = aHud;
hud.jsterm.clearOutput();
browser.addEventListener("load", tabReload, true);
content.location.reload();
content.location = uri.spec;
});
}, true);
}

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

@ -14,25 +14,35 @@ let tab1, tab2, win1, win2;
let noErrors = true;
function tab1Loaded(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
browser.removeEventListener(aEvent.type, tab1Loaded, true);
win2 = OpenBrowserWindow();
win2.addEventListener("load", win2Loaded, true);
}
function win2Loaded(aEvent) {
win2.removeEventListener(aEvent.type, arguments.callee, true);
win2.removeEventListener(aEvent.type, win2Loaded, true);
tab2 = win2.gBrowser.addTab();
tab2 = win2.gBrowser.addTab(TEST_URI);
win2.gBrowser.selectedTab = tab2;
tab2.linkedBrowser.addEventListener("load", tab2Loaded, true);
tab2.linkedBrowser.contentWindow.location = TEST_URI;
}
function tab2Loaded(aEvent) {
tab2.linkedBrowser.removeEventListener(aEvent.type, arguments.callee, true);
tab2.linkedBrowser.removeEventListener(aEvent.type, tab2Loaded, true);
waitForFocus(function() {
let consolesOpened = 0;
function onWebConsoleOpen() {
consolesOpened++;
if (consolesOpened == 2) {
Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
executeSoon(closeConsoles);
}
}
Services.obs.addObserver(onWebConsoleOpen, "web-console-created", false);
function openConsoles() {
try {
HUDService.activateHUDForContext(tab1);
}
@ -48,6 +58,20 @@ function tab2Loaded(aEvent) {
ok(false, "HUDService.activateHUDForContext(tab2) exception: " + ex);
noErrors = false;
}
}
let consolesClosed = 0;
function onWebConsoleClose()
{
consolesClosed++;
if (consolesClosed == 2) {
Services.obs.removeObserver(onWebConsoleClose, "web-console-destroyed");
executeSoon(testEnd);
}
}
function closeConsoles() {
Services.obs.addObserver(onWebConsoleClose, "web-console-destroyed", false);
try {
HUDService.deactivateHUDForContext(tab1);
@ -64,20 +88,26 @@ function tab2Loaded(aEvent) {
ok(false, "HUDService.deactivateHUDForContext(tab2) exception: " + ex);
noErrors = false;
}
}
if (noErrors) {
ok(true, "there were no errors");
}
function testEnd() {
ok(noErrors, "there were no errors");
win2.gBrowser.removeTab(tab2);
Array.forEach(win1.gBrowser.tabs, function(aTab) {
win1.gBrowser.removeTab(aTab);
});
Array.forEach(win2.gBrowser.tabs, function(aTab) {
win2.gBrowser.removeTab(aTab);
});
executeSoon(function() {
win2.close();
tab1 = tab2 = win1 = win2 = null;
finishTest();
});
}
}, tab2.linkedBrowser.contentWindow);
waitForFocus(openConsoles, tab2.linkedBrowser.contentWindow);
}
function test() {

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

@ -10,10 +10,12 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs";
function performTest(lastFinishedRequest)
function performTest(lastFinishedRequest, aConsole)
{
ok(lastFinishedRequest, "page load was logged");
let headers = null;
function readHeader(aName)
{
for (let header of headers) {
@ -24,13 +26,16 @@ function performTest(lastFinishedRequest)
return null;
}
let headers = lastFinishedRequest.log.entries[0].response.headers;
ok(headers, "we have the response headers");
ok(!readHeader("Content-Type"), "we do not have the Content-Type header");
isnot(readHeader("Content-Length"), 60, "Content-Length != 60");
aConsole.webConsoleClient.getResponseHeaders(lastFinishedRequest.actor,
function (aResponse) {
headers = aResponse.headers;
ok(headers, "we have the response headers");
ok(!readHeader("Content-Type"), "we do not have the Content-Type header");
isnot(readHeader("Content-Length"), 60, "Content-Length != 60");
executeSoon(finishTest);
});
HUDService.lastFinishedRequestCallback = null;
executeSoon(finishTest);
}
function test()

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

@ -10,39 +10,49 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-600183-charset.html";
function performTest(lastFinishedRequest)
function performTest(lastFinishedRequest, aConsole)
{
ok(lastFinishedRequest, "charset test page was loaded and logged");
let body = lastFinishedRequest.log.entries[0].response.content.text;
ok(body, "we have the response body");
aConsole.webConsoleClient.getResponseContent(lastFinishedRequest.actor,
function (aResponse) {
ok(!aResponse.contentDiscarded, "response body was not discarded");
let chars = "\u7684\u95ee\u5019!"; // 的问候!
isnot(body.indexOf("<p>" + chars + "</p>"), -1,
"found the chinese simplified string");
let body = aResponse.content.text;
ok(body, "we have the response body");
let chars = "\u7684\u95ee\u5019!"; // 的问候!
isnot(body.indexOf("<p>" + chars + "</p>"), -1,
"found the chinese simplified string");
executeSoon(finishTest);
});
HUDService.lastFinishedRequestCallback = null;
executeSoon(finishTest);
}
function test()
{
addTab("data:text/html;charset=utf-8,Web Console - bug 600183 test");
let initialLoad = true;
browser.addEventListener("load", function onLoad() {
if (initialLoad) {
openConsole(null, function(hud) {
browser.removeEventListener("load", onLoad, true);
hud.ui.saveRequestAndResponseBodies = true;
HUDService.lastFinishedRequestCallback = performTest;
openConsole(null, function(hud) {
hud.ui.saveRequestAndResponseBodies = true;
content.location = TEST_URI;
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return hud.ui.saveRequestAndResponseBodies;
},
successFn: function()
{
HUDService.lastFinishedRequestCallback = performTest;
content.location = TEST_URI;
},
failureFn: finishTest,
});
initialLoad = false;
} else {
browser.removeEventListener("load", onLoad, true);
}
});
}, true);
}

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

@ -16,14 +16,14 @@ const MINIMUM_CONSOLE_HEIGHT = 150;
const MINIMUM_PAGE_HEIGHT = 50;
const HEIGHT_PREF = "devtools.hud.height";
let hud, newHeight, height, innerHeight;
let hud, newHeight, height, innerHeight, testDriver;
function performTests(aWebConsole)
function testGen()
{
hud = aWebConsole.iframe;
height = parseInt(hud.style.height);
toggleConsole();
yield;
is(newHeight, height, "same height after reopening the console");
is(Services.prefs.getIntPref(HEIGHT_PREF), HUDService.lastConsoleHeight,
@ -31,6 +31,7 @@ function performTests(aWebConsole)
setHeight(Math.ceil(innerHeight * 0.5));
toggleConsole();
yield;
is(newHeight, height, "same height after reopening the console");
is(Services.prefs.getIntPref(HEIGHT_PREF), HUDService.lastConsoleHeight,
@ -38,6 +39,7 @@ function performTests(aWebConsole)
setHeight(MINIMUM_CONSOLE_HEIGHT - 1);
toggleConsole();
yield;
is(newHeight, MINIMUM_CONSOLE_HEIGHT, "minimum console height is respected");
is(Services.prefs.getIntPref(HEIGHT_PREF), HUDService.lastConsoleHeight,
@ -45,6 +47,7 @@ function performTests(aWebConsole)
setHeight(innerHeight - MINIMUM_PAGE_HEIGHT + 1);
toggleConsole();
yield;
is(newHeight, innerHeight - MINIMUM_PAGE_HEIGHT,
"minimum page height is respected");
@ -54,6 +57,7 @@ function performTests(aWebConsole)
setHeight(Math.ceil(innerHeight * 0.6));
Services.prefs.setIntPref(HEIGHT_PREF, -1);
toggleConsole();
yield;
is(newHeight, height, "same height after reopening the console");
is(Services.prefs.getIntPref(HEIGHT_PREF), -1, "pref is not updated");
@ -62,17 +66,23 @@ function performTests(aWebConsole)
HUDService.lastConsoleHeight = 0;
Services.prefs.setIntPref(HEIGHT_PREF, 0);
hud = testDriver = null;
executeSoon(finishTest);
yield;
}
function toggleConsole()
{
closeConsole();
openConsole();
closeConsole(null, function() {
openConsole(null, function() {
let hudId = HUDService.getHudIdByWindow(content);
hud = HUDService.hudReferences[hudId].iframe;
newHeight = parseInt(hud.style.height);
let hudId = HUDService.getHudIdByWindow(content);
hud = HUDService.hudReferences[hudId].iframe;
newHeight = parseInt(hud.style.height);
testDriver.next();
});
});
}
function setHeight(aHeight)
@ -87,7 +97,11 @@ function test()
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
innerHeight = content.innerHeight;
openConsole(null, performTests);
openConsole(null, function(aHud) {
hud = aHud.iframe;
testDriver = testGen();
testDriver.next();
});
}, true);
}

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

@ -86,8 +86,17 @@ function onpopupshown2(aEvent)
});
}, false);
executeSoon(function() {
menupopups[1].hidePopup();
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return huds[1].ui.saveRequestAndResponseBodies;
},
successFn: function()
{
menupopups[1].hidePopup();
},
failureFn: finishTest,
});
}
@ -147,8 +156,17 @@ function onpopupshown1(aEvent)
}, tabs[runCount*2 + 1].linkedBrowser.contentWindow);
}, false);
executeSoon(function() {
menupopups[0].hidePopup();
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return huds[0].ui.saveRequestAndResponseBodies;
},
successFn: function()
{
menupopups[0].hidePopup();
},
failureFn: finishTest,
});
}

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

@ -80,6 +80,6 @@ function performTest(HUD) {
}
function getExpectedClipboardText(aItem) {
return "[" + WebConsoleUtils.l10n.timestampString(aItem.timestamp) + "] " +
return "[" + WCU_l10n.timestampString(aItem.timestamp) + "] " +
aItem.clipboardText;
}

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

@ -58,7 +58,7 @@ function getExpectedClipboardText(aItemCount) {
for (let i = 0; i < aItemCount; i++) {
let item = outputNode.getItemAtIndex(i);
expectedClipboardText.push("[" +
WebConsoleUtils.l10n.timestampString(item.timestamp) + "] " +
WCU_l10n.timestampString(item.timestamp) + "] " +
item.clipboardText);
}
return expectedClipboardText.join("\n");

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

@ -10,20 +10,86 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs";
let lastFinishedRequests = {};
let webConsoleClient;
function requestDoneCallback(aHttpRequest)
function requestDoneCallback(aHttpRequest )
{
let status = aHttpRequest.log.entries[0].response.status;
let status = aHttpRequest.response.status;
lastFinishedRequests[status] = aHttpRequest;
}
function performTest(aEvent)
function consoleOpened(hud)
{
webConsoleClient = hud.ui.webConsoleClient;
hud.ui.saveRequestAndResponseBodies = true;
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return hud.ui.saveRequestAndResponseBodies;
},
successFn: function()
{
HUDService.lastFinishedRequestCallback = requestDoneCallback;
waitForSuccess(waitForResponses);
content.location = TEST_URI;
},
failureFn: finishTest,
});
let waitForResponses = {
name: "301 and 404 responses",
validatorFn: function()
{
return "301" in lastFinishedRequests &&
"404" in lastFinishedRequests;
},
successFn: getHeaders,
failureFn: finishTest,
};
}
function getHeaders()
{
HUDService.lastFinishedRequestCallback = null;
ok("301" in lastFinishedRequests, "request 1: 301 Moved Permanently");
ok("404" in lastFinishedRequests, "request 2: 404 Not found");
webConsoleClient.getResponseHeaders(lastFinishedRequests["301"].actor,
function (aResponse) {
lastFinishedRequests["301"].response.headers = aResponse.headers;
webConsoleClient.getResponseHeaders(lastFinishedRequests["404"].actor,
function (aResponse) {
lastFinishedRequests["404"].response.headers = aResponse.headers;
executeSoon(getContent);
});
});
}
function getContent()
{
webConsoleClient.getResponseContent(lastFinishedRequests["301"].actor,
function (aResponse) {
lastFinishedRequests["301"].response.content = aResponse.content;
lastFinishedRequests["301"].discardResponseBody = aResponse.contentDiscarded;
webConsoleClient.getResponseContent(lastFinishedRequests["404"].actor,
function (aResponse) {
lastFinishedRequests["404"].response.content = aResponse.content;
lastFinishedRequests["404"].discardResponseBody =
aResponse.contentDiscarded;
webConsoleClient = null;
executeSoon(performTest);
});
});
}
function performTest()
{
function readHeader(aName)
{
for (let header of headers) {
@ -34,7 +100,7 @@ function performTest(aEvent)
return null;
}
let headers = lastFinishedRequests["301"].log.entries[0].response.headers;
let headers = lastFinishedRequests["301"].response.headers;
is(readHeader("Content-Type"), "text/html",
"we do have the Content-Type header");
is(readHeader("Content-Length"), 71, "Content-Length is correct");
@ -42,14 +108,17 @@ function performTest(aEvent)
"Content-Length is correct");
is(readHeader("x-foobar-bug630733"), "bazbaz",
"X-Foobar-bug630733 is correct");
let body = lastFinishedRequests["301"].log.entries[0].response.content;
ok(!body.text, "body discarded for request 1");
headers = lastFinishedRequests["404"].log.entries[0].response.headers;
let body = lastFinishedRequests["301"].response.content;
ok(!body.text, "body discarded for request 1");
ok(lastFinishedRequests["301"].discardResponseBody,
"body discarded for request 1 (confirmed)");
headers = lastFinishedRequests["404"].response.headers;
ok(!readHeader("Location"), "no Location header");
ok(!readHeader("x-foobar-bug630733"), "no X-Foobar-bug630733 header");
body = lastFinishedRequests["404"].log.entries[0].response.content.text;
body = lastFinishedRequests["404"].response.content.text;
isnot(body.indexOf("404"), -1,
"body is correct for request 2");
@ -61,19 +130,8 @@ function test()
{
addTab("data:text/html;charset=utf-8,<p>Web Console test for bug 630733");
browser.addEventListener("load", function onLoad1(aEvent) {
browser.removeEventListener(aEvent.type, onLoad1, true);
openConsole(null, function(hud) {
hud.ui.saveRequestAndResponseBodies = true;
HUDService.lastFinishedRequestCallback = requestDoneCallback;
browser.addEventListener("load", function onLoad2(aEvent) {
browser.removeEventListener(aEvent.type, onLoad2, true);
executeSoon(performTest);
}, true);
content.location = TEST_URI;
});
browser.addEventListener("load", function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole(null, consoleOpened);
}, true);
}

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

@ -15,7 +15,7 @@ function test() {
function consoleOpened(HUD) {
let tmp = {};
Cu.import("resource:///modules/WebConsoleUtils.jsm", tmp);
Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tmp);
let WCU = tmp.WebConsoleUtils;
let JSPropertyProvider = tmp.JSPropertyProvider;
tmp = null;
@ -117,7 +117,7 @@ function testPropertyPanel(aPanel) {
ok(find("iter1: Iterator", false),
"iter1 is correctly displayed in the Property Panel");
ok(find("iter2: Iterator", false),
ok(find("iter2: Object", false),
"iter2 is correctly displayed in the Property Panel");
executeSoon(finishTest);

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

@ -25,7 +25,7 @@ function test()
hud = aHud;
HUDService.lastFinishedRequestCallback = function(aRequest) {
lastRequest = aRequest.log.entries[0];
lastRequest = aRequest;
if (requestCallback) {
requestCallback();
}

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

@ -23,7 +23,7 @@ function consoleOpened(aHud) {
let completeNode = jsterm.completeNode;
let tmp = {};
Cu.import("resource:///modules/WebConsoleUtils.jsm", tmp);
Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tmp);
let WCU = tmp.WebConsoleUtils;
tmp = null;
@ -38,7 +38,8 @@ function consoleOpened(aHud) {
// __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__
// constructor hasOwnProperty isPrototypeOf propertyIsEnumerable
// toLocaleString toSource toString unwatch valueOf watch.
let props = WCU.namesAndValuesOf(content.wrappedJSObject.document.body);
let props = WCU.inspectObject(content.wrappedJSObject.document.body,
function() { });
is(popup.itemCount, 14 + props.length, "popup.itemCount is correct");
popup._panel.addEventListener("popuphidden", autocompletePopupHidden, false);

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

@ -41,7 +41,7 @@ function testConsoleDir(outputNode) {
if (text == "querySelectorAll: function querySelectorAll()") {
foundQSA = true;
}
else if (text == "location: Object") {
else if (text == "location: Location") {
foundLocation = true;
}
else if (text == "write: function write()") {

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

@ -13,7 +13,7 @@
const TEST_HTTPS_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html";
function test() {
addTab("data:text/html,Web Console basic network logging test");
addTab("data:text/html;charset=utf8,Web Console mixed content test");
browser.addEventListener("load", onLoad, true);
}
@ -68,8 +68,9 @@ function testClickOpenNewTab(warningNode) {
let oldOpenUILinkIn = window.openUILinkIn;
window.openUILinkIn = function(aLink) {
if (aLink == "https://developer.mozilla.org/en/Security/MixedContent");
linkOpened = true;
if (aLink == "https://developer.mozilla.org/en/Security/MixedContent") {
linkOpened = true;
}
}
EventUtils.synthesizeMouse(warningNode, 2, 2, {},

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

@ -6,7 +6,7 @@
// Tests that code completion works properly.
function test() {
addTab("about:addons");
addTab("about:credits");
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, testChrome);
@ -15,7 +15,7 @@ function test() {
function testChrome(hud) {
ok(hud, "we have a console");
ok(hud.iframe, "we have the console iframe");
let jsterm = hud.jsterm;

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

@ -52,7 +52,7 @@ function testClipboard() {
for (let i = 0; i < outputNode.itemCount; i++) {
let item = outputNode.getItemAtIndex(i);
clipboardTexts.push("[" +
WebConsoleUtils.l10n.timestampString(item.timestamp) +
WCU_l10n.timestampString(item.timestamp) +
"] " + item.clipboardText);
}

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

@ -111,10 +111,10 @@ function testJSTerm(hud)
let foundTab = null;
waitForSuccess({
name: "help tab opened",
name: "help tabs opened",
validatorFn: function()
{
let newTabOpen = gBrowser.tabs.length == tabs + 1;
let newTabOpen = gBrowser.tabs.length == tabs + 3;
if (!newTabOpen) {
return false;
}
@ -124,7 +124,9 @@ function testJSTerm(hud)
},
successFn: function()
{
gBrowser.removeTab(foundTab);
gBrowser.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]);
gBrowser.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]);
gBrowser.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]);
nextTest();
},
failureFn: nextTest,
@ -176,7 +178,7 @@ function testJSTerm(hud)
jsterm.clearOutput();
jsterm.execute("pprint(print)");
checkResult(function(nodes) {
return nodes[0].textContent.indexOf("aJSTerm.") > -1;
return nodes[0].textContent.indexOf("aOwner.helperResult") > -1;
}, "pprint(function) shows source", 1);
yield;

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

@ -21,7 +21,6 @@ const TEST_DATA_JSON_CONTENT =
let lastRequest = null;
let requestCallback = null;
let lastActivity = null;
function test()
{
@ -33,19 +32,34 @@ function test()
openConsole(null, function(aHud) {
hud = aHud;
HUDService.lastFinishedRequestCallback = function(aRequest) {
lastRequest = aRequest.log.entries[0];
lastActivity = aRequest;
if (requestCallback) {
requestCallback();
}
};
HUDService.lastFinishedRequestCallback = requestCallbackWrapper;
executeSoon(testPageLoad);
});
}, true);
}
function requestCallbackWrapper(aRequest)
{
lastRequest = aRequest;
hud.ui.webConsoleClient.getResponseContent(lastRequest.actor,
function(aResponse) {
lastRequest.response.content = aResponse.content;
lastRequest.discardResponseBody = aResponse.contentDiscarded;
hud.ui.webConsoleClient.getRequestPostData(lastRequest.actor,
function(aResponse) {
lastRequest.request.postData = aResponse.postData;
lastRequest.discardRequestBody = aResponse.postDataDiscarded;
if (requestCallback) {
requestCallback();
}
});
});
}
function testPageLoad()
{
requestCallback = function() {
@ -55,8 +69,10 @@ function testPageLoad()
is(lastRequest.request.url, TEST_NETWORK_REQUEST_URI,
"Logged network entry is page load");
is(lastRequest.request.method, "GET", "Method is correct");
ok(!lastRequest.request.postData, "No request body was stored");
ok(!lastRequest.request.postData.text, "No request body was stored");
ok(lastRequest.discardRequestBody, "Request body was discarded");
ok(!lastRequest.response.content.text, "No response body was stored");
ok(lastRequest.discardResponseBody, "Response body was discarded");
lastRequest = null;
requestCallback = null;
@ -67,14 +83,29 @@ function testPageLoad()
}
function testPageLoadBody()
{
// Turn on logging of request bodies and check again.
hud.ui.saveRequestAndResponseBodies = true;
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return hud.ui.saveRequestAndResponseBodies;
},
successFn: testPageLoadBodyAfterSettingUpdate,
failureFn: finishTest,
});
}
function testPageLoadBodyAfterSettingUpdate()
{
let loaded = false;
let requestCallbackInvoked = false;
// Turn on logging of request bodies and check again.
hud.ui.saveRequestAndResponseBodies = true;
requestCallback = function() {
ok(lastRequest, "Page load was logged again");
ok(!lastRequest.discardResponseBody, "Response body was not discarded");
is(lastRequest.response.content.text.indexOf("<!DOCTYPE HTML>"), 0,
"Response body's beginning is okay");
@ -104,7 +135,8 @@ function testXhrGet()
requestCallback = function() {
ok(lastRequest, "testXhrGet() was logged");
is(lastRequest.request.method, "GET", "Method is correct");
ok(!lastRequest.request.postData, "No request body was sent");
ok(!lastRequest.request.postData.text, "No request body was sent");
ok(!lastRequest.discardRequestBody, "Request body was not discarded");
is(lastRequest.response.content.text, TEST_DATA_JSON_CONTENT,
"Response is correct");
@ -165,19 +197,18 @@ function testNetworkPanel()
{
// Open the NetworkPanel. The functionality of the NetworkPanel is tested
// within separate test files.
let networkPanel = hud.ui.openNetworkPanel(hud.ui.filterBox, lastActivity);
is(networkPanel, hud.ui.filterBox._netPanel,
"Network panel stored on anchor node");
let networkPanel = hud.ui.openNetworkPanel(hud.ui.filterBox, lastRequest);
networkPanel.panel.addEventListener("load", function onLoad(aEvent) {
networkPanel.panel.removeEventListener(aEvent.type, onLoad, true);
networkPanel.panel.addEventListener("popupshown", function onPopupShown() {
networkPanel.panel.removeEventListener("popupshown", onPopupShown, true);
is(hud.ui.filterBox._netPanel, networkPanel,
"Network panel stored on anchor node");
ok(true, "NetworkPanel was opened");
// All tests are done. Shutdown.
networkPanel.panel.hidePopup();
lastRequest = null;
lastActivity = null;
HUDService.lastFinishedRequestCallback = null;
executeSoon(finishTest);
}, true);

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

@ -64,48 +64,37 @@ function testGen() {
let hud = HUDService.getHudByWindow(content);
let filterBox = hud.ui.filterBox;
let tempScope = {};
Cu.import("resource:///modules/WebConsoleUtils.jsm", tempScope);
let l10n = tempScope.WebConsoleUtils.l10n;
tempScope = null;
let httpActivity = {
meta: {
stages: [],
discardRequestBody: true,
discardResponseBody: true,
updates: [],
discardRequestBody: true,
discardResponseBody: true,
startedDateTime: (new Date()).toISOString(),
request: {
url: "http://www.testpage.com",
method: "GET",
cookies: [],
headers: [
{ name: "foo", value: "bar" },
],
},
log: {
entries: [{
startedDateTime: (new Date()).toISOString(),
request: {
url: "http://www.testpage.com",
method: "GET",
cookies: [],
headers: [
{ name: "foo", value: "bar" },
],
},
response: {
headers: [],
content: {},
},
timings: {},
}],
response: {
headers: [],
content: {},
},
timings: {},
};
let entry = httpActivity.log.entries[0];
let networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
is(filterBox._netPanel, networkPanel,
"Network panel stored on the anchor object");
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -128,8 +117,8 @@ function testGen() {
// Test request body.
info("test 2: request body");
httpActivity.meta.discardRequestBody = false;
entry.request.postData = { text: "hello world" };
httpActivity.discardRequestBody = false;
httpActivity.request.postData = { text: "hello world" };
networkPanel.update();
checkIsVisible(networkPanel, {
@ -146,12 +135,12 @@ function testGen() {
// Test response header.
info("test 3: response header");
entry.timings.wait = 10;
entry.response.httpVersion = "HTTP/3.14";
entry.response.status = 999;
entry.response.statusText = "earthquake win";
entry.response.content.mimeType = "text/html";
entry.response.headers.push(
httpActivity.timings.wait = 10;
httpActivity.response.httpVersion = "HTTP/3.14";
httpActivity.response.status = 999;
httpActivity.response.statusText = "earthquake win";
httpActivity.response.content.mimeType = "text/html";
httpActivity.response.headers.push(
{ name: "Content-Type", value: "text/html" },
{ name: "leaveHouses", value: "true" }
);
@ -175,8 +164,8 @@ function testGen() {
info("test 4");
httpActivity.meta.discardResponseBody = false;
entry.timings.receive = 2;
httpActivity.discardResponseBody = false;
httpActivity.timings.receive = 2;
networkPanel.update();
checkIsVisible(networkPanel, {
@ -192,7 +181,7 @@ function testGen() {
info("test 5");
httpActivity.meta.stages.push("REQUEST_STOP", "TRANSACTION_CLOSE");
httpActivity.updates.push("responseContent", "eventTimings");
networkPanel.update();
checkNodeContent(networkPanel, "responseNoBodyInfo", "2ms");
@ -210,20 +199,22 @@ function testGen() {
// Second run: Test for cookies and response body.
info("test 6: cookies and response body");
entry.request.cookies.push(
httpActivity.request.cookies.push(
{ name: "foo", value: "bar" },
{ name: "hello", value: "world" }
);
entry.response.content.text = "get out here";
httpActivity.response.content.text = "get out here";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
is(filterBox._netPanel, networkPanel,
"Network panel stored on httpActivity object");
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -247,15 +238,17 @@ function testGen() {
// Check image request.
info("test 7: image request");
entry.response.headers[1].value = "image/png";
entry.response.content.mimeType = "image/png";
entry.request.url = TEST_IMG;
httpActivity.response.headers[1].value = "image/png";
httpActivity.response.content.mimeType = "image/png";
httpActivity.request.url = TEST_IMG;
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -296,15 +289,17 @@ function testGen() {
// Check cached image request.
info("test 8: cached image request");
entry.response.httpVersion = "HTTP/1.1";
entry.response.status = 304;
entry.response.statusText = "Not Modified";
httpActivity.response.httpVersion = "HTTP/1.1";
httpActivity.response.status = 304;
httpActivity.response.statusText = "Not Modified";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -326,17 +321,19 @@ function testGen() {
// Test sent form data.
info("test 9: sent form data");
entry.request.postData.text = [
httpActivity.request.postData.text = [
"Content-Type: application/x-www-form-urlencoded",
"Content-Length: 59",
"name=rob&age=20"
].join("\n");
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -357,13 +354,15 @@ function testGen() {
// Test no space after Content-Type:
info("test 10: no space after Content-Type header in post data");
entry.request.postData.text = "Content-Type:application/x-www-form-urlencoded\n";
httpActivity.request.postData.text = "Content-Type:application/x-www-form-urlencoded\n";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -384,16 +383,18 @@ function testGen() {
info("test 11: cached data");
entry.request.url = TEST_ENCODING_ISO_8859_1;
entry.response.headers[1].value = "application/json";
entry.response.content.mimeType = "application/json";
entry.response.content.text = "my cached data is here!";
httpActivity.request.url = TEST_ENCODING_ISO_8859_1;
httpActivity.response.headers[1].value = "application/json";
httpActivity.response.content.mimeType = "application/json";
httpActivity.response.content.text = "my cached data is here!";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -417,14 +418,16 @@ function testGen() {
// Test a response with a content type that can't be displayed in the
// NetworkPanel.
info("test 12: unknown content type");
entry.response.headers[1].value = "application/x-shockwave-flash";
entry.response.content.mimeType = "application/x-shockwave-flash";
httpActivity.response.headers[1].value = "application/x-shockwave-flash";
httpActivity.response.content.mimeType = "application/x-shockwave-flash";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -442,7 +445,7 @@ function testGen() {
});
let responseString =
l10n.getFormatStr("NetworkPanel.responseBodyUnableToDisplay.content",
WCU_l10n.getFormatStr("NetworkPanel.responseBodyUnableToDisplay.content",
["application/x-shockwave-flash"]);
checkNodeContent(networkPanel, "responseBodyUnknownTypeContent", responseString);
networkPanel.panel.hidePopup();

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

@ -17,7 +17,7 @@ function testPropertyProvider() {
browser.removeEventListener("load", testPropertyProvider, true);
let tmp = {};
Cu.import("resource:///modules/WebConsoleUtils.jsm", tmp);
Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tmp);
let JSPropertyProvider = tmp.JSPropertyProvider;
tmp = null;

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

@ -6,8 +6,10 @@
let tempScope = {};
Cu.import("resource:///modules/HUDService.jsm", tempScope);
let HUDService = tempScope.HUDService;
Cu.import("resource:///modules/WebConsoleUtils.jsm", tempScope);
Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tempScope);
let WebConsoleUtils = tempScope.WebConsoleUtils;
const WEBCONSOLE_STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
let WCU_l10n = new WebConsoleUtils.l10n(WEBCONSOLE_STRINGS_URI);
function log(aMsg)
{
@ -252,7 +254,7 @@ function tearDown()
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
tab = browser = hudId = hud = filterBox = outputNode = cs = null;
WCU_l10n = tab = browser = hudId = hud = filterBox = outputNode = cs = null;
}
registerCleanupFunction(tearDown);

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

@ -1,5 +1,6 @@
<!DOCTYPE HTML>
<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
<meta charset="utf8">
<title>Mixed Content test - http on https</title>
<script src="testscript.js"></script>
<!--

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

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

@ -817,11 +817,10 @@ jsbIndentCharDesc=The chars used to indent each line
# does.
jsbIndentCharManual=The chars used to indent each line. The possible choices are space or tab.
# LOCALIZATION NOTE (jsbPreserveNewlinesDesc) A very short description of the
# 'jsb <jsbPreserveNewlines>' parameter. This string is designed to be shown
# in a menu alongside the command name, which is why it should be as short as
# possible.
jsbPreserveNewlinesDesc=Keep existing line breaks?
# the 'jsb <doNotPreserveNewlines>' parameter. This string is designed to be
# shown in a menu alongside the command name, which is why it should be as short
# as possible.
jsbDoNotPreserveNewlinesDesc=Do not preserve line breaks
# LOCALIZATION NOTE (jsbPreserveNewlinesManual) A fuller description of the
# 'jsb <jsbPreserveNewlines>' parameter, displayed when the user asks for help
@ -854,23 +853,18 @@ jsbJslintHappyManual=When set to true, jslint-stricter mode is enforced
# 'jsb <braceStyle>' parameter. This string is designed to be shown
# in a menu alongside the command name, which is why it should be as short as
# possible.
jsbBraceStyleDesc=Collapse, expand, end-expand, expand-strict
jsbBraceStyleDesc=Select the coding style of braces
# LOCALIZATION NOTE (jsbBraceStyleManual) A fuller description of the
# 'jsb <braceStyle>' parameter, displayed when the user asks for help
# on what it does.
jsbBraceStyleManual=The coding style of braces. Either collapse, expand, end-expand or expand-strict
jsbBraceStyleManual=<p class="nowrap">The coding style of braces. Select from one of the following:</p><ul><li>collapse<br/><pre>if (x == 1) {\n ...\n} else {\n ...\n}</pre></li><li>expand<br/><pre>if (x == 1)\n{\n ...\n}\nelse\n{\n ...\n}</pre></li><li>end-expand<br/><pre>if (x == 1) {\n ...\n}\nelse {\n ...\n}</pre></li><li>expand-strict<br/><pre>if (x == 1)\n{\n return // This option can break scripts\n {\n a: 1\n };\n} else {\n ...\n}</pre></li></ul>
# LOCALIZATION NOTE (jsbSpaceBeforeConditionalDesc) A very short description of
# the 'jsb <spaceBeforeConditional>' parameter. This string is designed to be
# shown in a menu alongside the command name, which is why it should be as short
# as possible.
jsbSpaceBeforeConditionalDesc=Space before if statements?
# LOCALIZATION NOTE (jsbSpaceBeforeConditionalManual) A fuller description of
# the 'jsb <spaceBeforeConditional>' parameter, displayed when the user asks for
# help on what it does.
jsbSpaceBeforeConditionalManual=Should a space be added before conditional statements?
# LOCALIZATION NOTE (jsbNoSpaceBeforeConditionalDesc) A very short description
# of the 'jsb <noSpaceBeforeConditional>' parameter. This string is designed to
# be shown in a menu alongside the command name, which is why it should be as
# short as possible.
jsbNoSpaceBeforeConditionalDesc=No space before conditional statements
# LOCALIZATION NOTE (jsbUnescapeStringsDesc) A very short description of the
# 'jsb <unescapeStrings>' parameter. This string is designed to be shown
@ -887,6 +881,10 @@ jsbUnescapeStringsManual=Should printable characters in strings encoded in \\xNN
# the jsb command.
jsbInvalidURL=Please enter a valid URL
# LOCALIZATION NOTE (jsbOptionsDesc) The title of a set of options to
# the 'jsb' command, displayed as a heading to the list of options.
jsbOptionsDesc=Options
# LOCALIZATION NOTE (calllogDesc) A very short description of the
# 'calllog' command. This string is designed to be shown in a menu
# alongside the command name, which is why it should be as short as possible.

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

@ -2444,6 +2444,12 @@ html|*#gcli-output-frame {
0 1px 0 hsla(210,16%,76%,.15);
}
.gclitoolbar-input-node > .textbox-input-box > html|*.textbox-input::-moz-selection {
background-color: hsl(210,30%,85%);
color: hsl(210,11%,16%);
text-shadow: none;
}
.gclitoolbar-complete-node {
padding-left: 21px;
background-color: transparent;

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

@ -63,10 +63,15 @@
.gcli-row-out h4,
.gcli-row-out h5,
.gcli-row-out th,
.gcli-row-out strong {
.gcli-row-out strong,
.gcli-row-out pre {
color: hsl(210,30%,95%);
}
.gcli-row-out pre {
font-size: 80%;
}
.gcli-out-shortcut,
.gcli-help-synopsis {
padding: 0 3px;

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

@ -1,402 +0,0 @@
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2007, Parakey Inc.
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* * Neither the name of Parakey Inc. nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior
* written permission of Parakey Inc.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Creator:
* Joe Hewitt
* Contributors
* John J. Barton (IBM Almaden)
* Jan Odvarko (Mozilla Corp.)
* Max Stepanov (Aptana Inc.)
* Rob Campbell (Mozilla Corp.)
* Hans Hillen (Paciello Group, Mozilla)
* Curtis Bartley (Mozilla Corp.)
* Mike Collins (IBM Almaden)
* Kevin Decker
* Mike Ratcliffe (Comartis AG)
* Hernan Rodríguez Colmeiro
* Austin Andrews
* Christoph Dorn
* Steven Roussey (AppCenter Inc, Network54)
*/
html {
background-color: -moz-dialog;
}
body {
margin: 0;
overflow: auto;
font-family: Lucida Grande, sans-serif;
font-size: 11px;
padding-top: 5px;
}
h1 {
font-size: 17px;
border-bottom: 1px solid threedlightshadow;
}
a {
color: #0000ff;
}
pre {
margin: 0;
font: inherit;
}
code {
display: block;
white-space: pre;
}
/* DOMPlate */
.objectLink-element,
.objectLink-textNode,
.objectLink-function,
.objectBox-stackTrace,
.objectLink-profile {
font-family: Menlo, Andale Mono, monospace;
}
.objectLink-textNode {
white-space: pre-wrap;
}
.objectLink-styleRule,
.objectLink-element,
.objectLink-textNode {
color: #000088;
}
.selectorTag,
.selectorId,
.selectorClass {
font-family: Menlo, Andale Mono, monospace;
font-weight: normal;
}
.selectorTag {
color: #0000FF;
}
.selectorId {
color: DarkBlue;
}
.selectorClass {
color: red;
}
.selectorHidden > .selectorTag {
color: #5F82D9;
}
.selectorHidden > .selectorId {
color: #888888;
}
.selectorHidden > .selectorClass {
color: #D86060;
}
.selectorValue {
font-family: Menlo, Andale Mono, monospace;
font-style: italic;
color: #555555;
}
.panelNode-html {
-moz-box-sizing: padding-box;
padding: 4px 0 0 2px;
}
.nodeBox {
position: relative;
font-family: Menlo, Andale Mono, monospace;
padding-left: 13px;
-moz-user-select: -moz-none;
}
.nodeBox.search-selection {
-moz-user-select: text;
}
.twisty {
position: absolute;
left: 0px;
padding: 8px;
}
.nodeChildBox {
margin-left: 12px;
display: none;
}
.nodeLabel,
.nodeCloseLabel {
margin: -2px 2px 0 2px;
border: 2px solid transparent;
border-radius: 3px;
padding: 0 2px;
color: #000088;
}
.nodeCloseLabel {
display: none;
}
.nodeTag {
cursor: pointer;
color: blue;
}
.nodeValue {
color: #FF0000;
font-weight: normal;
}
.nodeText,
.nodeComment {
margin: 0 2px;
vertical-align: top;
}
.nodeText {
color: #333333;
}
.docType {
position: absolute;
/* position DOCTYPE element above/outside the "nodeBox" that contains it */
/* Note: to be fixed in Bug #688439 */
top: -16px;
font-family: Menlo, Andale Mono, monospace;
padding-left: 8px;
color: #999;
white-space: nowrap;
font-style: italic;
}
.htmlNodeBox {
/* make room for DOCTYPE element to be rendered above/outside "nodeBox" */
/* Note: to be fixed in Bug #688439 */
margin-top: 16px;
}
.nodeWhiteSpace {
border: 1px solid LightGray;
white-space: pre; /* otherwise the border will be collapsed around zero pixels */
margin-left: 1px;
color: gray;
}
.nodeWhiteSpace_Space {
border: 1px solid #ddd;
}
.nodeTextEntity {
border: 1px solid gray;
white-space: pre; /* otherwise the border will be collapsed around zero pixels */
margin-left: 1px;
}
.nodeComment {
color: DarkGreen;
}
.nodeBox.highlightOpen > .nodeLabel {
background-color: #EEEEEE;
}
.nodeBox.highlightOpen > .nodeCloseLabel,
.nodeBox.highlightOpen > .nodeChildBox,
.nodeBox.open > .nodeCloseLabel,
.nodeBox.open > .nodeChildBox {
display: block;
}
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel {
border-color: Highlight;
background-color: Highlight;
color: HighlightText !important;
}
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText {
color: inherit !important;
}
.nodeBox.highlighted > .nodeLabel {
border-color: Highlight !important;
background-color: cyan !important;
color: #000000 !important;
}
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox,
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeText {
color: #000000 !important;
}
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox,
.nodeBox.nodeHidden .nodeCloseLabel,
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeText,
.nodeBox.nodeHidden .nodeText {
color: #888888;
}
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.nodeHidden .nodeCloseLabel > .nodeCloseLabelBox > .nodeTag {
color: #5F82D9;
}
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue {
color: #D86060;
}
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeText {
color: SkyBlue !important;
}
.nodeBox.mutated > .nodeLabel,
.nodeAttr.mutated,
.nodeValue.mutated,
.nodeText.mutated,
.nodeBox.mutated > .nodeText {
background-color: #EFFF79;
color: #FF0000 !important;
}
.nodeBox.selected.mutated > .nodeLabel,
.nodeBox.selected.mutated > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr.mutated > .nodeValue,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue.mutated,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText.mutated {
background-color: #EFFF79;
border-color: #EFFF79;
color: #FF0000 !important;
}
.logRow-dirxml {
padding-left: 0;
}
.soloElement > .nodeBox {
padding-left: 0;
}
.useA11y .nodeLabel.focused {
outline: 2px solid #FF9933;
-moz-outline-radius: 3px;
outline-offset: -2px;
}
.useA11y .nodeLabelBox:focus {
outline: none;
}
/* from panel.css */
/* HTML panel */
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel {
border-color: #3875d7;
background-color: #3875d7;
color: #FFFFFF !important;
}
.nodeBox.highlighted > .nodeLabel {
border-color: #3875d7 !important;
}
/************************************************************************************************/
/* Twisties */
.twisty
{
-moz-appearance: treetwisty;
}
.nodeBox.highlightOpen > .nodeLabel > .twisty,
.nodeBox.open > .nodeLabel > .twisty
{
-moz-appearance: treetwistyopen;
}
/************************************************************************************************/
/* HTML panel */
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel {
border-color: #3875d7;
background-color: #3875d7;
color: #FFFFFF !important;
}
.nodeBox.highlighted > .nodeLabel {
border-color: #3875d7 !important;
}
.editingAttributeValue {
background-color: #492;
}
#attribute-editor {
visibility: hidden;
position: absolute;
z-index: 5000;
background-color: #fff;
border: 1px solid #000;
}
#attribute-editor.editing {
visibility: visible;
}
#attribute-editor-input {
border: none;
padding: 2px 5px;
font-family: Menlo, Andale Mono, monospace;
font-size: 11px;
}

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

@ -110,7 +110,6 @@ browser.jar:
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
skin/classic/browser/devtools/webconsole.png (devtools/webconsole.png)
skin/classic/browser/devtools/commandline.css (devtools/commandline.css)
skin/classic/browser/devtools/htmlpanel.css (devtools/htmlpanel.css)
skin/classic/browser/devtools/markup-view.css (devtools/markup-view.css)
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)

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

@ -3866,6 +3866,12 @@ html|*#gcli-output-frame {
0 1px 0 hsla(210,16%,76%,.15);
}
.gclitoolbar-input-node > .textbox-input-box > html|*.textbox-input::-moz-selection {
background-color: hsl(210,30%,85%);
color: hsl(210,11%,16%);
text-shadow: none;
}
.gclitoolbar-complete-node {
padding-left: 21px;
background-color: transparent;

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

@ -65,10 +65,15 @@
.gcli-row-out h4,
.gcli-row-out h5,
.gcli-row-out th,
.gcli-row-out strong {
.gcli-row-out strong,
.gcli-row-out pre {
color: hsl(210,30%,95%);
}
.gcli-row-out pre {
font-size: 80%;
}
.gcli-out-shortcut,
.gcli-help-synopsis {
padding: 0 3px;

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

@ -1,392 +0,0 @@
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2007, Parakey Inc.
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* * Neither the name of Parakey Inc. nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior
* written permission of Parakey Inc.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Creator:
* Joe Hewitt
* Contributors
* John J. Barton (IBM Almaden)
* Jan Odvarko (Mozilla Corp.)
* Max Stepanov (Aptana Inc.)
* Rob Campbell (Mozilla Corp.)
* Hans Hillen (Paciello Group, Mozilla)
* Curtis Bartley (Mozilla Corp.)
* Mike Collins (IBM Almaden)
* Kevin Decker
* Mike Ratcliffe (Comartis AG)
* Hernan Rodríguez Colmeiro
* Austin Andrews
* Christoph Dorn
* Steven Roussey (AppCenter Inc, Network54)
*/
html {
background-color: -moz-dialog;
}
body {
margin: 0;
overflow: auto;
font-family: Lucida Grande, sans-serif;
font-size: 11px;
padding-top: 5px;
}
h1 {
font-size: 17px;
border-bottom: 1px solid threedlightshadow;
}
a {
color: #0000ff;
}
pre {
margin: 0;
font: inherit;
}
code {
display: block;
white-space: pre;
}
/* DOMPlate */
.objectLink-element,
.objectLink-textNode,
.objectLink-function,
.objectBox-stackTrace,
.objectLink-profile {
font-family: Menlo, Andale Mono, monospace;
}
.objectLink-textNode {
white-space: pre-wrap;
}
.objectLink-styleRule,
.objectLink-element,
.objectLink-textNode {
color: #000088;
}
.selectorTag,
.selectorId,
.selectorClass {
font-family: Menlo, Andale Mono, monospace;
font-weight: normal;
}
.selectorTag {
color: #0000FF;
}
.selectorId {
color: DarkBlue;
}
.selectorClass {
color: red;
}
.selectorHidden > .selectorTag {
color: #5F82D9;
}
.selectorHidden > .selectorId {
color: #888888;
}
.selectorHidden > .selectorClass {
color: #D86060;
}
.selectorValue {
font-family: Menlo, Andale Mono, monospace;
font-style: italic;
color: #555555;
}
.panelNode-html {
-moz-box-sizing: padding-box;
padding: 4px 0 0 2px;
}
.nodeBox {
position: relative;
font-family: Menlo, Andale Mono, monospace;
padding-left: 13px;
-moz-user-select: -moz-none;
}
.nodeBox.search-selection {
-moz-user-select: text;
}
.twisty {
position: absolute;
left: 0px;
top: 0px;
width: 14px;
height: 14px;
}
.nodeChildBox {
margin-left: 12px;
display: none;
}
.nodeLabel,
.nodeCloseLabel {
margin: -2px 2px 0 2px;
border: 2px solid transparent;
border-radius: 3px;
padding: 0 2px;
color: #000088;
}
.nodeCloseLabel {
display: none;
}
.nodeTag {
cursor: pointer;
color: blue;
}
.nodeValue {
color: #FF0000;
font-weight: normal;
}
.nodeText,
.nodeComment {
margin: 0 2px;
vertical-align: top;
}
.nodeText {
color: #333333;
}
.docType {
position: absolute;
/* position DOCTYPE element above/outside the "nodeBox" that contains it */
/* Note: to be fixed in Bug #688439 */
top: -16px;
font-family: Menlo, Andale Mono, monospace;
padding-left: 8px;
color: #999;
white-space: nowrap;
font-style: italic;
}
.htmlNodeBox {
/* make room for DOCTYPE element to be rendered above/outside "nodeBox" */
/* Note: to be fixed in Bug #688439 */
margin-top: 16px;
}
.nodeWhiteSpace {
border: 1px solid LightGray;
white-space: pre; /* otherwise the border will be collapsed around zero pixels */
margin-left: 1px;
color: gray;
}
.nodeWhiteSpace_Space {
border: 1px solid #ddd;
}
.nodeTextEntity {
border: 1px solid gray;
white-space: pre; /* otherwise the border will be collapsed around zero pixels */
margin-left: 1px;
}
.nodeComment {
color: DarkGreen;
}
.nodeBox.highlightOpen > .nodeLabel {
background-color: #EEEEEE;
}
.nodeBox.highlightOpen > .nodeCloseLabel,
.nodeBox.highlightOpen > .nodeChildBox,
.nodeBox.open > .nodeCloseLabel,
.nodeBox.open > .nodeChildBox {
display: block;
}
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel {
border-color: Highlight;
background-color: Highlight;
color: HighlightText !important;
}
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText {
color: inherit !important;
}
.nodeBox.highlighted > .nodeLabel {
border-color: Highlight !important;
background-color: cyan !important;
color: #000000 !important;
}
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox,
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeText {
color: #000000 !important;
}
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox,
.nodeBox.nodeHidden .nodeCloseLabel,
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeText,
.nodeBox.nodeHidden .nodeText {
color: #888888;
}
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.nodeHidden .nodeCloseLabel > .nodeCloseLabelBox > .nodeTag {
color: #5F82D9;
}
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue {
color: #D86060;
}
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeText {
color: SkyBlue !important;
}
.nodeBox.mutated > .nodeLabel,
.nodeAttr.mutated,
.nodeValue.mutated,
.nodeText.mutated,
.nodeBox.mutated > .nodeText {
background-color: #EFFF79;
color: #FF0000 !important;
}
.nodeBox.selected.mutated > .nodeLabel,
.nodeBox.selected.mutated > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr.mutated > .nodeValue,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue.mutated,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText.mutated {
background-color: #EFFF79;
border-color: #EFFF79;
color: #FF0000 !important;
}
.logRow-dirxml {
padding-left: 0;
}
.soloElement > .nodeBox {
padding-left: 0;
}
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel {
border-color: #3875d7;
background-color: #3875d7;
color: #FFFFFF !important;
}
.nodeBox.highlighted > .nodeLabel {
border-color: #3875d7 !important;
}
/************************************************************************************************/
/* Twisties */
.twisty
{
-moz-appearance: treetwisty;
}
.nodeBox.highlightOpen > .nodeLabel > .twisty,
.nodeBox.open > .nodeLabel > .twisty
{
-moz-appearance: treetwistyopen;
}
.memberRow.hasChildren > .memberLabelCell > .memberLabel,
.hasHeaders .netHrefLabel {
background-position: 2px 2px;
}
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel {
border-color: #3875d7;
background-color: #3875d7;
color: #FFFFFF !important;
}
.nodeBox.highlighted > .nodeLabel {
border-color: #3875d7 !important;
}
.editingAttributeValue {
background-color: #492;
}
#attribute-editor {
visibility: hidden;
position: absolute;
z-index: 5000;
background-color: #fff;
border: 1px solid #000;
}
#attribute-editor.editing {
visibility: visible;
}
#attribute-editor-input {
border: none;
padding: 2px 5px;
font-family: Menlo, Andale Mono, monospace;
font-size: 11px;
}

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

@ -175,7 +175,6 @@ browser.jar:
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/browser/devtools/commandline.css (devtools/commandline.css)
skin/classic/browser/devtools/htmlpanel.css (devtools/htmlpanel.css)
skin/classic/browser/devtools/markup-view.css (devtools/markup-view.css)
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)

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

@ -3125,6 +3125,12 @@ html|*#gcli-output-frame {
0 0 0 1px hsla(210,40%,83%,.1);
}
.gclitoolbar-input-node > .textbox-input-box > html|*.textbox-input::-moz-selection {
background-color: hsl(210,30%,85%);
color: hsl(210,24%,16%);
text-shadow: none;
}
.gclitoolbar-complete-node {
padding-left: 21px;
background-color: transparent;

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

@ -63,10 +63,15 @@
.gcli-row-out h4,
.gcli-row-out h5,
.gcli-row-out th,
.gcli-row-out strong {
.gcli-row-out strong,
.gcli-row-out pre {
color: hsl(210,30%,95%);
}
.gcli-row-out pre {
font-size: 80%;
}
.gcli-out-shortcut,
.gcli-help-synopsis {
padding: 0 3px;

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

@ -1,377 +0,0 @@
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2007, Parakey Inc.
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* * Neither the name of Parakey Inc. nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior
* written permission of Parakey Inc.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Creator:
* Joe Hewitt
* Contributors
* John J. Barton (IBM Almaden)
* Jan Odvarko (Mozilla Corp.)
* Max Stepanov (Aptana Inc.)
* Rob Campbell (Mozilla Corp.)
* Hans Hillen (Paciello Group, Mozilla)
* Curtis Bartley (Mozilla Corp.)
* Mike Collins (IBM Almaden)
* Kevin Decker
* Mike Ratcliffe (Comartis AG)
* Hernan Rodríguez Colmeiro
* Austin Andrews
* Christoph Dorn
* Steven Roussey (AppCenter Inc, Network54)
*/
html {
background-color: -moz-dialog;
}
body {
margin: 0;
overflow: auto;
font-family: Lucida Grande, sans-serif;
font-size: 11px;
padding-top: 5px;
}
h1 {
font-size: 17px;
border-bottom: 1px solid threedlightshadow;
}
a {
color: #0000ff;
}
pre {
margin: 0;
font: inherit;
}
code {
display: block;
white-space: pre;
}
/* DOMPlate */
.objectLink-element,
.objectLink-textNode,
.objectLink-function,
.objectBox-stackTrace,
.objectLink-profile {
font-family: Menlo, Andale Mono, monospace;
}
.objectLink-textNode {
white-space: pre-wrap;
}
.objectLink-styleRule,
.objectLink-element,
.objectLink-textNode {
color: #000088;
}
.selectorTag,
.selectorId,
.selectorClass {
font-family: Menlo, Andale Mono, monospace;
font-weight: normal;
}
.selectorTag {
color: #0000FF;
}
.selectorId {
color: DarkBlue;
}
.selectorClass {
color: red;
}
.selectorHidden > .selectorTag {
color: #5F82D9;
}
.selectorHidden > .selectorId {
color: #888888;
}
.selectorHidden > .selectorClass {
color: #D86060;
}
.selectorValue {
font-family: Menlo, Andale Mono, monospace;
font-style: italic;
color: #555555;
}
.panelNode-html {
-moz-box-sizing: padding-box;
padding: 4px 0 0 2px;
}
.nodeBox {
position: relative;
font-family: Menlo, Andale Mono, monospace;
padding-left: 13px;
-moz-user-select: -moz-none;
}
.nodeBox.search-selection {
-moz-user-select: text;
}
.twisty {
position: absolute;
left: 0px;
top: 0px;
width: 14px;
height: 14px;
}
.nodeChildBox {
margin-left: 12px;
display: none;
}
.nodeLabel,
.nodeCloseLabel {
margin: -2px 2px 0 2px;
border: 2px solid transparent;
border-radius: 3px;
padding: 0 2px;
color: #000088;
}
.nodeCloseLabel {
display: none;
}
.nodeTag {
cursor: pointer;
color: blue;
}
.nodeValue {
color: #FF0000;
font-weight: normal;
}
.nodeText,
.nodeComment {
margin: 0 2px;
vertical-align: top;
}
.nodeText {
color: #333333;
}
.docType {
position: absolute;
/* position DOCTYPE element above/outside the "nodeBox" that contains it */
/* Note: to be fixed in Bug #688439 */
top: -16px;
font-family: Menlo, Andale Mono, monospace;
padding-left: 8px;
color: #999;
white-space: nowrap;
font-style: italic;
}
.htmlNodeBox {
/* make room for DOCTYPE element to be rendered above/outside "nodeBox" */
/* Note: to be fixed in Bug #688439 */
margin-top: 16px;
}
.nodeWhiteSpace {
border: 1px solid LightGray;
white-space: pre;
margin-left: 1px;
color: gray;
}
.nodeWhiteSpace_Space {
border: 1px solid #ddd;
}
.nodeTextEntity {
border: 1px solid gray;
white-space: pre;
margin-left: 1px;
}
.nodeComment {
color: DarkGreen;
}
.nodeBox.highlightOpen > .nodeLabel {
background-color: #EEEEEE;
}
.nodeBox.highlightOpen > .nodeCloseLabel,
.nodeBox.highlightOpen > .nodeChildBox,
.nodeBox.open > .nodeCloseLabel,
.nodeBox.open > .nodeChildBox {
display: block;
}
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel {
border-color: Highlight;
background-color: Highlight;
color: HighlightText !important;
}
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText {
color: inherit !important;
}
.nodeBox.highlighted > .nodeLabel {
border-color: Highlight !important;
background-color: cyan !important;
color: #000000 !important;
}
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox,
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeText {
color: #000000 !important;
}
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox,
.nodeBox.nodeHidden .nodeCloseLabel,
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeText,
.nodeBox.nodeHidden .nodeText {
color: #888888;
}
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.nodeHidden .nodeCloseLabel > .nodeCloseLabelBox > .nodeTag {
color: #5F82D9;
}
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue {
color: #D86060;
}
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeText {
color: SkyBlue !important;
}
.nodeBox.mutated > .nodeLabel,
.nodeAttr.mutated,
.nodeValue.mutated,
.nodeText.mutated,
.nodeBox.mutated > .nodeText {
background-color: #EFFF79;
color: #FF0000 !important;
}
.nodeBox.selected.mutated > .nodeLabel,
.nodeBox.selected.mutated > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr.mutated > .nodeValue,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue.mutated,
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText.mutated {
background-color: #EFFF79;
border-color: #EFFF79;
color: #FF0000 !important;
}
.logRow-dirxml {
padding-left: 0;
}
.soloElement > .nodeBox {
padding-left: 0;
}
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
.nodeBox.selected > .nodeLabel {
border-color: #3875d7;
background-color: #3875d7;
color: #FFFFFF !important;
}
.nodeBox.highlighted > .nodeLabel {
border-color: #3875d7 !important;
}
/* Twisties */
.twisty
{
background-repeat: no-repeat;
background-position: center;
background-image: url("chrome://global/skin/tree/twisty-clsd.png") !important;
}
.nodeBox.highlightOpen > .nodeLabel > .twisty,
.nodeBox.open > .nodeLabel > .twisty
{
background-image: url("chrome://global/skin/tree/twisty-open.png") !important;
}
.editingAttributeValue {
background-color: #492;
}
#attribute-editor {
visibility: hidden;
position: absolute;
z-index: 5000;
background-color: #fff;
border: 1px solid #000;
}
#attribute-editor.editing {
visibility: visible;
}
#attribute-editor-input {
border: none;
padding: 2px 5px;
font-family: Menlo, Andale Mono, monospace;
font-size: 11px;
}

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

@ -133,7 +133,6 @@ browser.jar:
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/browser/devtools/commandline.css (devtools/commandline.css)
skin/classic/browser/devtools/htmlpanel.css (devtools/htmlpanel.css)
skin/classic/browser/devtools/markup-view.css (devtools/markup-view.css)
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
@ -339,7 +338,6 @@ browser.jar:
skin/classic/aero/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/aero/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/aero/browser/devtools/commandline.css (devtools/commandline.css)
skin/classic/aero/browser/devtools/htmlpanel.css (devtools/htmlpanel.css)
skin/classic/aero/browser/devtools/markup-view.css (devtools/markup-view.css)
skin/classic/aero/browser/devtools/orion.css (devtools/orion.css)
skin/classic/aero/browser/devtools/orion-container.css (devtools/orion-container.css)

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

@ -69,17 +69,33 @@ var ConsoleAPIStorage = {
},
/**
* Get the events array by inner window ID.
* Get the events array by inner window ID or all events from all windows.
*
* @param string aId
* The inner window ID for which you want to get the array of cached
* events.
* @param string [aId]
* Optional, the inner window ID for which you want to get the array of
* cached events.
* @returns array
* The array of cached events for the given window.
* The array of cached events for the given window. If no |aId| is
* given this function returns all of the cached events, from any
* window.
*/
getEvents: function CS_getEvents(aId)
{
return (_consoleStorage[aId] || []).slice(0);
if (aId != null) {
return (_consoleStorage[aId] || []).slice(0);
}
let ids = [];
for each (let events in _consoleStorage) {
ids.push(events);
}
let result = [].concat.apply([], ids);
return result.sort(function(a, b) {
return a.timeStamp - b.timeStamp;
});
},
/**

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

@ -12,6 +12,7 @@ include $(topsrcdir)/config/config.mk
PARALLEL_DIRS += \
debugger \
sourcemap \
webconsole \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -22,6 +22,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "socketTransportService",
"@mozilla.org/network/socket-transport-service;1",
"nsISocketTransportService");
XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleClient",
"resource://gre/modules/devtools/WebConsoleClient.jsm");
let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
function dumpn(str)
@ -164,10 +167,16 @@ const ThreadStateTypes = {
* by the client.
*/
const UnsolicitedNotifications = {
"eventNotification": "eventNotification",
"consoleAPICall": "consoleAPICall",
"fileActivity": "fileActivity",
"locationChange": "locationChange",
"networkEvent": "networkEvent",
"networkEventUpdate": "networkEventUpdate",
"newScript": "newScript",
"tabDetached": "tabDetached",
"tabNavigated": "tabNavigated"
"tabNavigated": "tabNavigated",
"pageError": "pageError",
"profilerStateChanged": "profilerStateChanged"
};
/**
@ -194,6 +203,7 @@ function DebuggerClient(aTransport)
this._transport.hooks = this;
this._threadClients = {};
this._tabClients = {};
this._consoleClients = {};
this._pendingRequests = [];
this._activeRequests = {};
@ -249,10 +259,32 @@ DebuggerClient.prototype = {
}
}.bind(this);
if (this.activeThread) {
this.activeThread.detach(detachTab);
} else {
detachTab();
let detachThread = function _detachThread() {
if (this.activeThread) {
this.activeThread.detach(detachTab);
} else {
detachTab();
}
}.bind(this);
let consolesClosed = 0;
let consolesToClose = 0;
let onConsoleClose = function _onConsoleClose() {
consolesClosed++;
if (consolesClosed >= consolesToClose) {
this._consoleClients = {};
detachThread();
}
}.bind(this);
for each (let client in this._consoleClients) {
consolesToClose++;
client.close(onConsoleClose);
}
if (!consolesToClose) {
detachThread();
}
},
@ -282,8 +314,9 @@ DebuggerClient.prototype = {
let self = this;
let packet = { to: aTabActor, type: "attach" };
this.request(packet, function(aResponse) {
let tabClient;
if (!aResponse.error) {
var tabClient = new TabClient(self, aTabActor);
tabClient = new TabClient(self, aTabActor);
self._tabClients[aTabActor] = tabClient;
self.activeTab = tabClient;
}
@ -291,6 +324,36 @@ DebuggerClient.prototype = {
});
},
/**
* Attach to a Web Console actor.
*
* @param string aConsoleActor
* The ID for the console actor to attach to.
* @param array aListeners
* The console listeners you want to start.
* @param function aOnResponse
* Called with the response packet and a WebConsoleClient
* instance (which will be undefined on error).
*/
attachConsole:
function DC_attachConsole(aConsoleActor, aListeners, aOnResponse) {
let self = this;
let packet = {
to: aConsoleActor,
type: "startListeners",
listeners: aListeners,
};
this.request(packet, function(aResponse) {
let consoleClient;
if (!aResponse.error) {
consoleClient = new WebConsoleClient(self, aConsoleActor);
self._consoleClients[aConsoleActor] = consoleClient;
}
aOnResponse(aResponse, consoleClient);
});
},
/**
* Attach to a thread actor.
*
@ -313,6 +376,20 @@ DebuggerClient.prototype = {
});
},
/**
* Release an object actor.
*
* @param string aActor
* The actor ID to send the request to.
*/
release: function DC_release(aActor) {
let packet = {
to: aActor,
type: "release",
};
this.request(packet);
},
/**
* Send a request to the debugging server.
*

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

@ -141,7 +141,7 @@ BrowserRootActor.prototype = {
for (let name in aFactories) {
let actor = this._extraActors[name];
if (!actor) {
actor = aFactories[name].bind(null, this.conn);
actor = aFactories[name].bind(null, this.conn, this);
actor.prototype = aFactories[name].prototype;
actor.parentID = this.actorID;
this._extraActors[name] = actor;

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

@ -185,6 +185,9 @@ var DebuggerServer = {
*/
addBrowserActors: function DH_addBrowserActors() {
this.addActors("chrome://global/content/devtools/dbg-browser-actors.js");
this.addActors("chrome://global/content/devtools/dbg-webconsole-actors.js");
this.addTabActor(this.WebConsoleActor, "consoleActor");
this.addGlobalActor(this.WebConsoleActor, "consoleActor");
if ("nsIProfiler" in Ci)
this.addActors("chrome://global/content/devtools/dbg-profiler-actors.js");
},
@ -535,6 +538,7 @@ DebuggerServerConnection.prototype = {
"': " + safeErrorString(e))
});
}
instance.parentID = actor.parentID;
// We want the newly-constructed actor to completely replace the factory
// actor. Reusing the existing actor ID will make sure ActorPool.addActor
// does the right thing.

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

@ -7,4 +7,5 @@ toolkit.jar:
content/global/devtools/dbg-server.js (debugger/server/dbg-server.js)
content/global/devtools/dbg-script-actors.js (debugger/server/dbg-script-actors.js)
content/global/devtools/dbg-browser-actors.js (debugger/server/dbg-browser-actors.js)
content/global/devtools/dbg-webconsole-actors.js (webconsole/dbg-webconsole-actors.js)
content/global/devtools/dbg-profiler-actors.js (debugger/server/dbg-profiler-actors.js)

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

@ -0,0 +1,19 @@
# 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 = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ifneq (Android,$(OS_TARGET))
TEST_DIRS += test
endif
include $(topsrcdir)/config/rules.mk
libs::
$(INSTALL) $(IFLAGS1) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools

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

@ -99,8 +99,6 @@ var NetworkHelper =
return conv.ConvertToUnicode(aText);
}
catch (ex) {
Cu.reportError("NH_convertToUnicode(aText, '" +
aCharset + "') exception: " + ex);
return aText;
}
},
@ -177,8 +175,24 @@ var NetworkHelper =
readPostTextFromPage: function NH_readPostTextFromPage(aDocShell, aCharset)
{
let webNav = aDocShell.QueryInterface(Ci.nsIWebNavigation);
if (webNav instanceof Ci.nsIWebPageDescriptor) {
let descriptor = webNav.currentDescriptor;
return this.readPostTextFromPageViaWebNav(webNav, aCharset);
},
/**
* Reads the posted text from the page's cache, given an nsIWebNavigation
* object.
*
* @param nsIWebNavigation aWebNav
* @param string aCharset
* @returns string or null
* Returns the posted string if it was possible to read from
* aWebNav, otherwise null.
*/
readPostTextFromPageViaWebNav:
function NH_readPostTextFromPageViaWebNav(aWebNav, aCharset)
{
if (aWebNav instanceof Ci.nsIWebPageDescriptor) {
let descriptor = aWebNav.currentDescriptor;
if (descriptor instanceof Ci.nsISHEntry && descriptor.postData &&
descriptor instanceof Ci.nsISeekableStream) {

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

@ -0,0 +1,309 @@
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* vim: set 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;
var EXPORTED_SYMBOLS = ["WebConsoleClient"];
/**
* A WebConsoleClient is used as a front end for the WebConsoleActor that is
* created on the server, hiding implementation details.
*
* @param object aDebuggerClient
* The DebuggerClient instance we live for.
* @param string aActor
* The WebConsoleActor ID.
*/
function WebConsoleClient(aDebuggerClient, aActor)
{
this._actor = aActor;
this._client = aDebuggerClient;
}
WebConsoleClient.prototype = {
/**
* Retrieve the cached messages from the server.
*
* @see this.CACHED_MESSAGES
* @param array aTypes
* The array of message types you want from the server. See
* this.CACHED_MESSAGES for known types.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getCachedMessages: function WCC_getCachedMessages(aTypes, aOnResponse)
{
let packet = {
to: this._actor,
type: "getCachedMessages",
messageTypes: aTypes,
};
this._client.request(packet, aOnResponse);
},
/**
* Inspect the properties of an object.
*
* @param string aActor
* The WebConsoleObjectActor ID to send the request to.
* @param function aOnResponse
* The function invoked when the response is received.
*/
inspectObjectProperties:
function WCC_inspectObjectProperties(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "inspectProperties",
};
this._client.request(packet, aOnResponse);
},
/**
* Evaluate a JavaScript expression.
*
* @param string aString
* The code you want to evaluate.
* @param function aOnResponse
* The function invoked when the response is received.
*/
evaluateJS: function WCC_evaluateJS(aString, aOnResponse)
{
let packet = {
to: this._actor,
type: "evaluateJS",
text: aString,
};
this._client.request(packet, aOnResponse);
},
/**
* Autocomplete a JavaScript expression.
*
* @param string aString
* The code you want to autocomplete.
* @param number aCursor
* Cursor location inside the string. Index starts from 0.
* @param function aOnResponse
* The function invoked when the response is received.
*/
autocomplete: function WCC_autocomplete(aString, aCursor, aOnResponse)
{
let packet = {
to: this._actor,
type: "autocomplete",
text: aString,
cursor: aCursor,
};
this._client.request(packet, aOnResponse);
},
/**
* Clear the cache of messages (page errors and console API calls).
*/
clearMessagesCache: function WCC_clearMessagesCache()
{
let packet = {
to: this._actor,
type: "clearMessagesCache",
};
this._client.request(packet);
},
/**
* Set Web Console-related preferences on the server.
*
* @param object aPreferences
* An object with the preferences you want to change.
* @param function [aOnResponse]
* Optional function to invoke when the response is received.
*/
setPreferences: function WCC_setPreferences(aPreferences, aOnResponse)
{
let packet = {
to: this._actor,
type: "setPreferences",
preferences: aPreferences,
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the request headers from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getRequestHeaders: function WCC_getRequestHeaders(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getRequestHeaders",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the request cookies from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getRequestCookies: function WCC_getRequestCookies(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getRequestCookies",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the request post data from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getRequestPostData: function WCC_getRequestPostData(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getRequestPostData",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the response headers from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getResponseHeaders: function WCC_getResponseHeaders(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getResponseHeaders",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the response cookies from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getResponseCookies: function WCC_getResponseCookies(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getResponseCookies",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the response content from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getResponseContent: function WCC_getResponseContent(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getResponseContent",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the timing information for the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getEventTimings: function WCC_getEventTimings(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getEventTimings",
};
this._client.request(packet, aOnResponse);
},
/**
* Start the given Web Console listeners.
*
* @see this.LISTENERS
* @param array aListeners
* Array of listeners you want to start. See this.LISTENERS for
* known listeners.
* @param function aOnResponse
* Function to invoke when the server response is received.
*/
startListeners: function WCC_startListeners(aListeners, aOnResponse)
{
let packet = {
to: this._actor,
type: "startListeners",
listeners: aListeners,
};
this._client.request(packet, aOnResponse);
},
/**
* Stop the given Web Console listeners.
*
* @see this.LISTENERS
* @param array aListeners
* Array of listeners you want to stop. See this.LISTENERS for
* known listeners.
* @param function aOnResponse
* Function to invoke when the server response is received.
*/
stopListeners: function WCC_stopListeners(aListeners, aOnResponse)
{
let packet = {
to: this._actor,
type: "stopListeners",
listeners: aListeners,
};
this._client.request(packet, aOnResponse);
},
/**
* Close the WebConsoleClient. This stops all the listeners on the server and
* detaches from the console actor.
*
* @param function aOnResponse
* Function to invoke when the server response is received.
*/
close: function WCC_close(aOnResponse)
{
this.stopListeners(null, aOnResponse);
this._client = null;
},
};

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

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

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

@ -0,0 +1,27 @@
# 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_CHROME_FILES = \
test_basics.html \
test_cached_messages.html \
test_page_errors.html \
test_consoleapi.html \
test_jsterm.html \
test_object_actor.html \
test_network_get.html \
test_network_post.html \
network_requests_iframe.html \
data.json \
common.js \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,139 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const XHTML_NS = "http://www.w3.org/1999/xhtml";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm");
function initCommon()
{
//Services.prefs.setBoolPref("devtools.debugger.log", true);
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
}
function initDebuggerServer()
{
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
}
function connectToDebugger(aCallback)
{
initCommon();
initDebuggerServer();
let transport = DebuggerServer.connectPipe();
let client = new DebuggerClient(transport);
let dbgState = { dbgClient: client };
client.connect(aCallback.bind(null, dbgState));
}
function attachConsole(aListeners, aCallback, aAttachToTab)
{
function _onAttachConsole(aState, aResponse, aWebConsoleClient)
{
if (aResponse.error) {
Cu.reportError("attachConsole failed: " + aResponse.error + " " +
aResponse.message);
}
aState.client = aWebConsoleClient;
aCallback(aState, aResponse);
}
connectToDebugger(function _onConnect(aState, aResponse) {
if (aResponse.error) {
Cu.reportError("client.connect() failed: " + aResponse.error + " " +
aResponse.message);
aCallback(aState, aResponse);
return;
}
aState.dbgClient.listTabs(function _onListTabs(aResponse) {
if (aResponse.error) {
Cu.reportError("listTabs failed: " + aResponse.error + " " +
aResponse.message);
aCallback(aState, aResponse);
return;
}
let consoleActor = aAttachToTab ?
aResponse.tabs[aResponse.selected].consoleActor :
aResponse.consoleActor;
aState.actor = consoleActor;
aState.dbgClient.attachConsole(consoleActor, aListeners,
_onAttachConsole.bind(null, aState));
});
});
}
function closeDebugger(aState, aCallback)
{
aState.dbgClient.close(aCallback);
aState.dbgClient = null;
aState.client = null;
}
function checkConsoleAPICall(aCall, aExpected)
{
if (aExpected.level != "trace" && aExpected.arguments) {
is(aCall.arguments.length, aExpected.arguments.length,
"number of arguments");
}
checkObject(aCall, aExpected);
}
function checkObject(aObject, aExpected)
{
for (let name of Object.keys(aExpected))
{
let expected = aExpected[name];
let value = aObject[name];
if (value === undefined) {
ok(false, "'" + name + "' is undefined");
}
else if (typeof expected == "string" ||
typeof expected == "number" ||
typeof expected == "boolean") {
is(value, expected, "property '" + name + "'");
}
else if (expected instanceof RegExp) {
ok(expected.test(value), name + ": " + expected);
}
else if (Array.isArray(expected)) {
info("checking array for property '" + name + "'");
checkObject(value, expected);
}
else if (typeof expected == "object") {
info("checking object for property '" + name + "'");
checkObject(value, expected);
}
}
}
function checkHeadersOrCookies(aArray, aExpected)
{
for (let elem of aArray) {
if (!(elem.name in aExpected)) {
continue;
}
let expected = aExpected[elem.name];
if (expected instanceof RegExp) {
ok(expected.test(elem.value), elem.name + ": " + expected);
}
else {
is(elem.value, expected, elem.name);
}
}
}

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

@ -0,0 +1 @@
{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }

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

@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Console HTTP test page</title>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript"><!--
function makeXhr(aMethod, aUrl, aRequestBody, aCallback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open(aMethod, aUrl, true);
if (aCallback) {
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {
aCallback();
}
};
}
xmlhttp.send(aRequestBody);
}
function testXhrGet(aCallback) {
makeXhr('get', 'data.json', null, aCallback);
}
function testXhrPost(aCallback) {
makeXhr('post', 'data.json', "Hello world!", aCallback);
}
document.cookie = "foobar=fooval";
document.cookie = "omgfoo=bug768096";
// --></script>
</head>
<body>
<h1>Web Console HTTP Logging Testpage</h1>
<h2>This page is used to test the HTTP logging.</h2>
<form action="?" method="post">
<input name="name" type="text" value="foo bar"><br>
<input name="age" type="text" value="144"><br>
</form>
</body>
</html>

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

@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Basic Web Console Actor tests</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript;version=1.8" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Basic Web Console Actor tests</p>
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
function startTest()
{
removeEventListener("load", startTest);
attachConsole(["PageError"], onStartPageError);
}
function onStartPageError(aState, aResponse)
{
is(aResponse.startedListeners.length, 1, "startedListeners.length");
is(aResponse.startedListeners[0], "PageError", "startedListeners: PageError");
ok(aResponse.nativeConsoleAPI, "nativeConsoleAPI");
closeDebugger(aState, function() {
top.console_ = top.console;
top.console = { lolz: "foo" };
attachConsole(["PageError", "ConsoleAPI", "foo"],
onStartPageErrorAndConsoleAPI, true);
});
}
function onStartPageErrorAndConsoleAPI(aState, aResponse)
{
let startedListeners = aResponse.startedListeners;
is(startedListeners.length, 2, "startedListeners.length");
isnot(startedListeners.indexOf("PageError"), -1, "startedListeners: PageError");
isnot(startedListeners.indexOf("ConsoleAPI"), -1,
"startedListeners: ConsoleAPI");
is(startedListeners.indexOf("foo"), -1, "startedListeners: no foo");
ok(!aResponse.nativeConsoleAPI, "!nativeConsoleAPI");
aState.client.stopListeners(["ConsoleAPI", "foo"],
onStopConsoleAPI.bind(null, aState));
}
function onStopConsoleAPI(aState, aResponse)
{
is(aResponse.stoppedListeners.length, 1, "stoppedListeners.length");
is(aResponse.stoppedListeners[0], "ConsoleAPI", "stoppedListeners: ConsoleAPI");
closeDebugger(aState, function() {
attachConsole(["ConsoleAPI"], onStartConsoleAPI);
});
}
function onStartConsoleAPI(aState, aResponse)
{
is(aResponse.startedListeners.length, 1, "startedListeners.length");
is(aResponse.startedListeners[0], "ConsoleAPI", "startedListeners: ConsoleAPI");
ok(aResponse.nativeConsoleAPI, "nativeConsoleAPI");
top.console = top.console_;
delete top.console_;
closeDebugger(aState, function() {
SimpleTest.finish();
});
}
addEventListener("load", startTest);
</script>
</body>
</html>

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

@ -0,0 +1,179 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for cached messages</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript;version=1.8" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for cached messages</p>
<script class="testbody" type="application/javascript;version=1.8">
let expectedConsoleCalls = [];
let expectedPageErrors = [];
(function() {
Services.console.reset();
expectedPageErrors = [
{
_type: "PageError",
errorMessage: /fooColor/,
sourceName: /.+/,
category: "CSS Parser",
timeStamp: /^\d+$/,
error: false,
warning: true,
exception: false,
strict: false,
},
{
_type: "PageError",
errorMessage: /doTheImpossible/,
sourceName: /.+/,
category: "chrome javascript",
timeStamp: /^\d+$/,
error: false,
warning: false,
exception: true,
strict: false,
},
];
let body = top.document.documentElement;
let container = top.document.createElementNS(XHTML_NS, "script");
body.appendChild(container);
container.textContent = "document.documentElement.style.color = 'fooColor';";
body.removeChild(container);
container = top.document.createElementNS(XHTML_NS, "script");
body.appendChild(container);
container.textContent = "document.doTheImpossible();";
body.removeChild(container);
})();
function doConsoleCalls()
{
top.console.log("foobarBaz-log", undefined);
top.console.info("foobarBaz-info", null);
top.console.warn("foobarBaz-warn", document.body);
expectedConsoleCalls = [
{
_type: "ConsoleAPI",
level: "log",
filename: /test_cached_messages/,
functionName: "doConsoleCalls",
timeStamp: /^\d+$/,
arguments: ["foobarBaz-log", { type: "undefined" }],
},
{
_type: "ConsoleAPI",
level: "info",
filename: /test_cached_messages/,
functionName: "doConsoleCalls",
timeStamp: /^\d+$/,
arguments: ["foobarBaz-info", { type: "null" }],
},
{
_type: "ConsoleAPI",
level: "warn",
filename: /test_cached_messages/,
functionName: "doConsoleCalls",
timeStamp: /^\d+$/,
arguments: ["foobarBaz-warn", { type: "object", actor: /[a-z]/ }],
},
];
}
</script>
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
let consoleAPIListener;
let consoleAPICalls = 0;
let handlers = {
onConsoleAPICall: function onConsoleAPICall()
{
consoleAPICalls++;
if (consoleAPICalls == expectedConsoleCalls.length) {
checkConsoleAPICache();
}
},
};
function startTest()
{
removeEventListener("load", startTest);
consoleAPIListener = new ConsoleAPIListener(top, handlers);
consoleAPIListener.init();
doConsoleCalls();
}
function checkConsoleAPICache()
{
consoleAPIListener.destroy();
consoleAPIListener = null;
attachConsole(["ConsoleAPI"], onAttach1);
}
function onAttach1(aState, aResponse)
{
aState.client.getCachedMessages(["ConsoleAPI"],
onCachedConsoleAPI.bind(null, aState));
}
function onCachedConsoleAPI(aState, aResponse)
{
let msgs = aResponse.messages;
is(msgs.length, expectedConsoleCalls.length,
"number of cached console messages");
expectedConsoleCalls.forEach(function(aMessage, aIndex) {
info("checking received cached message #" + aIndex);
checkConsoleAPICall(msgs[aIndex], expectedConsoleCalls[aIndex]);
});
closeDebugger(aState, testPageErrors);
}
function testPageErrors()
{
attachConsole(["PageError"], onAttach2);
}
function onAttach2(aState, aResponse)
{
aState.client.getCachedMessages(["PageError"],
onCachedPageErrors.bind(null, aState));
}
function onCachedPageErrors(aState, aResponse)
{
let msgs = aResponse.messages;
is(msgs.length, expectedPageErrors.length,
"number of cached page errors");
expectedPageErrors.forEach(function(aMessage, aIndex) {
info("checking received cached message #" + aIndex);
checkObject(msgs[aIndex], expectedPageErrors[aIndex]);
});
closeDebugger(aState, function() {
SimpleTest.finish();
});
}
addEventListener("load", startTest);
</script>
</body>
</html>

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

@ -0,0 +1,148 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for the Console API</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript;version=1.8" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for the Console API</p>
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
let expectedConsoleCalls = [];
function doConsoleCalls(aState)
{
console.log("foobarBaz-log", undefined);
console.info("foobarBaz-info", null);
console.warn("foobarBaz-warn", document.body);
console.debug(null);
console.trace();
console.dir(document, window);
expectedConsoleCalls = [
{
level: "log",
filename: /test_consoleapi/,
functionName: "doConsoleCalls",
timeStamp: /^\d+$/,
arguments: ["foobarBaz-log", { type: "undefined" }],
},
{
level: "info",
filename: /test_consoleapi/,
functionName: "doConsoleCalls",
timeStamp: /^\d+$/,
arguments: ["foobarBaz-info", { type: "null" }],
},
{
level: "warn",
filename: /test_consoleapi/,
functionName: "doConsoleCalls",
timeStamp: /^\d+$/,
arguments: ["foobarBaz-warn", { type: "object", actor: /[a-z]/ }],
},
{
level: "debug",
filename: /test_consoleapi/,
functionName: "doConsoleCalls",
timeStamp: /^\d+$/,
arguments: [{ type: "null" }],
},
{
level: "trace",
filename: /test_consoleapi/,
functionName: "doConsoleCalls",
timeStamp: /^\d+$/,
arguments: [
{
filename: /test_consoleapi/,
functionName: "doConsoleCalls",
},
{
filename: /test_consoleapi/,
functionName: "onAttach",
},
],
},
{
level: "dir",
filename: /test_consoleapi/,
functionName: "doConsoleCalls",
timeStamp: /^\d+$/,
arguments: [
{
type: "object",
actor: /[a-z]/,
className: "HTMLDocument",
},
{
type: "object",
actor: /[a-z]/,
className: "Window",
}
],
objectProperties: [
{
name: "ATTRIBUTE_NODE",
value: 2,
},
{
name: "CDATA_SECTION_NODE",
value: 4,
}, // ...
],
},
];
}
function startTest()
{
removeEventListener("load", startTest);
attachConsole(["ConsoleAPI"], onAttach);
}
function onAttach(aState, aResponse)
{
onConsoleAPICall = onConsoleAPICall.bind(null, aState);
aState.dbgClient.addListener("consoleAPICall", onConsoleAPICall);
doConsoleCalls(aState.actor);
}
let consoleCalls = [];
function onConsoleAPICall(aState, aType, aPacket)
{
info("received message level: " + aPacket.message.level);
is(aPacket.from, aState.actor, "console API call actor");
consoleCalls.push(aPacket.message);
if (consoleCalls.length != expectedConsoleCalls.length) {
return;
}
aState.dbgClient.removeListener("consoleAPICall", onConsoleAPICall);
expectedConsoleCalls.forEach(function(aMessage, aIndex) {
info("checking received console call #" + aIndex);
checkConsoleAPICall(consoleCalls[aIndex], expectedConsoleCalls[aIndex]);
});
consoleCalls = [];
closeDebugger(aState, function() {
SimpleTest.finish();
});
}
addEventListener("load", startTest);
</script>
</body>
</html>

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

@ -0,0 +1,145 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for JavaScript terminal functionality</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript;version=1.8" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for JavaScript terminal functionality</p>
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
function startTest()
{
removeEventListener("load", startTest);
attachConsole(["PageError"], onAttach, true);
}
function onAttach(aState, aResponse)
{
top.foobarObject = Object.create(null);
top.foobarObject.foo = 1;
top.foobarObject.foobar = 2;
top.foobarObject.foobaz = 3;
top.foobarObject.omg = 4;
top.foobarObject.omgfoo = 5;
info("test autocomplete for 'window.foo'");
onAutocomplete1 = onAutocomplete1.bind(null, aState);
aState.client.autocomplete("window.foo", 0, onAutocomplete1);
}
function onAutocomplete1(aState, aResponse)
{
let matches = aResponse.matches;
is(aResponse.matchProp, "foo", "matchProp");
is(matches.length, 1, "matches.length");
is(matches[0], "foobarObject", "matches[0]");
info("test autocomplete for 'window.foobarObject.'");
onAutocomplete2 = onAutocomplete2.bind(null, aState);
aState.client.autocomplete("window.foobarObject.", 0, onAutocomplete2);
}
function onAutocomplete2(aState, aResponse)
{
let matches = aResponse.matches;
ok(!aResponse.matchProp, "matchProp");
is(matches.length, 5, "matches.length");
checkObject(matches, ["foo", "foobar", "foobaz", "omg", "omgfoo"]);
info("test eval '2+2'");
onEval1 = onEval1.bind(null, aState);
aState.client.evaluateJS("2+2", onEval1);
}
function onEval1(aState, aResponse)
{
checkObject(aResponse, {
from: aState.actor,
input: "2+2",
result: 4,
});
ok(!aResponse.error, "no js error");
ok(!aResponse.helperResult, "no helper result");
info("test eval 'window'");
onEval2 = onEval2.bind(null, aState);
aState.client.evaluateJS("window", onEval2);
}
function onEval2(aState, aResponse)
{
checkObject(aResponse, {
from: aState.actor,
input: "window",
result: {
type: "object",
className: "Window",
actor: /[a-z]/,
},
});
ok(!aResponse.error, "no js error");
ok(!aResponse.helperResult, "no helper result");
info("test eval with exception");
onEvalWithException = onEvalWithException.bind(null, aState);
aState.client.evaluateJS("window.doTheImpossible()",
onEvalWithException);
}
function onEvalWithException(aState, aResponse)
{
checkObject(aResponse, {
from: aState.actor,
input: "window.doTheImpossible()",
result: {
type: "undefined",
},
errorMessage: /doTheImpossible/,
});
ok(aResponse.error, "js error object");
ok(!aResponse.helperResult, "no helper result");
info("test eval with helper");
onEvalWithHelper = onEvalWithHelper.bind(null, aState);
aState.client.evaluateJS("clear()", onEvalWithHelper);
}
function onEvalWithHelper(aState, aResponse)
{
checkObject(aResponse, {
from: aState.actor,
input: "clear()",
result: {
type: "undefined",
},
helperResult: { type: "clearOutput" },
});
ok(!aResponse.error, "no js error");
closeDebugger(aState, function() {
SimpleTest.finish();
});
}
addEventListener("load", startTest);
</script>
</body>
</html>

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

@ -0,0 +1,242 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for the network actor (GET request)</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript;version=1.8" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for the network actor (GET request)</p>
<iframe src="http://example.com/chrome/toolkit/devtools/webconsole/test/network_requests_iframe.html"></iframe>
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
function startTest()
{
removeEventListener("load", startTest);
attachConsole(["NetworkActivity"], onAttach, true);
}
function onAttach(aState, aResponse)
{
info("test network GET request");
onNetworkEvent = onNetworkEvent.bind(null, aState);
aState.dbgClient.addListener("networkEvent", onNetworkEvent);
onNetworkEventUpdate = onNetworkEventUpdate.bind(null, aState);
aState.dbgClient.addListener("networkEventUpdate", onNetworkEventUpdate);
let iframe = document.querySelector("iframe").contentWindow;
iframe.wrappedJSObject.testXhrGet();
}
function onNetworkEvent(aState, aType, aPacket)
{
is(aPacket.from, aState.actor, "network event actor");
info("checking the network event packet");
let netActor = aPacket.eventActor;
checkObject(netActor, {
actor: /[a-z]/,
startedDateTime: /^\d+\-\d+\-\d+T.+$/,
url: /data\.json/,
method: "GET",
});
aState.netActor = netActor.actor;
aState.dbgClient.removeListener("networkEvent", onNetworkEvent);
}
let updates = [];
function onNetworkEventUpdate(aState, aType, aPacket)
{
info("received networkEventUpdate " + aPacket.updateType);
is(aPacket.from, aState.netActor, "networkEventUpdate actor");
updates.push(aPacket.updateType);
let expectedPacket = null;
switch (aPacket.updateType) {
case "requestHeaders":
case "responseHeaders":
ok(aPacket.headers > 0, "headers > 0");
ok(aPacket.headersSize > 0, "headersSize > 0");
break;
case "requestCookies":
expectedPacket = {
cookies: 2,
};
break;
case "requestPostData":
ok(false, "got unexpected requestPostData");
break;
case "responseStart":
expectedPacket = {
response: {
httpVersion: /^HTTP\/\d\.\d$/,
status: 200,
statusText: "OK",
headersSize: /^\d+$/,
discardResponseBody: true,
},
};
break;
case "responseCookies":
expectedPacket = {
cookies: 0,
};
break;
case "responseContent":
expectedPacket = {
mimeType: /^application\/(json|octet-stream)$/,
contentSize: 0,
discardResponseBody: true,
};
break;
case "eventTimings":
expectedPacket = {
totalTime: /^\d+$/,
};
break;
default:
ok(false, "unknown network event update type: " +
aPacket.updateType);
return;
}
if (expectedPacket) {
info("checking the packet content");
checkObject(aPacket, expectedPacket);
}
if (updates.indexOf("responseContent") > -1 &&
updates.indexOf("eventTimings") > -1) {
aState.dbgClient.removeListener("networkEventUpdate",
onNetworkEvent);
onRequestHeaders = onRequestHeaders.bind(null, aState);
aState.client.getRequestHeaders(aState.netActor,
onRequestHeaders);
}
}
function onRequestHeaders(aState, aResponse)
{
info("checking request headers");
ok(aResponse.headers.length > 0, "request headers > 0");
ok(aResponse.headersSize > 0, "request headersSize > 0");
checkHeadersOrCookies(aResponse.headers, {
Referer: /network_requests_iframe\.html/,
Cookie: /bug768096/,
});
onRequestCookies = onRequestCookies.bind(null, aState);
aState.client.getRequestCookies(aState.netActor,
onRequestCookies);
}
function onRequestCookies(aState, aResponse)
{
info("checking request cookies");
is(aResponse.cookies.length, 2, "request cookies length");
checkHeadersOrCookies(aResponse.cookies, {
foobar: "fooval",
omgfoo: "bug768096",
});
onRequestPostData = onRequestPostData.bind(null, aState);
aState.client.getRequestPostData(aState.netActor,
onRequestPostData);
}
function onRequestPostData(aState, aResponse)
{
info("checking request POST data");
ok(!aResponse.postData.text, "no request POST data");
ok(aResponse.postDataDiscarded, "request POST data was discarded");
onResponseHeaders = onResponseHeaders.bind(null, aState);
aState.client.getResponseHeaders(aState.netActor,
onResponseHeaders);
}
function onResponseHeaders(aState, aResponse)
{
info("checking response headers");
ok(aResponse.headers.length > 0, "response headers > 0");
ok(aResponse.headersSize > 0, "response headersSize > 0");
checkHeadersOrCookies(aResponse.headers, {
"Content-Type": /^application\/(json|octet-stream)$/,
"Content-Length": /^\d+$/,
});
onResponseCookies = onResponseCookies.bind(null, aState);
aState.client.getResponseCookies(aState.netActor,
onResponseCookies);
}
function onResponseCookies(aState, aResponse)
{
info("checking response cookies");
is(aResponse.cookies.length, 0, "response cookies length");
onResponseContent = onResponseContent.bind(null, aState);
aState.client.getResponseContent(aState.netActor,
onResponseContent);
}
function onResponseContent(aState, aResponse)
{
info("checking response content");
ok(!aResponse.content.text, "no response content");
ok(aResponse.contentDiscarded, "response content was discarded");
onEventTimings = onEventTimings.bind(null, aState);
aState.client.getEventTimings(aState.netActor,
onEventTimings);
}
function onEventTimings(aState, aResponse)
{
info("checking event timings");
checkObject(aResponse, {
timings: {
blocked: /^-1|\d+$/,
dns: /^-1|\d+$/,
connect: /^-1|\d+$/,
send: /^-1|\d+$/,
wait: /^-1|\d+$/,
receive: /^-1|\d+$/,
},
totalTime: /^\d+$/,
});
closeDebugger(aState, function() {
SimpleTest.finish();
});
}
addEventListener("load", startTest);
</script>
</body>
</html>

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

@ -0,0 +1,266 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for the network actor (POST request)</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript;version=1.8" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for the network actor (POST request)</p>
<iframe src="http://example.com/chrome/toolkit/devtools/webconsole/test/network_requests_iframe.html"></iframe>
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
function startTest()
{
removeEventListener("load", startTest);
attachConsole(["NetworkActivity"], onAttach, true);
}
function onAttach(aState, aResponse)
{
info("enable network request and response body logging");
onSetPreferences = onSetPreferences.bind(null, aState);
aState.client.setPreferences({
"NetworkMonitor.saveRequestAndResponseBodies": true,
}, onSetPreferences);
}
function onSetPreferences(aState, aResponse)
{
is(aResponse.updated.length, 1, "updated prefs length");
is(aResponse.updated[0], "NetworkMonitor.saveRequestAndResponseBodies",
"updated prefs length");
info("test network POST request");
onNetworkEvent = onNetworkEvent.bind(null, aState);
aState.dbgClient.addListener("networkEvent", onNetworkEvent);
onNetworkEventUpdate = onNetworkEventUpdate.bind(null, aState);
aState.dbgClient.addListener("networkEventUpdate", onNetworkEventUpdate);
let iframe = document.querySelector("iframe").contentWindow;
iframe.wrappedJSObject.testXhrPost();
}
function onNetworkEvent(aState, aType, aPacket)
{
is(aPacket.from, aState.actor, "network event actor");
info("checking the network event packet");
let netActor = aPacket.eventActor;
checkObject(netActor, {
actor: /[a-z]/,
startedDateTime: /^\d+\-\d+\-\d+T.+$/,
url: /data\.json/,
method: "POST",
});
aState.netActor = netActor.actor;
aState.dbgClient.removeListener("networkEvent", onNetworkEvent);
}
let updates = [];
function onNetworkEventUpdate(aState, aType, aPacket)
{
info("received networkEventUpdate " + aPacket.updateType);
is(aPacket.from, aState.netActor, "networkEventUpdate actor");
updates.push(aPacket.updateType);
let expectedPacket = null;
switch (aPacket.updateType) {
case "requestHeaders":
case "responseHeaders":
ok(aPacket.headers > 0, "headers > 0");
ok(aPacket.headersSize > 0, "headersSize > 0");
break;
case "requestCookies":
expectedPacket = {
cookies: 2,
};
break;
case "requestPostData":
ok(aPacket.dataSize > 0, "dataSize > 0");
ok(!aPacket.discardRequestBody, "discardRequestBody");
break;
case "responseStart":
expectedPacket = {
response: {
httpVersion: /^HTTP\/\d\.\d$/,
status: 200,
statusText: "OK",
headersSize: /^\d+$/,
discardResponseBody: false,
},
};
break;
case "responseCookies":
expectedPacket = {
cookies: 0,
};
break;
case "responseContent":
expectedPacket = {
mimeType: /^application\/(json|octet-stream)$/,
contentSize: /^\d+$/,
discardResponseBody: false,
};
break;
case "eventTimings":
expectedPacket = {
totalTime: /^\d+$/,
};
break;
default:
ok(false, "unknown network event update type: " +
aPacket.updateType);
return;
}
if (expectedPacket) {
info("checking the packet content");
checkObject(aPacket, expectedPacket);
}
if (updates.indexOf("responseContent") > -1 &&
updates.indexOf("eventTimings") > -1) {
aState.dbgClient.removeListener("networkEventUpdate",
onNetworkEvent);
onRequestHeaders = onRequestHeaders.bind(null, aState);
aState.client.getRequestHeaders(aState.netActor,
onRequestHeaders);
}
}
function onRequestHeaders(aState, aResponse)
{
info("checking request headers");
ok(aResponse.headers.length > 0, "request headers > 0");
ok(aResponse.headersSize > 0, "request headersSize > 0");
checkHeadersOrCookies(aResponse.headers, {
Referer: /network_requests_iframe\.html/,
Cookie: /bug768096/,
});
onRequestCookies = onRequestCookies.bind(null, aState);
aState.client.getRequestCookies(aState.netActor,
onRequestCookies);
}
function onRequestCookies(aState, aResponse)
{
info("checking request cookies");
is(aResponse.cookies.length, 2, "request cookies length");
checkHeadersOrCookies(aResponse.cookies, {
foobar: "fooval",
omgfoo: "bug768096",
});
onRequestPostData = onRequestPostData.bind(null, aState);
aState.client.getRequestPostData(aState.netActor,
onRequestPostData);
}
function onRequestPostData(aState, aResponse)
{
info("checking request POST data");
checkObject(aResponse, {
postData: {
text: "Hello world!",
},
postDataDiscarded: false,
});
onResponseHeaders = onResponseHeaders.bind(null, aState);
aState.client.getResponseHeaders(aState.netActor,
onResponseHeaders);
}
function onResponseHeaders(aState, aResponse)
{
info("checking response headers");
ok(aResponse.headers.length > 0, "response headers > 0");
ok(aResponse.headersSize > 0, "response headersSize > 0");
checkHeadersOrCookies(aResponse.headers, {
"Content-Type": /^application\/(json|octet-stream)$/,
"Content-Length": /^\d+$/,
});
onResponseCookies = onResponseCookies.bind(null, aState);
aState.client.getResponseCookies(aState.netActor,
onResponseCookies);
}
function onResponseCookies(aState, aResponse)
{
info("checking response cookies");
is(aResponse.cookies.length, 0, "response cookies length");
onResponseContent = onResponseContent.bind(null, aState);
aState.client.getResponseContent(aState.netActor,
onResponseContent);
}
function onResponseContent(aState, aResponse)
{
info("checking response content");
checkObject(aResponse, {
content: {
text: /"test JSON data"/,
},
contentDiscarded: false,
});
onEventTimings = onEventTimings.bind(null, aState);
aState.client.getEventTimings(aState.netActor,
onEventTimings);
}
function onEventTimings(aState, aResponse)
{
info("checking event timings");
checkObject(aResponse, {
timings: {
blocked: /^-1|\d+$/,
dns: /^-1|\d+$/,
connect: /^-1|\d+$/,
send: /^-1|\d+$/,
wait: /^-1|\d+$/,
receive: /^-1|\d+$/,
},
totalTime: /^\d+$/,
});
closeDebugger(aState, function() {
SimpleTest.finish();
});
}
addEventListener("load", startTest);
</script>
</body>
</html>

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

@ -0,0 +1,171 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for the object actor</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript;version=1.8" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for the object actor</p>
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
let expectedProps = [];
function startTest()
{
removeEventListener("load", startTest);
attachConsole(["ConsoleAPI"], onAttach, true);
}
function onAttach(aState, aResponse)
{
onConsoleCall = onConsoleCall.bind(null, aState);
aState.dbgClient.addListener("consoleAPICall", onConsoleCall);
window.foobarObject = Object.create(null);
foobarObject.foo = 1;
foobarObject.foobar = "hello";
foobarObject.foobaz = document;
foobarObject.omg = null;
foobarObject.testfoo = false;
foobarObject.notInspectable = {};
foobarObject.omgfn = function _omgfn() {
return "myResult";
};
foobarObject.abArray = ["a", "b"];
Object.defineProperty(foobarObject, "getterAndSetter", {
enumerable: true,
get: function fooGet() { return "foo"; },
set: function fooSet() { 1+2 },
});
console.log("hello", foobarObject);
expectedProps = [
{
name: "abArray",
value: {
type: "object",
className: "Array",
actor: /[a-z]/,
inspectable: true,
},
},
{
name: "foo",
configurable: true,
enumerable: true,
writable: true,
value: 1,
},
{
name: "foobar",
value: "hello",
},
{
name: "foobaz",
value: {
type: "object",
className: "HTMLDocument",
displayString: /\[object HTMLDocument/,
inspectable: true,
actor: /[a-z]/,
},
},
{
name: "getterAndSetter",
get: {
type: "function",
className: "function",
displayString: /function fooGet/,
actor: /[a-z]/,
inspectable: false,
},
set: {
type: "function",
className: "function",
displayString: /function fooSet/,
actor: /[a-z]/,
inspectable: false,
},
},
{
name: "notInspectable",
value: {
type: "object",
className: "Object",
actor: /[a-z]/,
inspectable: false,
},
},
{
name: "omg",
value: { type: "null" },
},
{
name: "omgfn",
value: {
type: "function",
className: "function",
displayString: /function _omgfn/,
actor: /[a-z]/,
inspectable: false,
},
},
{
name: "testfoo",
value: false,
},
];
}
function onConsoleCall(aState, aType, aPacket)
{
is(aPacket.from, aState.actor, "console API call actor");
info("checking the console API call packet");
checkConsoleAPICall(aPacket.message, {
level: "log",
filename: /test_object_actor/,
functionName: "onAttach",
arguments: ["hello", {
type: "object",
actor: /[a-z]/,
inspectable: true,
}],
});
aState.dbgClient.removeListener("consoleAPICall", onConsoleCall);
info("inspecting object properties");
let args = aPacket.message.arguments;
onProperties = onProperties.bind(null, aState);
aState.client.inspectObjectProperties(args[1].actor, onProperties);
}
function onProperties(aState, aResponse)
{
let props = aResponse.properties;
is(props.length, expectedProps.length,
"number of enumerable properties");
checkObject(props, expectedProps);
expectedProps = [];
closeDebugger(aState, function() {
SimpleTest.finish();
});
}
addEventListener("load", startTest);
</script>
</body>
</html>

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

@ -0,0 +1,97 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf8">
<title>Test for page errors</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript;version=1.8" src="common.js"></script>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for page errors</p>
<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
let expectedPageErrors = [];
function doPageErrors()
{
expectedPageErrors = [
{
errorMessage: /fooColor/,
sourceName: /test_page_errors/,
category: "CSS Parser",
timeStamp: /^\d+$/,
error: false,
warning: true,
exception: false,
strict: false,
},
{
errorMessage: /doTheImpossible/,
sourceName: /test_page_errors/,
category: "chrome javascript",
timeStamp: /^\d+$/,
error: false,
warning: false,
exception: true,
strict: false,
},
];
let container = document.createElement("script");
document.body.appendChild(container);
container.textContent = "document.body.style.color = 'fooColor';";
document.body.removeChild(container);
SimpleTest.expectUncaughtException();
container = document.createElement("script");
document.body.appendChild(container);
container.textContent = "document.doTheImpossible();";
document.body.removeChild(container);
}
function startTest()
{
removeEventListener("load", startTest);
attachConsole(["PageError"], onAttach);
}
function onAttach(aState, aResponse)
{
onPageError = onPageError.bind(null, aState);
aState.dbgClient.addListener("pageError", onPageError);
doPageErrors();
}
let pageErrors = [];
function onPageError(aState, aType, aPacket)
{
is(aPacket.from, aState.actor, "page error actor");
pageErrors.push(aPacket.pageError);
if (pageErrors.length != expectedPageErrors.length) {
return;
}
aState.dbgClient.removeListener("pageError", onPageError);
expectedPageErrors.forEach(function(aMessage, aIndex) {
info("checking received page error #" + aIndex);
checkObject(pageErrors[aIndex], expectedPageErrors[aIndex]);
});
closeDebugger(aState, function() {
SimpleTest.finish();
});
}
addEventListener("load", startTest);
</script>
</body>
</html>