зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to m-c.
This commit is contained in:
Коммит
a5e0e0ab4a
|
@ -1138,7 +1138,7 @@ let RemoteDebugger = {
|
||||||
*/
|
*/
|
||||||
DebuggerServer.createRootActor = function createRootActor(connection)
|
DebuggerServer.createRootActor = function createRootActor(connection)
|
||||||
{
|
{
|
||||||
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
|
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||||
let parameters = {
|
let parameters = {
|
||||||
// We do not expose browser tab actors yet,
|
// We do not expose browser tab actors yet,
|
||||||
// but we still have to define tabList.getList(),
|
// but we still have to define tabList.getList(),
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
const { Cc, Ci, Cu } = require("chrome");
|
const { Cc, Ci, Cu } = require("chrome");
|
||||||
|
|
||||||
const { SimulatorProcess } = require("./simulator-process");
|
const { SimulatorProcess } = require("./simulator-process");
|
||||||
const Promise = require("sdk/core/promise");
|
const { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||||
const Self = require("sdk/self");
|
const Self = require("sdk/self");
|
||||||
const System = require("sdk/system");
|
const System = require("sdk/system");
|
||||||
const { Simulator } = Cu.import("resource://gre/modules/devtools/Simulator.jsm");
|
const { Simulator } = Cu.import("resource://gre/modules/devtools/Simulator.jsm");
|
||||||
|
|
|
@ -17,7 +17,7 @@ const Runtime = require("sdk/system/runtime");
|
||||||
const Self = require("sdk/self");
|
const Self = require("sdk/self");
|
||||||
const URL = require("sdk/url");
|
const URL = require("sdk/url");
|
||||||
const Subprocess = require("subprocess");
|
const Subprocess = require("subprocess");
|
||||||
const Promise = require("sdk/core/promise");
|
const { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||||
|
|
||||||
const { rootURI: ROOT_URI } = require('@loader/options');
|
const { rootURI: ROOT_URI } = require('@loader/options');
|
||||||
const PROFILE_URL = ROOT_URI + "profile/";
|
const PROFILE_URL = ROOT_URI + "profile/";
|
||||||
|
|
|
@ -177,6 +177,7 @@ SocialUI = {
|
||||||
SocialShare.populateProviderMenu();
|
SocialShare.populateProviderMenu();
|
||||||
SocialStatus.populateToolbarPalette();
|
SocialStatus.populateToolbarPalette();
|
||||||
SocialMarks.populateToolbarPalette();
|
SocialMarks.populateToolbarPalette();
|
||||||
|
SocialShare.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
// This handles "ActivateSocialFeature" events fired against content documents
|
// This handles "ActivateSocialFeature" events fired against content documents
|
||||||
|
@ -514,7 +515,7 @@ SocialShare = {
|
||||||
if (!provider)
|
if (!provider)
|
||||||
provider = SocialSidebar.provider;
|
provider = SocialSidebar.provider;
|
||||||
// if our provider has no shareURL, select the first one that does
|
// if our provider has no shareURL, select the first one that does
|
||||||
if (provider && !provider.shareURL) {
|
if (!provider || !provider.shareURL) {
|
||||||
let providers = [p for (p of Social.providers) if (p.shareURL)];
|
let providers = [p for (p of Social.providers) if (p.shareURL)];
|
||||||
provider = providers.length > 0 && providers[0];
|
provider = providers.length > 0 && providers[0];
|
||||||
}
|
}
|
||||||
|
@ -582,7 +583,10 @@ SocialShare = {
|
||||||
// also update the relevent command's disabled state so the keyboard
|
// also update the relevent command's disabled state so the keyboard
|
||||||
// shortcut only works when available.
|
// shortcut only works when available.
|
||||||
let cmd = document.getElementById("Social:SharePage");
|
let cmd = document.getElementById("Social:SharePage");
|
||||||
cmd.setAttribute("disabled", shareButton.disabled ? "true" : "false");
|
if (shareButton.disabled)
|
||||||
|
cmd.setAttribute("disabled", "true");
|
||||||
|
else
|
||||||
|
cmd.removeAttribute("disabled");
|
||||||
},
|
},
|
||||||
|
|
||||||
onShowing: function() {
|
onShowing: function() {
|
||||||
|
@ -1411,6 +1415,7 @@ SocialMarks = {
|
||||||
for (let cfg of contextMenus) {
|
for (let cfg of contextMenus) {
|
||||||
this._populateContextPopup(cfg, providers);
|
this._populateContextPopup(cfg, providers);
|
||||||
}
|
}
|
||||||
|
this.updatePanelButtons();
|
||||||
},
|
},
|
||||||
|
|
||||||
MENU_LIMIT: 3, // adjustable for testing
|
MENU_LIMIT: 3, // adjustable for testing
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
|
|
||||||
|
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
|
||||||
|
|
||||||
let baseURL = "https://example.com/browser/browser/base/content/test/social/";
|
let baseURL = "https://example.com/browser/browser/base/content/test/social/";
|
||||||
|
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
|
|
||||||
let manifest = { // normal provider
|
let manifest = { // normal provider
|
||||||
name: "provider 1",
|
name: "provider 1",
|
||||||
origin: "https://example.com",
|
origin: "https://example.com",
|
||||||
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
|
|
||||||
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
|
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
|
||||||
iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png",
|
iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png",
|
||||||
shareURL: "https://example.com/browser/browser/base/content/test/social/share.html"
|
shareURL: "https://example.com/browser/browser/base/content/test/social/share.html"
|
||||||
};
|
};
|
||||||
runSocialTestWithProvider(manifest, function (finishcb) {
|
|
||||||
runSocialTests(tests, undefined, undefined, finishcb);
|
function test() {
|
||||||
});
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
runSocialTests(tests);
|
||||||
}
|
}
|
||||||
|
|
||||||
let corpus = [
|
let corpus = [
|
||||||
|
@ -78,7 +78,7 @@ function loadURLInTab(url, callback) {
|
||||||
tab.linkedBrowser.addEventListener("load", function listener() {
|
tab.linkedBrowser.addEventListener("load", function listener() {
|
||||||
is(tab.linkedBrowser.currentURI.spec, url, "tab loaded")
|
is(tab.linkedBrowser.currentURI.spec, url, "tab loaded")
|
||||||
tab.linkedBrowser.removeEventListener("load", listener, true);
|
tab.linkedBrowser.removeEventListener("load", listener, true);
|
||||||
callback(tab);
|
executeSoon(function() { callback(tab) });
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,10 +101,46 @@ function hasoptions(testOptions, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var tests = {
|
var tests = {
|
||||||
|
testShareDisabledOnActivation: function(next) {
|
||||||
|
// starting on about:blank page, share should be visible but disabled when
|
||||||
|
// adding provider
|
||||||
|
is(gBrowser.contentDocument.location.href, "about:blank");
|
||||||
|
SocialService.addProvider(manifest, function(provider) {
|
||||||
|
is(SocialUI.enabled, true, "SocialUI is enabled");
|
||||||
|
checkSocialUI();
|
||||||
|
// share should not be enabled since we only have about:blank page
|
||||||
|
let shareButton = SocialShare.shareButton;
|
||||||
|
is(shareButton.disabled, true, "share button is disabled");
|
||||||
|
// verify the attribute for proper css
|
||||||
|
is(shareButton.getAttribute("disabled"), "true", "share button attribute is disabled");
|
||||||
|
// button should be visible
|
||||||
|
is(shareButton.hidden, false, "share button is visible");
|
||||||
|
SocialService.removeProvider(manifest.origin, next);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
testShareEnabledOnActivation: function(next) {
|
||||||
|
// starting from *some* page, share should be visible and enabled when
|
||||||
|
// activating provider
|
||||||
|
let testData = corpus[0];
|
||||||
|
loadURLInTab(testData.url, function(tab) {
|
||||||
|
SocialService.addProvider(manifest, function(provider) {
|
||||||
|
is(SocialUI.enabled, true, "SocialUI is enabled");
|
||||||
|
checkSocialUI();
|
||||||
|
// share should not be enabled since we only have about:blank page
|
||||||
|
let shareButton = SocialShare.shareButton;
|
||||||
|
is(shareButton.disabled, false, "share button is enabled");
|
||||||
|
// verify the attribute for proper css
|
||||||
|
ok(!shareButton.hasAttribute("disabled"), "share button is enabled");
|
||||||
|
// button should be visible
|
||||||
|
is(shareButton.hidden, false, "share button is visible");
|
||||||
|
gBrowser.removeTab(tab);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
testSharePage: function(next) {
|
testSharePage: function(next) {
|
||||||
let panel = document.getElementById("social-flyout-panel");
|
let provider = Social._getProviderFromOrigin(manifest.origin);
|
||||||
SocialSidebar.show();
|
let port = provider.getWorkerPort();
|
||||||
let port = SocialSidebar.provider.getWorkerPort();
|
|
||||||
ok(port, "provider has a port");
|
ok(port, "provider has a port");
|
||||||
let testTab;
|
let testTab;
|
||||||
let testIndex = 0;
|
let testIndex = 0;
|
||||||
|
@ -120,22 +156,19 @@ var tests = {
|
||||||
port.onmessage = function (e) {
|
port.onmessage = function (e) {
|
||||||
let topic = e.data.topic;
|
let topic = e.data.topic;
|
||||||
switch (topic) {
|
switch (topic) {
|
||||||
case "got-sidebar-message":
|
|
||||||
// open a tab with share data, then open the share panel
|
|
||||||
runOneTest();
|
|
||||||
break;
|
|
||||||
case "got-share-data-message":
|
case "got-share-data-message":
|
||||||
gBrowser.removeTab(testTab);
|
gBrowser.removeTab(testTab);
|
||||||
hasoptions(testData.options, e.data.result);
|
hasoptions(testData.options, e.data.result);
|
||||||
testData = corpus[testIndex++];
|
testData = corpus[testIndex++];
|
||||||
if (testData) {
|
if (testData) {
|
||||||
runOneTest();
|
executeSoon(runOneTest);
|
||||||
} else {
|
} else {
|
||||||
next();
|
SocialService.removeProvider(manifest.origin, next);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
port.postMessage({topic: "test-init"});
|
port.postMessage({topic: "test-init"});
|
||||||
|
executeSoon(runOneTest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,28 @@ function test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var tests = {
|
var tests = {
|
||||||
|
testButtonDisabledOnActivate: function(next) {
|
||||||
|
// starting on about:blank page, share should be visible but disabled when
|
||||||
|
// adding provider
|
||||||
|
is(gBrowser.contentDocument.location.href, "about:blank");
|
||||||
|
SocialService.addProvider(manifest2, function(provider) {
|
||||||
|
is(provider.origin, manifest2.origin, "provider is installed");
|
||||||
|
let id = SocialMarks._toolbarHelper.idFromOrigin(manifest2.origin);
|
||||||
|
let widget = CustomizableUI.getWidget(id).forWindow(window)
|
||||||
|
ok(widget.node, "button added to widget set");
|
||||||
|
|
||||||
|
// bypass widget go directly to dom, check attribute states
|
||||||
|
let button = document.getElementById(id);
|
||||||
|
is(button.disabled, true, "mark button is disabled");
|
||||||
|
// verify the attribute for proper css
|
||||||
|
is(button.getAttribute("disabled"), "true", "mark button attribute is disabled");
|
||||||
|
// button should be visible
|
||||||
|
is(button.hidden, false, "mark button is visible");
|
||||||
|
|
||||||
|
checkSocialUI(window);
|
||||||
|
SocialService.removeProvider(manifest2.origin, next);
|
||||||
|
});
|
||||||
|
},
|
||||||
testNoButtonOnEnable: function(next) {
|
testNoButtonOnEnable: function(next) {
|
||||||
// we expect the addon install dialog to appear, we need to accept the
|
// we expect the addon install dialog to appear, we need to accept the
|
||||||
// install from the dialog.
|
// install from the dialog.
|
||||||
|
@ -117,6 +139,15 @@ var tests = {
|
||||||
let id = SocialMarks._toolbarHelper.idFromOrigin(manifest2.origin);
|
let id = SocialMarks._toolbarHelper.idFromOrigin(manifest2.origin);
|
||||||
let widget = CustomizableUI.getWidget(id).forWindow(window)
|
let widget = CustomizableUI.getWidget(id).forWindow(window)
|
||||||
ok(widget.node, "button added to widget set");
|
ok(widget.node, "button added to widget set");
|
||||||
|
|
||||||
|
// bypass widget go directly to dom, check attribute states
|
||||||
|
let button = document.getElementById(id);
|
||||||
|
is(button.disabled, false, "mark button is disabled");
|
||||||
|
// verify the attribute for proper css
|
||||||
|
ok(!button.hasAttribute("disabled"), "mark button attribute is disabled");
|
||||||
|
// button should be visible
|
||||||
|
is(button.hidden, false, "mark button is visible");
|
||||||
|
|
||||||
checkSocialUI(window);
|
checkSocialUI(window);
|
||||||
gBrowser.removeTab(tab);
|
gBrowser.removeTab(tab);
|
||||||
next();
|
next();
|
||||||
|
|
|
@ -207,6 +207,7 @@ function checkSocialUI(win) {
|
||||||
let enabled = win.SocialUI.enabled;
|
let enabled = win.SocialUI.enabled;
|
||||||
let active = Social.providers.length > 0 && !win.SocialUI._chromeless &&
|
let active = Social.providers.length > 0 && !win.SocialUI._chromeless &&
|
||||||
!PrivateBrowsingUtils.isWindowPrivate(win);
|
!PrivateBrowsingUtils.isWindowPrivate(win);
|
||||||
|
let sidebarEnabled = win.SocialSidebar.provider ? enabled : false;
|
||||||
|
|
||||||
// if we have enabled providers, we should also have instances of those
|
// if we have enabled providers, we should also have instances of those
|
||||||
// providers
|
// providers
|
||||||
|
@ -235,7 +236,7 @@ function checkSocialUI(win) {
|
||||||
function isbool(a, b, msg) {
|
function isbool(a, b, msg) {
|
||||||
_is(!!a, !!b, msg);
|
_is(!!a, !!b, msg);
|
||||||
}
|
}
|
||||||
isbool(win.SocialSidebar.canShow, enabled, "social sidebar active?");
|
isbool(win.SocialSidebar.canShow, sidebarEnabled, "social sidebar active?");
|
||||||
isbool(win.SocialChatBar.isAvailable, enabled, "chatbar available?");
|
isbool(win.SocialChatBar.isAvailable, enabled, "chatbar available?");
|
||||||
isbool(!win.SocialChatBar.chatbar.hidden, enabled, "chatbar visible?");
|
isbool(!win.SocialChatBar.chatbar.hidden, enabled, "chatbar visible?");
|
||||||
|
|
||||||
|
@ -276,7 +277,7 @@ function checkSocialUI(win) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// and for good measure, check all the social commands.
|
// and for good measure, check all the social commands.
|
||||||
isbool(!doc.getElementById("Social:ToggleSidebar").hidden, enabled, "Social:ToggleSidebar visible?");
|
isbool(!doc.getElementById("Social:ToggleSidebar").hidden, sidebarEnabled, "Social:ToggleSidebar visible?");
|
||||||
isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
|
isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
|
||||||
isbool(!doc.getElementById("Social:FocusChat").hidden, enabled, "Social:FocusChat visible?");
|
isbool(!doc.getElementById("Social:FocusChat").hidden, enabled, "Social:FocusChat visible?");
|
||||||
isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
|
isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
|
||||||
|
|
|
@ -12,11 +12,20 @@ openUILinkIn = (aUrl, aWhichTab) => {
|
||||||
is(aWhichTab, "current", "Should use the current tab for the search page.");
|
is(aWhichTab, "current", "Should use the current tab for the search page.");
|
||||||
openUILinkInCalled = true;
|
openUILinkInCalled = true;
|
||||||
if (!expectOpenUILinkInCall) {
|
if (!expectOpenUILinkInCall) {
|
||||||
ok(false, "OpenUILink in was called when it shouldn't have been.");
|
ok(false, "OpenUILinkIn was called when it shouldn't have been.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
logActiveElement();
|
logActiveElement();
|
||||||
|
|
||||||
|
function* waitForSearchBarFocus()
|
||||||
|
{
|
||||||
|
let searchbar = document.getElementById("searchbar");
|
||||||
|
yield waitForCondition(function () {
|
||||||
|
logActiveElement();
|
||||||
|
return document.activeElement === searchbar.textbox.inputField;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Ctrl+K should open the menu panel and focus the search bar if the search bar is in the panel.
|
// Ctrl+K should open the menu panel and focus the search bar if the search bar is in the panel.
|
||||||
add_task(function() {
|
add_task(function() {
|
||||||
let searchbar = document.getElementById("searchbar");
|
let searchbar = document.getElementById("searchbar");
|
||||||
|
@ -28,8 +37,7 @@ add_task(function() {
|
||||||
sendWebSearchKeyCommand();
|
sendWebSearchKeyCommand();
|
||||||
yield shownPanelPromise;
|
yield shownPanelPromise;
|
||||||
|
|
||||||
logActiveElement();
|
yield waitForSearchBarFocus();
|
||||||
is(document.activeElement, searchbar.textbox.inputField, "The searchbar should be focused");
|
|
||||||
|
|
||||||
let hiddenPanelPromise = promisePanelHidden(window);
|
let hiddenPanelPromise = promisePanelHidden(window);
|
||||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||||
|
@ -49,8 +57,8 @@ add_task(function() {
|
||||||
yield shownPanelPromise;
|
yield shownPanelPromise;
|
||||||
|
|
||||||
sendWebSearchKeyCommand();
|
sendWebSearchKeyCommand();
|
||||||
logActiveElement();
|
|
||||||
is(document.activeElement, searchbar.textbox.inputField, "The searchbar should be focused");
|
yield waitForSearchBarFocus();
|
||||||
|
|
||||||
let hiddenPanelPromise = promisePanelHidden(window);
|
let hiddenPanelPromise = promisePanelHidden(window);
|
||||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||||
|
@ -68,7 +76,6 @@ add_task(function() {
|
||||||
window.resizeTo(360, window.outerHeight);
|
window.resizeTo(360, window.outerHeight);
|
||||||
yield waitForCondition(() => navbar.getAttribute("overflowing") == "true");
|
yield waitForCondition(() => navbar.getAttribute("overflowing") == "true");
|
||||||
ok(!navbar.querySelector("#search-container"), "Search container should be overflowing");
|
ok(!navbar.querySelector("#search-container"), "Search container should be overflowing");
|
||||||
let searchbar = document.getElementById("searchbar");
|
|
||||||
|
|
||||||
let shownPanelPromise = promiseOverflowShown(window);
|
let shownPanelPromise = promiseOverflowShown(window);
|
||||||
sendWebSearchKeyCommand();
|
sendWebSearchKeyCommand();
|
||||||
|
@ -76,8 +83,8 @@ add_task(function() {
|
||||||
|
|
||||||
let chevron = document.getElementById("nav-bar-overflow-button");
|
let chevron = document.getElementById("nav-bar-overflow-button");
|
||||||
yield waitForCondition(function() chevron.open);
|
yield waitForCondition(function() chevron.open);
|
||||||
logActiveElement();
|
|
||||||
is(document.activeElement, searchbar.textbox.inputField, "The searchbar should be focused");
|
yield waitForSearchBarFocus();
|
||||||
|
|
||||||
let hiddenPanelPromise = promiseOverflowHidden(window);
|
let hiddenPanelPromise = promiseOverflowHidden(window);
|
||||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||||
|
@ -90,13 +97,12 @@ add_task(function() {
|
||||||
|
|
||||||
// Ctrl+K should focus the search bar if it is in the navbar and not overflowing.
|
// Ctrl+K should focus the search bar if it is in the navbar and not overflowing.
|
||||||
add_task(function() {
|
add_task(function() {
|
||||||
let searchbar = document.getElementById("searchbar");
|
|
||||||
let placement = CustomizableUI.getPlacementOfWidget("search-container");
|
let placement = CustomizableUI.getPlacementOfWidget("search-container");
|
||||||
is(placement.area, CustomizableUI.AREA_NAVBAR, "Should be in nav-bar");
|
is(placement.area, CustomizableUI.AREA_NAVBAR, "Should be in nav-bar");
|
||||||
|
|
||||||
sendWebSearchKeyCommand();
|
sendWebSearchKeyCommand();
|
||||||
logActiveElement();
|
|
||||||
is(document.activeElement, searchbar.textbox.inputField, "The searchbar should be focused");
|
yield waitForSearchBarFocus();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ctrl+K should open the search page if the search bar has been customized out.
|
// Ctrl+K should open the search page if the search bar has been customized out.
|
||||||
|
|
|
@ -318,7 +318,13 @@ InspectorPanel.prototype = {
|
||||||
this._destroyMarkup();
|
this._destroyMarkup();
|
||||||
this.isDirty = false;
|
this.isDirty = false;
|
||||||
|
|
||||||
this._getDefaultNodeForSelection().then(defaultNode => {
|
let onNodeSelected = defaultNode => {
|
||||||
|
// Cancel this promise resolution as a new one had
|
||||||
|
// been queued up.
|
||||||
|
if (this._pendingSelection != onNodeSelected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._pendingSelection = null;
|
||||||
this.selection.setNodeFront(defaultNode, "navigateaway");
|
this.selection.setNodeFront(defaultNode, "navigateaway");
|
||||||
|
|
||||||
this._initMarkup();
|
this._initMarkup();
|
||||||
|
@ -330,7 +336,9 @@ InspectorPanel.prototype = {
|
||||||
this.setupSearchBox();
|
this.setupSearchBox();
|
||||||
this.emit("new-root");
|
this.emit("new-root");
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
this._pendingSelection = onNodeSelected;
|
||||||
|
this._getDefaultNodeForSelection().then(onNodeSelected);
|
||||||
},
|
},
|
||||||
|
|
||||||
_selectionCssSelector: null,
|
_selectionCssSelector: null,
|
||||||
|
|
|
@ -19,6 +19,7 @@ skip-if = true
|
||||||
[browser_inspector_markup_edit_4.js]
|
[browser_inspector_markup_edit_4.js]
|
||||||
[browser_inspector_markup_add_attributes.js]
|
[browser_inspector_markup_add_attributes.js]
|
||||||
[browser_inspector_markup_edit_outerhtml.js]
|
[browser_inspector_markup_edit_outerhtml.js]
|
||||||
|
skip-if = os == 'linux' && debug # bug 970240
|
||||||
[browser_inspector_markup_edit_outerhtml2.js]
|
[browser_inspector_markup_edit_outerhtml2.js]
|
||||||
[browser_inspector_markup_mutation.js]
|
[browser_inspector_markup_mutation.js]
|
||||||
[browser_inspector_markup_mutation_flashing.js]
|
[browser_inspector_markup_mutation_flashing.js]
|
||||||
|
|
|
@ -766,7 +766,7 @@ CSSCompleter.prototype = {
|
||||||
completeProperties: function(startProp) {
|
completeProperties: function(startProp) {
|
||||||
let finalList = [];
|
let finalList = [];
|
||||||
if (!startProp)
|
if (!startProp)
|
||||||
return finalList;
|
return Promise.resolve(finalList);
|
||||||
|
|
||||||
let length = propertyNames.length;
|
let length = propertyNames.length;
|
||||||
let i = 0, count = 0;
|
let i = 0, count = 0;
|
||||||
|
|
|
@ -175,6 +175,7 @@ function testPropDelete(aProp)
|
||||||
|
|
||||||
waitForSuccess({
|
waitForSuccess({
|
||||||
name: "property deleted",
|
name: "property deleted",
|
||||||
|
timeout: 60000,
|
||||||
validatorFn: () => !("testUpdatedProp" in content.wrappedJSObject.fooObj),
|
validatorFn: () => !("testUpdatedProp" in content.wrappedJSObject.fooObj),
|
||||||
successFn: finishTest,
|
successFn: finishTest,
|
||||||
failureFn: finishTest,
|
failureFn: finishTest,
|
||||||
|
|
|
@ -4,64 +4,39 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
// Tests that errors still show up in the Web Console after a page reload.
|
// Tests that errors still show up in the Web Console after a page reload.
|
||||||
|
// See bug 580030: the error handler fails silently after page reload.
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=580030
|
||||||
|
|
||||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-error.html";
|
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-error.html";
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
expectUncaughtException();
|
Task.spawn(function*() {
|
||||||
addTab(TEST_URI);
|
const {tab} = yield loadTab(TEST_URI);
|
||||||
browser.addEventListener("load", onLoad, true);
|
const hud = yield openConsole(tab);
|
||||||
}
|
info("console opened");
|
||||||
|
|
||||||
// see bug 580030: the error handler fails silently after page reload.
|
executeSoon(() => {
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=580030
|
|
||||||
function onLoad(aEvent) {
|
|
||||||
browser.removeEventListener(aEvent.type, onLoad, true);
|
|
||||||
|
|
||||||
openConsole(null, function(hud) {
|
|
||||||
hud.jsterm.clearOutput();
|
hud.jsterm.clearOutput();
|
||||||
browser.addEventListener("load", testErrorsAfterPageReload, true);
|
info("wait for reload");
|
||||||
content.location.reload();
|
content.location.reload();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function testErrorsAfterPageReload(aEvent) {
|
yield hud.target.once("navigate");
|
||||||
browser.removeEventListener(aEvent.type, testErrorsAfterPageReload, true);
|
info("target navigated");
|
||||||
|
|
||||||
// dispatch a click event to the button in the test page and listen for
|
let button = content.document.querySelector("button");
|
||||||
// errors.
|
|
||||||
|
|
||||||
Services.console.registerListener(consoleObserver);
|
|
||||||
|
|
||||||
let button = content.document.querySelector("button").wrappedJSObject;
|
|
||||||
ok(button, "button found");
|
ok(button, "button found");
|
||||||
EventUtils.sendMouseEvent({type: "click"}, button, content.wrappedJSObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
var consoleObserver = {
|
expectUncaughtException();
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
EventUtils.sendMouseEvent({type: "click"}, button, content);
|
||||||
|
|
||||||
observe: function test_observe(aMessage)
|
yield waitForMessages({
|
||||||
{
|
webconsole: hud,
|
||||||
// Ignore errors we don't care about.
|
messages: [{
|
||||||
if (!(aMessage instanceof Ci.nsIScriptError) ||
|
text: "fooBazBaz is not defined",
|
||||||
aMessage.category != "content javascript") {
|
category: CATEGORY_JS,
|
||||||
return;
|
severity: SEVERITY_ERROR,
|
||||||
}
|
}],
|
||||||
|
|
||||||
Services.console.unregisterListener(this);
|
|
||||||
|
|
||||||
let outputNode = HUDService.getHudByWindow(content).outputNode;
|
|
||||||
|
|
||||||
waitForSuccess({
|
|
||||||
name: "error message after page reload",
|
|
||||||
validatorFn: function()
|
|
||||||
{
|
|
||||||
return outputNode.textContent.indexOf("fooBazBaz") > -1;
|
|
||||||
},
|
|
||||||
successFn: finishTest,
|
|
||||||
failureFn: finishTest,
|
|
||||||
});
|
});
|
||||||
|
}).then(finishTest);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
|
@ -8,36 +8,29 @@
|
||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const TEST_URI = "http://example.com/browser/browser/devtools/" +
|
const TEST_URI = "http://example.com/browser/browser/devtools/" +
|
||||||
"webconsole/test/test-bug-597136-external-script-" +
|
"webconsole/test/test-bug-597136-external-script-" +
|
||||||
"errors.html";
|
"errors.html";
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
addTab(TEST_URI);
|
Task.spawn(function* () {
|
||||||
browser.addEventListener("load", function onLoad() {
|
const {tab} = yield loadTab(TEST_URI);
|
||||||
browser.removeEventListener("load", onLoad, true);
|
const hud = yield openConsole(tab);
|
||||||
openConsole(null, function(hud) {
|
|
||||||
executeSoon(function() {
|
|
||||||
consoleOpened(hud);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function consoleOpened(hud) {
|
|
||||||
let button = content.document.querySelector("button");
|
let button = content.document.querySelector("button");
|
||||||
let outputNode = hud.outputNode;
|
|
||||||
|
|
||||||
expectUncaughtException();
|
expectUncaughtException();
|
||||||
EventUtils.sendMouseEvent({ type: "click" }, button, content);
|
EventUtils.sendMouseEvent({ type: "click" }, button, content);
|
||||||
|
|
||||||
waitForSuccess({
|
yield waitForMessages({
|
||||||
name: "external script error message",
|
webconsole: hud,
|
||||||
validatorFn: function()
|
messages: [{
|
||||||
{
|
text: "bogus is not defined",
|
||||||
return outputNode.textContent.indexOf("bogus is not defined") > -1;
|
category: CATEGORY_JS,
|
||||||
},
|
severity: SEVERITY_ERROR,
|
||||||
successFn: finishTest,
|
}],
|
||||||
failureFn: finishTest,
|
|
||||||
});
|
});
|
||||||
|
}).then(finishTest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ const PREF_LOGGING_DUMP = PREF_LOGGING + ".dump"; // experiments.logging
|
||||||
const PREF_MANIFEST_URI = "manifest.uri"; // experiments.logging.manifest.uri
|
const PREF_MANIFEST_URI = "manifest.uri"; // experiments.logging.manifest.uri
|
||||||
const PREF_MANIFEST_CHECKCERT = "manifest.cert.checkAttributes"; // experiments.manifest.cert.checkAttributes
|
const PREF_MANIFEST_CHECKCERT = "manifest.cert.checkAttributes"; // experiments.manifest.cert.checkAttributes
|
||||||
const PREF_MANIFEST_REQUIREBUILTIN = "manifest.cert.requireBuiltin"; // experiments.manifest.cert.requireBuiltin
|
const PREF_MANIFEST_REQUIREBUILTIN = "manifest.cert.requireBuiltin"; // experiments.manifest.cert.requireBuiltin
|
||||||
|
const PREF_FORCE_SAMPLE = "force-sample-value"; // experiments.force-sample-value
|
||||||
|
|
||||||
const PREF_HEALTHREPORT_ENABLED = "datareporting.healthreport.service.enabled";
|
const PREF_HEALTHREPORT_ENABLED = "datareporting.healthreport.service.enabled";
|
||||||
|
|
||||||
|
@ -164,6 +165,18 @@ Experiments.Policy.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
random: function () {
|
random: function () {
|
||||||
|
let pref = gPrefs.get(PREF_FORCE_SAMPLE);
|
||||||
|
if (pref !== undefined) {
|
||||||
|
let val = Number.parseFloat(pref);
|
||||||
|
gLogger.debug("Experiments::Policy::random sample forced: " + val);
|
||||||
|
if (IsNaN(val) || val < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (val > 1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
return Math.random();
|
return Math.random();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -625,7 +638,7 @@ Experiments.Experiments.prototype = {
|
||||||
if (!entry.initFromCacheData(item)) {
|
if (!entry.initFromCacheData(item)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
experiments.set(item.id, entry);
|
experiments.set(entry.id, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._experiments = experiments;
|
this._experiments = experiments;
|
||||||
|
@ -666,7 +679,7 @@ Experiments.Experiments.prototype = {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
experiments.set(data.id, entry);
|
experiments.set(entry.id, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we keep experiments that are or were running.
|
// Make sure we keep experiments that are or were running.
|
||||||
|
|
|
@ -170,6 +170,8 @@ pref("dom.experimental_forms", true);
|
||||||
pref("dom.forms.number", true);
|
pref("dom.forms.number", true);
|
||||||
|
|
||||||
/* extension manager and xpinstall */
|
/* extension manager and xpinstall */
|
||||||
|
pref("xpinstall.whitelist.directRequest", false);
|
||||||
|
pref("xpinstall.whitelist.fileRequest", false);
|
||||||
pref("xpinstall.whitelist.add", "addons.mozilla.org");
|
pref("xpinstall.whitelist.add", "addons.mozilla.org");
|
||||||
pref("xpinstall.whitelist.add.180", "marketplace.firefox.com");
|
pref("xpinstall.whitelist.add.180", "marketplace.firefox.com");
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,25 @@
|
||||||
<action android:name="android.intent.action.SEARCH" />
|
<action android:name="android.intent.action.SEARCH" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<!-- For XPI installs from websites and the download manager. -->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:scheme="file" />
|
||||||
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:mimeType="application/x-xpinstall" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<!-- For XPI installs from file: URLs. -->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:host="" />
|
||||||
|
<data android:scheme="file" />
|
||||||
|
<data android:pathPattern=".*\\.xpi" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
#ifdef MOZ_ANDROID_BEAM
|
#ifdef MOZ_ANDROID_BEAM
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
|
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
|
||||||
|
|
|
@ -5,12 +5,18 @@
|
||||||
|
|
||||||
package org.mozilla.gecko.home;
|
package org.mozilla.gecko.home;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
import org.mozilla.gecko.db.BrowserContract.HomeItems;
|
import org.mozilla.gecko.db.BrowserContract.HomeItems;
|
||||||
import org.mozilla.gecko.db.DBUtils;
|
import org.mozilla.gecko.db.DBUtils;
|
||||||
import org.mozilla.gecko.home.HomeConfig.PanelConfig;
|
import org.mozilla.gecko.home.HomeConfig.PanelConfig;
|
||||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||||
import org.mozilla.gecko.home.PanelLayout.DatasetHandler;
|
import org.mozilla.gecko.home.PanelLayout.DatasetHandler;
|
||||||
import org.mozilla.gecko.home.PanelLayout.DatasetRequest;
|
import org.mozilla.gecko.home.PanelLayout.DatasetRequest;
|
||||||
|
import org.mozilla.gecko.util.GeckoEventListener;
|
||||||
|
import org.mozilla.gecko.util.ThreadUtils;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
|
@ -45,7 +51,8 @@ import android.view.ViewGroup;
|
||||||
* See {@code PanelLayout} for more details on how {@code DynamicPanel}
|
* See {@code PanelLayout} for more details on how {@code DynamicPanel}
|
||||||
* receives dataset requests and delivers them back to the {@code PanelLayout}.
|
* receives dataset requests and delivers them back to the {@code PanelLayout}.
|
||||||
*/
|
*/
|
||||||
public class DynamicPanel extends HomeFragment {
|
public class DynamicPanel extends HomeFragment
|
||||||
|
implements GeckoEventListener {
|
||||||
private static final String LOGTAG = "GeckoDynamicPanel";
|
private static final String LOGTAG = "GeckoDynamicPanel";
|
||||||
|
|
||||||
// Dataset ID to be used by the loader
|
// Dataset ID to be used by the loader
|
||||||
|
@ -116,12 +123,15 @@ public class DynamicPanel extends HomeFragment {
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
GeckoAppShell.registerEventListener("HomePanels:RefreshDataset", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
mLayout = null;
|
mLayout = null;
|
||||||
|
|
||||||
|
GeckoAppShell.unregisterEventListener("HomePanels:RefreshDataset", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -152,10 +162,69 @@ public class DynamicPanel extends HomeFragment {
|
||||||
mLayout.load();
|
mLayout.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(String event, final JSONObject message) {
|
||||||
|
if (event.equals("HomePanels:RefreshDataset")) {
|
||||||
|
ThreadUtils.postToUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
handleDatasetRefreshRequest(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static int generateLoaderId(String datasetId) {
|
private static int generateLoaderId(String datasetId) {
|
||||||
return datasetId.hashCode();
|
return datasetId.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a dataset refresh request from Gecko. This is usually
|
||||||
|
* triggered by a HomeStorage.save() call in an add-on.
|
||||||
|
*/
|
||||||
|
private void handleDatasetRefreshRequest(JSONObject message) {
|
||||||
|
final String datasetId;
|
||||||
|
try {
|
||||||
|
datasetId = message.getString("datasetId");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(LOGTAG, "Failed to handle dataset refresh", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(LOGTAG, "Refresh request for dataset: " + datasetId);
|
||||||
|
|
||||||
|
final int loaderId = generateLoaderId(datasetId);
|
||||||
|
|
||||||
|
final LoaderManager lm = getLoaderManager();
|
||||||
|
final Loader<?> loader = (Loader<?>) lm.getLoader(loaderId);
|
||||||
|
|
||||||
|
// Only restart a loader if there's already an active one
|
||||||
|
// for the given dataset ID. Do nothing otherwise.
|
||||||
|
if (loader != null) {
|
||||||
|
final PanelDatasetLoader datasetLoader = (PanelDatasetLoader) loader;
|
||||||
|
final DatasetRequest request = datasetLoader.getRequest();
|
||||||
|
|
||||||
|
// Ensure the refresh request doesn't affect the view's filter
|
||||||
|
// stack (i.e. use DATASET_LOAD type) but keep the current
|
||||||
|
// dataset ID and filter.
|
||||||
|
final DatasetRequest newRequest =
|
||||||
|
new DatasetRequest(DatasetRequest.Type.DATASET_LOAD,
|
||||||
|
request.getDatasetId(),
|
||||||
|
request.getFilterDetail());
|
||||||
|
|
||||||
|
restartDatasetLoader(newRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restartDatasetLoader(DatasetRequest request) {
|
||||||
|
final Bundle bundle = new Bundle();
|
||||||
|
bundle.putParcelable(DATASET_REQUEST, request);
|
||||||
|
|
||||||
|
// Ensure one loader per dataset
|
||||||
|
final int loaderId = generateLoaderId(request.getDatasetId());
|
||||||
|
getLoaderManager().restartLoader(loaderId, bundle, mLoaderCallbacks);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by the PanelLayout to make load and reset requests to
|
* Used by the PanelLayout to make load and reset requests to
|
||||||
* the holding fragment.
|
* the holding fragment.
|
||||||
|
@ -171,12 +240,7 @@ public class DynamicPanel extends HomeFragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Bundle bundle = new Bundle();
|
restartDatasetLoader(request);
|
||||||
bundle.putParcelable(DATASET_REQUEST, request);
|
|
||||||
|
|
||||||
// Ensure one loader per dataset
|
|
||||||
final int loaderId = generateLoaderId(request.getDatasetId());
|
|
||||||
getLoaderManager().restartLoader(loaderId, bundle, mLoaderCallbacks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -42,19 +42,22 @@ class PanelItemView extends LinearLayout {
|
||||||
|
|
||||||
// Only show title if the item has one
|
// Only show title if the item has one
|
||||||
final boolean hasTitle = !TextUtils.isEmpty(title);
|
final boolean hasTitle = !TextUtils.isEmpty(title);
|
||||||
mTitleDescContainer.setVisibility(hasTitle ? View.VISIBLE : View.GONE);
|
mTitle.setVisibility(hasTitle ? View.VISIBLE : View.GONE);
|
||||||
if (hasTitle) {
|
if (hasTitle) {
|
||||||
mTitle.setText(title);
|
mTitle.setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
int descriptionIndex = cursor.getColumnIndexOrThrow(HomeItems.DESCRIPTION);
|
int descriptionIndex = cursor.getColumnIndexOrThrow(HomeItems.DESCRIPTION);
|
||||||
final String description = cursor.getString(descriptionIndex);
|
final String description = cursor.getString(descriptionIndex);
|
||||||
|
|
||||||
|
// Only show description if the item has one
|
||||||
final boolean hasDescription = !TextUtils.isEmpty(description);
|
final boolean hasDescription = !TextUtils.isEmpty(description);
|
||||||
mDescription.setVisibility(hasDescription ? View.VISIBLE : View.GONE);
|
mDescription.setVisibility(hasDescription ? View.VISIBLE : View.GONE);
|
||||||
if (hasDescription) {
|
if (hasDescription) {
|
||||||
mDescription.setText(description);
|
mDescription.setText(description);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
mTitleDescContainer.setVisibility(hasTitle || hasDescription ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
int imageIndex = cursor.getColumnIndexOrThrow(HomeItems.IMAGE_URL);
|
int imageIndex = cursor.getColumnIndexOrThrow(HomeItems.IMAGE_URL);
|
||||||
final String imageUrl = cursor.getString(imageIndex);
|
final String imageUrl = cursor.getString(imageIndex);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
android:layout_width="54dp"
|
android:layout_width="54dp"
|
||||||
android:layout_height="44dp"
|
android:layout_height="44dp"
|
||||||
android:layout_marginTop="10dip"
|
android:layout_marginTop="10dip"
|
||||||
|
android:layout_marginBottom="10dip"
|
||||||
android:layout_marginLeft="10dip"
|
android:layout_marginLeft="10dip"
|
||||||
android:scaleType="centerCrop"/>
|
android:scaleType="centerCrop"/>
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="2"
|
android:layout_weight="2"
|
||||||
|
android:gravity="center_vertical"
|
||||||
android:maxLength="1024"/>
|
android:maxLength="1024"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_marginTop="3dp"
|
android:gravity="center_vertical"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:maxLength="1024"/>
|
android:maxLength="1024"/>
|
||||||
|
|
||||||
|
|
|
@ -5695,7 +5695,10 @@ var XPInstallObserver = {
|
||||||
if (!tab)
|
if (!tab)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let host = installInfo.originatingURI.host;
|
let host = null;
|
||||||
|
if (installInfo.originatingURI) {
|
||||||
|
host = installInfo.originatingURI.host;
|
||||||
|
}
|
||||||
|
|
||||||
let brandShortName = Strings.brand.GetStringFromName("brandShortName");
|
let brandShortName = Strings.brand.GetStringFromName("brandShortName");
|
||||||
let notificationName, buttons, message;
|
let notificationName, buttons, message;
|
||||||
|
@ -5723,7 +5726,23 @@ var XPInstallObserver = {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
notificationName = "xpinstall";
|
notificationName = "xpinstall";
|
||||||
|
if (host) {
|
||||||
|
// We have a host which asked for the install.
|
||||||
message = strings.formatStringFromName("xpinstallPromptWarning2", [brandShortName, host], 2);
|
message = strings.formatStringFromName("xpinstallPromptWarning2", [brandShortName, host], 2);
|
||||||
|
} else {
|
||||||
|
// Without a host we address the add-on as the initiator of the install.
|
||||||
|
let addon = null;
|
||||||
|
if (installInfo.installs.length > 0) {
|
||||||
|
addon = installInfo.installs[0].name;
|
||||||
|
}
|
||||||
|
if (addon) {
|
||||||
|
// We have an addon name, show the regular message.
|
||||||
|
message = strings.formatStringFromName("xpinstallPromptWarningLocal", [brandShortName, addon], 2);
|
||||||
|
} else {
|
||||||
|
// We don't have an addon name, show an alternative message.
|
||||||
|
message = strings.formatStringFromName("xpinstallPromptWarningDirect", [brandShortName], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buttons = [{
|
buttons = [{
|
||||||
label: strings.GetStringFromName("xpinstallPromptAllowButton"),
|
label: strings.GetStringFromName("xpinstallPromptAllowButton"),
|
||||||
|
|
|
@ -71,6 +71,8 @@ blockPopups.label=Block Popups
|
||||||
|
|
||||||
# XPInstall
|
# XPInstall
|
||||||
xpinstallPromptWarning2=%S prevented this site (%S) from asking you to install software on your device.
|
xpinstallPromptWarning2=%S prevented this site (%S) from asking you to install software on your device.
|
||||||
|
xpinstallPromptWarningLocal=%S prevented this add-on (%S) from installing on your device.
|
||||||
|
xpinstallPromptWarningDirect=%S prevented an add-on from installing on your device.
|
||||||
xpinstallPromptAllowButton=Allow
|
xpinstallPromptAllowButton=Allow
|
||||||
xpinstallDisabledMessageLocked=Software installation has been disabled by your system administrator.
|
xpinstallDisabledMessageLocked=Software installation has been disabled by your system administrator.
|
||||||
xpinstallDisabledMessage2=Software installation is currently disabled. Press Enable and try again.
|
xpinstallDisabledMessage2=Software installation is currently disabled. Press Enable and try again.
|
||||||
|
|
|
@ -9,6 +9,7 @@ this.EXPORTED_SYMBOLS = [ "HomeProvider" ];
|
||||||
|
|
||||||
const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
|
const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||||
Cu.import("resource://gre/modules/osfile.jsm");
|
Cu.import("resource://gre/modules/osfile.jsm");
|
||||||
Cu.import("resource://gre/modules/Promise.jsm");
|
Cu.import("resource://gre/modules/Promise.jsm");
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
@ -88,6 +89,10 @@ var gTimerRegistered = false;
|
||||||
// Map of datasetId -> { interval: <integer>, callback: <function> }
|
// Map of datasetId -> { interval: <integer>, callback: <function> }
|
||||||
var gSyncCallbacks = {};
|
var gSyncCallbacks = {};
|
||||||
|
|
||||||
|
// Whether or not writes to the provider are expected.
|
||||||
|
// e.g. save() and deleteAll()
|
||||||
|
var gWritesAreExpected = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nsITimerCallback implementation. Checks to see if it's time to sync any registered datasets.
|
* nsITimerCallback implementation. Checks to see if it's time to sync any registered datasets.
|
||||||
*
|
*
|
||||||
|
@ -153,7 +158,10 @@ this.HomeProvider = Object.freeze({
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gWritesAreExpected = true;
|
||||||
callback(datasetId);
|
callback(datasetId);
|
||||||
|
gWritesAreExpected = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -291,6 +299,10 @@ HomeStorage.prototype = {
|
||||||
* @resolves When the operation has completed.
|
* @resolves When the operation has completed.
|
||||||
*/
|
*/
|
||||||
save: function(data) {
|
save: function(data) {
|
||||||
|
if (!gWritesAreExpected) {
|
||||||
|
Cu.reportError("HomeStorage: save() called outside of sync window");
|
||||||
|
}
|
||||||
|
|
||||||
return Task.spawn(function save_task() {
|
return Task.spawn(function save_task() {
|
||||||
let db = yield getDatabaseConnection();
|
let db = yield getDatabaseConnection();
|
||||||
try {
|
try {
|
||||||
|
@ -315,6 +327,11 @@ HomeStorage.prototype = {
|
||||||
} finally {
|
} finally {
|
||||||
yield db.close();
|
yield db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendMessageToJava({
|
||||||
|
type: "HomePanels:RefreshDataset",
|
||||||
|
datasetId: this.datasetId,
|
||||||
|
});
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -325,6 +342,10 @@ HomeStorage.prototype = {
|
||||||
* @resolves When the operation has completed.
|
* @resolves When the operation has completed.
|
||||||
*/
|
*/
|
||||||
deleteAll: function() {
|
deleteAll: function() {
|
||||||
|
if (!gWritesAreExpected) {
|
||||||
|
Cu.reportError("HomeStorage: deleteAll() called outside of sync window");
|
||||||
|
}
|
||||||
|
|
||||||
return Task.spawn(function delete_all_task() {
|
return Task.spawn(function delete_all_task() {
|
||||||
let db = yield getDatabaseConnection();
|
let db = yield getDatabaseConnection();
|
||||||
try {
|
try {
|
||||||
|
@ -333,6 +354,11 @@ HomeStorage.prototype = {
|
||||||
} finally {
|
} finally {
|
||||||
yield db.close();
|
yield db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendMessageToJava({
|
||||||
|
type: "HomePanels:RefreshDataset",
|
||||||
|
datasetId: this.datasetId,
|
||||||
|
});
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,7 +42,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
"resource://gre/modules/Task.jsm");
|
"resource://gre/modules/Task.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
"resource://gre/modules/Promise.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
|
XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
|
||||||
"resource://gre/modules/Deprecated.jsm");
|
"resource://gre/modules/Deprecated.jsm");
|
||||||
|
|
|
@ -6,7 +6,7 @@ const TRANSITION_TYPED = Ci.nsINavHistoryService.TRANSITION_TYPED;
|
||||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
"resource://gre/modules/Promise.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
"resource://gre/modules/Task.jsm");
|
"resource://gre/modules/Task.jsm");
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||||
"resource://gre/modules/NetUtil.jsm");
|
"resource://gre/modules/NetUtil.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
"resource://gre/modules/Promise.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||||
"resource://gre/modules/Services.jsm");
|
"resource://gre/modules/Services.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
|
|
|
@ -112,12 +112,14 @@ add_task(function test() {
|
||||||
checkOrder(id1, id3, id2);
|
checkOrder(id1, id3, id2);
|
||||||
|
|
||||||
// Add a visit, then check frecency ordering.
|
// Add a visit, then check frecency ordering.
|
||||||
yield promiseAddVisits({ uri: uri2,
|
|
||||||
transition: TRANSITION_TYPED});
|
|
||||||
// When the bookmarks service gets onVisit, it asynchronously fetches all
|
// When the bookmarks service gets onVisit, it asynchronously fetches all
|
||||||
// items for that visit, and then notifies onItemVisited. Thus we must
|
// items for that visit, and then notifies onItemVisited. Thus we must
|
||||||
// explicitly wait for that.
|
// explicitly wait for that.
|
||||||
yield promiseOnItemVisited();
|
let waitForVisited = promiseOnItemVisited();
|
||||||
|
yield promiseAddVisits({ uri: uri2,
|
||||||
|
transition: TRANSITION_TYPED});
|
||||||
|
yield waitForVisited;
|
||||||
|
|
||||||
do_print("Sort by frecency desc");
|
do_print("Sort by frecency desc");
|
||||||
result.sortingMode = NHQO.SORT_BY_FRECENCY_DESCENDING;
|
result.sortingMode = NHQO.SORT_BY_FRECENCY_DESCENDING;
|
||||||
|
|
|
@ -111,6 +111,21 @@ let snapshotFormatters = {
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
experiments: function experiments(data) {
|
||||||
|
$.append($("experiments-tbody"), data.map(function (experiment) {
|
||||||
|
return $.new("tr", [
|
||||||
|
$.new("td", experiment.name),
|
||||||
|
$.new("td", experiment.id),
|
||||||
|
$.new("td", experiment.description),
|
||||||
|
$.new("td", experiment.active),
|
||||||
|
$.new("td", experiment.endDate),
|
||||||
|
$.new("td", [
|
||||||
|
$.new("a", experiment.detailURL, null, {href : experiment.detailURL,})
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
modifiedPreferences: function modifiedPreferences(data) {
|
modifiedPreferences: function modifiedPreferences(data) {
|
||||||
$.append($("prefs-tbody"), sortedArrayFromObject(data).map(
|
$.append($("prefs-tbody"), sortedArrayFromObject(data).map(
|
||||||
function ([name, value]) {
|
function ([name, value]) {
|
||||||
|
|
|
@ -317,6 +317,39 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 class="major-section">
|
||||||
|
&aboutSupport.experimentsTitle;
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
&aboutSupport.experimentName;
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
&aboutSupport.experimentId;
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
&aboutSupport.experimentDescription;
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
&aboutSupport.experimentActive;
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
&aboutSupport.experimentEndDate;
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
&aboutSupport.experimentHomepage;
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="experiments-tbody">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<!-- - - - - - - - - - - - - - - - - - - - - -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -18,7 +18,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
"resource://gre/modules/Promise.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||||
"resource://gre/modules/Services.jsm");
|
"resource://gre/modules/Services.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
"resource://gre/modules/Promise.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
"resource://gre/modules/Task.jsm");
|
"resource://gre/modules/Task.jsm");
|
||||||
Components.utils.import("resource://gre/modules/Timer.jsm", this);
|
Components.utils.import("resource://gre/modules/Timer.jsm", this);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
Cu.import("resource://gre/modules/Promise.jsm");
|
||||||
|
|
||||||
let panel, anchor, arrow;
|
let panel, anchor, arrow;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,13 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource://gre/modules/CrashReports.jsm");
|
Cu.import("resource://gre/modules/CrashReports.jsm");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
let Experiments;
|
||||||
|
try {
|
||||||
|
Experiments = Cu.import("resource:///modules/experiments/Experiments.jsm").Experiments;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
// We use a preferences whitelist to make sure we only show preferences that
|
// We use a preferences whitelist to make sure we only show preferences that
|
||||||
// are useful for support and won't compromise the user's privacy. Note that
|
// are useful for support and won't compromise the user's privacy. Note that
|
||||||
// entries are *prefixes*: for example, "accessibility." applies to all prefs
|
// entries are *prefixes*: for example, "accessibility." applies to all prefs
|
||||||
|
@ -174,6 +181,18 @@ let dataProviders = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
experiments: function experiments(done) {
|
||||||
|
if (Experiments === undefined) {
|
||||||
|
done([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getExperiments promises experiment history
|
||||||
|
Experiments.instance().getExperiments().then(
|
||||||
|
experiments => done(experiments)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
modifiedPreferences: function modifiedPreferences(done) {
|
modifiedPreferences: function modifiedPreferences(done) {
|
||||||
function getPref(name) {
|
function getPref(name) {
|
||||||
let table = {};
|
let table = {};
|
||||||
|
|
|
@ -366,6 +366,9 @@ const SNAPSHOT_SCHEMA = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
experiments: {
|
||||||
|
type: "array",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,8 @@ const PREF_EM_AUTO_DISABLED_SCOPES = "extensions.autoDisableScopes";
|
||||||
const PREF_EM_SHOW_MISMATCH_UI = "extensions.showMismatchUI";
|
const PREF_EM_SHOW_MISMATCH_UI = "extensions.showMismatchUI";
|
||||||
const PREF_XPI_ENABLED = "xpinstall.enabled";
|
const PREF_XPI_ENABLED = "xpinstall.enabled";
|
||||||
const PREF_XPI_WHITELIST_REQUIRED = "xpinstall.whitelist.required";
|
const PREF_XPI_WHITELIST_REQUIRED = "xpinstall.whitelist.required";
|
||||||
|
const PREF_XPI_DIRECT_WHITELISTED = "xpinstall.whitelist.directRequest";
|
||||||
|
const PREF_XPI_FILE_WHITELISTED = "xpinstall.whitelist.fileRequest";
|
||||||
const PREF_XPI_PERMISSIONS_BRANCH = "xpinstall.";
|
const PREF_XPI_PERMISSIONS_BRANCH = "xpinstall.";
|
||||||
const PREF_XPI_UNPACK = "extensions.alwaysUnpack";
|
const PREF_XPI_UNPACK = "extensions.alwaysUnpack";
|
||||||
const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
|
const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
|
||||||
|
@ -3445,6 +3447,28 @@ var XPIProvider = {
|
||||||
return Prefs.getBoolPref(PREF_XPI_ENABLED, true);
|
return Prefs.getBoolPref(PREF_XPI_ENABLED, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to test whether installing XPI add-ons by direct URL requests is
|
||||||
|
* whitelisted.
|
||||||
|
*
|
||||||
|
* @return true if installing by direct requests is whitelisted
|
||||||
|
*/
|
||||||
|
isDirectRequestWhitelisted: function XPI_isDirectRequestWhitelisted() {
|
||||||
|
// Default to whitelisted if the preference does not exist.
|
||||||
|
return Prefs.getBoolPref(PREF_XPI_DIRECT_WHITELISTED, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to test whether installing XPI add-ons from file referrers is
|
||||||
|
* whitelisted.
|
||||||
|
*
|
||||||
|
* @return true if installing from file referrers is whitelisted
|
||||||
|
*/
|
||||||
|
isFileRequestWhitelisted: function XPI_isFileRequestWhitelisted() {
|
||||||
|
// Default to whitelisted if the preference does not exist.
|
||||||
|
return Prefs.getBoolPref(PREF_XPI_FILE_WHITELISTED, true);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to test whether installing XPI add-ons from a URI is allowed.
|
* Called to test whether installing XPI add-ons from a URI is allowed.
|
||||||
*
|
*
|
||||||
|
@ -3456,11 +3480,13 @@ var XPIProvider = {
|
||||||
if (!this.isInstallEnabled())
|
if (!this.isInstallEnabled())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Direct requests without a referrer are either whitelisted or blocked.
|
||||||
if (!aUri)
|
if (!aUri)
|
||||||
return true;
|
return this.isDirectRequestWhitelisted();
|
||||||
|
|
||||||
// file: and chrome: don't need whitelisted hosts
|
// Local referrers can be whitelisted.
|
||||||
if (aUri.schemeIs("chrome") || aUri.schemeIs("file"))
|
if (this.isFileRequestWhitelisted() &&
|
||||||
|
(aUri.schemeIs("chrome") || aUri.schemeIs("file")))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
this.importPermissions();
|
this.importPermissions();
|
||||||
|
|
|
@ -341,8 +341,10 @@ function DBAddonInternal(aLoaded) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
DBAddonInternal.prototype = {
|
function DBAddonInternalPrototype()
|
||||||
applyCompatibilityUpdate: function DBA_applyCompatibilityUpdate(aUpdate, aSyncCompatibility) {
|
{
|
||||||
|
this.applyCompatibilityUpdate =
|
||||||
|
function(aUpdate, aSyncCompatibility) {
|
||||||
this.targetApplications.forEach(function(aTargetApp) {
|
this.targetApplications.forEach(function(aTargetApp) {
|
||||||
aUpdate.targetApplications.forEach(function(aUpdateTarget) {
|
aUpdate.targetApplications.forEach(function(aUpdateTarget) {
|
||||||
if (aTargetApp.id == aUpdateTarget.id && (aSyncCompatibility ||
|
if (aTargetApp.id == aUpdateTarget.id && (aSyncCompatibility ||
|
||||||
|
@ -354,18 +356,21 @@ DBAddonInternal.prototype = {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
XPIProvider.updateAddonDisabledState(this);
|
XPIProvider.updateAddonDisabledState(this);
|
||||||
},
|
};
|
||||||
|
|
||||||
get inDatabase() {
|
this.toJSON =
|
||||||
return true;
|
function() {
|
||||||
},
|
|
||||||
|
|
||||||
toJSON: function() {
|
|
||||||
return copyProperties(this, PROP_JSON_FIELDS);
|
return copyProperties(this, PROP_JSON_FIELDS);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
DBAddonInternal.prototype.__proto__ = AddonInternal.prototype;
|
Object.defineProperty(this, "inDatabase",
|
||||||
|
{ get: function() { return true; },
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true });
|
||||||
|
}
|
||||||
|
DBAddonInternalPrototype.prototype = AddonInternal.prototype;
|
||||||
|
|
||||||
|
DBAddonInternal.prototype = new DBAddonInternalPrototype();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal interface: find an addon from an already loaded addonDB
|
* Internal interface: find an addon from an already loaded addonDB
|
||||||
|
|
|
@ -62,6 +62,8 @@ support-files =
|
||||||
[browser_installchrome.js]
|
[browser_installchrome.js]
|
||||||
[browser_localfile.js]
|
[browser_localfile.js]
|
||||||
[browser_localfile2.js]
|
[browser_localfile2.js]
|
||||||
|
[browser_localfile3.js]
|
||||||
|
[browser_localfile4.js]
|
||||||
[browser_multipackage.js]
|
[browser_multipackage.js]
|
||||||
[browser_navigateaway.js]
|
[browser_navigateaway.js]
|
||||||
[browser_navigateaway2.js]
|
[browser_navigateaway2.js]
|
||||||
|
@ -84,3 +86,4 @@ support-files =
|
||||||
[browser_whitelist4.js]
|
[browser_whitelist4.js]
|
||||||
[browser_whitelist5.js]
|
[browser_whitelist5.js]
|
||||||
[browser_whitelist6.js]
|
[browser_whitelist6.js]
|
||||||
|
[browser_whitelist7.js]
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Tests installing an add-on from a local file with whitelisting disabled.
|
||||||
|
// This should be blocked by the whitelist check.
|
||||||
|
function test() {
|
||||||
|
Harness.installBlockedCallback = allow_blocked;
|
||||||
|
Harness.installsCompletedCallback = finish_test;
|
||||||
|
Harness.setup();
|
||||||
|
|
||||||
|
// Disable direct request whitelisting, installing from file should be blocked.
|
||||||
|
Services.prefs.setBoolPref("xpinstall.whitelist.directRequest", false);
|
||||||
|
|
||||||
|
var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
|
||||||
|
.getService(Components.interfaces.nsIChromeRegistry);
|
||||||
|
|
||||||
|
var chromeroot = extractChromeRoot(gTestPath);
|
||||||
|
try {
|
||||||
|
var xpipath = cr.convertChromeURL(makeURI(chromeroot + "unsigned.xpi")).spec;
|
||||||
|
} catch (ex) {
|
||||||
|
var xpipath = chromeroot + "unsigned.xpi"; //scenario where we are running from a .jar and already extracted
|
||||||
|
}
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(xpipath);
|
||||||
|
}
|
||||||
|
|
||||||
|
function allow_blocked(installInfo) {
|
||||||
|
ok(true, "Seen blocked");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function finish_test(count) {
|
||||||
|
is(count, 0, "No add-ons should have been installed");
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref("xpinstall.whitelist.directRequest");
|
||||||
|
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
Harness.finish();
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Tests installing an add-on from a local file with whitelisting disabled.
|
||||||
|
// This should be blocked by the whitelist check.
|
||||||
|
function test() {
|
||||||
|
Harness.installBlockedCallback = allow_blocked;
|
||||||
|
Harness.installsCompletedCallback = finish_test;
|
||||||
|
Harness.setup();
|
||||||
|
|
||||||
|
// Disable file request whitelisting, installing by file referrer should be blocked.
|
||||||
|
Services.prefs.setBoolPref("xpinstall.whitelist.fileRequest", false);
|
||||||
|
|
||||||
|
var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
|
||||||
|
.getService(Components.interfaces.nsIChromeRegistry);
|
||||||
|
|
||||||
|
var chromeroot = extractChromeRoot(gTestPath);
|
||||||
|
try {
|
||||||
|
var xpipath = cr.convertChromeURL(makeURI(chromeroot)).spec;
|
||||||
|
} catch (ex) {
|
||||||
|
var xpipath = chromeroot; //scenario where we are running from a .jar and already extracted
|
||||||
|
}
|
||||||
|
var triggers = encodeURIComponent(JSON.stringify({
|
||||||
|
"Unsigned XPI": TESTROOT + "unsigned.xpi"
|
||||||
|
}));
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(xpipath + "installtrigger.html?" + triggers);
|
||||||
|
}
|
||||||
|
|
||||||
|
function allow_blocked(installInfo) {
|
||||||
|
ok(true, "Seen blocked");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function finish_test(count) {
|
||||||
|
is(count, 0, "No add-ons should have been installed");
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref("xpinstall.whitelist.fileRequest");
|
||||||
|
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
Harness.finish();
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Tests installing an unsigned add-on through a direct install request from
|
||||||
|
// web content. This should be blocked by the whitelist check because we disable
|
||||||
|
// direct request whitelisting, even though the target URI is whitelisted.
|
||||||
|
function test() {
|
||||||
|
Harness.installBlockedCallback = allow_blocked;
|
||||||
|
Harness.installsCompletedCallback = finish_test;
|
||||||
|
Harness.setup();
|
||||||
|
|
||||||
|
// Disable direct request whitelisting, installing should be blocked.
|
||||||
|
Services.prefs.setBoolPref("xpinstall.whitelist.directRequest", false);
|
||||||
|
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(TESTROOT + "unsigned.xpi");
|
||||||
|
}
|
||||||
|
|
||||||
|
function allow_blocked(installInfo) {
|
||||||
|
ok(true, "Seen blocked");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function finish_test(count) {
|
||||||
|
is(count, 0, "No add-ons should have been installed");
|
||||||
|
|
||||||
|
Services.perms.remove("example.org", "install");
|
||||||
|
Services.prefs.clearUserPref("xpinstall.whitelist.directRequest");
|
||||||
|
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
Harness.finish();
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче