diff --git a/browser/components/preferences/in-content/jar.mn b/browser/components/preferences/in-content/jar.mn index a4271f1202d..f63c6c37ff3 100644 --- a/browser/components/preferences/in-content/jar.mn +++ b/browser/components/preferences/in-content/jar.mn @@ -11,7 +11,7 @@ browser.jar: * content/browser/preferences/in-content/tabs.xul * content/browser/preferences/in-content/tabs.js content/browser/preferences/in-content/privacy.xul - content/browser/preferences/in-content/privacy.js +* content/browser/preferences/in-content/privacy.js * content/browser/preferences/in-content/advanced.xul * content/browser/preferences/in-content/advanced.js content/browser/preferences/in-content/applications.xul diff --git a/browser/components/preferences/in-content/privacy.js b/browser/components/preferences/in-content/privacy.js index 63e47801573..2818663122e 100644 --- a/browser/components/preferences/in-content/privacy.js +++ b/browser/components/preferences/in-content/privacy.js @@ -9,6 +9,11 @@ var gPrivacyPane = { */ _autoStartPrivateBrowsing: false, + /** + * Whether the prompt to restart Firefox should appear when changing the autostart pref. + */ + _shouldPromptForRestart: true, + /** * Sets up the UI for the number of days of history to keep, and updates the * label of the "Clear Now..." button. @@ -127,7 +132,8 @@ var gPrivacyPane = { let pref = document.getElementById("browser.privatebrowsing.autostart"); switch (document.getElementById("historyMode").value) { case "remember": - pref.value = false; + if (pref.value) + pref.value = false; // select the remember history option if needed let rememberHistoryCheckbox = document.getElementById("rememberHistory"); @@ -146,7 +152,8 @@ var gPrivacyPane = { document.getElementById("privacy.sanitize.sanitizeOnShutdown").value = false; break; case "dontremember": - pref.value = true; + if (!pref.value) + pref.value = true; break; } }, @@ -219,19 +226,65 @@ var gPrivacyPane = { observe: function PPP_observe(aSubject, aTopic, aData) { - let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"]. - getService(Components.interfaces.nsIPrivateBrowsingService); +#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING + if (!gPrivacyPane._shouldPromptForRestart) { + // We're performing a revert. Just let it happen. + gPrivacyPane._shouldPromptForRestart = true; + return; + } + const Cc = Components.classes, Ci = Components.interfaces; + let pref = document.getElementById("browser.privatebrowsing.autostart"); + let brandName = document.getElementById("bundleBrand").getString("brandShortName"); + let bundle = document.getElementById("bundlePreferences"); + let msg = bundle.getFormattedString(pref.value ? + "featureEnableRequiresRestart" : "featureDisableRequiresRestart", + [brandName]); + let title = bundle.getFormattedString("shouldRestartTitle", [brandName]); + let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService); + let shouldProceed = prompts.confirm(window, title, msg) + if (shouldProceed) { + let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"] + .createInstance(Ci.nsISupportsPRBool); + Services.obs.notifyObservers(cancelQuit, "quit-application-requested", + "restart"); + shouldProceed = !cancelQuit.data; + + if (shouldProceed) { + let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] + .getService(Ci.nsIAppStartup); + appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart); + return; + } + } + gPrivacyPane._shouldPromptForRestart = false; + pref.value = !pref.value; + + let mode = document.getElementById("historyMode"); + if (mode.value != "custom") { + mode.selectedIndex = pref.value ? 1 : 0; + mode.doCommand(); + } else { + let rememberHistoryCheckbox = document.getElementById("rememberHistory"); + rememberHistory.checked = pref.value; + } +#else // Toggle the private browsing mode without switching the session let prefValue = document.getElementById("browser.privatebrowsing.autostart").value; let keepCurrentSession = document.getElementById("browser.privatebrowsing.keep_current_session"); keepCurrentSession.value = true; + + let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"]. + getService(Components.interfaces.nsIPrivateBrowsingService); + // If activating from within the private browsing mode, reset the // private session if (prefValue && privateBrowsingService.privateBrowsingEnabled) privateBrowsingService.privateBrowsingEnabled = false; privateBrowsingService.privateBrowsingEnabled = prefValue; + keepCurrentSession.reset(); +#endif } }, diff --git a/browser/components/preferences/in-content/tests/Makefile.in b/browser/components/preferences/in-content/tests/Makefile.in index 796fd2c7f07..1b317d42886 100644 --- a/browser/components/preferences/in-content/tests/Makefile.in +++ b/browser/components/preferences/in-content/tests/Makefile.in @@ -15,22 +15,31 @@ _BROWSER_FILES = \ head.js \ browser_advanced_update.js \ browser_bug410900.js \ - browser_bug567487.js \ browser_bug731866.js \ browser_connection.js \ + $(NULL) + +ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING +_BROWSER_FILES += \ privacypane_tests.js \ + browser_bug567487.js \ browser_privacypane_1.js \ browser_privacypane_2.js \ browser_privacypane_3.js \ browser_privacypane_4.js \ browser_privacypane_5.js \ - browser_privacypane_8.js \ - $(NULL) - -ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING -_BROWSER_FILES += \ browser_privacypane_6.js \ browser_privacypane_7.js \ + browser_privacypane_8.js \ + $(NULL) +else +_BROWSER_FILES += \ + privacypane_tests_perwindow.js \ + browser_privacypane_1.js \ + browser_privacypane_3.js \ + browser_privacypane_4.js \ + browser_privacypane_5.js \ + browser_privacypane_8.js \ $(NULL) endif diff --git a/browser/components/preferences/in-content/tests/browser_privacypane_1.js b/browser/components/preferences/in-content/tests/browser_privacypane_1.js index b013d5c80b2..592026754f4 100644 --- a/browser/components/preferences/in-content/tests/browser_privacypane_1.js +++ b/browser/components/preferences/in-content/tests/browser_privacypane_1.js @@ -11,7 +11,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_pane_visibility, diff --git a/browser/components/preferences/in-content/tests/browser_privacypane_2.js b/browser/components/preferences/in-content/tests/browser_privacypane_2.js index 67716c6386e..0ac71721d88 100644 --- a/browser/components/preferences/in-content/tests/browser_privacypane_2.js +++ b/browser/components/preferences/in-content/tests/browser_privacypane_2.js @@ -11,7 +11,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_historymode_retention("remember", undefined), diff --git a/browser/components/preferences/in-content/tests/browser_privacypane_3.js b/browser/components/preferences/in-content/tests/browser_privacypane_3.js index b74f00d05b6..2e5977a9273 100644 --- a/browser/components/preferences/in-content/tests/browser_privacypane_3.js +++ b/browser/components/preferences/in-content/tests/browser_privacypane_3.js @@ -10,7 +10,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_custom_retention("rememberHistory", "remember"), diff --git a/browser/components/preferences/in-content/tests/browser_privacypane_4.js b/browser/components/preferences/in-content/tests/browser_privacypane_4.js index c0e8a59553f..2012e4092cb 100644 --- a/browser/components/preferences/in-content/tests/browser_privacypane_4.js +++ b/browser/components/preferences/in-content/tests/browser_privacypane_4.js @@ -10,7 +10,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_custom_retention("acceptCookies", "remember"), diff --git a/browser/components/preferences/in-content/tests/browser_privacypane_5.js b/browser/components/preferences/in-content/tests/browser_privacypane_5.js index 35055d89c05..98cb92a25c5 100644 --- a/browser/components/preferences/in-content/tests/browser_privacypane_5.js +++ b/browser/components/preferences/in-content/tests/browser_privacypane_5.js @@ -10,7 +10,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_locbar_suggestion_retention(-1, undefined), diff --git a/browser/components/preferences/in-content/tests/browser_privacypane_6.js b/browser/components/preferences/in-content/tests/browser_privacypane_6.js index 38ea026d122..0008da5d07b 100644 --- a/browser/components/preferences/in-content/tests/browser_privacypane_6.js +++ b/browser/components/preferences/in-content/tests/browser_privacypane_6.js @@ -10,7 +10,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_privatebrowsing_toggle, diff --git a/browser/components/preferences/in-content/tests/browser_privacypane_7.js b/browser/components/preferences/in-content/tests/browser_privacypane_7.js index 22bc03370e8..b51d2e483dd 100644 --- a/browser/components/preferences/in-content/tests/browser_privacypane_7.js +++ b/browser/components/preferences/in-content/tests/browser_privacypane_7.js @@ -10,7 +10,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_privatebrowsing_ui, diff --git a/browser/components/preferences/in-content/tests/browser_privacypane_8.js b/browser/components/preferences/in-content/tests/browser_privacypane_8.js index af9e1202c6b..11d270b6435 100644 --- a/browser/components/preferences/in-content/tests/browser_privacypane_8.js +++ b/browser/components/preferences/in-content/tests/browser_privacypane_8.js @@ -10,7 +10,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ // history mode should be initialized to remember diff --git a/browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js b/browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js new file mode 100644 index 00000000000..de8e54b81ed --- /dev/null +++ b/browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js @@ -0,0 +1,344 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function runTestOnPrivacyPrefPane(testFunc) { + + gBrowser.tabContainer.addEventListener("TabOpen", function(aEvent) { + gBrowser.tabContainer.removeEventListener("TabOpen", arguments.callee, true); + let browser = aEvent.originalTarget.linkedBrowser; + browser.addEventListener("Initialized", function(aEvent) { + browser.removeEventListener("Initialized", arguments.callee, true); + is(browser.contentWindow.location.href, "about:preferences", "Checking if the preferences tab was opened"); + testFunc(browser.contentWindow); + gBrowser.removeCurrentTab(); + testRunner.runNext(); + }, true); + }, true); + + gBrowser.selectedTab = gBrowser.addTab("about:preferences"); +} + +function controlChanged(element) { + element.doCommand(); +} + +// We can only test the panes that don't trigger a preference update +function test_pane_visibility(win) { + let modes = { + "remember": "historyRememberPane", + "custom": "historyCustomPane" + }; + + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let historypane = win.document.getElementById("historyPane"); + ok(historypane, "history mode pane should exist"); + + for (let mode in modes) { + historymode.value = mode; + controlChanged(historymode); + is(historypane.selectedPanel, win.document.getElementById(modes[mode]), + "The correct pane should be selected for the " + mode + " mode"); + } +} + +function test_dependent_elements(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let pbautostart = win.document.getElementById("privateBrowsingAutoStart"); + ok(pbautostart, "the private browsing auto-start checkbox should exist"); + let controls = [ + win.document.getElementById("rememberHistory"), + win.document.getElementById("rememberForms"), + win.document.getElementById("keepUntil"), + win.document.getElementById("keepCookiesUntil"), + win.document.getElementById("alwaysClear"), + ]; + controls.forEach(function(control) { + ok(control, "the dependent controls should exist"); + }); + let independents = [ + win.document.getElementById("acceptCookies"), + win.document.getElementById("acceptThirdParty"), + ]; + independents.forEach(function(control) { + ok(control, "the independent controls should exist"); + }); + let cookieexceptions = win.document.getElementById("cookieExceptions"); + ok(cookieexceptions, "the cookie exceptions button should exist"); + let keepuntil = win.document.getElementById("keepCookiesUntil"); + ok(keepuntil, "the keep cookies until menulist should exist"); + let alwaysclear = win.document.getElementById("alwaysClear"); + ok(alwaysclear, "the clear data on close checkbox should exist"); + let rememberhistory = win.document.getElementById("rememberHistory"); + ok(rememberhistory, "the remember history checkbox should exist"); + let rememberforms = win.document.getElementById("rememberForms"); + ok(rememberforms, "the remember forms checkbox should exist"); + let alwaysclearsettings = win.document.getElementById("clearDataSettings"); + ok(alwaysclearsettings, "the clear data settings button should exist"); + + function expect_disabled(disabled) { + controls.forEach(function(control) { + is(control.disabled, disabled, + control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled"); + }); + is(keepuntil.value, disabled ? 2 : 0, + "the keep cookies until menulist value should be as expected"); + if (disabled) { + ok(!alwaysclear.checked, + "the clear data on close checkbox value should be as expected"); + ok(!rememberhistory.checked, + "the remember history checkbox value should be as expected"); + ok(!rememberforms.checked, + "the remember forms checkbox value should be as expected"); + } + } + function check_independents(expected) { + independents.forEach(function(control) { + is(control.disabled, expected, + control.getAttribute("id") + " should " + (expected ? "" : "not ") + "be disabled"); + }); + + ok(!cookieexceptions.disabled, + "the cookie exceptions button should never be disabled"); + ok(alwaysclearsettings.disabled, + "the clear data settings button should always be disabled"); + } + + // controls should only change in custom mode + historymode.value = "remember"; + controlChanged(historymode); + expect_disabled(false); + check_independents(false); + + // setting the mode to custom shouldn't change anything + historymode.value = "custom"; + controlChanged(historymode); + expect_disabled(false); + check_independents(false); +} + +function test_dependent_cookie_elements(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let pbautostart = win.document.getElementById("privateBrowsingAutoStart"); + ok(pbautostart, "the private browsing auto-start checkbox should exist"); + let controls = [ + win.document.getElementById("acceptThirdParty"), + win.document.getElementById("keepUntil"), + win.document.getElementById("keepCookiesUntil"), + ]; + controls.forEach(function(control) { + ok(control, "the dependent cookie controls should exist"); + }); + let acceptcookies = win.document.getElementById("acceptCookies"); + ok(acceptcookies, "the accept cookies checkbox should exist"); + + function expect_disabled(disabled) { + controls.forEach(function(control) { + is(control.disabled, disabled, + control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled"); + }); + } + + historymode.value = "custom"; + controlChanged(historymode); + pbautostart.checked = false; + controlChanged(pbautostart); + expect_disabled(false); + + acceptcookies.checked = false; + controlChanged(acceptcookies); + expect_disabled(true); + + acceptcookies.checked = true; + controlChanged(acceptcookies); + expect_disabled(false); + + let accessthirdparty = controls.shift(); + acceptcookies.checked = false; + controlChanged(acceptcookies); + expect_disabled(true); + ok(accessthirdparty.disabled, "access third party button should be disabled"); + + pbautostart.checked = false; + controlChanged(pbautostart); + expect_disabled(true); + ok(accessthirdparty.disabled, "access third party button should be disabled"); + + acceptcookies.checked = true; + controlChanged(acceptcookies); + expect_disabled(false); + ok(!accessthirdparty.disabled, "access third party button should be enabled"); +} + +function test_dependent_clearonclose_elements(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let pbautostart = win.document.getElementById("privateBrowsingAutoStart"); + ok(pbautostart, "the private browsing auto-start checkbox should exist"); + let alwaysclear = win.document.getElementById("alwaysClear"); + ok(alwaysclear, "the clear data on close checkbox should exist"); + let alwaysclearsettings = win.document.getElementById("clearDataSettings"); + ok(alwaysclearsettings, "the clear data settings button should exist"); + + function expect_disabled(disabled) { + is(alwaysclearsettings.disabled, disabled, + "the clear data settings should " + (disabled ? "" : "not ") + "be disabled"); + } + + historymode.value = "custom"; + controlChanged(historymode); + pbautostart.checked = false; + controlChanged(pbautostart); + alwaysclear.checked = false; + controlChanged(alwaysclear); + expect_disabled(true); + + alwaysclear.checked = true; + controlChanged(alwaysclear); + expect_disabled(false); + + alwaysclear.checked = false; + controlChanged(alwaysclear); + expect_disabled(true); +} + +function test_dependent_prefs(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let controls = [ + win.document.getElementById("rememberHistory"), + win.document.getElementById("rememberForms"), + win.document.getElementById("acceptCookies"), + win.document.getElementById("acceptThirdParty"), + ]; + controls.forEach(function(control) { + ok(control, "the micro-management controls should exist"); + }); + + function expect_checked(checked) { + controls.forEach(function(control) { + is(control.checked, checked, + control.getAttribute("id") + " should " + (checked ? "not " : "") + "be checked"); + }); + } + + // controls should be checked in remember mode + historymode.value = "remember"; + controlChanged(historymode); + expect_checked(true); + + // even if they're unchecked in custom mode + historymode.value = "custom"; + controlChanged(historymode); + controls.forEach(function(control) { + control.checked = false; + controlChanged(control); + }); + expect_checked(false); + historymode.value = "remember"; + controlChanged(historymode); + expect_checked(true); +} + +function test_historymode_retention(mode, expect) { + return function(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + + if ((historymode.value == "remember" && mode == "dontremember") || + (historymode.value == "dontremember" && mode == "remember") || + (historymode.value == "custom" && mode == "dontremember")) { + return; + } + + if (expect !== undefined) { + is(historymode.value, expect, + "history mode is expected to remain " + expect); + } + + historymode.value = mode; + controlChanged(historymode); + }; +} + +function test_custom_retention(controlToChange, expect, valueIncrement) { + return function(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + + if (expect !== undefined) { + is(historymode.value, expect, + "history mode is expected to remain " + expect); + } + + historymode.value = "custom"; + controlChanged(historymode); + + controlToChange = win.document.getElementById(controlToChange); + ok(controlToChange, "the control to change should exist"); + switch (controlToChange.localName) { + case "checkbox": + controlToChange.checked = !controlToChange.checked; + break; + case "textbox": + controlToChange.value = parseInt(controlToChange.value) + valueIncrement; + break; + case "menulist": + controlToChange.value = valueIncrement; + break; + } + controlChanged(controlToChange); + }; +} + +function test_locbar_suggestion_retention(mode, expect) { + return function(win) { + let locbarsuggest = win.document.getElementById("locationBarSuggestion"); + ok(locbarsuggest, "location bar suggestion menulist should exist"); + + if (expect !== undefined) { + is(locbarsuggest.value, expect, + "location bar suggestion is expected to remain " + expect); + } + + locbarsuggest.value = mode; + controlChanged(locbarsuggest); + }; +} + +function reset_preferences(win) { + let prefs = win.document.querySelectorAll("#privacyPreferences > preference"); + for (let i = 0; i < prefs.length; ++i) + if (prefs[i].hasUserValue) + prefs[i].reset(); +} + +let testRunner; +function run_test_subset(subset) { + Services.prefs.setBoolPref("browser.preferences.instantApply", true); + + waitForExplicitFinish(); + registerCleanupFunction(function() { + // Reset pref to its default + Services.prefs.clearUserPref("browser.preferences.instantApply"); + }); + + testRunner = { + tests: subset, + counter: 0, + runNext: function() { + if (this.counter == this.tests.length) { + finish(); + } else { + let self = this; + setTimeout(function() { + runTestOnPrivacyPrefPane(self.tests[self.counter++]); + }, 0); + } + } + }; + + testRunner.runNext(); +} diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js index 35e3e3313ce..0014a1651cb 100644 --- a/browser/components/preferences/privacy.js +++ b/browser/components/preferences/privacy.js @@ -12,6 +12,11 @@ var gPrivacyPane = { */ _autoStartPrivateBrowsing: false, + /** + * Whether the prompt to restart Firefox should appear when changing the autostart pref. + */ + _shouldPromptForRestart: true, + /** * Sets up the UI for the number of days of history to keep, and updates the * label of the "Clear Now..." button. @@ -130,7 +135,8 @@ var gPrivacyPane = { let pref = document.getElementById("browser.privatebrowsing.autostart"); switch (document.getElementById("historyMode").value) { case "remember": - pref.value = false; + if (pref.value) + pref.value = false; // select the remember history option if needed let rememberHistoryCheckbox = document.getElementById("rememberHistory"); @@ -149,7 +155,8 @@ var gPrivacyPane = { document.getElementById("privacy.sanitize.sanitizeOnShutdown").value = false; break; case "dontremember": - pref.value = true; + if (!pref.value) + pref.value = true; break; } }, @@ -222,12 +229,54 @@ var gPrivacyPane = { observe: function PPP_observe(aSubject, aTopic, aData) { +#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING + if (!gPrivacyPane._shouldPromptForRestart) { + // We're performing a revert. Just let it happen. + gPrivacyPane._shouldPromptForRestart = true; + return; + } + + const Cc = Components.classes, Ci = Components.interfaces; + let pref = document.getElementById("browser.privatebrowsing.autostart"); + let brandName = document.getElementById("bundleBrand").getString("brandShortName"); + let bundle = document.getElementById("bundlePreferences"); + let msg = bundle.getFormattedString(pref.value ? + "featureEnableRequiresRestart" : "featureDisableRequiresRestart", + [brandName]); + let title = bundle.getFormattedString("shouldRestartTitle", [brandName]); + let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService); + let shouldProceed = prompts.confirm(window, title, msg) + if (shouldProceed) { + let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"] + .createInstance(Ci.nsISupportsPRBool); + Services.obs.notifyObservers(cancelQuit, "quit-application-requested", + "restart"); + shouldProceed = !cancelQuit.data; + + if (shouldProceed) { + let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] + .getService(Ci.nsIAppStartup); + appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart); + return; + } + } + gPrivacyPane._shouldPromptForRestart = false; + pref.value = !pref.value; + + let mode = document.getElementById("historyMode"); + if (mode.value != "custom") { + mode.selectedIndex = pref.value ? 1 : 0; + mode.doCommand(); + } else { + let rememberHistoryCheckbox = document.getElementById("rememberHistory"); + rememberHistory.checked = pref.value; + } +#else // Toggle the private browsing mode without switching the session let prefValue = document.getElementById("browser.privatebrowsing.autostart").value; let keepCurrentSession = document.getElementById("browser.privatebrowsing.keep_current_session"); keepCurrentSession.value = true; -#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"]. getService(Components.interfaces.nsIPrivateBrowsingService); @@ -236,9 +285,9 @@ var gPrivacyPane = { if (prefValue && privateBrowsingService.privateBrowsingEnabled) privateBrowsingService.privateBrowsingEnabled = false; privateBrowsingService.privateBrowsingEnabled = prefValue; -#endif keepCurrentSession.reset(); +#endif } }, diff --git a/browser/components/preferences/tests/Makefile.in b/browser/components/preferences/tests/Makefile.in index d939b4d9500..d8a30b72fee 100644 --- a/browser/components/preferences/tests/Makefile.in +++ b/browser/components/preferences/tests/Makefile.in @@ -14,23 +14,32 @@ include $(topsrcdir)/config/rules.mk _BROWSER_FILES = \ browser_advanced_update.js \ browser_bug410900.js \ - browser_bug567487.js \ browser_bug705422.js \ - privacypane_tests.js \ - browser_privacypane_1.js \ - browser_privacypane_2.js \ - browser_privacypane_3.js \ - browser_privacypane_4.js \ - browser_privacypane_5.js \ - browser_privacypane_8.js \ browser_permissions.js \ browser_chunk_permissions.js \ $(NULL) ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING _BROWSER_FILES += \ + privacypane_tests.js \ + browser_bug567487.js \ + browser_privacypane_1.js \ + browser_privacypane_2.js \ + browser_privacypane_3.js \ + browser_privacypane_4.js \ + browser_privacypane_5.js \ browser_privacypane_6.js \ browser_privacypane_7.js \ + browser_privacypane_8.js \ + $(NULL) +else +_BROWSER_FILES += \ + privacypane_tests_perwindow.js \ + browser_privacypane_1.js \ + browser_privacypane_3.js \ + browser_privacypane_4.js \ + browser_privacypane_5.js \ + browser_privacypane_8.js \ $(NULL) endif diff --git a/browser/components/preferences/tests/browser_privacypane_1.js b/browser/components/preferences/tests/browser_privacypane_1.js index a8dbe330d0c..cb114382b60 100644 --- a/browser/components/preferences/tests/browser_privacypane_1.js +++ b/browser/components/preferences/tests/browser_privacypane_1.js @@ -12,7 +12,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_pane_visibility, diff --git a/browser/components/preferences/tests/browser_privacypane_2.js b/browser/components/preferences/tests/browser_privacypane_2.js index 66f503966c7..73e74ddd814 100644 --- a/browser/components/preferences/tests/browser_privacypane_2.js +++ b/browser/components/preferences/tests/browser_privacypane_2.js @@ -12,7 +12,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_historymode_retention("remember", undefined), diff --git a/browser/components/preferences/tests/browser_privacypane_3.js b/browser/components/preferences/tests/browser_privacypane_3.js index 6875a2dfc38..21cfa713f1c 100644 --- a/browser/components/preferences/tests/browser_privacypane_3.js +++ b/browser/components/preferences/tests/browser_privacypane_3.js @@ -11,7 +11,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_custom_retention("rememberHistory", "remember"), diff --git a/browser/components/preferences/tests/browser_privacypane_4.js b/browser/components/preferences/tests/browser_privacypane_4.js index bb2f3b9a733..372ea865469 100644 --- a/browser/components/preferences/tests/browser_privacypane_4.js +++ b/browser/components/preferences/tests/browser_privacypane_4.js @@ -11,7 +11,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_custom_retention("acceptCookies", "remember"), diff --git a/browser/components/preferences/tests/browser_privacypane_5.js b/browser/components/preferences/tests/browser_privacypane_5.js index 27169c7cc78..778a3b70fb0 100644 --- a/browser/components/preferences/tests/browser_privacypane_5.js +++ b/browser/components/preferences/tests/browser_privacypane_5.js @@ -11,7 +11,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_locbar_suggestion_retention(-1, undefined), diff --git a/browser/components/preferences/tests/browser_privacypane_6.js b/browser/components/preferences/tests/browser_privacypane_6.js index 44c1d76da08..0d7df5a98bb 100644 --- a/browser/components/preferences/tests/browser_privacypane_6.js +++ b/browser/components/preferences/tests/browser_privacypane_6.js @@ -11,7 +11,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_privatebrowsing_toggle, diff --git a/browser/components/preferences/tests/browser_privacypane_7.js b/browser/components/preferences/tests/browser_privacypane_7.js index a0e764ed7fa..34c3550a964 100644 --- a/browser/components/preferences/tests/browser_privacypane_7.js +++ b/browser/components/preferences/tests/browser_privacypane_7.js @@ -11,7 +11,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ test_privatebrowsing_ui, diff --git a/browser/components/preferences/tests/browser_privacypane_8.js b/browser/components/preferences/tests/browser_privacypane_8.js index 9e39c8bccdf..91ce7017580 100644 --- a/browser/components/preferences/tests/browser_privacypane_8.js +++ b/browser/components/preferences/tests/browser_privacypane_8.js @@ -11,7 +11,11 @@ function test() { let tmpdir = extractJarToTmp(jar); rootDir = "file://" + tmpdir.path + '/'; } - loader.loadSubScript(rootDir + "privacypane_tests.js", this); + try { + loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this); + } catch(x) { + loader.loadSubScript(rootDir + "privacypane_tests.js", this); + } run_test_subset([ // history mode should be initialized to remember diff --git a/browser/components/preferences/tests/privacypane_tests_perwindow.js b/browser/components/preferences/tests/privacypane_tests_perwindow.js new file mode 100644 index 00000000000..a07800e3725 --- /dev/null +++ b/browser/components/preferences/tests/privacypane_tests_perwindow.js @@ -0,0 +1,352 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function runTestOnPrivacyPrefPane(testFunc) { + let observer = { + observe: function(aSubject, aTopic, aData) { + if (aTopic == "domwindowopened") { + Services.ww.unregisterNotification(this); + + let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget); + win.addEventListener("load", function() { + win.removeEventListener("load", arguments.callee, false); + testFunc(dialog.document.defaultView); + + Services.ww.registerNotification(observer); + dialog.close(); + }, false); + } else if (aTopic == "domwindowclosed") { + Services.ww.unregisterNotification(this); + testRunner.runNext(); + } + } + }; + Services.ww.registerNotification(observer); + + let dialog = openDialog("chrome://browser/content/preferences/preferences.xul", "Preferences", + "chrome,titlebar,toolbar,centerscreen,dialog=no", "panePrivacy"); +} + +function controlChanged(element) { + element.doCommand(); +} + +// We can only test the panes that don't trigger a preference update +function test_pane_visibility(win) { + let modes = { + "remember": "historyRememberPane", + "custom": "historyCustomPane" + }; + + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let historypane = win.document.getElementById("historyPane"); + ok(historypane, "history mode pane should exist"); + + for (let mode in modes) { + historymode.value = mode; + controlChanged(historymode); + is(historypane.selectedPanel, win.document.getElementById(modes[mode]), + "The correct pane should be selected for the " + mode + " mode"); + } +} + +function test_dependent_elements(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let pbautostart = win.document.getElementById("privateBrowsingAutoStart"); + ok(pbautostart, "the private browsing auto-start checkbox should exist"); + let controls = [ + win.document.getElementById("rememberHistory"), + win.document.getElementById("rememberForms"), + win.document.getElementById("keepUntil"), + win.document.getElementById("keepCookiesUntil"), + win.document.getElementById("alwaysClear"), + ]; + controls.forEach(function(control) { + ok(control, "the dependent controls should exist"); + }); + let independents = [ + win.document.getElementById("acceptCookies"), + win.document.getElementById("acceptThirdParty"), + ]; + independents.forEach(function(control) { + ok(control, "the independent controls should exist"); + }); + let cookieexceptions = win.document.getElementById("cookieExceptions"); + ok(cookieexceptions, "the cookie exceptions button should exist"); + let keepuntil = win.document.getElementById("keepCookiesUntil"); + ok(keepuntil, "the keep cookies until menulist should exist"); + let alwaysclear = win.document.getElementById("alwaysClear"); + ok(alwaysclear, "the clear data on close checkbox should exist"); + let rememberhistory = win.document.getElementById("rememberHistory"); + ok(rememberhistory, "the remember history checkbox should exist"); + let rememberforms = win.document.getElementById("rememberForms"); + ok(rememberforms, "the remember forms checkbox should exist"); + let alwaysclearsettings = win.document.getElementById("clearDataSettings"); + ok(alwaysclearsettings, "the clear data settings button should exist"); + + function expect_disabled(disabled) { + controls.forEach(function(control) { + is(control.disabled, disabled, + control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled"); + }); + is(keepuntil.value, disabled ? 2 : 0, + "the keep cookies until menulist value should be as expected"); + if (disabled) { + ok(!alwaysclear.checked, + "the clear data on close checkbox value should be as expected"); + ok(!rememberhistory.checked, + "the remember history checkbox value should be as expected"); + ok(!rememberforms.checked, + "the remember forms checkbox value should be as expected"); + } + } + function check_independents(expected) { + independents.forEach(function(control) { + is(control.disabled, expected, + control.getAttribute("id") + " should " + (expected ? "" : "not ") + "be disabled"); + }); + ok(!cookieexceptions.disabled, + "the cookie exceptions button should never be disabled"); + ok(alwaysclearsettings.disabled, + "the clear data settings button should always be disabled"); + } + + // controls should only change in custom mode + historymode.value = "remember"; + controlChanged(historymode); + expect_disabled(false); + check_independents(false); + + // setting the mode to custom shouldn't change anything + historymode.value = "custom"; + controlChanged(historymode); + expect_disabled(false); + check_independents(false); +} + +function test_dependent_cookie_elements(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let pbautostart = win.document.getElementById("privateBrowsingAutoStart"); + ok(pbautostart, "the private browsing auto-start checkbox should exist"); + let controls = [ + win.document.getElementById("acceptThirdParty"), + win.document.getElementById("keepUntil"), + win.document.getElementById("keepCookiesUntil"), + ]; + controls.forEach(function(control) { + ok(control, "the dependent cookie controls should exist"); + }); + let acceptcookies = win.document.getElementById("acceptCookies"); + ok(acceptcookies, "the accept cookies checkbox should exist"); + + function expect_disabled(disabled) { + controls.forEach(function(control) { + is(control.disabled, disabled, + control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled"); + }); + } + + historymode.value = "custom"; + controlChanged(historymode); + pbautostart.checked = false; + controlChanged(pbautostart); + expect_disabled(false); + + acceptcookies.checked = false; + controlChanged(acceptcookies); + expect_disabled(true); + + acceptcookies.checked = true; + controlChanged(acceptcookies); + expect_disabled(false); + + let accessthirdparty = controls.shift(); + acceptcookies.checked = false; + controlChanged(acceptcookies); + expect_disabled(true); + ok(accessthirdparty.disabled, "access third party button should be disabled"); + + pbautostart.checked = false; + controlChanged(pbautostart); + expect_disabled(true); + ok(accessthirdparty.disabled, "access third party button should be disabled"); + + acceptcookies.checked = true; + controlChanged(acceptcookies); + expect_disabled(false); + ok(!accessthirdparty.disabled, "access third party button should be enabled"); +} + +function test_dependent_clearonclose_elements(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let pbautostart = win.document.getElementById("privateBrowsingAutoStart"); + ok(pbautostart, "the private browsing auto-start checkbox should exist"); + let alwaysclear = win.document.getElementById("alwaysClear"); + ok(alwaysclear, "the clear data on close checkbox should exist"); + let alwaysclearsettings = win.document.getElementById("clearDataSettings"); + ok(alwaysclearsettings, "the clear data settings button should exist"); + + function expect_disabled(disabled) { + is(alwaysclearsettings.disabled, disabled, + "the clear data settings should " + (disabled ? "" : "not ") + "be disabled"); + } + + historymode.value = "custom"; + controlChanged(historymode); + pbautostart.checked = false; + controlChanged(pbautostart); + alwaysclear.checked = false; + controlChanged(alwaysclear); + expect_disabled(true); + + alwaysclear.checked = true; + controlChanged(alwaysclear); + expect_disabled(false); + + alwaysclear.checked = false; + controlChanged(alwaysclear); + expect_disabled(true); +} + +function test_dependent_prefs(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + let controls = [ + win.document.getElementById("rememberHistory"), + win.document.getElementById("rememberForms"), + win.document.getElementById("acceptCookies"), + win.document.getElementById("acceptThirdParty"), + ]; + controls.forEach(function(control) { + ok(control, "the micro-management controls should exist"); + }); + + function expect_checked(checked) { + controls.forEach(function(control) { + is(control.checked, checked, + control.getAttribute("id") + " should " + (checked ? "not " : "") + "be checked"); + }); + } + + // controls should be checked in remember mode + historymode.value = "remember"; + controlChanged(historymode); + expect_checked(true); + + // even if they're unchecked in custom mode + historymode.value = "custom"; + controlChanged(historymode); + controls.forEach(function(control) { + control.checked = false; + controlChanged(control); + }); + expect_checked(false); + historymode.value = "remember"; + controlChanged(historymode); + expect_checked(true); +} + +function test_historymode_retention(mode, expect) { + return function(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + + if ((historymode.value == "remember" && mode == "dontremember") || + (historymode.value == "dontremember" && mode == "remember") || + (historymode.value == "custom" && mode == "dontremember")) { + return; + } + + if (expect !== undefined) { + is(historymode.value, expect, + "history mode is expected to remain " + expect); + } + + historymode.value = mode; + controlChanged(historymode); + }; +} + +function test_custom_retention(controlToChange, expect, valueIncrement) { + return function(win) { + let historymode = win.document.getElementById("historyMode"); + ok(historymode, "history mode menulist should exist"); + + if (expect !== undefined) { + is(historymode.value, expect, + "history mode is expected to remain " + expect); + } + + historymode.value = "custom"; + controlChanged(historymode); + + controlToChange = win.document.getElementById(controlToChange); + ok(controlToChange, "the control to change should exist"); + switch (controlToChange.localName) { + case "checkbox": + controlToChange.checked = !controlToChange.checked; + break; + case "textbox": + controlToChange.value = parseInt(controlToChange.value) + valueIncrement; + break; + case "menulist": + controlToChange.value = valueIncrement; + break; + } + controlChanged(controlToChange); + }; +} + +function test_locbar_suggestion_retention(mode, expect) { + return function(win) { + let locbarsuggest = win.document.getElementById("locationBarSuggestion"); + ok(locbarsuggest, "location bar suggestion menulist should exist"); + + if (expect !== undefined) { + is(locbarsuggest.value, expect, + "location bar suggestion is expected to remain " + expect); + } + + locbarsuggest.value = mode; + controlChanged(locbarsuggest); + }; +} + +function reset_preferences(win) { + let prefs = win.document.getElementsByTagName("preference"); + for (let i = 0; i < prefs.length; ++i) + if (prefs[i].hasUserValue) + prefs[i].reset(); +} + +let testRunner; +function run_test_subset(subset) { + let instantApplyOrig = Services.prefs.getBoolPref("browser.preferences.instantApply"); + Services.prefs.setBoolPref("browser.preferences.instantApply", true); + + waitForExplicitFinish(); + + testRunner = { + tests: subset, + counter: 0, + runNext: function() { + if (this.counter == this.tests.length) { + // cleanup + Services.prefs.setBoolPref("browser.preferences.instantApply", instantApplyOrig); + finish(); + } else { + let self = this; + setTimeout(function() { + runTestOnPrivacyPrefPane(self.tests[self.counter++]); + }, 0); + } + } + }; + + testRunner.runNext(); +} diff --git a/browser/locales/en-US/chrome/browser/preferences/preferences.properties b/browser/locales/en-US/chrome/browser/preferences/preferences.properties index b9e0663211d..1066a46fe20 100644 --- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties +++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties @@ -126,3 +126,8 @@ actualAppCacheSize=Your application cache is currently using %1$S %2$S of disk s syncUnlink.title=Do you want to unlink your device? syncUnlink.label=This device will no longer be associated with your Sync account. All of your personal data, both on this device and in your Sync account, will remain intact. syncUnlinkConfirm.label=Unlink + +# LOCALIZATION NOTE (featureEnableRequiresRestart, featureDisableRequiresRestart, restartTitle): %S = brandShortName +featureEnableRequiresRestart=%S must restart to enable this feature. +featureDisableRequiresRestart=%S must restart to disable this feature. +shouldRestartTitle=Restart %S \ No newline at end of file diff --git a/toolkit/content/PrivateBrowsingUtils.jsm b/toolkit/content/PrivateBrowsingUtils.jsm index 1d524edbcd3..edad45dc93f 100644 --- a/toolkit/content/PrivateBrowsingUtils.jsm +++ b/toolkit/content/PrivateBrowsingUtils.jsm @@ -50,19 +50,3 @@ this.PrivateBrowsingUtils = { } }; -#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING -function autoStartObserver(aSubject, aTopic, aData) { - var newValue = Services.prefs.getBoolPref(kAutoStartPref); - var windowsEnum = Services.wm.getEnumerator(null); - while (windowsEnum.hasMoreElements()) { - var window = windowsEnum.getNext(); - window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsILoadContext) - .usePrivateBrowsing = newValue; - } -} - -Services.prefs.addObserver(kAutoStartPref, autoStartObserver, false); -#endif -