mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-03 02:25:34 +00:00
Merge m-c to inbound.
This commit is contained in:
commit
a7d45f8d16
@ -130,7 +130,9 @@ function openBrowserWindowIntl()
|
||||
"_blank", params,
|
||||
gBrowserContext.startURL);
|
||||
|
||||
addA11yLoadEvent(startBrowserTests, browserWindow());
|
||||
whenDelayedStartupFinished(browserWindow(), function () {
|
||||
addA11yLoadEvent(startBrowserTests, browserWindow());
|
||||
});
|
||||
}
|
||||
|
||||
function startBrowserTests()
|
||||
@ -140,3 +142,12 @@ function startBrowserTests()
|
||||
else
|
||||
gBrowserContext.testFunc();
|
||||
}
|
||||
|
||||
function whenDelayedStartupFinished(aWindow, aCallback) {
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic) {
|
||||
if (aWindow == aSubject) {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
setTimeout(aCallback, 0);
|
||||
}
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
}
|
||||
|
@ -1027,7 +1027,7 @@ pref("devtools.responsiveUI.enabled", true);
|
||||
|
||||
// Enable the Debugger
|
||||
pref("devtools.debugger.enabled", true);
|
||||
pref("devtools.debugger.chrome-enabled", false);
|
||||
pref("devtools.debugger.chrome-enabled", true);
|
||||
pref("devtools.debugger.remote-host", "localhost");
|
||||
pref("devtools.debugger.remote-autoconnect", false);
|
||||
pref("devtools.debugger.remote-connection-retries", 3);
|
||||
|
@ -1008,7 +1008,6 @@ var gBrowserInit = {
|
||||
if ("arguments" in window && window.arguments[0])
|
||||
var uriToLoad = window.arguments[0];
|
||||
|
||||
var isLoadingBlank = isBlankPageURL(uriToLoad);
|
||||
var mustLoadSidebar = false;
|
||||
|
||||
gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver, false);
|
||||
@ -1095,44 +1094,6 @@ var gBrowserInit = {
|
||||
// setup simple gestures support
|
||||
gGestureSupport.init(true);
|
||||
|
||||
|
||||
if (uriToLoad && uriToLoad != "about:blank") {
|
||||
if (uriToLoad instanceof Ci.nsISupportsArray) {
|
||||
let count = uriToLoad.Count();
|
||||
let specs = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
let urisstring = uriToLoad.GetElementAt(i).QueryInterface(Ci.nsISupportsString);
|
||||
specs.push(urisstring.data);
|
||||
}
|
||||
|
||||
// This function throws for certain malformed URIs, so use exception handling
|
||||
// so that we don't disrupt startup
|
||||
try {
|
||||
gBrowser.loadTabs(specs, false, true);
|
||||
} catch (e) {}
|
||||
}
|
||||
else if (uriToLoad instanceof XULElement) {
|
||||
// swap the given tab with the default about:blank tab and then close
|
||||
// the original tab in the other window.
|
||||
|
||||
// Stop the about:blank load
|
||||
gBrowser.stop();
|
||||
// make sure it has a docshell
|
||||
gBrowser.docShell;
|
||||
|
||||
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);
|
||||
}
|
||||
else if (window.arguments.length >= 3) {
|
||||
loadURI(uriToLoad, window.arguments[2], window.arguments[3] || null,
|
||||
window.arguments[4] || false);
|
||||
window.focus();
|
||||
}
|
||||
// Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
|
||||
// Such callers expect that window.arguments[0] is handled as a single URI.
|
||||
else
|
||||
loadOneOrMoreURIs(uriToLoad);
|
||||
}
|
||||
|
||||
if (window.opener && !window.opener.closed) {
|
||||
let openerSidebarBox = window.opener.document.getElementById("sidebar-box");
|
||||
// If the opener had a sidebar, open the same sidebar in our window.
|
||||
@ -1242,7 +1203,7 @@ var gBrowserInit = {
|
||||
retrieveToolbarIconsizesFromTheme();
|
||||
|
||||
// Wait until chrome is painted before executing code not critical to making the window visible
|
||||
this._boundDelayedStartup = this._delayedStartup.bind(this, isLoadingBlank, mustLoadSidebar);
|
||||
this._boundDelayedStartup = this._delayedStartup.bind(this, uriToLoad, mustLoadSidebar);
|
||||
window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
|
||||
|
||||
gStartupRan = true;
|
||||
@ -1253,7 +1214,7 @@ var gBrowserInit = {
|
||||
this._boundDelayedStartup = null;
|
||||
},
|
||||
|
||||
_delayedStartup: function(isLoadingBlank, mustLoadSidebar) {
|
||||
_delayedStartup: function(uriToLoad, mustLoadSidebar) {
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/TelemetryTimestamps.jsm", tmp);
|
||||
let TelemetryTimestamps = tmp.TelemetryTimestamps;
|
||||
@ -1261,6 +1222,45 @@ var gBrowserInit = {
|
||||
|
||||
this._cancelDelayedStartup();
|
||||
|
||||
var isLoadingBlank = isBlankPageURL(uriToLoad);
|
||||
|
||||
if (uriToLoad && uriToLoad != "about:blank") {
|
||||
if (uriToLoad instanceof Ci.nsISupportsArray) {
|
||||
let count = uriToLoad.Count();
|
||||
let specs = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
let urisstring = uriToLoad.GetElementAt(i).QueryInterface(Ci.nsISupportsString);
|
||||
specs.push(urisstring.data);
|
||||
}
|
||||
|
||||
// This function throws for certain malformed URIs, so use exception handling
|
||||
// so that we don't disrupt startup
|
||||
try {
|
||||
gBrowser.loadTabs(specs, false, true);
|
||||
} catch (e) {}
|
||||
}
|
||||
else if (uriToLoad instanceof XULElement) {
|
||||
// swap the given tab with the default about:blank tab and then close
|
||||
// the original tab in the other window.
|
||||
|
||||
// Stop the about:blank load
|
||||
gBrowser.stop();
|
||||
// make sure it has a docshell
|
||||
gBrowser.docShell;
|
||||
|
||||
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);
|
||||
}
|
||||
else if (window.arguments.length >= 3) {
|
||||
loadURI(uriToLoad, window.arguments[2], window.arguments[3] || null,
|
||||
window.arguments[4] || false);
|
||||
window.focus();
|
||||
}
|
||||
// Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
|
||||
// Such callers expect that window.arguments[0] is handled as a single URI.
|
||||
else
|
||||
loadOneOrMoreURIs(uriToLoad);
|
||||
}
|
||||
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
// Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008.
|
||||
setTimeout(function() { SafeBrowsing.init(); }, 2000);
|
||||
|
@ -1172,6 +1172,8 @@ Argument.prototype.merge = function(following) {
|
||||
* - prefixPostSpace: Should the prefix be altered to end with a space?
|
||||
* - suffixSpace: Should the suffix be altered to end with a space?
|
||||
* - type: Constructor to use in creating new instances. Default: Argument
|
||||
* - dontQuote: Should we avoid adding prefix/suffix quotes when the text value
|
||||
* has a space? Needed when we're completing a sub-command.
|
||||
*/
|
||||
Argument.prototype.beget = function(options) {
|
||||
var text = this.text;
|
||||
@ -1182,10 +1184,13 @@ Argument.prototype.beget = function(options) {
|
||||
text = options.text;
|
||||
|
||||
// We need to add quotes when the replacement string has spaces or is empty
|
||||
var needsQuote = text.indexOf(' ') >= 0 || text.length == 0;
|
||||
if (needsQuote && /['"]/.test(prefix)) {
|
||||
prefix = prefix + '\'';
|
||||
suffix = '\'' + suffix;
|
||||
if (!options.dontQuote) {
|
||||
var needsQuote = text.indexOf(' ') >= 0 || text.length == 0;
|
||||
var hasQuote = /['"]$/.test(prefix);
|
||||
if (needsQuote && !hasQuote) {
|
||||
prefix = prefix + '\'';
|
||||
suffix = '\'' + suffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1590,9 +1595,9 @@ NamedArgument.prototype.beget = function(options) {
|
||||
options.type = NamedArgument;
|
||||
var begotten = Argument.prototype.beget.call(this, options);
|
||||
|
||||
// Cut the prefix into |whitespace|non-whitespace|whitespace| so we can
|
||||
// Cut the prefix into |whitespace|non-whitespace|whitespace+quote so we can
|
||||
// rebuild nameArg and valueArg from the parts
|
||||
var matches = /^([\s]*)([^\s]*)([\s]*)$/.exec(begotten.prefix);
|
||||
var matches = /^([\s]*)([^\s]*)([\s]*['"]?)$/.exec(begotten.prefix);
|
||||
|
||||
if (this.valueArg == null && begotten.text === '') {
|
||||
begotten.nameArg = new Argument(matches[2], matches[1], matches[3]);
|
||||
@ -3038,13 +3043,23 @@ function hash(str) {
|
||||
return hash;
|
||||
}
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
var character = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + character;
|
||||
hash = hash & hash; // Convert to 32bit integer
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for clearElement/createTextNode/appendChild to make up for the lack
|
||||
* of standards around textContent/innerText
|
||||
*/
|
||||
exports.setTextContent = function(elem, text) {
|
||||
exports.clearElement(elem);
|
||||
var child = elem.ownerDocument.createTextNode(text);
|
||||
elem.appendChild(child);
|
||||
};
|
||||
|
||||
/**
|
||||
* There are problems with innerHTML on XML documents, so we need to do a dance
|
||||
* using document.createRange().createContextualFragment() when in XML mode
|
||||
@ -5411,7 +5426,7 @@ function UnassignedAssignment(requisition, arg) {
|
||||
name: 'param',
|
||||
requisition: requisition,
|
||||
isIncompleteName: (arg.text.charAt(0) === '-')
|
||||
},
|
||||
}
|
||||
});
|
||||
this.paramIndex = -1;
|
||||
this.onAssignmentChange = util.createEvent('UnassignedAssignment.onAssignmentChange');
|
||||
@ -5812,7 +5827,10 @@ Requisition.prototype.complete = function(cursor, predictionChoice) {
|
||||
}
|
||||
else {
|
||||
// Mutate this argument to hold the completion
|
||||
var arg = assignment.arg.beget({ text: prediction.name });
|
||||
var arg = assignment.arg.beget({
|
||||
text: prediction.name,
|
||||
dontQuote: (assignment === this.commandAssignment)
|
||||
});
|
||||
this.setAssignment(assignment, arg, { argUpdate: true });
|
||||
|
||||
if (!prediction.incomplete) {
|
||||
@ -5905,7 +5923,7 @@ Requisition.prototype.toCanonicalString = function() {
|
||||
* to display this typed input. It's a bit like toString on steroids.
|
||||
* <p>
|
||||
* The returned object has the following members:<ul>
|
||||
* <li>char: The character to which this arg trace refers.
|
||||
* <li>character: The character to which this arg trace refers.
|
||||
* <li>arg: The Argument to which this character is assigned.
|
||||
* <li>part: One of ['prefix'|'text'|suffix'] - how was this char understood
|
||||
* </ul>
|
||||
@ -5930,13 +5948,13 @@ Requisition.prototype.createInputArgTrace = function() {
|
||||
var i;
|
||||
this._args.forEach(function(arg) {
|
||||
for (i = 0; i < arg.prefix.length; i++) {
|
||||
args.push({ arg: arg, char: arg.prefix[i], part: 'prefix' });
|
||||
args.push({ arg: arg, character: arg.prefix[i], part: 'prefix' });
|
||||
}
|
||||
for (i = 0; i < arg.text.length; i++) {
|
||||
args.push({ arg: arg, char: arg.text[i], part: 'text' });
|
||||
args.push({ arg: arg, character: arg.text[i], part: 'text' });
|
||||
}
|
||||
for (i = 0; i < arg.suffix.length; i++) {
|
||||
args.push({ arg: arg, char: arg.suffix[i], part: 'suffix' });
|
||||
args.push({ arg: arg, character: arg.suffix[i], part: 'suffix' });
|
||||
}
|
||||
});
|
||||
|
||||
@ -6024,7 +6042,7 @@ Requisition.prototype.getInputStatusMarkup = function(cursor) {
|
||||
}
|
||||
}
|
||||
|
||||
markup.push({ status: status, string: argTrace.char });
|
||||
markup.push({ status: status, string: argTrace.character });
|
||||
}
|
||||
|
||||
// De-dupe: merge entries where 2 adjacent have same status
|
||||
@ -6796,7 +6814,12 @@ Output.prototype.toDom = function(element) {
|
||||
node = util.createElement(document, 'p');
|
||||
}
|
||||
|
||||
util.setContents(node, output.toString());
|
||||
if (this.command.returnType === 'string') {
|
||||
node.textContent = output;
|
||||
}
|
||||
else {
|
||||
util.setContents(node, output.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that links open in a new window.
|
||||
@ -6937,7 +6960,7 @@ var eagerHelperSettingSpec = {
|
||||
lookup: [
|
||||
{ name: 'never', value: Eagerness.NEVER },
|
||||
{ name: 'sometimes', value: Eagerness.SOMETIMES },
|
||||
{ name: 'always', value: Eagerness.ALWAYS },
|
||||
{ name: 'always', value: Eagerness.ALWAYS }
|
||||
]
|
||||
},
|
||||
defaultValue: Eagerness.SOMETIMES,
|
||||
@ -7345,7 +7368,6 @@ var TrueNamedArgument = require('gcli/argument').TrueNamedArgument;
|
||||
var FalseNamedArgument = require('gcli/argument').FalseNamedArgument;
|
||||
var ArrayArgument = require('gcli/argument').ArrayArgument;
|
||||
|
||||
var Conversion = require('gcli/types').Conversion;
|
||||
var ArrayConversion = require('gcli/types').ArrayConversion;
|
||||
|
||||
var StringType = require('gcli/types/basic').StringType;
|
||||
@ -7608,7 +7630,7 @@ function ArrayField(type, options) {
|
||||
this.addButton = util.createElement(this.document, 'button');
|
||||
this.addButton.classList.add('gcli-array-member-add');
|
||||
this.addButton.addEventListener('click', this._onAdd, false);
|
||||
this.addButton.innerHTML = l10n.lookup('fieldArrayAdd');
|
||||
this.addButton.textContent = l10n.lookup('fieldArrayAdd');
|
||||
this.element.appendChild(this.addButton);
|
||||
|
||||
// <div class=gcliArrayMbrs save="${mbrElement}">
|
||||
@ -7676,7 +7698,7 @@ ArrayField.prototype._onAdd = function(ev, subConversion) {
|
||||
var delButton = util.createElement(this.document, 'button');
|
||||
delButton.classList.add('gcli-array-member-del');
|
||||
delButton.addEventListener('click', this._onDel, false);
|
||||
delButton.innerHTML = l10n.lookup('fieldArrayDel');
|
||||
delButton.textContent = l10n.lookup('fieldArrayDel');
|
||||
element.appendChild(delButton);
|
||||
|
||||
var member = {
|
||||
@ -7790,10 +7812,7 @@ Field.prototype.setMessageElement = function(element) {
|
||||
*/
|
||||
Field.prototype.setMessage = function(message) {
|
||||
if (this.messageElement) {
|
||||
if (message == null) {
|
||||
message = '';
|
||||
}
|
||||
util.setContents(this.messageElement, message);
|
||||
util.setTextContent(this.messageElement, message || '');
|
||||
}
|
||||
};
|
||||
|
||||
@ -8453,7 +8472,7 @@ SelectionField.prototype._addOption = function(item) {
|
||||
this.items.push(item);
|
||||
|
||||
var option = util.createElement(this.document, 'option');
|
||||
option.innerHTML = item.name;
|
||||
option.textContent = item.name;
|
||||
option.value = item.index;
|
||||
this.element.appendChild(option);
|
||||
};
|
||||
@ -8594,7 +8613,7 @@ var helpCommandSpec = {
|
||||
name: 'search',
|
||||
type: 'string',
|
||||
description: l10n.lookup('helpSearchDesc'),
|
||||
manual: l10n.lookup('helpSearchManual2'),
|
||||
manual: l10n.lookup('helpSearchManual3'),
|
||||
defaultValue: null
|
||||
}
|
||||
],
|
||||
@ -8679,7 +8698,7 @@ function getListTemplateData(args, context) {
|
||||
|
||||
ondblclick: function(ev) {
|
||||
util.executeCommand(ev.currentTarget, context);
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -8699,11 +8718,8 @@ function getManTemplateData(command, context) {
|
||||
util.executeCommand(ev.currentTarget, context);
|
||||
},
|
||||
|
||||
describe: function(item, element) {
|
||||
var text = item.manual || item.description;
|
||||
var parent = element.ownerDocument.createElement('div');
|
||||
util.setContents(parent, text);
|
||||
return parent.childNodes;
|
||||
describe: function(item) {
|
||||
return item.manual || item.description;
|
||||
},
|
||||
|
||||
getTypeDescription: function(param) {
|
||||
@ -8755,7 +8771,7 @@ define("text!gcli/commands/help_man.html", [], "\n" +
|
||||
"\n" +
|
||||
" <h4 class=\"gcli-help-header\">${l10n.helpManDescription}:</h4>\n" +
|
||||
"\n" +
|
||||
" <p class=\"gcli-help-description\">${describe(command, __element)}</p>\n" +
|
||||
" <p class=\"gcli-help-description\">${describe(command)}</p>\n" +
|
||||
"\n" +
|
||||
" <div if=\"${command.exec}\">\n" +
|
||||
" <h4 class=\"gcli-help-header\">${l10n.helpManParameters}:</h4>\n" +
|
||||
@ -8765,7 +8781,7 @@ define("text!gcli/commands/help_man.html", [], "\n" +
|
||||
" <li foreach=\"param in ${command.params}\">\n" +
|
||||
" ${param.name} <em>${getTypeDescription(param)}</em>\n" +
|
||||
" <br/>\n" +
|
||||
" ${describe(param, __element)}\n" +
|
||||
" ${describe(param)}\n" +
|
||||
" </li>\n" +
|
||||
" </ul>\n" +
|
||||
" </div>\n" +
|
||||
@ -8904,7 +8920,7 @@ var prefSetCmdSpec = {
|
||||
activate: function() {
|
||||
context.exec('pref set ' + exports.allowSet.name + ' true');
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
args.setting.value = args.value;
|
||||
@ -9975,9 +9991,7 @@ Completer.prototype.resized = function(ev) {
|
||||
* Bring the completion element up to date with what the requisition says
|
||||
*/
|
||||
Completer.prototype.update = function(ev) {
|
||||
if (ev && ev.choice != null) {
|
||||
this.choice = ev.choice;
|
||||
}
|
||||
this.choice = (ev && ev.choice != null) ? ev.choice : 0;
|
||||
|
||||
var data = this._getCompleterTemplateData();
|
||||
var template = this.template.cloneNode(true);
|
||||
@ -10140,14 +10154,15 @@ exports.Completer = Completer;
|
||||
|
||||
});
|
||||
define("text!gcli/ui/completer.html", [], "\n" +
|
||||
"<description>\n" +
|
||||
"<description\n" +
|
||||
" xmlns=\"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul\">\n" +
|
||||
" <loop foreach=\"member in ${statusMarkup}\">\n" +
|
||||
" <label class=\"${member.className}\">${member.string}</label>\n" +
|
||||
" <label class=\"${member.className}\" value=\"${member.string}\"></label>\n" +
|
||||
" </loop>\n" +
|
||||
" <label class=\"gcli-in-ontab\">${directTabText}</label>\n" +
|
||||
" <label class=\"gcli-in-todo\" foreach=\"param in ${emptyParameters}\">${param}</label>\n" +
|
||||
" <label class=\"gcli-in-ontab\">${arrowTabText}</label>\n" +
|
||||
" <label class=\"gcli-in-closebrace\" if=\"${unclosedJs}\">}</label>\n" +
|
||||
" <label class=\"gcli-in-ontab\" value=\"${directTabText}\"/>\n" +
|
||||
" <label class=\"gcli-in-todo\" foreach=\"param in ${emptyParameters}\" value=\"${param}\"/>\n" +
|
||||
" <label class=\"gcli-in-ontab\" value=\"${arrowTabText}\"/>\n" +
|
||||
" <label class=\"gcli-in-closebrace\" if=\"${unclosedJs}\" value=\"}\"/>\n" +
|
||||
"</description>\n" +
|
||||
"");
|
||||
|
||||
@ -10375,7 +10390,7 @@ Tooltip.prototype.assignmentContentsChanged = function(ev) {
|
||||
}
|
||||
|
||||
this.field.setConversion(ev.conversion);
|
||||
util.setContents(this.descriptionEle, this.description);
|
||||
util.setTextContent(this.descriptionEle, this.description);
|
||||
|
||||
this._updatePosition();
|
||||
};
|
||||
@ -10429,19 +10444,7 @@ Object.defineProperty(Tooltip.prototype, 'description', {
|
||||
return '';
|
||||
}
|
||||
|
||||
var output = this.assignment.param.manual;
|
||||
if (output) {
|
||||
var wrapper = this.document.createElement('span');
|
||||
util.setContents(wrapper, output);
|
||||
if (!this.assignment.param.isDataRequired) {
|
||||
var optional = this.document.createElement('span');
|
||||
optional.appendChild(this.document.createTextNode(' (Optional)'));
|
||||
wrapper.appendChild(optional);
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
return this.assignment.param.description;
|
||||
return this.assignment.param.manual || this.assignment.param.description;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
@ -407,5 +407,53 @@ exports.testCompleteIntoOptional = function(options) {
|
||||
});
|
||||
};
|
||||
|
||||
exports.testSpaceComplete = function(options) {
|
||||
helpers.setInput('tslong --sel2 wit');
|
||||
helpers.check({
|
||||
input: 'tslong --sel2 wit',
|
||||
hints: 'h space <msg> [options]',
|
||||
markup: 'VVVVVVVIIIIIIVIII',
|
||||
cursor: 17,
|
||||
current: 'sel2',
|
||||
status: 'ERROR',
|
||||
tooltipState: 'true:importantFieldFlag',
|
||||
args: {
|
||||
command: { name: 'tslong' },
|
||||
msg: { status: 'INCOMPLETE', message: '' },
|
||||
num: { status: 'VALID' },
|
||||
sel: { status: 'VALID' },
|
||||
bool: { value: false, status: 'VALID' },
|
||||
num2: { status: 'VALID' },
|
||||
bool2: { value: false, status: 'VALID' },
|
||||
sel2: { arg: ' --sel2 wit', status: 'INCOMPLETE' }
|
||||
}
|
||||
});
|
||||
|
||||
helpers.pressTab();
|
||||
helpers.check({
|
||||
input: 'tslong --sel2 \'with space\' ',
|
||||
hints: '<msg> [options]',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
cursor: 27,
|
||||
current: 'sel2',
|
||||
status: 'ERROR',
|
||||
tooltipState: 'true:importantFieldFlag',
|
||||
args: {
|
||||
command: { name: 'tslong' },
|
||||
msg: { status: 'INCOMPLETE', message: '' },
|
||||
num: { status: 'VALID' },
|
||||
sel: { status: 'VALID' },
|
||||
bool: { value: false,status: 'VALID' },
|
||||
num2: { status: 'VALID' },
|
||||
bool2: { value: false,status: 'VALID' },
|
||||
sel2: {
|
||||
value: 'with space',
|
||||
arg: ' --sel2 \'with space\' ',
|
||||
status: 'VALID'
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// });
|
||||
|
@ -472,7 +472,7 @@ mockCommands.tslong = {
|
||||
name: 'sel2',
|
||||
type: {
|
||||
name: 'selection',
|
||||
data: ['collapse', 'expand', 'end-expand', 'expand-strict']
|
||||
data: [ 'collapse', 'basic', 'with space', 'with two spaces' ]
|
||||
},
|
||||
description: 'sel2 Desc',
|
||||
defaultValue: "collapse"
|
||||
|
@ -261,8 +261,7 @@ DebuggerPane.prototype = {
|
||||
*/
|
||||
_initServer: function DP__initServer() {
|
||||
if (!DebuggerServer.initialized) {
|
||||
// Always allow connections from nsIPipe transports.
|
||||
DebuggerServer.init(function() true);
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
},
|
||||
|
@ -51,6 +51,7 @@ let DebuggerController = {
|
||||
window.removeEventListener("load", this._startupDebugger, true);
|
||||
|
||||
DebuggerView.initialize(function() {
|
||||
DebuggerView._isInitialized = true;
|
||||
window.dispatchEvent("Debugger:Loaded");
|
||||
this._connect();
|
||||
}.bind(this));
|
||||
@ -67,6 +68,7 @@ let DebuggerController = {
|
||||
window.removeEventListener("unload", this._shutdownDebugger, true);
|
||||
|
||||
DebuggerView.destroy(function() {
|
||||
DebuggerView._isDestroyed = true;
|
||||
this.SourceScripts.disconnect();
|
||||
this.StackFrames.disconnect();
|
||||
this.ThreadState.disconnect();
|
||||
@ -155,8 +157,13 @@ let DebuggerController = {
|
||||
|
||||
client.connect(function(aType, aTraits) {
|
||||
client.listTabs(function(aResponse) {
|
||||
let tab = aResponse.tabs[aResponse.selected];
|
||||
this._startDebuggingTab(client, tab);
|
||||
if (window._isChromeDebugger) {
|
||||
let dbg = aResponse.chromeDebugger;
|
||||
this._startChromeDebugging(client, dbg);
|
||||
} else {
|
||||
let tab = aResponse.tabs[aResponse.selected];
|
||||
this._startDebuggingTab(client, tab);
|
||||
}
|
||||
window.dispatchEvent("Debugger:Connected");
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
@ -234,6 +241,36 @@ let DebuggerController = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up a chrome debugging session.
|
||||
*
|
||||
* @param DebuggerClient aClient
|
||||
* The debugger client.
|
||||
* @param object aChromeDebugger
|
||||
* The remote protocol grip of the chrome debugger.
|
||||
*/
|
||||
_startChromeDebugging: function DC__startChromeDebugging(aClient, aChromeDebugger) {
|
||||
if (!aClient) {
|
||||
Cu.reportError("No client found!");
|
||||
return;
|
||||
}
|
||||
this.client = aClient;
|
||||
|
||||
aClient.attachThread(aChromeDebugger, function(aResponse, aThreadClient) {
|
||||
if (!aThreadClient) {
|
||||
Cu.reportError("Couldn't attach to thread: " + aResponse.error);
|
||||
return;
|
||||
}
|
||||
this.activeThread = aThreadClient;
|
||||
|
||||
this.ThreadState.connect();
|
||||
this.StackFrames.connect();
|
||||
this.SourceScripts.connect();
|
||||
aThreadClient.resume();
|
||||
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempts to quit the current process if allowed.
|
||||
*/
|
||||
@ -685,6 +722,7 @@ StackFrames.prototype = {
|
||||
*/
|
||||
function SourceScripts() {
|
||||
this._onNewScript = this._onNewScript.bind(this);
|
||||
this._onNewGlobal = this._onNewGlobal.bind(this);
|
||||
this._onScriptsAdded = this._onScriptsAdded.bind(this);
|
||||
}
|
||||
|
||||
@ -697,6 +735,7 @@ SourceScripts.prototype = {
|
||||
*/
|
||||
connect: function SS_connect() {
|
||||
this.debuggerClient.addListener("newScript", this._onNewScript);
|
||||
this.debuggerClient.addListener("newGlobal", this._onNewGlobal);
|
||||
this._handleTabNavigation();
|
||||
},
|
||||
|
||||
@ -708,6 +747,7 @@ SourceScripts.prototype = {
|
||||
return;
|
||||
}
|
||||
this.debuggerClient.removeListener("newScript", this._onNewScript);
|
||||
this.debuggerClient.removeListener("newGlobal", this._onNewGlobal);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -769,6 +809,14 @@ SourceScripts.prototype = {
|
||||
window.dispatchEvent("Debugger:AfterNewScript");
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the debugger client's unsolicited newGlobal notification.
|
||||
*/
|
||||
_onNewGlobal: function SS__onNewGlobal(aNotification, aPacket) {
|
||||
// TODO: bug 806775, update the globals list using aPacket.hostAnnotations
|
||||
// from bug 801084.
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for the debugger's active thread getScripts() method.
|
||||
*/
|
||||
|
@ -56,7 +56,8 @@ ToolbarView.prototype = {
|
||||
this._stepOutButton.setAttribute("tooltiptext", this._stepOutTooltip);
|
||||
|
||||
this.toggleCloseButton(!window._isRemoteDebugger && !window._isChromeDebugger);
|
||||
this.toggleChromeGlobalsContainer(window._isChromeDebugger);
|
||||
// TODO: bug 806775
|
||||
// this.toggleChromeGlobalsContainer(window._isChromeDebugger);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -584,11 +585,12 @@ FilterView.prototype = {
|
||||
this._lineOperatorLabel.setAttribute("value",
|
||||
L10N.getFormatStr("searchPanelLine", [this._lineSearchKey]));
|
||||
|
||||
if (window._isChromeDebugger) {
|
||||
this.target = DebuggerView.ChromeGlobals;
|
||||
} else {
|
||||
this.target = DebuggerView.Sources;
|
||||
}
|
||||
// TODO: bug 806775
|
||||
// if (window._isChromeDebugger) {
|
||||
// this.target = DebuggerView.ChromeGlobals;
|
||||
// } else {
|
||||
this.target = DebuggerView.Sources;
|
||||
// }
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -45,7 +45,6 @@ let DebuggerView = {
|
||||
|
||||
this._initializePanes();
|
||||
this._initializeEditor(aCallback)
|
||||
this._isInitialized = true;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -157,8 +156,11 @@ let DebuggerView = {
|
||||
* The script url.
|
||||
* @param string aContentType [optional]
|
||||
* The script content type.
|
||||
* @param string aTextContent [optional]
|
||||
* The script text content.
|
||||
*/
|
||||
setEditorMode: function DV_setEditorMode(aUrl, aContentType) {
|
||||
setEditorMode:
|
||||
function DV_setEditorMode(aUrl, aContentType = "", aTextContent = "") {
|
||||
if (!this.editor) {
|
||||
return;
|
||||
}
|
||||
@ -171,12 +173,16 @@ let DebuggerView = {
|
||||
} else {
|
||||
this.editor.setMode(SourceEditor.MODES.HTML);
|
||||
}
|
||||
} else if (aTextContent.match(/^\s*</)) {
|
||||
// Use HTML mode for files in which the first non whitespace character is
|
||||
// <, regardless of extension.
|
||||
this.editor.setMode(SourceEditor.MODES.HTML);
|
||||
} else {
|
||||
// Use JS mode for files with .js and .jsm extensions.
|
||||
if (/\.jsm?$/.test(SourceUtils.trimUrlQuery(aUrl))) {
|
||||
this.editor.setMode(SourceEditor.MODES.JAVASCRIPT);
|
||||
} else {
|
||||
this.editor.setMode(SourceEditor.MODES.HTML);
|
||||
this.editor.setMode(SourceEditor.MODES.TEXT);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -216,7 +222,9 @@ let DebuggerView = {
|
||||
// If the source is already loaded, display it immediately.
|
||||
else {
|
||||
if (aSource.text.length < SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE) {
|
||||
this.setEditorMode(aSource.url, aSource.contentType);
|
||||
this.setEditorMode(aSource.url, aSource.contentType, aSource.text);
|
||||
} else {
|
||||
this.editor.setMode(SourceEditor.MODES.TEXT);
|
||||
}
|
||||
this.editor.setText(aSource.text);
|
||||
this.editor.resetUndo();
|
||||
@ -419,6 +427,7 @@ let DebuggerView = {
|
||||
_stackframesAndBreakpoints: null,
|
||||
_variables: null,
|
||||
_isInitialized: false,
|
||||
_isDestroyed: false
|
||||
};
|
||||
|
||||
/**
|
||||
@ -752,7 +761,7 @@ MenuContainer.prototype = {
|
||||
* @param string aLabel
|
||||
*/
|
||||
set selectedLabel(aLabel) {
|
||||
let item = this._itemsByLabel.get(aValue);
|
||||
let item = this._itemsByLabel.get(aLabel);
|
||||
if (item) {
|
||||
this._container.selectedItem = item.target;
|
||||
}
|
||||
|
@ -73,6 +73,8 @@ MOCHITEST_BROWSER_TESTS = \
|
||||
browser_dbg_bfcache.js \
|
||||
browser_dbg_breakpoint-new-script.js \
|
||||
browser_dbg_bug737803_editor_actual_location.js \
|
||||
browser_dbg_progress-listener-bug.js \
|
||||
browser_dbg_chrome-debugging.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
|
@ -0,0 +1,71 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Tests that chrome debugging works.
|
||||
|
||||
var gClient = null;
|
||||
var gTab = null;
|
||||
var gThreadClient = null;
|
||||
var gNewGlobal = false;
|
||||
var gAttached = false;
|
||||
var gChromeScript = false;
|
||||
const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html";
|
||||
|
||||
function test()
|
||||
{
|
||||
// Make sure there is enough time for findAllGlobals.
|
||||
requestLongerTimeout(3);
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
gTab = addTab(DEBUGGER_TAB_URL, function() {
|
||||
gClient.listTabs(function(aResponse) {
|
||||
let dbg = aResponse.chromeDebugger;
|
||||
ok(dbg, "Found a chrome debugging actor.");
|
||||
|
||||
gClient.addOneTimeListener("newGlobal", function() gNewGlobal = true);
|
||||
gClient.addListener("newScript", onNewScript);
|
||||
|
||||
gClient.attachThread(dbg, function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
ok(!aResponse.error, "Attached to the chrome debugger.");
|
||||
gAttached = true;
|
||||
|
||||
// Ensure that a new global will be created.
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.querySelector("body").appendChild(frame);
|
||||
|
||||
finish_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onNewScript(aEvent, aScript)
|
||||
{
|
||||
if (aScript.url.startsWith("chrome:")) {
|
||||
gChromeScript = true;
|
||||
}
|
||||
finish_test();
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
if (!gAttached || !gChromeScript) {
|
||||
return;
|
||||
}
|
||||
gClient.removeListener("newScript", onNewScript);
|
||||
gThreadClient.resume(function(aResponse) {
|
||||
removeTab(gTab);
|
||||
gClient.close(function() {
|
||||
ok(gNewGlobal, "Received newGlobal event.");
|
||||
ok(gChromeScript, "Received newScript event for a chrome: script.");
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}
|
@ -83,10 +83,17 @@ function test() {
|
||||
});
|
||||
|
||||
let iframe = gTab.linkedBrowser.contentWindow.wrappedJSObject.frames[0];
|
||||
|
||||
is(iframe.document.title, "Browser Debugger Test Tab", "Found the iframe");
|
||||
|
||||
iframe.runDebuggerStatement();
|
||||
function handler() {
|
||||
if (iframe.document.readyState != "complete") {
|
||||
return;
|
||||
}
|
||||
iframe.window.removeEventListener("load", handler, false);
|
||||
executeSoon(iframe.runDebuggerStatement);
|
||||
};
|
||||
iframe.window.addEventListener("load", handler, false);
|
||||
handler();
|
||||
},
|
||||
function beforeTabAdded() {
|
||||
if (!DebuggerServer.initialized) {
|
||||
|
@ -47,10 +47,17 @@ function test() {
|
||||
});
|
||||
|
||||
let iframe = gTab.linkedBrowser.contentWindow.wrappedJSObject.frames[0];
|
||||
|
||||
is(iframe.document.title, "Browser Debugger Test Tab", "Found the iframe");
|
||||
|
||||
iframe.runDebuggerStatement();
|
||||
function handler() {
|
||||
if (iframe.document.readyState != "complete") {
|
||||
return;
|
||||
}
|
||||
iframe.window.removeEventListener("load", handler, false);
|
||||
executeSoon(iframe.runDebuggerStatement);
|
||||
};
|
||||
iframe.window.addEventListener("load", handler, false);
|
||||
handler();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -13,43 +13,61 @@ var gDebugger = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
|
||||
testSimpleCall();
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
runTest();
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
});
|
||||
|
||||
window.addEventListener("Debugger:SourceShown", function _onEvent(aEvent) {
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("browser_dbg_stack") != -1) {
|
||||
scriptShown = true;
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
runTest();
|
||||
}
|
||||
});
|
||||
|
||||
function runTest()
|
||||
{
|
||||
if (scriptShown && framesAdded) {
|
||||
Services.tm.currentThread.dispatch({ run: testSimpleCall }, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({
|
||||
run: function() {
|
||||
var frames = gDebugger.DebuggerView.StackFrames._container._list,
|
||||
childNodes = frames.childNodes;
|
||||
var frames = gDebugger.DebuggerView.StackFrames._container._list,
|
||||
childNodes = frames.childNodes;
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
|
||||
"Should have only one frame.");
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
|
||||
"Should have only one frame.");
|
||||
|
||||
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
|
||||
"All children should be frames.");
|
||||
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
|
||||
"All children should be frames.");
|
||||
|
||||
isnot(gDebugger.DebuggerView.Sources.selectedValue, null,
|
||||
"There should be a selected script.");
|
||||
isnot(gDebugger.editor.getText().length, 0,
|
||||
"The source editor should have some text displayed.");
|
||||
isnot(gDebugger.DebuggerView.Sources.selectedValue, null,
|
||||
"There should be a selected script.");
|
||||
isnot(gDebugger.editor.getText().length, 0,
|
||||
"The source editor should have some text displayed.");
|
||||
isnot(gDebugger.editor.getText(), gDebugger.L10N.getStr("loadingText"),
|
||||
"The source editor text should not be 'Loading...'");
|
||||
|
||||
testLocationChange();
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
testLocationChange();
|
||||
}
|
||||
|
||||
function testLocationChange()
|
||||
|
@ -13,43 +13,61 @@ var gDebugger = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
|
||||
testSimpleCall();
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
runTest();
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
});
|
||||
|
||||
window.addEventListener("Debugger:SourceShown", function _onEvent(aEvent) {
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("browser_dbg_stack") != -1) {
|
||||
scriptShown = true;
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
runTest();
|
||||
}
|
||||
});
|
||||
|
||||
function runTest()
|
||||
{
|
||||
if (scriptShown && framesAdded) {
|
||||
Services.tm.currentThread.dispatch({ run: testSimpleCall }, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({
|
||||
run: function() {
|
||||
var frames = gDebugger.DebuggerView.StackFrames._container._list,
|
||||
childNodes = frames.childNodes;
|
||||
var frames = gDebugger.DebuggerView.StackFrames._container._list,
|
||||
childNodes = frames.childNodes;
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
|
||||
"Should have only one frame.");
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
|
||||
"Should have only one frame.");
|
||||
|
||||
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
|
||||
"All children should be frames.");
|
||||
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
|
||||
"All children should be frames.");
|
||||
|
||||
isnot(gDebugger.DebuggerView.Sources.selectedValue, null,
|
||||
"There should be a selected script.");
|
||||
isnot(gDebugger.editor.getText().length, 0,
|
||||
"The source editor should have some text displayed.");
|
||||
isnot(gDebugger.DebuggerView.Sources.selectedValue, null,
|
||||
"There should be a selected script.");
|
||||
isnot(gDebugger.editor.getText().length, 0,
|
||||
"The source editor should have some text displayed.");
|
||||
isnot(gDebugger.editor.getText(), gDebugger.L10N.getStr("loadingText"),
|
||||
"The source editor text should not be 'Loading...'");
|
||||
|
||||
testLocationChange();
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
testLocationChange();
|
||||
}
|
||||
|
||||
function testLocationChange()
|
||||
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Tests that the debugger does show up even if a progress listener reads the
|
||||
// WebProgress argument's DOMWindow property in onStateChange() (bug 771655).
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gOldListener = null;
|
||||
|
||||
const TEST_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
function test() {
|
||||
installListener();
|
||||
|
||||
debug_tab_pane(TEST_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gPane = aPane;
|
||||
let gDebugger = gPane.contentWindow;
|
||||
|
||||
is(gDebugger.DebuggerController._isInitialized, true,
|
||||
"Controller should be initialized after debug_tab_pane.");
|
||||
is(gDebugger.DebuggerView._isInitialized, true,
|
||||
"View should be initialized after debug_tab_pane.");
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
});
|
||||
}
|
||||
|
||||
// This is taken almost verbatim from bug 771655.
|
||||
function installListener() {
|
||||
if ("_testPL" in window) {
|
||||
gOldListener = _testPL;
|
||||
Cc['@mozilla.org/docloaderservice;1'].getService(Ci.nsIWebProgress)
|
||||
.removeProgressListener(_testPL);
|
||||
}
|
||||
|
||||
window._testPL = {
|
||||
START_DOC: Ci.nsIWebProgressListener.STATE_START |
|
||||
Ci.nsIWebProgressListener.STATE_IS_DOCUMENT,
|
||||
onStateChange: function(wp, req, stateFlags, status) {
|
||||
if ((stateFlags & this.START_DOC) === this.START_DOC) {
|
||||
// This DOMWindow access triggers the unload event.
|
||||
wp.DOMWindow;
|
||||
}
|
||||
},
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupportsWeakReference) ||
|
||||
iid.equals(Ci.nsIWebProgressListener))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
Cc['@mozilla.org/docloaderservice;1'].getService(Ci.nsIWebProgress)
|
||||
.addProgressListener(_testPL, Ci.nsIWebProgress.NOTIFY_STATE_REQUEST);
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
if (gOldListener) {
|
||||
window._testPL = gOldListener;
|
||||
} else {
|
||||
delete window._testPL;
|
||||
}
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
});
|
@ -7,6 +7,9 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript" src="test-script-switching-01.js?q=a"></script>
|
||||
<script type="text/javascript" src="test-editor-mode?a=b"></script>
|
||||
<script type="text/javascript">
|
||||
function banana() { }
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
@ -30,6 +30,7 @@ function test()
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
gScripts = gDebugger.DebuggerView.Sources._container;
|
||||
resumed = true;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
@ -60,14 +61,13 @@ function test()
|
||||
}
|
||||
|
||||
function testScriptsDisplay() {
|
||||
gScripts = gDebugger.DebuggerView.Sources._container;
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(gScripts.itemCount, 2, "Found the expected number of scripts.");
|
||||
is(gScripts.itemCount, 3,
|
||||
"Found the expected number of scripts.");
|
||||
|
||||
is(gDebugger.editor.getMode(), SourceEditor.MODES.HTML,
|
||||
is(gDebugger.editor.getMode(), SourceEditor.MODES.TEXT,
|
||||
"Found the expected editor mode.");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/debugger/) != -1,
|
||||
@ -77,7 +77,7 @@ function testScriptsDisplay() {
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("switching-01.js") != -1) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
testSwitchPaused();
|
||||
testSwitchPaused1();
|
||||
}
|
||||
});
|
||||
|
||||
@ -85,8 +85,14 @@ function testScriptsDisplay() {
|
||||
gDebugger.DebuggerView.Sources.selectedValue = url;
|
||||
}
|
||||
|
||||
function testSwitchPaused()
|
||||
function testSwitchPaused1()
|
||||
{
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(gScripts.itemCount, 3,
|
||||
"Found the expected number of scripts.");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/debugger/) == -1,
|
||||
"The second script is no longer displayed.");
|
||||
|
||||
@ -96,6 +102,38 @@ function testSwitchPaused()
|
||||
is(gDebugger.editor.getMode(), SourceEditor.MODES.JAVASCRIPT,
|
||||
"Found the expected editor mode.");
|
||||
|
||||
window.addEventListener("Debugger:SourceShown", function _onEvent(aEvent) {
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("update-editor-mode") != -1) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
testSwitchPaused2();
|
||||
}
|
||||
});
|
||||
|
||||
let label = "browser_dbg_update-editor-mode.html";
|
||||
gDebugger.DebuggerView.Sources.selectedLabel = label;
|
||||
}
|
||||
|
||||
function testSwitchPaused2()
|
||||
{
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(gScripts.itemCount, 3,
|
||||
"Found the expected number of scripts.");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/firstCall/) == -1,
|
||||
"The first script is no longer displayed.");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/debugger/) == -1,
|
||||
"The second script is no longer displayed.");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/banana/) != -1,
|
||||
"The third script is displayed.");
|
||||
|
||||
is(gDebugger.editor.getMode(), SourceEditor.MODES.HTML,
|
||||
"Found the expected editor mode.");
|
||||
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
closeDebuggerAndFinish();
|
||||
});
|
||||
|
@ -552,7 +552,7 @@ function OutputPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
<html:iframe xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
id="gcli-output-frame"
|
||||
src="chrome://browser/content/devtools/commandlineoutput.xhtml"
|
||||
flex="1"/>
|
||||
sandbox="allow-same-origin"/>
|
||||
</tooltip|panel>
|
||||
*/
|
||||
|
||||
@ -583,6 +583,7 @@ 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("sandbox", "allow-same-origin");
|
||||
this._panel.appendChild(this._frame);
|
||||
|
||||
this.displayedOutput = undefined;
|
||||
@ -850,7 +851,8 @@ function TooltipPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
<html:iframe xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
id="gcli-tooltip-frame"
|
||||
src="chrome://browser/content/devtools/commandlinetooltip.xhtml"
|
||||
flex="1"/>
|
||||
flex="1"
|
||||
sandbox="allow-same-origin"/>
|
||||
</tooltip|panel>
|
||||
*/
|
||||
|
||||
@ -882,6 +884,7 @@ function TooltipPanel(aChromeDoc, aInput, aLoadCallback)
|
||||
this._frame.id = "gcli-tooltip-frame";
|
||||
this._frame.setAttribute("src", "chrome://browser/content/devtools/commandlinetooltip.xhtml");
|
||||
this._frame.setAttribute("flex", "1");
|
||||
this._frame.setAttribute("sandbox", "allow-same-origin");
|
||||
this._panel.appendChild(this._frame);
|
||||
|
||||
this._frame.addEventListener("load", this._onload, true);
|
||||
|
@ -360,9 +360,8 @@ Function .onGUIEnd
|
||||
${AndIf} $CheckboxSendPing == 1
|
||||
System::Int64Op $DownloadedAmount / 1024
|
||||
Pop $DownloadedAmount
|
||||
InetBgDL::Get "${BaseURLStubPing}${Channel}/${AB_CD}/$ExitCode/" \
|
||||
"$FirefoxLaunch/$SecondsToDownload/$DownloadedAmount/" \
|
||||
"$ExistingProfile/$ExistingInstall/" "$PLUGINSDIR\_temp" /END
|
||||
InetBgDL::Get "${BaseURLStubPing}${Channel}/${AB_CD}/$ExitCode/$FirefoxLaunch/$SecondsToDownload/$DownloadedAmount/$ExistingProfile/$ExistingInstall/" \
|
||||
"$PLUGINSDIR\_temp" /END
|
||||
${EndIf}
|
||||
|
||||
${UnloadUAC}
|
||||
|
@ -123,16 +123,15 @@ helpDesc=Get help on the available commands
|
||||
helpManual=Provide help either on a specific command (if a search string is provided and an exact match is found) or on the available commands (if a search string is not provided, or if no exact match is found).
|
||||
|
||||
# LOCALIZATION NOTE (helpSearchDesc): A very short description of the 'search'
|
||||
# parameter to the 'help' command. See helpSearchManual2 for a fuller
|
||||
# parameter to the 'help' command. See helpSearchManual3 for a fuller
|
||||
# description of what it does. This string is designed to be shown in a dialog
|
||||
# with restricted space, which is why it should be as short as possible.
|
||||
helpSearchDesc=Search string
|
||||
|
||||
# LOCALIZATION NOTE (helpSearchManual2): A fuller description of the 'search'
|
||||
# LOCALIZATION NOTE (helpSearchManual3): A fuller description of the 'search'
|
||||
# parameter to the 'help' command. Displayed when the user asks for help on
|
||||
# what it does. Inline HTML (e.g. <strong>) can be used to emphasize the core
|
||||
# concept.
|
||||
helpSearchManual2=<strong>search string</strong> to use in narrowing down the displayed commands. Regular expressions not supported.
|
||||
# what it does.
|
||||
helpSearchManual3=search string to use in narrowing down the displayed commands. Regular expressions not supported.
|
||||
|
||||
# LOCALIZATION NOTE (helpManSynopsis): A heading shown at the top of a help
|
||||
# page for a command in the console It labels a summary of the parameters to
|
||||
|
@ -10,6 +10,7 @@ extern "C" {
|
||||
#include <libgnomevfs/gnome-vfs-mime-utils.h>
|
||||
}
|
||||
|
||||
#include "NSPRFormatTime.h" // must be before anything that includes prtime.h
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
|
48
js/src/jit-test/tests/debug/Debugger-debuggees-19.js
Normal file
48
js/src/jit-test/tests/debug/Debugger-debuggees-19.js
Normal file
@ -0,0 +1,48 @@
|
||||
// removeAllDebuggees removes all the debuggees.
|
||||
|
||||
var dbg = new Debugger;
|
||||
|
||||
// If we eval in a debuggee, log which debuggee it was.
|
||||
var log;
|
||||
dbg.onEnterFrame = function (frame) {
|
||||
log += 'e';
|
||||
log += frame.environment.object.label;
|
||||
};
|
||||
|
||||
var g1 = newGlobal();
|
||||
log = '';
|
||||
g1.eval('Math');
|
||||
assertEq(log, ''); // not yet a debuggee
|
||||
|
||||
var g1w = dbg.addDebuggee(g1);
|
||||
assertEq(g1w instanceof Debugger.Object, true);
|
||||
g1w.label = 'g1';
|
||||
log = '';
|
||||
g1.eval('Math'); // now a debuggee
|
||||
assertEq(log, 'eg1');
|
||||
|
||||
var g2 = newGlobal();
|
||||
log = '';
|
||||
g1.eval('Math'); // debuggee
|
||||
g2.eval('Math'); // not a debuggee
|
||||
assertEq(log, 'eg1');
|
||||
|
||||
var g2w = dbg.addDebuggee(g2);
|
||||
assertEq(g2w instanceof Debugger.Object, true);
|
||||
g2w.label = 'g2';
|
||||
log = '';
|
||||
g1.eval('Math'); // debuggee
|
||||
g2.eval('this'); // debuggee
|
||||
assertEq(log, 'eg1eg2');
|
||||
|
||||
var a1 = dbg.getDebuggees();
|
||||
assertEq(a1.length, 2);
|
||||
|
||||
assertEq(dbg.removeAllDebuggees(), undefined);
|
||||
var a2 = dbg.getDebuggees();
|
||||
assertEq(a2.length, 0);
|
||||
|
||||
log = '';
|
||||
g1.eval('Math'); // no longer a debuggee
|
||||
g2.eval('this'); // no longer a debuggee
|
||||
assertEq(log, '');
|
@ -1869,6 +1869,16 @@ Debugger::removeDebuggee(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
Debugger::removeAllDebuggees(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "removeAllDebuggees", args, dbg);
|
||||
for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
|
||||
dbg->removeDebuggeeGlobal(cx->runtime->defaultFreeOp(), e.front(), NULL, &e);
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
Debugger::hasDebuggee(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -2494,6 +2504,7 @@ JSPropertySpec Debugger::properties[] = {
|
||||
JSFunctionSpec Debugger::methods[] = {
|
||||
JS_FN("addDebuggee", Debugger::addDebuggee, 1, 0),
|
||||
JS_FN("removeDebuggee", Debugger::removeDebuggee, 1, 0),
|
||||
JS_FN("removeAllDebuggees", Debugger::removeAllDebuggees, 0, 0),
|
||||
JS_FN("hasDebuggee", Debugger::hasDebuggee, 1, 0),
|
||||
JS_FN("getDebuggees", Debugger::getDebuggees, 0, 0),
|
||||
JS_FN("getNewestFrame", Debugger::getNewestFrame, 0, 0),
|
||||
|
@ -176,6 +176,7 @@ class Debugger {
|
||||
static JSBool setUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool addDebuggee(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool removeDebuggee(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool removeAllDebuggees(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool hasDebuggee(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool getDebuggees(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool getNewestFrame(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
@ -52,6 +52,9 @@ public class AnnouncementsFetchResourceDelegate extends SyncResourceDelegate {
|
||||
request.addHeader("Accept-Language", delegate.getLocale().toString());
|
||||
request.addHeader("Accept", ACCEPT_HEADER);
|
||||
|
||||
// We never want to keep connections alive.
|
||||
request.addHeader("Connection", "close");
|
||||
|
||||
// Set If-Modified-Since to avoid re-fetching content.
|
||||
final long ifModifiedSince = delegate.getLastFetch();
|
||||
if (ifModifiedSince > 0) {
|
||||
|
@ -33,6 +33,7 @@ REPOSITORY_PATHS = [
|
||||
'mozboot/bootstrap.py',
|
||||
'mozboot/centos.py',
|
||||
'mozboot/fedora.py',
|
||||
'mozboot/gentoo.py',
|
||||
'mozboot/mint.py',
|
||||
'mozboot/openbsd.py',
|
||||
'mozboot/osx.py',
|
||||
|
@ -10,6 +10,7 @@ import sys
|
||||
|
||||
from mozboot.centos import CentOSBootstrapper
|
||||
from mozboot.fedora import FedoraBootstrapper
|
||||
from mozboot.gentoo import GentooBootstrapper
|
||||
from mozboot.mint import MintBootstrapper
|
||||
from mozboot.osx import OSXBootstrapper
|
||||
from mozboot.openbsd import OpenBSDBootstrapper
|
||||
@ -42,6 +43,8 @@ class Bootstrapper(object):
|
||||
cls = CentOSBootstrapper
|
||||
elif distro == 'Fedora':
|
||||
cls = FedoraBootstrapper
|
||||
elif distro == 'Gentoo Base System':
|
||||
cls = GentooBootstrapper
|
||||
elif distro == 'Mint':
|
||||
cls = MintBootstrapper
|
||||
elif distro == 'Ubuntu':
|
||||
|
19
python/mozboot/mozboot/gentoo.py
Normal file
19
python/mozboot/mozboot/gentoo.py
Normal file
@ -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/.
|
||||
|
||||
import os
|
||||
|
||||
from mozboot.base import BaseBootstrapper
|
||||
|
||||
class GentooBootstrapper(BaseBootstrapper):
|
||||
def __init__(self, version, dist_id):
|
||||
BaseBootstrapper.__init__(self)
|
||||
|
||||
self.version = version
|
||||
self.dist_id = dist_id
|
||||
|
||||
def install_system_packages(self):
|
||||
self.run_as_root(['emerge', '--onlydeps', '--quiet', 'firefox'])
|
||||
|
||||
self.run_as_root(['emerge', '--quiet', 'git', 'mercurial'])
|
@ -13,7 +13,6 @@ const HTTP_PORT = 8888;
|
||||
|
||||
let prefs = new Preferences();
|
||||
|
||||
Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
|
||||
prefs.set("extensions.getAddons.get.url", "http://localhost:8888/search/guid:%IDS%");
|
||||
loadAddonTestFunctions();
|
||||
startupManager();
|
||||
@ -77,110 +76,6 @@ function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_get_all_ids() {
|
||||
_("Ensures that getAllIDs() returns an appropriate set.");
|
||||
|
||||
engine._refreshReconcilerState();
|
||||
|
||||
let addon1 = installAddon("test_install1");
|
||||
let addon2 = installAddon("test_bootstrap1_1");
|
||||
|
||||
let ids = store.getAllIDs();
|
||||
do_check_eq("object", typeof(ids));
|
||||
do_check_eq(2, Object.keys(ids).length);
|
||||
do_check_true(addon1.syncGUID in ids);
|
||||
do_check_true(addon2.syncGUID in ids);
|
||||
|
||||
addon1.install.cancel();
|
||||
uninstallAddon(addon2);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_change_item_id() {
|
||||
_("Ensures that changeItemID() works properly.");
|
||||
|
||||
let addon = installAddon("test_bootstrap1_1");
|
||||
|
||||
let oldID = addon.syncGUID;
|
||||
let newID = Utils.makeGUID();
|
||||
|
||||
store.changeItemID(oldID, newID);
|
||||
|
||||
let newAddon = getAddonFromAddonManagerByID(addon.id);
|
||||
do_check_neq(null, newAddon);
|
||||
do_check_eq(newID, newAddon.syncGUID);
|
||||
|
||||
uninstallAddon(newAddon);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_create() {
|
||||
_("Ensure creating/installing an add-on from a record works.");
|
||||
|
||||
let server = createAndStartHTTPServer(HTTP_PORT);
|
||||
|
||||
let addon = installAddon("test_bootstrap1_1");
|
||||
let id = addon.id;
|
||||
uninstallAddon(addon);
|
||||
|
||||
let guid = Utils.makeGUID();
|
||||
let record = createRecordForThisApp(guid, id, true, false);
|
||||
|
||||
let failed = store.applyIncomingBatch([record]);
|
||||
do_check_eq(0, failed.length);
|
||||
|
||||
let newAddon = getAddonFromAddonManagerByID(id);
|
||||
do_check_neq(null, newAddon);
|
||||
do_check_eq(guid, newAddon.syncGUID);
|
||||
do_check_false(newAddon.userDisabled);
|
||||
|
||||
uninstallAddon(newAddon);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_create_missing_search() {
|
||||
_("Ensures that failed add-on searches are handled gracefully.");
|
||||
|
||||
let server = createAndStartHTTPServer(HTTP_PORT);
|
||||
|
||||
// The handler for this ID is not installed, so a search should 404.
|
||||
const id = "missing@tests.mozilla.org";
|
||||
let guid = Utils.makeGUID();
|
||||
let record = createRecordForThisApp(guid, id, true, false);
|
||||
|
||||
let failed = store.applyIncomingBatch([record]);
|
||||
do_check_eq(1, failed.length);
|
||||
do_check_eq(guid, failed[0]);
|
||||
|
||||
let addon = getAddonFromAddonManagerByID(id);
|
||||
do_check_eq(null, addon);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_create_bad_install() {
|
||||
_("Ensures that add-ons without a valid install are handled gracefully.");
|
||||
|
||||
let server = createAndStartHTTPServer(HTTP_PORT);
|
||||
|
||||
// The handler returns a search result but the XPI will 404.
|
||||
const id = "missing-xpi@tests.mozilla.org";
|
||||
let guid = Utils.makeGUID();
|
||||
let record = createRecordForThisApp(guid, id, true, false);
|
||||
|
||||
let failed = store.applyIncomingBatch([record]);
|
||||
do_check_eq(1, failed.length);
|
||||
do_check_eq(guid, failed[0]);
|
||||
|
||||
let addon = getAddonFromAddonManagerByID(id);
|
||||
do_check_eq(null, addon);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_remove() {
|
||||
_("Ensure removing add-ons from deleted records works.");
|
||||
|
||||
@ -406,6 +301,122 @@ add_test(function test_ignore_hotfixes() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
||||
add_test(function test_get_all_ids() {
|
||||
_("Ensures that getAllIDs() returns an appropriate set.");
|
||||
|
||||
Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
|
||||
|
||||
_("Installing two addons.");
|
||||
let addon1 = installAddon("test_install1");
|
||||
let addon2 = installAddon("test_bootstrap1_1");
|
||||
|
||||
_("Ensure they're syncable.");
|
||||
do_check_true(store.isAddonSyncable(addon1));
|
||||
do_check_true(store.isAddonSyncable(addon2));
|
||||
|
||||
let ids = store.getAllIDs();
|
||||
|
||||
do_check_eq("object", typeof(ids));
|
||||
do_check_eq(2, Object.keys(ids).length);
|
||||
do_check_true(addon1.syncGUID in ids);
|
||||
do_check_true(addon2.syncGUID in ids);
|
||||
|
||||
addon1.install.cancel();
|
||||
uninstallAddon(addon2);
|
||||
|
||||
Svc.Prefs.reset("addons.ignoreRepositoryChecking");
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_change_item_id() {
|
||||
_("Ensures that changeItemID() works properly.");
|
||||
|
||||
let addon = installAddon("test_bootstrap1_1");
|
||||
|
||||
let oldID = addon.syncGUID;
|
||||
let newID = Utils.makeGUID();
|
||||
|
||||
store.changeItemID(oldID, newID);
|
||||
|
||||
let newAddon = getAddonFromAddonManagerByID(addon.id);
|
||||
do_check_neq(null, newAddon);
|
||||
do_check_eq(newID, newAddon.syncGUID);
|
||||
|
||||
uninstallAddon(newAddon);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_create() {
|
||||
_("Ensure creating/installing an add-on from a record works.");
|
||||
|
||||
// Set this so that getInstallFromSearchResult doesn't end up
|
||||
// failing the install due to an insecure source URI scheme.
|
||||
Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
|
||||
let server = createAndStartHTTPServer(HTTP_PORT);
|
||||
|
||||
let addon = installAddon("test_bootstrap1_1");
|
||||
let id = addon.id;
|
||||
uninstallAddon(addon);
|
||||
|
||||
let guid = Utils.makeGUID();
|
||||
let record = createRecordForThisApp(guid, id, true, false);
|
||||
|
||||
let failed = store.applyIncomingBatch([record]);
|
||||
do_check_eq(0, failed.length);
|
||||
|
||||
let newAddon = getAddonFromAddonManagerByID(id);
|
||||
do_check_neq(null, newAddon);
|
||||
do_check_eq(guid, newAddon.syncGUID);
|
||||
do_check_false(newAddon.userDisabled);
|
||||
|
||||
uninstallAddon(newAddon);
|
||||
|
||||
Svc.Prefs.reset("addons.ignoreRepositoryChecking");
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_create_missing_search() {
|
||||
_("Ensures that failed add-on searches are handled gracefully.");
|
||||
|
||||
let server = createAndStartHTTPServer(HTTP_PORT);
|
||||
|
||||
// The handler for this ID is not installed, so a search should 404.
|
||||
const id = "missing@tests.mozilla.org";
|
||||
let guid = Utils.makeGUID();
|
||||
let record = createRecordForThisApp(guid, id, true, false);
|
||||
|
||||
let failed = store.applyIncomingBatch([record]);
|
||||
do_check_eq(1, failed.length);
|
||||
do_check_eq(guid, failed[0]);
|
||||
|
||||
let addon = getAddonFromAddonManagerByID(id);
|
||||
do_check_eq(null, addon);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_create_bad_install() {
|
||||
_("Ensures that add-ons without a valid install are handled gracefully.");
|
||||
|
||||
let server = createAndStartHTTPServer(HTTP_PORT);
|
||||
|
||||
// The handler returns a search result but the XPI will 404.
|
||||
const id = "missing-xpi@tests.mozilla.org";
|
||||
let guid = Utils.makeGUID();
|
||||
let record = createRecordForThisApp(guid, id, true, false);
|
||||
|
||||
let failed = store.applyIncomingBatch([record]);
|
||||
do_check_eq(1, failed.length);
|
||||
do_check_eq(guid, failed[0]);
|
||||
|
||||
let addon = getAddonFromAddonManagerByID(id);
|
||||
do_check_eq(null, addon);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_wipe() {
|
||||
_("Ensures that wiping causes add-ons to be uninstalled.");
|
||||
|
||||
|
@ -10,7 +10,7 @@ const logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
|
||||
const LOG_PREFIX_SUCCESS = "success-";
|
||||
const LOG_PREFIX_ERROR = "error-";
|
||||
const CLEANUP_DELAY = 1000; // delay to age files for cleanup (ms)
|
||||
const DELAY_BUFFER = 50; // buffer for timers on different OS platforms
|
||||
const DELAY_BUFFER = 500; // buffer for timers on different OS platforms
|
||||
|
||||
const PROLONGED_ERROR_DURATION =
|
||||
(Svc.Prefs.get('errorhandler.networkFailureReportTimeout') * 2) * 1000;
|
||||
@ -248,8 +248,8 @@ add_test(function test_login_error_logOnError_true() {
|
||||
|
||||
// Check that error log files are deleted above an age threshold.
|
||||
add_test(function test_logErrorCleanup_age() {
|
||||
let maxAge = CLEANUP_DELAY/1000;
|
||||
let firstlog_name;
|
||||
_("Beginning test_logErrorCleanup_age.");
|
||||
let maxAge = CLEANUP_DELAY / 1000;
|
||||
let oldLogs = [];
|
||||
let numLogs = 10;
|
||||
let errString = "some error log\n";
|
||||
@ -257,13 +257,15 @@ add_test(function test_logErrorCleanup_age() {
|
||||
Svc.Prefs.set("log.appender.file.logOnError", true);
|
||||
Svc.Prefs.set("log.appender.file.maxErrorAge", maxAge);
|
||||
|
||||
// Make some files.
|
||||
_("Making some files.");
|
||||
for (let i = 0; i < numLogs; i++) {
|
||||
let filename = LOG_PREFIX_ERROR + Date.now() + i + ".txt";
|
||||
let now = Date.now();
|
||||
let filename = LOG_PREFIX_ERROR + now + "" + i + ".txt";
|
||||
let newLog = FileUtils.getFile("ProfD", ["weave", "logs", filename]);
|
||||
let foStream = FileUtils.openFileOutputStream(newLog);
|
||||
foStream.write(errString, errString.length);
|
||||
foStream.close();
|
||||
_(" > Created " + filename);
|
||||
oldLogs.push(newLog.leafName);
|
||||
}
|
||||
|
||||
@ -291,7 +293,10 @@ add_test(function test_logErrorCleanup_age() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
let delay = CLEANUP_DELAY + DELAY_BUFFER;
|
||||
|
||||
_("Cleaning up logs after " + delay + "msec.");
|
||||
CommonUtils.namedTimer(function onTimer() {
|
||||
Svc.Obs.notify("weave:service:sync:error");
|
||||
}, CLEANUP_DELAY + DELAY_BUFFER, this, "cleanup-timer");
|
||||
}, delay, this, "cleanup-timer");
|
||||
});
|
||||
|
@ -96,8 +96,11 @@ Tester.prototype = {
|
||||
Services.obs.addObserver(this, "chrome-document-global-created", false);
|
||||
Services.obs.addObserver(this, "content-document-global-created", false);
|
||||
this._globalProperties = Object.keys(window);
|
||||
this._globalPropertyWhitelist = ["navigator", "constructor", "Application",
|
||||
"__SS_tabsToRestore", "__SSi", "webConsoleCommandController",
|
||||
this._globalPropertyWhitelist = [
|
||||
"navigator", "constructor", "top",
|
||||
"Application",
|
||||
"__SS_tabsToRestore", "__SSi",
|
||||
"webConsoleCommandController",
|
||||
];
|
||||
|
||||
if (this.tests.length)
|
||||
|
@ -186,6 +186,8 @@ let snapshotFormatters = {
|
||||
userJSFile.append("user.js");
|
||||
$("prefs-user-js-link").href = Services.io.newFileURI(userJSFile).spec;
|
||||
$("prefs-user-js-section").style.display = "";
|
||||
// Clear the no-copy class
|
||||
$("prefs-user-js-section").className = "";
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -209,7 +209,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<section id="prefs-user-js-section" style="display:none">
|
||||
<section id="prefs-user-js-section" class="no-copy" style="display:none">
|
||||
<h3>&aboutSupport.userJSTitle;</h3>
|
||||
<p>&aboutSupport.userJSDescription;</p>
|
||||
</section>
|
||||
|
@ -173,6 +173,7 @@ const UnsolicitedNotifications = {
|
||||
"locationChange": "locationChange",
|
||||
"networkEvent": "networkEvent",
|
||||
"networkEventUpdate": "networkEventUpdate",
|
||||
"newGlobal": "newGlobal",
|
||||
"newScript": "newScript",
|
||||
"tabDetached": "tabDetached",
|
||||
"tabNavigated": "tabNavigated",
|
||||
|
@ -72,18 +72,26 @@ BrowserRootActor.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the listTabs request. Builds a list of actors
|
||||
* for the tabs running in the process. The actors will survive
|
||||
* until at least the next listTabs request.
|
||||
* Handles the listTabs request. Builds a list of actors for the tabs running
|
||||
* in the process. The actors will survive until at least the next listTabs
|
||||
* request.
|
||||
*/
|
||||
onListTabs: function BRA_onListTabs() {
|
||||
// Get actors for all the currently-running tabs (reusing
|
||||
// existing actors where applicable), and store them in
|
||||
// an ActorPool.
|
||||
// Get actors for all the currently-running tabs (reusing existing actors
|
||||
// where applicable), and store them in an ActorPool.
|
||||
|
||||
let actorPool = new ActorPool(this.conn);
|
||||
let tabActorList = [];
|
||||
|
||||
// Get the chrome debugger actor.
|
||||
let actor = this._chromeDebugger;
|
||||
if (!actor) {
|
||||
actor = new ChromeDebuggerActor(this);
|
||||
actor.parentID = this.actorID;
|
||||
this._chromeDebugger = actor;
|
||||
actorPool.addActor(actor);
|
||||
}
|
||||
|
||||
// Walk over open browser windows.
|
||||
let e = windowMediator.getEnumerator("navigator:browser");
|
||||
let top = windowMediator.getMostRecentWindow("navigator:browser");
|
||||
@ -91,12 +99,12 @@ BrowserRootActor.prototype = {
|
||||
while (e.hasMoreElements()) {
|
||||
let win = e.getNext();
|
||||
|
||||
// Watch the window for tab closes so we can invalidate
|
||||
// actors as needed.
|
||||
// Watch the window for tab closes so we can invalidate actors as needed.
|
||||
this.watchWindow(win);
|
||||
|
||||
// List the tabs in this browser.
|
||||
let selectedBrowser = win.getBrowser().selectedBrowser;
|
||||
|
||||
let browsers = win.getBrowser().browsers;
|
||||
for each (let browser in browsers) {
|
||||
if (browser == selectedBrowser && win == top) {
|
||||
@ -115,9 +123,8 @@ BrowserRootActor.prototype = {
|
||||
|
||||
this._createExtraActors(DebuggerServer.globalActorFactories, actorPool);
|
||||
|
||||
// Now drop the old actorID -> actor map. Actors that still
|
||||
// mattered were added to the new map, others will go
|
||||
// away.
|
||||
// Now drop the old actorID -> actor map. Actors that still mattered were
|
||||
// added to the new map, others will go away.
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
}
|
||||
@ -127,7 +134,8 @@ BrowserRootActor.prototype = {
|
||||
let response = {
|
||||
"from": "root",
|
||||
"selected": selected,
|
||||
"tabs": [actor.grip() for (actor of tabActorList)]
|
||||
"tabs": [actor.grip() for (actor of tabActorList)],
|
||||
"chromeDebugger": this._chromeDebugger.actorID
|
||||
};
|
||||
this._appendExtraActors(response);
|
||||
return response;
|
||||
@ -204,7 +212,58 @@ BrowserRootActor.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
// nsIWindowMediatorListener
|
||||
// ChromeDebuggerActor hooks.
|
||||
|
||||
/**
|
||||
* Add the specified actor to the default actor pool connection, in order to
|
||||
* keep it alive as long as the server is. This is used by breakpoints in the
|
||||
* thread and chrome debugger actors.
|
||||
*
|
||||
* @param actor aActor
|
||||
* The actor object.
|
||||
*/
|
||||
addToParentPool: function BRA_addToParentPool(aActor) {
|
||||
this.conn.addActor(aActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the specified actor from the default actor pool.
|
||||
*
|
||||
* @param BreakpointActor aActor
|
||||
* The actor object.
|
||||
*/
|
||||
removeFromParentPool: function BRA_removeFromParentPool(aActor) {
|
||||
this.conn.removeActor(aActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to enter a nested event loop by disabling debuggee events.
|
||||
*/
|
||||
preNest: function BRA_preNest() {
|
||||
let top = windowMediator.getMostRecentWindow("navigator:browser");
|
||||
let browser = top.gBrowser.selectedBrowser;
|
||||
let windowUtils = browser.contentWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.suppressEventHandling(true);
|
||||
windowUtils.suspendTimeouts();
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to exit a nested event loop by enabling debuggee events.
|
||||
*/
|
||||
postNest: function BRA_postNest(aNestData) {
|
||||
let top = windowMediator.getMostRecentWindow("navigator:browser");
|
||||
let browser = top.gBrowser.selectedBrowser;
|
||||
let windowUtils = browser.contentWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.resumeTimeouts();
|
||||
windowUtils.suppressEventHandling(false);
|
||||
},
|
||||
|
||||
// nsIWindowMediatorListener.
|
||||
|
||||
onWindowTitleChange: function BRA_onWindowTitleChange(aWindow, aTitle) { },
|
||||
onOpenWindow: function BRA_onOpenWindow(aWindow) { },
|
||||
onCloseWindow: function BRA_onCloseWindow(aWindow) {
|
||||
@ -267,23 +326,24 @@ BrowserTabActor.prototype = {
|
||||
_pendingNavigation: null,
|
||||
|
||||
/**
|
||||
* Add the specified breakpoint to the default actor pool connection, in order
|
||||
* to be alive as long as the server is.
|
||||
* Add the specified actor to the default actor pool connection, in order to
|
||||
* keep it alive as long as the server is. This is used by breakpoints in the
|
||||
* thread actor.
|
||||
*
|
||||
* @param BreakpointActor aActor
|
||||
* @param actor aActor
|
||||
* The actor object.
|
||||
*/
|
||||
addToBreakpointPool: function BTA_addToBreakpointPool(aActor) {
|
||||
addToParentPool: function BTA_addToParentPool(aActor) {
|
||||
this.conn.addActor(aActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the specified breakpint from the default actor pool.
|
||||
* Remove the specified actor from the default actor pool.
|
||||
*
|
||||
* @param BreakpointActor aActor
|
||||
* The actor object.
|
||||
*/
|
||||
removeFromBreakpointPool: function BTA_removeFromBreakpointPool(aActor) {
|
||||
removeFromParentPool: function BTA_removeFromParentPool(aActor) {
|
||||
this.conn.removeActor(aActor);
|
||||
},
|
||||
|
||||
@ -296,9 +356,17 @@ BrowserTabActor.prototype = {
|
||||
dbg_assert(this.actorID,
|
||||
"tab should have an actorID.");
|
||||
|
||||
let title = this.browser.contentTitle;
|
||||
// If contentTitle is empty (e.g. on a not-yet-restored tab), but there is a
|
||||
// tabbrowser (i.e. desktop Firefox, but not Fennec), we can use the label
|
||||
// as the title.
|
||||
if (!title && this._tabbrowser) {
|
||||
title = this._tabbrowser
|
||||
._getTabForContentWindow(this.browser.contentWindow).label;
|
||||
}
|
||||
let response = {
|
||||
actor: this.actorID,
|
||||
title: this.browser.contentTitle,
|
||||
title: title,
|
||||
url: this.browser.currentURI.spec
|
||||
};
|
||||
|
||||
@ -384,21 +452,9 @@ BrowserTabActor.prototype = {
|
||||
this.conn.addActorPool(this._contextPool);
|
||||
|
||||
this.threadActor = new ThreadActor(this);
|
||||
this._addDebuggees(this.browser.contentWindow.wrappedJSObject);
|
||||
this._contextPool.addActor(this.threadActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the provided window and all windows in its frame tree as debuggees.
|
||||
*/
|
||||
_addDebuggees: function BTA__addDebuggees(aWindow) {
|
||||
this.threadActor.addDebuggee(aWindow);
|
||||
let frames = aWindow.frames;
|
||||
for (let i = 0; i < frames.length; i++) {
|
||||
this._addDebuggees(frames[i]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Exits the current thread actor and removes the context-lifetime actor pool.
|
||||
* The content window is no longer being debugged after this call.
|
||||
@ -509,7 +565,9 @@ BrowserTabActor.prototype = {
|
||||
}
|
||||
if (this._attached) {
|
||||
this.threadActor.clearDebuggees();
|
||||
this.threadActor.dbg.enabled = true;
|
||||
if (this.threadActor.dbg) {
|
||||
this.threadActor.dbg.enabled = true;
|
||||
}
|
||||
if (this._progressListener) {
|
||||
delete this._progressListener._needsTabNavigated;
|
||||
}
|
||||
@ -519,7 +577,10 @@ BrowserTabActor.prototype = {
|
||||
}
|
||||
|
||||
if (this._attached) {
|
||||
this._addDebuggees(evt.target.defaultView.wrappedJSObject);
|
||||
this.threadActor.global = evt.target.defaultView.wrappedJSObject;
|
||||
if (this.threadActor.attached) {
|
||||
this.threadActor.findGlobals();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -591,107 +652,10 @@ DebuggerProgressListener.prototype = {
|
||||
* Destroy the progress listener instance.
|
||||
*/
|
||||
destroy: function DPL_destroy() {
|
||||
this._tabActor._tabbrowser.removeProgressListener(this);
|
||||
if (this._tabActor._tabbrowser.removeProgressListener) {
|
||||
this._tabActor._tabbrowser.removeProgressListener(this);
|
||||
}
|
||||
this._tabActor._progressListener = null;
|
||||
this._tabActor = null;
|
||||
}
|
||||
};
|
||||
|
||||
// DebuggerServer extension API.
|
||||
|
||||
/**
|
||||
* Registers handlers for new tab-scoped request types defined dynamically.
|
||||
* This is used for example by add-ons to augment the functionality of the tab
|
||||
* actor.
|
||||
* TODO: remove this API in the next release after bug 753401 lands, once all
|
||||
* our experimental add-ons have been converted to the new API.
|
||||
*
|
||||
* @param aName string
|
||||
* The name of the new request type.
|
||||
* @param aFunction function
|
||||
* The handler for this request type.
|
||||
*/
|
||||
DebuggerServer.addTabRequest = function DS_addTabRequest(aName, aFunction) {
|
||||
BrowserTabActor.prototype.requestTypes[aName] = function(aRequest) {
|
||||
if (!this.attached) {
|
||||
return { error: "wrongState" };
|
||||
}
|
||||
return aFunction(this, aRequest);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers handlers for new tab-scoped request types defined dynamically.
|
||||
* This is used for example by add-ons to augment the functionality of the tab
|
||||
* actor.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
* @param aName string [optional]
|
||||
* The name of the new request type. If this is not present, the
|
||||
* actorPrefix property of the constructor prototype is used.
|
||||
*/
|
||||
DebuggerServer.addTabActor = function DS_addTabActor(aFunction, aName) {
|
||||
let name = aName ? aName : aFunction.prototype.actorPrefix;
|
||||
if (["title", "url", "actor"].indexOf(name) != -1) {
|
||||
throw Error(name + " is not allowed");
|
||||
}
|
||||
if (DebuggerServer.tabActorFactories.hasOwnProperty(name)) {
|
||||
throw Error(name + " already exists");
|
||||
}
|
||||
DebuggerServer.tabActorFactories[name] = aFunction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unregisters the handler for the specified tab-scoped request type.
|
||||
* This may be used for example by add-ons when shutting down or upgrading.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
*/
|
||||
DebuggerServer.removeTabActor = function DS_removeTabActor(aFunction) {
|
||||
for (let name in DebuggerServer.tabActorFactories) {
|
||||
let handler = DebuggerServer.tabActorFactories[name];
|
||||
if (handler.name == aFunction.name) {
|
||||
delete DebuggerServer.tabActorFactories[name];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers handlers for new browser-scoped request types defined dynamically.
|
||||
* This is used for example by add-ons to augment the functionality of the root
|
||||
* actor.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
* @param aName string [optional]
|
||||
* The name of the new request type. If this is not present, the
|
||||
* actorPrefix property of the constructor prototype is used.
|
||||
*/
|
||||
DebuggerServer.addGlobalActor = function DS_addGlobalActor(aFunction, aName) {
|
||||
let name = aName ? aName : aFunction.prototype.actorPrefix;
|
||||
if (["from", "tabs", "selected"].indexOf(name) != -1) {
|
||||
throw Error(name + " is not allowed");
|
||||
}
|
||||
if (DebuggerServer.globalActorFactories.hasOwnProperty(name)) {
|
||||
throw Error(name + " already exists");
|
||||
}
|
||||
DebuggerServer.globalActorFactories[name] = aFunction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unregisters the handler for the specified browser-scoped request type.
|
||||
* This may be used for example by add-ons when shutting down or upgrading.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
*/
|
||||
DebuggerServer.removeGlobalActor = function DS_removeGlobalActor(aFunction) {
|
||||
for (let name in DebuggerServer.globalActorFactories) {
|
||||
let handler = DebuggerServer.globalActorFactories[name];
|
||||
if (handler.name == aFunction.name) {
|
||||
delete DebuggerServer.globalActorFactories[name];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -17,16 +17,27 @@
|
||||
*
|
||||
* @param aHooks object
|
||||
* An object with preNest and postNest methods for calling when entering
|
||||
* and exiting a nested event loop, as well as addToBreakpointPool and
|
||||
* removeFromBreakpointPool methods for handling breakpoint lifetime.
|
||||
* and exiting a nested event loop, addToParentPool and
|
||||
* removeFromParentPool methods for handling the lifetime of actors that
|
||||
* will outlive the thread, like breakpoints, and also an optional (for
|
||||
* content debugging) browser property for getting a reference to the
|
||||
* content window.
|
||||
*/
|
||||
function ThreadActor(aHooks)
|
||||
{
|
||||
this._state = "detached";
|
||||
this._frameActors = [];
|
||||
this._environmentActors = [];
|
||||
this._hooks = aHooks ? aHooks : {};
|
||||
this._hooks = {};
|
||||
if (aHooks) {
|
||||
this._hooks = aHooks;
|
||||
if (aHooks.browser) {
|
||||
this.global = aHooks.browser.contentWindow.wrappedJSObject;
|
||||
}
|
||||
}
|
||||
this._scripts = {};
|
||||
this.findGlobals = this.globalManager.findGlobals.bind(this);
|
||||
this.onNewGlobal = this.globalManager.onNewGlobal.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,6 +50,9 @@ ThreadActor.prototype = {
|
||||
actorPrefix: "context",
|
||||
|
||||
get state() { return this._state; },
|
||||
get attached() this.state == "attached" ||
|
||||
this.state == "running" ||
|
||||
this.state == "paused",
|
||||
|
||||
get _breakpointStore() { return ThreadActor._breakpointStore; },
|
||||
|
||||
@ -52,19 +66,10 @@ ThreadActor.prototype = {
|
||||
|
||||
clearDebuggees: function TA_clearDebuggees() {
|
||||
if (this.dbg) {
|
||||
let debuggees = this.dbg.getDebuggees();
|
||||
for (let debuggee of debuggees) {
|
||||
this.dbg.removeDebuggee(debuggee);
|
||||
}
|
||||
this.dbg.removeAllDebuggees();
|
||||
}
|
||||
this.conn.removeActorPool(this._threadLifetimePool || undefined);
|
||||
this._threadLifetimePool = null;
|
||||
// Unless we carefully take apart the scripts table this way, we end up
|
||||
// leaking documents. It would be nice to track this down carefully, once
|
||||
// we have the appropriate tools.
|
||||
for (let url in this._scripts) {
|
||||
delete this._scripts[url];
|
||||
}
|
||||
this._scripts = {};
|
||||
},
|
||||
|
||||
@ -72,24 +77,25 @@ ThreadActor.prototype = {
|
||||
* Add a debuggee global to the Debugger object.
|
||||
*/
|
||||
addDebuggee: function TA_addDebuggee(aGlobal) {
|
||||
// Use the inspector xpcom component to turn on debugging
|
||||
// for aGlobal's compartment. Ideally this won't be necessary
|
||||
// medium- to long-term, and will be managed by the engine
|
||||
// instead.
|
||||
|
||||
if (!this.dbg) {
|
||||
this.dbg = new Debugger();
|
||||
this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
|
||||
this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this);
|
||||
this.dbg.onNewScript = this.onNewScript.bind(this);
|
||||
// Keep the debugger disabled until a client attaches.
|
||||
this.dbg.enabled = this._state != "detached";
|
||||
try {
|
||||
this.dbg.addDebuggee(aGlobal);
|
||||
} catch (e) {
|
||||
// Ignore attempts to add the debugger's compartment as a debuggee.
|
||||
dumpn("Ignoring request to add the debugger's compartment as a debuggee");
|
||||
}
|
||||
},
|
||||
|
||||
this.dbg.addDebuggee(aGlobal);
|
||||
for (let s of this.dbg.findScripts()) {
|
||||
this._addScript(s);
|
||||
}
|
||||
/**
|
||||
* Initialize the Debugger.
|
||||
*/
|
||||
_initDebugger: function TA__initDebugger() {
|
||||
this.dbg = new Debugger();
|
||||
this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
|
||||
this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this);
|
||||
this.dbg.onNewScript = this.onNewScript.bind(this);
|
||||
this.dbg.onNewGlobalObject = this.globalManager.onNewGlobal.bind(this);
|
||||
// Keep the debugger disabled until a client attaches.
|
||||
this.dbg.enabled = this._state != "detached";
|
||||
},
|
||||
|
||||
/**
|
||||
@ -104,6 +110,53 @@ ThreadActor.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the provided window and all windows in its frame tree as debuggees.
|
||||
*/
|
||||
_addDebuggees: function TA__addDebuggees(aWindow) {
|
||||
this.addDebuggee(aWindow);
|
||||
let frames = aWindow.frames;
|
||||
if (frames) {
|
||||
for (let i = 0; i < frames.length; i++) {
|
||||
this._addDebuggees(frames[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* An object that will be used by ThreadActors to tailor their behavior
|
||||
* depending on the debugging context being required (chrome or content).
|
||||
*/
|
||||
globalManager: {
|
||||
findGlobals: function TA_findGlobals() {
|
||||
this._addDebuggees(this.global);
|
||||
},
|
||||
|
||||
/**
|
||||
* A function that the engine calls when a new global object has been
|
||||
* created.
|
||||
*
|
||||
* @param aGlobal Debugger.Object
|
||||
* The new global object that was created.
|
||||
*/
|
||||
onNewGlobal: function TA_onNewGlobal(aGlobal) {
|
||||
// Content debugging only cares about new globals in the contant window,
|
||||
// like iframe children.
|
||||
if (aGlobal.hostAnnotations &&
|
||||
aGlobal.hostAnnotations.type == "document" &&
|
||||
aGlobal.hostAnnotations.element === this.global) {
|
||||
this.addDebuggee(aGlobal);
|
||||
}
|
||||
// Notify the client.
|
||||
this.conn.send({
|
||||
from: this.actorID,
|
||||
type: "newGlobal",
|
||||
// TODO: after bug 801084 lands see if we need to JSONify this.
|
||||
hostAnnotations: aGlobal.hostAnnotations
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
disconnect: function TA_disconnect() {
|
||||
if (this._state == "paused") {
|
||||
this.onResume();
|
||||
@ -139,10 +192,13 @@ ThreadActor.prototype = {
|
||||
|
||||
this._state = "attached";
|
||||
|
||||
if (!this.dbg) {
|
||||
this._initDebugger();
|
||||
}
|
||||
this.findGlobals();
|
||||
this.dbg.enabled = true;
|
||||
try {
|
||||
// Put ourselves in the paused state.
|
||||
// XXX: We need to put the debuggee in a paused state too.
|
||||
let packet = this._paused();
|
||||
if (!packet) {
|
||||
return { error: "notAttached" };
|
||||
@ -461,7 +517,7 @@ ThreadActor.prototype = {
|
||||
}
|
||||
if (!bpActor) {
|
||||
bpActor = new BreakpointActor(this, location);
|
||||
this._hooks.addToBreakpointPool(bpActor);
|
||||
this._hooks.addToParentPool(bpActor);
|
||||
if (scriptBreakpoints[location.line]) {
|
||||
scriptBreakpoints[location.line].actor = bpActor;
|
||||
}
|
||||
@ -1045,13 +1101,13 @@ ThreadActor.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the provided script to the server cache.
|
||||
* Check if the provided script is allowed to be stored in the cache.
|
||||
*
|
||||
* @param aScript Debugger.Script
|
||||
* The source script that will be stored.
|
||||
* @returns true, if the script was added, false otherwise.
|
||||
* @returns true, if the script can be added, false otherwise.
|
||||
*/
|
||||
_addScript: function TA__addScript(aScript) {
|
||||
_allowScript: function TA__allowScript(aScript) {
|
||||
// Ignore anything we don't have a URL for (eval scripts, for example).
|
||||
if (!aScript.url)
|
||||
return false;
|
||||
@ -1063,6 +1119,20 @@ ThreadActor.prototype = {
|
||||
if (aScript.url.indexOf("about:") == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the provided script to the server cache.
|
||||
*
|
||||
* @param aScript Debugger.Script
|
||||
* The source script that will be stored.
|
||||
* @returns true, if the script was added, false otherwise.
|
||||
*/
|
||||
_addScript: function TA__addScript(aScript) {
|
||||
if (!this._allowScript(aScript)) {
|
||||
return false;
|
||||
}
|
||||
// Use a sparse array for storing the scripts for each URL in order to
|
||||
// optimize retrieval.
|
||||
if (!this._scripts[aScript.url]) {
|
||||
@ -1174,26 +1244,6 @@ PauseScopedActor.prototype = {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Utility function for updating an object with the properties of another
|
||||
* object.
|
||||
*
|
||||
* @param aTarget Object
|
||||
* The object being updated.
|
||||
* @param aNewAttrs Object
|
||||
* The new attributes being set on the target.
|
||||
*/
|
||||
function update(aTarget, aNewAttrs) {
|
||||
for (let key in aNewAttrs) {
|
||||
let desc = Object.getOwnPropertyDescriptor(aNewAttrs, key);
|
||||
|
||||
if (desc) {
|
||||
Object.defineProperty(aTarget, key, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A SourceActor provides information about the source of a script.
|
||||
*
|
||||
@ -1815,7 +1865,7 @@ BreakpointActor.prototype = {
|
||||
let scriptBreakpoints = this.threadActor._breakpointStore[this.location.url];
|
||||
delete scriptBreakpoints[this.location.line];
|
||||
// Remove the actual breakpoint.
|
||||
this.threadActor._hooks.removeFromBreakpointPool(this);
|
||||
this.threadActor._hooks.removeFromParentPool(this);
|
||||
for (let script of this.scripts) {
|
||||
script.clearBreakpoint(this);
|
||||
}
|
||||
@ -2067,3 +2117,89 @@ function getFunctionName(aFunction) {
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates an actor for handling chrome debugging. ChromeDebuggerActor is a
|
||||
* thin wrapper over ThreadActor, slightly changing some of its behavior.
|
||||
*
|
||||
* @param aHooks object
|
||||
* An object with preNest and postNest methods for calling when entering
|
||||
* and exiting a nested event loop and also addToParentPool and
|
||||
* removeFromParentPool methods for handling the lifetime of actors that
|
||||
* will outlive the thread, like breakpoints.
|
||||
*/
|
||||
function ChromeDebuggerActor(aHooks)
|
||||
{
|
||||
ThreadActor.call(this, aHooks);
|
||||
}
|
||||
|
||||
ChromeDebuggerActor.prototype = Object.create(ThreadActor.prototype);
|
||||
|
||||
update(ChromeDebuggerActor.prototype, {
|
||||
constructor: ChromeDebuggerActor,
|
||||
|
||||
// A constant prefix that will be used to form the actor ID by the server.
|
||||
actorPrefix: "chromeDebugger",
|
||||
|
||||
/**
|
||||
* Override the eligibility check for scripts to make sure every script with a
|
||||
* URL is stored when debugging chrome.
|
||||
*/
|
||||
_allowScript: function(aScript) !!aScript.url,
|
||||
|
||||
/**
|
||||
* An object that will be used by ThreadActors to tailor their behavior
|
||||
* depending on the debugging context being required (chrome or content).
|
||||
* The methods that this object provides must be bound to the ThreadActor
|
||||
* before use.
|
||||
*/
|
||||
globalManager: {
|
||||
findGlobals: function CDA_findGlobals() {
|
||||
// Fetch the list of globals from the debugger.
|
||||
for (let g of this.dbg.findAllGlobals()) {
|
||||
this.addDebuggee(g);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A function that the engine calls when a new global object has been
|
||||
* created.
|
||||
*
|
||||
* @param aGlobal Debugger.Object
|
||||
* The new global object that was created.
|
||||
*/
|
||||
onNewGlobal: function CDA_onNewGlobal(aGlobal) {
|
||||
this.addDebuggee(aGlobal);
|
||||
// Notify the client.
|
||||
this.conn.send({
|
||||
from: this.actorID,
|
||||
type: "newGlobal",
|
||||
// TODO: after bug 801084 lands see if we need to JSONify this.
|
||||
hostAnnotations: aGlobal.hostAnnotations
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Utility functions.
|
||||
|
||||
/**
|
||||
* Utility function for updating an object with the properties of another
|
||||
* object.
|
||||
*
|
||||
* @param aTarget Object
|
||||
* The object being updated.
|
||||
* @param aNewAttrs Object
|
||||
* The new attributes being set on the target.
|
||||
*/
|
||||
function update(aTarget, aNewAttrs) {
|
||||
for (let key in aNewAttrs) {
|
||||
let desc = Object.getOwnPropertyDescriptor(aNewAttrs, key);
|
||||
|
||||
if (desc) {
|
||||
Object.defineProperty(aTarget, key, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ var DebuggerServer = {
|
||||
*
|
||||
* @return true if the connection should be permitted, false otherwise
|
||||
*/
|
||||
_defaultAllowConnection: function DH__defaultAllowConnection() {
|
||||
_defaultAllowConnection: function DS__defaultAllowConnection() {
|
||||
let title = L10N.getStr("remoteIncomingPromptTitle");
|
||||
let msg = L10N.getStr("remoteIncomingPromptMessage");
|
||||
let disableButton = L10N.getStr("remoteIncomingPromptDisable");
|
||||
@ -114,7 +114,7 @@ var DebuggerServer = {
|
||||
* The embedder-provider callback, that decides whether an incoming
|
||||
* remote protocol conection should be allowed or refused.
|
||||
*/
|
||||
init: function DH_init(aAllowConnectionCallback) {
|
||||
init: function DS_init(aAllowConnectionCallback) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
@ -135,7 +135,7 @@ var DebuggerServer = {
|
||||
* The embedder-provider callback, that decides whether an incoming
|
||||
* remote protocol conection should be allowed or refused.
|
||||
*/
|
||||
initTransport: function DH_initTransport(aAllowConnectionCallback) {
|
||||
initTransport: function DS_initTransport(aAllowConnectionCallback) {
|
||||
if (this._transportInitialized) {
|
||||
return;
|
||||
}
|
||||
@ -157,7 +157,7 @@ var DebuggerServer = {
|
||||
* debugger server is no longer useful, to avoid memory leaks. After this
|
||||
* method returns, the debugger server must be initialized again before use.
|
||||
*/
|
||||
destroy: function DH_destroy() {
|
||||
destroy: function DS_destroy() {
|
||||
if (Object.keys(this._connections).length == 0) {
|
||||
this.closeListener();
|
||||
delete this.globalActorFactories;
|
||||
@ -176,14 +176,14 @@ var DebuggerServer = {
|
||||
* that implements a createRootActor() function to create the
|
||||
* server's root actor.
|
||||
*/
|
||||
addActors: function DH_addActors(aURL) {
|
||||
addActors: function DS_addActors(aURL) {
|
||||
loadSubScript.call(this, aURL);
|
||||
},
|
||||
|
||||
/**
|
||||
* Install Firefox-specific actors.
|
||||
*/
|
||||
addBrowserActors: function DH_addBrowserActors() {
|
||||
addBrowserActors: function DS_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");
|
||||
@ -198,7 +198,7 @@ var DebuggerServer = {
|
||||
* @param aPort int
|
||||
* The port to listen on.
|
||||
*/
|
||||
openListener: function DH_openListener(aPort) {
|
||||
openListener: function DS_openListener(aPort) {
|
||||
if (!Services.prefs.getBoolPref("devtools.debugger.remote-enabled")) {
|
||||
return false;
|
||||
}
|
||||
@ -235,7 +235,7 @@ var DebuggerServer = {
|
||||
* If set to true, then the socket will be closed, regardless of the
|
||||
* number of open connections.
|
||||
*/
|
||||
closeListener: function DH_closeListener(aForce) {
|
||||
closeListener: function DS_closeListener(aForce) {
|
||||
if (!this._listener || this._socketConnections == 0) {
|
||||
return false;
|
||||
}
|
||||
@ -259,7 +259,7 @@ var DebuggerServer = {
|
||||
* @returns a client-side DebuggerTransport for communicating with
|
||||
* the newly-created connection.
|
||||
*/
|
||||
connectPipe: function DH_connectPipe() {
|
||||
connectPipe: function DS_connectPipe() {
|
||||
this._checkInit();
|
||||
|
||||
let serverTransport = new LocalDebuggerTransport;
|
||||
@ -273,7 +273,7 @@ var DebuggerServer = {
|
||||
|
||||
// nsIServerSocketListener implementation
|
||||
|
||||
onSocketAccepted: function DH_onSocketAccepted(aSocket, aTransport) {
|
||||
onSocketAccepted: function DS_onSocketAccepted(aSocket, aTransport) {
|
||||
if (!this._allowConnection()) {
|
||||
return;
|
||||
}
|
||||
@ -289,12 +289,12 @@ var DebuggerServer = {
|
||||
}
|
||||
},
|
||||
|
||||
onStopListening: function DH_onStopListening() { },
|
||||
onStopListening: function DS_onStopListening() { },
|
||||
|
||||
/**
|
||||
* Raises an exception if the server has not been properly initialized.
|
||||
*/
|
||||
_checkInit: function DH_checkInit() {
|
||||
_checkInit: function DS_checkInit() {
|
||||
if (!this._transportInitialized) {
|
||||
throw "DebuggerServer has not been initialized.";
|
||||
}
|
||||
@ -308,7 +308,7 @@ var DebuggerServer = {
|
||||
* Create a new debugger connection for the given transport. Called
|
||||
* after connectPipe() or after an incoming socket connection.
|
||||
*/
|
||||
_onConnection: function DH_onConnection(aTransport) {
|
||||
_onConnection: function DS_onConnection(aTransport) {
|
||||
let connID = "conn" + this._nextConnID++ + '.';
|
||||
let conn = new DebuggerServerConnection(connID, aTransport);
|
||||
this._connections[connID] = conn;
|
||||
@ -323,11 +323,95 @@ var DebuggerServer = {
|
||||
/**
|
||||
* Remove the connection from the debugging server.
|
||||
*/
|
||||
_connectionClosed: function DH_connectionClosed(aConnection) {
|
||||
_connectionClosed: function DS_connectionClosed(aConnection) {
|
||||
delete this._connections[aConnection.prefix];
|
||||
},
|
||||
|
||||
// DebuggerServer extension API.
|
||||
|
||||
/**
|
||||
* Registers handlers for new tab-scoped request types defined dynamically.
|
||||
* This is used for example by add-ons to augment the functionality of the tab
|
||||
* actor. Note that the name or actorPrefix of the request type is not allowed
|
||||
* to clash with existing protocol packet properties, like 'title', 'url' or
|
||||
* 'actor', since that would break the protocol.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
* @param aName string [optional]
|
||||
* The name of the new request type. If this is not present, the
|
||||
* actorPrefix property of the constructor prototype is used.
|
||||
*/
|
||||
addTabActor: function DS_addTabActor(aFunction, aName) {
|
||||
let name = aName ? aName : aFunction.prototype.actorPrefix;
|
||||
if (["title", "url", "actor"].indexOf(name) != -1) {
|
||||
throw Error(name + " is not allowed");
|
||||
}
|
||||
if (DebuggerServer.tabActorFactories.hasOwnProperty(name)) {
|
||||
throw Error(name + " already exists");
|
||||
}
|
||||
DebuggerServer.tabActorFactories[name] = aFunction;
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregisters the handler for the specified tab-scoped request type.
|
||||
* This may be used for example by add-ons when shutting down or upgrading.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
*/
|
||||
removeTabActor: function DS_removeTabActor(aFunction) {
|
||||
for (let name in DebuggerServer.tabActorFactories) {
|
||||
let handler = DebuggerServer.tabActorFactories[name];
|
||||
if (handler.name == aFunction.name) {
|
||||
delete DebuggerServer.tabActorFactories[name];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Registers handlers for new browser-scoped request types defined
|
||||
* dynamically. This is used for example by add-ons to augment the
|
||||
* functionality of the root actor. Note that the name or actorPrefix of the
|
||||
* request type is not allowed to clash with existing protocol packet
|
||||
* properties, like 'from', 'tabs' or 'selected', since that would break the
|
||||
* protocol.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
* @param aName string [optional]
|
||||
* The name of the new request type. If this is not present, the
|
||||
* actorPrefix property of the constructor prototype is used.
|
||||
*/
|
||||
addGlobalActor: function DS_addGlobalActor(aFunction, aName) {
|
||||
let name = aName ? aName : aFunction.prototype.actorPrefix;
|
||||
if (["from", "tabs", "selected"].indexOf(name) != -1) {
|
||||
throw Error(name + " is not allowed");
|
||||
}
|
||||
if (DebuggerServer.globalActorFactories.hasOwnProperty(name)) {
|
||||
throw Error(name + " already exists");
|
||||
}
|
||||
DebuggerServer.globalActorFactories[name] = aFunction;
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregisters the handler for the specified browser-scoped request type.
|
||||
* This may be used for example by add-ons when shutting down or upgrading.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
*/
|
||||
removeGlobalActor: function DS_removeGlobalActor(aFunction) {
|
||||
for (let name in DebuggerServer.globalActorFactories) {
|
||||
let handler = DebuggerServer.globalActorFactories[name];
|
||||
if (handler.name == aFunction.name) {
|
||||
delete DebuggerServer.globalActorFactories[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Construct an ActorPool.
|
||||
*
|
||||
|
@ -16,16 +16,16 @@ function createRootActor()
|
||||
this.conn.removeActor(aActor);
|
||||
}.bind(this);
|
||||
let hooks = {
|
||||
addToBreakpointPool: addBreakpoint,
|
||||
removeFromBreakpointPool: removeBreakpoint
|
||||
addToParentPool: addBreakpoint,
|
||||
removeFromParentPool: removeBreakpoint
|
||||
};
|
||||
let actor = new ThreadActor(hooks);
|
||||
actor.addDebuggee(g);
|
||||
actor._global = g;
|
||||
actor.global = g;
|
||||
actor.json = function() {
|
||||
return { actor: actor.actorID,
|
||||
threadActor: actor.actorID,
|
||||
global: actor._global.__name };
|
||||
global: actor.global.__name };
|
||||
};
|
||||
this.conn.addActor(actor);
|
||||
this._globalActors.push(actor);
|
||||
|
Loading…
Reference in New Issue
Block a user