Merge mozilla-central to mozilla-inbound
|
@ -599,6 +599,10 @@ toolbarbutton.bookmark-item {
|
|||
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
|
||||
image-rendering: -moz-crisp-edges;
|
||||
}
|
||||
/* Synced Tabs sidebar */
|
||||
html|*.tabs-container html|*.item-tabs-list html|*.item-icon-container {
|
||||
image-rendering: -moz-crisp-edges;
|
||||
}
|
||||
}
|
||||
|
||||
#editBMPanel_tagsSelector {
|
||||
|
|
|
@ -6443,13 +6443,14 @@ function checkEmptyPageOrigin(browser = gBrowser.selectedBrowser,
|
|||
}
|
||||
// Not all principals have URIs...
|
||||
if (contentPrincipal.URI) {
|
||||
// A manually entered about:blank URI is slightly magical:
|
||||
if (uri.spec == "about:blank" && contentPrincipal.isNullPrincipal) {
|
||||
return true;
|
||||
}
|
||||
return contentPrincipal.URI.equals(uri);
|
||||
}
|
||||
// ... so for those that don't have them, enforce that the page has the
|
||||
// system principal (this matches e.g. on about:home).
|
||||
// system principal (this matches e.g. on about:newtab).
|
||||
let ssm = Services.scriptSecurityManager;
|
||||
return ssm.isSystemPrincipal(contentPrincipal);
|
||||
}
|
||||
|
|
|
@ -564,12 +564,18 @@ nsContextMenu.prototype = {
|
|||
LoginHelper.openPasswordManager(window, gContextMenuContentData.documentURIObject.host);
|
||||
},
|
||||
|
||||
inspectNode: function CM_inspectNode() {
|
||||
inspectNode: function() {
|
||||
let {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
let gBrowser = this.browser.ownerDocument.defaultView.gBrowser;
|
||||
let tt = devtools.TargetFactory.forTab(gBrowser.selectedTab);
|
||||
return gDevTools.showToolbox(tt, "inspector").then(function(toolbox) {
|
||||
let target = devtools.TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
return gDevTools.showToolbox(target, "inspector").then(toolbox => {
|
||||
let inspector = toolbox.getCurrentPanel();
|
||||
|
||||
// new-node-front tells us when the node has been selected, whether the
|
||||
// browser is remote or not.
|
||||
let onNewNode = inspector.selection.once("new-node-front");
|
||||
|
||||
if (this.isRemote) {
|
||||
this.browser.messageManager.sendAsyncMessage("debug:inspect", {}, {node: this.target});
|
||||
inspector.walker.findInspectingNode().then(nodeFront => {
|
||||
|
@ -578,7 +584,13 @@ nsContextMenu.prototype = {
|
|||
} else {
|
||||
inspector.selection.setNode(this.target, "browser-context-menu");
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
return onNewNode.then(() => {
|
||||
// Now that the node has been selected, wait until the inspector is
|
||||
// fully updated.
|
||||
return inspector.once("inspector-updated");
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// Set various context menu attributes based on the state of the world.
|
||||
|
|
|
@ -111,7 +111,8 @@ Sanitizer.prototype = {
|
|||
|
||||
// Store the list of items to clear, in case we are killed before we
|
||||
// get a chance to complete.
|
||||
Preferences.set(Sanitizer.PREF_SANITIZE_IN_PROGRESS, JSON.stringify(itemsToClear));
|
||||
Preferences.set(Sanitizer.PREF_SANITIZE_IN_PROGRESS,
|
||||
JSON.stringify(itemsToClear));
|
||||
|
||||
// Store the list of items to clear, for debugging/forensics purposes
|
||||
for (let k of itemsToClear) {
|
||||
|
@ -677,10 +678,18 @@ Sanitizer.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
// "Static" members
|
||||
// The preferences branch for the sanitizer.
|
||||
Sanitizer.PREF_DOMAIN = "privacy.sanitize.";
|
||||
// Whether we should sanitize on shutdown.
|
||||
Sanitizer.PREF_SANITIZE_ON_SHUTDOWN = "privacy.sanitize.sanitizeOnShutdown";
|
||||
// During a sanitization this is set to a json containing the array of items
|
||||
// being sanitized, then cleared once the sanitization is complete.
|
||||
// This allows to retry a sanitization on startup in case it was interrupted
|
||||
// by a crash.
|
||||
Sanitizer.PREF_SANITIZE_IN_PROGRESS = "privacy.sanitize.sanitizeInProgress";
|
||||
// Whether the previous shutdown sanitization completed successfully.
|
||||
// Note that PREF_SANITIZE_IN_PROGRESS would be enough to detect an interrupted
|
||||
// sanitization, but this is still supported for backwards compatibility.
|
||||
Sanitizer.PREF_SANITIZE_DID_SHUTDOWN = "privacy.sanitize.didShutdownSanitize";
|
||||
|
||||
// Time span constants corresponding to values of the privacy.sanitize.timeSpan
|
||||
|
@ -766,6 +775,15 @@ Sanitizer.sanitize = function(aParentWindow)
|
|||
};
|
||||
|
||||
Sanitizer.onStartup = Task.async(function*() {
|
||||
// Check if we were interrupted during the last shutdown sanitization.
|
||||
let shutownSanitizationWasInterrupted =
|
||||
Preferences.get(Sanitizer.PREF_SANITIZE_ON_SHUTDOWN, false) &&
|
||||
!Preferences.has(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN);
|
||||
// Regardless, reset the pref, since we want to check it at the next startup
|
||||
// even if the browser exits abruptly.
|
||||
Preferences.reset(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN);
|
||||
Services.prefs.savePrefFile(null);
|
||||
|
||||
// Make sure that we are triggered during shutdown, at the right time,
|
||||
// and only once.
|
||||
let placesClient = Cc["@mozilla.org/browser/nav-history-service;1"]
|
||||
|
@ -786,18 +804,19 @@ Sanitizer.onStartup = Task.async(function*() {
|
|||
}
|
||||
placesClient.addBlocker("sanitize.js: Sanitize on shutdown", doSanitize);
|
||||
|
||||
// Handle incomplete sanitizations
|
||||
if (Preferences.has(Sanitizer.PREF_SANITIZE_IN_PROGRESS)) {
|
||||
// Firefox crashed during sanitization.
|
||||
// Check if Firefox crashed before completing a sanitization.
|
||||
let lastInterruptedSanitization = Preferences.get(Sanitizer.PREF_SANITIZE_IN_PROGRESS, "");
|
||||
if (lastInterruptedSanitization) {
|
||||
let s = new Sanitizer();
|
||||
let json = Preferences.get(Sanitizer.PREF_SANITIZE_IN_PROGRESS);
|
||||
let itemsToClear = JSON.parse(json);
|
||||
// If the json is invalid this will just throw and reject the Task.
|
||||
let itemsToClear = JSON.parse(lastInterruptedSanitization);
|
||||
yield s.sanitize(itemsToClear);
|
||||
}
|
||||
if (Preferences.has(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN)) {
|
||||
// Firefox crashed before having a chance to sanitize during shutdown.
|
||||
// (note that if Firefox crashed during shutdown sanitization, we
|
||||
// will hit both `if` so we will run a second double-sanitization).
|
||||
} else if (shutownSanitizationWasInterrupted) {
|
||||
// Ideally lastInterruptedSanitization should always be set when a
|
||||
// sanitization is interrupted, but some add-ons or Firefox previous
|
||||
// versions may not set the pref.
|
||||
// In such a case, we can still detect an interrupted shutdown sanitization,
|
||||
// and just redo it.
|
||||
yield Sanitizer.onShutdown();
|
||||
}
|
||||
});
|
||||
|
@ -810,5 +829,8 @@ Sanitizer.onShutdown = Task.async(function*() {
|
|||
let s = new Sanitizer();
|
||||
s.prefDomain = "privacy.clearOnShutdown.";
|
||||
yield s.sanitize();
|
||||
// We didn't crash during shutdown sanitization, so annotate it to avoid
|
||||
// sanitizing again on startup.
|
||||
Preferences.set(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN, true);
|
||||
Services.prefs.savePrefFile(null);
|
||||
});
|
||||
|
|
|
@ -6243,9 +6243,11 @@
|
|||
if (browser.audioMuted) {
|
||||
browser.unmute();
|
||||
this.removeAttribute("muted");
|
||||
BrowserUITelemetry.countTabMutingEvent("unmute", aMuteReason);
|
||||
} else {
|
||||
browser.mute();
|
||||
this.setAttribute("muted", "true");
|
||||
BrowserUITelemetry.countTabMutingEvent("mute", aMuteReason);
|
||||
}
|
||||
this.muteReason = aMuteReason || null;
|
||||
tabContainer.tabbrowser._tabAttrModified(this, ["muted"]);
|
||||
|
|
|
@ -413,7 +413,7 @@ WebContentConverterRegistrar.prototype = {
|
|||
let notificationValue = "Protocol Registration: " + aProtocol;
|
||||
let addButton = {
|
||||
label: this._getString("addProtocolHandlerAddButton"),
|
||||
accessKey: this._getString("addHandlerAddButtonAccesskey"),
|
||||
accessKey: this._getString("addProtocolHandlerAddButtonAccesskey"),
|
||||
protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
|
||||
|
||||
callback(aNotification, aButtonInfo) {
|
||||
|
|
|
@ -103,6 +103,9 @@ let gOpenDBs = new Map();
|
|||
|
||||
// Track open libraries
|
||||
let gLibs = {};
|
||||
this.ESE = ESE; // Required for tests.
|
||||
this.KERNEL = KERNEL; // ditto
|
||||
this.gLibs = gLibs; // ditto
|
||||
|
||||
function convertESEError(errorCode) {
|
||||
switch (errorCode) {
|
||||
|
@ -285,7 +288,10 @@ ESEDB.prototype = {
|
|||
ESE.SetSystemParameterW(this._instanceId.address(), 0,
|
||||
2 /* JET_paramLogFilePath*/, 0, this.logPath);
|
||||
|
||||
// Shouldn't try to call JetTerm if the following call fails.
|
||||
this._instanceCreated = false;
|
||||
ESE.Init(this._instanceId.address());
|
||||
this._instanceCreated = true;
|
||||
this._sessionId = new ESE.JET_SESID();
|
||||
ESE.BeginSessionW(this._instanceId, this._sessionId.address(), null,
|
||||
null);
|
||||
|
|
|
@ -52,15 +52,17 @@ XPCOMUtils.defineLazyGetter(this, "gEdgeDatabase", function() {
|
|||
* @param {function} filterFn a function that is called for each row.
|
||||
* Only rows for which it returns a truthy
|
||||
* value are included in the result.
|
||||
* @param {nsIFile} dbFile the database file to use. Defaults to
|
||||
* the main Edge database.
|
||||
* @returns {Array} An array of row objects.
|
||||
*/
|
||||
function readTableFromEdgeDB(tableName, columns, filterFn) {
|
||||
function readTableFromEdgeDB(tableName, columns, filterFn, dbFile=gEdgeDatabase) {
|
||||
let database;
|
||||
let rows = [];
|
||||
try {
|
||||
let logFile = gEdgeDatabase.parent;
|
||||
let logFile = dbFile.parent;
|
||||
logFile.append("LogFiles");
|
||||
database = ESEDBReader.openDB(gEdgeDatabase.parent, gEdgeDatabase, logFile);
|
||||
database = ESEDBReader.openDB(dbFile.parent, dbFile, logFile);
|
||||
|
||||
if (typeof columns == "function") {
|
||||
columns = columns(database);
|
||||
|
@ -74,7 +76,7 @@ function readTableFromEdgeDB(tableName, columns, filterFn) {
|
|||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError("Failed to extract items from table " + tableName + " in Edge database at " +
|
||||
gEdgeDatabase.path + " due to the following error: " + ex);
|
||||
dbFile.path + " due to the following error: " + ex);
|
||||
// Deliberately make this fail so we expose failure in the UI:
|
||||
throw ex;
|
||||
} finally {
|
||||
|
@ -221,33 +223,36 @@ EdgeReadingListMigrator.prototype = {
|
|||
}),
|
||||
};
|
||||
|
||||
function EdgeBookmarksMigrator() {
|
||||
function EdgeBookmarksMigrator(dbOverride) {
|
||||
this.dbOverride = dbOverride;
|
||||
}
|
||||
|
||||
EdgeBookmarksMigrator.prototype = {
|
||||
type: MigrationUtils.resourceTypes.BOOKMARKS,
|
||||
|
||||
get db() { return this.dbOverride || gEdgeDatabase; },
|
||||
|
||||
get TABLE_NAME() { return "Favorites" },
|
||||
|
||||
get exists() {
|
||||
if ("_exists" in this) {
|
||||
return this._exists;
|
||||
}
|
||||
return this._exists = (!!gEdgeDatabase && this._checkTableExists());
|
||||
return this._exists = (!!this.db && this._checkTableExists());
|
||||
},
|
||||
|
||||
_checkTableExists() {
|
||||
let database;
|
||||
let rv;
|
||||
try {
|
||||
let logFile = gEdgeDatabase.parent;
|
||||
let logFile = this.db.parent;
|
||||
logFile.append("LogFiles");
|
||||
database = ESEDBReader.openDB(gEdgeDatabase.parent, gEdgeDatabase, logFile);
|
||||
database = ESEDBReader.openDB(this.db.parent, this.db, logFile);
|
||||
|
||||
rv = database.tableExists(this.TABLE_NAME);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Failed to check for table " + tableName + " in Edge database at " +
|
||||
gEdgeDatabase.path + " due to the following error: " + ex);
|
||||
Cu.reportError("Failed to check for table " + this.TABLE_NAME + " in Edge database at " +
|
||||
this.db.path + " due to the following error: " + ex);
|
||||
return false;
|
||||
} finally {
|
||||
if (database) {
|
||||
|
@ -348,7 +353,7 @@ EdgeBookmarksMigrator.prototype = {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
let bookmarks = readTableFromEdgeDB(this.TABLE_NAME, columns, filterFn);
|
||||
let bookmarks = readTableFromEdgeDB(this.TABLE_NAME, columns, filterFn, this.db);
|
||||
return {bookmarks, folderMap};
|
||||
},
|
||||
|
||||
|
@ -388,10 +393,15 @@ EdgeBookmarksMigrator.prototype = {
|
|||
}
|
||||
|
||||
function EdgeProfileMigrator() {
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
EdgeProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||
|
||||
EdgeProfileMigrator.prototype.getESEMigratorForTesting = function(dbOverride) {
|
||||
return new EdgeBookmarksMigrator(dbOverride);
|
||||
};
|
||||
|
||||
EdgeProfileMigrator.prototype.getResources = function() {
|
||||
let bookmarksMigrator = new EdgeBookmarksMigrator();
|
||||
if (!bookmarksMigrator.exists) {
|
||||
|
|
|
@ -0,0 +1,465 @@
|
|||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
let eseBackStage = Cu.import("resource:///modules/ESEDBReader.jsm");
|
||||
let ESE = eseBackStage.ESE;
|
||||
let KERNEL = eseBackStage.KERNEL;
|
||||
let gLibs = eseBackStage.gLibs;
|
||||
let COLUMN_TYPES = eseBackStage.COLUMN_TYPES;
|
||||
let declareESEFunction = eseBackStage.declareESEFunction;
|
||||
let loadLibraries = eseBackStage.loadLibraries;
|
||||
|
||||
let gESEInstanceCounter = 1;
|
||||
|
||||
ESE.JET_COLUMNCREATE_W = new ctypes.StructType("JET_COLUMNCREATE_W", [
|
||||
{"cbStruct": ctypes.unsigned_long},
|
||||
{"szColumnName": ESE.JET_PCWSTR},
|
||||
{"coltyp": ESE.JET_COLTYP },
|
||||
{"cbMax": ctypes.unsigned_long },
|
||||
{"grbit": ESE.JET_GRBIT },
|
||||
{"pvDefault": ctypes.voidptr_t},
|
||||
{"cbDefault": ctypes.unsigned_long },
|
||||
{"cp": ctypes.unsigned_long },
|
||||
{"columnid": ESE.JET_COLUMNID},
|
||||
{"err": ESE.JET_ERR},
|
||||
]);
|
||||
|
||||
function createColumnCreationWrapper({name, type, cbMax}) {
|
||||
// We use a wrapper object because we need to be sure the JS engine won't GC
|
||||
// data that we're "only" pointing to.
|
||||
let wrapper = {};
|
||||
wrapper.column = new ESE.JET_COLUMNCREATE_W();
|
||||
wrapper.column.cbStruct = ESE.JET_COLUMNCREATE_W.size;
|
||||
let wchar_tArray = ctypes.ArrayType(ctypes.char16_t);
|
||||
wrapper.name = new wchar_tArray(name.length + 1);
|
||||
wrapper.name.value = String(name);
|
||||
wrapper.column.szColumnName = wrapper.name;
|
||||
wrapper.column.coltyp = type;
|
||||
let fallback = 0;
|
||||
switch (type) {
|
||||
case COLUMN_TYPES.JET_coltypText:
|
||||
fallback = 255;
|
||||
case COLUMN_TYPES.JET_coltypLongText:
|
||||
wrapper.column.cbMax = cbMax || fallback || 64 * 1024;
|
||||
break;
|
||||
case COLUMN_TYPES.JET_coltypGUID:
|
||||
wrapper.column.cbMax = 16;
|
||||
break;
|
||||
case COLUMN_TYPES.JET_coltypBit:
|
||||
wrapper.column.cbMax = 1;
|
||||
break;
|
||||
case COLUMN_TYPES.JET_coltypLongLong:
|
||||
wrapper.column.cbMax = 8;
|
||||
break;
|
||||
default:
|
||||
throw "Unknown column type!";
|
||||
}
|
||||
|
||||
wrapper.column.columnid = new ESE.JET_COLUMNID();
|
||||
wrapper.column.grbit = 0;
|
||||
wrapper.column.pvDefault = null;
|
||||
wrapper.column.cbDefault = 0;
|
||||
wrapper.column.cp = 0;
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// "forward declarations" of indexcreate and setinfo structs, which we don't use.
|
||||
ESE.JET_INDEXCREATE = new ctypes.StructType("JET_INDEXCREATE");
|
||||
ESE.JET_SETINFO = new ctypes.StructType("JET_SETINFO");
|
||||
|
||||
ESE.JET_TABLECREATE_W = new ctypes.StructType("JET_TABLECREATE_W", [
|
||||
{"cbStruct": ctypes.unsigned_long},
|
||||
{"szTableName": ESE.JET_PCWSTR},
|
||||
{"szTemplateTableName": ESE.JET_PCWSTR},
|
||||
{"ulPages": ctypes.unsigned_long},
|
||||
{"ulDensity": ctypes.unsigned_long},
|
||||
{"rgcolumncreate": ESE.JET_COLUMNCREATE_W.ptr},
|
||||
{"cColumns": ctypes.unsigned_long},
|
||||
{"rgindexcreate": ESE.JET_INDEXCREATE.ptr},
|
||||
{"cIndexes": ctypes.unsigned_long},
|
||||
{"grbit": ESE.JET_GRBIT},
|
||||
{"tableid": ESE.JET_TABLEID},
|
||||
{"cCreated": ctypes.unsigned_long},
|
||||
]);
|
||||
|
||||
function createTableCreationWrapper(tableName, columns) {
|
||||
let wrapper = {};
|
||||
let wchar_tArray = ctypes.ArrayType(ctypes.char16_t);
|
||||
wrapper.name = new wchar_tArray(tableName.length + 1);
|
||||
wrapper.name.value = String(tableName);
|
||||
wrapper.table = new ESE.JET_TABLECREATE_W();
|
||||
wrapper.table.cbStruct = ESE.JET_TABLECREATE_W.size;
|
||||
wrapper.table.szTableName = wrapper.name;
|
||||
wrapper.table.szTemplateTableName = null;
|
||||
wrapper.table.ulPages = 1;
|
||||
wrapper.table.ulDensity = 0;
|
||||
let columnArrayType = ESE.JET_COLUMNCREATE_W.array(columns.length);
|
||||
wrapper.columnAry = new columnArrayType();
|
||||
wrapper.table.rgcolumncreate = wrapper.columnAry.addressOfElement(0);
|
||||
wrapper.table.cColumns = columns.length;
|
||||
wrapper.columns = [];
|
||||
for (let i = 0; i < columns.length; i++) {
|
||||
let column = columns[i];
|
||||
let columnWrapper = createColumnCreationWrapper(column);
|
||||
wrapper.columnAry.addressOfElement(i).contents = columnWrapper.column;
|
||||
wrapper.columns.push(columnWrapper);
|
||||
}
|
||||
wrapper.table.rgindexcreate = null;
|
||||
wrapper.table.cIndexes = 0;
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function convertValueForWriting(value, valueType) {
|
||||
let buffer;
|
||||
let valueOfValueType = ctypes.UInt64.lo(valueType);
|
||||
switch (valueOfValueType) {
|
||||
case COLUMN_TYPES.JET_coltypLongLong:
|
||||
if (value instanceof Date) {
|
||||
buffer = new KERNEL.FILETIME();
|
||||
let sysTime = new KERNEL.SYSTEMTIME();
|
||||
sysTime.wYear = value.getUTCFullYear();
|
||||
sysTime.wMonth = value.getUTCMonth() + 1;
|
||||
sysTime.wDay = value.getUTCDate();
|
||||
sysTime.wHour = value.getUTCHours();
|
||||
sysTime.wMinute = value.getUTCMinutes();
|
||||
sysTime.wSecond = value.getUTCSeconds();
|
||||
sysTime.wMilliseconds = value.getUTCMilliseconds();
|
||||
let rv = KERNEL.SystemTimeToFileTime(sysTime.address(), buffer.address());
|
||||
if (!rv) {
|
||||
throw new Error("Failed to get FileTime.");
|
||||
}
|
||||
return [buffer, KERNEL.FILETIME.size];
|
||||
}
|
||||
throw new Error("Unrecognized value for longlong column");
|
||||
case COLUMN_TYPES.JET_coltypLongText:
|
||||
let wchar_tArray = ctypes.ArrayType(ctypes.char16_t);
|
||||
buffer = new wchar_tArray(value.length + 1);
|
||||
buffer.value = String(value);
|
||||
return [buffer, buffer.length * 2];
|
||||
case COLUMN_TYPES.JET_coltypBit:
|
||||
buffer = new ctypes.uint8_t();
|
||||
// Bizarre boolean values, but whatever:
|
||||
buffer.value = value ? 255 : 0;
|
||||
return [buffer, 1];
|
||||
case COLUMN_TYPES.JET_coltypGUID:
|
||||
let byteArray = ctypes.ArrayType(ctypes.uint8_t);
|
||||
buffer = new byteArray(16);
|
||||
let j = 0;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
if (!(/[0-9a-f]/i).test(value[i])) {
|
||||
continue;
|
||||
}
|
||||
let byteAsHex = value.substr(i, 2);
|
||||
buffer[j++] = parseInt(byteAsHex, 16);
|
||||
i++;
|
||||
}
|
||||
return [buffer, 16];
|
||||
}
|
||||
|
||||
throw new Error("Unknown type " + valueType);
|
||||
}
|
||||
|
||||
let initializedESE = false;
|
||||
|
||||
let eseDBWritingHelpers = {
|
||||
setupDB(dbFile, tableName, columns, rows) {
|
||||
if (!initializedESE) {
|
||||
initializedESE = true;
|
||||
loadLibraries();
|
||||
|
||||
KERNEL.SystemTimeToFileTime = gLibs.kernel.declare("SystemTimeToFileTime",
|
||||
ctypes.default_abi, ctypes.bool, KERNEL.SYSTEMTIME.ptr, KERNEL.FILETIME.ptr);
|
||||
|
||||
declareESEFunction("CreateDatabaseW", ESE.JET_SESID, ESE.JET_PCWSTR,
|
||||
ESE.JET_PCWSTR, ESE.JET_DBID.ptr, ESE.JET_GRBIT);
|
||||
declareESEFunction("CreateTableColumnIndexW", ESE.JET_SESID, ESE.JET_DBID,
|
||||
ESE.JET_TABLECREATE_W.ptr);
|
||||
declareESEFunction("BeginTransaction", ESE.JET_SESID);
|
||||
declareESEFunction("CommitTransaction", ESE.JET_SESID, ESE.JET_GRBIT);
|
||||
declareESEFunction("PrepareUpdate", ESE.JET_SESID, ESE.JET_TABLEID,
|
||||
ctypes.unsigned_long);
|
||||
declareESEFunction("Update", ESE.JET_SESID, ESE.JET_TABLEID,
|
||||
ctypes.voidptr_t, ctypes.unsigned_long,
|
||||
ctypes.unsigned_long.ptr);
|
||||
declareESEFunction("SetColumn", ESE.JET_SESID, ESE.JET_TABLEID,
|
||||
ESE.JET_COLUMNID, ctypes.voidptr_t,
|
||||
ctypes.unsigned_long, ESE.JET_GRBIT, ESE.JET_SETINFO.ptr);
|
||||
ESE.SetSystemParameterW(null, 0, 64 /* JET_paramDatabasePageSize*/,
|
||||
8192, null);
|
||||
}
|
||||
|
||||
let rootPath = dbFile.parent.path + "\\";
|
||||
let logPath = rootPath + "LogFiles\\";
|
||||
|
||||
try {
|
||||
this._instanceId = new ESE.JET_INSTANCE();
|
||||
ESE.CreateInstanceW(this._instanceId.address(),
|
||||
"firefox-dbwriter-" + (gESEInstanceCounter++));
|
||||
this._instanceCreated = true;
|
||||
|
||||
ESE.SetSystemParameterW(this._instanceId.address(), 0,
|
||||
0 /* JET_paramSystemPath*/, 0, rootPath);
|
||||
ESE.SetSystemParameterW(this._instanceId.address(), 0,
|
||||
1 /* JET_paramTempPath */, 0, rootPath);
|
||||
ESE.SetSystemParameterW(this._instanceId.address(), 0,
|
||||
2 /* JET_paramLogFilePath*/, 0, logPath);
|
||||
// Shouldn't try to call JetTerm if the following call fails.
|
||||
this._instanceCreated = false;
|
||||
ESE.Init(this._instanceId.address());
|
||||
this._instanceCreated = true;
|
||||
this._sessionId = new ESE.JET_SESID();
|
||||
ESE.BeginSessionW(this._instanceId, this._sessionId.address(), null,
|
||||
null);
|
||||
this._sessionCreated = true;
|
||||
|
||||
this._dbId = new ESE.JET_DBID();
|
||||
this._dbPath = rootPath + "spartan.edb";
|
||||
ESE.CreateDatabaseW(this._sessionId, this._dbPath, null,
|
||||
this._dbId.address(), 0);
|
||||
this._opened = this._attached = true;
|
||||
|
||||
let tableCreationWrapper = createTableCreationWrapper(tableName, columns);
|
||||
ESE.CreateTableColumnIndexW(this._sessionId, this._dbId,
|
||||
tableCreationWrapper.table.address());
|
||||
this._tableId = tableCreationWrapper.table.tableid;
|
||||
|
||||
let columnIdMap = new Map();
|
||||
if (rows.length) {
|
||||
// Iterate over the struct we passed into ESENT because they have the
|
||||
// created column ids.
|
||||
let columnCount = ctypes.UInt64.lo(tableCreationWrapper.table.cColumns);
|
||||
let columnsPassed = tableCreationWrapper.table.rgcolumncreate;
|
||||
for (let i = 0; i < columnCount; i++) {
|
||||
let column = columnsPassed.contents;
|
||||
columnIdMap.set(column.szColumnName.readString(), column);
|
||||
columnsPassed = columnsPassed.increment();
|
||||
}
|
||||
let rv = ESE.ManualMove(this._sessionId, this._tableId,
|
||||
-2147483648 /* JET_MoveFirst */, 0);
|
||||
ESE.BeginTransaction(this._sessionId);
|
||||
for (let row of rows) {
|
||||
ESE.PrepareUpdate(this._sessionId, this._tableId, 0 /* JET_prepInsert */);
|
||||
for (let columnName in row) {
|
||||
let col = columnIdMap.get(columnName);
|
||||
let colId = col.columnid;
|
||||
let [val, valSize] = convertValueForWriting(row[columnName], col.coltyp);
|
||||
/* JET_bitSetOverwriteLV */
|
||||
ESE.SetColumn(this._sessionId, this._tableId, colId, val.address(), valSize, 4, null);
|
||||
}
|
||||
let actualBookmarkSize = new ctypes.unsigned_long();
|
||||
ESE.Update(this._sessionId, this._tableId, null, 0, actualBookmarkSize.address());
|
||||
}
|
||||
ESE.CommitTransaction(this._sessionId, 0 /* JET_bitWaitLastLevel0Commit */);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
this._close();
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_close() {
|
||||
if (this._tableId) {
|
||||
ESE.FailSafeCloseTable(this._sessionId, this._tableId);
|
||||
delete this._tableId;
|
||||
}
|
||||
if (this._opened) {
|
||||
ESE.FailSafeCloseDatabase(this._sessionId, this._dbId, 0);
|
||||
this._opened = false;
|
||||
}
|
||||
if (this._attached) {
|
||||
ESE.FailSafeDetachDatabaseW(this._sessionId, this._dbPath);
|
||||
this._attached = false;
|
||||
}
|
||||
if (this._sessionCreated) {
|
||||
ESE.FailSafeEndSession(this._sessionId, 0);
|
||||
this._sessionCreated = false;
|
||||
}
|
||||
if (this._instanceCreated) {
|
||||
ESE.FailSafeTerm(this._instanceId);
|
||||
this._instanceCreated = false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function*() {
|
||||
let tempFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
tempFile.append("fx-xpcshell-edge-db");
|
||||
tempFile.createUnique(tempFile.DIRECTORY_TYPE, 0o600);
|
||||
|
||||
let db = tempFile.clone();
|
||||
db.append("spartan.edb");
|
||||
|
||||
let logs = tempFile.clone();
|
||||
logs.append("LogFiles");
|
||||
logs.create(tempFile.DIRECTORY_TYPE, 0o600);
|
||||
|
||||
let creationDate = new Date(Date.now() - 5000);
|
||||
const kEdgeMenuParent = "62d07e2b-5f0d-4e41-8426-5f5ec9717beb";
|
||||
let itemsInDB = [
|
||||
{
|
||||
URL: "http://www.mozilla.org/",
|
||||
Title: "Mozilla",
|
||||
DateUpdated: new Date(creationDate.valueOf() + 100),
|
||||
ItemId: "1c00c10a-15f6-4618-92dd-22575102a4da",
|
||||
ParentId: kEdgeMenuParent,
|
||||
IsFolder: false,
|
||||
IsDeleted: false,
|
||||
},
|
||||
{
|
||||
Title: "Folder",
|
||||
DateUpdated: new Date(creationDate.valueOf() + 200),
|
||||
ItemId: "564b21f2-05d6-4f7d-8499-304d00ccc3aa",
|
||||
ParentId: kEdgeMenuParent,
|
||||
IsFolder: true,
|
||||
IsDeleted: false,
|
||||
},
|
||||
{
|
||||
Title: "Item in folder",
|
||||
URL: "http://www.iteminfolder.org/",
|
||||
DateUpdated: new Date(creationDate.valueOf() + 300),
|
||||
ItemId: "c295ddaf-04a1-424a-866c-0ebde011e7c8",
|
||||
ParentId: "564b21f2-05d6-4f7d-8499-304d00ccc3aa",
|
||||
IsFolder: false,
|
||||
IsDeleted: false,
|
||||
},
|
||||
{
|
||||
Title: "Deleted folder",
|
||||
DateUpdated: new Date(creationDate.valueOf() + 400),
|
||||
ItemId: "a547573c-4d4d-4406-a736-5b5462d93bca",
|
||||
ParentId: kEdgeMenuParent,
|
||||
IsFolder: true,
|
||||
IsDeleted: true,
|
||||
},
|
||||
{
|
||||
Title: "Deleted item",
|
||||
URL: "http://www.deleteditem.org/",
|
||||
DateUpdated: new Date(creationDate.valueOf() + 500),
|
||||
ItemId: "37a574bb-b44b-4bbc-a414-908615536435",
|
||||
ParentId: kEdgeMenuParent,
|
||||
IsFolder: false,
|
||||
IsDeleted: true,
|
||||
},
|
||||
{
|
||||
Title: "Item in deleted folder (should be in root)",
|
||||
URL: "http://www.itemindeletedfolder.org/",
|
||||
DateUpdated: new Date(creationDate.valueOf() + 600),
|
||||
ItemId: "74dd1cc3-4c5d-471f-bccc-7bc7c72fa621",
|
||||
ParentId: "a547573c-4d4d-4406-a736-5b5462d93bca",
|
||||
IsFolder: false,
|
||||
IsDeleted: false,
|
||||
},
|
||||
{
|
||||
Title: "_Favorites_Bar_",
|
||||
DateUpdated: new Date(creationDate.valueOf() + 700),
|
||||
ItemId: "921dc8a0-6c83-40ef-8df1-9bd1c5c56aaf",
|
||||
ParentId: kEdgeMenuParent,
|
||||
IsFolder: true,
|
||||
IsDeleted: false,
|
||||
},
|
||||
{
|
||||
Title: "Item in favorites bar",
|
||||
URL: "http://www.iteminfavoritesbar.org/",
|
||||
DateUpdated: new Date(creationDate.valueOf() + 800),
|
||||
ItemId: "9f2b1ff8-b651-46cf-8f41-16da8bcb6791",
|
||||
ParentId: "921dc8a0-6c83-40ef-8df1-9bd1c5c56aaf",
|
||||
IsFolder: false,
|
||||
IsDeleted: false,
|
||||
},
|
||||
];
|
||||
eseDBWritingHelpers.setupDB(db, "Favorites", [
|
||||
{type: COLUMN_TYPES.JET_coltypLongText, name: "URL", cbMax: 4096},
|
||||
{type: COLUMN_TYPES.JET_coltypLongText, name: "Title", cbMax: 4096},
|
||||
{type: COLUMN_TYPES.JET_coltypLongLong, name: "DateUpdated"},
|
||||
{type: COLUMN_TYPES.JET_coltypGUID, name: "ItemId"},
|
||||
{type: COLUMN_TYPES.JET_coltypBit, name: "IsDeleted"},
|
||||
{type: COLUMN_TYPES.JET_coltypBit, name: "IsFolder"},
|
||||
{type: COLUMN_TYPES.JET_coltypGUID, name: "ParentId"},
|
||||
], itemsInDB);
|
||||
|
||||
let migrator = Cc["@mozilla.org/profile/migrator;1?app=browser&type=edge"]
|
||||
.createInstance(Ci.nsIBrowserProfileMigrator);
|
||||
let bookmarksMigrator = migrator.wrappedJSObject.getESEMigratorForTesting(db);
|
||||
Assert.ok(bookmarksMigrator.exists, "Should recognize table we just created");
|
||||
|
||||
let seenBookmarks = [];
|
||||
let bookmarkObserver = {
|
||||
onItemAdded(itemId, parentId, index, itemType, url, title, dateAdded, itemGuid, parentGuid) {
|
||||
if (title.startsWith("Deleted")) {
|
||||
ok(false, "Should not see deleted items being bookmarked!");
|
||||
}
|
||||
seenBookmarks.push({itemId, parentId, index, itemType, url, title, dateAdded, itemGuid, parentGuid});
|
||||
},
|
||||
onBeginUpdateBatch() {},
|
||||
onEndUpdateBatch() {},
|
||||
onItemRemoved() {},
|
||||
onItemChanged() {},
|
||||
onItemVisited() {},
|
||||
onItemMoved() {},
|
||||
}
|
||||
PlacesUtils.bookmarks.addObserver(bookmarkObserver, false);
|
||||
|
||||
let migrateResult = yield new Promise(resolve => bookmarksMigrator.migrate(resolve)).catch(ex => {
|
||||
Cu.reportError(ex);
|
||||
Assert.ok(false, "Got an exception trying to migrate data! " + ex);
|
||||
return false;
|
||||
});
|
||||
PlacesUtils.bookmarks.removeObserver(bookmarkObserver);
|
||||
Assert.ok(migrateResult, "Migration should succeed");
|
||||
Assert.equal(seenBookmarks.length, 7, "Should have seen 7 items being bookmarked.");
|
||||
|
||||
let menuParents = seenBookmarks.filter(item => item.parentGuid == PlacesUtils.bookmarks.menuGuid);
|
||||
Assert.equal(menuParents.length, 1, "Should have a single folder added to the menu");
|
||||
let toolbarParents = seenBookmarks.filter(item => item.parentGuid == PlacesUtils.bookmarks.toolbarGuid);
|
||||
Assert.equal(toolbarParents.length, 1, "Should have a single item added to the toolbar");
|
||||
let menuParentGuid = menuParents[0].itemGuid;
|
||||
let toolbarParentGuid = toolbarParents[0].itemGuid;
|
||||
|
||||
let expectedTitlesInMenu = itemsInDB.filter(item => item.ParentId == kEdgeMenuParent).map(item => item.Title);
|
||||
// Hacky, but seems like much the simplest way:
|
||||
expectedTitlesInMenu.push("Item in deleted folder (should be in root)");
|
||||
let expectedTitlesInToolbar = itemsInDB.filter(item => item.ParentId == "921dc8a0-6c83-40ef-8df1-9bd1c5c56aaf").map(item => item.Title);
|
||||
|
||||
let edgeNameStr = MigrationUtils.getLocalizedString("sourceNameEdge");
|
||||
let importParentFolderName = MigrationUtils.getLocalizedString("importedBookmarksFolder", [edgeNameStr]);
|
||||
|
||||
for (let bookmark of seenBookmarks) {
|
||||
let shouldBeInMenu = expectedTitlesInMenu.includes(bookmark.title);
|
||||
let shouldBeInToolbar = expectedTitlesInToolbar.includes(bookmark.title);
|
||||
if (bookmark.title == "Folder" || bookmark.title == importParentFolderName) {
|
||||
Assert.equal(bookmark.itemType, PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
"Bookmark " + bookmark.title + " should be a folder");
|
||||
} else {
|
||||
Assert.notEqual(bookmark.itemType, PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
"Bookmark " + bookmark.title + " should not be a folder");
|
||||
}
|
||||
|
||||
if (shouldBeInMenu) {
|
||||
Assert.equal(bookmark.parentGuid, menuParentGuid, "Item '" + bookmark.title + "' should be in menu");
|
||||
} else if (shouldBeInToolbar) {
|
||||
Assert.equal(bookmark.parentGuid, toolbarParentGuid, "Item '" + bookmark.title + "' should be in toolbar");
|
||||
} else if (bookmark.itemGuid == menuParentGuid || bookmark.itemGuid == toolbarParentGuid) {
|
||||
Assert.ok(true, "Expect toolbar and menu folders to not be in menu or toolbar");
|
||||
} else {
|
||||
// Bit hacky, but we do need to check this.
|
||||
Assert.equal(bookmark.title, "Item in folder", "Subfoldered item shouldn't be in menu or toolbar");
|
||||
let parent = seenBookmarks.find(maybeParent => maybeParent.itemGuid == bookmark.parentGuid);
|
||||
Assert.equal(parent && parent.title, "Folder", "Subfoldered item should be in subfolder labeled 'Folder'");
|
||||
}
|
||||
|
||||
let dbItem = itemsInDB.find(dbItem => bookmark.title == dbItem.Title);
|
||||
if (!dbItem) {
|
||||
Assert.equal(bookmark.title, importParentFolderName, "Only the extra layer of folders isn't in the input we stuck in the DB.");
|
||||
Assert.ok([menuParentGuid, toolbarParentGuid].includes(bookmark.itemGuid), "This item should be one of the containers");
|
||||
} else {
|
||||
Assert.equal(dbItem.URL || null, bookmark.url && bookmark.url.spec, "URL is correct");
|
||||
Assert.equal(dbItem.DateUpdated.valueOf(), (new Date(bookmark.dateAdded / 1000)).valueOf(), "Date added is correct");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -12,6 +12,8 @@ skip-if = os != "mac" # Relies on ULibDir
|
|||
[test_Chrome_passwords.js]
|
||||
skip-if = os != "win"
|
||||
[test_Edge_availability.js]
|
||||
[test_Edge_db_migration.js]
|
||||
skip-if = os != "win" || os_version == "5.1" || os_version == "5.2" # Relies on post-XP bits of ESEDB
|
||||
[test_fx_telemetry.js]
|
||||
[test_IE_bookmarks.js]
|
||||
skip-if = os != "win"
|
||||
|
|
|
@ -271,9 +271,7 @@ var gSyncPane = {
|
|||
gSyncPane.signIn();
|
||||
return false;
|
||||
});
|
||||
setEventListener("verifiedManage", "click",
|
||||
gSyncPane.manageFirefoxAccount);
|
||||
setEventListener("fxaUnlinkButton", "click", function () {
|
||||
setEventListener("fxaUnlinkButton", "command", function () {
|
||||
gSyncPane.unlinkFirefoxAccount(true);
|
||||
});
|
||||
setEventListener("verifyFxaAccount", "command",
|
||||
|
@ -550,13 +548,34 @@ var gSyncPane = {
|
|||
this._openAboutAccounts("reauth");
|
||||
},
|
||||
|
||||
openChangeProfileImage: function() {
|
||||
fxAccounts.promiseAccountsChangeProfileURI(this._getEntryPoint(), "avatar")
|
||||
.then(url => {
|
||||
|
||||
clickOrSpaceOrEnterPressed: function(event) {
|
||||
// Note: charCode is deprecated, but 'char' not yet implemented.
|
||||
// Replace charCode with char when implemented, see Bug 680830
|
||||
if ((event.type == "click" && event.button == 0) || // button 0 = 'main button', typically left click.
|
||||
(event.type == "keypress" &&
|
||||
(event.charCode == KeyEvent.DOM_VK_SPACE || event.keyCode == KeyEvent.DOM_VK_RETURN))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
openChangeProfileImage: function(event) {
|
||||
if (this.clickOrSpaceOrEnterPressed(event)) {
|
||||
fxAccounts.promiseAccountsChangeProfileURI(this._getEntryPoint(), "avatar")
|
||||
.then(url => {
|
||||
this.openContentInBrowser(url, {
|
||||
replaceQueryString: true
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
openManageFirefoxAccount: function(event) {
|
||||
if (this.clickOrSpaceOrEnterPressed(event)) {
|
||||
this.manageFirefoxAccount();
|
||||
}
|
||||
},
|
||||
|
||||
manageFirefoxAccount: function() {
|
||||
|
|
|
@ -199,8 +199,8 @@
|
|||
<vbox flex="1">
|
||||
<label id="signedOutAccountBoxTitle">&signedOut.accountBox.title;</label>
|
||||
<hbox class="fxaAccountBoxButtons" align="center">
|
||||
<button id="noFxaSignUp">&signedOut.accountBox.create;</button>
|
||||
<button id="noFxaSignIn">&signedOut.accountBox.signin;</button>
|
||||
<button id="noFxaSignUp" label="&signedOut.accountBox.create;"></button>
|
||||
<button id="noFxaSignIn" label="&signedOut.accountBox.signin;"></button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -234,16 +234,21 @@
|
|||
<!-- logged in and verified and all is good -->
|
||||
<hbox id="fxaLoginVerified" class="fxaAccountBox">
|
||||
<vbox>
|
||||
<image id="fxaProfileImage"
|
||||
onclick="gSyncPane.openChangeProfileImage();" hidden="true"
|
||||
tooltiptext="&profilePicture.tooltip;" class="actionable"/>
|
||||
<image id="fxaProfileImage" class="actionable"
|
||||
role="button"
|
||||
onclick="gSyncPane.openChangeProfileImage(event);" hidden="true"
|
||||
onkeypress="gSyncPane.openChangeProfileImage(event);"
|
||||
tooltiptext="&profilePicture.tooltip;"/>
|
||||
</vbox>
|
||||
<vbox flex="1">
|
||||
<label id="fxaEmailAddress1"/>
|
||||
<label id="fxaDisplayName" hidden="true"/>
|
||||
<hbox class="fxaAccountBoxButtons" align="center">
|
||||
<button id="fxaUnlinkButton">&disconnect.label;</button>
|
||||
<label id="verifiedManage" class="text-link">&verifiedManage.label;</label>
|
||||
<button id="fxaUnlinkButton" label="&disconnect.label;"/>
|
||||
<label id="verifiedManage" class="text-link"
|
||||
onclick="gSyncPane.openManageFirefoxAccount(event);"
|
||||
onkeypress="gSyncPane.openManageFirefoxAccount(event);"><!--
|
||||
-->&verifiedManage.label;</label>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
|
|
@ -141,6 +141,10 @@ var SessionHistoryInternal = {
|
|||
entry.referrerPolicy = shEntry.referrerPolicy;
|
||||
}
|
||||
|
||||
if (shEntry.originalURI) {
|
||||
entry.originalURI = shEntry.originalURI.spec;
|
||||
}
|
||||
|
||||
if (shEntry.srcdocData)
|
||||
entry.srcdocData = shEntry.srcdocData;
|
||||
|
||||
|
@ -309,6 +313,9 @@ var SessionHistoryInternal = {
|
|||
shEntry.referrerURI = Utils.makeURI(entry.referrer);
|
||||
shEntry.referrerPolicy = entry.referrerPolicy;
|
||||
}
|
||||
if (entry.originalURI) {
|
||||
shEntry.originalURI = Utils.makeURI(entry.originalURI);
|
||||
}
|
||||
if (entry.isSrcdocEntry)
|
||||
shEntry.srcdocData = entry.srcdocData;
|
||||
if (entry.baseURI)
|
||||
|
|
|
@ -11,6 +11,8 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
|||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
|
||||
"resource://gre/modules/WindowsRegistry.jsm");
|
||||
|
||||
/**
|
||||
* Internal functionality to save and restore the docShell.allow* properties.
|
||||
|
@ -54,11 +56,30 @@ let ShellServiceInternal = {
|
|||
return false;
|
||||
}
|
||||
|
||||
return Services.prefs.getBoolPref("browser.shell.checkDefaultBrowser");
|
||||
if (!Services.prefs.getBoolPref("browser.shell.checkDefaultBrowser")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
let optOutValue = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
"Software\\Mozilla\\Firefox",
|
||||
"DefaultBrowserOptOut");
|
||||
WindowsRegistry.removeRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
"Software\\Mozilla\\Firefox",
|
||||
"DefaultBrowserOptOut");
|
||||
if (optOutValue == "True") {
|
||||
Services.prefs.setBoolPref("browser.shell.checkDefaultBrowser", false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
set shouldCheckDefaultBrowser(shouldCheck) {
|
||||
Services.prefs.setBoolPref("browser.shell.checkDefaultBrowser", !!shouldCheck);
|
||||
},
|
||||
|
||||
isDefaultBrowser(startupCheck, forAllTypes) {
|
||||
// If this is the first browser window, maintain internal state that we've
|
||||
// checked this session (so that subsequent window opens don't show the
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<link rel="stylesheet" type="text/css" media="all" href="chrome://browser/skin/syncedtabs/sidebar.css"/>
|
||||
<link rel="stylesheet" type="text/css" media="all" href="chrome://global/skin/"/>
|
||||
<link rel="stylesheet" type="text/css" media="all" href="chrome://global/skin/textbox.css"/>
|
||||
<link rel="stylesheet" type="text/css" media="all" href="chrome://browser/content/browser.css"/>
|
||||
<title>&syncedTabs.sidebar.label;</title>
|
||||
</head>
|
||||
|
||||
|
|
|
@ -147,13 +147,14 @@ function hideInfoPromise(...args) {
|
|||
*/
|
||||
function showInfoPromise(target, title, text, icon, buttonsFunctionName, optionsFunctionName) {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let shownPromise = promisePanelElementShown(window, popup);
|
||||
return ContentTask.spawn(gTestTab.linkedBrowser, [...arguments], args => {
|
||||
let contentWin = Components.utils.waiveXrays(content);
|
||||
let [target, title, text, icon, buttonsFunctionName, optionsFunctionName] = args;
|
||||
let buttons = buttonsFunctionName ? contentWin[buttonsFunctionName]() : null;
|
||||
let options = optionsFunctionName ? contentWin[optionsFunctionName]() : null;
|
||||
contentWin.Mozilla.UITour.showInfo(target, title, text, icon, buttons, options);
|
||||
}).then(() => promisePanelElementShown(window, popup));
|
||||
}).then(() => shownPromise);
|
||||
}
|
||||
|
||||
function showHighlightPromise(...args) {
|
||||
|
@ -193,7 +194,7 @@ function promisePanelElementEvent(win, aPanel, aEvent) {
|
|||
return new Promise((resolve, reject) => {
|
||||
let timeoutId = win.setTimeout(() => {
|
||||
aPanel.removeEventListener(aEvent, onPanelEvent);
|
||||
reject("Event did not happen within 5 seconds.");
|
||||
reject(aEvent + " event did not happen within 5 seconds.");
|
||||
}, 5000);
|
||||
|
||||
function onPanelEvent(e) {
|
||||
|
|
|
@ -605,6 +605,12 @@ Section "-InstallEndCleanup"
|
|||
GetFunctionAddress $0 SetAsDefaultAppUserHKCU
|
||||
UAC::ExecCodeSegment $0
|
||||
${EndIf}
|
||||
${Else}
|
||||
${LogHeader} "Writing default-browser opt-out"
|
||||
WriteRegStr HKCU "Software\Mozilla\Firefox" "DefaultBrowserOptOut" "True"
|
||||
${If} ${Errors}
|
||||
${LogHeader} "Error writing default-browser opt-out"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
${EndUnless}
|
||||
|
||||
|
|
|
@ -49,3 +49,4 @@ feedSubscriptionVideoPodcast2=You can subscribe to this video podcast to receive
|
|||
# "Add %appName (%appDomain) as an application for %protocolType links?"
|
||||
addProtocolHandler=Add %S (%S) as an application for %S links?
|
||||
addProtocolHandlerAddButton=Add Application
|
||||
addProtocolHandlerAddButtonAccesskey=A
|
|
@ -134,6 +134,7 @@ XPCOMUtils.defineLazyGetter(this, "ALL_BUILTIN_ITEMS", function() {
|
|||
"BMB_unsortedBookmarksPopup",
|
||||
"BMB_bookmarksToolbarPopup",
|
||||
"search-go-button",
|
||||
"soundplaying-icon",
|
||||
]
|
||||
return DEFAULT_ITEMS.concat(PALETTE_ITEMS)
|
||||
.concat(SPECIAL_CASES);
|
||||
|
@ -610,6 +611,10 @@ this.BrowserUITelemetry = {
|
|||
this._countEvent(["forget-button", timeId]);
|
||||
},
|
||||
|
||||
countTabMutingEvent: function(action, reason) {
|
||||
this._countEvent(["tab-audio-control", action, reason || "no reason given"]);
|
||||
},
|
||||
|
||||
_logAwesomeBarSearchResult: function (url) {
|
||||
let spec = Services.search.parseSubmissionURL(url);
|
||||
if (spec.engine) {
|
||||
|
|
Двоичные данные
browser/themes/linux/menuPanel.png
До Ширина: | Высота: | Размер: 18 KiB После Ширина: | Высота: | Размер: 25 KiB |
Двоичные данные
browser/themes/linux/menuPanel@2x.png
До Ширина: | Высота: | Размер: 42 KiB После Ширина: | Высота: | Размер: 56 KiB |
|
@ -25,6 +25,10 @@
|
|||
margin-top: 2px !important;
|
||||
}
|
||||
|
||||
#fxaProfileImage {
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
menulist.actionsMenu > .menulist-dropmarker {
|
||||
margin-top: 11px;
|
||||
margin-bottom: 11px;
|
||||
|
|
Двоичные данные
browser/themes/osx/menuPanel-yosemite.png
До Ширина: | Высота: | Размер: 24 KiB После Ширина: | Высота: | Размер: 24 KiB |
Двоичные данные
browser/themes/osx/menuPanel-yosemite@2x.png
До Ширина: | Высота: | Размер: 56 KiB После Ширина: | Высота: | Размер: 57 KiB |
Двоичные данные
browser/themes/osx/menuPanel.png
До Ширина: | Высота: | Размер: 31 KiB После Ширина: | Высота: | Размер: 31 KiB |
Двоичные данные
browser/themes/osx/menuPanel@2x.png
До Ширина: | Высота: | Размер: 72 KiB После Ширина: | Высота: | Размер: 73 KiB |
|
@ -19,6 +19,10 @@ prefpane .groupbox-title {
|
|||
-moz-padding-start: 3px;
|
||||
}
|
||||
|
||||
#fxaProfileImage {
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
textbox + button {
|
||||
-moz-margin-start: -4px;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,10 @@
|
|||
-moz-image-region: rect(0px, 1024px, 32px, 992px);
|
||||
}
|
||||
|
||||
#sync-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 1024px, 64px, 992px);
|
||||
}
|
||||
|
||||
#feed-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #feed-button {
|
||||
-moz-image-region: rect(0px, 416px, 32px, 384px);
|
||||
|
@ -263,6 +267,10 @@
|
|||
-moz-image-region: rect(0px, 2048px, 64px, 1984px);
|
||||
}
|
||||
|
||||
#sync-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(64px, 2048px, 128px, 1984px);
|
||||
}
|
||||
|
||||
#feed-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #feed-button {
|
||||
-moz-image-region: rect(0px, 832px, 64px, 768px);
|
||||
|
|
Двоичные данные
browser/themes/windows/menuPanel-aero.png
До Ширина: | Высота: | Размер: 35 KiB После Ширина: | Высота: | Размер: 35 KiB |
Двоичные данные
browser/themes/windows/menuPanel-aero@2x.png
До Ширина: | Высота: | Размер: 93 KiB После Ширина: | Высота: | Размер: 94 KiB |
Двоичные данные
browser/themes/windows/menuPanel.png
До Ширина: | Высота: | Размер: 18 KiB После Ширина: | Высота: | Размер: 18 KiB |
Двоичные данные
browser/themes/windows/menuPanel@2x.png
До Ширина: | Высота: | Размер: 40 KiB После Ширина: | Высота: | Размер: 43 KiB |
|
@ -51,6 +51,10 @@ filefield + button {
|
|||
padding-bottom: 0; /* override padding from normal preferences.css */
|
||||
}
|
||||
|
||||
#fxaProfileImage {
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog
|
||||
*/
|
||||
|
|
13
configure.in
|
@ -8558,10 +8558,12 @@ AC_SUBST(MOZ_CHILD_PROCESS_BUNDLE)
|
|||
# "Profile" field, which controls profile location.
|
||||
# - MOZ_APP_ID: When set, used for application.ini's "ID" field, and
|
||||
# crash reporter server url.
|
||||
# - MOZ_APP_ANDROID_VERSION_CODE: On android, "android:versionCode" for
|
||||
# - MOZ_APP_ANDROID_VERSION_CODE: On Android, "android:versionCode" for
|
||||
# the main application is set to the value of this variable. If not
|
||||
# set, it falls back to a Mozilla-specific value derived from the
|
||||
# build ID.
|
||||
# - MOZ_ANDROID_SHARED_ID: On Android, "android:sharedUserId" for all Android
|
||||
# - packages produced.
|
||||
# - MOZ_PROFILE_MIGRATOR: When set, enables profile migrator.
|
||||
|
||||
if test -z "$MOZ_APP_NAME"; then
|
||||
|
@ -8580,6 +8582,14 @@ if test -z "$ANDROID_PACKAGE_NAME" ; then
|
|||
ANDROID_PACKAGE_NAME="org.mozilla.$MOZ_APP_NAME"
|
||||
fi
|
||||
|
||||
# Mozilla released Firefox for Android {Release,Beta} and {Aurora,Nightly} to
|
||||
# the public with specific common shared IDs and we need to keep them
|
||||
# consistent forever. The specific common values are set by per-channel
|
||||
# branding; all other channels use a generic sharedID, set below.
|
||||
if test -z "$MOZ_ANDROID_SHARED_ID" ; then
|
||||
MOZ_ANDROID_SHARED_ID="${ANDROID_PACKAGE_NAME}.sharedID"
|
||||
fi
|
||||
|
||||
# For extensions and langpacks, we require a max version that is compatible
|
||||
# across security releases. MOZ_APP_MAXVERSION is our method for doing that.
|
||||
# 24.0a1 and 24.0a2 aren't affected
|
||||
|
@ -8610,6 +8620,7 @@ AC_SUBST(MOZ_APP_VENDOR)
|
|||
AC_SUBST(MOZ_APP_PROFILE)
|
||||
AC_SUBST(MOZ_APP_ID)
|
||||
AC_SUBST(MOZ_APP_ANDROID_VERSION_CODE)
|
||||
AC_SUBST(MOZ_ANDROID_SHARED_ID)
|
||||
AC_SUBST(MAR_CHANNEL_ID)
|
||||
AC_SUBST(ACCEPTED_MAR_CHANNEL_IDS)
|
||||
AC_SUBST(MOZ_PROFILE_MIGRATOR)
|
||||
|
|
|
@ -16,11 +16,6 @@ button {
|
|||
padding-right: 20px;
|
||||
}
|
||||
|
||||
#body {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
/* Category tabs */
|
||||
|
||||
.category {
|
||||
|
@ -33,6 +28,13 @@ button {
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
.app {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
@ -41,10 +43,6 @@ button {
|
|||
max-width: 800px;
|
||||
}
|
||||
|
||||
.tab:not(.active) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Prefs */
|
||||
|
||||
label {
|
||||
|
@ -82,11 +80,11 @@ label {
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.addon-controls {
|
||||
.addons-controls {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.addon-options {
|
||||
.addons-options {
|
||||
flex: 1;
|
||||
}
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* eslint-env browser */
|
||||
/* global AddonsComponent, DebuggerClient, DebuggerServer, React,
|
||||
WorkersComponent */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci } = Components;
|
||||
const { loader } = Components.utils.import(
|
||||
"resource://devtools/shared/Loader.jsm", {});
|
||||
|
||||
loader.lazyRequireGetter(this, "AddonsComponent",
|
||||
"devtools/client/aboutdebugging/components/addons", true);
|
||||
loader.lazyRequireGetter(this, "DebuggerClient",
|
||||
"devtools/shared/client/main", true);
|
||||
loader.lazyRequireGetter(this, "DebuggerServer",
|
||||
"devtools/server/main", true);
|
||||
loader.lazyRequireGetter(this, "Telemetry",
|
||||
"devtools/client/shared/telemetry");
|
||||
loader.lazyRequireGetter(this, "WorkersComponent",
|
||||
"devtools/client/aboutdebugging/components/workers", true);
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
|
||||
loader.lazyImporter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/aboutdebugging.properties");
|
||||
|
||||
var AboutDebugging = {
|
||||
_prefListeners: [],
|
||||
|
||||
// Pointer to the current React component.
|
||||
_component: null,
|
||||
|
||||
_categories: null,
|
||||
get categories() {
|
||||
// If needed, initialize the list of available categories.
|
||||
if (!this._categories) {
|
||||
let elements = document.querySelectorAll(".category");
|
||||
this._categories = Array.map(elements, element => {
|
||||
let value = element.getAttribute("value");
|
||||
element.addEventListener("click", this.showTab.bind(this, value));
|
||||
return value;
|
||||
});
|
||||
}
|
||||
return this._categories;
|
||||
},
|
||||
|
||||
showTab(category) {
|
||||
// If no category was specified, try the URL hash.
|
||||
if (!category) {
|
||||
category = location.hash.substr(1);
|
||||
}
|
||||
// If no corresponding category can be found, use the first available.
|
||||
let categories = this.categories;
|
||||
if (categories.indexOf(category) < 0) {
|
||||
category = categories[0];
|
||||
}
|
||||
// Show the corresponding tab and hide the others.
|
||||
document.querySelector(".tab.active").classList.remove("active");
|
||||
document.querySelector("#tab-" + category).classList.add("active");
|
||||
document.querySelector(".category[selected]").removeAttribute("selected");
|
||||
document.querySelector(".category[value=" + category + "]")
|
||||
.setAttribute("selected", "true");
|
||||
location.hash = "#" + category;
|
||||
|
||||
if (category == "addons") {
|
||||
this._component = React.render(React.createElement(AddonsComponent,
|
||||
{client: this.client}), document.querySelector("#addons"));
|
||||
} else if (category == "workers") {
|
||||
this._component = React.render(React.createElement(WorkersComponent,
|
||||
{client: this.client}), document.querySelector("#workers"));
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
let telemetry = this._telemetry = new Telemetry();
|
||||
telemetry.toolOpened("aboutdebugging");
|
||||
|
||||
// Link checkboxes to prefs.
|
||||
let elements = document.querySelectorAll("input[type=checkbox][data-pref]");
|
||||
Array.map(elements, element => {
|
||||
let pref = element.dataset.pref;
|
||||
|
||||
let updatePref = () => {
|
||||
Services.prefs.setBoolPref(pref, element.checked);
|
||||
};
|
||||
element.addEventListener("change", updatePref, false);
|
||||
|
||||
let onPreferenceChanged = () => {
|
||||
element.checked = Services.prefs.getBoolPref(pref);
|
||||
this.update();
|
||||
};
|
||||
|
||||
Services.prefs.addObserver(pref, onPreferenceChanged, false);
|
||||
this._prefListeners.push([pref, onPreferenceChanged]);
|
||||
|
||||
// Initialize the current checkbox element.
|
||||
element.checked = Services.prefs.getBoolPref(pref);
|
||||
});
|
||||
|
||||
// Link buttons to their associated actions.
|
||||
let loadAddonButton = document.getElementById("load-addon-from-file");
|
||||
loadAddonButton.addEventListener("click", this.loadAddonFromFile);
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
DebuggerServer.allowChromeProcess = true;
|
||||
this.client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
|
||||
this.client.connect().then(() => {
|
||||
// Show the first available tab.
|
||||
this.showTab();
|
||||
window.addEventListener("hashchange", () => this.showTab());
|
||||
});
|
||||
},
|
||||
|
||||
update() {
|
||||
if (this._component) {
|
||||
this._component.setState({});
|
||||
}
|
||||
},
|
||||
|
||||
loadAddonFromFile() {
|
||||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
fp.init(window,
|
||||
Strings.GetStringFromName("selectAddonFromFile"),
|
||||
Ci.nsIFilePicker.modeOpen);
|
||||
let res = fp.show();
|
||||
if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
|
||||
return;
|
||||
}
|
||||
let file = fp.file;
|
||||
// AddonManager.installTemporaryAddon accepts either
|
||||
// addon directory or final xpi file.
|
||||
if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
|
||||
file = file.parent;
|
||||
}
|
||||
try {
|
||||
AddonManager.installTemporaryAddon(file);
|
||||
} catch (e) {
|
||||
alert("Error while installing the addon:\n" + e.message + "\n");
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
|
||||
destroy() {
|
||||
let telemetry = this._telemetry;
|
||||
telemetry.toolClosed("aboutdebugging");
|
||||
telemetry.destroy();
|
||||
|
||||
this._prefListeners.forEach(([pref, listener]) => {
|
||||
Services.prefs.removeObserver(pref, listener);
|
||||
});
|
||||
this._prefListeners = [];
|
||||
|
||||
React.unmountComponentAtNode(document.querySelector("#addons"));
|
||||
React.unmountComponentAtNode(document.querySelector("#workers"));
|
||||
|
||||
this.client.close();
|
||||
this.client = null;
|
||||
},
|
||||
};
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function load() {
|
||||
window.removeEventListener("DOMContentLoaded", load);
|
||||
AboutDebugging.init();
|
||||
});
|
||||
|
||||
window.addEventListener("unload", function unload() {
|
||||
window.removeEventListener("unload", unload);
|
||||
AboutDebugging.destroy();
|
||||
});
|
|
@ -16,39 +16,8 @@
|
|||
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/content/aboutdebugging/aboutdebugging.css" type="text/css"/>
|
||||
<script type="application/javascript" src="resource://devtools/client/shared/vendor/react.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="chrome://devtools/content/aboutdebugging/aboutdebugging.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="chrome://devtools/content/aboutdebugging/initializer.js"></script>
|
||||
</head>
|
||||
<body id="body">
|
||||
<div id="categories">
|
||||
<div class="category" value="addons" selected="true">
|
||||
<img class="category-icon" src="chrome://devtools/skin/images/debugging-addons.svg"/>
|
||||
<div class="category-name">&aboutDebugging.addons;</div>
|
||||
</div>
|
||||
<div class="category" value="workers">
|
||||
<img class="category-icon" src="chrome://devtools/skin/images/debugging-workers.svg"/>
|
||||
<div class="category-name">&aboutDebugging.workers;</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-content">
|
||||
<div id="tab-addons" class="tab active">
|
||||
<div class="header">
|
||||
<h1 class="header-name">&aboutDebugging.addons;</h1>
|
||||
</div>
|
||||
<div class="addon-controls">
|
||||
<div class="addon-options">
|
||||
<input id="enable-addon-debugging" type="checkbox" data-pref="devtools.chrome.enabled"/>
|
||||
<label for="enable-addon-debugging" title="&aboutDebugging.addonDebugging.tooltip;">&aboutDebugging.addonDebugging.label;</label>
|
||||
</div>
|
||||
<button id="load-addon-from-file">&aboutDebugging.loadTemporaryAddon;</button>
|
||||
</div>
|
||||
<div id="addons"></div>
|
||||
</div>
|
||||
<div id="tab-workers" class="tab">
|
||||
<div class="header">
|
||||
<h1 class="header-name">&aboutDebugging.workers;</h1>
|
||||
</div>
|
||||
<div id="workers"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/* 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/. */
|
||||
|
||||
/* global React */
|
||||
|
||||
"use strict";
|
||||
|
||||
loader.lazyRequireGetter(this, "React",
|
||||
"devtools/client/shared/vendor/react");
|
||||
loader.lazyRequireGetter(this, "AddonsTab",
|
||||
"devtools/client/aboutdebugging/components/addons-tab", true);
|
||||
loader.lazyRequireGetter(this, "TabMenu",
|
||||
"devtools/client/aboutdebugging/components/tab-menu", true);
|
||||
loader.lazyRequireGetter(this, "WorkersTab",
|
||||
"devtools/client/aboutdebugging/components/workers-tab", true);
|
||||
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/aboutdebugging.properties");
|
||||
|
||||
const tabs = [
|
||||
{ id: "addons", name: Strings.GetStringFromName("addons"),
|
||||
icon: "chrome://devtools/skin/images/debugging-addons.svg",
|
||||
component: AddonsTab },
|
||||
{ id: "workers", name: Strings.GetStringFromName("workers"),
|
||||
icon: "chrome://devtools/skin/images/debugging-workers.svg",
|
||||
component: WorkersTab },
|
||||
];
|
||||
const defaultTabId = "addons";
|
||||
|
||||
exports.AboutDebuggingApp = React.createClass({
|
||||
displayName: "AboutDebuggingApp",
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
selectedTabId: defaultTabId
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
this.props.window.addEventListener("hashchange", this.onHashChange);
|
||||
this.onHashChange();
|
||||
this.props.telemetry.toolOpened("aboutdebugging");
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.window.removeEventListener("hashchange", this.onHashChange);
|
||||
this.props.telemetry.toolClosed("aboutdebugging");
|
||||
this.props.telemetry.destroy();
|
||||
},
|
||||
|
||||
render() {
|
||||
let { client } = this.props;
|
||||
let { selectedTabId } = this.state;
|
||||
let selectTab = this.selectTab;
|
||||
|
||||
let selectedTab = tabs.find(t => t.id == selectedTabId);
|
||||
|
||||
return React.createElement(
|
||||
"div", { className: "app"},
|
||||
React.createElement(TabMenu, { tabs, selectedTabId, selectTab }),
|
||||
React.createElement("div", { className: "main-content" },
|
||||
React.createElement(selectedTab.component, { client }))
|
||||
);
|
||||
},
|
||||
|
||||
onHashChange() {
|
||||
let tabId = this.props.window.location.hash.substr(1);
|
||||
|
||||
let isValid = tabs.some(t => t.id == tabId);
|
||||
if (isValid) {
|
||||
this.setState({ selectedTabId: tabId });
|
||||
} else {
|
||||
// If the current hash matches no valid category, navigate to the default
|
||||
// tab.
|
||||
this.selectTab(defaultTabId);
|
||||
}
|
||||
},
|
||||
|
||||
selectTab(tabId) {
|
||||
let win = this.props.window;
|
||||
win.location.hash = "#" + tabId;
|
||||
}
|
||||
});
|
|
@ -0,0 +1,76 @@
|
|||
/* 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/. */
|
||||
|
||||
/* global React */
|
||||
|
||||
"use strict";
|
||||
|
||||
loader.lazyRequireGetter(this, "Ci", "chrome", true);
|
||||
loader.lazyRequireGetter(this, "Cc", "chrome", true);
|
||||
loader.lazyRequireGetter(this, "React", "devtools/client/shared/vendor/react");
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
|
||||
loader.lazyImporter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/aboutdebugging.properties");
|
||||
|
||||
exports.AddonsControls = React.createClass({
|
||||
displayName: "AddonsControls",
|
||||
|
||||
render() {
|
||||
let { debugDisabled } = this.props;
|
||||
|
||||
return React.createElement(
|
||||
"div", { className: "addons-controls" }, React.createElement(
|
||||
"div", { className: "addons-options" },
|
||||
React.createElement("input", {
|
||||
id: "enable-addon-debugging",
|
||||
type: "checkbox",
|
||||
checked: !debugDisabled,
|
||||
onChange: this.onEnableAddonDebuggingChange,
|
||||
}),
|
||||
React.createElement("label", {
|
||||
htmlFor: "enable-addon-debugging",
|
||||
title: Strings.GetStringFromName("addonDebugging.tooltip")
|
||||
}, Strings.GetStringFromName("addonDebugging.label"))
|
||||
),
|
||||
React.createElement("button", {
|
||||
id: "load-addon-from-file",
|
||||
onClick: this.loadAddonFromFile,
|
||||
}, Strings.GetStringFromName("loadTemporaryAddon"))
|
||||
);
|
||||
},
|
||||
|
||||
onEnableAddonDebuggingChange(event) {
|
||||
let enabled = event.target.checked;
|
||||
Services.prefs.setBoolPref("devtools.chrome.enabled", enabled);
|
||||
},
|
||||
|
||||
loadAddonFromFile(event) {
|
||||
let win = event.target.ownerDocument.defaultView;
|
||||
|
||||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
fp.init(win,
|
||||
Strings.GetStringFromName("selectAddonFromFile"),
|
||||
Ci.nsIFilePicker.modeOpen);
|
||||
let res = fp.show();
|
||||
if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
|
||||
return;
|
||||
}
|
||||
let file = fp.file;
|
||||
// AddonManager.installTemporaryAddon accepts either
|
||||
// addon directory or final xpi file.
|
||||
if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
|
||||
file = file.parent;
|
||||
}
|
||||
try {
|
||||
AddonManager.installTemporaryAddon(file);
|
||||
} catch (e) {
|
||||
win.alert("Error while installing the addon:\n" + e.message + "\n");
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
});
|
|
@ -0,0 +1,117 @@
|
|||
/* 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/. */
|
||||
|
||||
/* global AddonManager, React */
|
||||
|
||||
"use strict";
|
||||
|
||||
loader.lazyRequireGetter(this, "React",
|
||||
"devtools/client/shared/vendor/react");
|
||||
loader.lazyRequireGetter(this, "TargetList",
|
||||
"devtools/client/aboutdebugging/components/target-list", true);
|
||||
loader.lazyRequireGetter(this, "TabHeader",
|
||||
"devtools/client/aboutdebugging/components/tab-header", true);
|
||||
loader.lazyRequireGetter(this, "AddonsControls",
|
||||
"devtools/client/aboutdebugging/components/addons-controls", true);
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
|
||||
loader.lazyImporter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
const ExtensionIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/aboutdebugging.properties");
|
||||
|
||||
exports.AddonsTab = React.createClass({
|
||||
displayName: "AddonsTab",
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
extensions: [],
|
||||
debugDisabled: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
AddonManager.addAddonListener(this);
|
||||
Services.prefs.addObserver("devtools.chrome.enabled",
|
||||
this.updateDebugStatus, false);
|
||||
this.updateDebugStatus();
|
||||
this.updateAddonsList();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
AddonManager.removeAddonListener(this);
|
||||
Services.prefs.removeObserver("devtools.chrome.enabled",
|
||||
this.updateDebugStatus);
|
||||
},
|
||||
|
||||
render() {
|
||||
let { client } = this.props;
|
||||
let { debugDisabled, extensions: targets } = this.state;
|
||||
let name = Strings.GetStringFromName("extensions");
|
||||
|
||||
return React.createElement(
|
||||
"div", { id: "tab-addons", className: "tab", role: "tabpanel",
|
||||
"aria-labelledby": "tab-addons-header-name" },
|
||||
React.createElement(TabHeader, {
|
||||
id: "tab-addons-header-name",
|
||||
name: Strings.GetStringFromName("addons")}),
|
||||
React.createElement(AddonsControls, { debugDisabled }),
|
||||
React.createElement(
|
||||
"div", { id: "addons" },
|
||||
React.createElement(TargetList,
|
||||
{ name, targets, client, debugDisabled })
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
updateDebugStatus() {
|
||||
this.setState({
|
||||
debugDisabled: !Services.prefs.getBoolPref("devtools.chrome.enabled")
|
||||
});
|
||||
},
|
||||
|
||||
updateAddonsList() {
|
||||
AddonManager.getAllAddons(addons => {
|
||||
let extensions = addons.filter(addon => addon.isDebuggable).map(addon => {
|
||||
return {
|
||||
name: addon.name,
|
||||
icon: addon.iconURL || ExtensionIcon,
|
||||
type: addon.type,
|
||||
addonID: addon.id
|
||||
};
|
||||
});
|
||||
this.setState({ extensions });
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Mandatory callback as AddonManager listener.
|
||||
*/
|
||||
onInstalled() {
|
||||
this.updateAddonsList();
|
||||
},
|
||||
|
||||
/**
|
||||
* Mandatory callback as AddonManager listener.
|
||||
*/
|
||||
onUninstalled() {
|
||||
this.updateAddonsList();
|
||||
},
|
||||
|
||||
/**
|
||||
* Mandatory callback as AddonManager listener.
|
||||
*/
|
||||
onEnabled() {
|
||||
this.updateAddonsList();
|
||||
},
|
||||
|
||||
/**
|
||||
* Mandatory callback as AddonManager listener.
|
||||
*/
|
||||
onDisabled() {
|
||||
this.updateAddonsList();
|
||||
},
|
||||
});
|
|
@ -1,80 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* global AddonManager, React, TargetListComponent */
|
||||
|
||||
"use strict";
|
||||
|
||||
loader.lazyRequireGetter(this, "React",
|
||||
"devtools/client/shared/vendor/react");
|
||||
loader.lazyRequireGetter(this, "TargetListComponent",
|
||||
"devtools/client/aboutdebugging/components/target-list", true);
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
|
||||
loader.lazyImporter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
const ExtensionIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/aboutdebugging.properties");
|
||||
|
||||
exports.AddonsComponent = React.createClass({
|
||||
displayName: "AddonsComponent",
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
extensions: []
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
AddonManager.addAddonListener(this);
|
||||
this.update();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
AddonManager.removeAddonListener(this);
|
||||
},
|
||||
|
||||
render() {
|
||||
let client = this.props.client;
|
||||
let targets = this.state.extensions;
|
||||
let name = Strings.GetStringFromName("extensions");
|
||||
let debugDisabled = !Services.prefs.getBoolPref("devtools.chrome.enabled");
|
||||
return React.createElement("div", null,
|
||||
React.createElement(TargetListComponent,
|
||||
{ name, targets, client, debugDisabled })
|
||||
);
|
||||
},
|
||||
|
||||
update() {
|
||||
AddonManager.getAllAddons(addons => {
|
||||
let extensions = addons.filter(addon => addon.isDebuggable).map(addon => {
|
||||
return {
|
||||
name: addon.name,
|
||||
icon: addon.iconURL || ExtensionIcon,
|
||||
type: addon.type,
|
||||
addonID: addon.id
|
||||
};
|
||||
});
|
||||
this.setState({ extensions });
|
||||
});
|
||||
},
|
||||
|
||||
onInstalled() {
|
||||
this.update();
|
||||
},
|
||||
|
||||
onUninstalled() {
|
||||
this.update();
|
||||
},
|
||||
|
||||
onEnabled() {
|
||||
this.update();
|
||||
},
|
||||
|
||||
onDisabled() {
|
||||
this.update();
|
||||
},
|
||||
});
|
|
@ -3,8 +3,13 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'addons.js',
|
||||
'aboutdebugging.js',
|
||||
'addons-controls.js',
|
||||
'addons-tab.js',
|
||||
'tab-header.js',
|
||||
'tab-menu-entry.js',
|
||||
'tab-menu.js',
|
||||
'target-list.js',
|
||||
'target.js',
|
||||
'workers.js',
|
||||
'workers-tab.js',
|
||||
)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/* 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/. */
|
||||
|
||||
/* global React */
|
||||
|
||||
"use strict";
|
||||
|
||||
loader.lazyRequireGetter(this, "React",
|
||||
"devtools/client/shared/vendor/react");
|
||||
|
||||
exports.TabHeader = React.createClass({
|
||||
displayName: "TabHeader",
|
||||
|
||||
render() {
|
||||
let { name, id } = this.props;
|
||||
|
||||
return React.createElement(
|
||||
"div", { className: "header" }, React.createElement(
|
||||
"h1", { id, className: "header-name" }, name));
|
||||
},
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
/* 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/. */
|
||||
|
||||
/* global React */
|
||||
|
||||
"use strict";
|
||||
|
||||
loader.lazyRequireGetter(this, "React",
|
||||
"devtools/client/shared/vendor/react");
|
||||
|
||||
exports.TabMenuEntry = React.createClass({
|
||||
displayName: "TabMenuEntry",
|
||||
|
||||
render() {
|
||||
let { icon, name, selected } = this.props;
|
||||
|
||||
// Here .category, .category-icon, .category-name classnames are used to
|
||||
// apply common styles defined.
|
||||
let className = "category" + (selected ? " selected" : "");
|
||||
return React.createElement(
|
||||
"div", { className, onClick: this.onClick,
|
||||
"aria-selected": selected, role: "tab" },
|
||||
React.createElement("img", { className: "category-icon", src: icon,
|
||||
role: "presentation" }),
|
||||
React.createElement("div", { className: "category-name" }, name)
|
||||
);
|
||||
},
|
||||
|
||||
onClick() {
|
||||
this.props.selectTab(this.props.tabId);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,28 @@
|
|||
/* 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/. */
|
||||
|
||||
/* global React */
|
||||
|
||||
"use strict";
|
||||
|
||||
loader.lazyRequireGetter(this, "React",
|
||||
"devtools/client/shared/vendor/react");
|
||||
loader.lazyRequireGetter(this, "TabMenuEntry",
|
||||
"devtools/client/aboutdebugging/components/tab-menu-entry", true);
|
||||
|
||||
exports.TabMenu = React.createClass({
|
||||
displayName: "TabMenu",
|
||||
|
||||
render() {
|
||||
let { tabs, selectedTabId, selectTab } = this.props;
|
||||
let tabLinks = tabs.map(({ id, name, icon }) => {
|
||||
let selected = id == selectedTabId;
|
||||
return React.createElement(TabMenuEntry,
|
||||
{ tabId: id, name, icon, selected, selectTab });
|
||||
});
|
||||
|
||||
// "categories" id used for styling purposes
|
||||
return React.createElement("div", { id: "categories" }, tabLinks);
|
||||
},
|
||||
});
|
|
@ -2,13 +2,13 @@
|
|||
* 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/. */
|
||||
|
||||
/* global React, TargetComponent */
|
||||
/* global React */
|
||||
|
||||
"use strict";
|
||||
|
||||
loader.lazyRequireGetter(this, "React",
|
||||
"devtools/client/shared/vendor/react");
|
||||
loader.lazyRequireGetter(this, "TargetComponent",
|
||||
loader.lazyRequireGetter(this, "Target",
|
||||
"devtools/client/aboutdebugging/components/target", true);
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
|
||||
|
@ -18,15 +18,13 @@ const LocaleCompare = (a, b) => {
|
|||
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
||||
};
|
||||
|
||||
exports.TargetListComponent = React.createClass({
|
||||
displayName: "TargetListComponent",
|
||||
exports.TargetList = React.createClass({
|
||||
displayName: "TargetList",
|
||||
|
||||
render() {
|
||||
let client = this.props.client;
|
||||
let debugDisabled = this.props.debugDisabled;
|
||||
let { client, debugDisabled } = this.props;
|
||||
let targets = this.props.targets.sort(LocaleCompare).map(target => {
|
||||
return React.createElement(TargetComponent,
|
||||
{ client, target, debugDisabled });
|
||||
return React.createElement(Target, { client, target, debugDisabled });
|
||||
});
|
||||
return (
|
||||
React.createElement("div", { id: this.props.id, className: "targets" },
|
||||
|
|
|
@ -23,12 +23,11 @@ loader.lazyRequireGetter(this, "gDevTools",
|
|||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/aboutdebugging.properties");
|
||||
|
||||
exports.TargetComponent = React.createClass({
|
||||
displayName: "TargetComponent",
|
||||
exports.Target = React.createClass({
|
||||
displayName: "Target",
|
||||
|
||||
debug() {
|
||||
let client = this.props.client;
|
||||
let target = this.props.target;
|
||||
let { client, target } = this.props;
|
||||
switch (target.type) {
|
||||
case "extension":
|
||||
BrowserToolboxProcess.init({ addonID: target.addonID });
|
||||
|
@ -53,12 +52,11 @@ exports.TargetComponent = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
let target = this.props.target;
|
||||
let debugDisabled = this.props.debugDisabled;
|
||||
|
||||
let { target, debugDisabled } = this.props;
|
||||
return React.createElement("div", { className: "target" },
|
||||
React.createElement("img", {
|
||||
className: "target-icon",
|
||||
role: "presentation",
|
||||
src: target.icon }),
|
||||
React.createElement("div", { className: "target-details" },
|
||||
React.createElement("div", { className: "target-name" }, target.name),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
/* global React, TargetListComponent */
|
||||
/* global React */
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -10,8 +10,10 @@ loader.lazyRequireGetter(this, "Ci",
|
|||
"chrome", true);
|
||||
loader.lazyRequireGetter(this, "React",
|
||||
"devtools/client/shared/vendor/react");
|
||||
loader.lazyRequireGetter(this, "TargetListComponent",
|
||||
loader.lazyRequireGetter(this, "TargetList",
|
||||
"devtools/client/aboutdebugging/components/target-list", true);
|
||||
loader.lazyRequireGetter(this, "TabHeader",
|
||||
"devtools/client/aboutdebugging/components/tab-header", true);
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
|
||||
loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm");
|
||||
|
@ -20,8 +22,8 @@ const Strings = Services.strings.createBundle(
|
|||
"chrome://devtools/locale/aboutdebugging.properties");
|
||||
const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg";
|
||||
|
||||
exports.WorkersComponent = React.createClass({
|
||||
displayName: "WorkersComponent",
|
||||
exports.WorkersTab = React.createClass({
|
||||
displayName: "WorkersTab",
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
|
@ -47,22 +49,30 @@ exports.WorkersComponent = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
let client = this.props.client;
|
||||
let workers = this.state.workers;
|
||||
return React.createElement("div", { className: "inverted-icons" },
|
||||
React.createElement(TargetListComponent, {
|
||||
id: "service-workers",
|
||||
name: Strings.GetStringFromName("serviceWorkers"),
|
||||
targets: workers.service, client }),
|
||||
React.createElement(TargetListComponent, {
|
||||
id: "shared-workers",
|
||||
name: Strings.GetStringFromName("sharedWorkers"),
|
||||
targets: workers.shared, client }),
|
||||
React.createElement(TargetListComponent, {
|
||||
id: "other-workers",
|
||||
name: Strings.GetStringFromName("otherWorkers"),
|
||||
targets: workers.other, client })
|
||||
);
|
||||
let { client } = this.props;
|
||||
let { workers } = this.state;
|
||||
|
||||
return React.createElement(
|
||||
"div", { id: "tab-workers", className: "tab", role: "tabpanel",
|
||||
"aria-labelledby": "tab-workers-header-name" },
|
||||
React.createElement(TabHeader, {
|
||||
id: "tab-workers-header-name",
|
||||
name: Strings.GetStringFromName("workers")}),
|
||||
React.createElement(
|
||||
"div", { id: "workers", className: "inverted-icons" },
|
||||
React.createElement(TargetList, {
|
||||
id: "service-workers",
|
||||
name: Strings.GetStringFromName("serviceWorkers"),
|
||||
targets: workers.service, client }),
|
||||
React.createElement(TargetList, {
|
||||
id: "shared-workers",
|
||||
name: Strings.GetStringFromName("sharedWorkers"),
|
||||
targets: workers.shared, client }),
|
||||
React.createElement(TargetList, {
|
||||
id: "other-workers",
|
||||
name: Strings.GetStringFromName("otherWorkers"),
|
||||
targets: workers.other, client }))
|
||||
);
|
||||
},
|
||||
|
||||
update() {
|
|
@ -0,0 +1,55 @@
|
|||
/* 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/. */
|
||||
|
||||
/* eslint-env browser */
|
||||
/* global DebuggerClient, DebuggerServer, React */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { loader } = Components.utils.import(
|
||||
"resource://devtools/shared/Loader.jsm", {});
|
||||
|
||||
loader.lazyRequireGetter(this, "DebuggerClient",
|
||||
"devtools/shared/client/main", true);
|
||||
loader.lazyRequireGetter(this, "DebuggerServer",
|
||||
"devtools/server/main", true);
|
||||
loader.lazyRequireGetter(this, "Telemetry",
|
||||
"devtools/client/shared/telemetry");
|
||||
loader.lazyRequireGetter(this, "AboutDebuggingApp",
|
||||
"devtools/client/aboutdebugging/components/aboutdebugging", true);
|
||||
|
||||
var AboutDebugging = {
|
||||
init() {
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
DebuggerServer.allowChromeProcess = true;
|
||||
this.client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
|
||||
this.client.connect().then(() => {
|
||||
let client = this.client;
|
||||
let telemetry = new Telemetry();
|
||||
React.render(React.createElement(AboutDebuggingApp,
|
||||
{ client, telemetry, window }), document.querySelector("#body"));
|
||||
});
|
||||
},
|
||||
|
||||
destroy() {
|
||||
React.unmountComponentAtNode(document.querySelector("#body"));
|
||||
|
||||
this.client.close();
|
||||
this.client = null;
|
||||
},
|
||||
};
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function load() {
|
||||
window.removeEventListener("DOMContentLoaded", load);
|
||||
AboutDebugging.init();
|
||||
});
|
||||
|
||||
window.addEventListener("unload", function unload() {
|
||||
window.removeEventListener("unload", unload);
|
||||
AboutDebugging.destroy();
|
||||
});
|
|
@ -26,6 +26,7 @@ add_task(function* () {
|
|||
let swTab = yield addTab(TAB_URL);
|
||||
|
||||
let serviceWorkersElement = document.getElementById("service-workers");
|
||||
|
||||
yield waitForMutation(serviceWorkersElement, { childList: true });
|
||||
|
||||
// Check that the service worker appears in the UI
|
||||
|
|
|
@ -21,19 +21,22 @@ registerCleanupFunction(() => {
|
|||
DevToolsUtils.testing = false;
|
||||
});
|
||||
|
||||
function openAboutDebugging(page) {
|
||||
function* openAboutDebugging(page) {
|
||||
info("opening about:debugging");
|
||||
let url = "about:debugging";
|
||||
if (page) {
|
||||
url += "#" + page;
|
||||
}
|
||||
return addTab(url).then(tab => {
|
||||
let browser = tab.linkedBrowser;
|
||||
return {
|
||||
tab,
|
||||
document: browser.contentDocument,
|
||||
};
|
||||
});
|
||||
|
||||
let tab = yield addTab(url);
|
||||
let browser = tab.linkedBrowser;
|
||||
let document = browser.contentDocument;
|
||||
|
||||
if (!document.querySelector(".app")) {
|
||||
yield waitForMutation(document.body, { childList: true });
|
||||
}
|
||||
|
||||
return { tab, document };
|
||||
}
|
||||
|
||||
function closeAboutDebugging(tab) {
|
||||
|
|
|
@ -184,7 +184,7 @@ var AnimationsController = {
|
|||
this.nodeFront = null;
|
||||
|
||||
// Finish releasing players that haven't been released yet.
|
||||
yield Promise.all(this.nonBlockingPlayerReleases);
|
||||
yield promise.all(this.nonBlockingPlayerReleases);
|
||||
|
||||
if (this.animationsFront) {
|
||||
this.animationsFront.destroy();
|
||||
|
|
|
@ -258,8 +258,6 @@ var AnimationsPanel = {
|
|||
* the various components again.
|
||||
*/
|
||||
refreshAnimationsUI: Task.async(function*() {
|
||||
let done = gInspector.updating("animationspanel");
|
||||
|
||||
// Empty the whole panel first.
|
||||
this.togglePlayers(true);
|
||||
|
||||
|
@ -278,12 +276,10 @@ var AnimationsPanel = {
|
|||
if (!AnimationsController.animationPlayers.length) {
|
||||
this.togglePlayers(false);
|
||||
this.emit(this.UI_UPDATED_EVENT);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
this.emit(this.UI_UPDATED_EVENT);
|
||||
done();
|
||||
})
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* global nsContextMenu*/
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
@ -17,7 +16,7 @@ add_task(function*() {
|
|||
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
info("Select the test node with the browser ctx menu");
|
||||
yield selectWithBrowserMenu(inspector);
|
||||
yield clickOnInspectMenuItem(testActor, "div");
|
||||
assertNodeSelected(inspector, "div");
|
||||
|
||||
info("Press arrowUp to focus <body> " +
|
||||
|
@ -47,27 +46,6 @@ function selectPreviousNodeWithArrowUp(inspector) {
|
|||
return Promise.all([onUpdated, onNodeHighlighted]);
|
||||
}
|
||||
|
||||
function* selectWithBrowserMenu(inspector) {
|
||||
let contentAreaContextMenu = document.querySelector("#contentAreaContextMenu");
|
||||
let contextOpened = once(contentAreaContextMenu, "popupshown");
|
||||
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
|
||||
type: "contextmenu",
|
||||
button: 2
|
||||
}, gBrowser.selectedBrowser);
|
||||
|
||||
yield contextOpened;
|
||||
|
||||
yield gContextMenu.inspectNode();
|
||||
|
||||
let contextClosed = once(contentAreaContextMenu, "popuphidden");
|
||||
contentAreaContextMenu.hidden = true;
|
||||
contentAreaContextMenu.hidePopup();
|
||||
|
||||
yield inspector.once("inspector-updated");
|
||||
yield contextClosed;
|
||||
}
|
||||
|
||||
function* selectWithElementPicker(inspector, testActor) {
|
||||
yield startPicker(inspector.toolbox);
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ support-files =
|
|||
[browser_rules_completion-popup-hidden-after-navigation.js]
|
||||
[browser_rules_content_01.js]
|
||||
[browser_rules_content_02.js]
|
||||
skip-if = e10s # Bug 1039528: "inspect element" contextual-menu doesn't work with e10s
|
||||
skip-if = e10s && debug && os == 'win' # Bug 1250058 - Docshell leak on win debug e10s
|
||||
[browser_rules_context-menu-show-mdn-docs-01.js]
|
||||
[browser_rules_context-menu-show-mdn-docs-02.js]
|
||||
[browser_rules_context-menu-show-mdn-docs-03.js]
|
||||
|
|
|
@ -19,34 +19,12 @@ const STRINGS = Services.strings
|
|||
.createBundle("chrome://devtools-shared/locale/styleinspector.properties");
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + CONTENT);
|
||||
let tab = yield addTab("data:text/html;charset=utf-8," + CONTENT);
|
||||
|
||||
info("Getting the test element");
|
||||
let element = getNode("span");
|
||||
let testActor = yield getTestActorWithoutToolbox(tab);
|
||||
let inspector = yield clickOnInspectMenuItem(testActor, "span");
|
||||
|
||||
info("Opening the inspector using the content context-menu");
|
||||
let onInspectorReady = gDevTools.once("inspector-ready");
|
||||
|
||||
document.popupNode = element;
|
||||
let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
|
||||
let contextMenu = new nsContextMenu(contentAreaContextMenu);
|
||||
yield contextMenu.inspectNode();
|
||||
|
||||
// Clean up context menu:
|
||||
contextMenu.hiding();
|
||||
|
||||
yield onInspectorReady;
|
||||
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
let toolbox = gDevTools.getToolbox(target);
|
||||
|
||||
info("Getting the inspector and making sure it is fully updated");
|
||||
let inspector = toolbox.getPanel("inspector");
|
||||
yield inspector.once("inspector-updated");
|
||||
|
||||
let view = inspector.ruleview.view;
|
||||
|
||||
checkRuleViewContent(view);
|
||||
checkRuleViewContent(inspector.ruleview.view);
|
||||
});
|
||||
|
||||
function checkRuleViewContent({styleDocument}) {
|
||||
|
@ -81,3 +59,4 @@ function checkRuleViewContent({styleDocument}) {
|
|||
is(propertyValues.length, 1, "There's only one property value, as expected");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@ Services.telemetry.canRecordExtended = true;
|
|||
registerCleanupFunction(function() {
|
||||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
});
|
||||
const HISTOGRAM_ID = "DEVTOOLS_PICKER_EYEDROPPER_OPENED_BOOLEAN";
|
||||
const HISTOGRAM_ID = "DEVTOOLS_PICKER_EYEDROPPER_OPENED_COUNT";
|
||||
const FLAG_HISTOGRAM_ID = "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG";
|
||||
const EXPECTED_TELEMETRY = {
|
||||
"DEVTOOLS_PICKER_EYEDROPPER_OPENED_BOOLEAN": 2,
|
||||
"DEVTOOLS_PICKER_EYEDROPPER_OPENED_COUNT": 2,
|
||||
"DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG": 1
|
||||
};
|
||||
|
||||
|
@ -122,7 +122,7 @@ function checkTelemetry() {
|
|||
let histogram = Services.telemetry.getHistogramById(histogramId);
|
||||
let snapshot = histogram.snapshot();
|
||||
|
||||
is(snapshot.counts[1], expected,
|
||||
is(snapshot.sum, expected,
|
||||
"eyedropper telemetry value correct for " + histogramId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,7 +217,9 @@ var openInspector = Task.async(function*() {
|
|||
inspector = toolbox.getPanel("inspector");
|
||||
|
||||
info("Waiting for the inspector to update");
|
||||
yield inspector.once("inspector-updated");
|
||||
if (inspector._updateProgress) {
|
||||
yield inspector.once("inspector-updated");
|
||||
}
|
||||
|
||||
return {
|
||||
toolbox: toolbox,
|
||||
|
|
|
@ -80,7 +80,7 @@ skip-if = e10s # GCLI isn't e10s compatible. See bug 1128988.
|
|||
[browser_inspector_iframe-navigation.js]
|
||||
[browser_inspector_infobar_01.js]
|
||||
[browser_inspector_initialization.js]
|
||||
skip-if = e10s && debug && os == 'win'
|
||||
skip-if = e10s && debug && os == 'win' # Bug 1250058 - Docshell leak on win debug e10s
|
||||
[browser_inspector_inspect-object-element.js]
|
||||
[browser_inspector_invalidate.js]
|
||||
[browser_inspector_keyboard-shortcuts-copy-outerhtml.js]
|
||||
|
|
|
@ -114,27 +114,3 @@ function* testBreadcrumbs(selector, inspector) {
|
|||
ok(button, "A crumbs is checked=true");
|
||||
is(button.getAttribute("tooltiptext"), expectedText, "Crumb refers to the right node");
|
||||
}
|
||||
|
||||
function* clickOnInspectMenuItem(testActor, selector) {
|
||||
info("Showing the contextual menu on node " + selector);
|
||||
let contentAreaContextMenu = document.querySelector("#contentAreaContextMenu");
|
||||
let contextOpened = once(contentAreaContextMenu, "popupshown");
|
||||
|
||||
yield testActor.synthesizeMouse({
|
||||
selector: selector,
|
||||
center: true,
|
||||
options: {type: "contextmenu", button: 2}
|
||||
});
|
||||
|
||||
yield contextOpened;
|
||||
|
||||
info("Triggering inspect action and hiding the menu.");
|
||||
yield gContextMenu.inspectNode();
|
||||
|
||||
let contextClosed = once(contentAreaContextMenu, "popuphidden");
|
||||
contentAreaContextMenu.hidePopup();
|
||||
|
||||
info("Waiting for inspector to update.");
|
||||
yield getActiveInspector().once("inspector-updated");
|
||||
yield contextClosed;
|
||||
}
|
||||
|
|
|
@ -175,6 +175,36 @@ function getActiveInspector() {
|
|||
return gDevTools.getToolbox(target).getPanel("inspector");
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click on a node in the test page and click on the inspect menu item.
|
||||
* @param {TestActor}
|
||||
* @param {String} selector The selector for the node to click on in the page.
|
||||
* @return {Promise} Resolves to the inspector when it has opened and is updated
|
||||
*/
|
||||
var clickOnInspectMenuItem = Task.async(function*(testActor, selector) {
|
||||
info("Showing the contextual menu on node " + selector);
|
||||
let contentAreaContextMenu = document.querySelector("#contentAreaContextMenu");
|
||||
let contextOpened = once(contentAreaContextMenu, "popupshown");
|
||||
|
||||
yield testActor.synthesizeMouse({
|
||||
selector: selector,
|
||||
center: true,
|
||||
options: {type: "contextmenu", button: 2}
|
||||
});
|
||||
|
||||
yield contextOpened;
|
||||
|
||||
info("Triggering the inspect action");
|
||||
yield gContextMenu.inspectNode();
|
||||
|
||||
info("Hiding the menu");
|
||||
let contextClosed = once(contentAreaContextMenu, "popuphidden");
|
||||
contentAreaContextMenu.hidePopup();
|
||||
yield contextClosed;
|
||||
|
||||
return getActiveInspector();
|
||||
});
|
||||
|
||||
/**
|
||||
* Open the toolbox, with the inspector tool visible, and the one of the sidebar
|
||||
* tabs selected.
|
||||
|
|
|
@ -138,7 +138,7 @@ devtools.jar:
|
|||
content/eyedropper/nocursor.css (eyedropper/nocursor.css)
|
||||
content/aboutdebugging/aboutdebugging.xhtml (aboutdebugging/aboutdebugging.xhtml)
|
||||
content/aboutdebugging/aboutdebugging.css (aboutdebugging/aboutdebugging.css)
|
||||
content/aboutdebugging/aboutdebugging.js (aboutdebugging/aboutdebugging.js)
|
||||
content/aboutdebugging/initializer.js (aboutdebugging/initializer.js)
|
||||
content/responsive.html/index.xhtml (responsive.html/index.xhtml)
|
||||
content/responsive.html/index.js (responsive.html/index.js)
|
||||
% skin devtools classic/1.0 %skin/
|
||||
|
|
|
@ -3,8 +3,3 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!ENTITY aboutDebugging.title "about:debugging">
|
||||
<!ENTITY aboutDebugging.addons "Add-ons">
|
||||
<!ENTITY aboutDebugging.addonDebugging.label "Enable add-on debugging">
|
||||
<!ENTITY aboutDebugging.addonDebugging.tooltip "Turning this on will allow you to debug add-ons and various other parts of the browser chrome">
|
||||
<!ENTITY aboutDebugging.loadTemporaryAddon "Load Temporary Add-on">
|
||||
<!ENTITY aboutDebugging.workers "Workers">
|
||||
|
|
|
@ -4,10 +4,17 @@
|
|||
|
||||
debug = Debug
|
||||
|
||||
addons = Add-ons
|
||||
addonDebugging.label = Enable add-on debugging
|
||||
addonDebugging.tooltip = Turning this on will allow you to debug add-ons and various other parts of the browser chrome
|
||||
loadTemporaryAddon = Load Temporary Add-on
|
||||
extensions = Extensions
|
||||
selectAddonFromFile = Select Add-on Directory or XPI File
|
||||
|
||||
workers = Workers
|
||||
serviceWorkers = Service Workers
|
||||
sharedWorkers = Shared Workers
|
||||
otherWorkers = Other Workers
|
||||
|
||||
nothing = Nothing yet.
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ const OBJECT_CLASS = { by: "objectClass", then: COUNT, other: COUNT };
|
|||
|
||||
const breakdowns = exports.breakdowns = {
|
||||
coarseType: {
|
||||
displayName: "Coarse Type",
|
||||
displayName: "Type",
|
||||
get tooltip() {
|
||||
// Importing down here is necessary because of the circular dependency
|
||||
// this introduces with `./utils.js`.
|
||||
|
@ -131,31 +131,13 @@ const breakdowns = exports.breakdowns = {
|
|||
},
|
||||
|
||||
allocationStack: {
|
||||
displayName: "Allocation Stack",
|
||||
displayName: "Call Stack",
|
||||
get tooltip() {
|
||||
const { L10N } = require("./utils");
|
||||
return L10N.getStr("breakdowns.allocationStack.tooltip");
|
||||
},
|
||||
breakdown: ALLOCATION_STACK,
|
||||
},
|
||||
|
||||
objectClass: {
|
||||
displayName: "Object Class",
|
||||
get tooltip() {
|
||||
const { L10N } = require("./utils");
|
||||
return L10N.getStr("breakdowns.objectClass.tooltip");
|
||||
},
|
||||
breakdown: OBJECT_CLASS,
|
||||
},
|
||||
|
||||
internalType: {
|
||||
displayName: "Internal Type",
|
||||
get tooltip() {
|
||||
const { L10N } = require("./utils");
|
||||
return L10N.getStr("breakdowns.internalType.tooltip");
|
||||
},
|
||||
breakdown: INTERNAL_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
const DOMINATOR_TREE_LABEL_COARSE_TYPE = {
|
||||
|
@ -175,7 +157,7 @@ const DOMINATOR_TREE_LABEL_COARSE_TYPE = {
|
|||
|
||||
const dominatorTreeBreakdowns = exports.dominatorTreeBreakdowns = {
|
||||
coarseType: {
|
||||
displayName: "Coarse Type",
|
||||
displayName: "Type",
|
||||
get tooltip() {
|
||||
const { L10N } = require("./utils");
|
||||
return L10N.getStr("dominatorTreeBreakdowns.coarseType.tooltip");
|
||||
|
@ -184,7 +166,7 @@ const dominatorTreeBreakdowns = exports.dominatorTreeBreakdowns = {
|
|||
},
|
||||
|
||||
allocationStack: {
|
||||
displayName: "Allocation Stack",
|
||||
displayName: "Call Stack",
|
||||
get tooltip() {
|
||||
const { L10N } = require("./utils");
|
||||
return L10N.getStr("dominatorTreeBreakdowns.allocationStack.tooltip");
|
||||
|
@ -195,15 +177,6 @@ const dominatorTreeBreakdowns = exports.dominatorTreeBreakdowns = {
|
|||
noStack: DOMINATOR_TREE_LABEL_COARSE_TYPE,
|
||||
},
|
||||
},
|
||||
|
||||
internalType: {
|
||||
displayName: "Internal Type",
|
||||
get tooltip() {
|
||||
const { L10N } = require("./utils");
|
||||
return L10N.getStr("dominatorTreeBreakdowns.internalType.tooltip");
|
||||
},
|
||||
breakdown: INTERNAL_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
/*** View States **************************************************************/
|
||||
|
|
|
@ -50,7 +50,7 @@ function catchAndIgnore(fn) {
|
|||
* @see `js/src/doc/Debugger/Debugger.Memory.md`
|
||||
*/
|
||||
let breakdownModel = exports.breakdown = PropTypes.shape({
|
||||
by: PropTypes.oneOf(["coarseType", "allocationStack", "objectClass", "internalType"]).isRequired,
|
||||
by: PropTypes.string.isRequired,
|
||||
});
|
||||
|
||||
let censusModel = exports.censusModel = PropTypes.shape({
|
||||
|
|
|
@ -61,10 +61,6 @@ exports.countCensus = makeInfallible(function ({ inverted, filter, diffing, brea
|
|||
histogram.add(COARSE_TYPE);
|
||||
} else if (breakdown === breakdowns.allocationStack.breakdown) {
|
||||
histogram.add(ALLOCATION_STACK);
|
||||
} else if (breakdown === breakdowns.objectClass.breakdown) {
|
||||
histogram.add(OBJECT_CLASS);
|
||||
} else if (breakdown === breakdowns.internalType.breakdown) {
|
||||
histogram.add(INTERNAL_TYPE);
|
||||
} else {
|
||||
histogram.add(CUSTOM);
|
||||
}
|
||||
|
@ -91,8 +87,6 @@ exports.countDominatorTree = makeInfallible(function ({ breakdown }) {
|
|||
histogram.add(COARSE_TYPE);
|
||||
} else if (breakdown === dominatorTreeBreakdowns.allocationStack.breakdown) {
|
||||
histogram.add(ALLOCATION_STACK);
|
||||
} else if (breakdown === dominatorTreeBreakdowns.internalType.breakdown) {
|
||||
histogram.add(INTERNAL_TYPE);
|
||||
} else {
|
||||
histogram.add(CUSTOM);
|
||||
}
|
||||
|
|
|
@ -19,13 +19,9 @@ this.test = makeMemoryTest(TEST_URL, function* ({ tab, panel }) {
|
|||
info("Check coarse type heap view");
|
||||
["objects", "other", "scripts", "strings"].forEach(findNameCell);
|
||||
|
||||
yield setBreakdown(panel.panelWin, "objectClass");
|
||||
info("Check object class heap view");
|
||||
["Function", "Object"].forEach(findNameCell);
|
||||
|
||||
yield setBreakdown(panel.panelWin, "internalType");
|
||||
info("Check internal type heap view");
|
||||
["JSObject"].forEach(findNameCell);
|
||||
yield setBreakdown(panel.panelWin, "allocationStack");
|
||||
info("Check allocation stack heap view");
|
||||
[L10N.getStr("tree-item.nostack")].forEach(findNameCell);
|
||||
|
||||
function findNameCell (name) {
|
||||
let el = Array.prototype.find.call($$(".tree .heap-tree-item-name span"), el => el.textContent === name);
|
||||
|
|
|
@ -28,11 +28,8 @@ this.test = makeMemoryTest(TEST_URL, function* ({ tab, panel }) {
|
|||
const doc = panel.panelWin.document;
|
||||
|
||||
yield dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
yield dispatch(breakdownActions.setBreakdownAndRefresh(heapWorker,
|
||||
breakdowns.objectClass.breakdown));
|
||||
|
||||
is(getState().breakdown.by, "objectClass",
|
||||
"Should be using object class breakdown");
|
||||
is(getState().breakdown.by, "coarseType",
|
||||
"Should be using coarse type breakdown");
|
||||
|
||||
const bytesCells = [...doc.querySelectorAll(".heap-tree-item-bytes")];
|
||||
checkCells(bytesCells);
|
||||
|
|
|
@ -14,7 +14,7 @@ Services.scriptloader.loadSubScript(
|
|||
this);
|
||||
|
||||
var { snapshotState: states } = require("devtools/client/memory/constants");
|
||||
var { breakdownEquals, breakdownNameToSpec } = require("devtools/client/memory/utils");
|
||||
var { breakdownEquals, breakdownNameToSpec, L10N } = require("devtools/client/memory/utils");
|
||||
|
||||
Services.prefs.setBoolPref("devtools.memory.enabled", true);
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ var HeapSnapshotFileUtils = require("devtools/shared/heapsnapshot/HeapSnapshotFi
|
|||
var HeapAnalysesClient = require("devtools/shared/heapsnapshot/HeapAnalysesClient");
|
||||
var { addDebuggerToGlobal } = require("resource://gre/modules/jsdebugger.jsm");
|
||||
var Store = require("devtools/client/memory/store");
|
||||
var { L10N } = require("devtools/client/memory/utils");
|
||||
var SYSTEM_PRINCIPAL = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
|
||||
|
||||
function dumpn(msg) {
|
||||
|
@ -80,11 +81,8 @@ function isBreakdownType (report, type) {
|
|||
switch (type) {
|
||||
case "coarseType":
|
||||
return report.children.find(c => c.name === "objects");
|
||||
case "objectClass":
|
||||
return report.children.find(c => c.name === "Function");
|
||||
case "internalType":
|
||||
return report.children.find(c => c.name === "js::BaseShape") &&
|
||||
!report.children.find(c => c.name === "objects");
|
||||
case "allocationStack":
|
||||
return report.children.find(c => c.name === "noStack");
|
||||
default:
|
||||
throw new Error(`isBreakdownType does not yet support ${type}`);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ add_task(function *() {
|
|||
|
||||
// Test default breakdown with no snapshots
|
||||
equal(getState().breakdown.by, "coarseType", "default coarseType breakdown selected at start.");
|
||||
dispatch(setBreakdownAndRefresh(heapWorker, breakdowns.objectClass.breakdown));
|
||||
equal(getState().breakdown.by, "objectClass", "breakdown changed with no snapshots");
|
||||
dispatch(setBreakdownAndRefresh(heapWorker, breakdowns.allocationStack.breakdown));
|
||||
equal(getState().breakdown.by, "allocationStack", "breakdown changed with no snapshots");
|
||||
|
||||
// Test invalid breakdowns
|
||||
ok(getState().errors.length === 0, "No error actions in the queue.");
|
||||
|
@ -34,13 +34,13 @@ add_task(function *() {
|
|||
yield waitUntilState(store, () => getState().errors.length === 1);
|
||||
ok(true, "Emits an error action when passing in an invalid breakdown object");
|
||||
|
||||
equal(getState().breakdown.by, "objectClass",
|
||||
equal(getState().breakdown.by, "allocationStack",
|
||||
"current breakdown unchanged when passing invalid breakdown");
|
||||
|
||||
// Test new snapshots
|
||||
dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS]);
|
||||
ok(isBreakdownType(getState().snapshots[0].census.report, "objectClass"),
|
||||
ok(isBreakdownType(getState().snapshots[0].census.report, "allocationStack"),
|
||||
"New snapshots use the current, non-default breakdown");
|
||||
|
||||
|
||||
|
@ -57,21 +57,24 @@ add_task(function *() {
|
|||
// Updates when changing breakdown during `SAVING_CENSUS`
|
||||
dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS, states.SAVED_CENSUS, states.SAVING_CENSUS]);
|
||||
dispatch(setBreakdownAndRefresh(heapWorker, breakdowns.objectClass.breakdown));
|
||||
dispatch(setBreakdownAndRefresh(heapWorker, breakdowns.allocationStack.breakdown));
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS, states.SAVED_CENSUS, states.SAVED_CENSUS]);
|
||||
|
||||
ok(breakdownEquals(getState().snapshots[2].census.breakdown, breakdowns.objectClass.breakdown),
|
||||
ok(breakdownEquals(getState().snapshots[2].census.breakdown, breakdowns.allocationStack.breakdown),
|
||||
"Breakdown can be changed while saving census, stores updated breakdown in snapshot");
|
||||
ok(isBreakdownType(getState().snapshots[2].census.report, "objectClass"),
|
||||
ok(isBreakdownType(getState().snapshots[2].census.report, "allocationStack"),
|
||||
"Breakdown can be changed while saving census, uses updated breakdown in census");
|
||||
|
||||
// Updates census on currently selected snapshot when changing breakdown
|
||||
ok(getState().snapshots[2].selected, "Third snapshot currently selected");
|
||||
dispatch(setBreakdownAndRefresh(heapWorker, breakdowns.internalType.breakdown));
|
||||
yield waitUntilState(store, () => isBreakdownType(getState().snapshots[2].census.report, "internalType"));
|
||||
ok(isBreakdownType(getState().snapshots[2].census.report, "internalType"),
|
||||
dispatch(setBreakdownAndRefresh(heapWorker, breakdowns.coarseType.breakdown));
|
||||
yield waitUntilState(store, () => isBreakdownType(getState().snapshots[2].census.report, "coarseType"));
|
||||
ok(isBreakdownType(getState().snapshots[2].census.report, "coarseType"),
|
||||
"Snapshot census updated when changing breakdowns after already generating one census");
|
||||
|
||||
dispatch(setBreakdownAndRefresh(heapWorker, breakdowns.allocationStack.breakdown));
|
||||
yield waitUntilState(store, () => isBreakdownType(getState().snapshots[2].census.report, "allocationStack"));
|
||||
|
||||
// Does not update unselected censuses
|
||||
ok(!getState().snapshots[1].selected, "Second snapshot unselected currently");
|
||||
ok(breakdownEquals(getState().snapshots[1].census.breakdown, breakdowns.coarseType.breakdown),
|
||||
|
@ -85,10 +88,10 @@ add_task(function *() {
|
|||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS, states.SAVED_CENSUS, states.SAVED_CENSUS]);
|
||||
|
||||
ok(getState().snapshots[1].selected, "Second snapshot selected currently");
|
||||
ok(breakdownEquals(getState().snapshots[1].census.breakdown, breakdowns.internalType.breakdown),
|
||||
"Second snapshot using `internalType` breakdown and updated to correct breakdown");
|
||||
ok(isBreakdownType(getState().snapshots[1].census.report, "internalType"),
|
||||
"Second snapshot using `internalType` for census and updated to correct breakdown");
|
||||
ok(breakdownEquals(getState().snapshots[1].census.breakdown, breakdowns.allocationStack.breakdown),
|
||||
"Second snapshot using `allocationStack` breakdown and updated to correct breakdown");
|
||||
ok(isBreakdownType(getState().snapshots[1].census.report, "allocationStack"),
|
||||
"Second snapshot using `allocationStack` for census and updated to correct breakdown");
|
||||
|
||||
heapWorker.destroy();
|
||||
yield front.detach();
|
||||
|
|
|
@ -24,8 +24,8 @@ add_task(function *() {
|
|||
|
||||
// Test default breakdown with no snapshots
|
||||
equal(getState().breakdown.by, "coarseType", "default coarseType breakdown selected at start.");
|
||||
dispatch(setBreakdown(breakdowns.objectClass.breakdown));
|
||||
equal(getState().breakdown.by, "objectClass", "breakdown changed with no snapshots");
|
||||
dispatch(setBreakdown(breakdowns.allocationStack.breakdown));
|
||||
equal(getState().breakdown.by, "allocationStack", "breakdown changed with no snapshots");
|
||||
|
||||
// Test invalid breakdowns
|
||||
try {
|
||||
|
@ -34,12 +34,12 @@ add_task(function *() {
|
|||
} catch (e) {
|
||||
ok(true, "Throws when passing in an invalid breakdown object");
|
||||
}
|
||||
equal(getState().breakdown.by, "objectClass",
|
||||
equal(getState().breakdown.by, "allocationStack",
|
||||
"current breakdown unchanged when passing invalid breakdown");
|
||||
|
||||
// Test new snapshots
|
||||
dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS]);
|
||||
ok(isBreakdownType(getState().snapshots[0].census.report, "objectClass"),
|
||||
ok(isBreakdownType(getState().snapshots[0].census.report, "allocationStack"),
|
||||
"New snapshots use the current, non-default breakdown");
|
||||
});
|
||||
|
|
|
@ -71,7 +71,7 @@ add_task(function *() {
|
|||
name: "changing breakdowns",
|
||||
func: () =>
|
||||
dispatch(setBreakdownAndRefresh(heapWorker,
|
||||
breakdowns.objectClass.breakdown))
|
||||
breakdowns.allocationStack.breakdown))
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -55,10 +55,10 @@ add_task(function *() {
|
|||
getState().snapshots[0].dominatorTree.breakdown,
|
||||
"and the newly computed dominator tree has that breakdown");
|
||||
|
||||
// Switch to the internalType breakdown.
|
||||
// Switch to the allocationStack breakdown.
|
||||
dispatch(setDominatorTreeBreakdownAndRefresh(
|
||||
heapWorker,
|
||||
dominatorTreeBreakdowns.internalType.breakdown));
|
||||
dominatorTreeBreakdowns.allocationStack.breakdown));
|
||||
|
||||
yield waitUntilState(store, state =>
|
||||
state.snapshots[0].dominatorTree.state === dominatorTreeState.FETCHING);
|
||||
|
@ -69,10 +69,10 @@ add_task(function *() {
|
|||
yield waitUntilState(store, state =>
|
||||
state.snapshots[0].dominatorTree.state === dominatorTreeState.LOADED);
|
||||
equal(getState().snapshots[0].dominatorTree.breakdown,
|
||||
dominatorTreeBreakdowns.internalType.breakdown,
|
||||
"The new dominator tree's breakdown is internalType");
|
||||
dominatorTreeBreakdowns.allocationStack.breakdown,
|
||||
"The new dominator tree's breakdown is allocationStack");
|
||||
equal(getState().dominatorTreeBreakdown,
|
||||
dominatorTreeBreakdowns.internalType.breakdown,
|
||||
dominatorTreeBreakdowns.allocationStack.breakdown,
|
||||
"as is our requested dominator tree breakdown");
|
||||
|
||||
heapWorker.destroy();
|
||||
|
|
|
@ -55,21 +55,21 @@ add_task(function *() {
|
|||
getState().snapshots[0].dominatorTree.breakdown,
|
||||
"and the newly computed dominator tree has that breakdown");
|
||||
|
||||
// Switch to the internalType breakdown while we are still fetching the
|
||||
// Switch to the allocationStack breakdown while we are still fetching the
|
||||
// dominator tree.
|
||||
dispatch(setDominatorTreeBreakdownAndRefresh(
|
||||
heapWorker,
|
||||
dominatorTreeBreakdowns.internalType.breakdown));
|
||||
dominatorTreeBreakdowns.allocationStack.breakdown));
|
||||
|
||||
// Wait for the dominator tree to finish being fetched.
|
||||
yield waitUntilState(store, state =>
|
||||
state.snapshots[0].dominatorTree.state === dominatorTreeState.LOADED);
|
||||
|
||||
equal(getState().snapshots[0].dominatorTree.breakdown,
|
||||
dominatorTreeBreakdowns.internalType.breakdown,
|
||||
"The new dominator tree's breakdown is internalType");
|
||||
dominatorTreeBreakdowns.allocationStack.breakdown,
|
||||
"The new dominator tree's breakdown is allocationStack");
|
||||
equal(getState().dominatorTreeBreakdown,
|
||||
dominatorTreeBreakdowns.internalType.breakdown,
|
||||
dominatorTreeBreakdowns.allocationStack.breakdown,
|
||||
"as is our requested dominator tree breakdown");
|
||||
|
||||
heapWorker.destroy();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
DevToolsModules(
|
||||
'browser.js',
|
||||
'resizable-viewport.js',
|
||||
'viewport-dimension.js',
|
||||
'viewport-toolbar.js',
|
||||
'viewport.js',
|
||||
'viewports.js',
|
||||
|
|
|
@ -9,12 +9,13 @@
|
|||
const { DOM: dom, createClass, createFactory, PropTypes } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
|
||||
const Constants = require("../constants");
|
||||
const Types = require("../types");
|
||||
const Browser = createFactory(require("./browser"));
|
||||
const ViewportToolbar = createFactory(require("./viewport-toolbar"));
|
||||
|
||||
const VIEWPORT_MIN_WIDTH = 280;
|
||||
const VIEWPORT_MIN_HEIGHT = 280;
|
||||
const VIEWPORT_MIN_WIDTH = Constants.MIN_VIEWPORT_DIMENSION;
|
||||
const VIEWPORT_MIN_HEIGHT = Constants.MIN_VIEWPORT_DIMENSION;
|
||||
|
||||
module.exports = createClass({
|
||||
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { DOM: dom, createClass, PropTypes } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
|
||||
const Constants = require("../constants");
|
||||
const Types = require("../types");
|
||||
|
||||
module.exports = createClass({
|
||||
|
||||
displayName: "ViewportDimension",
|
||||
|
||||
propTypes: {
|
||||
viewport: PropTypes.shape(Types.viewport).isRequired,
|
||||
onResizeViewport: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
let { width, height } = this.props.viewport;
|
||||
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
isEditing: false,
|
||||
isInvalid: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
let { width, height } = nextProps.viewport;
|
||||
|
||||
this.setState({
|
||||
width,
|
||||
height,
|
||||
});
|
||||
},
|
||||
|
||||
validateInput(value) {
|
||||
let isInvalid = true;
|
||||
|
||||
// Check the value is a number and greater than MIN_VIEWPORT_DIMENSION
|
||||
if (/^\d{3,4}$/.test(value) &&
|
||||
parseInt(value, 10) >= Constants.MIN_VIEWPORT_DIMENSION) {
|
||||
isInvalid = false;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isInvalid,
|
||||
});
|
||||
},
|
||||
|
||||
onInputBlur() {
|
||||
this.onInputSubmit();
|
||||
|
||||
this.setState({
|
||||
isEditing: false,
|
||||
inInvalid: false,
|
||||
});
|
||||
},
|
||||
|
||||
onInputChange({ target }) {
|
||||
if (target.value.length > 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.refs.widthInput == target) {
|
||||
this.setState({ width: target.value });
|
||||
this.validateInput(target.value);
|
||||
}
|
||||
|
||||
if (this.refs.heightInput == target) {
|
||||
this.setState({ height: target.value });
|
||||
this.validateInput(target.value);
|
||||
}
|
||||
},
|
||||
|
||||
onInputFocus() {
|
||||
this.setState({
|
||||
isEditing: true,
|
||||
});
|
||||
},
|
||||
|
||||
onInputKeyUp({ target, keyCode }) {
|
||||
// On Enter, submit the input
|
||||
if (keyCode == 13) {
|
||||
this.onInputSubmit();
|
||||
}
|
||||
|
||||
// On Esc, blur the target
|
||||
if (keyCode == 27) {
|
||||
target.blur();
|
||||
}
|
||||
},
|
||||
|
||||
onInputSubmit() {
|
||||
if (this.state.isInvalid) {
|
||||
let { width, height } = this.props.viewport;
|
||||
|
||||
this.setState({
|
||||
width,
|
||||
height,
|
||||
isInvalid: false,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onResizeViewport(parseInt(this.state.width, 10),
|
||||
parseInt(this.state.height, 10));
|
||||
},
|
||||
|
||||
render() {
|
||||
let editableClass = "viewport-dimension-editable";
|
||||
let inputClass = "viewport-dimension-input";
|
||||
|
||||
if (this.state.isEditing) {
|
||||
editableClass += " editing";
|
||||
inputClass += " editing";
|
||||
}
|
||||
|
||||
if (this.state.isInvalid) {
|
||||
editableClass += " invalid";
|
||||
}
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "viewport-dimension",
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
className: editableClass,
|
||||
},
|
||||
dom.input({
|
||||
ref: "widthInput",
|
||||
className: inputClass,
|
||||
size: 4,
|
||||
value: this.state.width,
|
||||
onBlur: this.onInputBlur,
|
||||
onChange: this.onInputChange,
|
||||
onFocus: this.onInputFocus,
|
||||
onKeyUp: this.onInputKeyUp,
|
||||
}),
|
||||
dom.span({
|
||||
className: "viewport-dimension-separator",
|
||||
}, "×"),
|
||||
dom.input({
|
||||
ref: "heightInput",
|
||||
className: inputClass,
|
||||
size: 4,
|
||||
value: this.state.height,
|
||||
onBlur: this.onInputBlur,
|
||||
onChange: this.onInputChange,
|
||||
onFocus: this.onInputFocus,
|
||||
onKeyUp: this.onInputKeyUp,
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
});
|
|
@ -9,6 +9,7 @@ const { DOM: dom, createClass, createFactory, PropTypes } =
|
|||
|
||||
const Types = require("../types");
|
||||
const ResizableViewport = createFactory(require("./resizable-viewport"));
|
||||
const ViewportDimension = createFactory(require("./viewport-dimension"));
|
||||
|
||||
module.exports = createClass({
|
||||
|
||||
|
@ -38,6 +39,10 @@ module.exports = createClass({
|
|||
viewport,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
}),
|
||||
ViewportDimension({
|
||||
viewport,
|
||||
onResizeViewport,
|
||||
})
|
||||
);
|
||||
},
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// The minimum viewport width and height
|
||||
exports.MIN_VIEWPORT_DIMENSION = 280;
|
|
@ -7,10 +7,14 @@
|
|||
|
||||
.theme-light {
|
||||
--viewport-box-shadow: 0 4px 4px 0 rgba(155, 155, 155, 0.26);
|
||||
--viewport-dimension-color: var(--theme-splitter-color);
|
||||
--viewport-dimension-editing-color: var(--theme-body-color);
|
||||
}
|
||||
|
||||
.theme-dark {
|
||||
--viewport-box-shadow: 0 4px 4px 0 rgba(105, 105, 105, 0.26);
|
||||
--viewport-dimension-color: var(--theme-body-color);
|
||||
--viewport-dimension-editing-color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
* {
|
||||
|
@ -57,11 +61,11 @@ body {
|
|||
display: inline-block;
|
||||
/* Align all viewports to the top */
|
||||
vertical-align: top;
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
box-shadow: var(--viewport-box-shadow);
|
||||
}
|
||||
|
||||
.resizable-viewport {
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
box-shadow: var(--viewport-box-shadow);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
@ -152,3 +156,47 @@ body {
|
|||
bottom: -4px;
|
||||
cursor: s-resize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Viewport Dimension Label
|
||||
*/
|
||||
|
||||
.viewport-dimension {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font: 10px sans-serif;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.viewport-dimension-editable {
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
.viewport-dimension-editable,
|
||||
.viewport-dimension-input {
|
||||
color: var(--viewport-dimension-color);
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.viewport-dimension-editable.editing,
|
||||
.viewport-dimension-input.editing {
|
||||
color: var(--viewport-dimension-editing-color);
|
||||
}
|
||||
|
||||
.viewport-dimension-editable.editing {
|
||||
border-bottom: 1px solid var(--theme-selection-background);
|
||||
}
|
||||
|
||||
.viewport-dimension-editable.editing.invalid {
|
||||
border-bottom: 1px solid #d92215;
|
||||
}
|
||||
|
||||
.viewport-dimension-input {
|
||||
background: transparent;
|
||||
border: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.viewport-dimension-separator {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ DIRS += [
|
|||
|
||||
DevToolsModules(
|
||||
'app.js',
|
||||
'constants.js',
|
||||
'index.css',
|
||||
'manager.js',
|
||||
'reducers.js',
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
*
|
||||
* To add metrics for a tool:
|
||||
*
|
||||
* 1. Create boolean, flag and exponential entries in
|
||||
* 1. Create count, flag, and exponential entries in
|
||||
* toolkit/components/telemetry/Histograms.json. Each type is optional but it
|
||||
* is best if all three can be included.
|
||||
*
|
||||
* 2. Add your chart entries to devtools/client/shared/telemetry.js
|
||||
* (Telemetry.prototype._histograms):
|
||||
* mytoolname: {
|
||||
* histogram: "DEVTOOLS_MYTOOLNAME_OPENED_BOOLEAN",
|
||||
* histogram: "DEVTOOLS_MYTOOLNAME_OPENED_COUNT",
|
||||
* userHistogram: "DEVTOOLS_MYTOOLNAME_OPENED_PER_USER_FLAG",
|
||||
* timerHistogram: "DEVTOOLS_MYTOOLNAME_TIME_ACTIVE_SECONDS"
|
||||
* },
|
||||
|
@ -61,176 +61,176 @@ var {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
|
|||
Telemetry.prototype = {
|
||||
_histograms: {
|
||||
toolbox: {
|
||||
histogram: "DEVTOOLS_TOOLBOX_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_TOOLBOX_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
options: {
|
||||
histogram: "DEVTOOLS_OPTIONS_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_OPTIONS_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_OPTIONS_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_OPTIONS_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webconsole: {
|
||||
histogram: "DEVTOOLS_WEBCONSOLE_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_WEBCONSOLE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBCONSOLE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_WEBCONSOLE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
browserconsole: {
|
||||
histogram: "DEVTOOLS_BROWSERCONSOLE_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_BROWSERCONSOLE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_BROWSERCONSOLE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_BROWSERCONSOLE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
inspector: {
|
||||
histogram: "DEVTOOLS_INSPECTOR_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_INSPECTOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
ruleview: {
|
||||
histogram: "DEVTOOLS_RULEVIEW_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_RULEVIEW_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
computedview: {
|
||||
histogram: "DEVTOOLS_COMPUTEDVIEW_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_COMPUTEDVIEW_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_COMPUTEDVIEW_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
layoutview: {
|
||||
histogram: "DEVTOOLS_LAYOUTVIEW_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_LAYOUTVIEW_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_LAYOUTVIEW_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
fontinspector: {
|
||||
histogram: "DEVTOOLS_FONTINSPECTOR_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_FONTINSPECTOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
animationinspector: {
|
||||
histogram: "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_ANIMATIONINSPECTOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
jsdebugger: {
|
||||
histogram: "DEVTOOLS_JSDEBUGGER_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_JSDEBUGGER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_JSDEBUGGER_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_JSDEBUGGER_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
jsbrowserdebugger: {
|
||||
histogram: "DEVTOOLS_JSBROWSERDEBUGGER_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_JSBROWSERDEBUGGER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_JSBROWSERDEBUGGER_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_JSBROWSERDEBUGGER_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
styleeditor: {
|
||||
histogram: "DEVTOOLS_STYLEEDITOR_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_STYLEEDITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_STYLEEDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_STYLEEDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
shadereditor: {
|
||||
histogram: "DEVTOOLS_SHADEREDITOR_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_SHADEREDITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_SHADEREDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_SHADEREDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webaudioeditor: {
|
||||
histogram: "DEVTOOLS_WEBAUDIOEDITOR_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_WEBAUDIOEDITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBAUDIOEDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_WEBAUDIOEDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
canvasdebugger: {
|
||||
histogram: "DEVTOOLS_CANVASDEBUGGER_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_CANVASDEBUGGER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_CANVASDEBUGGER_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_CANVASDEBUGGER_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
performance: {
|
||||
histogram: "DEVTOOLS_JSPROFILER_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_JSPROFILER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_JSPROFILER_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_JSPROFILER_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
memory: {
|
||||
histogram: "DEVTOOLS_MEMORY_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_MEMORY_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_MEMORY_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_MEMORY_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
netmonitor: {
|
||||
histogram: "DEVTOOLS_NETMONITOR_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_NETMONITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_NETMONITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_NETMONITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
storage: {
|
||||
histogram: "DEVTOOLS_STORAGE_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_STORAGE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
tilt: {
|
||||
histogram: "DEVTOOLS_TILT_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_TILT_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_TILT_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_TILT_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
paintflashing: {
|
||||
histogram: "DEVTOOLS_PAINTFLASHING_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_PAINTFLASHING_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_PAINTFLASHING_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_PAINTFLASHING_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
scratchpad: {
|
||||
histogram: "DEVTOOLS_SCRATCHPAD_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_SCRATCHPAD_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_SCRATCHPAD_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_SCRATCHPAD_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
"scratchpad-window": {
|
||||
histogram: "DEVTOOLS_SCRATCHPAD_WINDOW_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_SCRATCHPAD_WINDOW_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_SCRATCHPAD_WINDOW_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_SCRATCHPAD_WINDOW_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
responsive: {
|
||||
histogram: "DEVTOOLS_RESPONSIVE_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_RESPONSIVE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_RESPONSIVE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_RESPONSIVE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
eyedropper: {
|
||||
histogram: "DEVTOOLS_EYEDROPPER_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_EYEDROPPER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||
},
|
||||
menueyedropper: {
|
||||
histogram: "DEVTOOLS_MENU_EYEDROPPER_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_MENU_EYEDROPPER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_MENU_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||
},
|
||||
pickereyedropper: {
|
||||
histogram: "DEVTOOLS_PICKER_EYEDROPPER_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_PICKER_EYEDROPPER_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||
},
|
||||
developertoolbar: {
|
||||
histogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_DEVELOPERTOOLBAR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
aboutdebugging: {
|
||||
histogram: "DEVTOOLS_ABOUTDEBUGGING_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_ABOUTDEBUGGING_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_ABOUTDEBUGGING_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_ABOUTDEBUGGING_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webide: {
|
||||
histogram: "DEVTOOLS_WEBIDE_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_WEBIDE_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_WEBIDE_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webideProjectEditor: {
|
||||
histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
webideProjectEditorSave: {
|
||||
histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_BOOLEAN",
|
||||
histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_PER_USER_FLAG",
|
||||
},
|
||||
webideNewProject: {
|
||||
histogram: "DEVTOOLS_WEBIDE_NEW_PROJECT_BOOLEAN",
|
||||
histogram: "DEVTOOLS_WEBIDE_NEW_PROJECT_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_NEW_PROJECT_PER_USER_FLAG",
|
||||
},
|
||||
webideImportProject: {
|
||||
histogram: "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN",
|
||||
histogram: "DEVTOOLS_WEBIDE_IMPORT_PROJECT_COUNT",
|
||||
userHistogram: "DEVTOOLS_WEBIDE_IMPORT_PROJECT_PER_USER_FLAG",
|
||||
},
|
||||
custom: {
|
||||
histogram: "DEVTOOLS_CUSTOM_OPENED_BOOLEAN",
|
||||
histogram: "DEVTOOLS_CUSTOM_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS"
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ function checkResults(histIdFocus, Telemetry) {
|
|||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
is(value.length, 1, histId + " has one entry");
|
||||
|
||||
let okay = value.every(element => element === true);
|
||||
|
|
|
@ -71,7 +71,7 @@ function checkResults(histIdFocus, Telemetry) {
|
|||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
|
|
|
@ -74,7 +74,7 @@ function checkResults(histIdFocus, Telemetry) {
|
|||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
|
|
|
@ -106,7 +106,7 @@ function checkResults(histIdFocus, Telemetry) {
|
|||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
|
|
|
@ -89,7 +89,7 @@ function checkResults(histIdFocus, Telemetry) {
|
|||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
|
|
|
@ -62,9 +62,9 @@ function checkResults(Telemetry) {
|
|||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId === "DEVTOOLS_TOOLBOX_OPENED_BOOLEAN") {
|
||||
} else if (histId === "DEVTOOLS_TOOLBOX_OPENED_COUNT") {
|
||||
is(value.length, 1, histId + " has only one entry");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
|
|
|
@ -168,7 +168,7 @@ function checkTelemetryResults(Telemetry) {
|
|||
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||
ok(value.length === 1 && value[0] === true,
|
||||
"Per user value " + histId + " has a single value of true");
|
||||
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||
} else if (histId.endsWith("OPENED_COUNT")) {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
|
|
|
@ -172,10 +172,10 @@
|
|||
ok(value.length === 1 && !!value[0],
|
||||
histId + " has 1 successful entry");
|
||||
} else if (histId ===
|
||||
"DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_BOOLEAN") {
|
||||
"DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_COUNT") {
|
||||
ok(value.length === 1 && !!value[0],
|
||||
histId + " has 1 successful entry");
|
||||
} else if (histId === "DEVTOOLS_WEBIDE_OPENED_BOOLEAN") {
|
||||
} else if (histId === "DEVTOOLS_WEBIDE_OPENED_COUNT") {
|
||||
ok(value.length > 1, histId + " has more than one entry");
|
||||
|
||||
let okay = value.every(function(element) {
|
||||
|
|
|
@ -12826,6 +12826,46 @@ class CGRegisterWorkerBindings(CGAbstractMethod):
|
|||
lines.append(CGGeneric("return true;\n"))
|
||||
return CGList(lines, "\n").define()
|
||||
|
||||
class CGRegisterWorkerDebuggerBindings(CGAbstractMethod):
|
||||
def __init__(self, config):
|
||||
CGAbstractMethod.__init__(self, None, 'RegisterWorkerDebuggerBindings', 'bool',
|
||||
[Argument('JSContext*', 'aCx'),
|
||||
Argument('JS::Handle<JSObject*>', 'aObj')])
|
||||
self.config = config
|
||||
|
||||
def definition_body(self):
|
||||
# We have to be a bit careful: Some of the interfaces we want to expose
|
||||
# in workers only have one descriptor, while others have both a worker
|
||||
# and a non-worker descriptor. When both are present we want the worker
|
||||
# descriptor, but otherwise we want whatever descriptor we've got.
|
||||
descriptors = self.config.getDescriptors(hasInterfaceObject=True,
|
||||
isExposedInWorkerDebugger=True,
|
||||
register=True,
|
||||
skipGen=False,
|
||||
workers=True)
|
||||
workerDescriptorIfaceNames = set(d.interface.identifier.name for
|
||||
d in descriptors)
|
||||
descriptors.extend(
|
||||
filter(
|
||||
lambda d: d.interface.identifier.name not in workerDescriptorIfaceNames,
|
||||
self.config.getDescriptors(hasInterfaceObject=True,
|
||||
isExposedInWorkerDebugger=True,
|
||||
register=True,
|
||||
skipGen=False,
|
||||
workers=False)))
|
||||
conditions = []
|
||||
for desc in descriptors:
|
||||
bindingNS = toBindingNamespace(desc.name)
|
||||
condition = "!%s::GetConstructorObject(aCx, aObj)" % bindingNS
|
||||
if desc.isExposedConditionally():
|
||||
condition = (
|
||||
"%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
|
||||
+ condition)
|
||||
conditions.append(condition)
|
||||
lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
|
||||
condition in conditions]
|
||||
lines.append(CGGeneric("return true;\n"))
|
||||
return CGList(lines, "\n").define()
|
||||
|
||||
class CGResolveSystemBinding(CGAbstractMethod):
|
||||
def __init__(self, config):
|
||||
|
@ -16081,6 +16121,32 @@ class GlobalGenRoots():
|
|||
# Done.
|
||||
return curr
|
||||
|
||||
@staticmethod
|
||||
def RegisterWorkerDebuggerBindings(config):
|
||||
|
||||
curr = CGRegisterWorkerDebuggerBindings(config)
|
||||
|
||||
# Wrap all of that in our namespaces.
|
||||
curr = CGNamespace.build(['mozilla', 'dom'],
|
||||
CGWrapper(curr, post='\n'))
|
||||
curr = CGWrapper(curr, post='\n')
|
||||
|
||||
# Add the includes
|
||||
defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
|
||||
for desc in config.getDescriptors(hasInterfaceObject=True,
|
||||
register=True,
|
||||
isExposedInWorkerDebugger=True,
|
||||
skipGen=False)]
|
||||
|
||||
curr = CGHeaders([], [], [], [], [], defineIncludes,
|
||||
'RegisterWorkerDebuggerBindings', curr)
|
||||
|
||||
# Add include guards.
|
||||
curr = CGIncludeGuard('RegisterWorkerDebuggerBindings', curr)
|
||||
|
||||
# Done.
|
||||
return curr
|
||||
|
||||
@staticmethod
|
||||
def ResolveSystemBinding(config):
|
||||
|
||||
|
|
|
@ -228,6 +228,8 @@ class Configuration:
|
|||
getter = lambda x: x.interface.getNavigatorProperty() is not None
|
||||
elif key == 'isExposedInAnyWorker':
|
||||
getter = lambda x: x.interface.isExposedInAnyWorker()
|
||||
elif key == 'isExposedInWorkerDebugger':
|
||||
getter = lambda x: x.interface.isExposedInWorkerDebugger()
|
||||
elif key == 'isExposedInSystemGlobals':
|
||||
getter = lambda x: x.interface.isExposedInSystemGlobals()
|
||||
elif key == 'isExposedInWindow':
|
||||
|
|
|
@ -133,6 +133,7 @@ class WebIDLCodegenManager(LoggingMixin):
|
|||
'PrototypeList.h',
|
||||
'RegisterBindings.h',
|
||||
'RegisterWorkerBindings.h',
|
||||
'RegisterWorkerDebuggerBindings.h',
|
||||
'ResolveSystemBinding.h',
|
||||
'UnionConversions.h',
|
||||
'UnionTypes.h',
|
||||
|
@ -142,6 +143,7 @@ class WebIDLCodegenManager(LoggingMixin):
|
|||
GLOBAL_DEFINE_FILES = {
|
||||
'RegisterBindings.cpp',
|
||||
'RegisterWorkerBindings.cpp',
|
||||
'RegisterWorkerDebuggerBindings.cpp',
|
||||
'ResolveSystemBinding.cpp',
|
||||
'UnionTypes.cpp',
|
||||
'PrototypeList.cpp',
|
||||
|
|
|
@ -508,6 +508,9 @@ class IDLExposureMixins():
|
|||
def isExposedInAnyWorker(self):
|
||||
return len(self.getWorkerExposureSet()) > 0
|
||||
|
||||
def isExposedInWorkerDebugger(self):
|
||||
return len(self.getWorkerDebuggerExposureSet()) > 0
|
||||
|
||||
def isExposedInSystemGlobals(self):
|
||||
return 'BackstagePass' in self.exposureSet
|
||||
|
||||
|
@ -527,6 +530,10 @@ class IDLExposureMixins():
|
|||
workerScopes = self._globalScope.globalNameMapping["Worker"]
|
||||
return workerScopes.intersection(self.exposureSet)
|
||||
|
||||
def getWorkerDebuggerExposureSet(self):
|
||||
workerDebuggerScopes = self._globalScope.globalNameMapping["WorkerDebugger"]
|
||||
return workerDebuggerScopes.intersection(self.exposureSet)
|
||||
|
||||
|
||||
class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
|
||||
def __init__(self, location, parentScope, identifier):
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// [Constructor(DOMString url, optional (URL or DOMString) base = "about:blank")]
|
||||
[Constructor(DOMString url, URL base),
|
||||
Constructor(DOMString url, optional DOMString base),
|
||||
Exposed=(Window,Worker)]
|
||||
Exposed=(Window,Worker,WorkerDebugger)]
|
||||
interface URL {
|
||||
// Bug 824857: no support for stringifier attributes yet.
|
||||
// stringifier attribute USVString href;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
[Constructor(optional USVString init = ""),
|
||||
Constructor(URLSearchParams init),
|
||||
Exposed=(Window,Worker,System)]
|
||||
Exposed=(Window,Worker,WorkerDebugger,System)]
|
||||
interface URLSearchParams {
|
||||
void append(USVString name, USVString value);
|
||||
void delete(USVString name);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/dom/RegisterWorkerBindings.h"
|
||||
#include "mozilla/dom/RegisterWorkerDebuggerBindings.h"
|
||||
#include "mozilla/OSFileConstants.h"
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
@ -36,3 +37,19 @@ WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerPrivate::RegisterDebuggerBindings(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGlobal)
|
||||
{
|
||||
// Init Web IDL bindings
|
||||
if (!RegisterWorkerDebuggerBindings(aCx, aGlobal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS_DefineDebuggerObject(aCx, aGlobal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -6440,14 +6440,18 @@ WorkerPrivate::CreateDebuggerGlobalScope(JSContext* aCx)
|
|||
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
|
||||
if (!JS_DefineDebuggerObject(aCx, global)) {
|
||||
// RegisterDebuggerBindings() can spin a nested event loop so we have to set
|
||||
// mDebuggerScope before calling it, and we have to make sure to unset
|
||||
// mDebuggerScope if it fails.
|
||||
mDebuggerScope = Move(globalScope);
|
||||
|
||||
if (!RegisterDebuggerBindings(aCx, global)) {
|
||||
mDebuggerScope = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS_FireOnNewGlobalObject(aCx, global);
|
||||
|
||||
mDebuggerScope = globalScope.forget();
|
||||
|
||||
return mDebuggerScope;
|
||||
}
|
||||
|
||||
|
|