зеркало из https://github.com/mozilla/gecko-dev.git
merge fx-team to mozilla-central a=merge
This commit is contained in:
Коммит
9182dc1158
|
@ -1466,6 +1466,8 @@
|
|||
let index = tab._tPos;
|
||||
let filter = this.mTabFilters[index];
|
||||
aBrowser.webProgress.removeProgressListener(filter);
|
||||
// Make sure the browser is destroyed so it unregisters from observer notifications
|
||||
aBrowser.destroy();
|
||||
|
||||
// Change the "remote" attribute.
|
||||
let parent = aBrowser.parentNode;
|
||||
|
|
|
@ -123,6 +123,7 @@ skip-if = e10s # Bug 1101993 - times out for unknown reasons when run in the dir
|
|||
[browser_autocomplete_no_title.js]
|
||||
[browser_autocomplete_autoselect.js]
|
||||
[browser_autocomplete_oldschool_wrap.js]
|
||||
[browser_autocomplete_tag_star_visibility.js]
|
||||
[browser_backButtonFitts.js]
|
||||
skip-if = os != "win" || e10s # The Fitts Law back button is only supported on Windows (bug 571454) / e10s - Bug 1099154: test touches content (attempts to add an event listener directly to the contentWindow)
|
||||
[browser_blob-channelname.js]
|
||||
|
@ -197,8 +198,7 @@ skip-if = buildapp == 'mulet' || e10s # Bug 1093206 - need to re-enable tests re
|
|||
skip-if = e10s # Bug 1102020 - test tries to use browserDOMWindow.openURI to open a link, and gets a null rv where it expects a window
|
||||
[browser_bug550565.js]
|
||||
[browser_bug553455.js]
|
||||
skip-if = true # Bug 1094312
|
||||
#skip-if = buildapp == 'mulet' || e10s # Bug 1066070 - I don't think either popup notifications nor addon install stuff works on mulet? ; for e10s, indefinite waiting halfway through the test, tracked in bug 1093586
|
||||
skip-if = buildapp == 'mulet' # Bug 1066070 - I don't think either popup notifications nor addon install stuff works on mulet?
|
||||
[browser_bug555224.js]
|
||||
skip-if = e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
|
||||
[browser_bug555767.js]
|
||||
|
@ -232,7 +232,6 @@ skip-if = e10s # Bug 1093756 - can't bookmark the data: url in e10s somehow
|
|||
[browser_bug581947.js]
|
||||
skip-if = e10s
|
||||
[browser_bug585558.js]
|
||||
skip-if = true # Bug 1094312 - Disabling browser_bug553455.js made this permafail
|
||||
[browser_bug585785.js]
|
||||
[browser_bug585830.js]
|
||||
[browser_bug590206.js]
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
add_task(function*() {
|
||||
// This test is only relevant if UnifiedComplete is enabled.
|
||||
Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
|
||||
Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete");
|
||||
Services.prefs.clearUserPref("browser.urlbar.suggest.bookmark");
|
||||
});
|
||||
|
||||
function* addTagItem(tagName) {
|
||||
let uri = NetUtil.newURI(`http://example.com/this/is/tagged/${tagName}`);
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
`test ${tagName}`);
|
||||
PlacesUtils.tagging.tagURI(uri, [tagName]);
|
||||
yield PlacesTestUtils.addVisits([{uri: uri, title: `Test page with tag ${tagName}`}]);
|
||||
}
|
||||
|
||||
// We use different tags for each part of the test, as otherwise the
|
||||
// autocomplete code tries to be smart by using the previously cached element
|
||||
// without updating it (since all parameters it knows about are the same).
|
||||
|
||||
let testcases = [{
|
||||
description: "Test with suggest.bookmark=true",
|
||||
tagName: "tagtest1",
|
||||
prefs: {
|
||||
"suggest.bookmark": true,
|
||||
},
|
||||
input: "tagtest1",
|
||||
expected: {
|
||||
type: "bookmark-tag",
|
||||
typeImageVisible: true,
|
||||
},
|
||||
}, {
|
||||
description: "Test with suggest.bookmark=false",
|
||||
tagName: "tagtest2",
|
||||
prefs: {
|
||||
"suggest.bookmark": false,
|
||||
},
|
||||
input: "tagtest2",
|
||||
expected: {
|
||||
type: "tag",
|
||||
typeImageVisible: false,
|
||||
},
|
||||
}, {
|
||||
description: "Test with suggest.bookmark=true (again)",
|
||||
tagName: "tagtest3",
|
||||
prefs: {
|
||||
"suggest.bookmark": true,
|
||||
},
|
||||
input: "tagtest3",
|
||||
expected: {
|
||||
type: "bookmark-tag",
|
||||
typeImageVisible: true,
|
||||
},
|
||||
}, {
|
||||
description: "Test with bookmark restriction token",
|
||||
tagName: "tagtest4",
|
||||
prefs: {
|
||||
"suggest.bookmark": true,
|
||||
},
|
||||
input: "* tagtest4",
|
||||
expected: {
|
||||
type: "bookmark-tag",
|
||||
typeImageVisible: true,
|
||||
},
|
||||
}, {
|
||||
description: "Test with history restriction token",
|
||||
tagName: "tagtest5",
|
||||
prefs: {
|
||||
"suggest.bookmark": true,
|
||||
},
|
||||
input: "^ tagtest5",
|
||||
expected: {
|
||||
type: "tag",
|
||||
typeImageVisible: false,
|
||||
},
|
||||
}];
|
||||
|
||||
|
||||
for (let testcase of testcases) {
|
||||
info(`Test case: ${testcase.description}`);
|
||||
|
||||
yield addTagItem(testcase.tagName);
|
||||
for (let prefName of Object.keys(testcase.prefs)) {
|
||||
Services.prefs.setBoolPref(`browser.urlbar.${prefName}`, testcase.prefs[prefName]);
|
||||
}
|
||||
|
||||
yield promiseAutocompleteResultPopup(testcase.input);
|
||||
let result = gURLBar.popup.richlistbox.children[1];
|
||||
ok(result && !result.collasped, "Should have result");
|
||||
|
||||
is(result.getAttribute("type"), testcase.expected.type, "Result should have expected type");
|
||||
if (testcase.expected.typeImageVisible) {
|
||||
is_element_visible(result._typeImage, "Type image should be visible");
|
||||
} else {
|
||||
is_element_hidden(result._typeImage, "Type image should be hidden");
|
||||
}
|
||||
|
||||
gURLBar.popup.hidePopup();
|
||||
yield promisePopupHidden(gURLBar.popup);
|
||||
}
|
||||
});
|
|
@ -7,6 +7,7 @@ const TESTROOT2 = "http://example.org/browser/toolkit/mozapps/extensions/test/xp
|
|||
const SECUREROOT = "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
|
||||
const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
|
||||
const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
|
||||
const PROGRESS_NOTIFICATION = "addon-progress-notification";
|
||||
|
||||
var rootDir = getRootDirectory(gTestPath);
|
||||
var path = rootDir.split('/');
|
||||
|
@ -23,15 +24,25 @@ var gApp = document.getElementById("bundle_brand").getString("brandShortName");
|
|||
var gVersion = Services.appinfo.version;
|
||||
var check_notification;
|
||||
|
||||
function wait_for_notification(aCallback) {
|
||||
info("Waiting for notification");
|
||||
function wait_for_progress_notification(aCallback) {
|
||||
wait_for_notification(PROGRESS_NOTIFICATION, aCallback, "popupshowing");
|
||||
}
|
||||
|
||||
function wait_for_notification(aId, aCallback, aEvent = "popupshown") {
|
||||
info("Waiting for " + aId + " notification");
|
||||
check_notification = function() {
|
||||
PopupNotifications.panel.removeEventListener("popupshown", check_notification, false);
|
||||
info("Saw notification");
|
||||
// Ignore the progress notification unless that is the notification we want
|
||||
if (aId != PROGRESS_NOTIFICATION && PopupNotifications.panel.childNodes[0].id == PROGRESS_NOTIFICATION)
|
||||
return;
|
||||
|
||||
PopupNotifications.panel.removeEventListener(aEvent, check_notification, false);
|
||||
info("Saw a notification");
|
||||
is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
|
||||
if (PopupNotifications.panel.childNodes.length)
|
||||
is(PopupNotifications.panel.childNodes[0].id, aId, "Should have seen the right notification");
|
||||
aCallback(PopupNotifications.panel);
|
||||
};
|
||||
PopupNotifications.panel.addEventListener("popupshown", check_notification, false);
|
||||
PopupNotifications.panel.addEventListener(aEvent, check_notification, false);
|
||||
}
|
||||
|
||||
function wait_for_notification_close(aCallback) {
|
||||
|
@ -103,9 +114,8 @@ function test_disabled_install() {
|
|||
Services.prefs.setBoolPref("xpinstall.enabled", false);
|
||||
|
||||
// Wait for the disabled notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("xpinstall-disabled-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "xpinstall-disabled-notification", "Should have seen installs disabled");
|
||||
is(notification.button.label, "Enable", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
"Software installation is currently disabled. Click Enable and try again.");
|
||||
|
@ -141,9 +151,8 @@ function test_disabled_install() {
|
|||
|
||||
function test_blocked_install() {
|
||||
// Wait for the blocked notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-blocked-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-blocked-notification", "Should have seen the install blocked");
|
||||
is(notification.button.label, "Allow", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
gApp + " prevented this site (example.com) from asking you to install " +
|
||||
|
@ -153,9 +162,8 @@ function test_blocked_install() {
|
|||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
"XPI Test will be installed after you restart " + gApp + ".",
|
||||
|
@ -192,16 +200,12 @@ function test_blocked_install() {
|
|||
|
||||
function test_whitelisted_install() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
"XPI Test will be installed after you restart " + gApp + ".",
|
||||
|
@ -233,14 +237,10 @@ function test_whitelisted_install() {
|
|||
|
||||
function test_failed_download() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the failed notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-failed-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-failed-notification", "Should have seen the install fail");
|
||||
is(notification.getAttribute("label"),
|
||||
"The add-on could not be downloaded because of a connection failure " +
|
||||
"on example.com.",
|
||||
|
@ -264,14 +264,10 @@ function test_failed_download() {
|
|||
|
||||
function test_corrupt_file() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the failed notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-failed-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-failed-notification", "Should have seen the install fail");
|
||||
is(notification.getAttribute("label"),
|
||||
"The add-on downloaded from example.com could not be installed " +
|
||||
"because it appears to be corrupt.",
|
||||
|
@ -295,14 +291,10 @@ function test_corrupt_file() {
|
|||
|
||||
function test_incompatible() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the failed notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-failed-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-failed-notification", "Should have seen the install fail");
|
||||
is(notification.getAttribute("label"),
|
||||
"XPI Test could not be installed because it is not compatible with " +
|
||||
gApp + " " + gVersion + ".",
|
||||
|
@ -326,16 +318,12 @@ function test_incompatible() {
|
|||
|
||||
function test_restartless() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the install complete");
|
||||
is(notification.getAttribute("label"),
|
||||
"XPI Test has been installed successfully.",
|
||||
"Should have seen the right message");
|
||||
|
@ -369,16 +357,12 @@ function test_restartless() {
|
|||
|
||||
function test_multiple() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
"2 add-ons will be installed after you restart " + gApp + ".",
|
||||
|
@ -415,16 +399,12 @@ function test_multiple() {
|
|||
|
||||
function test_url() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
"XPI Test will be installed after you restart " + gApp + ".",
|
||||
|
@ -485,13 +465,10 @@ function test_wronghost() {
|
|||
gBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-failed-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-failed-notification", "Should have seen the install fail");
|
||||
is(notification.getAttribute("label"),
|
||||
"The add-on downloaded from example.com could not be installed " +
|
||||
"because it appears to be corrupt.",
|
||||
|
@ -509,16 +486,12 @@ function test_wronghost() {
|
|||
|
||||
function test_reload() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
"XPI Test will be installed after you restart " + gApp + ".",
|
||||
|
@ -566,16 +539,12 @@ function test_reload() {
|
|||
|
||||
function test_theme() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
"Theme Test will be installed after you restart " + gApp + ".",
|
||||
|
@ -613,18 +582,13 @@ function test_theme() {
|
|||
|
||||
function test_renotify_blocked() {
|
||||
// Wait for the blocked notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-blocked-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-blocked-notification", "Should have seen the install blocked");
|
||||
|
||||
wait_for_notification_close(function () {
|
||||
info("Timeouts after this probably mean bug 589954 regressed");
|
||||
executeSoon(function () {
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-blocked-notification",
|
||||
"Should have seen the install blocked - 2nd time");
|
||||
|
||||
wait_for_notification("addon-install-blocked-notification", function(aPanel) {
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 2, "Should be two pending installs");
|
||||
aInstalls[0].cancel();
|
||||
|
@ -653,35 +617,23 @@ function test_renotify_blocked() {
|
|||
|
||||
function test_renotify_installed() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the install complete");
|
||||
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
// Dismiss the notification
|
||||
wait_for_notification_close(function () {
|
||||
// Install another
|
||||
executeSoon(function () {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
wait_for_progress_notification(function(aPanel) {
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
info("Timeouts after this probably mean bug 589954 regressed");
|
||||
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the second install complete");
|
||||
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 1, "Should be one pending installs");
|
||||
aInstalls[0].cancel();
|
||||
|
@ -719,11 +671,14 @@ function test_renotify_installed() {
|
|||
},
|
||||
|
||||
function test_cancel_restart() {
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
function complete_install(callback) {
|
||||
let url = TESTROOT + "slowinstall.sjs?continue=true"
|
||||
NetUtil.asyncFetch(url, callback || (() => {}));
|
||||
}
|
||||
|
||||
// Wait for the progress notification
|
||||
wait_for_notification(PROGRESS_NOTIFICATION, function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
// Close the notification
|
||||
let anchor = document.getElementById("addons-notification-icon");
|
||||
anchor.click();
|
||||
|
@ -737,52 +692,65 @@ function test_cancel_restart() {
|
|||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
let button = document.getAnonymousElementByAttribute(notification, "anonid", "cancel");
|
||||
|
||||
// Cancel the download
|
||||
EventUtils.synthesizeMouse(button, 2, 2, {});
|
||||
// Wait for the install to fully cancel
|
||||
let install = notification.notification.options.installs[0];
|
||||
install.addListener({
|
||||
onDownloadCancelled: function() {
|
||||
install.removeListener(this);
|
||||
|
||||
// Notification should have changed to cancelled
|
||||
notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-cancelled-notification", "Should have seen the cancelled notification");
|
||||
executeSoon(function() {
|
||||
ok(PopupNotifications.isPanelOpen, "Notification should still be open");
|
||||
is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
|
||||
isnot(notification, aPanel.childNodes[0], "Should have reconstructed the notification UI");
|
||||
notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-cancelled-notification", "Should have seen the cancelled notification");
|
||||
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete-notification", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
"XPI Test will be installed after you restart " + gApp + ".",
|
||||
"Should have seen the right message");
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
// Wait for the complete notification
|
||||
wait_for_notification("addon-install-complete-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
is(notification.getAttribute("label"),
|
||||
"XPI Test will be installed after you restart " + gApp + ".",
|
||||
"Should have seen the right message");
|
||||
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 1, "Should be one pending install");
|
||||
aInstalls[0].cancel();
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 1, "Should be one pending install");
|
||||
aInstalls[0].cancel();
|
||||
|
||||
Services.perms.remove("example.com", "install");
|
||||
wait_for_notification_close(runNextTest);
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
Services.perms.remove("example.com", "install");
|
||||
wait_for_notification_close(runNextTest);
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
});
|
||||
|
||||
aWindow.document.documentElement.acceptDialog();
|
||||
});
|
||||
|
||||
// Restart the download
|
||||
EventUtils.synthesizeMouseAtCenter(notification.button, {});
|
||||
|
||||
// Should be back to a progress notification
|
||||
ok(PopupNotifications.isPanelOpen, "Notification should still be open");
|
||||
is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
|
||||
notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
|
||||
complete_install();
|
||||
});
|
||||
});
|
||||
|
||||
aWindow.document.documentElement.acceptDialog();
|
||||
}
|
||||
});
|
||||
|
||||
// Restart the download
|
||||
EventUtils.synthesizeMouse(notification.button, 20, 10, {});
|
||||
|
||||
// Should be back to a progress notification
|
||||
ok(PopupNotifications.isPanelOpen, "Notification should still be open");
|
||||
is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
|
||||
notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
|
||||
// Cancel the download
|
||||
EventUtils.synthesizeMouseAtCenter(button, {});
|
||||
});
|
||||
|
||||
var pm = Services.perms;
|
||||
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||
|
||||
var triggers = encodeURIComponent(JSON.stringify({
|
||||
"XPI": "unsigned.xpi"
|
||||
"XPI": "slowinstall.sjs?file=unsigned.xpi"
|
||||
}));
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||
|
@ -796,9 +764,8 @@ function test_failed_security() {
|
|||
});
|
||||
|
||||
// Wait for the blocked notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
wait_for_notification("addon-install-blocked-notification", function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-blocked-notification", "Should have seen the install blocked");
|
||||
|
||||
// Click on Allow
|
||||
EventUtils.synthesizeMouse(notification.button, 20, 10, {});
|
||||
|
|
|
@ -513,8 +513,11 @@ loop.panel = (function(_, mozL10n) {
|
|||
* FxA sign in/up link component.
|
||||
*/
|
||||
var AuthLink = React.createClass({displayName: "AuthLink",
|
||||
mixins: [sharedMixins.WindowCloseMixin],
|
||||
|
||||
handleSignUpLinkClick: function() {
|
||||
navigator.mozLoop.logInToFxA();
|
||||
this.closeWindow();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
|
|
@ -513,8 +513,11 @@ loop.panel = (function(_, mozL10n) {
|
|||
* FxA sign in/up link component.
|
||||
*/
|
||||
var AuthLink = React.createClass({
|
||||
mixins: [sharedMixins.WindowCloseMixin],
|
||||
|
||||
handleSignUpLinkClick: function() {
|
||||
navigator.mozLoop.logInToFxA();
|
||||
this.closeWindow();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
|
|
@ -182,6 +182,13 @@ loop.shared.views.FeedbackView = (function(l10n) {
|
|||
|
||||
componentDidMount: function() {
|
||||
this._timer = setInterval(function() {
|
||||
if (this.state.countdown == 1) {
|
||||
clearInterval(this._timer);
|
||||
if (this.props.onAfterFeedbackReceived) {
|
||||
this.props.onAfterFeedbackReceived();
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.setState({countdown: this.state.countdown - 1});
|
||||
}.bind(this), 1000);
|
||||
},
|
||||
|
@ -193,12 +200,6 @@ loop.shared.views.FeedbackView = (function(l10n) {
|
|||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.countdown < 1) {
|
||||
clearInterval(this._timer);
|
||||
if (this.props.onAfterFeedbackReceived) {
|
||||
this.props.onAfterFeedbackReceived();
|
||||
}
|
||||
}
|
||||
return (
|
||||
React.createElement(FeedbackLayout, {title: l10n.get("feedback_thank_you_heading")},
|
||||
React.createElement("p", {className: "info thank-you"},
|
||||
|
|
|
@ -182,6 +182,13 @@ loop.shared.views.FeedbackView = (function(l10n) {
|
|||
|
||||
componentDidMount: function() {
|
||||
this._timer = setInterval(function() {
|
||||
if (this.state.countdown == 1) {
|
||||
clearInterval(this._timer);
|
||||
if (this.props.onAfterFeedbackReceived) {
|
||||
this.props.onAfterFeedbackReceived();
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.setState({countdown: this.state.countdown - 1});
|
||||
}.bind(this), 1000);
|
||||
},
|
||||
|
@ -193,12 +200,6 @@ loop.shared.views.FeedbackView = (function(l10n) {
|
|||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.countdown < 1) {
|
||||
clearInterval(this._timer);
|
||||
if (this.props.onAfterFeedbackReceived) {
|
||||
this.props.onAfterFeedbackReceived();
|
||||
}
|
||||
}
|
||||
return (
|
||||
<FeedbackLayout title={l10n.get("feedback_thank_you_heading")}>
|
||||
<p className="info thank-you">{
|
||||
|
|
|
@ -253,6 +253,17 @@ describe("loop.panel", function() {
|
|||
});
|
||||
|
||||
describe("AuthLink", function() {
|
||||
|
||||
beforeEach(function() {
|
||||
navigator.mozLoop.calls = { clearCallInProgress: function() {} };
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
delete navigator.mozLoop.logInToFxA;
|
||||
delete navigator.mozLoop.calls;
|
||||
navigator.mozLoop.fxAEnabled = true;
|
||||
});
|
||||
|
||||
it("should trigger the FxA sign in/up process when clicking the link",
|
||||
function() {
|
||||
navigator.mozLoop.loggedInToFxA = false;
|
||||
|
@ -266,6 +277,19 @@ describe("loop.panel", function() {
|
|||
sinon.assert.calledOnce(navigator.mozLoop.logInToFxA);
|
||||
});
|
||||
|
||||
it("should close the panel after clicking the link",
|
||||
function() {
|
||||
navigator.mozLoop.loggedInToFxA = false;
|
||||
navigator.mozLoop.logInToFxA = sandbox.stub();
|
||||
|
||||
var view = createTestPanelView();
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
view.getDOMNode().querySelector(".signin-link a"));
|
||||
|
||||
sinon.assert.calledOnce(fakeWindow.close);
|
||||
});
|
||||
|
||||
it("should be hidden if FxA is not enabled",
|
||||
function() {
|
||||
navigator.mozLoop.fxAEnabled = false;
|
||||
|
@ -273,10 +297,6 @@ describe("loop.panel", function() {
|
|||
React.createElement(loop.panel.AuthLink));
|
||||
expect(view.getDOMNode()).to.be.null;
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
navigator.mozLoop.fxAEnabled = true;
|
||||
});
|
||||
});
|
||||
|
||||
describe("SettingsDropdown", function() {
|
||||
|
|
|
@ -88,21 +88,25 @@
|
|||
label="&trackingProtection.label;" />
|
||||
<image id="trackingProtectionImage"/>
|
||||
</hbox>
|
||||
<label id="trackingProtectionLearnMore"
|
||||
class="text-link"
|
||||
value="&trackingProtectionLearnMore.label;"/>
|
||||
<separator/>
|
||||
<hbox align="center"
|
||||
class="indent">
|
||||
<label id="trackingProtectionLearnMore"
|
||||
class="text-link"
|
||||
value="&trackingProtectionLearnMore.label;"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<checkbox id="privacyDoNotTrackCheckbox"
|
||||
label="&dntTrackingNotOkay.label2;"
|
||||
accesskey="&dntTrackingNotOkay.accesskey;"
|
||||
preference="privacy.donottrackheader.enabled"/>
|
||||
<separator class="thin"/>
|
||||
<vbox>
|
||||
<hbox pack="end">
|
||||
<spacer flex="1"/>
|
||||
<label class="text-link" id="doNotTrackInfo"
|
||||
href="https://www.mozilla.org/dnt">
|
||||
<hbox align="center">
|
||||
<checkbox id="privacyDoNotTrackCheckbox"
|
||||
label="&dntTrackingNotOkay.label2;"
|
||||
accesskey="&dntTrackingNotOkay.accesskey;"
|
||||
preference="privacy.donottrackheader.enabled"/>
|
||||
</hbox>
|
||||
<hbox align="center"
|
||||
class="indent">
|
||||
<label id="doNotTrackInfo"
|
||||
class="text-link"
|
||||
href="https://www.mozilla.org/dnt">
|
||||
&doNotTrackInfo.label;
|
||||
</label>
|
||||
</hbox>
|
||||
|
|
|
@ -95,24 +95,30 @@
|
|||
preference="privacy.trackingprotection.enabled"
|
||||
accesskey="&trackingProtection.accesskey;"
|
||||
label="&trackingProtection.label;" />
|
||||
<image id="trackingProtectionImage" src="chrome://browser/skin/bad-content-blocked-16.png"/>
|
||||
<image id="trackingProtectionImage"
|
||||
src="chrome://browser/skin/bad-content-blocked-16.png"/>
|
||||
</hbox>
|
||||
<hbox align="center"
|
||||
class="indent">
|
||||
<label id="trackingProtectionLearnMore"
|
||||
class="text-link"
|
||||
value="&trackingProtectionLearnMore.label;"/>
|
||||
</hbox>
|
||||
<label id="trackingProtectionLearnMore"
|
||||
class="text-link"
|
||||
value="&trackingProtectionLearnMore.label;"/>
|
||||
<separator/>
|
||||
</vbox>
|
||||
<checkbox id="privacyDoNotTrackCheckbox"
|
||||
label="&dntTrackingNotOkay.label2;"
|
||||
accesskey="&dntTrackingNotOkay.accesskey;"
|
||||
preference="privacy.donottrackheader.enabled"/>
|
||||
<separator class="thin"/>
|
||||
<vbox>
|
||||
<hbox pack="end">
|
||||
<spacer flex="1"/>
|
||||
<label class="text-link" id="doNotTrackInfo"
|
||||
href="https://www.mozilla.org/dnt"
|
||||
value="&doNotTrackInfo.label;"/>
|
||||
<hbox align="center">
|
||||
<checkbox id="privacyDoNotTrackCheckbox"
|
||||
label="&dntTrackingNotOkay.label2;"
|
||||
accesskey="&dntTrackingNotOkay.accesskey;"
|
||||
preference="privacy.donottrackheader.enabled"/>
|
||||
</hbox>
|
||||
<hbox align="center"
|
||||
class="indent">
|
||||
<label id="doNotTrackInfo"
|
||||
class="text-link"
|
||||
href="https://www.mozilla.org/dnt">
|
||||
&doNotTrackInfo.label;
|
||||
</label>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
|
|
|
@ -9,6 +9,12 @@ XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () {
|
|||
return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {});
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
|
||||
"resource://gre/modules/FxAccounts.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "fxaMigrator",
|
||||
"resource://services-sync/FxaMigrator.jsm");
|
||||
|
||||
const PAGE_NO_ACCOUNT = 0;
|
||||
const PAGE_HAS_ACCOUNT = 1;
|
||||
const PAGE_NEEDS_UPDATE = 2;
|
||||
|
@ -25,7 +31,6 @@ const FXA_LOGIN_UNVERIFIED = 1;
|
|||
const FXA_LOGIN_FAILED = 2;
|
||||
|
||||
let gSyncPane = {
|
||||
_stringBundle: null,
|
||||
prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs",
|
||||
"engine.tabs", "engine.history"],
|
||||
|
||||
|
@ -89,6 +94,7 @@ let gSyncPane = {
|
|||
"weave:service:setup-complete",
|
||||
"weave:service:logout:finish",
|
||||
FxAccountsCommon.ONVERIFIED_NOTIFICATION];
|
||||
let migrateTopic = "fxa-migration:state-changed";
|
||||
|
||||
// Add the observers now and remove them on unload
|
||||
//XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
|
||||
|
@ -96,18 +102,34 @@ let gSyncPane = {
|
|||
topics.forEach(function (topic) {
|
||||
Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this);
|
||||
}, this);
|
||||
window.addEventListener("unload", function() {
|
||||
topics.forEach(function (topic) {
|
||||
Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this);
|
||||
}, gSyncPane);
|
||||
}, false);
|
||||
// The FxA migration observer is a special case.
|
||||
Weave.Svc.Obs.add(migrateTopic, this.updateMigrationState, this);
|
||||
|
||||
window.addEventListener("unload", function() {
|
||||
topics.forEach(topic => {
|
||||
Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this);
|
||||
});
|
||||
Weave.Svc.Obs.remove(migrateTopic, this.updateMigrationState, this);
|
||||
}.bind(this), false);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, '_stringBundle', () => {
|
||||
return Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, '_accountsStringBundle', () => {
|
||||
return Services.strings.createBundle("chrome://browser/locale/accounts.properties");
|
||||
});
|
||||
|
||||
this._stringBundle =
|
||||
Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
|
||||
this.updateWeavePrefs();
|
||||
},
|
||||
|
||||
updateWeavePrefs: function () {
|
||||
// ask the migration module to broadcast its current state (and nothing will
|
||||
// happen if it's not loaded - which is good, as that means no migration
|
||||
// is pending/necessary) - we don't want to suck that module in just to
|
||||
// find there's nothing to do.
|
||||
Services.obs.notifyObservers(null, "fxa-migration:state-request", null);
|
||||
|
||||
let service = Components.classes["@mozilla.org/weave/service;1"]
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
|
@ -116,7 +138,6 @@ let gSyncPane = {
|
|||
if (service.fxAccountsEnabled) {
|
||||
// determine the fxa status...
|
||||
this.page = PAGE_PLEASE_WAIT;
|
||||
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
|
||||
fxAccounts.getSignedInUser().then(data => {
|
||||
if (!data) {
|
||||
this.page = FXA_PAGE_LOGGED_OUT;
|
||||
|
@ -175,6 +196,78 @@ let gSyncPane = {
|
|||
}
|
||||
},
|
||||
|
||||
updateMigrationState: function(subject, state) {
|
||||
let selIndex;
|
||||
let container = document.getElementById("sync-migration");
|
||||
switch (state) {
|
||||
case fxaMigrator.STATE_USER_FXA: {
|
||||
let sb = this._accountsStringBundle;
|
||||
// There are 2 cases here - no email address means it is an offer on
|
||||
// the first device (so the user is prompted to create an account).
|
||||
// If there is an email address it is the "join the party" flow, so the
|
||||
// user is prompted to sign in with the address they previously used.
|
||||
let email = subject ? subject.QueryInterface(Components.interfaces.nsISupportsString).data : null;
|
||||
let elt = document.getElementById("sync-migrate-upgrade-description");
|
||||
elt.textContent = email ?
|
||||
sb.formatStringFromName("signInAfterUpgradeOnOtherDevice.description",
|
||||
[email], 1) :
|
||||
sb.GetStringFromName("needUserLong");
|
||||
|
||||
// The "upgrade" button.
|
||||
let button = document.getElementById("sync-migrate-upgrade");
|
||||
button.setAttribute("label",
|
||||
sb.GetStringFromName(email
|
||||
? "signInAfterUpgradeOnOtherDevice.label"
|
||||
: "upgradeToFxA.label"));
|
||||
button.setAttribute("accesskey",
|
||||
sb.GetStringFromName(email
|
||||
? "signInAfterUpgradeOnOtherDevice.accessKey"
|
||||
: "upgradeToFxA.accessKey"));
|
||||
// The "unlink" button - this is only shown for first migration
|
||||
button = document.getElementById("sync-migrate-unlink");
|
||||
if (email) {
|
||||
button.hidden = true;
|
||||
} else {
|
||||
button.setAttribute("label", sb.GetStringFromName("unlinkMigration.label"));
|
||||
button.setAttribute("accesskey", sb.GetStringFromName("unlinkMigration.accessKey"));
|
||||
}
|
||||
selIndex = 0;
|
||||
break;
|
||||
}
|
||||
case fxaMigrator.STATE_USER_FXA_VERIFIED: {
|
||||
let sb = this._accountsStringBundle;
|
||||
let email = subject.QueryInterface(Components.interfaces.nsISupportsString).data;
|
||||
let label = sb.formatStringFromName("needVerifiedUserLong", [email], 1);
|
||||
let elt = document.getElementById("sync-migrate-verify-description");
|
||||
elt.textContent = label;
|
||||
// The "resend" button.
|
||||
let button = document.getElementById("sync-migrate-resend");
|
||||
button.setAttribute("label", sb.GetStringFromName("resendVerificationEmail.label"));
|
||||
button.setAttribute("accesskey", sb.GetStringFromName("resendVerificationEmail.accessKey"));
|
||||
// The "forget" button.
|
||||
button = document.getElementById("sync-migrate-forget");
|
||||
button.setAttribute("label", sb.GetStringFromName("forgetMigration.label"));
|
||||
button.setAttribute("accesskey", sb.GetStringFromName("forgetMigration.accessKey"));
|
||||
selIndex = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (state) { // |null| is expected, but everything else is not.
|
||||
Cu.reportError("updateMigrationState has unknown state: " + state);
|
||||
}
|
||||
if (!container.hidden) {
|
||||
window.innerHeight -= container.clientHeight;
|
||||
container.hidden = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
document.getElementById("sync-migration-deck").selectedIndex = selIndex;
|
||||
if (container.hidden) {
|
||||
container.hidden = false;
|
||||
window.innerHeight += container.clientHeight;
|
||||
}
|
||||
},
|
||||
|
||||
startOver: function (showDialog) {
|
||||
if (showDialog) {
|
||||
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
|
||||
|
@ -282,7 +375,6 @@ let gSyncPane = {
|
|||
},
|
||||
|
||||
verifyFirefoxAccount: function() {
|
||||
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
|
||||
fxAccounts.resendVerificationEmail().then(() => {
|
||||
fxAccounts.getSignedInUser().then(data => {
|
||||
let sb = Services.strings.createBundle("chrome://browser/locale/accounts.properties");
|
||||
|
@ -323,7 +415,6 @@ let gSyncPane = {
|
|||
return;
|
||||
}
|
||||
}
|
||||
Components.utils.import('resource://gre/modules/FxAccounts.jsm');
|
||||
fxAccounts.signOut().then(() => {
|
||||
this.updateWeavePrefs();
|
||||
});
|
||||
|
@ -356,5 +447,43 @@ let gSyncPane = {
|
|||
resetSync: function () {
|
||||
this.openSetup("reset");
|
||||
},
|
||||
|
||||
// click handlers for the FxA migration.
|
||||
migrateUpgrade: function() {
|
||||
fxaMigrator.getFxAccountCreationOptions().then(({url, options}) => {
|
||||
this.openContentInBrowser(url, options);
|
||||
});
|
||||
},
|
||||
|
||||
migrateForget: function() {
|
||||
fxaMigrator.forgetFxAccount();
|
||||
},
|
||||
|
||||
migrateResend: function() {
|
||||
fxaMigrator.resendVerificationMail(window);
|
||||
},
|
||||
|
||||
// When the "Unlink" button in the migration header is selected we display
|
||||
// a slightly different message.
|
||||
startOverMigration: function () {
|
||||
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
|
||||
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL +
|
||||
Services.prompt.BUTTON_POS_1_DEFAULT;
|
||||
let sb = this._accountsStringBundle;
|
||||
let buttonChoice =
|
||||
Services.prompt.confirmEx(window,
|
||||
sb.GetStringFromName("unlinkVerificationTitle"),
|
||||
sb.GetStringFromName("unlinkVerificationDescription"),
|
||||
flags,
|
||||
sb.GetStringFromName("unlinkVerificationConfirm"),
|
||||
null, null, null, {});
|
||||
|
||||
// If the user selects cancel, just bail
|
||||
if (buttonChoice == 1)
|
||||
return;
|
||||
|
||||
Weave.Service.startOver();
|
||||
this.updateWeavePrefs();
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -36,6 +36,30 @@
|
|||
<script type="application/javascript"
|
||||
src="chrome://browser/content/sync/utils.js"/>
|
||||
|
||||
<vbox id="sync-migration" flex="1" hidden="true">
|
||||
|
||||
<deck id="sync-migration-deck">
|
||||
<!-- When we are in the "need FxA user" state -->
|
||||
<hbox align="center">
|
||||
<description id="sync-migrate-upgrade-description" flex="1"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="sync-migrate-unlink"
|
||||
onclick="event.stopPropagation(); gSyncPane.startOverMigration();"/>
|
||||
<button id="sync-migrate-upgrade"
|
||||
onclick="event.stopPropagation(); gSyncPane.migrateUpgrade();"/>
|
||||
</hbox>
|
||||
|
||||
<!-- When we are in the "need the user to be verified" state -->
|
||||
<hbox align="center">
|
||||
<description id="sync-migrate-verify-description" flex="1"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="sync-migrate-forget"
|
||||
onclick="event.stopPropagation(); gSyncPane.migrateForget();"/>
|
||||
<button id="sync-migrate-resend"
|
||||
onclick="event.stopPropagation(); gSyncPane.migrateResend();"/>
|
||||
</hbox>
|
||||
</deck>
|
||||
</vbox>
|
||||
|
||||
<deck id="weavePrefsDeck">
|
||||
|
||||
|
|
|
@ -98,8 +98,9 @@ FontInspector.prototype = {
|
|||
|
||||
this.chromeDoc.querySelector("#all-fonts").innerHTML = "";
|
||||
|
||||
let fillStyle = (Services.prefs.getCharPref("devtools.theme") == "light") ?
|
||||
"black" : "white";
|
||||
// Assume light theme colors as the default (see also bug 1118179).
|
||||
let fillStyle = (Services.prefs.getCharPref("devtools.theme") == "dark") ?
|
||||
"white" : "black";
|
||||
let options = {
|
||||
includePreviews: true,
|
||||
previewFillStyle: fillStyle
|
||||
|
|
|
@ -33,6 +33,8 @@ devtools.lazyRequireGetter(this, "CallView",
|
|||
"devtools/profiler/tree-view", true);
|
||||
devtools.lazyRequireGetter(this, "ThreadNode",
|
||||
"devtools/profiler/tree-model", true);
|
||||
devtools.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
|
||||
"devtools/timeline/global", true);
|
||||
|
||||
devtools.lazyImporter(this, "CanvasGraphUtils",
|
||||
"resource:///modules/devtools/Graphs.jsm");
|
||||
|
|
|
@ -16,7 +16,7 @@ let WaterfallView = {
|
|||
this._onMarkerSelected = this._onMarkerSelected.bind(this);
|
||||
this._onResize = this._onResize.bind(this);
|
||||
|
||||
this.graph = new Waterfall($("#waterfall-graph"), $("#details-pane"));
|
||||
this.graph = new Waterfall($("#waterfall-graph"), $("#details-pane"), TIMELINE_BLUEPRINT);
|
||||
this.markerDetails = new MarkerDetails($("#waterfall-details"), $("#waterfall-view > splitter"));
|
||||
|
||||
this.graph.on("selected", this._onMarkerSelected);
|
||||
|
|
|
@ -80,7 +80,7 @@ let OverviewView = {
|
|||
* Sets up the markers overivew graph.
|
||||
*/
|
||||
_showMarkersGraph: Task.async(function *() {
|
||||
this.markersOverview = new MarkersOverview($("#markers-overview"));
|
||||
this.markersOverview = new MarkersOverview($("#markers-overview"), TIMELINE_BLUEPRINT);
|
||||
this.markersOverview.headerHeight = MARKERS_GRAPH_HEADER_HEIGHT;
|
||||
this.markersOverview.bodyHeight = MARKERS_GRAPH_BODY_HEIGHT;
|
||||
this.markersOverview.groupPadding = MARKERS_GROUP_VERTICAL_PADDING;
|
||||
|
|
|
@ -75,7 +75,7 @@ function Waterfall(parent, container, blueprint) {
|
|||
|
||||
// Lazy require is a bit slow, and these are hot objects.
|
||||
this._l10n = L10N;
|
||||
this._blueprint = blueprint
|
||||
this._blueprint = blueprint;
|
||||
this._setNamedTimeout = setNamedTimeout;
|
||||
this._clearNamedTimeout = clearNamedTimeout;
|
||||
|
||||
|
|
|
@ -189,4 +189,25 @@ label.small {
|
|||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync migration
|
||||
*/
|
||||
#sync-migration {
|
||||
border: 1px solid rgba(0, 0, 0, 0.32);
|
||||
background-color: InfoBackground;
|
||||
color: InfoText;
|
||||
text-shadow: none;
|
||||
margin: 5px 0 0 0;
|
||||
animation: fadein 3000ms;
|
||||
}
|
||||
|
||||
#sync-migration description {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
%endif
|
||||
|
|
|
@ -250,4 +250,25 @@ html|a.inline-link:-moz-focusring {
|
|||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync migration
|
||||
*/
|
||||
#sync-migration {
|
||||
border: 1px solid rgba(0, 0, 0, 0.32);
|
||||
background-color: InfoBackground;
|
||||
color: InfoText;
|
||||
text-shadow: none;
|
||||
margin: 5px 0 0 0;
|
||||
animation: fadein 3000ms;
|
||||
}
|
||||
|
||||
#sync-migration description {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
%endif
|
||||
|
|
|
@ -176,4 +176,25 @@ label.small {
|
|||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync migration
|
||||
*/
|
||||
#sync-migration {
|
||||
border: 1px solid rgba(0, 0, 0, 0.32);
|
||||
background-color: InfoBackground;
|
||||
color: InfoText;
|
||||
text-shadow: none;
|
||||
margin: 5px 0 0 0;
|
||||
animation: fadein 3000ms;
|
||||
}
|
||||
|
||||
#sync-migration description {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
%endif
|
||||
|
|
|
@ -11,6 +11,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|||
const UPDATE_URL_PREF = "browser.webapps.updateCheckUrl";
|
||||
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Downloads.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
@ -137,30 +138,29 @@ this.WebappManager = {
|
|||
[p + "=" + encodeURIComponent(params[p]) for (p in params)].join("&");
|
||||
debug("downloading APK from " + generatorUrl.spec);
|
||||
|
||||
let file = Cc["@mozilla.org/download-manager;1"].
|
||||
getService(Ci.nsIDownloadManager).
|
||||
defaultDownloadsDirectory.
|
||||
clone();
|
||||
file.append(aManifestUrl.replace(/[^a-zA-Z0-9]/gi, "") + ".apk");
|
||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
|
||||
debug("downloading APK to " + file.path);
|
||||
Downloads.getSystemDownloadsDirectory().then(function(downloadsDir) {
|
||||
let file = new FileUtils.File(downloadsDir);
|
||||
file.append(aManifestUrl.replace(/[^a-zA-Z0-9]/gi, "") + ".apk");
|
||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
|
||||
debug("downloading APK to " + file.path);
|
||||
|
||||
let worker = new ChromeWorker("resource://gre/modules/WebappManagerWorker.js");
|
||||
worker.onmessage = function(event) {
|
||||
let { type, message } = event.data;
|
||||
let worker = new ChromeWorker("resource://gre/modules/WebappManagerWorker.js");
|
||||
worker.onmessage = function(event) {
|
||||
let { type, message } = event.data;
|
||||
|
||||
worker.terminate();
|
||||
worker.terminate();
|
||||
|
||||
if (type == "success") {
|
||||
deferred.resolve(file.path);
|
||||
} else { // type == "failure"
|
||||
debug("error downloading APK: " + message);
|
||||
deferred.reject(message);
|
||||
if (type == "success") {
|
||||
deferred.resolve(file.path);
|
||||
} else { // type == "failure"
|
||||
debug("error downloading APK: " + message);
|
||||
deferred.reject(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger the download.
|
||||
worker.postMessage({ url: generatorUrl.spec, path: file.path });
|
||||
// Trigger the download.
|
||||
worker.postMessage({ url: generatorUrl.spec, path: file.path });
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
package org.mozilla.search;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.R;
|
||||
|
@ -40,6 +42,8 @@ public class PostSearchFragment extends Fragment {
|
|||
private WebView webview;
|
||||
private View errorView;
|
||||
|
||||
private String resultsPageHost;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
@ -72,6 +76,7 @@ public class PostSearchFragment extends Fragment {
|
|||
final String url = engine.resultsUriForQuery(query);
|
||||
// Only load urls if the url is different than the webview's current url.
|
||||
if (!TextUtils.equals(webview.getUrl(), url)) {
|
||||
resultsPageHost = null;
|
||||
webview.loadUrl(Constants.ABOUT_BLANK);
|
||||
webview.loadUrl(url);
|
||||
}
|
||||
|
@ -95,14 +100,22 @@ public class PostSearchFragment extends Fragment {
|
|||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
// Ignore about:blank URL loads.
|
||||
if (TextUtils.equals(url, Constants.ABOUT_BLANK)) {
|
||||
// Ignore about:blank URL loads and the first results page we try to load.
|
||||
if (TextUtils.equals(url, Constants.ABOUT_BLANK) || resultsPageHost == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the URL is a results page, don't override the URL load, but
|
||||
String host = null;
|
||||
try {
|
||||
host = new URL(url).getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
Log.e(LOG_TAG, "Error getting host from URL loading in webview", e);
|
||||
}
|
||||
|
||||
// If the host name is the same as the results page, don't override the URL load, but
|
||||
// do update the query in the search bar if possible.
|
||||
if (engine.isSearchResultsPage(url)) {
|
||||
if (TextUtils.equals(resultsPageHost, host)) {
|
||||
// This won't work for results pages that redirect (e.g. Google in different country)
|
||||
final String query = engine.queryForResultsUrl(url);
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
((AcceptsSearchQuery) getActivity()).onQueryChange(query);
|
||||
|
@ -132,7 +145,7 @@ public class PostSearchFragment extends Fragment {
|
|||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
||||
|
@ -166,6 +179,14 @@ public class PostSearchFragment extends Fragment {
|
|||
errorView.setVisibility(networkError ? View.VISIBLE : View.GONE);
|
||||
webview.setVisibility(networkError ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
if (!TextUtils.equals(url, Constants.ABOUT_BLANK) && resultsPageHost == null) {
|
||||
try {
|
||||
resultsPageHost = new URL(url).getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
Log.e(LOG_TAG, "Error getting host from results page URL", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -219,14 +219,6 @@ public class SearchEngine {
|
|||
return iconURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a particular url belongs to this search engine. If not,
|
||||
* the url will be sent to Fennec.
|
||||
*/
|
||||
public boolean isSearchResultsPage(String url) {
|
||||
return getResultsUri().getAuthority().equalsIgnoreCase(Uri.parse(url).getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the search query encoded in a given results URL.
|
||||
*
|
||||
|
|
|
@ -370,9 +370,26 @@ Migrator.prototype = {
|
|||
// we'll move to either the STATE_USER_FXA_VERIFIED state or we'll just
|
||||
// complete the migration if they login as an already verified user.
|
||||
createFxAccount: Task.async(function* (win) {
|
||||
let {url, options} = yield this.getFxAccountCreationOptions();
|
||||
win.switchToTabHavingURI(url, true, options);
|
||||
// An FxA observer will fire when the user completes this, which will
|
||||
// cause us to move to the next "user blocked" state and notify via our
|
||||
// observer notification.
|
||||
}),
|
||||
|
||||
// Returns an object with properties "url" and "options", suitable for
|
||||
// opening FxAccounts to create/signin to FxA suitable for the migration
|
||||
// state. The caller of this is responsible for the actual opening of the
|
||||
// page.
|
||||
// This should only be called while we are in the STATE_USER_FXA state. When
|
||||
// the user completes the creation we'll see an ONLOGIN_NOTIFICATION
|
||||
// notification from FxA and we'll move to either the STATE_USER_FXA_VERIFIED
|
||||
// state or we'll just complete the migration if they login as an already
|
||||
// verified user.
|
||||
getFxAccountCreationOptions: Task.async(function* (win) {
|
||||
// warn if we aren't in the expected state - but go ahead anyway!
|
||||
if (this._state != this.STATE_USER_FXA) {
|
||||
this.log.warn("createFxAccount called in an unexpected state: ${}", this._state);
|
||||
this.log.warn("getFxAccountCreationOptions called in an unexpected state: ${}", this._state);
|
||||
}
|
||||
// We need to obtain the sentinel and apply any prefs that might be
|
||||
// specified *before* attempting to setup FxA as the prefs might
|
||||
|
@ -387,16 +404,17 @@ Migrator.prototype = {
|
|||
// See if we can find a default account name to use.
|
||||
let email = yield this._getDefaultAccountName(sentinel);
|
||||
let tail = email ? "&email=" + encodeURIComponent(email) : "";
|
||||
// A special flag so server-side metrics can tell this is part of migration.
|
||||
tail += "&migration=sync11";
|
||||
// We want to ask FxA to offer a "Customize Sync" checkbox iff any engines
|
||||
// are disabled.
|
||||
let customize = !this._allEnginesEnabled();
|
||||
tail += "&customizeSync=" + customize;
|
||||
|
||||
win.switchToTabHavingURI("about:accounts?action=" + action + tail, true,
|
||||
{ignoreFragment: true, replaceQueryString: true});
|
||||
// An FxA observer will fire when the user completes this, which will
|
||||
// cause us to move to the next "user blocked" state and notify via our
|
||||
// observer notification.
|
||||
return {
|
||||
url: "about:accounts?action=" + action + tail,
|
||||
options: {ignoreFragment: true, replaceQueryString: true}
|
||||
};
|
||||
}),
|
||||
|
||||
// Ask the FxA servers to re-send a verification mail for the currently
|
||||
|
@ -407,7 +425,7 @@ Migrator.prototype = {
|
|||
resendVerificationMail: Task.async(function * (win) {
|
||||
// warn if we aren't in the expected state - but go ahead anyway!
|
||||
if (this._state != this.STATE_USER_FXA_VERIFIED) {
|
||||
this.log.warn("createFxAccount called in an unexpected state: ${}", this._state);
|
||||
this.log.warn("resendVerificationMail called in an unexpected state: ${}", this._state);
|
||||
}
|
||||
let ok = true;
|
||||
try {
|
||||
|
@ -442,7 +460,7 @@ Migrator.prototype = {
|
|||
forgetFxAccount: Task.async(function * () {
|
||||
// warn if we aren't in the expected state - but go ahead anyway!
|
||||
if (this._state != this.STATE_USER_FXA_VERIFIED) {
|
||||
this.log.warn("createFxAccount called in an unexpected state: ${}", this._state);
|
||||
this.log.warn("forgetFxAccount called in an unexpected state: ${}", this._state);
|
||||
}
|
||||
return fxAccounts.signOut();
|
||||
}),
|
||||
|
|
|
@ -111,6 +111,30 @@ try {
|
|||
}
|
||||
catch (e) { }
|
||||
|
||||
// Configure a console listener so messages sent to it are logged as part
|
||||
// of the test.
|
||||
try {
|
||||
let levelNames = {}
|
||||
for (let level of ["debug", "info", "warn", "error"]) {
|
||||
levelNames[Components.interfaces.nsIConsoleMessage[level]] = level;
|
||||
}
|
||||
|
||||
let listener = {
|
||||
QueryInterface : function(iid) {
|
||||
if (!iid.equals(Components.interfaces.nsISupports) &&
|
||||
!iid.equals(Components.interfaces.nsIConsoleListener)) {
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
observe : function (msg) {
|
||||
do_print("CONSOLE_MESSAGE: (" + levelNames[msg.logLevel] + ") " + msg.toString());
|
||||
}
|
||||
};
|
||||
Components.classes["@mozilla.org/consoleservice;1"]
|
||||
.getService(Components.interfaces.nsIConsoleService)
|
||||
.registerListener(listener);
|
||||
} catch (e) {}
|
||||
/**
|
||||
* Date.now() is not necessarily monotonically increasing (insert sob story
|
||||
* about times not being the right tool to use for measuring intervals of time,
|
||||
|
|
|
@ -1286,7 +1286,9 @@ Search.prototype = {
|
|||
// search or because of the user's preferences), so only set it if we
|
||||
// haven't already done so.
|
||||
if (showTags) {
|
||||
match.style = "tag";
|
||||
// If we're not suggesting bookmarks, then this shouldn't
|
||||
// display as one.
|
||||
match.style = this.hasBehavior("bookmark") ? "bookmark-tag" : "tag";
|
||||
}
|
||||
else if (bookmarked) {
|
||||
match.style = "bookmark";
|
||||
|
|
|
@ -171,7 +171,7 @@ function* check_autocomplete(test) {
|
|||
// Got a match on both uri and title?
|
||||
if (stripPrefix(uri.spec) == stripPrefix(value) && title == comment) {
|
||||
do_log_info("Got a match at index " + j + "!");
|
||||
let actualStyle = controller.getStyleAt(i).split(/\W+/).sort();
|
||||
let actualStyle = controller.getStyleAt(i).split(/\s+/).sort();
|
||||
if (style)
|
||||
Assert.equal(actualStyle.toString(), style.toString(), "Match should have expected style");
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ add_task(function* test_tag_match_has_bookmark_title() {
|
|||
tags: [ "superTag" ]});
|
||||
yield check_autocomplete({
|
||||
search: "superTag",
|
||||
matches: [ { uri: uri, title: "Bookmark title", tags: [ "superTag" ], style: [ "tag" ] } ]
|
||||
matches: [ { uri: uri, title: "Bookmark title", tags: [ "superTag" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
|
|
@ -23,15 +23,15 @@ add_task(function* test_tag_match_url() {
|
|||
addBookmark({ uri: uri1,
|
||||
title: "title",
|
||||
tags: [ "superTag" ],
|
||||
style: [ "tag" ] });
|
||||
style: [ "bookmark-tag" ] });
|
||||
addBookmark({ uri: uri2,
|
||||
title: "title",
|
||||
tags: [ "superTag" ],
|
||||
style: [ "tag" ] });
|
||||
style: [ "bookmark-tag" ] });
|
||||
yield check_autocomplete({
|
||||
search: "superTag",
|
||||
matches: [ { uri: uri1, title: "title", tags: [ "superTag" ], style: [ "tag" ] },
|
||||
{ uri: uri2, title: "title", tags: [ "superTag" ], style: [ "tag" ] } ]
|
||||
matches: [ { uri: uri1, title: "title", tags: [ "superTag" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri2, title: "title", tags: [ "superTag" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
|
|
@ -33,32 +33,32 @@ add_task(function* test_javascript_match() {
|
|||
do_log_info("Make sure tags come back in the title when matching tags");
|
||||
yield check_autocomplete({
|
||||
search: "page1 tag",
|
||||
matches: [ { uri: uri1, title: "tagged", tags: [ "tag1" ], style: [ "tag" ] } ]
|
||||
matches: [ { uri: uri1, title: "tagged", tags: [ "tag1" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Check tags in title for page2");
|
||||
yield check_autocomplete({
|
||||
search: "page2 tag",
|
||||
matches: [ { uri: uri2, title: "tagged", tags: [ "tag1", "tag2" ], style: [ "tag" ] } ]
|
||||
matches: [ { uri: uri2, title: "tagged", tags: [ "tag1", "tag2" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Make sure tags appear even when not matching the tag");
|
||||
yield check_autocomplete({
|
||||
search: "page3",
|
||||
matches: [ { uri: uri3, title: "tagged", tags: [ "tag1", "tag3" ], style: [ "tag" ] } ]
|
||||
matches: [ { uri: uri3, title: "tagged", tags: [ "tag1", "tag3" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Multiple tags come in commas for page4");
|
||||
yield check_autocomplete({
|
||||
search: "page4",
|
||||
matches: [ { uri: uri4, title: "tagged", tags: [ "tag1", "tag2", "tag3" ], style: [ "tag" ] } ]
|
||||
matches: [ { uri: uri4, title: "tagged", tags: [ "tag1", "tag2", "tag3" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Extra test just to make sure we match the title");
|
||||
yield check_autocomplete({
|
||||
search: "tag2",
|
||||
matches: [ { uri: uri2, title: "tagged", tags: [ "tag1", "tag2" ], style: [ "tag" ] },
|
||||
{ uri: uri4, title: "tagged", tags: [ "tag1", "tag2", "tag3" ], style: [ "tag" ] } ]
|
||||
matches: [ { uri: uri2, title: "tagged", tags: [ "tag1", "tag2" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri4, title: "tagged", tags: [ "tag1", "tag2", "tag3" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
|
|
|
@ -63,10 +63,10 @@ add_task(function* test_special_searches() {
|
|||
{ uri: uri6, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri7, title: "title", style: [ "bookmark" ] },
|
||||
{ uri: uri8, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar"], style: [ "tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar"], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Tag restrict");
|
||||
|
@ -138,10 +138,10 @@ add_task(function* test_special_searches() {
|
|||
matches: [ { uri: uri6, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri7, title: "title", style: [ "bookmark" ] },
|
||||
{ uri: uri8, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo | -> is star (change pref)");
|
||||
|
@ -151,10 +151,10 @@ add_task(function* test_special_searches() {
|
|||
matches: [ { uri: uri6, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri7, title: "title", style: [ "bookmark" ] },
|
||||
{ uri: uri8, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo # -> in title");
|
||||
|
@ -251,7 +251,7 @@ add_task(function* test_special_searches() {
|
|||
yield check_autocomplete({
|
||||
search: "foo ^ *",
|
||||
matches: [ { uri: uri6, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo ^ # -> history, in title");
|
||||
|
@ -289,10 +289,10 @@ add_task(function* test_special_searches() {
|
|||
search: "foo * #",
|
||||
matches: [ { uri: uri6, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri8, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo * @ -> is star, in url");
|
||||
|
@ -300,23 +300,23 @@ add_task(function* test_special_searches() {
|
|||
search: "foo * @",
|
||||
matches: [ { uri: uri7, title: "title", style: [ "bookmark" ] },
|
||||
{ uri: uri8, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo * + -> same as +");
|
||||
yield check_autocomplete({
|
||||
search: "foo * +",
|
||||
matches: [ { uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
matches: [ { uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo * ~ -> is star, is typed");
|
||||
yield check_autocomplete({
|
||||
search: "foo * ~",
|
||||
matches: [ { uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
matches: [ { uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo # @ -> in title, in url");
|
||||
|
@ -393,10 +393,10 @@ add_task(function* test_special_searches() {
|
|||
{ uri: uri6, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri7, title: "title", style: [ "bookmark" ] },
|
||||
{ uri: uri8, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar"], style: [ "tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar"], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo -> default history, is star, is typed");
|
||||
|
@ -407,7 +407,7 @@ add_task(function* test_special_searches() {
|
|||
yield check_autocomplete({
|
||||
search: "foo",
|
||||
matches: [ { uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo -> is star");
|
||||
|
@ -419,10 +419,10 @@ add_task(function* test_special_searches() {
|
|||
matches: [ { uri: uri6, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri7, title: "title", style: [ "bookmark" ] },
|
||||
{ uri: uri8, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo -> is star, is typed");
|
||||
|
@ -435,10 +435,10 @@ add_task(function* test_special_searches() {
|
|||
matches: [ { uri: uri6, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri7, title: "title", style: [ "bookmark" ] },
|
||||
{ uri: uri8, title: "foo.bar", style: [ "bookmark" ] },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "tag" ] } ]
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
|
|
|
@ -52,7 +52,7 @@ add_task(function* test_escape() {
|
|||
search: "match",
|
||||
matches: [ { uri: uri1, title: "title1" },
|
||||
{ uri: uri3, title: "matchme2" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "tag" ] },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "title1" } ]
|
||||
});
|
||||
|
||||
|
@ -61,7 +61,7 @@ add_task(function* test_escape() {
|
|||
search: "dont",
|
||||
matches: [ { uri: uri2, title: "title1" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "tag" ] } ]
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 'match' at the beginning or after / or on a CamelCase");
|
||||
|
@ -69,8 +69,8 @@ add_task(function* test_escape() {
|
|||
search: "2",
|
||||
matches: [ { uri: uri3, title: "matchme2" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "tag" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "tag" ] } ]
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "bookmark-tag" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 't' at the beginning or after /");
|
||||
|
@ -80,8 +80,8 @@ add_task(function* test_escape() {
|
|||
{ uri: uri2, title: "title1" },
|
||||
{ uri: uri3, title: "matchme2" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "tag" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "tag" ] },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "title1" } ]
|
||||
});
|
||||
|
||||
|
@ -98,8 +98,8 @@ add_task(function* test_escape() {
|
|||
{ uri: uri2, title: "title1" },
|
||||
{ uri: uri3, title: "matchme2" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "tag" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "tag" ] },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri7, title: "!@#$%^&*()_+{}|:<>?word" },
|
||||
{ uri: uri8, title: katakana.join("") },
|
||||
{ uri: uri9, title: ideograph.join("") },
|
||||
|
@ -164,8 +164,8 @@ add_task(function* test_escape() {
|
|||
{ uri: uri2, title: "title1" },
|
||||
{ uri: uri3, title: "matchme2" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "tag" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "tag" ] },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "bookmark-tag" ] },
|
||||
{ uri: uri10, title: "title1" } ]
|
||||
});
|
||||
|
||||
|
|
|
@ -451,6 +451,15 @@ var PrintUtils = {
|
|||
|
||||
let onEntered = (message) => {
|
||||
mm.removeMessageListener("Printing:PrintPreview:Entered", onEntered);
|
||||
|
||||
if (message.data.failed) {
|
||||
// Something went wrong while putting the document into print preview
|
||||
// mode. Bail out.
|
||||
this._listener.onEnter();
|
||||
this._listener.onExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// Stash the focused element so that we can return to it after exiting
|
||||
// print preview.
|
||||
gFocusedElement = document.commandDispatcher.focusedElement;
|
||||
|
@ -520,7 +529,7 @@ var PrintUtils = {
|
|||
if (gFocusedElement)
|
||||
fm.setFocus(gFocusedElement, fm.FLAG_NOSCROLL);
|
||||
else
|
||||
window.content.focus();
|
||||
this._sourceBrowser.focus();
|
||||
gFocusedElement = null;
|
||||
|
||||
this._listener.onExit();
|
||||
|
|
|
@ -25,6 +25,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
|
|||
"resource://gre/modules/Deprecated.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SearchStaticData",
|
||||
"resource://gre/modules/SearchStaticData.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "clearTimeout",
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gTextToSubURI",
|
||||
"@mozilla.org/intl/texttosuburi;1",
|
||||
|
@ -463,61 +467,113 @@ let ensureKnownCountryCode = Task.async(function* () {
|
|||
Services.prefs.getCharPref("browser.search.countryCode");
|
||||
return; // pref exists, so we've done this before.
|
||||
} catch(e) {}
|
||||
// we don't have it cached, so fetch it.
|
||||
let cc = yield fetchCountryCode();
|
||||
if (cc) {
|
||||
// we got one - stash it away
|
||||
Services.prefs.setCharPref("browser.search.countryCode", cc);
|
||||
// and update our "isUS" cache pref if it is US - that will prevent a
|
||||
// fallback to the timezone check.
|
||||
// However, only do this if the locale also matches.
|
||||
if (getLocale() == "en-US") {
|
||||
Services.prefs.setBoolPref("browser.search.isUS", (cc == "US"));
|
||||
}
|
||||
// and telemetry...
|
||||
let isTimezoneUS = isUSTimezone();
|
||||
if (cc == "US" && !isTimezoneUS) {
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_US_COUNTRY_MISMATCHED_TIMEZONE").add(1);
|
||||
}
|
||||
if (cc != "US" && isTimezoneUS) {
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_US_TIMEZONE_MISMATCHED_COUNTRY").add(1);
|
||||
}
|
||||
}
|
||||
// We don't have it cached, so fetch it. fetchCountryCode() will call
|
||||
// storeCountryCode if it gets a result (even if that happens after the
|
||||
// promise resolves)
|
||||
yield fetchCountryCode();
|
||||
// If gInitialized is true then the search service was forced to perform
|
||||
// a sync initialization during our XHR - capture this via telemetry.
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_CAUSED_SYNC_INIT").add(gInitialized);
|
||||
});
|
||||
|
||||
// Store the result of the geoip request as well as any other values and
|
||||
// telemetry which depend on it.
|
||||
function storeCountryCode(cc) {
|
||||
// Set the country-code itself.
|
||||
Services.prefs.setCharPref("browser.search.countryCode", cc);
|
||||
// and update our "isUS" cache pref if it is US - that will prevent a
|
||||
// fallback to the timezone check.
|
||||
// However, only do this if the locale also matches.
|
||||
if (getLocale() == "en-US") {
|
||||
Services.prefs.setBoolPref("browser.search.isUS", (cc == "US"));
|
||||
}
|
||||
// and telemetry...
|
||||
let isTimezoneUS = isUSTimezone();
|
||||
if (cc == "US" && !isTimezoneUS) {
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_US_COUNTRY_MISMATCHED_TIMEZONE").add(1);
|
||||
}
|
||||
if (cc != "US" && isTimezoneUS) {
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_US_TIMEZONE_MISMATCHED_COUNTRY").add(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the country we are in via a XHR geoip request.
|
||||
function fetchCountryCode() {
|
||||
// values for the SEARCH_SERVICE_COUNTRY_FETCH_RESULT 'enum' telemetry probe.
|
||||
const TELEMETRY_RESULT_ENUM = {
|
||||
SUCCESS: 0,
|
||||
SUCCESS_WITHOUT_DATA: 1,
|
||||
XHRTIMEOUT: 2,
|
||||
ERROR: 3,
|
||||
// Note that we expect to add finer-grained error types here later (eg,
|
||||
// dns error, network error, ssl error, etc) with .ERROR remaining as the
|
||||
// generic catch-all that doesn't fit into other categories.
|
||||
};
|
||||
let endpoint = Services.urlFormatter.formatURLPref("browser.search.geoip.url");
|
||||
// As an escape hatch, no endpoint means no geoip.
|
||||
if (!endpoint) {
|
||||
return Promise.resolve(null);
|
||||
return Promise.resolve();
|
||||
}
|
||||
let startTime = Date.now();
|
||||
return new Promise(resolve => {
|
||||
// Instead of using a timeout on the xhr object itself, we simulate one
|
||||
// using a timer and let the XHR request complete. This allows us to
|
||||
// capture reliable telemetry on what timeout value should actually be
|
||||
// used to ensure most users don't see one while not making it so large
|
||||
// that many users end up doing a sync init of the search service and thus
|
||||
// would see the jank that implies.
|
||||
// (Note we do actually use a timeout on the XHR, but that's set to be a
|
||||
// large value just incase the request never completes - we don't want the
|
||||
// XHR object to live forever)
|
||||
let timeoutMS = Services.prefs.getIntPref("browser.search.geoip.timeout");
|
||||
let timerId = setTimeout(() => {
|
||||
LOG("_fetchCountryCode: timeout fetching country information");
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_TIMEOUT").add(1);
|
||||
timerId = null;
|
||||
resolve();
|
||||
}, timeoutMS);
|
||||
|
||||
let resolveAndReportSuccess = (result, reason) => {
|
||||
// Even if we timed out, we want to save the country code and everything
|
||||
// related so next startup sees the value and doesn't retry this dance.
|
||||
if (result) {
|
||||
storeCountryCode(result);
|
||||
}
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_RESULT").add(reason);
|
||||
|
||||
// This notification is just for tests...
|
||||
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "geoip-lookup-xhr-complete");
|
||||
|
||||
// If we've already timed out then we've already resolved the promise,
|
||||
// so there's nothing else to do.
|
||||
if (timerId == null) {
|
||||
return;
|
||||
}
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_TIMEOUT").add(0);
|
||||
clearTimeout(timerId);
|
||||
resolve();
|
||||
};
|
||||
|
||||
let request = new XMLHttpRequest();
|
||||
request.timeout = Services.prefs.getIntPref("browser.search.geoip.timeout");
|
||||
// This notification is just for tests...
|
||||
Services.obs.notifyObservers(request, SEARCH_SERVICE_TOPIC, "geoip-lookup-xhr-starting");
|
||||
request.timeout = 100000; // 100 seconds as the last-chance fallback
|
||||
request.onload = function(event) {
|
||||
let took = Date.now() - startTime;
|
||||
let cc = event.target.response && event.target.response.country_code;
|
||||
LOG("_fetchCountryCode got success response in " + took + "ms: " + cc);
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_MS").add(took);
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_SUCCESS").add(cc ? 1 : 0);
|
||||
if (!cc) {
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_SUCCESS_WITHOUT_DATA").add(1);
|
||||
}
|
||||
resolve(cc);
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS").add(took);
|
||||
let reason = cc ? TELEMETRY_RESULT_ENUM.SUCCESS : TELEMETRY_RESULT_ENUM.SUCCESS_WITHOUT_DATA;
|
||||
resolveAndReportSuccess(cc, reason);
|
||||
};
|
||||
request.ontimeout = function(event) {
|
||||
LOG("_fetchCountryCode: XHR finally timed-out fetching country information");
|
||||
resolveAndReportSuccess(null, TELEMETRY_RESULT_ENUM.XHRTIMEOUT);
|
||||
};
|
||||
request.onerror = function(event) {
|
||||
LOG("_fetchCountryCode: failed to retrieve country information");
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_SUCCESS").add(0);
|
||||
resolve(null);
|
||||
resolveAndReportSuccess(null, TELEMETRY_RESULT_ENUM.ERROR);
|
||||
};
|
||||
request.ontimeout = function(event) {
|
||||
LOG("_fetchCountryCode: timeout fetching country information");
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_TIMEOUT").add(1);
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_SUCCESS").add(0);
|
||||
resolve(null);
|
||||
}
|
||||
request.open("POST", endpoint, true);
|
||||
request.setRequestHeader("Content-Type", "application/json");
|
||||
request.responseType = "json";
|
||||
|
|
|
@ -302,3 +302,51 @@ let addTestEngines = Task.async(function* (aItems) {
|
|||
|
||||
return engines;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns a promise that is resolved when an observer notification from the
|
||||
* search service fires with the specified data.
|
||||
*
|
||||
* @param aExpectedData
|
||||
* The value the observer notification sends that causes us to resolve
|
||||
* the promise.
|
||||
*/
|
||||
function waitForSearchNotification(aExpectedData) {
|
||||
return new Promise(resolve => {
|
||||
const SEARCH_SERVICE_TOPIC = "browser-search-service";
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
|
||||
if (aData != aExpectedData)
|
||||
return;
|
||||
|
||||
Services.obs.removeObserver(observer, SEARCH_SERVICE_TOPIC);
|
||||
resolve(aSubject);
|
||||
}, SEARCH_SERVICE_TOPIC, false);
|
||||
});
|
||||
}
|
||||
|
||||
// This "enum" from nsSearchService.js
|
||||
const TELEMETRY_RESULT_ENUM = {
|
||||
SUCCESS: 0,
|
||||
SUCCESS_WITHOUT_DATA: 1,
|
||||
XHRTIMEOUT: 2,
|
||||
ERROR: 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks the value of the SEARCH_SERVICE_COUNTRY_FETCH_RESULT probe.
|
||||
*
|
||||
* @param aExpectedValue
|
||||
* If a value from TELEMETRY_RESULT_ENUM, we expect to see this value
|
||||
* recorded exactly once in the probe. If |null|, we expect to see
|
||||
* nothing recorded in the probe at all.
|
||||
*/
|
||||
function checkCountryResultTelemetry(aExpectedValue) {
|
||||
let histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_RESULT");
|
||||
let snapshot = histogram.snapshot();
|
||||
// The probe is declared with 8 values, but we get 9 back from .counts
|
||||
let expectedCounts = [0,0,0,0,0,0,0,0,0];
|
||||
if (aExpectedValue != null) {
|
||||
expectedCounts[aExpectedValue] = 1;
|
||||
}
|
||||
deepEqual(snapshot.counts, expectedCounts);
|
||||
}
|
||||
|
|
|
@ -25,9 +25,14 @@ function run_test() {
|
|||
equal(Services.prefs.getCharPref("browser.search.countryCode"), "AU", "got the correct country code.");
|
||||
equal(Services.prefs.getBoolPref("browser.search.isUS"), false, "AU is not in the US.")
|
||||
// check we have "success" recorded in telemetry
|
||||
let histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_SUCCESS");
|
||||
let snapshot = histogram.snapshot();
|
||||
equal(snapshot.sum, 1)
|
||||
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.SUCCESS);
|
||||
// a false value for each of SEARCH_SERVICE_COUNTRY_TIMEOUT and SEARCH_SERVICE_COUNTRY_FETCH_CAUSED_SYNC_INIT
|
||||
for (let hid of ["SEARCH_SERVICE_COUNTRY_TIMEOUT",
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_CAUSED_SYNC_INIT"]) {
|
||||
let histogram = Services.telemetry.getHistogramById(hid);
|
||||
let snapshot = histogram.snapshot();
|
||||
deepEqual(snapshot.counts, [1,0,0]); // boolean probe so 3 buckets, expect 1 result for |0|.
|
||||
}
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -20,7 +20,9 @@ function run_test() {
|
|||
removeCacheFile();
|
||||
});
|
||||
|
||||
// from server-locations.txt, we choose a URL without a cert.
|
||||
// this will cause an "unknown host" error, but not report an external
|
||||
// network connection in the tests (note that the hosts listed in
|
||||
// server-locations.txt are *not* loaded for xpcshell tests...)
|
||||
let url = "https://nocert.example.com:443";
|
||||
Services.prefs.setCharPref("browser.search.geoip.url", url);
|
||||
Services.search.init(() => {
|
||||
|
@ -28,15 +30,15 @@ function run_test() {
|
|||
Services.prefs.getCharPref("browser.search.countryCode");
|
||||
ok(false, "not expecting countryCode to be set");
|
||||
} catch (ex) {}
|
||||
// should be no success recorded.
|
||||
let histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_SUCCESS");
|
||||
let snapshot = histogram.snapshot();
|
||||
equal(snapshot.sum, 0);
|
||||
|
||||
// should be no timeout either.
|
||||
histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_TIMEOUT");
|
||||
snapshot = histogram.snapshot();
|
||||
equal(snapshot.sum, 0);
|
||||
// should have an error recorded.
|
||||
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.ERROR);
|
||||
// but false values for timeout and forced-sync-init.
|
||||
for (let hid of ["SEARCH_SERVICE_COUNTRY_TIMEOUT",
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_CAUSED_SYNC_INIT"]) {
|
||||
let histogram = Services.telemetry.getHistogramById(hid);
|
||||
let snapshot = histogram.snapshot();
|
||||
deepEqual(snapshot.counts, [1,0,0]); // boolean probe so 3 buckets, expect 1 result for |0|.
|
||||
}
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
|
|
|
@ -36,15 +36,15 @@ function run_test() {
|
|||
equal(Services.prefs.getBoolPref("browser.search.isUS"),
|
||||
isUSTimezone(),
|
||||
"should have set isUS based on current timezone.");
|
||||
// should have a false value for success.
|
||||
let histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_SUCCESS");
|
||||
let snapshot = histogram.snapshot();
|
||||
equal(snapshot.sum, 0);
|
||||
|
||||
// and a flag for SEARCH_SERVICE_COUNTRY_SUCCESS_WITHOUT_DATA
|
||||
histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_SUCCESS_WITHOUT_DATA");
|
||||
snapshot = histogram.snapshot();
|
||||
equal(snapshot.sum, 1);
|
||||
// should have recorded SUCCESS_WITHOUT_DATA
|
||||
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.SUCCESS_WITHOUT_DATA);
|
||||
// and false values for timeout and forced-sync-init.
|
||||
for (let hid of ["SEARCH_SERVICE_COUNTRY_TIMEOUT",
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_CAUSED_SYNC_INIT"]) {
|
||||
let histogram = Services.telemetry.getHistogramById(hid);
|
||||
let snapshot = histogram.snapshot();
|
||||
deepEqual(snapshot.counts, [1,0,0]); // boolean probe so 3 buckets, expect 1 result for |0|.
|
||||
}
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
|
|
|
@ -64,15 +64,32 @@ add_task(function* test_simple() {
|
|||
deepEqual(getCountryCodePref(), undefined, "didn't do the geoip xhr");
|
||||
// and no telemetry evidence of geoip.
|
||||
for (let hid of [
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_MS",
|
||||
"SEARCH_SERVICE_COUNTRY_SUCCESS",
|
||||
"SEARCH_SERVICE_COUNTRY_SUCCESS_WITHOUT_DATA",
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_TIMEOUT",
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_RESULT",
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS",
|
||||
"SEARCH_SERVICE_COUNTRY_TIMEOUT",
|
||||
"SEARCH_SERVICE_US_COUNTRY_MISMATCHED_TIMEZONE",
|
||||
"SEARCH_SERVICE_US_TIMEZONE_MISMATCHED_COUNTRY",
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_CAUSED_SYNC_INIT",
|
||||
]) {
|
||||
let histogram = Services.telemetry.getHistogramById(hid);
|
||||
let snapshot = histogram.snapshot();
|
||||
equal(snapshot.sum, 0);
|
||||
equal(snapshot.sum, 0, hid);
|
||||
switch (snapshot.histogram_type) {
|
||||
case Ci.nsITelemetry.HISTOGRAM_FLAG:
|
||||
// flags are a special case in that they are initialized with a default
|
||||
// of one |0|.
|
||||
deepEqual(snapshot.counts, [1,0,0], hid);
|
||||
break;
|
||||
case Ci.nsITelemetry.HISTOGRAM_BOOLEAN:
|
||||
// booleans aren't initialized at all, so should have all zeros.
|
||||
deepEqual(snapshot.counts, [0,0,0], hid);
|
||||
break;
|
||||
case Ci.nsITelemetry.HISTOGRAM_EXPONENTIAL:
|
||||
case Ci.nsITelemetry.HISTOGRAM_LINEAR:
|
||||
equal(snapshot.counts.reduce((a, b) => a+b), 0, hid);
|
||||
break;
|
||||
default:
|
||||
ok(false, "unknown histogram type " + snapshot.histogram_type + " for " + hid);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function startServer() {
|
||||
// This is testing the "normal" timer-based timeout for the location search.
|
||||
|
||||
function startServer(continuePromise) {
|
||||
let srv = new HttpServer();
|
||||
function lookupCountry(metadata, response) {
|
||||
response.processAsync();
|
||||
// wait 200 ms before writing a valid response - the search service
|
||||
// should timeout before the response is written so the response should
|
||||
// be ignored.
|
||||
do_timeout(200, () => {
|
||||
// wait for our continuePromise to resolve before writing a valid
|
||||
// response.
|
||||
// This will be resolved after the timeout period, so we can check
|
||||
// the behaviour in that case.
|
||||
continuePromise.then(() => {
|
||||
response.setStatusLine("1.1", 200, "OK");
|
||||
response.write('{"country_code" : "AU"}');
|
||||
response.finish();
|
||||
});
|
||||
}
|
||||
srv.registerPathHandler("/lookup_country", lookupCountry);
|
||||
|
@ -18,6 +22,11 @@ function startServer() {
|
|||
return srv;
|
||||
}
|
||||
|
||||
function getProbeSum(probe, sum) {
|
||||
let histogram = Services.telemetry.getHistogramById(probe);
|
||||
return histogram.snapshot().sum;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
removeMetadata();
|
||||
removeCacheFile();
|
||||
|
@ -37,7 +46,12 @@ function run_test() {
|
|||
removeCacheFile();
|
||||
});
|
||||
|
||||
let server = startServer();
|
||||
let resolveContinuePromise;
|
||||
let continuePromise = new Promise(resolve => {
|
||||
resolveContinuePromise = resolve;
|
||||
});
|
||||
|
||||
let server = startServer(continuePromise);
|
||||
let url = "http://localhost:" + server.identity.primaryPort + "/lookup_country";
|
||||
Services.prefs.setCharPref("browser.search.geoip.url", url);
|
||||
Services.prefs.setIntPref("browser.search.geoip.timeout", 50);
|
||||
|
@ -46,18 +60,36 @@ function run_test() {
|
|||
Services.prefs.getCharPref("browser.search.countryCode");
|
||||
ok(false, "not expecting countryCode to be set");
|
||||
} catch (ex) {}
|
||||
// should be no success recorded.
|
||||
let histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_SUCCESS");
|
||||
// should be no result recorded at all.
|
||||
checkCountryResultTelemetry(null);
|
||||
|
||||
// should have set the flag indicating we saw a timeout.
|
||||
let histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_TIMEOUT");
|
||||
let snapshot = histogram.snapshot();
|
||||
equal(snapshot.sum, 0);
|
||||
deepEqual(snapshot.counts, [0,1,0]);
|
||||
// should not yet have SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS recorded as our
|
||||
// test server is still blocked on our promise.
|
||||
equal(getProbeSum("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS"), 0);
|
||||
|
||||
// should be a timeout.
|
||||
histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_TIMEOUT");
|
||||
snapshot = histogram.snapshot();
|
||||
equal(snapshot.sum, 1);
|
||||
waitForSearchNotification("geoip-lookup-xhr-complete").then(() => {
|
||||
// now we *should* have a report of how long the response took even though
|
||||
// it timed out.
|
||||
// The telemetry "sum" will be the actual time in ms - just check it's non-zero.
|
||||
ok(getProbeSum("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS") != 0);
|
||||
// should have reported the fetch ended up being successful
|
||||
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.SUCCESS);
|
||||
|
||||
do_test_finished();
|
||||
server.stop(run_next_test);
|
||||
// and should have the result of the response that finally came in, and
|
||||
// everything dependent should also be updated.
|
||||
equal(Services.prefs.getCharPref("browser.search.countryCode"), "AU");
|
||||
equal(Services.prefs.getBoolPref("browser.search.isUS"), false);
|
||||
|
||||
do_test_finished();
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
// now tell the server to send its response. That will end up causing the
|
||||
// search service to notify of that the response was received.
|
||||
resolveContinuePromise();
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This is testing the long, last-resort XHR-based timeout for the location
|
||||
// search.
|
||||
|
||||
function startServer(continuePromise) {
|
||||
let srv = new HttpServer();
|
||||
function lookupCountry(metadata, response) {
|
||||
response.processAsync();
|
||||
// wait for our continuePromise to resolve before writing a valid
|
||||
// response.
|
||||
// This will be resolved after the timeout period, so we can check
|
||||
// the behaviour in that case.
|
||||
continuePromise.then(() => {
|
||||
response.setStatusLine("1.1", 200, "OK");
|
||||
response.write('{"country_code" : "AU"}');
|
||||
response.finish();
|
||||
});
|
||||
}
|
||||
srv.registerPathHandler("/lookup_country", lookupCountry);
|
||||
srv.start(-1);
|
||||
return srv;
|
||||
}
|
||||
|
||||
function verifyProbeSum(probe, sum) {
|
||||
let histogram = Services.telemetry.getHistogramById(probe);
|
||||
let snapshot = histogram.snapshot();
|
||||
equal(snapshot.sum, sum, probe);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
removeMetadata();
|
||||
removeCacheFile();
|
||||
|
||||
do_check_false(Services.search.isInitialized);
|
||||
|
||||
let engineDummyFile = gProfD.clone();
|
||||
engineDummyFile.append("searchplugins");
|
||||
engineDummyFile.append("test-search-engine.xml");
|
||||
let engineDir = engineDummyFile.parent;
|
||||
engineDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
|
||||
do_get_file("data/engine.xml").copyTo(engineDir, "engine.xml");
|
||||
|
||||
do_register_cleanup(function() {
|
||||
removeMetadata();
|
||||
removeCacheFile();
|
||||
});
|
||||
|
||||
let resolveContinuePromise;
|
||||
let continuePromise = new Promise(resolve => {
|
||||
resolveContinuePromise = resolve;
|
||||
});
|
||||
|
||||
let server = startServer(continuePromise);
|
||||
let url = "http://localhost:" + server.identity.primaryPort + "/lookup_country";
|
||||
Services.prefs.setCharPref("browser.search.geoip.url", url);
|
||||
// The timeout for the timer.
|
||||
Services.prefs.setIntPref("browser.search.geoip.timeout", 10);
|
||||
let promiseXHRStarted = waitForSearchNotification("geoip-lookup-xhr-starting");
|
||||
Services.search.init(() => {
|
||||
try {
|
||||
Services.prefs.getCharPref("browser.search.countryCode");
|
||||
ok(false, "not expecting countryCode to be set");
|
||||
} catch (ex) {}
|
||||
// should be no result recorded at all.
|
||||
checkCountryResultTelemetry(null);
|
||||
|
||||
// should have set the flag indicating we saw a timeout.
|
||||
let histogram = Services.telemetry.getHistogramById("SEARCH_SERVICE_COUNTRY_TIMEOUT");
|
||||
let snapshot = histogram.snapshot();
|
||||
deepEqual(snapshot.counts, [0,1,0]);
|
||||
|
||||
// should not have SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS recorded as our
|
||||
// test server is still blocked on our promise.
|
||||
verifyProbeSum("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS", 0);
|
||||
|
||||
promiseXHRStarted.then(xhr => {
|
||||
// Set the timeout on the xhr object to an extremely low value, so it
|
||||
// should timeout immediately.
|
||||
xhr.timeout = 10;
|
||||
// wait for the xhr timeout to fire.
|
||||
waitForSearchNotification("geoip-lookup-xhr-complete").then(() => {
|
||||
// should have the XHR timeout recorded.
|
||||
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.XHRTIMEOUT);
|
||||
// still should not have a report of how long the response took as we
|
||||
// only record that on success responses.
|
||||
verifyProbeSum("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS", 0);
|
||||
// and we don't know the country code.
|
||||
try {
|
||||
Services.prefs.getCharPref("browser.search.countryCode");
|
||||
ok(false, "not expecting countryCode to be set");
|
||||
} catch (ex) {}
|
||||
|
||||
// unblock the server even though nothing is listening.
|
||||
resolveContinuePromise();
|
||||
|
||||
do_test_finished();
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
|
@ -47,20 +47,8 @@ function getDefaultEngineName() {
|
|||
return Services.prefs.getComplexValue(pref, nsIPLS).data;
|
||||
}
|
||||
|
||||
function waitForNotification(aExpectedData) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
const SEARCH_SERVICE_TOPIC = "browser-search-service";
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
|
||||
if (aData != aExpectedData)
|
||||
return;
|
||||
|
||||
Services.obs.removeObserver(observer, SEARCH_SERVICE_TOPIC);
|
||||
deferred.resolve();
|
||||
}, SEARCH_SERVICE_TOPIC, false);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
// waitForSearchNotification is in head_search.js
|
||||
let waitForNotification = waitForSearchNotification;
|
||||
|
||||
function asyncInit() {
|
||||
let deferred = Promise.defer();
|
||||
|
|
|
@ -35,6 +35,7 @@ support-files =
|
|||
[test_location_malformed_json.js]
|
||||
[test_location_sync.js]
|
||||
[test_location_timeout.js]
|
||||
[test_location_timeout_xhr.js]
|
||||
[test_nodb.js]
|
||||
[test_nodb_pluschanges.js]
|
||||
[test_save_sorted_engines.js]
|
||||
|
|
|
@ -4577,31 +4577,32 @@
|
|||
"extended_statistics_ok": true,
|
||||
"description": "Time (ms) it takes to build the cache of the search service"
|
||||
},
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_MS": {
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS": {
|
||||
"alert_emails": ["mhammond@mozilla.com", "gavin@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "linear",
|
||||
"n_buckets": 20,
|
||||
"high": 2000,
|
||||
"kind": "exponential",
|
||||
"n_buckets": 30,
|
||||
"high": 100000,
|
||||
"description": "Time (ms) it takes to fetch the country code"
|
||||
},
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_TIMEOUT": {
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_RESULT": {
|
||||
"alert_emails": ["mhammond@mozilla.com", "gavin@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "flag",
|
||||
"description": "If we saw a timeout fetching the country-code"
|
||||
"kind": "enumerated",
|
||||
"n_values": 8,
|
||||
"description": "Result of XHR request fetching the country-code. 0=SUCCESS, 1=SUCCESS_WITHOUT_DATA, 2=XHRTIMEOUT, 3=ERROR (rest reserved for finer-grained error codes later)"
|
||||
},
|
||||
"SEARCH_SERVICE_COUNTRY_SUCCESS": {
|
||||
"SEARCH_SERVICE_COUNTRY_TIMEOUT": {
|
||||
"alert_emails": ["mhammond@mozilla.com", "gavin@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "boolean",
|
||||
"description": "If we successfully fetched the country-code."
|
||||
"description": "True if we stopped waiting for the XHR response before it completed"
|
||||
},
|
||||
"SEARCH_SERVICE_COUNTRY_SUCCESS_WITHOUT_DATA": {
|
||||
"SEARCH_SERVICE_COUNTRY_FETCH_CAUSED_SYNC_INIT": {
|
||||
"alert_emails": ["mhammond@mozilla.com", "gavin@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "flag",
|
||||
"description": "If we got a success response but no country-code"
|
||||
"kind": "boolean",
|
||||
"description": "True if the search service was synchronously initialized while we were waiting for the XHR response"
|
||||
},
|
||||
"SEARCH_SERVICE_US_COUNTRY_MISMATCHED_TIMEZONE": {
|
||||
"alert_emails": ["mhammond@mozilla.com", "gavin@mozilla.com"],
|
||||
|
|
|
@ -416,17 +416,35 @@ let Printing = {
|
|||
printSettings = null;
|
||||
}
|
||||
|
||||
// We'll call this whenever we've finished reflowing the document, or if
|
||||
// we errored out while attempting to print preview (in which case, we'll
|
||||
// notify the parent that we've failed).
|
||||
let notifyEntered = (error) => {
|
||||
removeEventListener("printPreviewUpdate", onPrintPreviewReady);
|
||||
sendAsyncMessage("Printing:Preview:Entered", {
|
||||
failed: !!error,
|
||||
});
|
||||
};
|
||||
|
||||
let onPrintPreviewReady = () => {
|
||||
notifyEntered();
|
||||
};
|
||||
|
||||
// We have to wait for the print engine to finish reflowing all of the
|
||||
// documents and subdocuments before we can tell the parent to flip to
|
||||
// the print preview UI - otherwise, the print preview UI might ask for
|
||||
// information (like the number of pages in the document) before we have
|
||||
// our PresShells set up.
|
||||
addEventListener("printPreviewUpdate", function onPrintPreviewReady() {
|
||||
removeEventListener("printPreviewUpdate", onPrintPreviewReady);
|
||||
sendAsyncMessage("Printing:Preview:Entered");
|
||||
});
|
||||
addEventListener("printPreviewUpdate", onPrintPreviewReady);
|
||||
|
||||
docShell.printPreview.printPreview(printSettings, contentWindow, this);
|
||||
try {
|
||||
docShell.printPreview.printPreview(printSettings, contentWindow, this);
|
||||
} catch(error) {
|
||||
// This might fail if we, for example, attempt to print a XUL document.
|
||||
// In that case, we inform the parent to bail out of print preview.
|
||||
Components.utils.reportError(error);
|
||||
notifyEntered(error);
|
||||
}
|
||||
},
|
||||
|
||||
exitPrintPreview() {
|
||||
|
|
|
@ -1596,6 +1596,7 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
|||
// we need extra stuff.
|
||||
this._extraBox.hidden = true;
|
||||
this._titleBox.flex = 1;
|
||||
this._typeImage.hidden = false;
|
||||
|
||||
this.removeAttribute("actiontype");
|
||||
this.classList.remove("overridable-action");
|
||||
|
@ -1681,7 +1682,7 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
|||
type = [...types].join(" ");
|
||||
|
||||
// If we have a tag match, show the tags and icon
|
||||
if (type == "tag") {
|
||||
if (type == "tag" || type == "bookmark-tag") {
|
||||
// Configure the extra box for tags display
|
||||
this._extraBox.hidden = false;
|
||||
this._extraBox.childNodes[0].hidden = false;
|
||||
|
@ -1699,8 +1700,13 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
|||
// Emphasize the matching text in the tags
|
||||
this._setUpDescription(this._extra, sortedTags);
|
||||
|
||||
// Treat tagged matches as bookmarks for the star
|
||||
type = "bookmark";
|
||||
// If we're suggesting bookmarks, then treat tagged matches as
|
||||
// bookmarks for the star.
|
||||
if (type == "bookmark-tag") {
|
||||
type = "bookmark";
|
||||
} else {
|
||||
this._typeImage.hidden = true;
|
||||
}
|
||||
// keyword and favicon type results for search engines
|
||||
// have an extra magnifying glass icon after them
|
||||
} else if (type == "keyword" || (initialTypes.has("search") &&
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
readonly="true">
|
||||
<getter><![CDATA[
|
||||
if (!this._securityUI) {
|
||||
// Don't attempt to create the remote web progress if the
|
||||
// messageManager has already gone away
|
||||
if (!this.messageManager)
|
||||
return null;
|
||||
|
||||
let jsm = "resource://gre/modules/RemoteSecurityUI.jsm";
|
||||
let RemoteSecurityUI = Components.utils.import(jsm, {}).RemoteSecurityUI;
|
||||
this._securityUI = new RemoteSecurityUI();
|
||||
|
@ -40,6 +45,8 @@
|
|||
]]></body>
|
||||
</method>
|
||||
|
||||
<field name="_controller">null</field>
|
||||
|
||||
<field name="_remoteWebNavigation">null</field>
|
||||
|
||||
<property name="webNavigation"
|
||||
|
@ -52,8 +59,13 @@
|
|||
<getter>
|
||||
<![CDATA[
|
||||
if (!this._remoteWebProgress) {
|
||||
// Don't attempt to create the remote web progress if the
|
||||
// messageManager has already gone away
|
||||
if (!this.messageManager)
|
||||
return null;
|
||||
|
||||
let jsm = "resource://gre/modules/RemoteWebProgress.jsm";
|
||||
let RemoteWebProgressManager = Cu.import(jsm, {}).RemoteWebProgressManager;
|
||||
let { RemoteWebProgressManager } = Cu.import(jsm, {});
|
||||
this._remoteWebProgressManager = new RemoteWebProgressManager(this);
|
||||
this._remoteWebProgress = this._remoteWebProgressManager.topLevelWebProgress;
|
||||
}
|
||||
|
@ -67,8 +79,13 @@
|
|||
<property name="finder" readonly="true">
|
||||
<getter><![CDATA[
|
||||
if (!this._remoteFinder) {
|
||||
// Don't attempt to create the remote web progress if the
|
||||
// messageManager has already gone away
|
||||
if (!this.messageManager)
|
||||
return null;
|
||||
|
||||
let jsm = "resource://gre/modules/RemoteFinder.jsm";
|
||||
let RemoteFinder = Cu.import(jsm, {}).RemoteFinder;
|
||||
let { RemoteFinder } = Cu.import(jsm, {});
|
||||
this._remoteFinder = new RemoteFinder(this);
|
||||
}
|
||||
return this._remoteFinder;
|
||||
|
@ -206,6 +223,8 @@
|
|||
</setter>
|
||||
</property>
|
||||
|
||||
<field name="mDestroyed">false</field>
|
||||
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
/*
|
||||
|
@ -246,10 +265,24 @@
|
|||
|
||||
<destructor>
|
||||
<![CDATA[
|
||||
Services.obs.removeObserver(this, "ask-children-to-exit-fullscreen");
|
||||
this.destroy();
|
||||
]]>
|
||||
</destructor>
|
||||
|
||||
<!-- This is necessary because the destructor doesn't always get called when
|
||||
we are removed from a tabbrowser. This will be explicitly called by tabbrowser -->
|
||||
<method name="destroy">
|
||||
<body><![CDATA[
|
||||
if (this.mDestroyed)
|
||||
return;
|
||||
this.mDestroyed = true;
|
||||
|
||||
this.controllers.removeController(this._controller);
|
||||
|
||||
Services.obs.removeObserver(this, "ask-children-to-exit-fullscreen");
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="receiveMessage">
|
||||
<parameter name="aMessage"/>
|
||||
<body><![CDATA[
|
||||
|
|
|
@ -24,6 +24,7 @@ support-files =
|
|||
signed-untrusted.xpi
|
||||
signed.xpi
|
||||
signed2.xpi
|
||||
slowinstall.sjs
|
||||
startsoftwareupdate.html
|
||||
theme.xpi
|
||||
triggerredirect.html
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const RELATIVE_PATH = "browser/toolkit/mozapps/extensions/test/xpinstall"
|
||||
const NOTIFICATION_TOPIC = "slowinstall-complete";
|
||||
|
||||
/**
|
||||
* Helper function to create a JS object representing the url parameters from
|
||||
* the request's queryString.
|
||||
*
|
||||
* @param aQueryString
|
||||
* The request's query string.
|
||||
* @return A JS object representing the url parameters from the request's
|
||||
* queryString.
|
||||
*/
|
||||
function parseQueryString(aQueryString) {
|
||||
var paramArray = aQueryString.split("&");
|
||||
var regex = /^([^=]+)=(.*)$/;
|
||||
var params = {};
|
||||
for (var i = 0, sz = paramArray.length; i < sz; i++) {
|
||||
var match = regex.exec(paramArray[i]);
|
||||
if (!match)
|
||||
throw "Bad parameter in queryString! '" + paramArray[i] + "'";
|
||||
params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function handleRequest(aRequest, aResponse) {
|
||||
let id = +getState("ID");
|
||||
setState("ID", "" + (id + 1));
|
||||
|
||||
function LOG(str) {
|
||||
dump("slowinstall.sjs[" + id + "]: " + str + "\n");
|
||||
}
|
||||
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
|
||||
|
||||
var params = { };
|
||||
if (aRequest.queryString)
|
||||
params = parseQueryString(aRequest.queryString);
|
||||
|
||||
if (params.file) {
|
||||
let xpiFile = "";
|
||||
|
||||
function complete_download() {
|
||||
LOG("Completing download");
|
||||
downloadPaused = false;
|
||||
|
||||
try {
|
||||
// Doesn't seem to be a sane way to read using OS.File and write to an
|
||||
// nsIOutputStream so here we are.
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.initWithPath(xpiFile);
|
||||
let stream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
stream.init(file, -1, -1, stream.DEFER_OPEN + stream.CLOSE_ON_EOF);
|
||||
|
||||
NetUtil.asyncCopy(stream, aResponse.bodyOutputStream, () => {
|
||||
LOG("Download complete");
|
||||
aResponse.finish();
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
LOG("Exception " + e);
|
||||
}
|
||||
}
|
||||
|
||||
let waitForComplete = new Promise(resolve => {
|
||||
function complete() {
|
||||
Services.obs.removeObserver(complete, NOTIFICATION_TOPIC);
|
||||
resolve();
|
||||
}
|
||||
|
||||
Services.obs.addObserver(complete, NOTIFICATION_TOPIC, false);
|
||||
});
|
||||
|
||||
aResponse.processAsync();
|
||||
|
||||
OS.File.getCurrentDirectory().then(dir => {
|
||||
xpiFile = OS.Path.join(dir, ...RELATIVE_PATH.split("/"), params.file);
|
||||
LOG("Starting slow download of " + xpiFile);
|
||||
|
||||
OS.File.stat(xpiFile).then(info => {
|
||||
aResponse.setHeader("Content-Type", "binary/octet-stream");
|
||||
aResponse.setHeader("Content-Length", info.size.toString());
|
||||
|
||||
LOG("Download paused");
|
||||
waitForComplete.then(complete_download);
|
||||
});
|
||||
});
|
||||
}
|
||||
else if (params.continue) {
|
||||
dump("slowinstall.sjs: Received signal to complete all current downloads.\n");
|
||||
Services.obs.notifyObservers(null, NOTIFICATION_TOPIC, null);
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче