Merge m-c to inbound, a=merge CLOSED TREE
MozReview-Commit-ID: 4SEUTTY9jRn
1
.hgtags
@ -124,3 +124,4 @@ fcef8ded82219c89298b4e376cfbdfba79a1d35a FIREFOX_AURORA_43_BASE
|
||||
67a788db9f07822cfef52351bbbe3745dff8bd7f FIREFOX_AURORA_44_BASE
|
||||
99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
|
||||
67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
|
||||
68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
|
||||
|
1
CLOBBER
@ -23,4 +23,3 @@
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1250297 - Doesn't actually need a clobber, but updating the tree to an older changeset does.
|
||||
|
||||
|
@ -1403,8 +1403,7 @@ var BookmarkingUI = {
|
||||
extraCSSClass);
|
||||
item.addEventListener("command", onItemCommand);
|
||||
if (icon) {
|
||||
let iconURL = "moz-anno:favicon:" + icon;
|
||||
item.setAttribute("image", iconURL);
|
||||
item.setAttribute("image", icon);
|
||||
}
|
||||
fragment.appendChild(item);
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ support-files =
|
||||
searchSuggestionEngine.xml
|
||||
searchSuggestionEngine2.xml
|
||||
subtst_contextmenu.html
|
||||
subtst_contextmenu_input.html
|
||||
test-mixedcontent-securityerrors.html
|
||||
test_bug435035.html
|
||||
test_bug462673.html
|
||||
@ -294,6 +295,8 @@ skip-if = os == 'win'
|
||||
[browser_contentAreaClick.js]
|
||||
[browser_contextmenu.js]
|
||||
skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
|
||||
[browser_contextmenu_input.js]
|
||||
skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
|
||||
[browser_ctrlTab.js]
|
||||
[browser_datachoices_notification.js]
|
||||
skip-if = !datareporting
|
||||
@ -412,12 +415,12 @@ run-if = e10s
|
||||
[browser_subframe_favicons_not_used.js]
|
||||
[browser_syncui.js]
|
||||
[browser_tabDrop.js]
|
||||
skip-if = buildapp == 'mulet' || e10s
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_tabReorder.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_tabMatchesInAwesomebar.js]
|
||||
[browser_tabMatchesInAwesomebar_perwindowpb.js]
|
||||
skip-if = e10s || os == 'linux' # Bug 1093373, bug 1104755
|
||||
skip-if = os == 'linux' # Bug 1104755
|
||||
[browser_tab_detach_restore.js]
|
||||
[browser_tab_drag_drop_perwindow.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
@ -475,7 +478,6 @@ support-files =
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_unknownContentType_title.js]
|
||||
[browser_unloaddialogs.js]
|
||||
skip-if = e10s # Bug 1100700 - test relies on unload event firing on closed tabs, which it doesn't
|
||||
[browser_urlHighlight.js]
|
||||
[browser_urlbarAutoFillTrimURLs.js]
|
||||
[browser_urlbarCopying.js]
|
||||
|
@ -786,105 +786,6 @@ add_task(function* test_cleanup() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
let lastElementSelector = null;
|
||||
|
||||
/**
|
||||
* Right-clicks on the element that matches `selector` and checks the
|
||||
* context menu that appears against the `menuItems` array.
|
||||
*
|
||||
* @param {String} selector
|
||||
* A selector passed to querySelector to find
|
||||
* the element that will be referenced.
|
||||
* @param {Array} menuItems
|
||||
* An array of menuitem ids and their associated enabled state. A state
|
||||
* of null means that it will be ignored. Ids of '---' are used for
|
||||
* menuseparators.
|
||||
* @param {Object} options, optional
|
||||
* skipFocusChange: don't move focus to the element before test, useful
|
||||
* if you want to delay spell-check initialization
|
||||
* offsetX: horizontal mouse offset from the top-left corner of
|
||||
* the element, optional
|
||||
* offsetY: vertical mouse offset from the top-left corner of the
|
||||
* element, optional
|
||||
* centered: if true, mouse position is centered in element, defaults
|
||||
* to true if offsetX and offsetY are not provided
|
||||
* waitForSpellCheck: wait until spellcheck is initialized before
|
||||
* starting test
|
||||
* preCheckContextMenuFn: callback to run before opening menu
|
||||
* postCheckContextMenuFn: callback to run after opening menu
|
||||
* @return {Promise} resolved after the test finishes
|
||||
*/
|
||||
function* test_contextmenu(selector, menuItems, options={}) {
|
||||
contextMenu = document.getElementById("contentAreaContextMenu");
|
||||
is(contextMenu.state, "closed", "checking if popup is closed");
|
||||
|
||||
// Default to centered if no positioning is defined.
|
||||
if (!options.offsetX && !options.offsetY) {
|
||||
options.centered = true;
|
||||
}
|
||||
|
||||
if (!options.skipFocusChange) {
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser,
|
||||
{lastElementSelector, selector},
|
||||
function*({lastElementSelector, selector}) {
|
||||
if (lastElementSelector) {
|
||||
let lastElement = content.document.querySelector(lastElementSelector);
|
||||
lastElement.blur();
|
||||
}
|
||||
let element = content.document.querySelector(selector);
|
||||
element.focus();
|
||||
});
|
||||
lastElementSelector = selector;
|
||||
info(`Moved focus to ${selector}`);
|
||||
}
|
||||
|
||||
if (options.waitForSpellCheck) {
|
||||
info("Waiting for spell check");
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, selector, function*(selector) {
|
||||
let {onSpellCheck} = Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", {});
|
||||
let element = content.document.querySelector(selector);
|
||||
yield new Promise(resolve => onSpellCheck(element, resolve));
|
||||
info("Spell check running");
|
||||
});
|
||||
}
|
||||
|
||||
if (options.preCheckContextMenuFn) {
|
||||
yield options.preCheckContextMenuFn();
|
||||
info("Completed preCheckContextMenuFn");
|
||||
}
|
||||
|
||||
let awaitPopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
yield BrowserTestUtils.synthesizeMouse(selector, options.offsetX || 0, options.offsetY || 0, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
shiftkey: options.shiftkey,
|
||||
centered: options.centered
|
||||
},
|
||||
gBrowser.selectedBrowser);
|
||||
yield awaitPopupShown;
|
||||
info("Popup Shown");
|
||||
|
||||
if (menuItems) {
|
||||
if (Services.prefs.getBoolPref("devtools.inspector.enabled")) {
|
||||
let inspectItems = ["---", null,
|
||||
"context-inspect", true];
|
||||
menuItems = menuItems.concat(inspectItems);
|
||||
}
|
||||
|
||||
checkContextMenu(menuItems);
|
||||
}
|
||||
|
||||
let awaitPopupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
|
||||
|
||||
if (options.postCheckContextMenuFn) {
|
||||
yield options.postCheckContextMenuFn();
|
||||
info("Completed postCheckContextMenuFn");
|
||||
}
|
||||
|
||||
contextMenu.hidePopup();
|
||||
yield awaitPopupHidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the text of the element that matches the provided `selector`
|
||||
*
|
||||
|
249
browser/base/content/test/general/browser_contextmenu_input.js
Normal file
@ -0,0 +1,249 @@
|
||||
"use strict";
|
||||
|
||||
let contextMenu;
|
||||
add_task(function* test_setup() {
|
||||
const example_base = "http://example.com/browser/browser/base/content/test/general/";
|
||||
const url = example_base + "subtst_contextmenu_input.html";
|
||||
yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
|
||||
const chrome_base = "chrome://mochitests/content/browser/browser/base/content/test/general/";
|
||||
const contextmenu_common = chrome_base + "contextmenu_common.js";
|
||||
Services.scriptloader.loadSubScript(contextmenu_common, this);
|
||||
});
|
||||
|
||||
add_task(function* test_text_input() {
|
||||
yield test_contextmenu("#input_text",
|
||||
["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", false,
|
||||
"---", null,
|
||||
"spell-check-enabled", true]);
|
||||
});
|
||||
|
||||
add_task(function* test_text_input_spellcheck() {
|
||||
yield test_contextmenu("#input_spellcheck_no_value",
|
||||
["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", false,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"spell-dictionaries", true,
|
||||
["spell-check-dictionary-en-US", true,
|
||||
"---", null,
|
||||
"spell-add-dictionaries", true], null],
|
||||
{
|
||||
waitForSpellCheck: true,
|
||||
// Need to dynamically add/remove the "password" type or LoginManager
|
||||
// will think that the form inputs on the page are part of a login
|
||||
// and will add fill-login context menu items.
|
||||
*preCheckContextMenuFn() {
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
|
||||
let doc = content.document;
|
||||
let input = doc.getElementById("input_spellcheck_no_value");
|
||||
input.setAttribute("spellcheck", "true");
|
||||
input.clientTop; // force layout flush
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_text_input_spellcheckwrong() {
|
||||
yield test_contextmenu("#input_spellcheck_incorrect",
|
||||
["*prodigality", true, // spelling suggestion
|
||||
"spell-add-to-dictionary", true,
|
||||
"---", null,
|
||||
"context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"spell-dictionaries", true,
|
||||
["spell-check-dictionary-en-US", true,
|
||||
"---", null,
|
||||
"spell-add-dictionaries", true], null],
|
||||
{waitForSpellCheck: true}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_text_input_spellcheckcorrect() {
|
||||
yield test_contextmenu("#input_spellcheck_correct",
|
||||
["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"spell-dictionaries", true,
|
||||
["spell-check-dictionary-en-US", true,
|
||||
"---", null,
|
||||
"spell-add-dictionaries", true], null],
|
||||
{waitForSpellCheck: true}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_text_input_disabled() {
|
||||
yield test_contextmenu("#input_disabled",
|
||||
["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"spell-check-enabled", true],
|
||||
{skipFocusChange: true}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_password_input() {
|
||||
todo(false, "context-selectall is enabled on osx-e10s, and windows when" +
|
||||
" it should be disabled");
|
||||
yield test_contextmenu("#input_password",
|
||||
["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", null,
|
||||
"---", null,
|
||||
"fill-login", null,
|
||||
["fill-login-no-logins", false,
|
||||
"---", null,
|
||||
"fill-login-saved-passwords", true], null],
|
||||
{
|
||||
skipFocusChange: true,
|
||||
// Need to dynamically add/remove the "password" type or LoginManager
|
||||
// will think that the form inputs on the page are part of a login
|
||||
// and will add fill-login context menu items.
|
||||
*preCheckContextMenuFn() {
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
|
||||
let doc = content.document;
|
||||
let input = doc.getElementById("input_password");
|
||||
input.type = "password";
|
||||
input.clientTop; // force layout flush
|
||||
});
|
||||
},
|
||||
*postCheckContextMenuFn() {
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
|
||||
let doc = content.document;
|
||||
let input = doc.getElementById("input_password");
|
||||
input.type = "text";
|
||||
input.clientTop; // force layout flush
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_tel_email_url_number_input() {
|
||||
todo(false, "context-selectall is enabled on osx-e10s, and windows when" +
|
||||
" it should be disabled");
|
||||
for (let selector of ["#input_email", "#input_url", "#input_tel", "#input_number"]) {
|
||||
yield test_contextmenu(selector,
|
||||
["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", null],
|
||||
{skipFocusChange: true}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_date_time_color_range_input() {
|
||||
for (let selector of ["#input_date", "#input_time", "#input_color", "#input_range"]) {
|
||||
yield test_contextmenu(selector,
|
||||
["context-navigation", null,
|
||||
["context-back", false,
|
||||
"context-forward", false,
|
||||
"context-reload", true,
|
||||
"context-bookmarkpage", true], null,
|
||||
"---", null,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
"context-selectall", null,
|
||||
"---", null,
|
||||
"context-viewsource", true,
|
||||
"context-viewinfo", true],
|
||||
{skipFocusChange: true}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_search_input() {
|
||||
todo(false, "context-selectall is enabled on osx-e10s, and windows when" +
|
||||
" it should be disabled");
|
||||
yield test_contextmenu("#input_search",
|
||||
["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", null,
|
||||
"---", null,
|
||||
"spell-check-enabled", true],
|
||||
{skipFocusChange: true}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_datetime_month_week_datetimelocal_input_todos() {
|
||||
for (let type of ["datetime", "month", "week", "datetime-local"]) {
|
||||
let returnedType = yield ContentTask.spawn(gBrowser.selectedBrowser, type, function*(type) {
|
||||
let doc = content.document;
|
||||
let input = doc.getElementById("input_" + type);
|
||||
return input.type;
|
||||
});
|
||||
todo_is(returnedType, type, `TODO: add test for ${type} input fields`);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_text_input_readonly() {
|
||||
todo(false, "context-selectall is enabled on osx-e10s, and windows when" +
|
||||
" it should be disabled");
|
||||
todo(false, "spell-check should not be enabled for input[readonly]. see bug 1246296");
|
||||
yield test_contextmenu("#input_readonly",
|
||||
["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", null],
|
||||
{skipFocusChange: true}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_cleanup() {
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
@ -1,77 +1,61 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
registerCleanupFunction(function* cleanup() {
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
yield BrowserTestUtils.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]);
|
||||
}
|
||||
Services.search.currentEngine = originalEngine;
|
||||
let engine = Services.search.getEngineByName("MozSearch");
|
||||
Services.search.removeEngine(engine);
|
||||
});
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
let originalEngine;
|
||||
add_task(function* test_setup() {
|
||||
// Stop search-engine loads from hitting the network
|
||||
Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET",
|
||||
"http://example.com/?q={searchTerms}");
|
||||
let engine = Services.search.getEngineByName("MozSearch");
|
||||
originalEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
});
|
||||
|
||||
let newTab = gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true});
|
||||
registerCleanupFunction(function () {
|
||||
gBrowser.removeTab(newTab);
|
||||
});
|
||||
add_task(function*() { yield drop("mochi.test/first", true); });
|
||||
add_task(function*() { yield drop("javascript:'bad'"); });
|
||||
add_task(function*() { yield drop("jAvascript:'bad'"); });
|
||||
add_task(function*() { yield drop("search this", true); });
|
||||
add_task(function*() { yield drop("mochi.test/second", true); });
|
||||
add_task(function*() { yield drop("data:text/html,bad"); });
|
||||
add_task(function*() { yield drop("mochi.test/third", true); });
|
||||
|
||||
function* drop(text, valid = false) {
|
||||
info(`Starting test for text:${text}; valid:${valid}`);
|
||||
let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let ChromeUtils = {};
|
||||
scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", ChromeUtils);
|
||||
|
||||
let tabContainer = gBrowser.tabContainer;
|
||||
var receivedDropCount = 0;
|
||||
function dropListener() {
|
||||
receivedDropCount++;
|
||||
if (receivedDropCount == triggeredDropCount) {
|
||||
is(openedTabs, validDropCount, "correct number of tabs were opened");
|
||||
executeSoon(finish);
|
||||
}
|
||||
let awaitDrop = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "drop");
|
||||
let awaitTabOpen = valid && BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
|
||||
// A drop type of "link" onto an existing tab would normally trigger a
|
||||
// load in that same tab, but tabbrowser code in _getDragTargetTab treats
|
||||
// drops on the outer edges of a tab differently (loading a new tab
|
||||
// instead). Make events created by synthesizeDrop have all of their
|
||||
// coordinates set to 0 (screenX/screenY), so they're treated as drops
|
||||
// on the outer edge of the tab, thus they open new tabs.
|
||||
var event = {
|
||||
clientX: 0,
|
||||
clientY: 0,
|
||||
screenX: 0,
|
||||
screenY: 0,
|
||||
};
|
||||
ChromeUtils.synthesizeDrop(gBrowser.selectedTab, gBrowser.selectedTab, [[{type: "text/plain", data: text}]], "link", window, undefined, event);
|
||||
let tabOpened = false;
|
||||
if (awaitTabOpen) {
|
||||
let tabOpenEvent = yield awaitTabOpen;
|
||||
info("Got TabOpen event");
|
||||
tabOpened = true;
|
||||
yield BrowserTestUtils.removeTab(tabOpenEvent.target);
|
||||
}
|
||||
tabContainer.addEventListener("drop", dropListener, false);
|
||||
registerCleanupFunction(function () {
|
||||
tabContainer.removeEventListener("drop", dropListener, false);
|
||||
});
|
||||
is(tabOpened, valid, `Tab for ${text} should only open if valid`);
|
||||
|
||||
var openedTabs = 0;
|
||||
function tabOpenListener(e) {
|
||||
openedTabs++;
|
||||
let tab = e.target;
|
||||
executeSoon(function () {
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
}
|
||||
|
||||
tabContainer.addEventListener("TabOpen", tabOpenListener, false);
|
||||
registerCleanupFunction(function () {
|
||||
tabContainer.removeEventListener("TabOpen", tabOpenListener, false);
|
||||
});
|
||||
|
||||
var triggeredDropCount = 0;
|
||||
var validDropCount = 0;
|
||||
function drop(text, valid) {
|
||||
triggeredDropCount++;
|
||||
if (valid)
|
||||
validDropCount++;
|
||||
executeSoon(function () {
|
||||
// A drop type of "link" onto an existing tab would normally trigger a
|
||||
// load in that same tab, but tabbrowser code in _getDragTargetTab treats
|
||||
// drops on the outer edges of a tab differently (loading a new tab
|
||||
// instead). Make events created by synthesizeDrop have all of their
|
||||
// coordinates set to 0 (screenX/screenY), so they're treated as drops
|
||||
// on the outer edge of the tab, thus they open new tabs.
|
||||
var event = {
|
||||
clientX: 0,
|
||||
clientY: 0,
|
||||
screenX: 0,
|
||||
screenY: 0,
|
||||
};
|
||||
ChromeUtils.synthesizeDrop(newTab, newTab, [[{type: "text/plain", data: text}]], "link", window, undefined, event);
|
||||
});
|
||||
}
|
||||
|
||||
// Begin and end with valid drops to make sure we wait for all drops before
|
||||
// ending the test
|
||||
drop("mochi.test/first", true);
|
||||
drop("javascript:'bad'");
|
||||
drop("jAvascript:'bad'");
|
||||
drop("search this", true);
|
||||
drop("mochi.test/second", true);
|
||||
drop("data:text/html,bad");
|
||||
drop("mochi.test/third", true);
|
||||
yield awaitDrop;
|
||||
ok(true, "Got drop event");
|
||||
}
|
||||
|
@ -1,106 +1,84 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
let testURL = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
add_task(function*() {
|
||||
let normalWindow = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
let privateWindow = yield BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
yield runTest(normalWindow, privateWindow, false);
|
||||
yield BrowserTestUtils.closeWindow(normalWindow);
|
||||
yield BrowserTestUtils.closeWindow(privateWindow);
|
||||
|
||||
let testURL = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
|
||||
normalWindow = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
privateWindow = yield BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
yield runTest(privateWindow, normalWindow, false);
|
||||
yield BrowserTestUtils.closeWindow(normalWindow);
|
||||
yield BrowserTestUtils.closeWindow(privateWindow);
|
||||
|
||||
function testOnWindow(aOptions, aCallback) {
|
||||
whenNewWindowLoaded(aOptions, function(aWin) {
|
||||
// execute should only be called when need, like when you are opening
|
||||
// web pages on the test. If calling executeSoon() is not necesary, then
|
||||
// call whenNewWindowLoaded() instead of testOnWindow() on your test.
|
||||
executeSoon(() => aCallback(aWin));
|
||||
});
|
||||
};
|
||||
privateWindow = yield BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
yield runTest(privateWindow, privateWindow, false);
|
||||
yield BrowserTestUtils.closeWindow(privateWindow);
|
||||
|
||||
testOnWindow({}, function(aNormalWindow) {
|
||||
testOnWindow({private: true}, function(aPrivateWindow) {
|
||||
runTest(aNormalWindow, aPrivateWindow, false, function() {
|
||||
aNormalWindow.close();
|
||||
aPrivateWindow.close();
|
||||
testOnWindow({}, function(aNormalWindow) {
|
||||
testOnWindow({private: true}, function(aPrivateWindow) {
|
||||
runTest(aPrivateWindow, aNormalWindow, false, function() {
|
||||
aNormalWindow.close();
|
||||
aPrivateWindow.close();
|
||||
testOnWindow({private: true}, function(aPrivateWindow) {
|
||||
runTest(aPrivateWindow, aPrivateWindow, false, function() {
|
||||
aPrivateWindow.close();
|
||||
testOnWindow({}, function(aNormalWindow) {
|
||||
runTest(aNormalWindow, aNormalWindow, true, function() {
|
||||
aNormalWindow.close();
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
normalWindow = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
yield runTest(normalWindow, normalWindow, true);
|
||||
yield BrowserTestUtils.closeWindow(normalWindow);
|
||||
});
|
||||
|
||||
function* runTest(aSourceWindow, aDestWindow, aExpectSwitch, aCallback) {
|
||||
let baseTab = yield BrowserTestUtils.openNewForegroundTab(aSourceWindow.gBrowser, testURL);
|
||||
let testTab = yield BrowserTestUtils.openNewForegroundTab(aDestWindow.gBrowser);
|
||||
|
||||
info("waiting for focus on the window");
|
||||
yield promiseWaitForFocus(aDestWindow);
|
||||
info("got focus on the window");
|
||||
|
||||
// Select the testTab
|
||||
aDestWindow.gBrowser.selectedTab = testTab;
|
||||
|
||||
// Ensure that this tab has no history entries
|
||||
let sessionHistoryCount = yield new Promise(resolve => {
|
||||
SessionStore.getSessionHistory(gBrowser.selectedTab, function(sessionHistory) {
|
||||
resolve(sessionHistory.entries.length);
|
||||
});
|
||||
});
|
||||
|
||||
function runTest(aSourceWindow, aDestWindow, aExpectSwitch, aCallback) {
|
||||
// Open the base tab
|
||||
let baseTab = aSourceWindow.gBrowser.addTab(testURL);
|
||||
baseTab.linkedBrowser.addEventListener("load", function() {
|
||||
// Wait for the tab to be fully loaded so matching happens correctly
|
||||
if (baseTab.linkedBrowser.currentURI.spec == "about:blank")
|
||||
return;
|
||||
baseTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
ok(sessionHistoryCount < 2,
|
||||
`The test tab has 1 or fewer history entries. sessionHistoryCount=${sessionHistoryCount}`);
|
||||
// Ensure that this tab is on about:blank
|
||||
is(testTab.linkedBrowser.currentURI.spec, "about:blank",
|
||||
"The test tab is on about:blank");
|
||||
// Ensure that this tab's document has no child nodes
|
||||
yield ContentTask.spawn(testTab.linkedBrowser, null, function*() {
|
||||
ok(!content.document.body.hasChildNodes(),
|
||||
"The test tab has no child nodes");
|
||||
});
|
||||
ok(!testTab.hasAttribute("busy"),
|
||||
"The test tab doesn't have the busy attribute");
|
||||
|
||||
let testTab = aDestWindow.gBrowser.addTab();
|
||||
// Wait for the Awesomebar popup to appear.
|
||||
yield promiseAutocompleteResultPopup(testURL, aDestWindow);
|
||||
|
||||
waitForFocus(function() {
|
||||
// Select the testTab
|
||||
aDestWindow.gBrowser.selectedTab = testTab;
|
||||
info(`awesomebar popup appeared. aExpectSwitch: ${aExpectSwitch}`);
|
||||
// Make sure the last match is selected.
|
||||
let {controller, popup} = aDestWindow.gURLBar;
|
||||
while (popup.selectedIndex < controller.matchCount - 1) {
|
||||
info("handling key navigation for DOM_VK_DOWN key");
|
||||
controller.handleKeyNavigation(KeyEvent.DOM_VK_DOWN);
|
||||
}
|
||||
|
||||
// Ensure that this tab has no history entries
|
||||
ok(testTab.linkedBrowser.sessionHistory.count < 2,
|
||||
"The test tab has 1 or less history entries");
|
||||
// Ensure that this tab is on about:blank
|
||||
is(testTab.linkedBrowser.currentURI.spec, "about:blank",
|
||||
"The test tab is on about:blank");
|
||||
// Ensure that this tab's document has no child nodes
|
||||
ok(!testTab.linkedBrowser.contentDocument.body.hasChildNodes(),
|
||||
"The test tab has no child nodes");
|
||||
ok(!testTab.hasAttribute("busy"),
|
||||
"The test tab doesn't have the busy attribute");
|
||||
let awaitTabSwitch;
|
||||
if (aExpectSwitch) {
|
||||
awaitTabSwitch = BrowserTestUtils.removeTab(testTab, {dontRemove: true})
|
||||
}
|
||||
|
||||
// Wait for the Awesomebar popup to appear.
|
||||
promiseAutocompleteResultPopup(testURL, aDestWindow).then(() => {
|
||||
if (aExpectSwitch) {
|
||||
// If we expect a tab switch then the current tab
|
||||
// will be closed and we switch to the other tab.
|
||||
let tabContainer = aDestWindow.gBrowser.tabContainer;
|
||||
tabContainer.addEventListener("TabClose", function onClose(event) {
|
||||
if (event.target == testTab) {
|
||||
tabContainer.removeEventListener("TabClose", onClose);
|
||||
executeSoon(aCallback);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// If we don't expect a tab switch then wait for the tab to load.
|
||||
testTab.addEventListener("load", function onLoad() {
|
||||
testTab.removeEventListener("load", onLoad, true);
|
||||
executeSoon(aCallback);
|
||||
}, true);
|
||||
}
|
||||
// Execute the selected action.
|
||||
controller.handleEnter(true);
|
||||
info("sent Enter command to the controller");
|
||||
|
||||
// Make sure the last match is selected.
|
||||
let {controller, popup} = aDestWindow.gURLBar;
|
||||
while (popup.selectedIndex < controller.matchCount - 1) {
|
||||
controller.handleKeyNavigation(KeyEvent.DOM_VK_DOWN);
|
||||
}
|
||||
|
||||
// Execute the selected action.
|
||||
controller.handleEnter(true);
|
||||
});
|
||||
}, aDestWindow);
|
||||
}, true);
|
||||
if (aExpectSwitch) {
|
||||
// If we expect a tab switch then the current tab
|
||||
// will be closed and we switch to the other tab.
|
||||
yield awaitTabSwitch;
|
||||
} else {
|
||||
// If we don't expect a tab switch then wait for the tab to load.
|
||||
yield BrowserTestUtils.browserLoaded(testTab.linkedBrowser);
|
||||
}
|
||||
}
|
||||
|
@ -28,46 +28,14 @@ var testUrls =
|
||||
"window.addEventListener('unload', handle, true);" +
|
||||
"</script><body>Testing confirm during pagehide/beforeunload/unload</body>",
|
||||
];
|
||||
var testsDone = 0;
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
runTest();
|
||||
}
|
||||
|
||||
function runTest()
|
||||
{
|
||||
whenNewTabLoaded(window, function() {
|
||||
gBrowser.selectedBrowser.addEventListener("load", onLoad, true);
|
||||
executeSoon(function() {
|
||||
info("Loading page with pagehide, beforeunload, and unload handlers that attempt to create dialogs");
|
||||
gBrowser.selectedBrowser.loadURI(testUrls[testsDone]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onLoad(event)
|
||||
{
|
||||
info("Page loaded");
|
||||
|
||||
event.target.removeEventListener("load", onLoad, true);
|
||||
gBrowser.selectedBrowser.addEventListener("unload", done, true);
|
||||
|
||||
executeSoon(function () {
|
||||
info("Closing page");
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
}
|
||||
|
||||
function done() {
|
||||
ok(true, "Page closed (hopefully) without timeout");
|
||||
|
||||
testsDone++;
|
||||
if (testsDone == testUrls.length) {
|
||||
finish();
|
||||
return;
|
||||
add_task(function*() {
|
||||
for (let url of testUrls) {
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
ok(true, "Loaded page " + url);
|
||||
// Wait one turn of the event loop before closing, so everything settles.
|
||||
yield new Promise(resolve => setTimeout(resolve, 0));
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
ok(true, "Closed page " + url + " without timeout");
|
||||
}
|
||||
|
||||
executeSoon(runTest);
|
||||
}
|
||||
});
|
||||
|
@ -216,3 +216,101 @@ function checkMenu(menu, expectedItems, data) {
|
||||
// Could find unexpected extra items at the end...
|
||||
is(actualItems.length, expectedItems.length, "checking expected number of menu entries");
|
||||
}
|
||||
|
||||
let lastElementSelector = null;
|
||||
/**
|
||||
* Right-clicks on the element that matches `selector` and checks the
|
||||
* context menu that appears against the `menuItems` array.
|
||||
*
|
||||
* @param {String} selector
|
||||
* A selector passed to querySelector to find
|
||||
* the element that will be referenced.
|
||||
* @param {Array} menuItems
|
||||
* An array of menuitem ids and their associated enabled state. A state
|
||||
* of null means that it will be ignored. Ids of '---' are used for
|
||||
* menuseparators.
|
||||
* @param {Object} options, optional
|
||||
* skipFocusChange: don't move focus to the element before test, useful
|
||||
* if you want to delay spell-check initialization
|
||||
* offsetX: horizontal mouse offset from the top-left corner of
|
||||
* the element, optional
|
||||
* offsetY: vertical mouse offset from the top-left corner of the
|
||||
* element, optional
|
||||
* centered: if true, mouse position is centered in element, defaults
|
||||
* to true if offsetX and offsetY are not provided
|
||||
* waitForSpellCheck: wait until spellcheck is initialized before
|
||||
* starting test
|
||||
* preCheckContextMenuFn: callback to run before opening menu
|
||||
* postCheckContextMenuFn: callback to run after opening menu
|
||||
* @return {Promise} resolved after the test finishes
|
||||
*/
|
||||
function* test_contextmenu(selector, menuItems, options={}) {
|
||||
contextMenu = document.getElementById("contentAreaContextMenu");
|
||||
is(contextMenu.state, "closed", "checking if popup is closed");
|
||||
|
||||
// Default to centered if no positioning is defined.
|
||||
if (!options.offsetX && !options.offsetY) {
|
||||
options.centered = true;
|
||||
}
|
||||
|
||||
if (!options.skipFocusChange) {
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser,
|
||||
{lastElementSelector, selector},
|
||||
function*({lastElementSelector, selector}) {
|
||||
if (lastElementSelector) {
|
||||
let lastElement = content.document.querySelector(lastElementSelector);
|
||||
lastElement.blur();
|
||||
}
|
||||
let element = content.document.querySelector(selector);
|
||||
element.focus();
|
||||
});
|
||||
lastElementSelector = selector;
|
||||
info(`Moved focus to ${selector}`);
|
||||
}
|
||||
|
||||
if (options.preCheckContextMenuFn) {
|
||||
yield options.preCheckContextMenuFn();
|
||||
info("Completed preCheckContextMenuFn");
|
||||
}
|
||||
|
||||
if (options.waitForSpellCheck) {
|
||||
info("Waiting for spell check");
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, selector, function*(selector) {
|
||||
let {onSpellCheck} = Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", {});
|
||||
let element = content.document.querySelector(selector);
|
||||
yield new Promise(resolve => onSpellCheck(element, resolve));
|
||||
info("Spell check running");
|
||||
});
|
||||
}
|
||||
|
||||
let awaitPopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
yield BrowserTestUtils.synthesizeMouse(selector, options.offsetX || 0, options.offsetY || 0, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
shiftkey: options.shiftkey,
|
||||
centered: options.centered
|
||||
},
|
||||
gBrowser.selectedBrowser);
|
||||
yield awaitPopupShown;
|
||||
info("Popup Shown");
|
||||
|
||||
if (menuItems) {
|
||||
if (Services.prefs.getBoolPref("devtools.inspector.enabled")) {
|
||||
let inspectItems = ["---", null,
|
||||
"context-inspect", true];
|
||||
menuItems = menuItems.concat(inspectItems);
|
||||
}
|
||||
|
||||
checkContextMenu(menuItems);
|
||||
}
|
||||
|
||||
let awaitPopupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
|
||||
|
||||
if (options.postCheckContextMenuFn) {
|
||||
yield options.postCheckContextMenuFn();
|
||||
info("Completed postCheckContextMenuFn");
|
||||
}
|
||||
|
||||
contextMenu.hidePopup();
|
||||
yield awaitPopupHidden;
|
||||
}
|
||||
|
@ -28,8 +28,6 @@ support-files =
|
||||
|
||||
[test_bug364677.html]
|
||||
[test_bug395533.html]
|
||||
[test_contextmenu_input.html]
|
||||
skip-if = toolkit == "gtk2" || toolkit == "gtk3" || e10s # disabled on Linux due to bug 513558
|
||||
[test_feed_discovery.html]
|
||||
skip-if = e10s
|
||||
[test_offlineNotification.html]
|
||||
|
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Subtest for browser context menu</title>
|
||||
</head>
|
||||
<body>
|
||||
Browser context menu subtest.
|
||||
<input id="input_text">
|
||||
<input id="input_spellcheck_no_value">
|
||||
<input id="input_spellcheck_incorrect" spellcheck="true" value="prodkjfgigrty">
|
||||
<input id="input_spellcheck_correct" spellcheck="true" value="foo">
|
||||
<input id="input_disabled" disabled="true">
|
||||
<input id="input_password">
|
||||
<input id="input_email" type="email">
|
||||
<input id="input_tel" type="tel">
|
||||
<input id="input_url" type="url">
|
||||
<input id="input_number" type="number">
|
||||
<input id="input_date" type="date">
|
||||
<input id="input_time" type="time">
|
||||
<input id="input_color" type="color">
|
||||
<input id="input_range" type="range">
|
||||
<input id="input_search" type="search">
|
||||
<input id="input_datetime" type="datetime">
|
||||
<input id="input_month" type="month">
|
||||
<input id="input_week" type="week">
|
||||
<input id="input_datetime-local" type="datetime-local">
|
||||
<input id="input_readonly" readonly="true">
|
||||
</body>
|
||||
</html>
|
@ -1,364 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Tests for browser context menu</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
Browser context menu tests for input.
|
||||
<p id="display"></p>
|
||||
|
||||
<div id="content">
|
||||
</div>
|
||||
|
||||
<pre id="test">
|
||||
<script type="text/javascript" src="contextmenu_common.js"></script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
const Ci = SpecialPowers.Ci;
|
||||
|
||||
/*
|
||||
* runTest
|
||||
*
|
||||
* Called by a popupshowing event handler. Each test checks for expected menu
|
||||
* contents, closes the popup, and finally triggers the popup on a new element
|
||||
* (thus kicking off another cycle).
|
||||
*
|
||||
*/
|
||||
function runTest(testNum) {
|
||||
ok(true, "Starting test #" + testNum);
|
||||
|
||||
switch (testNum) {
|
||||
case 1:
|
||||
openContextMenuFor(input); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Context menu for text input field.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", false,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
closeContextMenu();
|
||||
input.setAttribute('spellcheck', 'true');
|
||||
// Invoke context menu for next test and wait for spell check to finish
|
||||
openContextMenuFor(input, false, true);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
var value = false;
|
||||
// Context menu for spell-check input.
|
||||
checkContextMenu(["context-undo", value,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", value,
|
||||
"---", null,
|
||||
"context-selectall", value,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"spell-dictionaries", true,
|
||||
["spell-check-dictionary-en-US", true,
|
||||
"---", null,
|
||||
"spell-add-dictionaries", true], null,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
|
||||
closeContextMenu();
|
||||
input.removeAttribute('spellcheck');
|
||||
// Invoke context menu for next test and wait for spell check to finish
|
||||
openContextMenuFor(inputspellwrong, false, true);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
var value = false;
|
||||
// Context menu for spell-check input with a unknwon word.
|
||||
checkContextMenu(["*prodigality", true, // spelling suggestion
|
||||
"spell-add-to-dictionary", true,
|
||||
"---", null,
|
||||
"context-undo", value,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", value,
|
||||
"---", null,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"spell-dictionaries", true,
|
||||
["spell-check-dictionary-en-US", true,
|
||||
"---", null,
|
||||
"spell-add-dictionaries", true], null,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
|
||||
closeContextMenu();
|
||||
// Invoke context menu for next test and wait for spell check to finish
|
||||
openContextMenuFor(inputspellcorrect, false, true);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
var value = false;
|
||||
// Context menu for spell-check input with a known word.
|
||||
checkContextMenu(["context-undo", value,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", value,
|
||||
"---", null,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"spell-dictionaries", true,
|
||||
["spell-check-dictionary-en-US", true,
|
||||
"---", null,
|
||||
"spell-add-dictionaries", true], null,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
|
||||
closeContextMenu();
|
||||
input.disabled = true;
|
||||
openContextMenuFor(input); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// Context menu for disabled input.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
|
||||
closeContextMenu();
|
||||
input.disabled = false;
|
||||
input.type = 'password';
|
||||
openContextMenuFor(input); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 7: // password
|
||||
// Context menu for password input fields.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", false,
|
||||
"---", null,
|
||||
"fill-login", null,
|
||||
["fill-login-no-logins", false,
|
||||
"---", null,
|
||||
"fill-login-saved-passwords", true], null,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
|
||||
closeContextMenu();
|
||||
|
||||
input.type = 'email';
|
||||
|
||||
openContextMenuFor(input); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 8: // email
|
||||
case 9: // url
|
||||
case 10: // tel
|
||||
case 11: // type='number'
|
||||
// Context menu for tel, email, url and number input fields.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", false,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
|
||||
closeContextMenu();
|
||||
|
||||
if (testNum == 8) {
|
||||
input.type = 'url';
|
||||
} else if (testNum == 9) {
|
||||
input.type = 'tel';
|
||||
} else if (testNum == 10) {
|
||||
input.type = 'number';
|
||||
} else if (testNum == 11) {
|
||||
input.type = 'date';
|
||||
}
|
||||
|
||||
openContextMenuFor(input); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 12: // type='date'
|
||||
case 13: // type='time'
|
||||
case 14: // type='color'
|
||||
case 15: // type='range'
|
||||
checkContextMenu(["context-navigation", null,
|
||||
["context-back", false,
|
||||
"context-forward", false,
|
||||
"context-reload", true,
|
||||
"context-bookmarkpage", true], null,
|
||||
"---", null,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
"context-selectall", null,
|
||||
"---", null,
|
||||
"context-viewsource", true,
|
||||
"context-viewinfo", true,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
closeContextMenu();
|
||||
|
||||
if (testNum == 12) {
|
||||
input.type = 'time';
|
||||
} else if (testNum == 13) {
|
||||
input.type = 'color';
|
||||
} else if (testNum == 14) {
|
||||
input.type = 'range';
|
||||
} else {
|
||||
input.type = 'search';
|
||||
}
|
||||
|
||||
openContextMenuFor(input);
|
||||
break;
|
||||
|
||||
case 16: // type='search'
|
||||
// Context menu for search input fields.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", false,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
|
||||
closeContextMenu();
|
||||
|
||||
// Add some todos to make sure all input fields got a test.
|
||||
var todos = [ "datetime", "month", "week", "datetime-local" ];
|
||||
todos.forEach(function(type) {
|
||||
input.type = type;
|
||||
todo_is(input.type, type, "TODO: add test for " + type + " input fields");
|
||||
});
|
||||
|
||||
input.type = 'text';
|
||||
input.readOnly = true;
|
||||
openContextMenuFor(input);
|
||||
break;
|
||||
|
||||
case 17:
|
||||
// Context menu for a read-only input.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", false,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
closeContextMenu();
|
||||
|
||||
// Clean-up.
|
||||
subwindow.close();
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
|
||||
default:
|
||||
ok(false, "Unexpected invocation of test #" + testNum);
|
||||
subwindow.close();
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
var gTestNum = 1;
|
||||
var subwindow, chromeWin, contextMenu;
|
||||
var input, inputspellwrong, inputspellcorrect;
|
||||
|
||||
function startTest() {
|
||||
chromeWin = SpecialPowers.wrap(subwindow)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow)
|
||||
.QueryInterface(Ci.nsIDOMChromeWindow);
|
||||
contextMenu = chromeWin.document.getElementById("contentAreaContextMenu");
|
||||
ok(contextMenu, "Got context menu XUL");
|
||||
|
||||
if (chromeWin.document.getElementById("Browser:Stop").getAttribute("disabled") != "true") {
|
||||
SimpleTest.executeSoon(startTest);
|
||||
return;
|
||||
}
|
||||
|
||||
var inputs = subwindow.document.getElementsByTagName('input');
|
||||
input = inputs[0];
|
||||
inputspellwrong = inputs[1];
|
||||
inputspellcorrect = inputs[2];
|
||||
|
||||
contextMenu.addEventListener("popupshown", function() { runTest(++gTestNum); }, false);
|
||||
runTest(1);
|
||||
}
|
||||
|
||||
// We open this in a separate window, because the Mochitests run inside a frame.
|
||||
// The frame causes an extra menu item, and prevents running the test
|
||||
// standalone (ie, clicking the test name in the Mochitest window) to see
|
||||
// success/failure messages.
|
||||
var painted = false, loaded = false;
|
||||
|
||||
function waitForEvents(event)
|
||||
{
|
||||
if (event.type == "MozAfterPaint")
|
||||
painted = true;
|
||||
else if (event.type == "load")
|
||||
loaded = true;
|
||||
if (painted && loaded) {
|
||||
subwindow.removeEventListener("MozAfterPaint", waitForEvents, false);
|
||||
subwindow.onload = null;
|
||||
SimpleTest.waitForFocus(startTest, subwindow);
|
||||
}
|
||||
}
|
||||
|
||||
var subwindow = window.open("data:text/html,<!DOCTYPE html><input><input spellcheck='true' value='prodkjfgigrty'><input spellcheck='true' value='foo'><input readonly spellcheck='false'>", "contextmenu-subtext", "width=600,height=700");
|
||||
subwindow.addEventListener("MozAfterPaint", waitForEvents, false);
|
||||
subwindow.onload = waitForEvents;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -66,7 +66,6 @@ skip-if = !crashreporter
|
||||
[browser_plugins_added_dynamically.js]
|
||||
[browser_pluginnotification.js]
|
||||
[browser_plugin_infolink.js]
|
||||
skip-if = (os == 'win' && os_version == "6.2" && e10s) # Win8 permafail in subsequent tests
|
||||
[browser_plugin_reloading.js]
|
||||
[browser_blocklist_content.js]
|
||||
skip-if = !e10s
|
||||
|
@ -1,47 +1,34 @@
|
||||
var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
|
||||
var gTestBrowser = null;
|
||||
var oldBrowserOpenAddonsMgr = window.BrowserOpenAddonsMgr;
|
||||
|
||||
add_task(function* () {
|
||||
registerCleanupFunction(function () {
|
||||
clearAllPluginPermissions();
|
||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||
gTestBrowser = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
window.focus();
|
||||
});
|
||||
registerCleanupFunction(function* cleanup() {
|
||||
clearAllPluginPermissions();
|
||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||
window.BrowserOpenAddonsMgr = oldBrowserOpenAddonsMgr;
|
||||
window.focus();
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gTestBrowser = gBrowser.selectedBrowser;
|
||||
|
||||
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||
add_task(function* test_clicking_manage_link_in_plugin_overlay_should_open_about_addons() {
|
||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_DISABLED, "Test Plug-in");
|
||||
|
||||
// Prime the blocklist service, the remote service doesn't launch on startup.
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
|
||||
let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
|
||||
ok(!exmsg, "exception: " + exmsg);
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html");
|
||||
let browser = tab.linkedBrowser;
|
||||
yield promiseUpdatePluginBindings(browser);
|
||||
|
||||
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
|
||||
|
||||
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||
|
||||
let pluginInfo = yield promiseForPluginInfo("test");
|
||||
let pluginInfo = yield promiseForPluginInfo("test", browser);
|
||||
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_DISABLED,
|
||||
"Test 1a, plugin fallback type should be PLUGIN_DISABLED");
|
||||
"plugin fallback type should be PLUGIN_DISABLED");
|
||||
|
||||
// This test opens a new tab to about:addons
|
||||
let promise = waitForEvent(gBrowser.tabContainer, "TabOpen", null, true);
|
||||
yield ContentTask.spawn(gTestBrowser, null, function* () {
|
||||
let awaitBrowserOpenAddonsMgr = new Promise(resolve => {
|
||||
window.BrowserOpenAddonsMgr = function(view) {
|
||||
resolve(view);
|
||||
}
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
let pluginNode = content.document.getElementById("test");
|
||||
let manageLink = content.document.getAnonymousElementByAttribute(pluginNode, "anonid", "managePluginsLink");
|
||||
let bounds = manageLink.getBoundingClientRect();
|
||||
@ -54,24 +41,8 @@ add_task(function* () {
|
||||
Assert.ok(true, "click on manage link");
|
||||
});
|
||||
|
||||
yield promise;
|
||||
let requestedView = yield awaitBrowserOpenAddonsMgr;
|
||||
is(requestedView, "addons://list/plugin", "The Add-ons Manager should open the plugin view");
|
||||
|
||||
promise = waitForEvent(gBrowser.tabContainer, "TabClose", null, true);
|
||||
|
||||
// in-process page, no cpows here
|
||||
let condition = function() {
|
||||
let win = gBrowser.selectedBrowser.contentWindow;
|
||||
if (!!win && !!win.wrappedJSObject && !!win.wrappedJSObject.gViewController) {
|
||||
return win.wrappedJSObject.gViewController.currentViewId == "addons://list/plugin";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
yield promiseForCondition(condition, "Waited too long for about:addons to display.", 40, 500);
|
||||
|
||||
// remove the tab containing about:addons
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
yield promise;
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
|
@ -106,6 +106,24 @@ AppendDistroSearchDirs(nsIProperties* aDirSvc, nsCOMArray<nsIFile> &array)
|
||||
|
||||
localePlugins->AppendNative(NS_LITERAL_CSTRING("locale"));
|
||||
|
||||
nsCString defLocale;
|
||||
rv = prefs->GetCharPref("distribution.searchplugins.defaultLocale",
|
||||
getter_Copies(defLocale));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
||||
nsCOMPtr<nsIFile> defLocalePlugins;
|
||||
rv = localePlugins->Clone(getter_AddRefs(defLocalePlugins));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
||||
defLocalePlugins->AppendNative(defLocale);
|
||||
rv = defLocalePlugins->Exists(&exists);
|
||||
if (NS_SUCCEEDED(rv) && exists)
|
||||
array.AppendObject(defLocalePlugins);
|
||||
return; // all done
|
||||
}
|
||||
}
|
||||
|
||||
// we didn't have a defaultLocale, use the user agent locale
|
||||
nsCString locale;
|
||||
nsCOMPtr<nsIPrefLocalizedString> prefString;
|
||||
rv = prefs->GetComplexValue("general.useragent.locale",
|
||||
@ -133,23 +151,6 @@ AppendDistroSearchDirs(nsIProperties* aDirSvc, nsCOMArray<nsIFile> &array)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we didn't append the locale dir - try the default one
|
||||
nsCString defLocale;
|
||||
rv = prefs->GetCharPref("distribution.searchplugins.defaultLocale",
|
||||
getter_Copies(defLocale));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
||||
nsCOMPtr<nsIFile> defLocalePlugins;
|
||||
rv = localePlugins->Clone(getter_AddRefs(defLocalePlugins));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
||||
defLocalePlugins->AppendNative(defLocale);
|
||||
rv = defLocalePlugins->Exists(&exists);
|
||||
if (NS_SUCCEEDED(rv) && exists)
|
||||
array.AppendObject(defLocalePlugins);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,7 +353,7 @@ DistributionCustomizer.prototype = {
|
||||
try {
|
||||
let value = this._ini.getString("Preferences-" + this._locale, key);
|
||||
if (value) {
|
||||
Preferences.set(key, parseValue(value));
|
||||
defaults.set(key, parseValue(value));
|
||||
}
|
||||
usedPreferences.push(key);
|
||||
} catch (e) { /* ignore bad prefs and move on */ }
|
||||
@ -368,7 +368,7 @@ DistributionCustomizer.prototype = {
|
||||
try {
|
||||
let value = this._ini.getString("Preferences-" + this._language, key);
|
||||
if (value) {
|
||||
Preferences.set(key, parseValue(value));
|
||||
defaults.set(key, parseValue(value));
|
||||
}
|
||||
usedPreferences.push(key);
|
||||
} catch (e) { /* ignore bad prefs and move on */ }
|
||||
@ -385,7 +385,7 @@ DistributionCustomizer.prototype = {
|
||||
if (value) {
|
||||
value = value.replace(/%LOCALE%/g, this._locale);
|
||||
value = value.replace(/%LANGUAGE%/g, this._language);
|
||||
Preferences.set(key, parseValue(value));
|
||||
defaults.set(key, parseValue(value));
|
||||
}
|
||||
} catch (e) { /* ignore bad prefs and move on */ }
|
||||
}
|
||||
|
@ -653,7 +653,7 @@ extensions.registerSchemaAPI("tabs", null, (extension, context) => {
|
||||
};
|
||||
|
||||
return context.sendMessage(browser.messageManager, "Extension:Capture",
|
||||
message, recipient);
|
||||
message, {recipient});
|
||||
},
|
||||
|
||||
detectLanguage: function(tabId) {
|
||||
@ -666,7 +666,7 @@ extensions.registerSchemaAPI("tabs", null, (extension, context) => {
|
||||
let recipient = {innerWindowID: browser.innerWindowID};
|
||||
|
||||
return context.sendMessage(browser.messageManager, "Extension:DetectLanguage",
|
||||
{}, recipient);
|
||||
{}, {recipient});
|
||||
},
|
||||
|
||||
_execute: function(tabId, details, kind, method) {
|
||||
@ -724,7 +724,7 @@ extensions.registerSchemaAPI("tabs", null, (extension, context) => {
|
||||
options.run_at = "document_idle";
|
||||
}
|
||||
|
||||
return context.sendMessage(mm, "Extension:Execute", {options}, recipient);
|
||||
return context.sendMessage(mm, "Extension:Execute", {options}, {recipient});
|
||||
},
|
||||
|
||||
executeScript: function(tabId, details) {
|
||||
|
@ -15,28 +15,35 @@ add_task(function* tabsSendMessageReply() {
|
||||
},
|
||||
|
||||
background: function() {
|
||||
let firstTab;
|
||||
let promiseResponse = new Promise(resolve => {
|
||||
browser.runtime.onMessage.addListener((msg, sender, respond) => {
|
||||
if (msg == "content-script-ready") {
|
||||
let tabId = sender.tab.id;
|
||||
|
||||
browser.tabs.sendMessage(tabId, "respond-never", response => {
|
||||
browser.test.fail("Got unexpected response callback");
|
||||
browser.test.fail(`Got unexpected response callback: ${response}`);
|
||||
browser.test.notifyFail("sendMessage");
|
||||
});
|
||||
|
||||
Promise.all([
|
||||
promiseResponse,
|
||||
|
||||
browser.tabs.sendMessage(tabId, "respond-now"),
|
||||
browser.tabs.sendMessage(tabId, "respond-now-2"),
|
||||
new Promise(resolve => browser.tabs.sendMessage(tabId, "respond-soon", resolve)),
|
||||
browser.tabs.sendMessage(tabId, "respond-promise"),
|
||||
browser.tabs.sendMessage(tabId, "respond-never"),
|
||||
|
||||
browser.tabs.sendMessage(tabId, "respond-error").catch(error => Promise.resolve({error})),
|
||||
browser.tabs.sendMessage(tabId, "throw-error").catch(error => Promise.resolve({error})),
|
||||
]).then(([response, respondNow, respondSoon, respondPromise, respondNever, respondError, throwError]) => {
|
||||
|
||||
browser.tabs.sendMessage(firstTab, "no-listener").catch(error => Promise.resolve({error})),
|
||||
]).then(([response, respondNow, respondNow2, respondSoon, respondPromise, respondNever, respondError, throwError, noListener]) => {
|
||||
browser.test.assertEq("expected-response", response, "Content script got the expected response");
|
||||
|
||||
browser.test.assertEq("respond-now", respondNow, "Got the expected immediate response");
|
||||
browser.test.assertEq("respond-now-2", respondNow2, "Got the expected immediate response from the second listener");
|
||||
browser.test.assertEq("respond-soon", respondSoon, "Got the expected delayed response");
|
||||
browser.test.assertEq("respond-promise", respondPromise, "Got the expected promise response");
|
||||
browser.test.assertEq(undefined, respondNever, "Got the expected no-response resolution");
|
||||
@ -44,6 +51,10 @@ add_task(function* tabsSendMessageReply() {
|
||||
browser.test.assertEq("respond-error", respondError.error.message, "Got the expected error response");
|
||||
browser.test.assertEq("throw-error", throwError.error.message, "Got the expected thrown error response");
|
||||
|
||||
browser.test.assertEq("Could not establish connection. Receiving end does not exist.",
|
||||
noListener.error.message,
|
||||
"Got the expected no listener response");
|
||||
|
||||
return browser.tabs.remove(tabId);
|
||||
}).then(() => {
|
||||
browser.test.notifyPass("sendMessage");
|
||||
@ -56,7 +67,10 @@ add_task(function* tabsSendMessageReply() {
|
||||
});
|
||||
});
|
||||
|
||||
browser.tabs.create({url: "http://example.com/"});
|
||||
browser.tabs.query({currentWindow: true, active: true}).then(tabs => {
|
||||
firstTab = tabs[0].id;
|
||||
browser.tabs.create({url: "http://example.com/"});
|
||||
});
|
||||
},
|
||||
|
||||
files: {
|
||||
@ -77,6 +91,13 @@ add_task(function* tabsSendMessageReply() {
|
||||
throw new Error(msg);
|
||||
}
|
||||
});
|
||||
browser.runtime.onMessage.addListener((msg, sender, respond) => {
|
||||
if (msg == "respond-now") {
|
||||
respond("hello");
|
||||
} else if (msg == "respond-now-2") {
|
||||
respond(msg);
|
||||
}
|
||||
});
|
||||
browser.runtime.sendMessage("content-script-ready").then(response => {
|
||||
browser.runtime.sendMessage(["got-response", response]);
|
||||
});
|
||||
@ -107,7 +128,7 @@ add_task(function* tabsSendMessageNoExceptionOnNonExistentTab() {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
browser.test.assertEq(undefined, exception, "no exception should be raised on tabs.sendMessage to unexistent tabs");
|
||||
browser.test.assertEq(undefined, exception, "no exception should be raised on tabs.sendMessage to nonexistent tabs");
|
||||
browser.tabs.remove(tab.id, function() {
|
||||
browser.test.notifyPass("tabs.sendMessage");
|
||||
});
|
||||
|
@ -357,6 +357,11 @@ var gAdvancedPane = {
|
||||
this.observer = {
|
||||
onNetworkCacheDiskConsumption: function(consumption) {
|
||||
var size = DownloadUtils.convertByteUnits(consumption);
|
||||
// The XBL binding for the string bundle may have been destroyed if
|
||||
// the page was closed before this callback was executed.
|
||||
if (!prefStrBundle.getFormattedString) {
|
||||
return;
|
||||
}
|
||||
actualSizeLabel.value = prefStrBundle.getFormattedString("actualDiskCacheSize", size);
|
||||
},
|
||||
|
||||
@ -385,6 +390,11 @@ var gAdvancedPane = {
|
||||
var actualSizeLabel = document.getElementById("actualAppCacheSize");
|
||||
var sizeStrings = DownloadUtils.convertByteUnits(aConsumption);
|
||||
var prefStrBundle = document.getElementById("bundlePreferences");
|
||||
// The XBL binding for the string bundle may have been destroyed if
|
||||
// the page was closed before this callback was executed.
|
||||
if (!prefStrBundle.getFormattedString) {
|
||||
return;
|
||||
}
|
||||
var sizeStr = prefStrBundle.getFormattedString("actualAppCacheSize", sizeStrings);
|
||||
actualSizeLabel.value = sizeStr;
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ skip-if = true || !healthreport # Bug 1185403 for the "true"
|
||||
[browser_privacypane_4.js]
|
||||
[browser_privacypane_5.js]
|
||||
[browser_privacypane_8.js]
|
||||
skip-if = e10s # Bug ?????? - "leaked until shutdown [nsGlobalWindow #99 about:preferences]"
|
||||
[browser_sanitizeOnShutdown_prefLocked.js]
|
||||
[browser_searchsuggestions.js]
|
||||
[browser_subdialogs.js]
|
||||
|
@ -1,25 +1,18 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_pane_visibility,
|
||||
test_dependent_elements,
|
||||
test_dependent_cookie_elements,
|
||||
test_dependent_clearonclose_elements,
|
||||
test_dependent_prefs,
|
||||
]);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_pane_visibility,
|
||||
test_dependent_elements,
|
||||
test_dependent_cookie_elements,
|
||||
test_dependent_clearonclose_elements,
|
||||
test_dependent_prefs,
|
||||
]);
|
||||
|
@ -1,22 +1,17 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_custom_retention("rememberHistory", "remember"),
|
||||
test_custom_retention("rememberHistory", "custom"),
|
||||
test_custom_retention("rememberForms", "remember"),
|
||||
test_custom_retention("rememberForms", "custom"),
|
||||
test_historymode_retention("remember", "remember"),
|
||||
]);
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_custom_retention("rememberHistory", "remember"),
|
||||
test_custom_retention("rememberHistory", "custom"),
|
||||
test_custom_retention("rememberForms", "remember"),
|
||||
test_custom_retention("rememberForms", "custom"),
|
||||
test_historymode_retention("remember", "remember"),
|
||||
]);
|
||||
|
@ -1,33 +1,23 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
let runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
|
||||
|
||||
run_test_subset(Array.concat([
|
||||
test_custom_retention("acceptCookies", "remember"),
|
||||
test_custom_retention("acceptCookies", "custom")
|
||||
],
|
||||
[
|
||||
test_custom_retention("acceptThirdPartyMenu", "remember", "visited"),
|
||||
test_custom_retention("acceptThirdPartyMenu", "custom", "always")
|
||||
], [
|
||||
test_custom_retention("keepCookiesUntil", "remember", 1),
|
||||
test_custom_retention("keepCookiesUntil", "custom", 2),
|
||||
test_custom_retention("keepCookiesUntil", "custom", 0),
|
||||
test_custom_retention("alwaysClear", "remember"),
|
||||
test_custom_retention("alwaysClear", "custom"),
|
||||
test_historymode_retention("remember", "remember"),
|
||||
]));
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
let runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
|
||||
|
||||
run_test_subset([
|
||||
test_custom_retention("acceptCookies", "remember"),
|
||||
test_custom_retention("acceptCookies", "custom"),
|
||||
test_custom_retention("acceptThirdPartyMenu", "remember", "visited"),
|
||||
test_custom_retention("acceptThirdPartyMenu", "custom", "always"),
|
||||
test_custom_retention("keepCookiesUntil", "remember", 1),
|
||||
test_custom_retention("keepCookiesUntil", "custom", 2),
|
||||
test_custom_retention("keepCookiesUntil", "custom", 0),
|
||||
test_custom_retention("alwaysClear", "remember"),
|
||||
test_custom_retention("alwaysClear", "custom"),
|
||||
test_historymode_retention("remember", "remember"),
|
||||
]);
|
||||
|
@ -1,24 +1,17 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
|
||||
let tests = [
|
||||
test_locbar_suggestion_retention("history", true),
|
||||
test_locbar_suggestion_retention("bookmark", true),
|
||||
test_locbar_suggestion_retention("openpage", false),
|
||||
test_locbar_suggestion_retention("history", true),
|
||||
test_locbar_suggestion_retention("history", false),
|
||||
];
|
||||
|
||||
run_test_subset(tests);
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
|
||||
run_test_subset([
|
||||
test_locbar_suggestion_retention("history", true),
|
||||
test_locbar_suggestion_retention("bookmark", true),
|
||||
test_locbar_suggestion_retention("openpage", false),
|
||||
test_locbar_suggestion_retention("history", true),
|
||||
test_locbar_suggestion_retention("history", false),
|
||||
]);
|
||||
|
@ -1,31 +1,26 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
|
||||
run_test_subset([
|
||||
// history mode should be initialized to remember
|
||||
test_historymode_retention("remember", undefined),
|
||||
|
||||
// history mode should remain remember; toggle acceptCookies checkbox
|
||||
test_custom_retention("acceptCookies", "remember"),
|
||||
|
||||
// history mode should now be custom; set history mode to dontremember
|
||||
test_historymode_retention("dontremember", "custom"),
|
||||
|
||||
// history mode should remain custom; set history mode to remember
|
||||
test_historymode_retention("remember", "custom"),
|
||||
|
||||
// history mode should now be remember
|
||||
test_historymode_retention("remember", "remember"),
|
||||
]);
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let jar = getJar(rootDir);
|
||||
if (jar) {
|
||||
let tmpdir = extractJarToTmp(jar);
|
||||
rootDir = "file://" + tmpdir.path + '/';
|
||||
}
|
||||
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
|
||||
|
||||
run_test_subset([
|
||||
// history mode should be initialized to remember
|
||||
test_historymode_retention("remember", undefined),
|
||||
|
||||
// history mode should remain remember; toggle acceptCookies checkbox
|
||||
test_custom_retention("acceptCookies", "remember"),
|
||||
|
||||
// history mode should now be custom; set history mode to dontremember
|
||||
test_historymode_retention("dontremember", "custom"),
|
||||
|
||||
// history mode should remain custom; set history mode to remember
|
||||
test_historymode_retention("remember", "custom"),
|
||||
|
||||
// history mode should now be remember
|
||||
test_historymode_retention("remember", "remember"),
|
||||
]);
|
||||
|
@ -1,22 +1,12 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function runTestOnPrivacyPrefPane(testFunc) {
|
||||
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", function(aEvent) {
|
||||
gBrowser.tabContainer.removeEventListener("TabOpen", arguments.callee, true);
|
||||
let browser = aEvent.originalTarget.linkedBrowser;
|
||||
browser.addEventListener("Initialized", function(aEvent) {
|
||||
browser.removeEventListener("Initialized", arguments.callee, true);
|
||||
is(browser.contentWindow.location.href, "about:preferences", "Checking if the preferences tab was opened");
|
||||
browser.contentWindow.gotoPref("panePrivacy");
|
||||
testFunc(browser.contentWindow);
|
||||
gBrowser.removeCurrentTab();
|
||||
testRunner.runNext();
|
||||
}, true);
|
||||
}, true);
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:preferences");
|
||||
function* runTestOnPrivacyPrefPane(testFunc) {
|
||||
info("runTestOnPrivacyPrefPane entered");
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences", true, true);
|
||||
let browser = tab.linkedBrowser;
|
||||
info("loaded about:preferences");
|
||||
browser.contentWindow.gotoPref("panePrivacy");
|
||||
info("viewing privacy pane, executing testFunc");
|
||||
testFunc(browser.contentWindow);
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
||||
function controlChanged(element) {
|
||||
@ -254,7 +244,7 @@ function test_dependent_prefs(win) {
|
||||
}
|
||||
|
||||
function test_historymode_retention(mode, expect) {
|
||||
return function(win) {
|
||||
return function test_historymode_retention_fn(win) {
|
||||
let historymode = win.document.getElementById("historyMode");
|
||||
ok(historymode, "history mode menulist should exist");
|
||||
|
||||
@ -275,7 +265,7 @@ function test_historymode_retention(mode, expect) {
|
||||
}
|
||||
|
||||
function test_custom_retention(controlToChange, expect, valueIncrement) {
|
||||
return function(win) {
|
||||
return function test_custom_retention_fn(win) {
|
||||
let historymode = win.document.getElementById("historyMode");
|
||||
ok(historymode, "history mode menulist should exist");
|
||||
|
||||
@ -329,31 +319,12 @@ function reset_preferences(win) {
|
||||
pref.value = gPrefCache.get(pref.name);
|
||||
}
|
||||
|
||||
var testRunner;
|
||||
function run_test_subset(subset) {
|
||||
Services.prefs.setBoolPref("browser.preferences.instantApply", true);
|
||||
dump("subset: " + Array.from(subset, x => x.name).join(",") + "\n");
|
||||
info("subset: " + Array.from(subset, x => x.name).join(",") + "\n");
|
||||
SpecialPowers.pushPrefEnv({"set": [["browser.preferences.instantApply", true]]});
|
||||
|
||||
waitForExplicitFinish();
|
||||
registerCleanupFunction(function() {
|
||||
// Reset pref to its default
|
||||
Services.prefs.clearUserPref("browser.preferences.instantApply");
|
||||
});
|
||||
|
||||
testRunner = {
|
||||
tests: [cache_preferences, ...subset, reset_preferences],
|
||||
counter: 0,
|
||||
runNext: function() {
|
||||
if (this.counter == this.tests.length) {
|
||||
finish();
|
||||
} else {
|
||||
let self = this;
|
||||
setTimeout(function() {
|
||||
runTestOnPrivacyPrefPane(self.tests[self.counter++]);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
testRunner.runNext();
|
||||
let tests = [cache_preferences, ...subset, reset_preferences];
|
||||
for (let test of tests) {
|
||||
add_task(runTestOnPrivacyPrefPane.bind(undefined, test));
|
||||
}
|
||||
}
|
||||
|
8
browser/components/tests/unit/data/engine-de-DE.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>Google</ShortName>
|
||||
<Description>override-de-DE</Description>
|
||||
<InputEncoding>UTF-8</InputEncoding>
|
||||
<Url type="text/html" method="GET" template="http://searchtest.local">
|
||||
<Param name="search" value="{searchTerms}"/>
|
||||
</Url>
|
||||
</SearchPlugin>
|
@ -23,6 +23,45 @@ if (commonFile) {
|
||||
const TOPICDATA_DISTRIBUTION_CUSTOMIZATION = "force-distribution-customization";
|
||||
const TOPIC_BROWSERGLUE_TEST = "browser-glue-test";
|
||||
|
||||
/**
|
||||
* Copy the engine-distribution.xml engine to a fake distribution
|
||||
* created in the profile, and registered with the directory service.
|
||||
* Create an empty en-US directory to make sure it isn't used.
|
||||
*/
|
||||
function installDistributionEngine() {
|
||||
const XRE_APP_DISTRIBUTION_DIR = "XREAppDist";
|
||||
|
||||
const gProfD = do_get_profile().QueryInterface(Ci.nsILocalFile);
|
||||
|
||||
let dir = gProfD.clone();
|
||||
dir.append("distribution");
|
||||
let distDir = dir.clone();
|
||||
|
||||
dir.append("searchplugins");
|
||||
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
|
||||
dir.append("locale");
|
||||
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
let localeDir = dir.clone();
|
||||
|
||||
dir.append("en-US");
|
||||
dir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
|
||||
localeDir.append("de-DE");
|
||||
localeDir.create(dir.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
|
||||
do_get_file("data/engine-de-DE.xml").copyTo(localeDir, "engine-de-DE.xml");
|
||||
|
||||
Services.dirsvc.registerProvider({
|
||||
getFile: function(aProp, aPersistent) {
|
||||
aPersistent.value = true;
|
||||
if (aProp == XRE_APP_DISTRIBUTION_DIR)
|
||||
return distDir.clone();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// Set special pref to load distribution.ini from the profile folder.
|
||||
Services.prefs.setBoolPref("distribution.testing.loadFromProfile", true);
|
||||
@ -42,19 +81,18 @@ function run_test() {
|
||||
testDistributionFile.copyTo(distroDir, "distribution.ini");
|
||||
Assert.ok(testDistributionFile.exists());
|
||||
|
||||
installDistributionEngine();
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
do_register_cleanup(function () {
|
||||
// Remove the distribution file, even if the test failed, otherwise all
|
||||
// next tests will import it.
|
||||
let iniFile = gProfD.clone();
|
||||
iniFile.leafName = "distribution";
|
||||
iniFile.append("distribution.ini");
|
||||
if (iniFile.exists()) {
|
||||
iniFile.remove(false);
|
||||
}
|
||||
Assert.ok(!iniFile.exists());
|
||||
// Remove the distribution dir, even if the test failed, otherwise all
|
||||
// next tests will use it.
|
||||
let distDir = gProfD.clone();
|
||||
distDir.append("distribution");
|
||||
distDir.remove(true);
|
||||
Assert.ok(!distDir.exists());
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
@ -62,47 +100,60 @@ add_task(function* () {
|
||||
let glue = Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsIObserver)
|
||||
glue.observe(null, TOPIC_BROWSERGLUE_TEST, TOPICDATA_DISTRIBUTION_CUSTOMIZATION);
|
||||
|
||||
Assert.equal(Services.prefs.getCharPref("distribution.id"), "disttest");
|
||||
Assert.equal(Services.prefs.getCharPref("distribution.version"), "1.0");
|
||||
Assert.equal(Services.prefs.getComplexValue("distribution.about", Ci.nsISupportsString).data, "Tèƨƭ δïƨƭřïβúƭïôñ ƒïℓè");
|
||||
var defaultBranch = Services.prefs.getDefaultBranch(null);
|
||||
|
||||
Assert.equal(Services.prefs.getCharPref("distribution.test.string"), "Test String");
|
||||
Assert.equal(Services.prefs.getCharPref("distribution.test.string.noquotes"), "Test String");
|
||||
Assert.equal(Services.prefs.getIntPref("distribution.test.int"), 777);
|
||||
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.true"), true);
|
||||
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.false"), false);
|
||||
Assert.equal(defaultBranch.getCharPref("distribution.id"), "disttest");
|
||||
Assert.equal(defaultBranch.getCharPref("distribution.version"), "1.0");
|
||||
Assert.equal(defaultBranch.getComplexValue("distribution.about", Ci.nsISupportsString).data, "Tèƨƭ δïƨƭřïβúƭïôñ ƒïℓè");
|
||||
|
||||
Assert.throws(() => Services.prefs.getCharPref("distribution.test.empty"));
|
||||
Assert.throws(() => Services.prefs.getIntPref("distribution.test.empty"));
|
||||
Assert.throws(() => Services.prefs.getBoolPref("distribution.test.empty"));
|
||||
Assert.equal(defaultBranch.getCharPref("distribution.test.string"), "Test String");
|
||||
Assert.equal(defaultBranch.getCharPref("distribution.test.string.noquotes"), "Test String");
|
||||
Assert.equal(defaultBranch.getIntPref("distribution.test.int"), 777);
|
||||
Assert.equal(defaultBranch.getBoolPref("distribution.test.bool.true"), true);
|
||||
Assert.equal(defaultBranch.getBoolPref("distribution.test.bool.false"), false);
|
||||
|
||||
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale"), "en-US");
|
||||
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.language.en"), "en");
|
||||
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale.en-US"), "en-US");
|
||||
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.language.de"));
|
||||
Assert.throws(() => defaultBranch.getCharPref("distribution.test.empty"));
|
||||
Assert.throws(() => defaultBranch.getIntPref("distribution.test.empty"));
|
||||
Assert.throws(() => defaultBranch.getBoolPref("distribution.test.empty"));
|
||||
|
||||
Assert.equal(defaultBranch.getCharPref("distribution.test.pref.locale"), "en-US");
|
||||
Assert.equal(defaultBranch.getCharPref("distribution.test.pref.language.en"), "en");
|
||||
Assert.equal(defaultBranch.getCharPref("distribution.test.pref.locale.en-US"), "en-US");
|
||||
Assert.throws(() => defaultBranch.getCharPref("distribution.test.pref.language.de"));
|
||||
// This value was never set because of the empty language specific pref
|
||||
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.language.reset"));
|
||||
Assert.throws(() => defaultBranch.getCharPref("distribution.test.pref.language.reset"));
|
||||
// This value was never set because of the empty locale specific pref
|
||||
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.locale.reset"));
|
||||
Assert.throws(() => defaultBranch.getCharPref("distribution.test.pref.locale.reset"));
|
||||
// This value was overridden by a locale specific setting
|
||||
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale.set"), "Locale Set");
|
||||
Assert.equal(defaultBranch.getCharPref("distribution.test.pref.locale.set"), "Locale Set");
|
||||
// This value was overridden by a language specific setting
|
||||
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.language.set"), "Language Set");
|
||||
Assert.equal(defaultBranch.getCharPref("distribution.test.pref.language.set"), "Language Set");
|
||||
// Language should not override locale
|
||||
Assert.notEqual(Services.prefs.getCharPref("distribution.test.pref.locale.set"), "Language Set");
|
||||
Assert.notEqual(defaultBranch.getCharPref("distribution.test.pref.locale.set"), "Language Set");
|
||||
|
||||
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale", Ci.nsIPrefLocalizedString).data, "en-US");
|
||||
Assert.equal(Services.prefs.getComplexValue("distribution.test.language.en", Ci.nsIPrefLocalizedString).data, "en");
|
||||
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale.en-US", Ci.nsIPrefLocalizedString).data, "en-US");
|
||||
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.de", Ci.nsIPrefLocalizedString));
|
||||
Assert.equal(defaultBranch.getComplexValue("distribution.test.locale", Ci.nsIPrefLocalizedString).data, "en-US");
|
||||
Assert.equal(defaultBranch.getComplexValue("distribution.test.language.en", Ci.nsIPrefLocalizedString).data, "en");
|
||||
Assert.equal(defaultBranch.getComplexValue("distribution.test.locale.en-US", Ci.nsIPrefLocalizedString).data, "en-US");
|
||||
Assert.throws(() => defaultBranch.getComplexValue("distribution.test.language.de", Ci.nsIPrefLocalizedString));
|
||||
// This value was never set because of the empty language specific pref
|
||||
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.reset", Ci.nsIPrefLocalizedString));
|
||||
Assert.throws(() => defaultBranch.getComplexValue("distribution.test.language.reset", Ci.nsIPrefLocalizedString));
|
||||
// This value was never set because of the empty locale specific pref
|
||||
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.locale.reset", Ci.nsIPrefLocalizedString));
|
||||
Assert.throws(() => defaultBranch.getComplexValue("distribution.test.locale.reset", Ci.nsIPrefLocalizedString));
|
||||
// This value was overridden by a locale specific setting
|
||||
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale.set", Ci.nsIPrefLocalizedString).data, "Locale Set");
|
||||
Assert.equal(defaultBranch.getComplexValue("distribution.test.locale.set", Ci.nsIPrefLocalizedString).data, "Locale Set");
|
||||
// This value was overridden by a language specific setting
|
||||
Assert.equal(Services.prefs.getComplexValue("distribution.test.language.set", Ci.nsIPrefLocalizedString).data, "Language Set");
|
||||
Assert.equal(defaultBranch.getComplexValue("distribution.test.language.set", Ci.nsIPrefLocalizedString).data, "Language Set");
|
||||
// Language should not override locale
|
||||
Assert.notEqual(Services.prefs.getComplexValue("distribution.test.locale.set", Ci.nsIPrefLocalizedString).data, "Language Set");
|
||||
Assert.notEqual(defaultBranch.getComplexValue("distribution.test.locale.set", Ci.nsIPrefLocalizedString).data, "Language Set");
|
||||
|
||||
do_test_pending();
|
||||
|
||||
Services.prefs.setCharPref("distribution.searchplugins.defaultLocale", "de-DE");
|
||||
|
||||
Services.search.init(function() {
|
||||
Assert.equal(Services.search.isInitialized, true);
|
||||
var engine = Services.search.getEngineByName("Google");
|
||||
Assert.equal(engine.description, "override-de-DE");
|
||||
do_test_finished();
|
||||
});
|
||||
});
|
||||
|
@ -3,5 +3,6 @@ firefox-appdir = browser
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk'
|
||||
support-files =
|
||||
distribution.ini
|
||||
data/engine-de-DE.xml
|
||||
|
||||
[test_distribution.js]
|
||||
|
@ -1 +1 @@
|
||||
47.0a1
|
||||
48.0a1
|
||||
|
@ -1 +1 @@
|
||||
47.0a1
|
||||
48.0a1
|
||||
|
@ -452,12 +452,12 @@ Experiments.Experiments.prototype = {
|
||||
this._shutdown = true;
|
||||
if (this._mainTask) {
|
||||
if (this._networkRequest) {
|
||||
try {
|
||||
this._log.trace("Aborting pending network request: " + this._networkRequest);
|
||||
this._networkRequest.abort();
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
try {
|
||||
this._log.trace("Aborting pending network request: " + this._networkRequest);
|
||||
this._networkRequest.abort();
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
try {
|
||||
this._log.trace("uninit: waiting on _mainTask");
|
||||
@ -634,7 +634,7 @@ Experiments.Experiments.prototype = {
|
||||
active: experiment.enabled,
|
||||
endDate: experiment.endDate.getTime(),
|
||||
detailURL: experiment._homepageURL,
|
||||
branch: experiment.branch,
|
||||
branch: experiment.branch,
|
||||
});
|
||||
}
|
||||
|
||||
@ -709,7 +709,7 @@ Experiments.Experiments.prototype = {
|
||||
} else {
|
||||
e = this._getActiveExperiment();
|
||||
if (e === null) {
|
||||
throw new Error("No active experiment");
|
||||
throw new Error("No active experiment");
|
||||
}
|
||||
}
|
||||
return e.branch;
|
||||
@ -958,7 +958,7 @@ Experiments.Experiments.prototype = {
|
||||
if (xhr.status !== 200 && xhr.state !== 0) {
|
||||
log.error("httpGetRequest::onLoad() - Request to " + url + " returned status " + xhr.status);
|
||||
deferred.reject(new Error("Experiments - XHR status for " + url + " is " + xhr.status));
|
||||
this._networkRequest = null;
|
||||
this._networkRequest = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1043,6 +1043,14 @@ Experiments.Experiments.prototype = {
|
||||
if (!entry.initFromCacheData(item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Discard old experiments if they ended more than 180 days ago.
|
||||
if (entry.shouldDiscard()) {
|
||||
// We discarded an experiment, the cache needs to be updated.
|
||||
this._dirty = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
experiments.set(entry.id, entry);
|
||||
}
|
||||
|
||||
@ -1543,7 +1551,9 @@ Experiments.ExperimentEntry.prototype = {
|
||||
}
|
||||
});
|
||||
|
||||
this._lastChangedDate = this._policy.now();
|
||||
// In order for the experiment's data expiration mechanism to work, use the experiment's
|
||||
// |_endData| as the |_lastChangedDate| (if available).
|
||||
this._lastChangedDate = !!this._endDate ? this._endDate : this._policy.now();
|
||||
|
||||
return true;
|
||||
},
|
||||
|
@ -80,6 +80,15 @@ function checkExperimentSerializations(experimentEntryIterator) {
|
||||
}
|
||||
}
|
||||
|
||||
function validateCache(cachedExperiments, experimentIds) {
|
||||
let cachedExperimentIds = new Set(cachedExperiments);
|
||||
Assert.equal(cachedExperimentIds.size, experimentIds.length,
|
||||
"The number of cached experiments does not match with the provided list");
|
||||
for (let id of experimentIds) {
|
||||
Assert.ok(cachedExperimentIds.has(id), "The cache must contain the experiment with id " + id);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up an experiments instance and check if it is properly restored from cache.
|
||||
|
||||
add_task(function* test_cache() {
|
||||
@ -247,3 +256,147 @@ add_task(function* test_cache() {
|
||||
yield promiseRestartManager();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
||||
add_task(function* test_expiration() {
|
||||
// The manifest data we test with.
|
||||
gManifestObject = {
|
||||
"version": 1,
|
||||
experiments: [
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
|
||||
xpiHash: EXPERIMENT1_XPI_SHA1,
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
{
|
||||
id: EXPERIMENT2_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
|
||||
xpiHash: EXPERIMENT2_XPI_SHA1,
|
||||
maxActiveSeconds: 50 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
// The 3rd experiment will never run, so it's ok to use experiment's 2 data.
|
||||
{
|
||||
id: EXPERIMENT3_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
|
||||
xpiHash: EXPERIMENT2_XPI_SHA1,
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
// Data to compare the result of Experiments.getExperiments() against.
|
||||
let experimentListData = [
|
||||
{
|
||||
id: EXPERIMENT2_ID,
|
||||
name: "Test experiment 2",
|
||||
description: "And yet another experiment that experiments experimentally.",
|
||||
},
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
name: EXPERIMENT1_NAME,
|
||||
description: "Yet another experiment that experiments experimentally.",
|
||||
},
|
||||
];
|
||||
|
||||
// Setup dates for the experiments.
|
||||
let baseDate = new Date(2014, 5, 1, 12);
|
||||
let startDates = [];
|
||||
let endDates = [];
|
||||
|
||||
for (let i=0; i<gManifestObject.experiments.length; ++i) {
|
||||
let experiment = gManifestObject.experiments[i];
|
||||
// Spread out experiments in time so that one experiment can end and expire while
|
||||
// the next is still running.
|
||||
startDates.push(futureDate(baseDate, (50 + (200 * i)) * MS_IN_ONE_DAY));
|
||||
endDates .push(futureDate(startDates[i], 50 * MS_IN_ONE_DAY));
|
||||
experiment.startTime = dateToSeconds(startDates[i]);
|
||||
experiment.endTime = dateToSeconds(endDates[i]);
|
||||
}
|
||||
|
||||
let now = null;
|
||||
let experiments = null;
|
||||
|
||||
let setDateAndRestartExperiments = new Task.async(function* (newDate) {
|
||||
now = newDate;
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield promiseRestartManager();
|
||||
experiments = new Experiments.Experiments(gPolicy);
|
||||
yield experiments._run();
|
||||
});
|
||||
|
||||
// Trigger update & re-init, clock set to before any activation.
|
||||
now = baseDate;
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
experiments = new Experiments.Experiments(gPolicy);
|
||||
yield experiments.updateManifest();
|
||||
let list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 0, "Experiment list should be empty.");
|
||||
|
||||
// Re-init, clock set for experiment 1 to start...
|
||||
yield setDateAndRestartExperiments(startDates[0]);
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "The first experiment should have started.");
|
||||
|
||||
// ... init again, and set the clock so that the first experiment ends.
|
||||
yield setDateAndRestartExperiments(endDates[0]);
|
||||
|
||||
// The experiment just ended, it should still be in the cache, but marked
|
||||
// as finished.
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
|
||||
|
||||
experimentListData[1].active = false;
|
||||
experimentListData[1].endDate = now.getTime();
|
||||
checkExperimentListsEqual(experimentListData.slice(1), list);
|
||||
validateCache([...experiments._experiments.keys()], [EXPERIMENT1_ID, EXPERIMENT2_ID, EXPERIMENT3_ID]);
|
||||
|
||||
// Start the second experiment.
|
||||
yield setDateAndRestartExperiments(startDates[1]);
|
||||
|
||||
// The experiments cache should contain the finished experiment and the
|
||||
// one that's still running.
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 2, "Experiment list should have 2 entries.");
|
||||
|
||||
experimentListData[0].active = true;
|
||||
experimentListData[0].endDate = now.getTime() + 50 * MS_IN_ONE_DAY;
|
||||
checkExperimentListsEqual(experimentListData, list);
|
||||
|
||||
// Move the clock in the future, just 31 days after the start date of the second experiment,
|
||||
// so that the cache for the first experiment expires and the second experiment is still running.
|
||||
yield setDateAndRestartExperiments(futureDate(startDates[1], 31 * MS_IN_ONE_DAY));
|
||||
validateCache([...experiments._experiments.keys()], [EXPERIMENT2_ID, EXPERIMENT3_ID]);
|
||||
|
||||
// Make sure that the expired experiment is not reported anymore.
|
||||
let history = yield experiments.getExperiments();
|
||||
Assert.equal(history.length, 1, "Experiments older than 180 days must be removed from the cache.");
|
||||
|
||||
// Test that we don't write expired experiments in the cache.
|
||||
yield setDateAndRestartExperiments(now);
|
||||
validateCache([...experiments._experiments.keys()], [EXPERIMENT2_ID, EXPERIMENT3_ID]);
|
||||
|
||||
// The first experiment should be expired and not in the cache, it ended more than
|
||||
// 180 days ago. We should see the one still running in the cache.
|
||||
history = yield experiments.getExperiments();
|
||||
Assert.equal(history.length, 1, "Expired experiments must not be saved to cache.");
|
||||
checkExperimentListsEqual(experimentListData.slice(0, 1), history);
|
||||
|
||||
// Test that experiments that are cached locally but never ran are removed from cache
|
||||
// when they are removed from the manifest (this is cached data, not really history).
|
||||
gManifestObject["experiments"] = gManifestObject["experiments"].slice(1, 1);
|
||||
yield experiments.updateManifest();
|
||||
validateCache([...experiments._experiments.keys()], [EXPERIMENT2_ID]);
|
||||
|
||||
// Cleanup.
|
||||
yield experiments._toggleExperimentsEnabled(false);
|
||||
yield promiseRestartManager();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
@ -948,6 +948,10 @@ var MozLoopServiceInternal = {
|
||||
|
||||
let url = this.getChatURL(windowId);
|
||||
|
||||
// Ensure about:loopconversation has access to the camera.
|
||||
Services.perms.add(Services.io.newURI(url, null, null), "camera",
|
||||
Services.perms.ALLOW_ACTION, Services.perms.EXPIRE_SESSION);
|
||||
|
||||
Chat.registerButton(kChatboxHangupButton);
|
||||
|
||||
let callback = chatbox => {
|
||||
|
@ -51,3 +51,7 @@
|
||||
-moz-image-region: rect(36px, 36px, 72px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#PanelUI-pocketView[mainview=true] > .panel-subview-body > #pocket-panel-iframe {
|
||||
border-radius: var(--panel-arrowcontent-border-radius);
|
||||
}
|
||||
|
@ -27,15 +27,17 @@ XPCOMUtils.defineLazyServiceGetter(this, "_focusManager",
|
||||
|
||||
|
||||
// Constants
|
||||
const TAB_EVENTS = ["TabOpen", "TabSelect"];
|
||||
const TAB_EVENTS = ["TabOpen", "TabSelect", "TabRemotenessChange"];
|
||||
const WINDOW_EVENTS = ["activate", "unload"];
|
||||
// PRIORITY DELTA is -10 because lower priority value is actually a higher priority
|
||||
const PRIORITY_DELTA = -10;
|
||||
// lower value means higher priority
|
||||
const PRIORITY_DELTA = Ci.nsISupportsPriority.PRIORITY_NORMAL - Ci.nsISupportsPriority.PRIORITY_LOW;
|
||||
|
||||
|
||||
// Variables
|
||||
var _lastFocusedWindow = null;
|
||||
var _windows = [];
|
||||
// this is used for restoring the priority after TabRemotenessChange
|
||||
var _priorityBackup = new WeakMap();
|
||||
|
||||
|
||||
// Exported symbol
|
||||
@ -56,6 +58,9 @@ function _handleEvent(aEvent) {
|
||||
case "activate":
|
||||
WindowHelper.onActivate(aEvent.target);
|
||||
break;
|
||||
case "TabRemotenessChange":
|
||||
BrowserHelper.onRemotenessChange(aEvent.target.linkedBrowser);
|
||||
break;
|
||||
case "unload":
|
||||
WindowHelper.removeWindow(aEvent.currentTarget);
|
||||
break;
|
||||
@ -66,6 +71,8 @@ function _handleEvent(aEvent) {
|
||||
// Methods that impact a browser. Put into single object for organization.
|
||||
var BrowserHelper = {
|
||||
onOpen: function NP_BH_onOpen(aBrowser) {
|
||||
_priorityBackup.set(aBrowser.permanentKey, Ci.nsISupportsPriority.PRIORITY_NORMAL);
|
||||
|
||||
// If the tab is in the focused window, leave priority as it is
|
||||
if (aBrowser.ownerDocument.defaultView != _lastFocusedWindow)
|
||||
this.decreasePriority(aBrowser);
|
||||
@ -80,12 +87,20 @@ var BrowserHelper = {
|
||||
windowEntry.lastSelectedBrowser = aBrowser;
|
||||
},
|
||||
|
||||
onRemotenessChange: function (aBrowser) {
|
||||
aBrowser.setPriority(_priorityBackup.get(aBrowser.permanentKey));
|
||||
},
|
||||
|
||||
increasePriority: function NP_BH_increasePriority(aBrowser) {
|
||||
aBrowser.adjustPriority(PRIORITY_DELTA);
|
||||
_priorityBackup.set(aBrowser.permanentKey,
|
||||
_priorityBackup.get(aBrowser.permanentKey) + PRIORITY_DELTA);
|
||||
},
|
||||
|
||||
decreasePriority: function NP_BH_decreasePriority(aBrowser) {
|
||||
aBrowser.adjustPriority(PRIORITY_DELTA * -1);
|
||||
_priorityBackup.set(aBrowser.permanentKey,
|
||||
_priorityBackup.get(aBrowser.permanentKey) - PRIORITY_DELTA);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,6 @@ support-files =
|
||||
contentSearchSuggestions.sjs
|
||||
contentSearchSuggestions.xml
|
||||
[browser_NetworkPrioritizer.js]
|
||||
skip-if = e10s # Bug 666804 - Support NetworkPrioritizer in e10s
|
||||
[browser_SelfSupportBackend.js]
|
||||
support-files =
|
||||
../../components/uitour/test/uitour.html
|
||||
|
@ -2,153 +2,164 @@
|
||||
* 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/. */
|
||||
|
||||
function test() {
|
||||
/** Tests for NetworkPrioritizer.jsm (Bug 514490) **/
|
||||
/** Tests for NetworkPrioritizer.jsm (Bug 514490) **/
|
||||
|
||||
waitForExplicitFinish();
|
||||
const LOWEST = Ci.nsISupportsPriority.PRIORITY_LOWEST;
|
||||
const LOW = Ci.nsISupportsPriority.PRIORITY_LOW;
|
||||
const NORMAL = Ci.nsISupportsPriority.PRIORITY_NORMAL;
|
||||
const HIGH = Ci.nsISupportsPriority.PRIORITY_HIGH;
|
||||
const HIGHEST = Ci.nsISupportsPriority.PRIORITY_HIGHEST;
|
||||
|
||||
const PRIORITY_DELTA = -10; // same as in NetworkPrioritizer
|
||||
const DELTA = NORMAL - LOW; // lower value means higher priority
|
||||
|
||||
// Test helper functions.
|
||||
// getPriority and setPriority can take a Tab or a Browser
|
||||
function getPriority(aBrowser) {
|
||||
// Assume we were passed a tab if it's not a browser
|
||||
if (!aBrowser.webNavigation)
|
||||
aBrowser = aBrowser.linkedBrowser;
|
||||
return aBrowser.webNavigation.QueryInterface(Ci.nsIDocumentLoader)
|
||||
.loadGroup.QueryInterface(Ci.nsISupportsPriority).priority;
|
||||
}
|
||||
function setPriority(aBrowser, aPriority) {
|
||||
if (!aBrowser.webNavigation)
|
||||
aBrowser = aBrowser.linkedBrowser;
|
||||
aBrowser.webNavigation.QueryInterface(Ci.nsIDocumentLoader)
|
||||
.loadGroup.QueryInterface(Ci.nsISupportsPriority).priority = aPriority;
|
||||
}
|
||||
|
||||
function isWindowState(aWindow, aTabPriorities) {
|
||||
let browsers = aWindow.gBrowser.browsers;
|
||||
// Make sure we have the right number of tabs & priorities
|
||||
is(browsers.length, aTabPriorities.length,
|
||||
"Window has expected number of tabs");
|
||||
// aState should be in format [ priority, priority, priority ]
|
||||
for (let i = 0; i < browsers.length; i++) {
|
||||
is(getPriority(browsers[i]), aTabPriorities[i],
|
||||
"Tab had expected priority");
|
||||
}
|
||||
// Test helper functions.
|
||||
// getPriority and setPriority can take a tab or a Browser
|
||||
function* getPriority(aBrowser) {
|
||||
if (aBrowser.localName == "tab")
|
||||
aBrowser = aBrowser.linkedBrowser;
|
||||
|
||||
return yield ContentTask.spawn(aBrowser, null, function* () {
|
||||
return docShell.QueryInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsIDocumentLoader)
|
||||
.loadGroup
|
||||
.QueryInterface(Components.interfaces.nsISupportsPriority)
|
||||
.priority;
|
||||
});
|
||||
}
|
||||
|
||||
function* setPriority(aBrowser, aPriority) {
|
||||
if (aBrowser.localName == "tab")
|
||||
aBrowser = aBrowser.linkedBrowser;
|
||||
|
||||
yield ContentTask.spawn(aBrowser, aPriority, function* (aPriority) {
|
||||
docShell.QueryInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsIDocumentLoader)
|
||||
.loadGroup
|
||||
.QueryInterface(Ci.nsISupportsPriority)
|
||||
.priority = aPriority;
|
||||
});
|
||||
}
|
||||
|
||||
function* isWindowState(aWindow, aTabPriorities) {
|
||||
let browsers = aWindow.gBrowser.browsers;
|
||||
// Make sure we have the right number of tabs & priorities
|
||||
is(browsers.length, aTabPriorities.length,
|
||||
"Window has expected number of tabs");
|
||||
// aState should be in format [ priority, priority, priority ]
|
||||
for (let i = 0; i < browsers.length; i++) {
|
||||
is(yield getPriority(browsers[i]), aTabPriorities[i],
|
||||
"Tab " + i + " had expected priority");
|
||||
}
|
||||
}
|
||||
|
||||
function promiseWaitForFocus(aWindow) {
|
||||
return new Promise((resolve) => {
|
||||
waitForFocus(resolve, aWindow);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
// This is the real test. It creates multiple tabs & windows, changes focus,
|
||||
// closes windows/tabs to make sure we behave correctly.
|
||||
// This test assumes that no priorities have been adjusted and the loadgroup
|
||||
// priority starts at 0.
|
||||
function test_behavior() {
|
||||
|
||||
// Call window "window_A" to make the test easier to follow
|
||||
let window_A = window;
|
||||
// Call window "window_A" to make the test easier to follow
|
||||
let window_A = window;
|
||||
|
||||
// Test 1 window, 1 tab case.
|
||||
isWindowState(window_A, [-10]);
|
||||
// Test 1 window, 1 tab case.
|
||||
yield isWindowState(window_A, [HIGH]);
|
||||
|
||||
// Exising tab is tab_A1
|
||||
let tab_A2 = window_A.gBrowser.addTab("http://example.com");
|
||||
let tab_A3 = window_A.gBrowser.addTab("about:config");
|
||||
tab_A3.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab_A3.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
// Exising tab is tab_A1
|
||||
let tab_A2 = window_A.gBrowser.addTab("http://example.com");
|
||||
let tab_A3 = window_A.gBrowser.addTab("about:config");
|
||||
yield BrowserTestUtils.browserLoaded(tab_A3.linkedBrowser);
|
||||
|
||||
// tab_A2 isn't focused yet
|
||||
isWindowState(window_A, [-10, 0, 0]);
|
||||
// tab_A2 isn't focused yet
|
||||
yield isWindowState(window_A, [HIGH, NORMAL, NORMAL]);
|
||||
|
||||
// focus tab_A2 & make sure priority got updated
|
||||
window_A.gBrowser.selectedTab = tab_A2;
|
||||
isWindowState(window_A, [0, -10, 0]);
|
||||
// focus tab_A2 & make sure priority got updated
|
||||
window_A.gBrowser.selectedTab = tab_A2;
|
||||
yield isWindowState(window_A, [NORMAL, HIGH, NORMAL]);
|
||||
|
||||
window_A.gBrowser.removeTab(tab_A2);
|
||||
// Next tab is auto selected
|
||||
isWindowState(window_A, [0, -10]);
|
||||
window_A.gBrowser.removeTab(tab_A2);
|
||||
// Next tab is auto selected synchronously as part of removeTab, and we
|
||||
// expect the priority to be updated immediately.
|
||||
yield isWindowState(window_A, [NORMAL, HIGH]);
|
||||
|
||||
// Open another window then play with focus
|
||||
let window_B = openDialog(location, "_blank", "chrome,all,dialog=no", "http://example.com");
|
||||
window_B.addEventListener("load", function(aEvent) {
|
||||
window_B.removeEventListener("load", arguments.callee, false);
|
||||
window_B.gBrowser.addEventListener("load", function(aEvent) {
|
||||
// waitForFocus can attach to the wrong "window" with about:blank loading first
|
||||
// So just ensure that we're getting the load event for the right URI
|
||||
if (window_B.gBrowser.currentURI.spec == "about:blank")
|
||||
return;
|
||||
window_B.gBrowser.removeEventListener("load", arguments.callee, true);
|
||||
// Open another window then play with focus
|
||||
let window_B = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
waitForFocus(function() {
|
||||
isWindowState(window_A, [10, 0]);
|
||||
isWindowState(window_B, [-10]);
|
||||
yield promiseWaitForFocus(window_B);
|
||||
yield isWindowState(window_A, [LOW, NORMAL]);
|
||||
yield isWindowState(window_B, [HIGH]);
|
||||
|
||||
waitForFocus(function() {
|
||||
isWindowState(window_A, [0, -10]);
|
||||
isWindowState(window_B, [0]);
|
||||
yield promiseWaitForFocus(window_A);
|
||||
yield isWindowState(window_A, [NORMAL, HIGH]);
|
||||
yield isWindowState(window_B, [NORMAL]);
|
||||
|
||||
waitForFocus(function() {
|
||||
isWindowState(window_A, [10, 0]);
|
||||
isWindowState(window_B, [-10]);
|
||||
|
||||
// And we're done. Cleanup & run the next test
|
||||
window_B.close();
|
||||
window_A.gBrowser.removeTab(tab_A3);
|
||||
executeSoon(runNextTest);
|
||||
}, window_B);
|
||||
}, window_A);
|
||||
}, window_B);
|
||||
}, true);
|
||||
}, false);
|
||||
}, true);
|
||||
|
||||
}
|
||||
yield promiseWaitForFocus(window_B);
|
||||
yield isWindowState(window_A, [LOW, NORMAL]);
|
||||
yield isWindowState(window_B, [HIGH]);
|
||||
|
||||
// Cleanup
|
||||
window_A.gBrowser.removeTab(tab_A3);
|
||||
yield BrowserTestUtils.closeWindow(window_B);
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
// This is more a test of nsLoadGroup and how it handles priorities. But since
|
||||
// we depend on its behavior, it's good to test it. This is testing that there
|
||||
// are no errors if we adjust beyond nsISupportsPriority's bounds.
|
||||
function test_extremePriorities() {
|
||||
let tab_A1 = gBrowser.tabContainer.getItemAtIndex(0);
|
||||
let oldPriority = getPriority(tab_A1);
|
||||
|
||||
// Set the priority of tab_A1 to the lowest possible. Selecting the other tab
|
||||
// will try to lower it
|
||||
setPriority(tab_A1, Ci.nsISupportsPriority.PRIORITY_LOWEST);
|
||||
yield promiseWaitForFocus();
|
||||
|
||||
let tab_A2 = gBrowser.addTab("http://example.com");
|
||||
tab_A2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab_A2.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
gBrowser.selectedTab = tab_A2;
|
||||
is(getPriority(tab_A1), Ci.nsISupportsPriority.PRIORITY_LOWEST - PRIORITY_DELTA,
|
||||
"Can adjust priority beyond 'lowest'");
|
||||
let tab1 = gBrowser.tabs[0];
|
||||
let oldPriority = yield getPriority(tab1);
|
||||
|
||||
// Now set priority to "highest" and make sure that no errors occur.
|
||||
setPriority(tab_A1, Ci.nsISupportsPriority.PRIORITY_HIGHEST);
|
||||
gBrowser.selectedTab = tab_A1;
|
||||
// Set the priority of tab1 to the lowest possible. Selecting the other tab
|
||||
// will try to lower it
|
||||
yield setPriority(tab1, LOWEST);
|
||||
|
||||
is(getPriority(tab_A1), Ci.nsISupportsPriority.PRIORITY_HIGHEST + PRIORITY_DELTA,
|
||||
"Can adjust priority beyond 'highest'");
|
||||
let tab2 = gBrowser.addTab("http://example.com");
|
||||
yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
|
||||
gBrowser.selectedTab = tab2;
|
||||
is(yield getPriority(tab1), LOWEST - DELTA, "Can adjust priority beyond 'lowest'");
|
||||
|
||||
// Cleanup, run next test
|
||||
gBrowser.removeTab(tab_A2);
|
||||
executeSoon(function() {
|
||||
setPriority(tab_A1, oldPriority);
|
||||
runNextTest();
|
||||
});
|
||||
// Now set priority to "highest" and make sure that no errors occur.
|
||||
yield setPriority(tab1, HIGHEST);
|
||||
gBrowser.selectedTab = tab1;
|
||||
|
||||
}, true);
|
||||
is(yield getPriority(tab1), HIGHEST + DELTA, "Can adjust priority beyond 'highest'");
|
||||
|
||||
// Cleanup
|
||||
gBrowser.removeTab(tab2);
|
||||
yield setPriority(tab1, oldPriority);
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
// This tests that the priority doesn't get lost when switching the browser's remoteness
|
||||
|
||||
if (!gMultiProcessBrowser) {
|
||||
return;
|
||||
}
|
||||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
let tests = [test_behavior, test_extremePriorities];
|
||||
function runNextTest() {
|
||||
if (tests.length) {
|
||||
// Linux has problems if window isn't focused. Should help prevent [orange].
|
||||
waitForFocus(tests.shift());
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
browser.loadURI("http://example.com");
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
ok(browser.isRemoteBrowser, "web page should be loaded in remote browser");
|
||||
is(yield getPriority(browser), HIGH, "priority of selected tab should be 'high'");
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
browser.loadURI("about:rights");
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
ok(!browser.isRemoteBrowser, "about:rights should switch browser to non-remote");
|
||||
is(yield getPriority(browser), HIGH,
|
||||
"priority of selected tab should be 'high' when going from remote to non-remote");
|
||||
|
||||
browser.loadURI("http://example.com");
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
ok(browser.isRemoteBrowser, "going from about:rights to web page should switch browser to remote");
|
||||
is(yield getPriority(browser), HIGH,
|
||||
"priority of selected tab should be 'high' when going from non-remote to remote");
|
||||
});
|
||||
|
@ -10,4 +10,4 @@
|
||||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
47.0a1
|
||||
48.0a1
|
||||
|
@ -224,17 +224,18 @@ var AnimationsController = {
|
||||
return;
|
||||
}
|
||||
|
||||
this.nodeFront = gInspector.selection.nodeFront;
|
||||
let done = gInspector.updating("animationscontroller");
|
||||
|
||||
if (!gInspector.selection.isConnected() ||
|
||||
!gInspector.selection.isElementNode()) {
|
||||
!gInspector.selection.isElementNode() ||
|
||||
gInspector.selection.isPseudoElementNode()) {
|
||||
this.destroyAnimationPlayers();
|
||||
this.emit(this.PLAYERS_UPDATED_EVENT);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
this.nodeFront = gInspector.selection.nodeFront;
|
||||
yield this.refreshAnimationPlayers(this.nodeFront);
|
||||
this.emit(this.PLAYERS_UPDATED_EVENT, this.animationPlayers);
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
</div>
|
||||
<div id="players"></div>
|
||||
<div id="error-message">
|
||||
<p>&invalidElement;</p>
|
||||
<p id="error-type"></p>
|
||||
<p>&selectElement;</p>
|
||||
<button id="element-picker" standalone="true" class="devtools-button"></button>
|
||||
</div>
|
||||
|
@ -183,6 +183,9 @@ var AnimationsPanel = {
|
||||
} else {
|
||||
document.body.setAttribute("empty", "true");
|
||||
document.body.removeAttribute("timeline");
|
||||
$("#error-type").textContent = gInspector.selection.isPseudoElementNode()
|
||||
? L10N.getStr("panel.pseudoElementSelected")
|
||||
: L10N.getStr("panel.invalidElementSelected");
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1,21 +1,20 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
// Test that the panel shows no animation data for invalid or not animated nodes
|
||||
|
||||
const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {inspector, panel, window} = yield openAnimationInspector();
|
||||
let {document} = window;
|
||||
|
||||
let {inspector, panel} = yield openAnimationInspector();
|
||||
yield testEmptyPanel(inspector, panel);
|
||||
});
|
||||
|
||||
function* testEmptyPanel(inspector, panel) {
|
||||
info("Select node .still and check that the panel is empty");
|
||||
let stillNode = yield getNodeFront(".still", inspector);
|
||||
let onUpdated = panel.once(panel.UI_UPDATED_EVENT);
|
||||
@ -26,6 +25,9 @@ function* testEmptyPanel(inspector, panel) {
|
||||
"No animation players stored in the timeline component for a still node");
|
||||
is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 0,
|
||||
"No animation displayed in the timeline component for a still node");
|
||||
is(document.querySelector("#error-type").textContent,
|
||||
L10N.getStr("panel.invalidElementSelected"),
|
||||
"The correct error message is displayed");
|
||||
|
||||
info("Select the comment text node and check that the panel is empty");
|
||||
let commentNode = yield inspector.walker.previousSibling(stillNode);
|
||||
@ -36,4 +38,25 @@ function* testEmptyPanel(inspector, panel) {
|
||||
is(panel.animationsTimelineComponent.animations.length, 0,
|
||||
"No animation players stored in the timeline component for a text node");
|
||||
is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 0,
|
||||
"No animation displayed in the timeline component for a text node");}
|
||||
"No animation displayed in the timeline component for a text node");
|
||||
is(document.querySelector("#error-type").textContent,
|
||||
L10N.getStr("panel.invalidElementSelected"),
|
||||
"The correct error message is displayed");
|
||||
|
||||
info("Select the pseudo element node and check that the panel is empty " +
|
||||
"and contains the special animated pseudo-element message");
|
||||
let pseudoElParent = yield getNodeFront(".pseudo", inspector);
|
||||
let {nodes} = yield inspector.walker.children(pseudoElParent);
|
||||
let pseudoEl = nodes[0];
|
||||
onUpdated = panel.once(panel.UI_UPDATED_EVENT);
|
||||
yield selectNode(pseudoEl, inspector);
|
||||
yield onUpdated;
|
||||
|
||||
is(panel.animationsTimelineComponent.animations.length, 0,
|
||||
"No animation players stored in the timeline component for a pseudo-node");
|
||||
is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 0,
|
||||
"No animation displayed in the timeline component for a pseudo-node");
|
||||
is(document.querySelector("#error-type").textContent,
|
||||
L10N.getStr("panel.pseudoElementSelected"),
|
||||
"The correct error message is displayed");
|
||||
});
|
||||
|
@ -82,6 +82,21 @@
|
||||
animation: no-compositor 10s cubic-bezier(.57,-0.02,1,.31) forwards;
|
||||
}
|
||||
|
||||
.pseudo {
|
||||
top: 800px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.pseudo::before {
|
||||
content: "";
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
border-radius: 50%;
|
||||
background: black;
|
||||
position: absolute;
|
||||
animation: simple-animation 1s infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes simple-animation {
|
||||
100% {
|
||||
transform: translateX(300px);
|
||||
@ -112,5 +127,6 @@
|
||||
<div class="ball long"></div>
|
||||
<div class="ball negative-delay"></div>
|
||||
<div class="ball no-compositor"></div>
|
||||
<div class="ball pseudo"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -605,17 +605,19 @@ MarkupView.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore keystrokes with modifiers to allow native shortcuts (such as save:
|
||||
// accel + S) to bubble up.
|
||||
if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.keyCode) {
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_H:
|
||||
if (event.metaKey || event.shiftKey) {
|
||||
handled = false;
|
||||
let node = this._selectedContainer.node;
|
||||
if (node.hidden) {
|
||||
this.walker.unhideNode(node);
|
||||
} else {
|
||||
let node = this._selectedContainer.node;
|
||||
if (node.hidden) {
|
||||
this.walker.unhideNode(node);
|
||||
} else {
|
||||
this.walker.hideNode(node);
|
||||
}
|
||||
this.walker.hideNode(node);
|
||||
}
|
||||
break;
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_DELETE:
|
||||
|
@ -88,6 +88,7 @@ skip-if = (e10s && os == 'mac') # bug 1252345
|
||||
[browser_markup_keybindings_03.js]
|
||||
[browser_markup_keybindings_04.js]
|
||||
[browser_markup_keybindings_delete_attributes.js]
|
||||
[browser_markup_keybindings_scrolltonode.js]
|
||||
[browser_markup_mutation_01.js]
|
||||
[browser_markup_mutation_02.js]
|
||||
[browser_markup_node_names.js]
|
||||
|
@ -0,0 +1,87 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test the keyboard shortcut "S" used to scroll to the selected node.
|
||||
|
||||
const HTML =
|
||||
`<div style="width: 300px; height: 3000px; position:relative;">
|
||||
<div id="scroll-top"
|
||||
style="height: 50px; top: 0; position:absolute;">
|
||||
TOP</div>
|
||||
<div id="scroll-bottom"
|
||||
style="height: 50px; bottom: 0; position:absolute;">
|
||||
BOTTOM</div>
|
||||
</div>`;
|
||||
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
|
||||
|
||||
add_task(function*() {
|
||||
let { inspector, testActor } = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
info("Make sure the markup frame has the focus");
|
||||
inspector.markup._frame.focus();
|
||||
|
||||
info("Before test starts, #scroll-top is visible, #scroll-bottom is hidden");
|
||||
yield checkElementIsInViewport("#scroll-top", true, testActor);
|
||||
yield checkElementIsInViewport("#scroll-bottom", false, testActor);
|
||||
|
||||
info("Select the #scroll-bottom node");
|
||||
yield selectNode("#scroll-bottom", inspector);
|
||||
info("Press S to scroll to the bottom node");
|
||||
let waitForScroll = testActor.waitForEventOnNode("scroll");
|
||||
yield EventUtils.synthesizeKey("S", {}, inspector.panelWin);
|
||||
yield waitForScroll;
|
||||
ok(true, "Scroll event received");
|
||||
|
||||
info("#scroll-top should be scrolled out, #scroll-bottom should be visible");
|
||||
yield checkElementIsInViewport("#scroll-top", false, testActor);
|
||||
yield checkElementIsInViewport("#scroll-bottom", true, testActor);
|
||||
|
||||
info("Select the #scroll-top node");
|
||||
yield selectNode("#scroll-top", inspector);
|
||||
info("Press S to scroll to the top node");
|
||||
waitForScroll = testActor.waitForEventOnNode("scroll");
|
||||
yield EventUtils.synthesizeKey("S", {}, inspector.panelWin);
|
||||
yield waitForScroll;
|
||||
ok(true, "Scroll event received");
|
||||
|
||||
info("#scroll-top should be visible, #scroll-bottom should be scrolled out");
|
||||
yield checkElementIsInViewport("#scroll-top", true, testActor);
|
||||
yield checkElementIsInViewport("#scroll-bottom", false, testActor);
|
||||
|
||||
info("Select #scroll-bottom node");
|
||||
yield selectNode("#scroll-bottom", inspector);
|
||||
info("Press shift + S, nothing should happen due to the modifier");
|
||||
yield EventUtils.synthesizeKey("S", {shiftKey: true}, inspector.panelWin);
|
||||
|
||||
info("Same state, #scroll-top is visible, #scroll-bottom is scrolled out");
|
||||
yield checkElementIsInViewport("#scroll-top", true, testActor);
|
||||
yield checkElementIsInViewport("#scroll-bottom", false, testActor);
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify that the element matching the provided selector is either in or out
|
||||
* of the viewport, depending on the provided "expected" argument.
|
||||
* Returns a promise that will resolve when the test has been performed.
|
||||
*
|
||||
* @param {String} selector
|
||||
* css selector for the element to test
|
||||
* @param {Boolean} expected
|
||||
* true if the element is expected to be in the viewport, false otherwise
|
||||
* @param {TestActor} testActor
|
||||
* current test actor
|
||||
* @return {Promise} promise
|
||||
*/
|
||||
function* checkElementIsInViewport(selector, expected, testActor) {
|
||||
let isInViewport = yield testActor.eval(`
|
||||
let node = content.document.querySelector("${selector}");
|
||||
let rect = node.getBoundingClientRect();
|
||||
rect.bottom >= 0 && rect.right >= 0 &&
|
||||
rect.top <= content.innerHeight && rect.left <= content.innerWidth;
|
||||
`);
|
||||
|
||||
is(isInViewport, expected,
|
||||
selector + " in the viewport: expected to be " + expected);
|
||||
}
|
@ -15,10 +15,6 @@
|
||||
sidebar tab -->
|
||||
<!ENTITY animationInspectorTitle "Animations">
|
||||
|
||||
<!-- LOCALIZATION NOTE (invalidElement): This is the label shown in the panel
|
||||
when an invalid node is currently selected in the inspector. -->
|
||||
<!ENTITY invalidElement "No animations were found for the current element.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (selectElement): This is the label shown in the panel
|
||||
when an invalid node is currently selected in the inspector, to invite the
|
||||
user to select a new node by clicking on the element-picker icon. -->
|
||||
|
@ -10,6 +10,18 @@
|
||||
# A good criteria is the language in which you'd find the best
|
||||
# documentation on web development on the web.
|
||||
|
||||
# LOCALIZATION NOTE (panel.invalidElementSelected):
|
||||
# This is the label shown in the panel when an invalid node is currently
|
||||
# selected in the inspector (i.e. a non-element node or a node that is not
|
||||
# animated).
|
||||
panel.invalidElementSelected=No animations were found for the current element.
|
||||
|
||||
# LOCALIZATION NOTE (panel.pseudoElementSelected):
|
||||
# This is the label shown in the panel when a pseudo-element is currently
|
||||
# selected in the inspector (pseudo-elements can be animated, but the tool
|
||||
# doesn't yet support them).
|
||||
panel.pseudoElementSelected=Animated pseudo-elements are not supported yet.
|
||||
|
||||
# LOCALIZATION NOTE (player.animationNameLabel):
|
||||
# This string is displayed in each animation player widget. It is the label
|
||||
# displayed before the animation name.
|
||||
|
@ -14,6 +14,7 @@ const { actions, snapshotState: states, viewState, dominatorTreeState } = requir
|
||||
const telemetry = require("../telemetry");
|
||||
const view = require("./view");
|
||||
const refresh = require("./refresh");
|
||||
const diffing = require("./diffing");
|
||||
|
||||
/**
|
||||
* A series of actions are fired from this task to save, read and generate the
|
||||
@ -427,6 +428,10 @@ const clearSnapshots = exports.clearSnapshots = function (heapWorker) {
|
||||
|
||||
dispatch({ type: actions.DELETE_SNAPSHOTS_START, ids });
|
||||
|
||||
if (getState().diffing) {
|
||||
dispatch(diffing.toggleDiffing());
|
||||
}
|
||||
|
||||
yield Promise.all(snapshots.map(snapshot => {
|
||||
return heapWorker.deleteHeapSnapshot(snapshot.path).catch(error => {
|
||||
reportException("clearSnapshots", error);
|
||||
|
@ -13,7 +13,6 @@ module.exports = createClass({
|
||||
displayName: "Toolbar",
|
||||
propTypes: {
|
||||
censusDisplays: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
displayName: PropTypes.string.isRequired,
|
||||
})).isRequired,
|
||||
onTakeSnapshotClick: PropTypes.func.isRequired,
|
||||
@ -29,7 +28,6 @@ module.exports = createClass({
|
||||
view: PropTypes.string.isRequired,
|
||||
onViewChange: PropTypes.func.isRequired,
|
||||
dominatorTreeDisplays: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
displayName: PropTypes.string.isRequired,
|
||||
})).isRequired,
|
||||
onDominatorTreeDisplayChange: PropTypes.func.isRequired,
|
||||
|
@ -0,0 +1,58 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that clearSnapshots disables diffing when deleting snapshots
|
||||
|
||||
const {
|
||||
takeSnapshotAndCensus,
|
||||
clearSnapshots } = require("devtools/client/memory/actions/snapshot");
|
||||
const {
|
||||
snapshotState: states,
|
||||
actions } = require("devtools/client/memory/constants");
|
||||
const {
|
||||
toggleDiffing,
|
||||
selectSnapshotForDiffingAndRefresh
|
||||
} = require("devtools/client/memory/actions/diffing");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
let front = new StubbedMemoryFront();
|
||||
let heapWorker = new HeapAnalysesClient();
|
||||
yield front.attach();
|
||||
let store = Store();
|
||||
const { getState, dispatch } = store;
|
||||
|
||||
ok(true, "Create 2 snapshots in SAVED_CENSUS state");
|
||||
dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
ok(true, "Snapshots created in SAVED_CENSUS state");
|
||||
yield waitUntilSnapshotState(store,
|
||||
[states.SAVED_CENSUS, states.SAVED_CENSUS]);
|
||||
|
||||
dispatch(toggleDiffing());
|
||||
dispatch(selectSnapshotForDiffingAndRefresh(heapWorker,
|
||||
getState().snapshots[0]));
|
||||
dispatch(selectSnapshotForDiffingAndRefresh(heapWorker,
|
||||
getState().snapshots[1]));
|
||||
ok(getState().diffing, "We should be in diffing view");
|
||||
|
||||
ok(true, "Dispatch clearSnapshots action");
|
||||
let deleteEvents = Promise.all([
|
||||
waitUntilAction(store, actions.DELETE_SNAPSHOTS_START),
|
||||
waitUntilAction(store, actions.DELETE_SNAPSHOTS_END)
|
||||
]);
|
||||
dispatch(clearSnapshots(heapWorker));
|
||||
yield deleteEvents;
|
||||
ok(true, "received delete snapshots events");
|
||||
|
||||
ok(getState().snapshots.length === 0, "Snapshots array should be empty");
|
||||
ok(!getState().diffing, "We should no longer be diffing");
|
||||
|
||||
heapWorker.destroy();
|
||||
yield front.detach();
|
||||
});
|
@ -15,6 +15,7 @@ skip-if = toolkit == 'android' || toolkit == 'gonk'
|
||||
[test_action-clear-snapshots_03.js]
|
||||
[test_action-clear-snapshots_04.js]
|
||||
[test_action-clear-snapshots_05.js]
|
||||
[test_action-clear-snapshots_06.js]
|
||||
[test_action-export-snapshot.js]
|
||||
[test_action-filter-01.js]
|
||||
[test_action-filter-02.js]
|
||||
|
@ -23,14 +23,26 @@ let App = createClass({
|
||||
onExit: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
onRotateViewport(id) {
|
||||
this.props.dispatch(rotateViewport(id));
|
||||
},
|
||||
|
||||
onResizeViewport(id, width, height) {
|
||||
this.props.dispatch(resizeViewport(id, width, height));
|
||||
},
|
||||
|
||||
render() {
|
||||
let {
|
||||
dispatch,
|
||||
location,
|
||||
viewports,
|
||||
onExit,
|
||||
} = this.props;
|
||||
|
||||
let {
|
||||
onRotateViewport,
|
||||
onResizeViewport,
|
||||
} = this;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
id: "app",
|
||||
@ -41,9 +53,8 @@ let App = createClass({
|
||||
Viewports({
|
||||
location,
|
||||
viewports,
|
||||
onRotateViewport: id => dispatch(rotateViewport(id)),
|
||||
onResizeViewport: (id, width, height) =>
|
||||
dispatch(resizeViewport(id, width, height)),
|
||||
onRotateViewport,
|
||||
onResizeViewport,
|
||||
})
|
||||
);
|
||||
},
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { DOM: dom, createClass, PropTypes } =
|
||||
const { DOM: dom, createClass, PropTypes, addons } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
|
||||
const Types = require("../types");
|
||||
@ -13,6 +13,8 @@ module.exports = createClass({
|
||||
|
||||
displayName: "Browser",
|
||||
|
||||
mixins: [ addons.PureRenderMixin ],
|
||||
|
||||
propTypes: {
|
||||
location: Types.location.isRequired,
|
||||
width: Types.viewport.width.isRequired,
|
||||
|
@ -5,13 +5,15 @@
|
||||
"use strict";
|
||||
|
||||
const { getStr } = require("./utils/l10n");
|
||||
const { DOM: dom, createClass, PropTypes } =
|
||||
const { DOM: dom, createClass, PropTypes, addons } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
|
||||
module.exports = createClass({
|
||||
|
||||
displayName: "GlobalToolbar",
|
||||
|
||||
mixins: [ addons.PureRenderMixin ],
|
||||
|
||||
propTypes: {
|
||||
onExit: PropTypes.func.isRequired,
|
||||
},
|
||||
|
@ -4,13 +4,15 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { DOM: dom, createClass, PropTypes } =
|
||||
const { DOM: dom, createClass, PropTypes, addons } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
|
||||
module.exports = createClass({
|
||||
|
||||
displayName: "ViewportToolbar",
|
||||
|
||||
mixins: [ addons.PureRenderMixin ],
|
||||
|
||||
propTypes: {
|
||||
onRotateViewport: PropTypes.func.isRequired,
|
||||
},
|
||||
|
@ -22,14 +22,35 @@ module.exports = createClass({
|
||||
onRotateViewport: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
onResizeViewport(width, height) {
|
||||
let {
|
||||
viewport,
|
||||
onResizeViewport,
|
||||
} = this.props;
|
||||
|
||||
onResizeViewport(viewport.id, width, height);
|
||||
},
|
||||
|
||||
onRotateViewport() {
|
||||
let {
|
||||
viewport,
|
||||
onRotateViewport,
|
||||
} = this.props;
|
||||
|
||||
onRotateViewport(viewport.id);
|
||||
},
|
||||
|
||||
render() {
|
||||
let {
|
||||
location,
|
||||
viewport,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
} = this.props;
|
||||
|
||||
let {
|
||||
onRotateViewport,
|
||||
onResizeViewport,
|
||||
} = this;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "viewport",
|
||||
|
@ -38,9 +38,8 @@ module.exports = createClass({
|
||||
key: viewport.id,
|
||||
location,
|
||||
viewport,
|
||||
onResizeViewport: (width, height) =>
|
||||
onResizeViewport(viewport.id, width, height),
|
||||
onRotateViewport: () => onRotateViewport(viewport.id),
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
function test()
|
||||
{
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
@ -15,9 +15,7 @@ function test()
|
||||
content.location = "data:text/html,test context switch in Scratchpad";
|
||||
}
|
||||
|
||||
|
||||
function runTests()
|
||||
{
|
||||
function runTests() {
|
||||
let sp = gScratchpadWindow.Scratchpad;
|
||||
let contentMenu = gScratchpadWindow.document.getElementById("sp-menu-content");
|
||||
let chromeMenu = gScratchpadWindow.document.getElementById("sp-menu-browser");
|
||||
@ -29,7 +27,7 @@ function runTests()
|
||||
|
||||
let tests = [{
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
prepare: function*() {
|
||||
sp.setContentContext();
|
||||
|
||||
is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_CONTENT,
|
||||
@ -46,17 +44,18 @@ function runTests()
|
||||
|
||||
sp.editor.setText("window.foobarBug636725 = 'aloha';");
|
||||
|
||||
ok(!content.wrappedJSObject.foobarBug636725,
|
||||
"no content.foobarBug636725");
|
||||
let pageResult = yield inContent(function*() {
|
||||
return content.wrappedJSObject.foobarBug636725;
|
||||
});
|
||||
ok(!pageResult, "no content.foobarBug636725");
|
||||
},
|
||||
then: function() {
|
||||
then: function*() {
|
||||
is(content.wrappedJSObject.foobarBug636725, "aloha",
|
||||
"content.foobarBug636725 has been set");
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
prepare: function*() {
|
||||
sp.setBrowserContext();
|
||||
|
||||
is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_BROWSER,
|
||||
@ -77,62 +76,57 @@ function runTests()
|
||||
is(sp.getText(), "window.foobarBug636725 = 'aloha2';",
|
||||
"setText() worked");
|
||||
},
|
||||
then: function() {
|
||||
then: function*() {
|
||||
is(window.foobarBug636725, "aloha2",
|
||||
"window.foobarBug636725 has been set");
|
||||
|
||||
delete window.foobarBug636725;
|
||||
ok(!window.foobarBug636725, "no window.foobarBug636725");
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
prepare: function*() {
|
||||
sp.editor.replaceText("gBrowser", sp.editor.getPosition(7));
|
||||
|
||||
is(sp.getText(), "window.gBrowser",
|
||||
"setText() worked with no end for the replace range");
|
||||
},
|
||||
then: function([, , result]) {
|
||||
then: function*([, , result]) {
|
||||
is(result.class, "XULElement",
|
||||
"chrome context has access to chrome objects");
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
prepare: function*() {
|
||||
// Check that the sandbox is cached.
|
||||
sp.editor.setText("typeof foobarBug636725cache;");
|
||||
},
|
||||
then: function([, , result]) {
|
||||
then: function*([, , result]) {
|
||||
is(result, "undefined", "global variable does not exist");
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
prepare: function*() {
|
||||
sp.editor.setText("window.foobarBug636725cache = 'foo';" +
|
||||
"typeof foobarBug636725cache;");
|
||||
},
|
||||
then: function([, , result]) {
|
||||
then: function*([, , result]) {
|
||||
is(result, "string",
|
||||
"global variable exists across two different executions");
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
prepare: function*() {
|
||||
sp.editor.setText("window.foobarBug636725cache2 = 'foo';" +
|
||||
"typeof foobarBug636725cache2;");
|
||||
},
|
||||
then: function([, , result]) {
|
||||
then: function*([, , result]) {
|
||||
is(result, "string",
|
||||
"global variable exists across two different executions");
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
prepare: function*() {
|
||||
sp.setContentContext();
|
||||
|
||||
is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_CONTENT,
|
||||
@ -140,7 +134,7 @@ function runTests()
|
||||
|
||||
sp.editor.setText("typeof foobarBug636725cache2;");
|
||||
},
|
||||
then: function([, , result]) {
|
||||
then: function*([, , result]) {
|
||||
is(result, "undefined",
|
||||
"global variable no longer exists after changing the context");
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
function test()
|
||||
{
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
@ -15,49 +15,52 @@ function test()
|
||||
content.location = "data:text/html,<p>test run() and display() in Scratchpad";
|
||||
}
|
||||
|
||||
|
||||
function runTests()
|
||||
{
|
||||
function runTests() {
|
||||
let sp = gScratchpadWindow.Scratchpad;
|
||||
let tests = [{
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
content.wrappedJSObject.foobarBug636725 = 1;
|
||||
prepare: function*() {
|
||||
yield inContent(function*() {
|
||||
content.wrappedJSObject.foobarBug636725 = 1;
|
||||
});
|
||||
sp.editor.setText("++window.foobarBug636725");
|
||||
},
|
||||
then: function([code, , result]) {
|
||||
then: function*([code, , result]) {
|
||||
is(code, sp.getText(), "code is correct");
|
||||
is(result, content.wrappedJSObject.foobarBug636725,
|
||||
|
||||
let pageResult = yield inContent(function*() {
|
||||
return content.wrappedJSObject.foobarBug636725;
|
||||
});
|
||||
is(result, pageResult,
|
||||
"result is correct");
|
||||
|
||||
is(sp.getText(), "++window.foobarBug636725",
|
||||
"run() does not change the editor content");
|
||||
|
||||
is(content.wrappedJSObject.foobarBug636725, 2,
|
||||
"run() updated window.foobarBug636725");
|
||||
is(pageResult, 2, "run() updated window.foobarBug636725");
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
method: "display",
|
||||
prepare: function() {},
|
||||
then: function() {
|
||||
is(content.wrappedJSObject.foobarBug636725, 3,
|
||||
"display() updated window.foobarBug636725");
|
||||
prepare: function*() {},
|
||||
then: function*() {
|
||||
let pageResult = yield inContent(function*() {
|
||||
return content.wrappedJSObject.foobarBug636725;
|
||||
});
|
||||
is(pageResult, 3, "display() updated window.foobarBug636725");
|
||||
|
||||
is(sp.getText(), "++window.foobarBug636725\n/*\n3\n*/",
|
||||
"display() shows evaluation result in the textbox");
|
||||
|
||||
is(sp.editor.getSelection(), "\n/*\n3\n*/", "getSelection is correct");
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
prepare: function*() {
|
||||
sp.editor.setText("window.foobarBug636725 = 'a';\n" +
|
||||
"window.foobarBug636725 = 'b';");
|
||||
sp.editor.setSelection({ line: 0, ch: 0 }, { line: 0, ch: 29 });
|
||||
},
|
||||
then: function([code, , result]) {
|
||||
then: function*([code, , result]) {
|
||||
is(code, "window.foobarBug636725 = 'a';", "code is correct");
|
||||
is(result, "a", "result is correct");
|
||||
|
||||
@ -65,20 +68,23 @@ function runTests()
|
||||
"window.foobarBug636725 = 'b';",
|
||||
"run() does not change the textbox value");
|
||||
|
||||
is(content.wrappedJSObject.foobarBug636725, "a",
|
||||
"run() worked for the selected range");
|
||||
let pageResult = yield inContent(function*() {
|
||||
return content.wrappedJSObject.foobarBug636725;
|
||||
});
|
||||
is(pageResult, "a", "run() worked for the selected range");
|
||||
}
|
||||
},
|
||||
{
|
||||
}, {
|
||||
method: "display",
|
||||
prepare: function() {
|
||||
prepare: function*() {
|
||||
sp.editor.setText("window.foobarBug636725 = 'c';\n" +
|
||||
"window.foobarBug636725 = 'b';");
|
||||
sp.editor.setSelection({ line: 0, ch: 0 }, { line: 0, ch: 22 });
|
||||
},
|
||||
then: function() {
|
||||
is(content.wrappedJSObject.foobarBug636725, "a",
|
||||
"display() worked for the selected range");
|
||||
then: function*() {
|
||||
let pageResult = yield inContent(function*() {
|
||||
return content.wrappedJSObject.foobarBug636725;
|
||||
});
|
||||
is(pageResult, "a", "display() worked for the selected range");
|
||||
|
||||
is(sp.getText(), "window.foobarBug636725" +
|
||||
"\n/*\na\n*/" +
|
||||
|
@ -191,21 +191,19 @@ function runAsyncTests(aScratchpad, aTests)
|
||||
* @return Promise
|
||||
* The promise that will be resolved when all tests are finished.
|
||||
*/
|
||||
function runAsyncCallbackTests(aScratchpad, aTests)
|
||||
{
|
||||
let deferred = promise.defer();
|
||||
var runAsyncCallbackTests = Task.async(function*(aScratchpad, aTests) {
|
||||
for (let {prepare, method, then} of aTests) {
|
||||
yield prepare();
|
||||
let res = yield aScratchpad[method]();
|
||||
yield then(res);
|
||||
}
|
||||
});
|
||||
|
||||
(function runTest() {
|
||||
if (aTests.length) {
|
||||
let test = aTests.shift();
|
||||
test.prepare();
|
||||
aScratchpad[test.method]().then(test.then.bind(test)).then(runTest);
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
})();
|
||||
|
||||
return deferred.promise;
|
||||
/**
|
||||
* A simple wrapper for ContentTask.spawn for more compact code.
|
||||
*/
|
||||
function inContent(generator) {
|
||||
return ContentTask.spawn(gBrowser.selectedBrowser, {}, generator);
|
||||
}
|
||||
|
||||
function cleanup()
|
||||
|
@ -226,6 +226,28 @@ var TestActor = exports.TestActor = protocol.ActorClass({
|
||||
response: {}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Wait for a specific event on a node matching the provided selector.
|
||||
* @param {String} eventName The name of the event to listen to
|
||||
* @param {String} selector Optional: css selector of the node which should
|
||||
* trigger the event. If ommitted, target will be the content window
|
||||
*/
|
||||
waitForEventOnNode: protocol.method(function (eventName, selector) {
|
||||
return new Promise(resolve => {
|
||||
let node = selector ? this._querySelector(selector) : this.content;
|
||||
node.addEventListener(eventName, function onEvent() {
|
||||
node.removeEventListener(eventName, onEvent);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}, {
|
||||
request: {
|
||||
eventName: Arg(0, "string"),
|
||||
selector: Arg(1, "nullable:string")
|
||||
},
|
||||
response: {}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Change the zoom level of the page.
|
||||
* Optionally subscribe to the box-model highlighter's update event and waiting
|
||||
|
@ -232,6 +232,7 @@ ul.children + .tag-line::before {
|
||||
margin-top: .3em;
|
||||
left: 1px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Selected nodes in the tree should have light selected text.
|
||||
|
@ -674,9 +674,7 @@
|
||||
.devtools-separator {
|
||||
margin: 0 2px;
|
||||
width: 2px;
|
||||
background-image: linear-gradient(transparent, hsla(204,45%,98%,.1), transparent),
|
||||
linear-gradient(transparent, hsla(206,37%,4%,.6), transparent),
|
||||
linear-gradient(transparent, hsla(204,45%,98%,.1), transparent);
|
||||
background-image: linear-gradient(transparent 15%, var(--theme-splitter-color) 15%, var(--theme-splitter-color) 85%, transparent 85%);
|
||||
background-size: 1px 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0, 1px, 2px;
|
||||
|
@ -212,7 +212,6 @@ tags = mcb
|
||||
[browser_webconsole_bug_586388_select_all.js]
|
||||
[browser_webconsole_bug_587617_output_copy.js]
|
||||
[browser_webconsole_bug_588342_document_focus.js]
|
||||
skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
|
||||
[browser_webconsole_bug_588730_text_node_insertion.js]
|
||||
[browser_webconsole_bug_588967_input_expansion.js]
|
||||
[browser_webconsole_bug_589162_css_filter.js]
|
||||
|
@ -7,28 +7,30 @@
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 588342";
|
||||
|
||||
var fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
|
||||
|
||||
add_task(function* () {
|
||||
let { browser } = yield loadTab(TEST_URI);
|
||||
|
||||
let hud = yield openConsole();
|
||||
yield consoleOpened(hud);
|
||||
|
||||
is(fm.focusedWindow, browser.contentWindow,
|
||||
"content document has focus");
|
||||
yield checkConsoleFocus(hud);
|
||||
|
||||
fm = null;
|
||||
let isFocused = yield ContentTask.spawn(browser, { }, function* () {
|
||||
var fm = Components.classes["@mozilla.org/focus-manager;1"].
|
||||
getService(Components.interfaces.nsIFocusManager);
|
||||
return fm.focusedWindow == content;
|
||||
});
|
||||
|
||||
ok(isFocused, "content document has focus");
|
||||
});
|
||||
|
||||
function consoleOpened(hud) {
|
||||
let deferred = promise.defer();
|
||||
waitForFocus(function() {
|
||||
is(hud.jsterm.inputNode.getAttribute("focused"), "true",
|
||||
"jsterm input is focused on web console open");
|
||||
isnot(fm.focusedWindow, content, "content document has no focus");
|
||||
closeConsole(null).then(deferred.resolve);
|
||||
}, hud.iframeWindow);
|
||||
function* checkConsoleFocus(hud) {
|
||||
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
|
||||
|
||||
return deferred.promise;
|
||||
yield new Promise(resolve => {
|
||||
waitForFocus(resolve);
|
||||
});
|
||||
|
||||
is(hud.jsterm.inputNode.getAttribute("focused"), "true",
|
||||
"jsterm input is focused on web console open");
|
||||
is(fm.focusedWindow, hud.iframeWindow, "hud window is focused");
|
||||
yield closeConsole(null);
|
||||
}
|
||||
|
@ -2074,17 +2074,6 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
|
||||
RemoveFromWindowList(windowID, listener);
|
||||
return NS_OK;
|
||||
}
|
||||
} else if (loop) {
|
||||
// Record that we gave Loop permission to use camera access.
|
||||
nsCOMPtr<nsIPermissionManager> permManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = permManager->Add(docURI, "camera",
|
||||
nsIPermissionManager::ALLOW_ACTION,
|
||||
nsIPermissionManager::EXPIRE_SESSION,
|
||||
0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "ServiceWorkerManager.h"
|
||||
#include "nsICategoryManager.h"
|
||||
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/unused.h"
|
||||
@ -183,29 +184,43 @@ nsresult
|
||||
PushNotifier::NotifyPushObservers(const nsACString& aScope,
|
||||
Maybe<nsTArray<uint8_t>> aData)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obsService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (!obsService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIPushMessage> message = nullptr;
|
||||
if (aData) {
|
||||
message = new PushMessage(aData.ref());
|
||||
}
|
||||
return obsService->NotifyObservers(message, OBSERVER_TOPIC_PUSH,
|
||||
NS_ConvertUTF8toUTF16(aScope).get());
|
||||
return DoNotifyObservers(message, OBSERVER_TOPIC_PUSH, aScope);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PushNotifier::NotifySubscriptionChangeObservers(const nsACString& aScope)
|
||||
{
|
||||
return DoNotifyObservers(nullptr, OBSERVER_TOPIC_SUBSCRIPTION_CHANGE, aScope);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PushNotifier::DoNotifyObservers(nsISupports *aSubject, const char *aTopic,
|
||||
const nsACString& aScope)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obsService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (!obsService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return obsService->NotifyObservers(nullptr,
|
||||
OBSERVER_TOPIC_SUBSCRIPTION_CHANGE,
|
||||
// If there's a service for this push category, make sure it is alive.
|
||||
nsCOMPtr<nsICategoryManager> catMan =
|
||||
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
||||
if (catMan) {
|
||||
nsXPIDLCString contractId;
|
||||
nsresult rv = catMan->GetCategoryEntry("push",
|
||||
PromiseFlatCString(aScope).get(),
|
||||
getter_Copies(contractId));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Ensure the service is created - we don't need to do anything with
|
||||
// it though - we assume the service constructor attaches a listener.
|
||||
nsCOMPtr<nsISupports> service = do_GetService(contractId);
|
||||
}
|
||||
}
|
||||
return obsService->NotifyObservers(aSubject, aTopic,
|
||||
NS_ConvertUTF8toUTF16(aScope).get());
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,8 @@ private:
|
||||
nsresult NotifyPushObservers(const nsACString& aScope,
|
||||
Maybe<nsTArray<uint8_t>> aData);
|
||||
nsresult NotifySubscriptionChangeObservers(const nsACString& aScope);
|
||||
nsresult DoNotifyObservers(nsISupports *aSubject, const char *aTopic,
|
||||
const nsACString& aScope);
|
||||
bool ShouldNotifyObservers(nsIPrincipal* aPrincipal);
|
||||
bool ShouldNotifyWorkers(nsIPrincipal* aPrincipal);
|
||||
};
|
||||
|
@ -46,6 +46,8 @@ UNIFIED_SOURCES += [
|
||||
'PushNotifier.cpp',
|
||||
]
|
||||
|
||||
TEST_DIRS += ['test/xpcshell']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
|
4
dom/push/test/xpcshell/moz.build
Normal file
@ -0,0 +1,4 @@
|
||||
EXTRA_COMPONENTS += [
|
||||
'PushServiceHandler.js',
|
||||
'PushServiceHandler.manifest',
|
||||
]
|
@ -6,6 +6,8 @@ skip-if = toolkit == 'android'
|
||||
|
||||
[test_clear_origin_data.js]
|
||||
[test_drop_expired.js]
|
||||
[test_handler_service.js]
|
||||
support-files = PushServiceHandler.js PushServiceHandler.manifest
|
||||
[test_notification_ack.js]
|
||||
[test_notification_data.js]
|
||||
[test_notification_duplicate.js]
|
||||
|
@ -63,8 +63,7 @@ public class AppConstants {
|
||||
* If our MAX_SDK_VERSION is lower than ICS, we must not be an ICS device.
|
||||
* Otherwise, we need a range check.
|
||||
*/
|
||||
public static final boolean preM = MAX_SDK_VERSION < 23 ||
|
||||
(MIN_SDK_VERSION < 23 && Build.VERSION.SDK_INT < 23 && !Build.VERSION.RELEASE.equals("M"));
|
||||
public static final boolean preMarshmallow = MAX_SDK_VERSION < 23 || (MIN_SDK_VERSION < 23 && Build.VERSION.SDK_INT < 23);
|
||||
public static final boolean preLollipop = MAX_SDK_VERSION < 21 || (MIN_SDK_VERSION < 21 && Build.VERSION.SDK_INT < 21);
|
||||
public static final boolean preJBMR2 = MAX_SDK_VERSION < 18 || (MIN_SDK_VERSION < 18 && Build.VERSION.SDK_INT < 18);
|
||||
public static final boolean preJBMR1 = MAX_SDK_VERSION < 17 || (MIN_SDK_VERSION < 17 && Build.VERSION.SDK_INT < 17);
|
||||
|
@ -447,8 +447,6 @@ public class Favicons {
|
||||
}
|
||||
loadTasks.clear();
|
||||
}
|
||||
|
||||
LoadFaviconTask.closeHTTPClient();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,17 +4,11 @@
|
||||
|
||||
package org.mozilla.gecko.favicons;
|
||||
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import ch.boye.httpclientandroidlib.Header;
|
||||
import ch.boye.httpclientandroidlib.HttpEntity;
|
||||
import ch.boye.httpclientandroidlib.HttpResponse;
|
||||
import ch.boye.httpclientandroidlib.client.methods.HttpGet;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
@ -22,9 +16,12 @@ import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
|
||||
import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
|
||||
import org.mozilla.gecko.util.GeckoJarReader;
|
||||
import org.mozilla.gecko.util.IOUtils;
|
||||
import org.mozilla.gecko.util.ProxySelector;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
@ -78,14 +75,18 @@ public class LoadFaviconTask {
|
||||
volatile boolean mCancelled;
|
||||
|
||||
// Assuming square favicons, judging by width only is acceptable.
|
||||
protected int targetWidth;
|
||||
protected int targetWidthAndHeight;
|
||||
private LinkedList<LoadFaviconTask> chainees;
|
||||
private boolean isChaining;
|
||||
|
||||
static DefaultHttpClient httpClient = new DefaultHttpClient();
|
||||
private static class Response {
|
||||
public final int contentLength;
|
||||
public final InputStream stream;
|
||||
|
||||
public LoadFaviconTask(Context context, String pageURL, String faviconURL, int flags, OnFaviconLoadedListener listener) {
|
||||
this(context, pageURL, faviconURL, flags, listener, -1, false);
|
||||
private Response(InputStream stream, int contentLength) {
|
||||
this.stream = stream;
|
||||
this.contentLength = contentLength;
|
||||
}
|
||||
}
|
||||
|
||||
public LoadFaviconTask(Context context, String pageURL, String faviconURL, int flags, OnFaviconLoadedListener listener,
|
||||
@ -98,7 +99,7 @@ public class LoadFaviconTask {
|
||||
this.faviconURL = faviconURL;
|
||||
this.listener = listener;
|
||||
this.flags = flags;
|
||||
this.targetWidth = targetWidth;
|
||||
this.targetWidthAndHeight = targetWidth;
|
||||
this.onlyFromLocal = onlyFromLocal;
|
||||
}
|
||||
|
||||
@ -127,73 +128,53 @@ public class LoadFaviconTask {
|
||||
* @param faviconURI URL of Favicon to try and download
|
||||
* @return The HttpResponse containing the downloaded Favicon if successful, null otherwise.
|
||||
*/
|
||||
private HttpResponse tryDownload(URI faviconURI) throws URISyntaxException, IOException {
|
||||
private Response tryDownload(URI faviconURI) throws URISyntaxException, IOException {
|
||||
HashSet<String> visitedLinkSet = new HashSet<>();
|
||||
visitedLinkSet.add(faviconURI.toString());
|
||||
return tryDownloadRecurse(faviconURI, visitedLinkSet);
|
||||
}
|
||||
private HttpResponse tryDownloadRecurse(URI faviconURI, HashSet<String> visited) throws URISyntaxException, IOException {
|
||||
private Response tryDownloadRecurse(URI faviconURI, HashSet<String> visited) throws URISyntaxException, IOException {
|
||||
if (visited.size() == MAX_REDIRECTS_TO_FOLLOW) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpGet request = new HttpGet(faviconURI);
|
||||
request.setHeader("User-Agent", GeckoAppShell.getGeckoInterface().getDefaultUAString());
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
if (response == null) {
|
||||
HttpURLConnection connection = (HttpURLConnection) ProxySelector.openConnectionWithProxy(faviconURI);
|
||||
connection.setRequestProperty("User-Agent", GeckoAppShell.getGeckoInterface().getDefaultUAString());
|
||||
|
||||
connection.connect();
|
||||
|
||||
// Was the response a failure?
|
||||
int status = connection.getResponseCode();
|
||||
|
||||
// Handle HTTP status codes requesting a redirect.
|
||||
if (status >= 300 && status < 400) {
|
||||
final String newURI = connection.getHeaderField("Location");
|
||||
|
||||
// Handle mad webservers.
|
||||
try {
|
||||
if (newURI == null || newURI.equals(faviconURI.toString())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (visited.contains(newURI)) {
|
||||
// Already been redirected here - abort.
|
||||
return null;
|
||||
}
|
||||
|
||||
visited.add(newURI);
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
|
||||
return tryDownloadRecurse(new URI(newURI), visited);
|
||||
}
|
||||
|
||||
if (status >= 400) {
|
||||
connection.disconnect();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response.getStatusLine() != null) {
|
||||
|
||||
// Was the response a failure?
|
||||
int status = response.getStatusLine().getStatusCode();
|
||||
|
||||
// Handle HTTP status codes requesting a redirect.
|
||||
if (status >= 300 && status < 400) {
|
||||
Header header = response.getFirstHeader("Location");
|
||||
|
||||
// Handle mad webservers.
|
||||
final String newURI;
|
||||
try {
|
||||
if (header == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
newURI = header.getValue();
|
||||
if (newURI == null || newURI.equals(faviconURI.toString())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (visited.contains(newURI)) {
|
||||
// Already been redirected here - abort.
|
||||
return null;
|
||||
}
|
||||
|
||||
visited.add(newURI);
|
||||
} finally {
|
||||
// Consume the entity before recurse or exit.
|
||||
try {
|
||||
response.getEntity().consumeContent();
|
||||
} catch (Exception e) {
|
||||
// Doesn't matter.
|
||||
}
|
||||
}
|
||||
|
||||
return tryDownloadRecurse(new URI(newURI), visited);
|
||||
}
|
||||
|
||||
if (status >= 400) {
|
||||
// Consume the entity and exit.
|
||||
try {
|
||||
response.getEntity().consumeContent();
|
||||
} catch (Exception e) {
|
||||
// Doesn't matter.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
return new Response(connection.getInputStream(), connection.getHeaderFieldInt("Content-Length", -1));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -256,22 +237,17 @@ public class LoadFaviconTask {
|
||||
*/
|
||||
private LoadFaviconResult downloadAndDecodeImage(URI targetFaviconURL) throws IOException, URISyntaxException {
|
||||
// Try the URL we were given.
|
||||
HttpResponse response = tryDownload(targetFaviconURL);
|
||||
Response response = tryDownload(targetFaviconURL);
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Decode the image from the fetched response.
|
||||
try {
|
||||
return decodeImageFromResponse(entity);
|
||||
return decodeImageFromResponse(response);
|
||||
} finally {
|
||||
// Close the stream and free related resources.
|
||||
entity.consumeContent();
|
||||
IOUtils.safeStreamClose(response.stream);
|
||||
}
|
||||
}
|
||||
|
||||
@ -279,27 +255,26 @@ public class LoadFaviconTask {
|
||||
* Copies the favicon stream to a buffer and decodes downloaded content into bitmaps using the
|
||||
* FaviconDecoder.
|
||||
*
|
||||
* @param entity HttpEntity containing the favicon stream to decode.
|
||||
* @param response Response containing the favicon stream to decode.
|
||||
* @return A LoadFaviconResult containing the bitmap(s) extracted from the downloaded file, or
|
||||
* null if no or corrupt data were received.
|
||||
* @throws IOException If attempts to fully read the stream result in such an exception, such as
|
||||
* in the event of a transient connection failure.
|
||||
*/
|
||||
private LoadFaviconResult decodeImageFromResponse(HttpEntity entity) throws IOException {
|
||||
private LoadFaviconResult decodeImageFromResponse(Response response) throws IOException {
|
||||
// This may not be provided, but if it is, it's useful.
|
||||
final long entityReportedLength = entity.getContentLength();
|
||||
int bufferSize;
|
||||
if (entityReportedLength > 0) {
|
||||
if (response.contentLength > 0) {
|
||||
// The size was reported and sane, so let's use that.
|
||||
// Integer overflow should not be a problem for Favicon sizes...
|
||||
bufferSize = (int) entityReportedLength + 1;
|
||||
bufferSize = response.contentLength + 1;
|
||||
} else {
|
||||
// No declared size, so guess and reallocate later if it turns out to be too small.
|
||||
bufferSize = DEFAULT_FAVICON_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Read the InputStream into a byte[].
|
||||
ConsumedInputStream result = IOUtils.readFully(entity.getContent(), bufferSize);
|
||||
ConsumedInputStream result = IOUtils.readFully(response.stream, bufferSize);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
@ -474,7 +449,7 @@ public class LoadFaviconTask {
|
||||
sizes.add(b.getWidth());
|
||||
}
|
||||
|
||||
int bestSize = Favicons.selectBestSizeFromList(sizes, targetWidth);
|
||||
int bestSize = Favicons.selectBestSizeFromList(sizes, targetWidthAndHeight);
|
||||
return iconMap.get(bestSize);
|
||||
}
|
||||
}
|
||||
@ -528,8 +503,7 @@ public class LoadFaviconTask {
|
||||
*/
|
||||
private Bitmap pushToCacheAndGetResult(LoadFaviconResult loadedBitmaps) {
|
||||
Favicons.putFaviconsInMemCache(faviconURL, loadedBitmaps.getBitmaps());
|
||||
Bitmap result = Favicons.getSizedFaviconFromCache(faviconURL, targetWidth);
|
||||
return result;
|
||||
return Favicons.getSizedFaviconFromCache(faviconURL, targetWidthAndHeight);
|
||||
}
|
||||
|
||||
private static boolean imageIsValid(final Bitmap image) {
|
||||
@ -576,9 +550,9 @@ public class LoadFaviconTask {
|
||||
|
||||
// Notify listeners, scaling if required.
|
||||
if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) != 0) {
|
||||
scaled = Bitmap.createScaledBitmap(image, targetWidth, targetWidth, true);
|
||||
} else if (targetWidth != -1 && image != null && image.getWidth() != targetWidth) {
|
||||
scaled = Favicons.getSizedFaviconFromCache(faviconURL, targetWidth);
|
||||
scaled = Bitmap.createScaledBitmap(image, targetWidthAndHeight, targetWidthAndHeight, true);
|
||||
} else if (targetWidthAndHeight != -1 && image != null && image.getWidth() != targetWidthAndHeight) {
|
||||
scaled = Favicons.getSizedFaviconFromCache(faviconURL, targetWidthAndHeight);
|
||||
} else {
|
||||
scaled = image;
|
||||
}
|
||||
@ -629,23 +603,4 @@ public class LoadFaviconTask {
|
||||
int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
static void closeHTTPClient() {
|
||||
// This work must be done on a background thread because it shuts down
|
||||
// the connection pool, which typically involves closing a connection --
|
||||
// which counts as network activity.
|
||||
if (ThreadUtils.isOnBackgroundThread()) {
|
||||
if (httpClient != null) {
|
||||
httpClient.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LoadFaviconTask.closeHTTPClient();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ class AndroidImportPreference extends MultiPrefMultiChoicePreference {
|
||||
public static class Handler implements GeckoPreferences.PrefHandler {
|
||||
public boolean setupPref(Context context, Preference pref) {
|
||||
// Feature disabled on devices running Android M+ (Bug 1183559)
|
||||
return Versions.preM && Restrictions.isAllowed(context, Restrictable.IMPORT_SETTINGS);
|
||||
return Versions.preMarshmallow && Restrictions.isAllowed(context, Restrictable.IMPORT_SETTINGS);
|
||||
}
|
||||
|
||||
public void onChange(Context context, Preference pref, Object newValue) { }
|
||||
|
@ -14,15 +14,12 @@ import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.preferences.GeckoPreferences;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
@ -64,7 +61,7 @@ public class TabQueueHelper {
|
||||
* @return true if the specified context can draw on top of other apps, false otherwise.
|
||||
*/
|
||||
public static boolean canDrawOverlays(Context context) {
|
||||
if (AppConstants.Versions.preM) {
|
||||
if (AppConstants.Versions.preMarshmallow) {
|
||||
return true; // We got the permission at install time.
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ public class TabQueueService extends Service {
|
||||
} else {
|
||||
try {
|
||||
windowManager.addView(toastLayout, toastLayoutParams);
|
||||
} catch (final SecurityException e) {
|
||||
} catch (final SecurityException | WindowManager.BadTokenException e) {
|
||||
Toast.makeText(this, getText(R.string.tab_queue_toast_message), Toast.LENGTH_SHORT).show();
|
||||
showSettingsNotification();
|
||||
}
|
||||
@ -233,7 +233,7 @@ public class TabQueueService extends Service {
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
private void showSettingsNotification() {
|
||||
if (AppConstants.Versions.preM) {
|
||||
if (AppConstants.Versions.preMarshmallow) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -22,15 +22,14 @@ import org.mozilla.gecko.animation.PropertyAnimator;
|
||||
import org.mozilla.gecko.animation.ViewHelper;
|
||||
import org.mozilla.gecko.toolbar.BrowserToolbarTabletBase.ForwardButtonAnimation;
|
||||
import org.mozilla.gecko.util.ColorUtils;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
import org.mozilla.gecko.util.StringUtils;
|
||||
import org.mozilla.gecko.widget.themed.ThemedLinearLayout;
|
||||
import org.mozilla.gecko.widget.themed.ThemedTextView;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
@ -125,7 +124,11 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout {
|
||||
// Icon used for about:home
|
||||
private static final int LEVEL_SEARCH_ICON = 999;
|
||||
|
||||
private final ForegroundColorSpan mBlockedColor;
|
||||
private final ForegroundColorSpan mUrlColorSpan;
|
||||
private final ForegroundColorSpan mBlockedColorSpan;
|
||||
private final ForegroundColorSpan mDomainColorSpan;
|
||||
private final ForegroundColorSpan mPrivateDomainColorSpan;
|
||||
private final ForegroundColorSpan mCertificateOwnerColorSpan;
|
||||
|
||||
public ToolbarDisplayLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@ -138,7 +141,11 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout {
|
||||
mTitle = (ThemedTextView) findViewById(R.id.url_bar_title);
|
||||
mTitlePadding = mTitle.getPaddingRight();
|
||||
|
||||
mBlockedColor = new ForegroundColorSpan(ColorUtils.getColor(context, R.color.url_bar_blockedtext));
|
||||
mUrlColorSpan = new ForegroundColorSpan(ColorUtils.getColor(context, R.color.url_bar_urltext));
|
||||
mBlockedColorSpan = new ForegroundColorSpan(ColorUtils.getColor(context, R.color.url_bar_blockedtext));
|
||||
mDomainColorSpan = new ForegroundColorSpan(ColorUtils.getColor(context, R.color.url_bar_domaintext));
|
||||
mPrivateDomainColorSpan = new ForegroundColorSpan(ColorUtils.getColor(context, R.color.url_bar_domaintext_private));
|
||||
mCertificateOwnerColorSpan = new ForegroundColorSpan(ColorUtils.getColor(context, R.color.affirmative_green));
|
||||
|
||||
mSiteSecurity = (ImageButton) findViewById(R.id.site_security);
|
||||
|
||||
@ -249,7 +256,7 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout {
|
||||
final String title = tab.getDisplayTitle();
|
||||
|
||||
final SpannableStringBuilder builder = new SpannableStringBuilder(title);
|
||||
builder.setSpan(mBlockedColor, 0, title.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
builder.setSpan(mBlockedColorSpan, 0, title.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
|
||||
setTitle(builder);
|
||||
setContentDescription(null);
|
||||
@ -271,27 +278,48 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout {
|
||||
|
||||
final SiteIdentity siteIdentity = tab.getSiteIdentity();
|
||||
if (siteIdentity.hasOwner()) {
|
||||
final String title;
|
||||
|
||||
if (siteIdentity.hasCountry()) {
|
||||
title = String.format("%s (%s)", siteIdentity.getOwner(), siteIdentity.getCountry());
|
||||
} else {
|
||||
title = siteIdentity.getOwner();
|
||||
}
|
||||
|
||||
final int color = ContextCompat.getColor(getContext(), R.color.affirmative_green);
|
||||
|
||||
final SpannableString spannable = new SpannableString(title);
|
||||
spannable.setSpan(new ForegroundColorSpan(color), 0, title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
setTitle(spannable);
|
||||
} else if (!TextUtils.isEmpty(baseDomain)) {
|
||||
// Show Owner of EV certificate as title
|
||||
updateTitleFromSiteIdentity(siteIdentity);
|
||||
} else if (!HardwareUtils.isTablet() && !TextUtils.isEmpty(baseDomain)) {
|
||||
// Show just the base domain as title
|
||||
setTitle(baseDomain);
|
||||
} else {
|
||||
setTitle(strippedURL);
|
||||
// Display full URL as title
|
||||
updateAndColorTitleFromFullURL(strippedURL, baseDomain, tab.isPrivate());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTitleFromSiteIdentity(SiteIdentity siteIdentity) {
|
||||
final String title;
|
||||
|
||||
if (siteIdentity.hasCountry()) {
|
||||
title = String.format("%s (%s)", siteIdentity.getOwner(), siteIdentity.getCountry());
|
||||
} else {
|
||||
title = siteIdentity.getOwner();
|
||||
}
|
||||
|
||||
final SpannableString spannable = new SpannableString(title);
|
||||
spannable.setSpan(mCertificateOwnerColorSpan, 0, title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
setTitle(spannable);
|
||||
}
|
||||
|
||||
private void updateAndColorTitleFromFullURL(String url, String baseDomain, boolean isPrivate) {
|
||||
int index = url.indexOf(baseDomain);
|
||||
if (index == -1) {
|
||||
setTitle(url);
|
||||
return;
|
||||
}
|
||||
|
||||
final SpannableStringBuilder builder = new SpannableStringBuilder(url);
|
||||
|
||||
builder.setSpan(mUrlColorSpan, 0, url.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
builder.setSpan(isPrivate ? mPrivateDomainColorSpan : mDomainColorSpan,
|
||||
index, index + baseDomain.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
|
||||
setTitle(builder);
|
||||
}
|
||||
|
||||
private String stripAboutReaderURL(final String url) {
|
||||
if (!AboutPages.isAboutReader(url)) {
|
||||
return url;
|
||||
|
@ -12,6 +12,7 @@ import org.mozilla.gecko.R;
|
||||
import org.mozilla.apache.commons.codec.binary.Hex;
|
||||
|
||||
import org.mozilla.gecko.permissions.Permissions;
|
||||
import org.mozilla.gecko.util.ProxySelector;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
@ -47,8 +48,6 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
@ -373,21 +372,6 @@ public class UpdateService extends IntentService {
|
||||
}
|
||||
}
|
||||
|
||||
private URLConnection openConnectionWithProxy(URI uri) throws java.net.MalformedURLException, java.io.IOException {
|
||||
Log.i(LOGTAG, "opening connection with URI: " + uri);
|
||||
|
||||
ProxySelector ps = ProxySelector.getDefault();
|
||||
Proxy proxy = Proxy.NO_PROXY;
|
||||
if (ps != null) {
|
||||
List<Proxy> proxies = ps.select(uri);
|
||||
if (proxies != null && !proxies.isEmpty()) {
|
||||
proxy = proxies.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
return uri.toURL().openConnection(proxy);
|
||||
}
|
||||
|
||||
private UpdateInfo findUpdate(boolean force) {
|
||||
try {
|
||||
URI uri = getUpdateURI(force);
|
||||
@ -398,7 +382,7 @@ public class UpdateService extends IntentService {
|
||||
}
|
||||
|
||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
Document dom = builder.parse(openConnectionWithProxy(uri).getInputStream());
|
||||
Document dom = builder.parse(ProxySelector.openConnectionWithProxy(uri).getInputStream());
|
||||
|
||||
NodeList nodes = dom.getElementsByTagName("update");
|
||||
if (nodes == null || nodes.getLength() == 0)
|
||||
@ -579,7 +563,7 @@ public class UpdateService extends IntentService {
|
||||
mWifiLock.acquire();
|
||||
}
|
||||
|
||||
URLConnection conn = openConnectionWithProxy(info.uri);
|
||||
URLConnection conn = ProxySelector.openConnectionWithProxy(info.uri);
|
||||
int length = conn.getContentLength();
|
||||
|
||||
output = new BufferedOutputStream(new FileOutputStream(downloadFile));
|
||||
|
@ -23,8 +23,24 @@ import android.text.TextUtils;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.URI;
|
||||
import java.net.URLConnection;
|
||||
import java.util.List;
|
||||
|
||||
public class ProxySelector {
|
||||
public static URLConnection openConnectionWithProxy(URI uri) throws IOException {
|
||||
java.net.ProxySelector ps = java.net.ProxySelector.getDefault();
|
||||
Proxy proxy = Proxy.NO_PROXY;
|
||||
if (ps != null) {
|
||||
List<Proxy> proxies = ps.select(uri);
|
||||
if (proxies != null && !proxies.isEmpty()) {
|
||||
proxy = proxies.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
return uri.toURL().openConnection(proxy);
|
||||
}
|
||||
|
||||
public ProxySelector() {
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,6 @@ final class UnusedResourcesUtil {
|
||||
|
||||
public static final int[] USED_IN_JS = {
|
||||
R.drawable.ab_search,
|
||||
R.drawable.alert_app,
|
||||
R.drawable.alert_app_animation,
|
||||
R.drawable.alert_camera,
|
||||
R.drawable.alert_download,
|
||||
R.drawable.alert_download_animation,
|
||||
|
@ -504,7 +504,6 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||
'RemoteClientsDialogFragment.java',
|
||||
'RemoteTabsExpandableListAdapter.java',
|
||||
'Restarter.java',
|
||||
'Restrictions.java',
|
||||
'restrictions/DefaultConfiguration.java',
|
||||
'restrictions/GuestProfileConfiguration.java',
|
||||
'restrictions/Restrictable.java',
|
||||
@ -512,6 +511,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||
'restrictions/RestrictionCache.java',
|
||||
'restrictions/RestrictionConfiguration.java',
|
||||
'restrictions/RestrictionProvider.java',
|
||||
'restrictions/Restrictions.java',
|
||||
'ScreenshotObserver.java',
|
||||
'ServiceNotificationClient.java',
|
||||
'SessionParser.java',
|
||||
|
Before Width: | Height: | Size: 460 B |
Before Width: | Height: | Size: 292 B |
Before Width: | Height: | Size: 450 B |
Before Width: | Height: | Size: 408 B |
Before Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 421 B |
Before Width: | Height: | Size: 443 B |
Before Width: | Height: | Size: 362 B |
Before Width: | Height: | Size: 407 B |
Before Width: | Height: | Size: 544 B |
Before Width: | Height: | Size: 460 B |
Before Width: | Height: | Size: 450 B |
Before Width: | Height: | Size: 450 B |
Before Width: | Height: | Size: 408 B |