mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
01caadd25e
@ -1,6 +1,5 @@
|
||||
function test() {
|
||||
var tab = gBrowser.addTab(null, {skipAnimation: true});
|
||||
gBrowser.selectedTab = tab;
|
||||
add_task(function* test() {
|
||||
var tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
|
||||
|
||||
var gotTabAttrModified = false;
|
||||
var gotTabClose = false;
|
||||
@ -16,11 +15,11 @@ function test() {
|
||||
|
||||
tab.addEventListener("TabClose", onTabClose, false);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
|
||||
ok(gotTabClose, "should have got the TabClose event");
|
||||
ok(!gotTabAttrModified, "shouldn't have got the TabAttrModified event after TabClose");
|
||||
|
||||
tab.removeEventListener("TabClose", onTabClose, false);
|
||||
tab.removeEventListener("TabAttrModified", onTabAttrModified, false);
|
||||
}
|
||||
});
|
||||
|
@ -7,6 +7,7 @@
|
||||
"EventEmitter": true,
|
||||
"IconDetails": true,
|
||||
"makeWidgetId": true,
|
||||
"pageActionFor": true,
|
||||
"PanelPopup": true,
|
||||
"TabContext": true,
|
||||
"ViewPopup": true,
|
||||
|
@ -17,10 +17,6 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
// WeakMap[Extension -> BrowserAction]
|
||||
var browserActionMap = new WeakMap();
|
||||
|
||||
function browserActionOf(extension) {
|
||||
return browserActionMap.get(extension);
|
||||
}
|
||||
|
||||
// Responsible for the browser_action section of the manifest as well
|
||||
// as the associated popup.
|
||||
function BrowserAction(options, extension) {
|
||||
@ -203,6 +199,12 @@ BrowserAction.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
BrowserAction.for = (extension) => {
|
||||
return browserActionMap.get(extension);
|
||||
};
|
||||
|
||||
global.browserActionFor = BrowserAction.for;
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
extensions.on("manifest_browser_action", (type, directive, extension, manifest) => {
|
||||
let browserAction = new BrowserAction(manifest.browser_action, extension);
|
||||
@ -226,20 +228,20 @@ extensions.registerSchemaAPI("browserAction", null, (extension, context) => {
|
||||
let tab = TabManager.activeTab;
|
||||
fire(TabManager.convert(extension, tab));
|
||||
};
|
||||
browserActionOf(extension).on("click", listener);
|
||||
BrowserAction.for(extension).on("click", listener);
|
||||
return () => {
|
||||
browserActionOf(extension).off("click", listener);
|
||||
BrowserAction.for(extension).off("click", listener);
|
||||
};
|
||||
}).api(),
|
||||
|
||||
enable: function(tabId) {
|
||||
let tab = tabId !== null ? TabManager.getTab(tabId) : null;
|
||||
browserActionOf(extension).setProperty(tab, "enabled", true);
|
||||
BrowserAction.for(extension).setProperty(tab, "enabled", true);
|
||||
},
|
||||
|
||||
disable: function(tabId) {
|
||||
let tab = tabId !== null ? TabManager.getTab(tabId) : null;
|
||||
browserActionOf(extension).setProperty(tab, "enabled", false);
|
||||
BrowserAction.for(extension).setProperty(tab, "enabled", false);
|
||||
},
|
||||
|
||||
setTitle: function(details) {
|
||||
@ -250,30 +252,30 @@ extensions.registerSchemaAPI("browserAction", null, (extension, context) => {
|
||||
if (tab && title == "") {
|
||||
title = null;
|
||||
}
|
||||
browserActionOf(extension).setProperty(tab, "title", title);
|
||||
BrowserAction.for(extension).setProperty(tab, "title", title);
|
||||
},
|
||||
|
||||
getTitle: function(details) {
|
||||
let tab = details.tabId !== null ? TabManager.getTab(details.tabId) : null;
|
||||
let title = browserActionOf(extension).getProperty(tab, "title");
|
||||
let title = BrowserAction.for(extension).getProperty(tab, "title");
|
||||
return Promise.resolve(title);
|
||||
},
|
||||
|
||||
setIcon: function(details) {
|
||||
let tab = details.tabId !== null ? TabManager.getTab(details.tabId) : null;
|
||||
let icon = IconDetails.normalize(details, extension, context);
|
||||
browserActionOf(extension).setProperty(tab, "icon", icon);
|
||||
BrowserAction.for(extension).setProperty(tab, "icon", icon);
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
setBadgeText: function(details) {
|
||||
let tab = details.tabId !== null ? TabManager.getTab(details.tabId) : null;
|
||||
browserActionOf(extension).setProperty(tab, "badgeText", details.text);
|
||||
BrowserAction.for(extension).setProperty(tab, "badgeText", details.text);
|
||||
},
|
||||
|
||||
getBadgeText: function(details) {
|
||||
let tab = details.tabId !== null ? TabManager.getTab(details.tabId) : null;
|
||||
let text = browserActionOf(extension).getProperty(tab, "badgeText");
|
||||
let text = BrowserAction.for(extension).getProperty(tab, "badgeText");
|
||||
return Promise.resolve(text);
|
||||
},
|
||||
|
||||
@ -285,23 +287,23 @@ extensions.registerSchemaAPI("browserAction", null, (extension, context) => {
|
||||
// For internal consistency, we currently resolve both relative to the
|
||||
// calling context.
|
||||
let url = details.popup && context.uri.resolve(details.popup);
|
||||
browserActionOf(extension).setProperty(tab, "popup", url);
|
||||
BrowserAction.for(extension).setProperty(tab, "popup", url);
|
||||
},
|
||||
|
||||
getPopup: function(details) {
|
||||
let tab = details.tabId !== null ? TabManager.getTab(details.tabId) : null;
|
||||
let popup = browserActionOf(extension).getProperty(tab, "popup");
|
||||
let popup = BrowserAction.for(extension).getProperty(tab, "popup");
|
||||
return Promise.resolve(popup);
|
||||
},
|
||||
|
||||
setBadgeBackgroundColor: function(details) {
|
||||
let tab = details.tabId !== null ? TabManager.getTab(details.tabId) : null;
|
||||
browserActionOf(extension).setProperty(tab, "badgeBackgroundColor", details.color);
|
||||
BrowserAction.for(extension).setProperty(tab, "badgeBackgroundColor", details.color);
|
||||
},
|
||||
|
||||
getBadgeBackgroundColor: function(details, callback) {
|
||||
let tab = details.tabId !== null ? TabManager.getTab(details.tabId) : null;
|
||||
let color = browserActionOf(extension).getProperty(tab, "badgeBackgroundColor");
|
||||
let color = BrowserAction.for(extension).getProperty(tab, "badgeBackgroundColor");
|
||||
return Promise.resolve(color);
|
||||
},
|
||||
},
|
||||
|
@ -15,10 +15,17 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
// WeakMap[Extension -> CommandList]
|
||||
var commandsMap = new WeakMap();
|
||||
|
||||
function CommandList(commandsObj, extensionID) {
|
||||
this.commands = this.loadCommandsFromManifest(commandsObj);
|
||||
this.keysetID = `ext-keyset-id-${makeWidgetId(extensionID)}`;
|
||||
function CommandList(manifest, extension) {
|
||||
this.extension = extension;
|
||||
this.id = makeWidgetId(extension.id);
|
||||
this.windowOpenListener = null;
|
||||
|
||||
// Map[{String} commandName -> {Object} commandProperties]
|
||||
this.commands = this.loadCommandsFromManifest(manifest);
|
||||
|
||||
// WeakMap[Window -> <xul:keyset>]
|
||||
this.keysetsMap = new WeakMap();
|
||||
|
||||
this.register();
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
@ -30,11 +37,13 @@ CommandList.prototype = {
|
||||
*/
|
||||
register() {
|
||||
for (let window of WindowListManager.browserWindows()) {
|
||||
this.registerKeysToDocument(window.document);
|
||||
this.registerKeysToDocument(window);
|
||||
}
|
||||
|
||||
this.windowOpenListener = (window) => {
|
||||
this.registerKeysToDocument(window.document);
|
||||
if (!this.keysetsMap.has(window)) {
|
||||
this.registerKeysToDocument(window);
|
||||
}
|
||||
};
|
||||
|
||||
WindowListManager.addOpenListener(this.windowOpenListener);
|
||||
@ -46,9 +55,8 @@ CommandList.prototype = {
|
||||
*/
|
||||
unregister() {
|
||||
for (let window of WindowListManager.browserWindows()) {
|
||||
let keyset = window.document.getElementById(this.keysetID);
|
||||
if (keyset) {
|
||||
keyset.remove();
|
||||
if (this.keysetsMap.has(window)) {
|
||||
this.keysetsMap.get(window).remove();
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,15 +65,15 @@ CommandList.prototype = {
|
||||
|
||||
/**
|
||||
* Creates a Map from commands for each command in the manifest.commands object.
|
||||
* @param {Object} commandsObj The manifest.commands JSON object.
|
||||
* @param {Object} manifest The manifest JSON object.
|
||||
*/
|
||||
loadCommandsFromManifest(commandsObj) {
|
||||
loadCommandsFromManifest(manifest) {
|
||||
let commands = new Map();
|
||||
// For Windows, chrome.runtime expects 'win' while chrome.commands
|
||||
// expects 'windows'. We can special case this for now.
|
||||
let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os;
|
||||
for (let name of Object.keys(commandsObj)) {
|
||||
let command = commandsObj[name];
|
||||
for (let name of Object.keys(manifest.commands)) {
|
||||
let command = manifest.commands[name];
|
||||
commands.set(name, {
|
||||
description: command.description,
|
||||
shortcut: command.suggested_key[os] || command.suggested_key.default,
|
||||
@ -76,16 +84,18 @@ CommandList.prototype = {
|
||||
|
||||
/**
|
||||
* Registers the commands to a document.
|
||||
* @param {Document} doc The XUL document to insert the Keyset.
|
||||
* @param {ChromeWindow} window The XUL window to insert the Keyset.
|
||||
*/
|
||||
registerKeysToDocument(doc) {
|
||||
registerKeysToDocument(window) {
|
||||
let doc = window.document;
|
||||
let keyset = doc.createElementNS(XUL_NS, "keyset");
|
||||
keyset.id = this.keysetID;
|
||||
keyset.id = `ext-keyset-id-${this.id}`;
|
||||
this.commands.forEach((command, name) => {
|
||||
let keyElement = this.buildKey(doc, name, command.shortcut);
|
||||
keyset.appendChild(keyElement);
|
||||
});
|
||||
doc.documentElement.appendChild(keyset);
|
||||
this.keysetsMap.set(window, keyset);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -110,7 +120,12 @@ CommandList.prototype = {
|
||||
// We remove all references to the key elements when the extension is shutdown,
|
||||
// therefore the listeners for these elements will be garbage collected.
|
||||
keyElement.addEventListener("command", (event) => {
|
||||
this.emit("command", name);
|
||||
if (name == "_execute_page_action") {
|
||||
let win = event.target.ownerDocument.defaultView;
|
||||
pageActionFor(this.extension).triggerAction(win);
|
||||
} else {
|
||||
this.emit("command", name);
|
||||
}
|
||||
});
|
||||
/* eslint-enable mozilla/balanced-listeners */
|
||||
|
||||
@ -195,7 +210,7 @@ CommandList.prototype = {
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
extensions.on("manifest_commands", (type, directive, extension, manifest) => {
|
||||
commandsMap.set(extension, new CommandList(manifest.commands, extension.id));
|
||||
commandsMap.set(extension, new CommandList(manifest, extension));
|
||||
});
|
||||
|
||||
extensions.on("shutdown", (type, extension) => {
|
||||
|
@ -2,6 +2,7 @@
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
var {
|
||||
EventManager,
|
||||
@ -10,7 +11,6 @@ var {
|
||||
// WeakMap[Extension -> PageAction]
|
||||
var pageActionMap = new WeakMap();
|
||||
|
||||
|
||||
// Handles URL bar icons, including the |page_action| manifest entry
|
||||
// and associated API.
|
||||
function PageAction(options, extension) {
|
||||
@ -123,6 +123,19 @@ PageAction.prototype = {
|
||||
return this.buttons.get(window);
|
||||
},
|
||||
|
||||
/**
|
||||
* Triggers this page action for the given window, with the same effects as
|
||||
* if it were clicked by a user.
|
||||
*
|
||||
* This has no effect if the page action is hidden for the selected tab.
|
||||
*/
|
||||
triggerAction(window) {
|
||||
let pageAction = pageActionMap.get(this.extension);
|
||||
if (pageAction.getProperty(window.gBrowser.selectedTab, "show")) {
|
||||
pageAction.handleClick(window);
|
||||
}
|
||||
},
|
||||
|
||||
// Handles a click event on the page action button for the given
|
||||
// window.
|
||||
// If the page action has a |popup| property, a panel is opened to
|
||||
@ -163,11 +176,6 @@ PageAction.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
PageAction.for = extension => {
|
||||
return pageActionMap.get(extension);
|
||||
};
|
||||
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
extensions.on("manifest_page_action", (type, directive, extension, manifest) => {
|
||||
let pageAction = new PageAction(manifest.page_action, extension);
|
||||
@ -182,6 +190,11 @@ extensions.on("shutdown", (type, extension) => {
|
||||
});
|
||||
/* eslint-enable mozilla/balanced-listeners */
|
||||
|
||||
PageAction.for = extension => {
|
||||
return pageActionMap.get(extension);
|
||||
};
|
||||
|
||||
global.pageActionFor = PageAction.for;
|
||||
|
||||
extensions.registerSchemaAPI("pageAction", null, (extension, context) => {
|
||||
return {
|
||||
|
@ -24,6 +24,7 @@ support-files =
|
||||
[browser_ext_browserAction_popup.js]
|
||||
[browser_ext_popup_api_injection.js]
|
||||
[browser_ext_contextMenus.js]
|
||||
[browser_ext_commands_execute_page_action.js]
|
||||
[browser_ext_commands_getAll.js]
|
||||
[browser_ext_commands_onCommand.js]
|
||||
[browser_ext_getViews.js]
|
||||
|
@ -0,0 +1,133 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_execute_page_action_without_popup() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"commands": {
|
||||
"_execute_page_action": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+J",
|
||||
},
|
||||
},
|
||||
"send-keys-command": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+3",
|
||||
},
|
||||
},
|
||||
},
|
||||
"page_action": {},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
let isShown = false;
|
||||
|
||||
browser.commands.onCommand.addListener((commandName) => {
|
||||
if (commandName == "_execute_page_action") {
|
||||
browser.test.fail(`The onCommand listener should never fire for ${commandName}.`);
|
||||
} else if (commandName == "send-keys-command") {
|
||||
if (!isShown) {
|
||||
isShown = true;
|
||||
browser.tabs.query({currentWindow: true, active: true}, tabs => {
|
||||
tabs.forEach(tab => {
|
||||
browser.pageAction.show(tab.id);
|
||||
});
|
||||
browser.test.sendMessage("send-keys");
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
browser.pageAction.onClicked.addListener(() => {
|
||||
browser.test.assertTrue(isShown, "The onClicked event should fire if the page action is shown.");
|
||||
browser.test.notifyPass("page-action-without-popup");
|
||||
});
|
||||
|
||||
browser.test.sendMessage("send-keys");
|
||||
},
|
||||
});
|
||||
|
||||
extension.onMessage("send-keys", () => {
|
||||
EventUtils.synthesizeKey("j", {altKey: true, shiftKey: true});
|
||||
EventUtils.synthesizeKey("3", {altKey: true, shiftKey: true});
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("page-action-without-popup");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_execute_page_action_with_popup() {
|
||||
let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>Test Popup</body></html>`;
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"commands": {
|
||||
"_execute_page_action": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+J",
|
||||
},
|
||||
},
|
||||
"send-keys-command": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+3",
|
||||
},
|
||||
},
|
||||
},
|
||||
"page_action": {
|
||||
"default_popup": "popup.html",
|
||||
},
|
||||
},
|
||||
|
||||
files: {
|
||||
"popup.html": scriptPage("popup.js"),
|
||||
"popup.js": function() {
|
||||
browser.runtime.sendMessage("popup-opened");
|
||||
},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
let isShown = false;
|
||||
|
||||
browser.commands.onCommand.addListener((message) => {
|
||||
if (message == "_execute_page_action") {
|
||||
browser.test.fail(`The onCommand listener should never fire for ${message}.`);
|
||||
}
|
||||
|
||||
if (message == "send-keys-command") {
|
||||
if (!isShown) {
|
||||
isShown = true;
|
||||
browser.tabs.query({currentWindow: true, active: true}, tabs => {
|
||||
tabs.forEach(tab => {
|
||||
browser.pageAction.show(tab.id);
|
||||
});
|
||||
browser.test.sendMessage("send-keys");
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
browser.pageAction.onClicked.addListener(() => {
|
||||
browser.test.fail(`The onClicked listener should never fire when the pageAction has a popup.`);
|
||||
});
|
||||
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
browser.test.assertEq(msg, "popup-opened", "expected popup opened");
|
||||
browser.test.assertTrue(isShown, "The onClicked event should fire if the page action is shown.");
|
||||
browser.test.notifyPass("page-action-with-popup");
|
||||
});
|
||||
|
||||
browser.test.sendMessage("send-keys");
|
||||
},
|
||||
});
|
||||
|
||||
extension.onMessage("send-keys", () => {
|
||||
EventUtils.synthesizeKey("j", {altKey: true, shiftKey: true});
|
||||
EventUtils.synthesizeKey("3", {altKey: true, shiftKey: true});
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("page-action-with-popup");
|
||||
yield extension.unload();
|
||||
});
|
@ -2,7 +2,7 @@
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
add_task(function* test_user_defined_commands() {
|
||||
// Create a window before the extension is loaded.
|
||||
let win1 = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
yield BrowserTestUtils.loadURI(win1.gBrowser.selectedBrowser, "about:robots");
|
||||
@ -10,7 +10,6 @@ add_task(function* () {
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"name": "Commands Extension",
|
||||
"commands": {
|
||||
"toggle-feature-using-alt-shift-3": {
|
||||
"suggested_key": {
|
||||
@ -27,8 +26,8 @@ add_task(function* () {
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.commands.onCommand.addListener((message) => {
|
||||
browser.test.sendMessage("oncommand", message);
|
||||
browser.commands.onCommand.addListener((commandName) => {
|
||||
browser.test.sendMessage("oncommand", commandName);
|
||||
});
|
||||
browser.test.sendMessage("ready");
|
||||
},
|
||||
@ -53,10 +52,12 @@ add_task(function* () {
|
||||
// Confirm the keysets have been added to both windows.
|
||||
let keysetID = `ext-keyset-id-${makeWidgetId(extension.id)}`;
|
||||
let keyset = win1.document.getElementById(keysetID);
|
||||
is(keyset.childNodes.length, 2, "Expected keyset to exist and have 2 children");
|
||||
ok(keyset != null, "Expected keyset to exist");
|
||||
is(keyset.childNodes.length, 2, "Expected keyset to have 2 children");
|
||||
|
||||
keyset = win2.document.getElementById(keysetID);
|
||||
is(keyset.childNodes.length, 2, "Expected keyset to exist and have 2 children");
|
||||
ok(keyset != null, "Expected keyset to exist");
|
||||
is(keyset.childNodes.length, 2, "Expected keyset to have 2 children");
|
||||
|
||||
// Confirm that the commands are registered to both windows.
|
||||
yield focusWindow(win1);
|
||||
@ -84,3 +85,5 @@ add_task(function* () {
|
||||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
});
|
||||
|
||||
|
||||
|
@ -116,8 +116,7 @@ function _removeOrDisableBreakpoint(location, isDisabled) {
|
||||
return dispatch(Object.assign({}, action, {
|
||||
[PROMISE]: bpClient.remove()
|
||||
}));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return dispatch(Object.assign({}, action, { status: "done" }));
|
||||
}
|
||||
}
|
||||
@ -154,21 +153,30 @@ function setBreakpointCondition(location, condition) {
|
||||
}
|
||||
|
||||
const bpClient = getBreakpointClient(bp.actor);
|
||||
|
||||
return dispatch({
|
||||
const action = {
|
||||
type: constants.SET_BREAKPOINT_CONDITION,
|
||||
breakpoint: bp,
|
||||
condition: condition,
|
||||
[PROMISE]: Task.spawn(function*() {
|
||||
const newClient = yield bpClient.setCondition(gThreadClient, condition);
|
||||
condition: condition
|
||||
};
|
||||
|
||||
// Remove the old instance and save the new one
|
||||
setBreakpointClient(bpClient.actor, null);
|
||||
setBreakpointClient(newClient.actor, newClient);
|
||||
// If it's not disabled, we need to update the condition on the
|
||||
// server. Otherwise, just dispatch a non-remote action that
|
||||
// updates the condition locally.
|
||||
if(!bp.disabled) {
|
||||
return dispatch(Object.assign({}, action, {
|
||||
[PROMISE]: Task.spawn(function*() {
|
||||
const newClient = yield bpClient.setCondition(gThreadClient, condition);
|
||||
|
||||
return { actor: newClient.actor };
|
||||
})
|
||||
});
|
||||
// Remove the old instance and save the new one
|
||||
setBreakpointClient(bpClient.actor, null);
|
||||
setBreakpointClient(newClient.actor, newClient);
|
||||
|
||||
return { actor: newClient.actor };
|
||||
})
|
||||
}));
|
||||
} else {
|
||||
return dispatch(action);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,14 @@ function update(state = initialState, action, emitChange) {
|
||||
const bp = state.breakpoints[id];
|
||||
emitChange("breakpoint-condition-updated", bp);
|
||||
|
||||
if (action.status === 'start') {
|
||||
if (!action.status) {
|
||||
// No status means that it wasn't a remote request. Just update
|
||||
// the condition locally.
|
||||
return mergeIn(state, ['breakpoints', id], {
|
||||
condition: action.condition
|
||||
});
|
||||
}
|
||||
else if (action.status === 'start') {
|
||||
return mergeIn(state, ['breakpoints', id], {
|
||||
loading: true,
|
||||
condition: action.condition
|
||||
@ -126,6 +133,7 @@ function update(state = initialState, action, emitChange) {
|
||||
else if (action.status === 'done') {
|
||||
return mergeIn(state, ['breakpoints', id], {
|
||||
loading: false,
|
||||
condition: action.condition,
|
||||
// Setting a condition creates a new breakpoint client as of
|
||||
// now, so we need to update the actor
|
||||
actor: action.value.actor
|
||||
|
@ -67,8 +67,15 @@ function update(state = initialState, action, emitChange) {
|
||||
loading: false
|
||||
});
|
||||
|
||||
// If it errored, just display the source as it way before.
|
||||
emitChange('prettyprinted', s.sources[action.source.actor]);
|
||||
// If it errored, just display the source as it was before, but
|
||||
// only if there is existing text already. If auto-prettifying
|
||||
// is on, the original text may still be coming in and we don't
|
||||
// have it yet. If we try to set empty text we confuse the
|
||||
// editor because it thinks it's already displaying the source's
|
||||
// text and won't load the text when it actually comes in.
|
||||
if(s.sourcesText[action.source.actor].text != null) {
|
||||
emitChange('prettyprinted', s.sources[action.source.actor]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
s = _updateText(state, action);
|
||||
|
@ -82,6 +82,7 @@ var DebuggerView = {
|
||||
this._initializeVariablesView();
|
||||
|
||||
this._editorSource = {};
|
||||
this._editorDocuments = {};
|
||||
|
||||
document.title = L10N.getStr("DebuggerWindowTitle");
|
||||
|
||||
@ -374,14 +375,15 @@ var DebuggerView = {
|
||||
|
||||
if (source && source.actor === location.actor) {
|
||||
this.editor.removeBreakpoint(location.line - 1);
|
||||
this.editor.removeBreakpointCondition(location.line - 1);
|
||||
}
|
||||
},
|
||||
|
||||
renderEditorBreakpointCondition: function (breakpoint) {
|
||||
const { location, condition } = breakpoint;
|
||||
const { location, condition, disabled } = breakpoint;
|
||||
const source = queries.getSelectedSource(this.controller.getState());
|
||||
|
||||
if (source && source.actor === location.actor) {
|
||||
if (source && source.actor === location.actor && !disabled) {
|
||||
if (condition) {
|
||||
this.editor.setBreakpointCondition(location.line - 1);
|
||||
} else {
|
||||
@ -415,14 +417,28 @@ var DebuggerView = {
|
||||
* Sets the currently displayed text contents in the source editor.
|
||||
* This resets the mode and undo stack.
|
||||
*
|
||||
* @param string documentKey
|
||||
* Key to get the correct editor document
|
||||
*
|
||||
* @param string aTextContent
|
||||
* The source text content.
|
||||
*
|
||||
* @param boolean shouldUpdateText
|
||||
Forces a text and mode reset
|
||||
*/
|
||||
_setEditorText: function(aTextContent = "") {
|
||||
this.editor.setMode(Editor.modes.text);
|
||||
this.editor.setText(aTextContent);
|
||||
_setEditorText: function(documentKey, aTextContent = "", shouldUpdateText = false) {
|
||||
const isNew = this._setEditorDocument(documentKey);
|
||||
|
||||
this.editor.clearDebugLocation();
|
||||
this.editor.clearHistory();
|
||||
this.editor.setCursor({ line: 0, ch: 0});
|
||||
this.editor.removeBreakpoints();
|
||||
|
||||
// Only set editor's text and mode if it is a new document
|
||||
if (isNew || shouldUpdateText) {
|
||||
this.editor.setMode(Editor.modes.text);
|
||||
this.editor.setText(aTextContent);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -452,6 +468,29 @@ var DebuggerView = {
|
||||
this.editor.setMode(Editor.modes.text);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the editor's displayed document.
|
||||
* If there isn't a document for the source, create one
|
||||
*
|
||||
* @param string key - key used to access the editor document cache
|
||||
*
|
||||
* @return boolean isNew - was the document just created
|
||||
*/
|
||||
_setEditorDocument: function(key) {
|
||||
let isNew;
|
||||
|
||||
if (!this._editorDocuments[key]) {
|
||||
isNew = true;
|
||||
this._editorDocuments[key] = this.editor.createDocument();
|
||||
} else {
|
||||
isNew = false;
|
||||
}
|
||||
|
||||
const doc = this._editorDocuments[key];
|
||||
this.editor.replaceDocument(doc);
|
||||
return isNew;
|
||||
},
|
||||
|
||||
renderBlackBoxed: function(source) {
|
||||
this._renderSourceText(
|
||||
source,
|
||||
@ -477,6 +516,7 @@ var DebuggerView = {
|
||||
_renderSourceText: function(source, textInfo, opts = {}) {
|
||||
const selectedSource = queries.getSelectedSource(this.controller.getState());
|
||||
|
||||
// Exit early if we're attempting to render an unselected source
|
||||
if (!selectedSource || selectedSource.actor !== source.actor) {
|
||||
return;
|
||||
}
|
||||
@ -496,12 +536,12 @@ var DebuggerView = {
|
||||
// TODO: bug 1228866, we need to update `_editorSource` here but
|
||||
// still make the editor be updated when the full text comes
|
||||
// through somehow.
|
||||
this._setEditorText(L10N.getStr("loadingText"));
|
||||
this._setEditorText('loading', L10N.getStr("loadingText"));
|
||||
return;
|
||||
}
|
||||
else if (textInfo.error) {
|
||||
let msg = L10N.getFormatStr("errorLoadingText2", textInfo.error);
|
||||
this._setEditorText(msg);
|
||||
this._setEditorText('error', msg);
|
||||
Cu.reportError(msg);
|
||||
dumpn(msg);
|
||||
|
||||
@ -528,14 +568,18 @@ var DebuggerView = {
|
||||
return;
|
||||
}
|
||||
|
||||
let { text, contentType } = textInfo;
|
||||
let shouldUpdateText = this._editorSource.prettyPrinted != source.isPrettyPrinted;
|
||||
this._setEditorText(source.actor, text, shouldUpdateText);
|
||||
|
||||
this._editorSource.actor = source.actor;
|
||||
this._editorSource.prettyPrinted = source.isPrettyPrinted;
|
||||
this._editorSource.blackboxed = source.isBlackBoxed;
|
||||
this._editorSource.prettyPrinted = source.isPrettyPrinted;
|
||||
|
||||
let { text, contentType } = textInfo;
|
||||
this._setEditorText(text);
|
||||
this._setEditorMode(source.url, contentType, text);
|
||||
this.updateEditorBreakpoints(source);
|
||||
|
||||
setTimeout(() => {
|
||||
window.emit(EVENTS.SOURCE_SHOWN, source);
|
||||
}, 0);
|
||||
@ -787,7 +831,6 @@ var DebuggerView = {
|
||||
*/
|
||||
handleTabNavigation: function() {
|
||||
dumpn("Handling tab navigation in the DebuggerView");
|
||||
|
||||
this.Filtering.clearSearch();
|
||||
this.GlobalSearch.clearView();
|
||||
this.StackFrames.empty();
|
||||
@ -800,6 +843,7 @@ var DebuggerView = {
|
||||
this.editor.setText("");
|
||||
this.editor.clearHistory();
|
||||
this._editorSource = {};
|
||||
this._editorDocuments = {};
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -25,6 +25,13 @@ function test() {
|
||||
var client = gPanel.target.client;
|
||||
client.mainRoot.traits.conditionalBreakpoints = false;
|
||||
|
||||
function waitForConditionUpdate() {
|
||||
// This will close the popup and send another request to update
|
||||
// the condition
|
||||
gSources._hideConditionalPopup();
|
||||
return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
|
||||
}
|
||||
|
||||
Task.spawn(function*() {
|
||||
yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
|
||||
const location = { actor: gSources.selectedValue, line: 18 };
|
||||
@ -36,7 +43,7 @@ function test() {
|
||||
const bp = queries.getBreakpoint(getState(), location);
|
||||
is(bp.condition, "hello", "The conditional expression is correct.");
|
||||
|
||||
const finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWING);
|
||||
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWING);
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gDebugger.document.querySelector(".dbg-breakpoint"),
|
||||
gDebugger);
|
||||
@ -45,6 +52,18 @@ function test() {
|
||||
const textbox = gDebugger.document.getElementById("conditional-breakpoint-panel-textbox");
|
||||
is(textbox.value, "hello", "The expression is correct (2).")
|
||||
|
||||
yield waitForConditionUpdate();
|
||||
yield actions.disableBreakpoint(location);
|
||||
yield actions.setBreakpointCondition(location, "foo");
|
||||
yield actions.addBreakpoint(location);
|
||||
|
||||
finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWING);
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gDebugger.document.querySelector(".dbg-breakpoint"),
|
||||
gDebugger);
|
||||
yield finished;
|
||||
is(textbox.value, "foo", "The expression is correct (3).")
|
||||
|
||||
// Reset traits back to default value
|
||||
client.mainRoot.traits.conditionalBreakpoints = true;
|
||||
resumeDebuggerThenCloseAndFinish(gPanel);
|
||||
|
@ -21,6 +21,13 @@ function test() {
|
||||
const actions = bindActionCreators(gPanel);
|
||||
const getState = gDebugger.DebuggerController.getState;
|
||||
|
||||
function waitForConditionUpdate() {
|
||||
// This will close the popup and send another request to update
|
||||
// the condition
|
||||
gSources._hideConditionalPopup();
|
||||
return waitForDispatch(gPanel, constants.SET_BREAKPOINT_CONDITION);
|
||||
}
|
||||
|
||||
Task.spawn(function*() {
|
||||
yield waitForSourceAndCaretAndScopes(gPanel, ".html", 17);
|
||||
const location = { actor: gSources.selectedValue, line: 18 };
|
||||
@ -32,7 +39,7 @@ function test() {
|
||||
const bp = queries.getBreakpoint(getState(), location);
|
||||
is(bp.condition, "hello", "The conditional expression is correct.");
|
||||
|
||||
const finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWING);
|
||||
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWING);
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gDebugger.document.querySelector(".dbg-breakpoint"),
|
||||
gDebugger);
|
||||
@ -41,6 +48,18 @@ function test() {
|
||||
const textbox = gDebugger.document.getElementById("conditional-breakpoint-panel-textbox");
|
||||
is(textbox.value, "hello", "The expression is correct (2).")
|
||||
|
||||
yield waitForConditionUpdate();
|
||||
yield actions.disableBreakpoint(location);
|
||||
yield actions.setBreakpointCondition(location, "foo");
|
||||
yield actions.addBreakpoint(location);
|
||||
|
||||
finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWING);
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gDebugger.document.querySelector(".dbg-breakpoint"),
|
||||
gDebugger);
|
||||
yield finished;
|
||||
is(textbox.value, "foo", "The expression is correct (3).")
|
||||
|
||||
yield resumeDebuggerThenCloseAndFinish(gPanel);
|
||||
});
|
||||
|
||||
|
@ -89,11 +89,6 @@ function makeStateBroadcaster(stillAliveFunc) {
|
||||
if (stillAliveFunc()) {
|
||||
enqueuedChanges.forEach(([name, payload]) => {
|
||||
if (listeners[name]) {
|
||||
let payloadStr = payload;
|
||||
try {
|
||||
payloadStr = JSON.stringify(payload);
|
||||
}
|
||||
catch(e) {}
|
||||
listeners[name].forEach(listener => {
|
||||
listener(payload)
|
||||
});
|
||||
|
@ -173,9 +173,29 @@ function addBreakpoint(ctx, line, cond) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helps reset the debugger's breakpoint state
|
||||
* - removes the breakpoints in the editor
|
||||
* - cleares the debugger's breakpoint state
|
||||
*
|
||||
* Note, does not *actually* remove a source's breakpoints.
|
||||
* The canonical state is kept in the app state.
|
||||
*
|
||||
*/
|
||||
function removeBreakpoints(ctx) {
|
||||
let { ed, cm } = ctx;
|
||||
|
||||
let meta = dbginfo.get(ed);
|
||||
if (meta.breakpoints != null) {
|
||||
meta.breakpoints = {};
|
||||
}
|
||||
|
||||
cm.doc.iter((line) => { removeBreakpoint(ctx, line) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a visual breakpoint from a specified line and
|
||||
* makes Editor to emit a breakpointRemoved event.
|
||||
* makes Editor emit a breakpointRemoved event.
|
||||
*/
|
||||
function removeBreakpoint(ctx, line) {
|
||||
if (!hasBreakpoint(ctx, line)) {
|
||||
@ -303,7 +323,7 @@ function findPrev(ctx, query) {
|
||||
|
||||
[
|
||||
initialize, hasBreakpoint, addBreakpoint, removeBreakpoint, moveBreakpoint,
|
||||
setBreakpointCondition, removeBreakpointCondition, getBreakpoints,
|
||||
setBreakpointCondition, removeBreakpointCondition, getBreakpoints, removeBreakpoints,
|
||||
setDebugLocation, getDebugLocation, clearDebugLocation, find, findNext,
|
||||
findPrev
|
||||
].forEach(func => module.exports[func.name] = func);
|
||||
|
@ -241,6 +241,7 @@ Editor.prototype = {
|
||||
container: null,
|
||||
version: null,
|
||||
config: null,
|
||||
Doc: null,
|
||||
|
||||
/**
|
||||
* Appends the current Editor instance to the element specified by
|
||||
@ -302,6 +303,7 @@ Editor.prototype = {
|
||||
// context menus won't work).
|
||||
|
||||
cm = win.CodeMirror(win.document.body, this.config);
|
||||
this.Doc = win.CodeMirror.Doc;
|
||||
|
||||
// Disable APZ for source editors. It currently causes the line numbers to
|
||||
// "tear off" and swim around on top of the content. Bug 1160601 tracks
|
||||
@ -488,6 +490,22 @@ Editor.prototype = {
|
||||
Services.scriptloader.loadSubScript(url, win, "utf8");
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a CodeMirror Document
|
||||
* @returns CodeMirror.Doc
|
||||
*/
|
||||
createDocument: function() {
|
||||
return new this.Doc("");
|
||||
},
|
||||
|
||||
/**
|
||||
* Replaces the current document with a new source document
|
||||
*/
|
||||
replaceDocument: function(doc) {
|
||||
let cm = editors.get(this);
|
||||
cm.swapDoc(doc);
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the value of a currently used highlighting mode.
|
||||
* See Editor.modes for the list of all supported modes.
|
||||
|
@ -1,6 +1,7 @@
|
||||
<!-- 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/. -->
|
||||
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#babec3">
|
||||
<path d="M8,1.1c-3.8,0-6.9,3-6.9,6.9s3,6.9,6.9,6.9s6.9-3,6.9-6.9S11.8,1.1,8,1.1z M13.1,7.9c0,1.1-0.4,2.1-1,3L5,3.8 c0.8-0.6,1.9-1,3-1C10.8,2.8,13.1,5.1,13.1,7.9z M2.9,7.9c0-1.1,0.3-2.1,0.9-2.9l7.1,7.1C10.1,12.7,9.1,13,8,13 C5.2,13,2.9,10.7,2.9,7.9z"/>
|
||||
</svg>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#babec3">
|
||||
<path d="M6 3h3V2c0-.003-3 0-3 0-.002 0 0 1 0 1zm-5 .5c0-.276.226-.5.494-.5h12.012c.273 0 .494.232.494.5 0 .276-.226.5-.494.5H1.494C1.22 4 1 3.768 1 3.5zM5 3V2c0-.553.444-1 1-1h3c.552 0 1 .443 1 1v1H5z"/>
|
||||
<path d="M5 13h1V7H5v6zm4 0h1V7H9v6zm3-8v8.998c-.046.553-.45 1.002-1 1.002H4c-.55 0-.954-.456-1-1.002V5h9zm-5 8h1V7H7v6z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 571 B After Width: | Height: | Size: 651 B |
@ -107,7 +107,7 @@ HeapSnapshot::Create(JSContext* cx,
|
||||
|
||||
template<typename MessageType>
|
||||
static bool
|
||||
parseMessage(ZeroCopyInputStream& stream, MessageType& message)
|
||||
parseMessage(ZeroCopyInputStream& stream, uint32_t sizeOfMessage, MessageType& message)
|
||||
{
|
||||
// We need to create a new `CodedInputStream` for each message so that the
|
||||
// 64MB limit is applied per-message rather than to the whole stream.
|
||||
@ -122,16 +122,7 @@ parseMessage(ZeroCopyInputStream& stream, MessageType& message)
|
||||
// non-dominating messages.
|
||||
codedStream.SetRecursionLimit(HeapSnapshot::MAX_STACK_DEPTH * 3);
|
||||
|
||||
// Because protobuf messages aren't self-delimiting, we serialize each message
|
||||
// preceeded by its size in bytes. When deserializing, we read this size and
|
||||
// then limit reading from the stream to the given byte size. If we didn't,
|
||||
// then the first message would consume the entire stream.
|
||||
|
||||
uint32_t size = 0;
|
||||
if (NS_WARN_IF(!codedStream.ReadVarint32(&size)))
|
||||
return false;
|
||||
|
||||
auto limit = codedStream.PushLimit(size);
|
||||
auto limit = codedStream.PushLimit(sizeOfMessage);
|
||||
if (NS_WARN_IF(!message.ParseFromCodedStream(&codedStream)) ||
|
||||
NS_WARN_IF(!codedStream.ConsumedEntireMessage()) ||
|
||||
NS_WARN_IF(codedStream.BytesUntilLimit() != 0))
|
||||
@ -391,27 +382,16 @@ HeapSnapshot::saveStackFrame(const protobuf::StackFrame& frame,
|
||||
#undef GET_STRING_OR_REF_WITH_PROP_NAMES
|
||||
#undef GET_STRING_OR_REF
|
||||
|
||||
static inline bool
|
||||
StreamHasData(GzipInputStream& stream)
|
||||
// Because protobuf messages aren't self-delimiting, we serialize each message
|
||||
// preceded by its size in bytes. When deserializing, we read this size and then
|
||||
// limit reading from the stream to the given byte size. If we didn't, then the
|
||||
// first message would consume the entire stream.
|
||||
static bool
|
||||
readSizeOfNextMessage(ZeroCopyInputStream& stream, uint32_t* sizep)
|
||||
{
|
||||
// Test for the end of the stream. The protobuf library gives no way to tell
|
||||
// the difference between an underlying read error and the stream being
|
||||
// done. All we can do is attempt to read data and extrapolate guestimations
|
||||
// from the result of that operation.
|
||||
|
||||
const void* buf;
|
||||
int size;
|
||||
bool more = stream.Next(&buf, &size);
|
||||
if (!more)
|
||||
// Could not read any more data. We are optimistic and assume the stream is
|
||||
// just exhausted and there is not an underlying IO error, since this
|
||||
// function is only called at message boundaries.
|
||||
return false;
|
||||
|
||||
// There is more data still available in the stream. Return the data we read
|
||||
// to the stream and let the parser get at it.
|
||||
stream.BackUp(size);
|
||||
return true;
|
||||
MOZ_ASSERT(sizep);
|
||||
CodedInputStream codedStream(&stream);
|
||||
return codedStream.ReadVarint32(sizep) && *sizep > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -422,11 +402,14 @@ HeapSnapshot::init(JSContext* cx, const uint8_t* buffer, uint32_t size)
|
||||
|
||||
ArrayInputStream stream(buffer, size);
|
||||
GzipInputStream gzipStream(&stream);
|
||||
uint32_t sizeOfMessage = 0;
|
||||
|
||||
// First is the metadata.
|
||||
|
||||
protobuf::Metadata metadata;
|
||||
if (!parseMessage(gzipStream, metadata))
|
||||
if (NS_WARN_IF(!readSizeOfNextMessage(gzipStream, &sizeOfMessage)))
|
||||
return false;
|
||||
if (!parseMessage(gzipStream, sizeOfMessage, metadata))
|
||||
return false;
|
||||
if (metadata.has_timestamp())
|
||||
timestamp.emplace(metadata.timestamp());
|
||||
@ -434,7 +417,9 @@ HeapSnapshot::init(JSContext* cx, const uint8_t* buffer, uint32_t size)
|
||||
// Next is the root node.
|
||||
|
||||
protobuf::Node root;
|
||||
if (!parseMessage(gzipStream, root))
|
||||
if (NS_WARN_IF(!readSizeOfNextMessage(gzipStream, &sizeOfMessage)))
|
||||
return false;
|
||||
if (!parseMessage(gzipStream, sizeOfMessage, root))
|
||||
return false;
|
||||
|
||||
// Although the id is optional in the protobuf format for future proofing, we
|
||||
@ -453,9 +438,13 @@ HeapSnapshot::init(JSContext* cx, const uint8_t* buffer, uint32_t size)
|
||||
|
||||
// Finally, the rest of the nodes in the core dump.
|
||||
|
||||
while (StreamHasData(gzipStream)) {
|
||||
// Test for the end of the stream. The protobuf library gives no way to tell
|
||||
// the difference between an underlying read error and the stream being
|
||||
// done. All we can do is attempt to read the size of the next message and
|
||||
// extrapolate guestimations from the result of that operation.
|
||||
while (readSizeOfNextMessage(gzipStream, &sizeOfMessage)) {
|
||||
protobuf::Node node;
|
||||
if (!parseMessage(gzipStream, node))
|
||||
if (!parseMessage(gzipStream, sizeOfMessage, node))
|
||||
return false;
|
||||
if (NS_WARN_IF(!saveNode(node, edgeReferents)))
|
||||
return false;
|
||||
|
@ -7,6 +7,7 @@ support-files =
|
||||
[test_notification_basics.html]
|
||||
[test_notification_storage.html]
|
||||
[test_bug931307.html]
|
||||
skip-if = (os == 'android') # Bug 1258975 on android.
|
||||
[test_notification_resend.html]
|
||||
skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || e10s # On e10s, faking the app seems to be failing
|
||||
[test_notification_noresend.html]
|
||||
|
@ -211,9 +211,17 @@ public final class IntentHelper implements GeckoEventListener,
|
||||
callback.sendSuccess(null);
|
||||
|
||||
} else {
|
||||
// We originally loaded about:neterror when we failed to match the Intent. However, many
|
||||
// websites worked around Chrome's implementation, which does nothing in this case. For
|
||||
// example, the site might set a timeout and load a play store url for their app if the
|
||||
// intent link fails to load, i.e. the app is not installed. These work-arounds would often
|
||||
// end with our users seeing about:neterror instead of the intended experience. While I
|
||||
// feel showing about:neterror is a better solution for users (when not hacked around),
|
||||
// we should match the status quo for the good of our users.
|
||||
//
|
||||
// Don't log the URI to prevent leaking it.
|
||||
Log.w(LOGTAG, "Unable to open URI, default case - loading about:neterror");
|
||||
callback.sendError(getUnknownProtocolErrorPageUri(intent.getData().toString()));
|
||||
Log.w(LOGTAG, "Unable to open URI - ignoring click");
|
||||
callback.sendSuccess(null); // pretend we opened the page.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
<layer-list>
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/toolbar_grey"/>
|
||||
<solid android:color="@color/about_page_header_grey"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionContent.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
@ -104,3 +105,9 @@ AboutReaderListener.init();
|
||||
addMessageListener("RemoteLogins:fillForm", function(message) {
|
||||
LoginManagerContent.receiveMessage(message, content);
|
||||
});
|
||||
|
||||
ExtensionContent.init(this);
|
||||
addEventListener("unload", () => {
|
||||
ExtensionContent.uninit(this);
|
||||
});
|
||||
|
||||
|
@ -310,6 +310,8 @@
|
||||
@BINPATH@/components/NetworkGeolocationProvider.manifest
|
||||
@BINPATH@/components/NetworkGeolocationProvider.js
|
||||
@BINPATH@/components/extensions.manifest
|
||||
@BINPATH@/components/utils.manifest
|
||||
@BINPATH@/components/simpleServices.js
|
||||
@BINPATH@/components/addonManager.js
|
||||
@BINPATH@/components/amContentHandler.js
|
||||
@BINPATH@/components/amInstallTrigger.js
|
||||
|
@ -1,5 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = os == 'android'
|
||||
support-files =
|
||||
file_download.html
|
||||
file_download.txt
|
||||
@ -12,3 +11,4 @@ skip-if = 1 # Currently causes too many intermittent failures.
|
||||
[test_chrome_ext_downloads_search.html]
|
||||
[test_chrome_ext_eventpage_warning.html]
|
||||
[test_chrome_ext_contentscript_unrecognizedprop_warning.html]
|
||||
skip-if = (os == 'android') # browser.tabs is undefined. Bug 1258975 on android.
|
||||
|
@ -1,5 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = os == 'android' || buildapp == 'mulet'
|
||||
skip-if = buildapp == 'mulet' || asan
|
||||
support-files =
|
||||
head.js
|
||||
file_WebRequest_page1.html
|
||||
@ -44,26 +44,26 @@ skip-if = buildapp == 'b2g' # runat != document_idle is not supported.
|
||||
[test_ext_permission_xhr.html]
|
||||
skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE:
|
||||
[test_ext_runtime_connect.html]
|
||||
skip-if = buildapp == 'b2g' # port.sender.tab is undefined on b2g.
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android.
|
||||
[test_ext_runtime_connect2.html]
|
||||
skip-if = buildapp == 'b2g' # port.sender.tab is undefined on b2g.
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android.
|
||||
[test_ext_runtime_disconnect.html]
|
||||
[test_ext_runtime_getPlatformInfo.html]
|
||||
[test_ext_runtime_sendMessage.html]
|
||||
[test_ext_sandbox_var.html]
|
||||
[test_ext_sendmessage_reply.html]
|
||||
skip-if = buildapp == 'b2g' # sender.tab is undefined on b2g.
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
|
||||
[test_ext_sendmessage_reply2.html]
|
||||
skip-if = buildapp == 'b2g' # sender.tab is undefined on b2g.
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
|
||||
[test_ext_sendmessage_doublereply.html]
|
||||
skip-if = buildapp == 'b2g' # sender.tab is undefined on b2g.
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
|
||||
[test_ext_storage.html]
|
||||
[test_ext_background_runtime_connect_params.html]
|
||||
[test_ext_cookies.html]
|
||||
[test_ext_cookies_permissions.html]
|
||||
skip-if = e10s || buildapp == 'b2g' # Uses cookie service via SpecialPowers.Services, which does not support e10s.
|
||||
[test_ext_bookmarks.html]
|
||||
skip-if = buildapp == 'b2g' # unimplemented api.
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # unimplemented api. Bug 1258975 on android.
|
||||
[test_ext_alarms.html]
|
||||
[test_ext_background_window_properties.html]
|
||||
[test_ext_background_sub_windows.html]
|
||||
@ -71,8 +71,10 @@ skip-if = buildapp == 'b2g' # unimplemented api.
|
||||
[test_ext_jsversion.html]
|
||||
skip-if = e10s || buildapp == 'b2g' # Uses a console monitor which doesn't work from a content process. The code being tested doesn't run in a tab content process in any case.
|
||||
[test_ext_i18n.html]
|
||||
skip-if = (os == 'android') # Bug 1258975 on android.
|
||||
[test_ext_web_accessible_resources.html]
|
||||
skip-if = (os == 'android') # Bug 1258975 on android.
|
||||
[test_ext_webrequest.html]
|
||||
skip-if = buildapp == 'b2g' # webrequest api uninplemented (bug 1199504)
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # webrequest api uninplemented (bug 1199504). Bug 1258975 on android.
|
||||
[test_ext_webnavigation.html]
|
||||
skip-if = buildapp == 'b2g' # needs TabManager which is not yet implemented
|
||||
skip-if = (os == 'android' || buildapp == 'b2g') # needs TabManager which is not yet implemented. Bug 1258975 on android.
|
||||
|
@ -19,20 +19,20 @@ support-files =
|
||||
|
||||
[test_basic_form_2pw_2.html]
|
||||
[test_basic_form_autocomplete.html]
|
||||
skip-if = toolkit == 'android'
|
||||
skip-if = toolkit == 'android' # Bug 1258975 on android.
|
||||
[test_bug_627616.html]
|
||||
skip-if = toolkit == 'android' #TIMED_OUT
|
||||
skip-if = toolkit == 'android' # Bug 1258975 on android.
|
||||
[test_master_password.html]
|
||||
skip-if = toolkit == 'android' #TIMED_OUT
|
||||
skip-if = toolkit == 'android' # Bug 1258975 on android.
|
||||
[test_master_password_cleanup.html]
|
||||
skip-if = toolkit == 'android'
|
||||
skip-if = toolkit == 'android' # Bug 1258975 on android.
|
||||
[test_notifications_popup.html]
|
||||
skip-if = true || os == "linux" || toolkit == 'android' # bug 934057
|
||||
skip-if = true || os == "linux" || toolkit == 'android' # bug 934057. Bug 1258975 on android.
|
||||
[test_prompt.html]
|
||||
skip-if = os == "linux" || toolkit == 'android' #TIMED_OUT
|
||||
skip-if = os == "linux" || toolkit == 'android' # Bug 1258975 on android.
|
||||
[test_prompt_async.html]
|
||||
skip-if = toolkit == 'android' #TIMED_OUT
|
||||
skip-if = toolkit == 'android' # Bug 1258975 on android.
|
||||
[test_xhr.html]
|
||||
skip-if = toolkit == 'android' #TIMED_OUT
|
||||
skip-if = toolkit == 'android' # Bug 1258975 on android.
|
||||
[test_xml_load.html]
|
||||
skip-if = toolkit == 'android' #TIMED_OUT
|
||||
skip-if = toolkit == 'android' # Bug 1258975 on android.
|
@ -30,4 +30,5 @@ skip-if = toolkit == 'android' # Bug 1259768
|
||||
[test_maxlength.html]
|
||||
[test_passwords_in_type_password.html]
|
||||
[test_recipe_login_fields.html]
|
||||
[test_xhr_2.html]
|
||||
skip-if = (toolkit == 'android') # Bug 1258975 on android.
|
||||
[test_xhr_2.html]
|
@ -5587,11 +5587,12 @@
|
||||
"kind": "enumerated",
|
||||
"keyed": true,
|
||||
"n_values": 40,
|
||||
"description": "Usage of popup notifications, keyed by ID (0 = Offered, 1..4 = Action, 5 = Click outside, 6 = Leave page, 7 = Use 'X', 8 = Not now, 10 = Open submenu, 11 = Learn more. Add 20 if happened after reopen.)"
|
||||
"description": "(Bug 1207089) Usage of popup notifications, keyed by ID (0 = Offered, 1..4 = Action, 5 = Click outside, 6 = Leave page, 7 = Use 'X', 8 = Not now, 10 = Open submenu, 11 = Learn more. Add 20 if happened after reopen.)"
|
||||
},
|
||||
"POPUP_NOTIFICATION_MAIN_ACTION_MS": {
|
||||
"alert_emails": ["firefox-dev@mozilla.org"],
|
||||
"expires_in_version": "48",
|
||||
"bug_numbers": [1207089],
|
||||
"expires_in_version": "52",
|
||||
"kind": "exponential",
|
||||
"keyed": true,
|
||||
"low": 100,
|
||||
@ -5601,7 +5602,8 @@
|
||||
},
|
||||
"POPUP_NOTIFICATION_DISMISSAL_MS": {
|
||||
"alert_emails": ["firefox-dev@mozilla.org"],
|
||||
"expires_in_version": "48",
|
||||
"bug_numbers": [1207089],
|
||||
"expires_in_version": "52",
|
||||
"kind": "exponential",
|
||||
"keyed": true,
|
||||
"low": 200,
|
||||
|
Loading…
Reference in New Issue
Block a user