зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to graphics
MozReview-Commit-ID: 1rTRVEHequ9
This commit is contained in:
Коммит
0fee7584e7
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1346967 - Generate metadata for all three ISimpleDOM interfaces via a single combined run of MIDL
|
||||
Bug 1343682 - backing out a previous version didn't stop the failures from it, so it appears to need a clobber both out and in
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
#include "mozilla/AppUnits.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
|
@ -652,28 +648,14 @@ TextAttrsMgr::FontWeightTextAttr::
|
|||
if (font->IsSyntheticBold())
|
||||
return 700;
|
||||
|
||||
bool useFontEntryWeight = true;
|
||||
|
||||
// Under Linux, when gfxPangoFontGroup code is used,
|
||||
// font->GetStyle()->weight will give the absolute weight requested of the
|
||||
// font face. The gfxPangoFontGroup code uses the gfxFontEntry constructor
|
||||
// which doesn't initialize the weight field.
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
useFontEntryWeight = gfxPlatformGtk::UseFcFontList();
|
||||
#endif
|
||||
|
||||
if (useFontEntryWeight) {
|
||||
// On Windows, font->GetStyle()->weight will give the same weight as
|
||||
// fontEntry->Weight(), the weight of the first font in the font group,
|
||||
// which may not be the weight of the font face used to render the
|
||||
// characters. On Mac, font->GetStyle()->weight will just give the same
|
||||
// number as getComputedStyle(). fontEntry->Weight() will give the weight
|
||||
// of the font face used.
|
||||
gfxFontEntry *fontEntry = font->GetFontEntry();
|
||||
return fontEntry->Weight();
|
||||
} else {
|
||||
return font->GetStyle()->weight;
|
||||
}
|
||||
// On Windows, font->GetStyle()->weight will give the same weight as
|
||||
// fontEntry->Weight(), the weight of the first font in the font group,
|
||||
// which may not be the weight of the font face used to render the
|
||||
// characters. On Mac, font->GetStyle()->weight will just give the same
|
||||
// number as getComputedStyle(). fontEntry->Weight() will give the weight
|
||||
// of the font face used.
|
||||
gfxFontEntry *fontEntry = font->GetFontEntry();
|
||||
return fontEntry->Weight();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -595,6 +595,7 @@ nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
|
|||
}
|
||||
|
||||
if (child) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(child->Parent(), "Unattached accessible from tree");
|
||||
document->ContentRemoved(child->Parent(), aChildNode);
|
||||
#ifdef A11Y_LOG
|
||||
if (logging::IsEnabled(logging::eTree))
|
||||
|
|
|
@ -8,7 +8,7 @@ module.exports = {
|
|||
"rules": {
|
||||
// XXX Bug 1326071 - This should be reduced down - probably to 20 or to
|
||||
// be removed & synced with the mozilla/recommended value.
|
||||
"complexity": ["error", {"max": 40}],
|
||||
"complexity": ["error", {"max": 42}],
|
||||
|
||||
"no-shadow": "error",
|
||||
}
|
||||
|
|
|
@ -2180,6 +2180,11 @@
|
|||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="23.0.0.205" minVersion="23.0.0.185" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="26c2a4e2-9aff-4ab1-b654-20e478b375f0" os="Linux">
|
||||
<match exp="libflashplayer\.so" name="filename"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="24.0.0.221" minVersion="24.0.0.194" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p248">
|
||||
<match exp="Scorch\.plugin" name="filename"/>
|
||||
<versionRange maxVersion="6.2.0b88" minVersion="0" severity="1"/>
|
||||
|
@ -2206,6 +2211,11 @@
|
|||
<pluginItem blockID="p31">
|
||||
<match exp="NPMySrch.dll" name="filename"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="2b608fae-1750-4a06-a142-0bc9ba17a7d0">
|
||||
<match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="24.0.0.221" minVersion="24.0.0.194" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1020">
|
||||
<match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
|
|
|
@ -38,6 +38,7 @@ pref("extensions.minCompatibleAppVersion", "4.0");
|
|||
pref("extensions.checkCompatibility.temporaryThemeOverride_minAppVersion", "29.0a1");
|
||||
|
||||
pref("xpinstall.customConfirmationUI", true);
|
||||
pref("extensions.webextPermissionPrompts", true);
|
||||
|
||||
// Preferences for AMO integration
|
||||
pref("extensions.getAddons.cache.enabled", true);
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
panel.style.display = "block";
|
||||
document.getElementById("netErrorButtonContainer").style.display = "none";
|
||||
document.getElementById("prefResetButton").addEventListener("click", function resetPreferences(e) {
|
||||
const event = new CustomEvent("AboutNetErrorResetPreferences", {bubbles:true});
|
||||
const event = new CustomEvent("AboutNetErrorResetPreferences", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
addAutofocus("prefResetButton", "beforeend");
|
||||
|
@ -127,7 +127,7 @@
|
|||
|
||||
if (panel.style.display == "block") {
|
||||
// send event to trigger telemetry ping
|
||||
var event = new CustomEvent("AboutNetErrorUIExpanded", {bubbles:true});
|
||||
var event = new CustomEvent("AboutNetErrorUIExpanded", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
});
|
||||
|
@ -292,7 +292,7 @@
|
|||
}
|
||||
}, true, true);
|
||||
|
||||
var event = new CustomEvent("AboutNetErrorLoad", {bubbles:true});
|
||||
var event = new CustomEvent("AboutNetErrorLoad", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
|
||||
if (err == "inadequateSecurityError") {
|
||||
|
@ -315,7 +315,7 @@
|
|||
|
||||
document.getElementById("openPortalLoginPageButton")
|
||||
.addEventListener("click", () => {
|
||||
let event = new CustomEvent("AboutNetErrorOpenCaptivePortal", {bubbles:true});
|
||||
let event = new CustomEvent("AboutNetErrorOpenCaptivePortal", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
|
||||
|
@ -362,7 +362,7 @@
|
|||
}
|
||||
}, true, true);
|
||||
|
||||
let event = new CustomEvent("AboutNetErrorLoad", {bubbles:true});
|
||||
let event = new CustomEvent("AboutNetErrorLoad", {bubbles: true});
|
||||
document.getElementById("advancedButton").dispatchEvent(event);
|
||||
|
||||
addDomainErrorLinks();
|
||||
|
|
|
@ -105,7 +105,7 @@ var AboutTabCrashed = {
|
|||
document.getElementById("email").addEventListener("input", this);
|
||||
|
||||
// Error pages are loaded as LOAD_BACKGROUND, so they don't get load events.
|
||||
let event = new CustomEvent("AboutTabCrashedLoad", {bubbles:true});
|
||||
let event = new CustomEvent("AboutTabCrashedLoad", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
|
||||
sendAsyncMessage("Load");
|
||||
|
@ -202,7 +202,7 @@ var AboutTabCrashed = {
|
|||
document.getElementById("requestAutoSubmit").hidden = false;
|
||||
}
|
||||
|
||||
let event = new CustomEvent("AboutTabCrashedReady", {bubbles:true});
|
||||
let event = new CustomEvent("AboutTabCrashedReady", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
},
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ window.addEventListener("pageshow", function() {
|
|||
window.addEventListener("resize", fitToWidth);
|
||||
|
||||
// Ask chrome to update snippets.
|
||||
var event = new CustomEvent("AboutHomeLoad", {bubbles:true});
|
||||
var event = new CustomEvent("AboutHomeLoad", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
|
||||
|
@ -241,7 +241,7 @@ function setupSearch() {
|
|||
* Inform the test harness that we're done loading the page.
|
||||
*/
|
||||
function loadCompleted() {
|
||||
var event = new CustomEvent("AboutHomeLoadSnippetsCompleted", {bubbles:true});
|
||||
var event = new CustomEvent("AboutHomeLoadSnippetsCompleted", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ function loadSnippets() {
|
|||
throw new Error("Snippets map has not properly been initialized");
|
||||
|
||||
// Allow tests to modify the snippets map before using it.
|
||||
var event = new CustomEvent("AboutHomeLoadSnippets", {bubbles:true});
|
||||
var event = new CustomEvent("AboutHomeLoadSnippets", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
|
||||
// Check cached snippets version.
|
||||
|
|
|
@ -135,7 +135,7 @@
|
|||
}
|
||||
|
||||
// Inform the test harness that we're done loading the page
|
||||
var event = new CustomEvent("AboutBlockedLoaded", {bubbles:true});
|
||||
var event = new CustomEvent("AboutBlockedLoaded", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
]]></script>
|
||||
|
|
|
@ -798,13 +798,13 @@ var gPopupBlockerObserver = {
|
|||
} catch (e) { }
|
||||
|
||||
var bundlePreferences = document.getElementById("bundle_preferences");
|
||||
var params = { blockVisible : false,
|
||||
sessionVisible : false,
|
||||
allowVisible : true,
|
||||
prefilledHost : prefillValue,
|
||||
permissionType : "popup",
|
||||
windowTitle : bundlePreferences.getString("popuppermissionstitle"),
|
||||
introText : bundlePreferences.getString("popuppermissionstext") };
|
||||
var params = { blockVisible: false,
|
||||
sessionVisible: false,
|
||||
allowVisible: true,
|
||||
prefilledHost: prefillValue,
|
||||
permissionType: "popup",
|
||||
windowTitle: bundlePreferences.getString("popuppermissionstitle"),
|
||||
introText: bundlePreferences.getString("popuppermissionstext") };
|
||||
var existingWindow = Services.wm.getMostRecentWindow("Browser:Permissions");
|
||||
if (existingWindow) {
|
||||
existingWindow.initWithParams(params);
|
||||
|
@ -3056,7 +3056,7 @@ var BrowserOnClick = {
|
|||
securityInfo = getSecurityInfo(securityInfoAsString);
|
||||
let sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider)
|
||||
.SSLStatus;
|
||||
let params = { exceptionAdded : false,
|
||||
let params = { exceptionAdded: false,
|
||||
sslStatus };
|
||||
|
||||
try {
|
||||
|
@ -3611,7 +3611,7 @@ function openHomeDialog(aURL) {
|
|||
|
||||
var pressedVal = Services.prompt.confirmEx(window, promptTitle, promptMsg,
|
||||
Services.prompt.STD_YES_NO_BUTTONS,
|
||||
null, null, null, null, {value:0});
|
||||
null, null, null, null, {value: 0});
|
||||
|
||||
if (pressedVal == 0) {
|
||||
try {
|
||||
|
@ -6232,7 +6232,7 @@ var OfflineApps = {
|
|||
let options = {
|
||||
persistent: true,
|
||||
hideClose: true,
|
||||
controlledItems : [[Cu.getWeakReference(browser), docId, uri]]
|
||||
controlledItems: [[Cu.getWeakReference(browser), docId, uri]]
|
||||
};
|
||||
notification = PopupNotifications.show(browser, notificationID, message,
|
||||
anchorID, mainAction,
|
||||
|
|
|
@ -1258,8 +1258,10 @@ var PageInfoListener = {
|
|||
try {
|
||||
// Note: makeURLAbsolute will throw if either the baseURI is not a valid URI
|
||||
// or the URI formed from the baseURI and the URL is not a valid URI.
|
||||
let href = makeURLAbsolute(elem.baseURI, elem.href.baseVal);
|
||||
addImage(href, strings.mediaImg, "", elem, false);
|
||||
if (elem.href.baseVal) {
|
||||
let href = Services.io.newURI(elem.href.baseVal, null, Services.io.newURI(elem.baseURI)).spec;
|
||||
addImage(href, strings.mediaImg, "", elem, false);
|
||||
}
|
||||
} catch (e) { }
|
||||
} else if (elem instanceof content.HTMLVideoElement) {
|
||||
addImage(elem.currentSrc, strings.mediaVideo, "", elem, false);
|
||||
|
|
|
@ -1002,12 +1002,9 @@ function formatDate(datestr, unknown) {
|
|||
if (!date.valueOf())
|
||||
return unknown;
|
||||
|
||||
const locale = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Components.interfaces.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global", true);
|
||||
const dtOptions = { year: "numeric", month: "long", day: "numeric",
|
||||
hour: "numeric", minute: "numeric", second: "numeric" };
|
||||
return date.toLocaleString(locale, dtOptions);
|
||||
return date.toLocaleString(undefined, dtOptions);
|
||||
}
|
||||
|
||||
function doCopy() {
|
||||
|
|
|
@ -218,7 +218,8 @@ function onIndexedDBUsageCallback(request) {
|
|||
throw new Error("Callback received for bad URI: " + uri);
|
||||
}
|
||||
|
||||
if (request.usage) {
|
||||
let usage = request.result.usage;
|
||||
if (usage) {
|
||||
if (!("DownloadUtils" in window)) {
|
||||
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
}
|
||||
|
@ -228,7 +229,7 @@ function onIndexedDBUsageCallback(request) {
|
|||
|
||||
status.value =
|
||||
gBundle.getFormattedString("indexedDBUsage",
|
||||
DownloadUtils.convertByteUnits(request.usage));
|
||||
DownloadUtils.convertByteUnits(usage));
|
||||
status.removeAttribute("hidden");
|
||||
button.removeAttribute("hidden");
|
||||
}
|
||||
|
|
|
@ -55,15 +55,15 @@ var security = {
|
|||
|
||||
var retval = {
|
||||
hostName,
|
||||
cAName : issuerName,
|
||||
encryptionAlgorithm : undefined,
|
||||
encryptionStrength : undefined,
|
||||
cAName: issuerName,
|
||||
encryptionAlgorithm: undefined,
|
||||
encryptionStrength: undefined,
|
||||
version: undefined,
|
||||
isBroken,
|
||||
isMixed,
|
||||
isEV,
|
||||
cert,
|
||||
certificateTransparency : undefined
|
||||
certificateTransparency: undefined
|
||||
};
|
||||
|
||||
var version;
|
||||
|
@ -111,15 +111,15 @@ var security = {
|
|||
}
|
||||
return {
|
||||
hostName,
|
||||
cAName : "",
|
||||
encryptionAlgorithm : "",
|
||||
encryptionStrength : 0,
|
||||
cAName: "",
|
||||
encryptionAlgorithm: "",
|
||||
encryptionStrength: 0,
|
||||
version: "",
|
||||
isBroken,
|
||||
isMixed,
|
||||
isEV,
|
||||
cert : null,
|
||||
certificateTransparency : null
|
||||
cert: null,
|
||||
certificateTransparency: null
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -165,7 +165,7 @@ var security = {
|
|||
win.focus();
|
||||
} else
|
||||
window.openDialog("chrome://browser/content/preferences/cookies.xul",
|
||||
"Browser:Cookies", "", {filterString : eTLD});
|
||||
"Browser:Cookies", "", {filterString: eTLD});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -175,7 +175,7 @@ var security = {
|
|||
LoginHelper.openPasswordManager(window, this._getSecurityInfo().hostName);
|
||||
},
|
||||
|
||||
_cert : null
|
||||
_cert: null
|
||||
};
|
||||
|
||||
function securityOnLoad(uri, windowInfo) {
|
||||
|
|
|
@ -189,8 +189,8 @@ Sanitizer.prototype = {
|
|||
// and can optionally specify a specific range. If timespan is not ignored,
|
||||
// and range is not set, sanitize() will use the value of the timespan
|
||||
// pref to determine a range
|
||||
ignoreTimespan : true,
|
||||
range : null,
|
||||
ignoreTimespan: true,
|
||||
range: null,
|
||||
|
||||
items: {
|
||||
cache: {
|
||||
|
|
|
@ -68,9 +68,6 @@
|
|||
Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
|
||||
.getService(Components.interfaces.mozIPlacesAutoComplete);
|
||||
</field>
|
||||
<field name="AppConstants" readonly="true">
|
||||
(Components.utils.import("resource://gre/modules/AppConstants.jsm", {})).AppConstants;
|
||||
</field>
|
||||
<field name="mTabBox" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "tabbox");
|
||||
</field>
|
||||
|
@ -108,7 +105,7 @@
|
|||
new Map();
|
||||
</field>
|
||||
<field name="arrowKeysShouldWrap" readonly="true">
|
||||
this.AppConstants.platform == "macosx";
|
||||
AppConstants == "macosx";
|
||||
</field>
|
||||
|
||||
<field name="_autoScrollPopup">
|
||||
|
@ -2555,6 +2552,23 @@
|
|||
<parameter name="aParams"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// We collect Telemetry on how long it takes to close a tab.
|
||||
// Sometimes, tabs animate closed, and sometimes they don't, and
|
||||
// it doesn't really make sense to put timings for both cases in the
|
||||
// same bucket.
|
||||
//
|
||||
// We decide later on whether or not we're actually going to animate
|
||||
// the tab closed. In order to capture as much of the time we care
|
||||
// about with these stopwatches, but also in order to avoid any
|
||||
// unnecessary work (since calculating whether or not we're going
|
||||
// to do the animation might involved a style flush), we start
|
||||
// stopwatches for both the animating and non-animating case. When
|
||||
// we decide that we're animating, we cancel the non-animating case,
|
||||
// and vice-versa. Then, in _endRemoveTab, we "finish" both
|
||||
// stopwatches, which is a no-op for cancelled stopwatches.
|
||||
TelemetryStopwatch.start("FX_TAB_CLOSE_TIME_ANIM_MS", aTab);
|
||||
TelemetryStopwatch.start("FX_TAB_CLOSE_TIME_NO_ANIM_MS", aTab);
|
||||
|
||||
if (aParams) {
|
||||
var animate = aParams.animate;
|
||||
var byMouse = aParams.byMouse;
|
||||
|
@ -2573,8 +2587,11 @@
|
|||
|
||||
var isLastTab = (this.tabs.length - this._removingTabs.length == 1);
|
||||
|
||||
if (!this._beginRemoveTab(aTab, null, null, true, skipPermitUnload))
|
||||
if (!this._beginRemoveTab(aTab, null, null, true, skipPermitUnload)) {
|
||||
TelemetryStopwatch.cancel("FX_TAB_CLOSE_TIME_ANIM_MS", aTab);
|
||||
TelemetryStopwatch.cancel("FX_TAB_CLOSE_TIME_NO_ANIM_MS", aTab);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aTab.pinned && !aTab.hidden && aTab._fullyOpen && byMouse)
|
||||
this.tabContainer._lockTabSizing(aTab);
|
||||
|
@ -2589,10 +2606,15 @@
|
|||
aTab.getAttribute("fadein") != "true" /* fade-in transition hasn't been triggered yet */ ||
|
||||
window.getComputedStyle(aTab).maxWidth == "0.1px" /* fade-in transition hasn't moved yet */ ||
|
||||
!Services.prefs.getBoolPref("browser.tabs.animate")) {
|
||||
// We're not animating, so we can cancel the animation stopwatch.
|
||||
TelemetryStopwatch.cancel("FX_TAB_CLOSE_TIME_ANIM_MS", aTab);
|
||||
this._endRemoveTab(aTab);
|
||||
return;
|
||||
}
|
||||
|
||||
// We're animating, so we can cancel the non-animation stopwatch.
|
||||
TelemetryStopwatch.cancel("FX_TAB_CLOSE_TIME_NO_ANIM_MS", aTab);
|
||||
|
||||
this.tabContainer._handleTabTelemetryStart(aTab);
|
||||
|
||||
this._blurTab(aTab);
|
||||
|
@ -2630,14 +2652,22 @@
|
|||
|
||||
var browser = this.getBrowserForTab(aTab);
|
||||
|
||||
if (!aTab._pendingPermitUnload && !aAdoptedByTab && !aSkipPermitUnload) {
|
||||
if (!aTab._pendingPermitUnload &&
|
||||
!aSkipPermitUnload &&
|
||||
aTab.linkedPanel &&
|
||||
!aAdoptedByTab) {
|
||||
// We need to block while calling permitUnload() because it
|
||||
// processes the event queue and may lead to another removeTab()
|
||||
// call before permitUnload() returns.
|
||||
|
||||
TelemetryStopwatch.start("FX_TAB_CLOSE_PERMIT_UNLOAD_TIME_MS", aTab);
|
||||
|
||||
aTab._pendingPermitUnload = true;
|
||||
let {permitUnload, timedOut} = aTab.linkedPanel ?
|
||||
browser.permitUnload() : {permitUnload: true, timedOut: false};
|
||||
let {permitUnload, timedOut} = browser.permitUnload();
|
||||
delete aTab._pendingPermitUnload;
|
||||
|
||||
TelemetryStopwatch.finish("FX_TAB_CLOSE_PERMIT_UNLOAD_TIME_MS", aTab);
|
||||
|
||||
// If we were closed during onbeforeunload, we return false now
|
||||
// so we don't (try to) close the same tab again. Of course, we
|
||||
// also stop if the unload was cancelled by the user:
|
||||
|
@ -2847,6 +2877,14 @@
|
|||
|
||||
panel.remove();
|
||||
|
||||
// closeWindow might wait an arbitrary length of time if we're supposed
|
||||
// to warn about closing the window, so we'll just stop the tab close
|
||||
// stopwatches here instead.
|
||||
TelemetryStopwatch.finish("FX_TAB_CLOSE_TIME_ANIM_MS", aTab,
|
||||
true /* aCanceledOkay */);
|
||||
TelemetryStopwatch.finish("FX_TAB_CLOSE_TIME_NO_ANIM_MS", aTab,
|
||||
true /* aCanceledOkay */);
|
||||
|
||||
if (aCloseWindow)
|
||||
this._windowIsClosing = closeWindow(true, window.warnAboutClosingWindow);
|
||||
]]>
|
||||
|
@ -3386,7 +3424,7 @@
|
|||
<parameter name="aTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (!this.AppConstants.E10S_TESTING_ONLY) {
|
||||
if (!AppConstants.E10S_TESTING_ONLY) {
|
||||
throw "This method is intended only for e10s testing!";
|
||||
}
|
||||
let url = aTab.linkedBrowser.currentURI.spec;
|
||||
|
@ -3998,7 +4036,7 @@
|
|||
dump("Assertion failure\n" + Error().stack);
|
||||
|
||||
// Don't break a user's browser if an assertion fails.
|
||||
if (this.tabbrowser.AppConstants.DEBUG) {
|
||||
if (AppConstants.DEBUG) {
|
||||
throw new Error("Assertion failure");
|
||||
}
|
||||
}
|
||||
|
@ -4774,7 +4812,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (this.AppConstants.platform != "macosx") {
|
||||
if (AppConstants.platform != "macosx") {
|
||||
if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey &&
|
||||
aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
|
||||
!this.mCurrentTab.pinned) {
|
||||
|
@ -4796,7 +4834,7 @@
|
|||
if (aEvent.altKey)
|
||||
return;
|
||||
|
||||
if (this.AppConstants.platform == "macosx") {
|
||||
if (AppConstants.platform == "macosx") {
|
||||
if (!aEvent.metaKey)
|
||||
return;
|
||||
|
||||
|
@ -4859,7 +4897,7 @@
|
|||
}
|
||||
} else {
|
||||
label = tab.getAttribute("label");
|
||||
if (this.AppConstants.E10S_TESTING_ONLY &&
|
||||
if (AppConstants.E10S_TESTING_ONLY &&
|
||||
tab.linkedBrowser &&
|
||||
tab.linkedBrowser.isRemoteBrowser) {
|
||||
label += " - e10s";
|
||||
|
@ -5142,7 +5180,7 @@
|
|||
let els = Components.classes["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(nsIEventListenerService);
|
||||
els.addSystemEventListener(document, "keydown", this, false);
|
||||
if (this.AppConstants.platform == "macosx") {
|
||||
if (AppConstants.platform == "macosx") {
|
||||
els.addSystemEventListener(document, "keypress", this, false);
|
||||
}
|
||||
window.addEventListener("sizemodechange", this);
|
||||
|
@ -5259,7 +5297,7 @@
|
|||
let els = Components.classes["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(nsIEventListenerService);
|
||||
els.removeSystemEventListener(document, "keydown", this, false);
|
||||
if (this.AppConstants.platform == "macosx") {
|
||||
if (AppConstants.platform == "macosx") {
|
||||
els.removeSystemEventListener(document, "keypress", this, false);
|
||||
}
|
||||
window.removeEventListener("sizemodechange", this);
|
||||
|
@ -6619,7 +6657,7 @@
|
|||
return;
|
||||
|
||||
let wrongModifiers;
|
||||
if (this.tabbrowser.AppConstants.platform == "macosx") {
|
||||
if (AppConstants.platform == "macosx") {
|
||||
wrongModifiers = !event.metaKey;
|
||||
} else {
|
||||
wrongModifiers = !event.ctrlKey || event.metaKey;
|
||||
|
@ -6702,7 +6740,7 @@
|
|||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
let captureListener;
|
||||
let platform = this.tabbrowser.AppConstants.platform;
|
||||
let platform = AppConstants.platform;
|
||||
// On Windows and Mac we can update the drag image during a drag
|
||||
// using updateDragImage. On Linux, we can use a panel.
|
||||
if (platform == "win" || platform == "macosx") {
|
||||
|
@ -6987,7 +7025,7 @@
|
|||
window.focus();
|
||||
} else {
|
||||
let props = { screenX: left, screenY: top };
|
||||
if (this.tabbrowser.AppConstants.platform != "win") {
|
||||
if (AppConstants.platform != "win") {
|
||||
props.outerWidth = winWidth;
|
||||
props.outerHeight = winHeight;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ add_task(function* checkCaptivePortalCertErrorUI() {
|
|||
let portalTab2 = yield portalTabPromise;
|
||||
is(portalTab2, portalTab, "The existing portal tab should be focused.");
|
||||
|
||||
let portalTabRemoved = BrowserTestUtils.removeTab(portalTab, {dontRemove: true});
|
||||
let portalTabRemoved = BrowserTestUtils.tabRemoved(portalTab);
|
||||
let errorTabReloaded = BrowserTestUtils.waitForErrorPage(browser);
|
||||
|
||||
Services.obs.notifyObservers(null, "captive-portal-login-success", null);
|
||||
|
|
|
@ -46,7 +46,7 @@ add_task(function*() {
|
|||
});
|
||||
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter(`#${id} > input`,
|
||||
{ type : "contextmenu", button : 2 },
|
||||
{ type: "contextmenu", button: 2 },
|
||||
tab.linkedBrowser);
|
||||
let target = yield contextMenuPromise;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ add_task(function*() {
|
|||
var tab = gBrowser.selectedTab;
|
||||
gPrefService.setBoolPref("browser.tabs.closeWindowWithLastTab", false);
|
||||
|
||||
let tabClosedPromise = BrowserTestUtils.removeTab(tab, {dontRemove: true});
|
||||
let tabClosedPromise = BrowserTestUtils.tabRemoved(tab);
|
||||
EventUtils.synthesizeKey("w", { accelKey: true });
|
||||
yield tabClosedPromise;
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ function getObserverTopic(aNotificationId) {
|
|||
topic = "addon-install-started";
|
||||
else if (topic == "addon-install-restart")
|
||||
topic = "addon-install-complete";
|
||||
else if (topic == "addon-installed")
|
||||
topic = "webextension-install-notify";
|
||||
return topic;
|
||||
}
|
||||
|
||||
|
@ -441,14 +443,9 @@ function test_restartless() {
|
|||
yield progressPromise;
|
||||
let installDialog = yield dialogPromise;
|
||||
|
||||
let notificationPromise = waitForNotification("addon-install-complete");
|
||||
let notificationPromise = waitForNotification("addon-installed");
|
||||
acceptInstallDialog(installDialog);
|
||||
let panel = yield notificationPromise;
|
||||
|
||||
let notification = panel.childNodes[0];
|
||||
is(notification.getAttribute("label"),
|
||||
"XPI Test has been installed successfully.",
|
||||
"Should have seen the right message");
|
||||
yield notificationPromise;
|
||||
|
||||
let installs = yield getInstalls();
|
||||
is(installs.length, 0, "Should be no pending installs");
|
||||
|
@ -574,7 +571,7 @@ function test_allUnverified() {
|
|||
is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
|
||||
is(container.childNodes[0].childNodes.length, 1, "Shouldn't have the unverified marker");
|
||||
|
||||
let notificationPromise = waitForNotification("addon-install-complete");
|
||||
let notificationPromise = waitForNotification("addon-installed");
|
||||
acceptInstallDialog(installDialog);
|
||||
yield notificationPromise;
|
||||
|
||||
|
@ -1024,7 +1021,7 @@ var gTestStart = null;
|
|||
|
||||
var XPInstallObserver = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
|
||||
var installInfo = aSubject.wrappedJSObject;
|
||||
info("Observed " + aTopic + " for " + installInfo.installs.length + " installs");
|
||||
installInfo.installs.forEach(function(aInstall) {
|
||||
info("Install of " + aInstall.sourceURI.spec + " was in state " + aInstall.state);
|
||||
|
@ -1043,7 +1040,6 @@ add_task(function* () {
|
|||
Services.obs.addObserver(XPInstallObserver, "addon-install-started", false);
|
||||
Services.obs.addObserver(XPInstallObserver, "addon-install-blocked", false);
|
||||
Services.obs.addObserver(XPInstallObserver, "addon-install-failed", false);
|
||||
Services.obs.addObserver(XPInstallObserver, "addon-install-complete", false);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// Make sure no more test parts run in case we were timed out
|
||||
|
@ -1063,7 +1059,6 @@ add_task(function* () {
|
|||
Services.obs.removeObserver(XPInstallObserver, "addon-install-started");
|
||||
Services.obs.removeObserver(XPInstallObserver, "addon-install-blocked");
|
||||
Services.obs.removeObserver(XPInstallObserver, "addon-install-failed");
|
||||
Services.obs.removeObserver(XPInstallObserver, "addon-install-complete");
|
||||
});
|
||||
|
||||
for (let i = 0; i < TESTS.length; ++i) {
|
||||
|
|
|
@ -13,7 +13,7 @@ function checkPopupHide() {
|
|||
}
|
||||
|
||||
var gObserver = {
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]),
|
||||
|
||||
notifyInvalidSubmit(aFormElement, aInvalidElements) {
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ add_task(function *() {
|
|||
// Get the point of the element with the page menu (test-pagemenu) and
|
||||
// synthesize a right mouse click there.
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
yield BrowserTestUtils.synthesizeMouse("#test-pagemenu", 5, 5, { type : "contextmenu", button : 2 }, tab.linkedBrowser);
|
||||
yield BrowserTestUtils.synthesizeMouse("#test-pagemenu", 5, 5, { type: "contextmenu", button: 2 }, tab.linkedBrowser);
|
||||
yield popupShownPromise;
|
||||
|
||||
checkMenu(contextMenu);
|
||||
|
|
|
@ -46,7 +46,7 @@ function* expectFocusOnF6(backward, expectedDocument, expectedElement, onContent
|
|||
|
||||
if (!contentExpectedElement) {
|
||||
sendSyncMessage("BrowserTest:FocusChanged",
|
||||
{ details : "expected element " + arg.expectedElementId + " not found" });
|
||||
{ details: "expected element " + arg.expectedElementId + " not found" });
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,14 +11,14 @@ function test() {
|
|||
var urlString = value + "\n" + content.document.title;
|
||||
var htmlString = "<a href=\"" + value + "\">" + value + "</a>";
|
||||
var expected = [ [
|
||||
{ type : "text/x-moz-url",
|
||||
data : urlString },
|
||||
{ type : "text/uri-list",
|
||||
data : value },
|
||||
{ type : "text/plain",
|
||||
data : value },
|
||||
{ type : "text/html",
|
||||
data : htmlString }
|
||||
{ type: "text/x-moz-url",
|
||||
data: urlString },
|
||||
{ type: "text/uri-list",
|
||||
data: value },
|
||||
{ type: "text/plain",
|
||||
data: value },
|
||||
{ type: "text/html",
|
||||
data: htmlString }
|
||||
] ];
|
||||
// set the valid attribute so dropping is allowed
|
||||
var oldstate = gURLBar.getAttribute("pageproxystate");
|
||||
|
|
|
@ -519,41 +519,41 @@ function* setupFormHistory() {
|
|||
op: "remove"
|
||||
},
|
||||
{
|
||||
op : "add",
|
||||
fieldname : "10minutes",
|
||||
value : "10m"
|
||||
op: "add",
|
||||
fieldname: "10minutes",
|
||||
value: "10m"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "1hour",
|
||||
value : "1h"
|
||||
op: "add",
|
||||
fieldname: "1hour",
|
||||
value: "1h"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "1hour10minutes",
|
||||
value : "1h10m"
|
||||
op: "add",
|
||||
fieldname: "1hour10minutes",
|
||||
value: "1h10m"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "2hour",
|
||||
value : "2h"
|
||||
op: "add",
|
||||
fieldname: "2hour",
|
||||
value: "2h"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "2hour10minutes",
|
||||
value : "2h10m"
|
||||
op: "add",
|
||||
fieldname: "2hour10minutes",
|
||||
value: "2h10m"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "4hour",
|
||||
value : "4h"
|
||||
op: "add",
|
||||
fieldname: "4hour",
|
||||
value: "4h"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "4hour10minutes",
|
||||
value : "4h10m"
|
||||
op: "add",
|
||||
fieldname: "4hour10minutes",
|
||||
value: "4h10m"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "today",
|
||||
value : "1d"
|
||||
op: "add",
|
||||
fieldname: "today",
|
||||
value: "1d"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "b4today",
|
||||
value : "1y"
|
||||
op: "add",
|
||||
fieldname: "b4today",
|
||||
value: "1y"
|
||||
}]);
|
||||
|
||||
// Artifically age the entries to the proper vintage.
|
||||
|
|
|
@ -78,7 +78,7 @@ function focusInChild() {
|
|||
id = getWindowDocId(event.originalTarget) + "-document";
|
||||
else
|
||||
id = event.originalTarget.id;
|
||||
sendSyncMessage("Browser:FocusChanged", { details : event.type + ": " + id });
|
||||
sendSyncMessage("Browser:FocusChanged", { details: event.type + ": " + id });
|
||||
}
|
||||
|
||||
addEventListener("focus", eventListener, true);
|
||||
|
|
|
@ -32,7 +32,7 @@ add_task(function*() {
|
|||
yield secondTabLoadedPromise;
|
||||
|
||||
let closeBtn = document.getAnonymousElementByAttribute(secondTab, "anonid", "close-button");
|
||||
let closePromise = BrowserTestUtils.removeTab(secondTab, {dontRemove: true});
|
||||
let closePromise = BrowserTestUtils.tabRemoved(secondTab);
|
||||
info("closing second tab (which will self-close in beforeunload)");
|
||||
closeBtn.click();
|
||||
ok(secondTab.closing, "Second tab should be marked as closing synchronously.");
|
||||
|
|
|
@ -12,7 +12,7 @@ function openContextMenuFor(element, shiftkey, waitForSpellCheck) {
|
|||
// run on them.
|
||||
function actuallyOpenContextMenuFor() {
|
||||
lastElement = element;
|
||||
var eventDetails = { type : "contextmenu", button : 2, shiftKey : shiftkey };
|
||||
var eventDetails = { type: "contextmenu", button: 2, shiftKey: shiftkey };
|
||||
synthesizeMouse(element, 2, 2, eventDetails, element.ownerGlobal);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,3 +6,7 @@ support-files =
|
|||
[browser_pageinfo_images.js]
|
||||
[browser_pageinfo_image_info.js]
|
||||
skip-if = (os == 'linux' && e10s) # bug 1161699
|
||||
[browser_pageinfo_svg_image.js]
|
||||
support-files =
|
||||
svg_image.html
|
||||
../general/title_test.svg
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
var pageInfo = BrowserPageInfo(gBrowser.selectedBrowser.currentURI.spec,
|
||||
"mediaTab");
|
||||
|
||||
pageInfo.addEventListener("load", function() {
|
||||
pageInfo.onFinished.push(function() {
|
||||
executeSoon(function() {
|
||||
var imageTree = pageInfo.document.getElementById("imagetree");
|
||||
var imageRowsNum = imageTree.view.rowCount;
|
||||
|
||||
ok(imageTree, "Image tree is null (media tab is broken)");
|
||||
|
||||
is(imageRowsNum, 1, "should have one image");
|
||||
|
||||
// Only bother running this if we've got the right number of rows.
|
||||
if (imageRowsNum == 1) {
|
||||
is(imageTree.view.getCellText(0, imageTree.columns[0]),
|
||||
"https://example.com/browser/browser/base/content/test/pageinfo/title_test.svg",
|
||||
"The URL should be the svg image.");
|
||||
}
|
||||
|
||||
pageInfo.close();
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
}, {capture: true, once: true});
|
||||
|
||||
content.location =
|
||||
"https://example.com/browser/browser/base/content/test/pageinfo/svg_image.html";
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for page info svg images</title>
|
||||
</head>
|
||||
<body>
|
||||
<svg width="20" height="20">
|
||||
<image xlink:href="title_test.svg" width="20" height="20">
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
|
@ -77,7 +77,7 @@ var corpus = [
|
|||
url: "https://www.mozilla.org/",
|
||||
// shortUrl: this.getShortURL(),
|
||||
// og:image
|
||||
previews:["https://www.mozilla.org/favicon.png"],
|
||||
previews: ["https://www.mozilla.org/favicon.png"],
|
||||
// og:site_name
|
||||
siteName: ">My simple test page<"
|
||||
}
|
||||
|
|
|
@ -169,15 +169,6 @@ var whitelist = new Set([
|
|||
platforms: ["linux"]},
|
||||
// Bug 1348559
|
||||
{file: "chrome://pippki/content/resetpassword.xul"},
|
||||
// Bug 1348562
|
||||
{file: "chrome://devtools/skin/images/debugging-devices.svg",
|
||||
isFromDevTools: true},
|
||||
{file: "chrome://devtools/skin/images/fast-forward.svg",
|
||||
isFromDevTools: true},
|
||||
{file: "chrome://devtools/skin/images/firebug/spinner.png",
|
||||
isFromDevTools: true},
|
||||
{file: "chrome://devtools/skin/images/noise.png",
|
||||
isFromDevTools: true},
|
||||
|
||||
].filter(item =>
|
||||
("isFromDevTools" in item) == isDevtools &&
|
||||
|
|
|
@ -25,7 +25,7 @@ add_task(function* test_without_dump() {
|
|||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
|
||||
let tabRemovedPromise = BrowserTestUtils.removeTab(tab, { dontRemove: true });
|
||||
let tabRemovedPromise = BrowserTestUtils.tabRemoved(tab);
|
||||
|
||||
yield ContentTask.spawn(browser, null, function*() {
|
||||
let doc = content.document;
|
||||
|
|
|
@ -4,6 +4,7 @@ support-files =
|
|||
|
||||
[browser_abandonment_telemetry.js]
|
||||
[browser_allow_process_switches_despite_related_browser.js]
|
||||
[browser_tabCloseProbes.js]
|
||||
[browser_tabSpinnerProbe.js]
|
||||
skip-if = !e10s # Tab spinner is e10s only.
|
||||
[browser_tabSpinnerTypeProbe.js]
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
"use strict";
|
||||
|
||||
var gAnimHistogram = Services.telemetry
|
||||
.getHistogramById("FX_TAB_CLOSE_TIME_ANIM_MS");
|
||||
var gNoAnimHistogram = Services.telemetry
|
||||
.getHistogramById("FX_TAB_CLOSE_TIME_NO_ANIM_MS");
|
||||
|
||||
/**
|
||||
* Takes a Telemetry histogram snapshot and makes sure
|
||||
* that the sum of all counts equals expectedCount.
|
||||
*
|
||||
* @param snapshot (Object)
|
||||
* The Telemetry histogram snapshot to examine.
|
||||
* @param expectedCount (int)
|
||||
* What we expect the number of incremented counts to be. For example,
|
||||
* If we expect this probe to have only had a single recording, this
|
||||
* would be 1. If we expected it to have not recorded any data at all,
|
||||
* this would be 0.
|
||||
*/
|
||||
function assertCount(snapshot, expectedCount) {
|
||||
// Use Array.prototype.reduce to sum up all of the
|
||||
// snapshot.count entries
|
||||
Assert.equal(snapshot.counts.reduce((a, b) => a + b), expectedCount,
|
||||
`Should only be ${expectedCount} collected value.`);
|
||||
}
|
||||
|
||||
add_task(function* setup() {
|
||||
// These probes are opt-in, meaning we only capture them if extended
|
||||
// Telemetry recording is enabled.
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [["toolkit.telemetry.enabled", true]]
|
||||
});
|
||||
|
||||
let oldCanRecord = Services.telemetry.canRecordExtended;
|
||||
Services.telemetry.canRecordExtended = true;
|
||||
registerCleanupFunction(() => {
|
||||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests the FX_TAB_CLOSE_TIME_ANIM_MS probe by closing a tab with the tab
|
||||
* close animation.
|
||||
*/
|
||||
add_task(function* test_close_time_anim_probe() {
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
|
||||
|
||||
gAnimHistogram.clear();
|
||||
gNoAnimHistogram.clear();
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab, { animate: true });
|
||||
|
||||
assertCount(gAnimHistogram.snapshot(), 1);
|
||||
assertCount(gNoAnimHistogram.snapshot(), 0);
|
||||
|
||||
gAnimHistogram.clear();
|
||||
gNoAnimHistogram.clear();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests the FX_TAB_CLOSE_TIME_NO_ANIM_MS probe by closing a tab without the
|
||||
* tab close animation.
|
||||
*/
|
||||
add_task(function* test_close_time_no_anim_probe() {
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
|
||||
|
||||
gAnimHistogram.clear();
|
||||
gNoAnimHistogram.clear();
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab, { animate: false });
|
||||
|
||||
assertCount(gAnimHistogram.snapshot(), 0);
|
||||
assertCount(gNoAnimHistogram.snapshot(), 1);
|
||||
|
||||
gAnimHistogram.clear();
|
||||
gNoAnimHistogram.clear();
|
||||
});
|
|
@ -66,7 +66,7 @@ function* runTest(aSourceWindow, aDestWindow, aExpectSwitch, aCallback) {
|
|||
|
||||
let awaitTabSwitch;
|
||||
if (aExpectSwitch) {
|
||||
awaitTabSwitch = BrowserTestUtils.removeTab(testTab, {dontRemove: true})
|
||||
awaitTabSwitch = BrowserTestUtils.tabRemoved(testTab)
|
||||
}
|
||||
|
||||
// Execute the selected action.
|
||||
|
|
|
@ -81,11 +81,6 @@ function promiseSetDisabled(addon) {
|
|||
let cleanup;
|
||||
|
||||
add_task(function* () {
|
||||
// XXX remove this when prompts are enabled by default
|
||||
yield SpecialPowers.pushPrefEnv({set: [
|
||||
["extensions.webextPermissionPrompts", true],
|
||||
]});
|
||||
|
||||
// ICON_URL wouldn't ever appear as an actual webextension icon, but
|
||||
// we're just mocking out the addon here, so all we care about is that
|
||||
// that it propagates correctly to the popup.
|
||||
|
|
|
@ -35,9 +35,6 @@ add_task(function* setup() {
|
|||
// We don't have pre-pinned certificates for the local mochitest server
|
||||
["extensions.install.requireBuiltInCerts", false],
|
||||
["extensions.update.requireBuiltInCerts", false],
|
||||
|
||||
// XXX remove this when prompts are enabled by default
|
||||
["extensions.webextPermissionPrompts", true],
|
||||
]});
|
||||
|
||||
// Navigate away from the initial page so that about:addons always
|
||||
|
|
|
@ -7,9 +7,6 @@ add_task(async function test_unsigned() {
|
|||
await SpecialPowers.pushPrefEnv({set: [
|
||||
["extensions.webapi.testing", true],
|
||||
["extensions.install.requireBuiltInCerts", false],
|
||||
|
||||
// XXX remove this when prompts are enabled by default
|
||||
["extensions.webextPermissionPrompts", true],
|
||||
]});
|
||||
|
||||
let testURI = makeURI("https://example.com/");
|
||||
|
|
|
@ -8,9 +8,6 @@ add_task(function* setup() {
|
|||
// We don't have pre-pinned certificates for the local mochitest server
|
||||
["extensions.install.requireBuiltInCerts", false],
|
||||
["extensions.update.requireBuiltInCerts", false],
|
||||
|
||||
// XXX remove this when prompts are enabled by default
|
||||
["extensions.webextPermissionPrompts", true],
|
||||
]});
|
||||
});
|
||||
|
||||
|
|
|
@ -8,9 +8,6 @@ add_task(function* setup() {
|
|||
|
||||
// Point updates to the local mochitest server
|
||||
["extensions.update.url", `${BASE}/browser_webext_update.json`],
|
||||
|
||||
// XXX remove this when prompts are enabled by default
|
||||
["extensions.webextPermissionPrompts", true],
|
||||
]});
|
||||
});
|
||||
|
||||
|
|
|
@ -217,9 +217,6 @@ async function testInstallMethod(installFn, telemetryBase) {
|
|||
await SpecialPowers.pushPrefEnv({set: [
|
||||
["extensions.webapi.testing", true],
|
||||
["extensions.install.requireBuiltInCerts", false],
|
||||
|
||||
// XXX remove this when prompts are enabled by default
|
||||
["extensions.webextPermissionPrompts", true],
|
||||
]});
|
||||
|
||||
if (telemetryBase !== undefined) {
|
||||
|
|
|
@ -12,7 +12,7 @@ skip-if = (os == "linux" && debug) # linux: bug 976544
|
|||
[browser_devices_get_user_media_multi_process.js]
|
||||
skip-if = (e10s && debug) # bug 1347625
|
||||
[browser_devices_get_user_media_screen.js]
|
||||
skip-if = (e10s && debug) || (os == "linux") || (os == "win" && !debug) # bug 1320754 for e10s debug, and bug 1320994 for linux opt, bug 1338038 for windows and linux debug
|
||||
skip-if = (os == "linux") || (os == "win" && !debug) # bug 1320994 for linux opt, bug 1338038 for windows and linux debug
|
||||
[browser_devices_get_user_media_tear_off_tab.js]
|
||||
[browser_devices_get_user_media_unprompted_access.js]
|
||||
[browser_devices_get_user_media_unprompted_access_in_frame.js]
|
||||
|
|
|
@ -790,7 +790,7 @@ function openPreferences(paneID, extraArgs) {
|
|||
}
|
||||
|
||||
function openAdvancedPreferences(tabID) {
|
||||
openPreferences("paneAdvanced", { "advancedTab" : tabID });
|
||||
openPreferences("paneAdvanced", { "advancedTab": tabID });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -20,6 +21,8 @@ namespace browser {
|
|||
|
||||
NS_IMPL_ISUPPORTS(AboutRedirector, nsIAboutModule)
|
||||
|
||||
bool AboutRedirector::sUseOldPreferences = false;
|
||||
|
||||
struct RedirEntry {
|
||||
const char* id;
|
||||
const char* url;
|
||||
|
@ -138,6 +141,13 @@ AboutRedirector::NewChannel(nsIURI* aURI,
|
|||
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
static bool sPrefCacheInited = false;
|
||||
if (!sPrefCacheInited) {
|
||||
Preferences::AddBoolVarCache(&sUseOldPreferences,
|
||||
"browser.preferences.useOldOrganization");
|
||||
sPrefCacheInited = true;
|
||||
}
|
||||
|
||||
for (auto & redir : kRedirMap) {
|
||||
if (!strcmp(path.get(), redir.id)) {
|
||||
nsAutoCString url;
|
||||
|
@ -149,6 +159,8 @@ AboutRedirector::NewChannel(nsIURI* aURI,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aboutNewTabService->GetDefaultURL(url);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else if (path.EqualsLiteral("preferences") && sUseOldPreferences) {
|
||||
url.AssignASCII("chrome://browser/content/preferences/in-content-old/preferences.xul");
|
||||
}
|
||||
// fall back to the specified url in the map
|
||||
if (url.IsEmpty()) {
|
||||
|
|
|
@ -24,6 +24,9 @@ public:
|
|||
|
||||
protected:
|
||||
virtual ~AboutRedirector() {}
|
||||
|
||||
private:
|
||||
static bool sUseOldPreferences;
|
||||
};
|
||||
|
||||
} // namespace browser
|
||||
|
|
|
@ -544,14 +544,8 @@ XPCOMUtils.defineConstant(this, "PanelUI", PanelUI);
|
|||
|
||||
/**
|
||||
* Gets the currently selected locale for display.
|
||||
* @return the selected locale or "en-US" if none is selected
|
||||
* @return the selected locale
|
||||
*/
|
||||
function getLocale() {
|
||||
try {
|
||||
let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry);
|
||||
return chromeRegistry.getSelectedLocale("browser");
|
||||
} catch (ex) {
|
||||
return "en-US";
|
||||
}
|
||||
return Services.locale.getAppLocaleAsLangTag();
|
||||
}
|
||||
|
|
|
@ -240,6 +240,18 @@ var gMenuBuilder = {
|
|||
info.modifiers.push("MacCtrl");
|
||||
}
|
||||
|
||||
// Allow context menu's to open various actions supported in webext prior
|
||||
// to notifying onclicked.
|
||||
let actionFor = {
|
||||
_execute_page_action: pageActionFor,
|
||||
_execute_browser_action: browserActionFor,
|
||||
_execute_sidebar_action: sidebarActionFor,
|
||||
}[item.command];
|
||||
if (actionFor) {
|
||||
let win = event.target.ownerGlobal;
|
||||
actionFor(item.extension).triggerAction(win);
|
||||
}
|
||||
|
||||
item.extension.emit("webext-contextmenu-menuitem-click", info, tab);
|
||||
});
|
||||
|
||||
|
|
|
@ -202,6 +202,11 @@
|
|||
"type": "boolean",
|
||||
"optional": true,
|
||||
"description": "Whether this context menu item is enabled or disabled. Defaults to true."
|
||||
},
|
||||
"command": {
|
||||
"type": "string",
|
||||
"optional": true,
|
||||
"description": "Specifies a command to issue for the context click. Currently supports internal commands _execute_page_action, _execute_browser_action and _execute_sidebar_action."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -50,6 +50,7 @@ support-files =
|
|||
[browser_ext_contextMenus.js]
|
||||
[browser_ext_contextMenus_checkboxes.js]
|
||||
[browser_ext_contextMenus_chrome.js]
|
||||
[browser_ext_contextMenus_commands.js]
|
||||
[browser_ext_contextMenus_icons.js]
|
||||
[browser_ext_contextMenus_onclick.js]
|
||||
[browser_ext_contextMenus_radioGroups.js]
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
function background() {
|
||||
browser.contextMenus.create({
|
||||
title: "open_browser_action",
|
||||
contexts: ["all"],
|
||||
command: "_execute_browser_action",
|
||||
});
|
||||
browser.contextMenus.create({
|
||||
title: "open_page_action",
|
||||
contexts: ["all"],
|
||||
command: "_execute_page_action",
|
||||
});
|
||||
browser.contextMenus.create({
|
||||
title: "open_sidebar_action",
|
||||
contexts: ["all"],
|
||||
command: "_execute_sidebar_action",
|
||||
});
|
||||
browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
||||
browser.pageAction.show(tabId);
|
||||
});
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
|
||||
function testScript() {
|
||||
window.onload = () => {
|
||||
browser.test.sendMessage("test-opened", true);
|
||||
};
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"permissions": ["contextMenus", "activeTab", "tabs"],
|
||||
"browser_action": {
|
||||
"default_title": "Test BrowserAction",
|
||||
"default_popup": "test.html",
|
||||
"browser_style": true,
|
||||
},
|
||||
"page_action": {
|
||||
"default_title": "Test PageAction",
|
||||
"default_popup": "test.html",
|
||||
"browser_style": true,
|
||||
},
|
||||
"sidebar_action": {
|
||||
"default_title": "Test Sidebar",
|
||||
"default_panel": "test.html",
|
||||
},
|
||||
},
|
||||
background,
|
||||
files: {
|
||||
"test.html": `<!DOCTYPE html><meta charset="utf-8"><script src="test.js"></script>`,
|
||||
"test.js": testScript,
|
||||
},
|
||||
});
|
||||
|
||||
function* testContext(id) {
|
||||
const menu = yield openExtensionContextMenu();
|
||||
const items = menu.getElementsByAttribute("label", id);
|
||||
yield closeExtensionContextMenu(items[0]);
|
||||
return extension.awaitMessage("test-opened");
|
||||
}
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
// open a page so page action works
|
||||
const PAGE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html?test=commands";
|
||||
const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
||||
|
||||
ok(yield testContext("open_sidebar_action"), "_execute_sidebar_action worked");
|
||||
ok(yield testContext("open_browser_action"), "_execute_browser_action worked");
|
||||
ok(yield testContext("open_page_action"), "_execute_page_action worked");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
yield extension.unload();
|
||||
});
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
add_task(function* () {
|
||||
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
|
||||
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
|
||||
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html?test=icons");
|
||||
|
||||
let encodedImageData = "iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAC4klEQVRYhdWXLWzbQBSADQtDAwsHC1tUhUxqfL67lk2tdn+OJg0ODU0rLByqgqINBY6tmlbn7LMTJ5FaFVVBk1G0oUGjG2jT2Y7jxmmcbU/6iJ+f36fz+e5sGP9riCGm9hB37RG+scd4Yo/wsDXCZyIE2xuXsce4bY+wXkAsQtzYmExrfFgvkJkRbkzo1ehoxx5iXcgI/9iYUGt8WH9MqDXEcmNChmEYrRCf2SHWeYgQx3x0tLNRIeKQLTtEFyJEep4NTuhk8BC+yMrwEE3+iozo42d8gK7FAOkMsRiiN8QhW2ttSK5QTfRRV4QoymVeJMvPvDp7gCZigD613MN6yRFA3SWarow9QB9LCfG+NeF9qCtjAKOSQjCqVKhfVsiHEQ+grgx/lRGqUihAc1uL8EFD+KCRO+GrF4J61phcoRoPoEzkYhZYpykh5sMb7kOdIeY+jHKur4QI4Feh4AFX1nVeLxrAvQchGsBz5ls6wa2QdwcvIcE2863bTH79KOvsz/uUYJsp+J0pSzNlDckVqqVGUAF+n6uS7txcOl6wot4JVy70ufDLy4pWLUQVPE81pRI0mGe9oxLMHSeohHvMs/STUNaUK6vDPCvOyxMFDx4achehRDJmHnydnkPww5OFfLxrGIZBFDyYl4LpMzlTQFIP6AQx86w2UeYBccFpJrcKv5L9eGDtUAU6RIELqsB74uynjy/UBRF1gS5BTFxwQT1wTiXoUg9MH7m/3NZRRoi5IJytUbMgzv4Wc832+oQkiKgEehmyMkkpKsFkQV11QsRJL5rJYBLItQgRaUZEmnoZXsomz3vGiWw+I9KMF9SVFOqZEemZekli1jN3U/UOqhHHvC6oWWGElhfSpGdOk6+O9prdwvtLj5BjRsQxdRnot+Zeifpy/2/0stktKTRNLmbk0mwXyl8253fyojj+8rxOHNAhjjm5n0/5OOCGOKBzkrMO0Z75lvSAzKlrF32Z/3z8BqLAn+yMV7VhAAAAAElFTkSuQmCC";
|
||||
const IMAGE_ARRAYBUFFER = imageBufferFromDataURI(encodedImageData);
|
||||
|
@ -26,6 +26,7 @@ add_task(function* () {
|
|||
title: "child-to-delete",
|
||||
onclick: () => {
|
||||
browser.contextMenus.remove(menuitemId);
|
||||
browser.test.sendMessage("child-deleted");
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -33,9 +34,6 @@ add_task(function* () {
|
|||
title: "child",
|
||||
});
|
||||
|
||||
browser.test.onMessage.addListener(() => {
|
||||
browser.test.sendMessage("pong");
|
||||
});
|
||||
browser.test.notifyPass("contextmenus-icons");
|
||||
},
|
||||
});
|
||||
|
@ -57,10 +55,7 @@ add_task(function* () {
|
|||
|
||||
let childToDelete = extensionMenu.getElementsByAttribute("label", "child-to-delete")[0];
|
||||
yield closeExtensionContextMenu(childToDelete);
|
||||
// Now perform a roundtrip to the extension process to make sure that the
|
||||
// click event has had a chance to fire.
|
||||
extension.sendMessage("ping");
|
||||
yield extension.awaitMessage("pong");
|
||||
yield extension.awaitMessage("child-deleted");
|
||||
|
||||
yield openExtensionContextMenu();
|
||||
|
||||
|
|
|
@ -189,12 +189,9 @@ FeedWriter.prototype = {
|
|||
__dateFormatter: null,
|
||||
get _dateFormatter() {
|
||||
if (!this.__dateFormatter) {
|
||||
const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global", true);
|
||||
const dtOptions = { year: "numeric", month: "long", day: "numeric",
|
||||
hour: "numeric", minute: "numeric" };
|
||||
this.__dateFormatter = new Intl.DateTimeFormat(locale, dtOptions);
|
||||
this.__dateFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
|
||||
}
|
||||
return this.__dateFormatter;
|
||||
},
|
||||
|
|
|
@ -638,10 +638,8 @@ const AutoMigrate = {
|
|||
// Strip out any empty elements, so an empty pref doesn't
|
||||
// lead to a an array with 1 empty string in it.
|
||||
surveyLocales = new Set(surveyLocales.filter(str => !!str));
|
||||
let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry);
|
||||
canDoSurveyInLocale =
|
||||
surveyLocales.has(chromeRegistry.getSelectedLocale("global"));
|
||||
surveyLocales.has(Services.locale.getAppLocaleAsLangTag());
|
||||
} catch (ex) {
|
||||
/* ignore exceptions and just don't do the survey. */
|
||||
}
|
||||
|
|
|
@ -222,7 +222,7 @@ add_task(function* test_datareporting_many() {
|
|||
Assert.ok(ok, "callback should have been true");
|
||||
|
||||
checkDirectoryContains(targetDir, {
|
||||
"datareporting" : {
|
||||
"datareporting": {
|
||||
"state.json": shouldBeCopied,
|
||||
"session-state.json": shouldBeCopied,
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ add_task(function* test_no_session_state() {
|
|||
Assert.ok(ok, "callback should have been true");
|
||||
|
||||
checkDirectoryContains(targetDir, {
|
||||
"datareporting" : {
|
||||
"datareporting": {
|
||||
"state.json": stateContent,
|
||||
}
|
||||
});
|
||||
|
@ -259,7 +259,7 @@ add_task(function* test_no_state() {
|
|||
Assert.ok(ok, "callback should have been true");
|
||||
|
||||
checkDirectoryContains(targetDir, {
|
||||
"datareporting" : {
|
||||
"datareporting": {
|
||||
"session-state.json": sessionStateContent,
|
||||
}
|
||||
});
|
||||
|
|
|
@ -283,7 +283,7 @@ nsBrowserContentHandler.prototype = {
|
|||
|
||||
/* helper functions */
|
||||
|
||||
mChromeURL : null,
|
||||
mChromeURL: null,
|
||||
|
||||
get chromeURL() {
|
||||
if (this.mChromeURL) {
|
||||
|
@ -296,13 +296,13 @@ nsBrowserContentHandler.prototype = {
|
|||
},
|
||||
|
||||
/* nsISupports */
|
||||
QueryInterface : XPCOMUtils.generateQI([nsICommandLineHandler,
|
||||
nsIBrowserHandler,
|
||||
nsIContentHandler,
|
||||
nsICommandLineValidator]),
|
||||
QueryInterface: XPCOMUtils.generateQI([nsICommandLineHandler,
|
||||
nsIBrowserHandler,
|
||||
nsIContentHandler,
|
||||
nsICommandLineValidator]),
|
||||
|
||||
/* nsICommandLineHandler */
|
||||
handle : function bch_handle(cmdLine) {
|
||||
handle: function bch_handle(cmdLine) {
|
||||
if (cmdLine.handleFlag("browser", false)) {
|
||||
// Passing defaultArgs, so use NO_EXTERNAL_URIS
|
||||
openWindow(null, this.chromeURL, "_blank",
|
||||
|
@ -558,9 +558,9 @@ nsBrowserContentHandler.prototype = {
|
|||
return uri;
|
||||
},
|
||||
|
||||
mFeatures : null,
|
||||
mFeatures: null,
|
||||
|
||||
getFeatures : function bch_features(cmdLine) {
|
||||
getFeatures: function bch_features(cmdLine) {
|
||||
if (this.mFeatures === null) {
|
||||
this.mFeatures = "";
|
||||
|
||||
|
@ -587,7 +587,7 @@ nsBrowserContentHandler.prototype = {
|
|||
|
||||
/* nsIContentHandler */
|
||||
|
||||
handleContent : function bch_handleContent(contentType, context, request) {
|
||||
handleContent: function bch_handleContent(contentType, context, request) {
|
||||
try {
|
||||
var webNavInfo = Components.classes["@mozilla.org/webnavigation-info;1"]
|
||||
.getService(nsIWebNavigationInfo);
|
||||
|
@ -605,7 +605,7 @@ nsBrowserContentHandler.prototype = {
|
|||
},
|
||||
|
||||
/* nsICommandLineValidator */
|
||||
validate : function bch_validate(cmdLine) {
|
||||
validate: function bch_validate(cmdLine) {
|
||||
// Other handlers may use osint so only handle the osint flag if the url
|
||||
// flag is also present and the command line is valid.
|
||||
var osintFlagIdx = cmdLine.findFlag("osint", false);
|
||||
|
@ -669,7 +669,7 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
classID: Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}"),
|
||||
|
||||
/* nsISupports */
|
||||
QueryInterface : function dch_QI(iid) {
|
||||
QueryInterface: function dch_QI(iid) {
|
||||
if (!iid.equals(nsISupports) &&
|
||||
!iid.equals(nsICommandLineHandler))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
|
@ -680,7 +680,7 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
_haveProfile: false,
|
||||
|
||||
/* nsICommandLineHandler */
|
||||
handle : function dch_handle(cmdLine) {
|
||||
handle: function dch_handle(cmdLine) {
|
||||
var urilist = [];
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
|
@ -765,7 +765,7 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
helpInfo : "",
|
||||
helpInfo: "",
|
||||
};
|
||||
|
||||
var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler];
|
||||
|
|
|
@ -512,18 +512,18 @@ var BookmarkPropertiesPanel = {
|
|||
var childTransactions = [];
|
||||
|
||||
if (this._description) {
|
||||
let annoObj = { name : PlacesUIUtils.DESCRIPTION_ANNO,
|
||||
type : Ci.nsIAnnotationService.TYPE_STRING,
|
||||
flags : 0,
|
||||
value : this._description,
|
||||
let annoObj = { name: PlacesUIUtils.DESCRIPTION_ANNO,
|
||||
type: Ci.nsIAnnotationService.TYPE_STRING,
|
||||
flags: 0,
|
||||
value: this._description,
|
||||
expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
|
||||
let editItemTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
|
||||
childTransactions.push(editItemTxn);
|
||||
}
|
||||
|
||||
if (this._loadInSidebar) {
|
||||
let annoObj = { name : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
|
||||
value : true };
|
||||
let annoObj = { name: PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
|
||||
value: true };
|
||||
let setLoadTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
|
||||
childTransactions.push(setLoadTxn);
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ var gEditItemOverlay = {
|
|||
if (!this.initialized || !this._paneInfo.isBookmark)
|
||||
return;
|
||||
|
||||
let annotation = { name : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO };
|
||||
let annotation = { name: PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO };
|
||||
if (this._loadInSidebarCheckbox.checked)
|
||||
annotation.value = true;
|
||||
|
||||
|
|
|
@ -411,11 +411,8 @@ var PlacesOrganizer = {
|
|||
populateRestoreMenu: function PO_populateRestoreMenu() {
|
||||
let restorePopup = document.getElementById("fileRestorePopup");
|
||||
|
||||
const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global", true);
|
||||
const dtOptions = { year: "numeric", month: "long", day: "numeric" };
|
||||
let dateFormatter = new Intl.DateTimeFormat(locale, dtOptions);
|
||||
let dateFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
|
||||
|
||||
// Remove existing menu items. Last item is the restoreFromFile item.
|
||||
while (restorePopup.childNodes.length > 1)
|
||||
|
|
|
@ -499,11 +499,8 @@ PlacesTreeView.prototype = {
|
|||
__todayFormatter: null,
|
||||
get _todayFormatter() {
|
||||
if (!this.__todayFormatter) {
|
||||
const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global", true);
|
||||
const dtOptions = { hour: "numeric", minute: "numeric" };
|
||||
this.__todayFormatter = new Intl.DateTimeFormat(locale, dtOptions);
|
||||
this.__todayFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
|
||||
}
|
||||
return this.__todayFormatter;
|
||||
},
|
||||
|
@ -511,12 +508,9 @@ PlacesTreeView.prototype = {
|
|||
__dateFormatter: null,
|
||||
get _dateFormatter() {
|
||||
if (!this.__dateFormatter) {
|
||||
const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global", true);
|
||||
const dtOptions = { year: "numeric", month: "numeric", day: "numeric",
|
||||
hour: "numeric", minute: "numeric" };
|
||||
this.__dateFormatter = new Intl.DateTimeFormat(locale, dtOptions);
|
||||
this.__dateFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
|
||||
}
|
||||
return this.__dateFormatter;
|
||||
},
|
||||
|
|
|
@ -104,9 +104,6 @@
|
|||
ok(rc >= 3, "Rows found");
|
||||
let columns = tree.columns;
|
||||
ok(columns.count > 0, "Columns found");
|
||||
const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global", true);
|
||||
for (let r = 0; r < rc; r++) {
|
||||
let node = treeView.nodeForTreeIndex(r);
|
||||
ok(node, "Places node found");
|
||||
|
@ -138,7 +135,7 @@
|
|||
// a redirecting uri could be put in the tree while we test.
|
||||
break;
|
||||
}
|
||||
let timeStr = timeObj.toLocaleString(locale, dtOptions);
|
||||
let timeStr = timeObj.toLocaleString(undefined, dtOptions);
|
||||
|
||||
is(text, timeStr, "Date format is correct");
|
||||
break;
|
||||
|
|
|
@ -83,7 +83,7 @@ this.SiteDataManager = {
|
|||
promises.push(new Promise(resolve => {
|
||||
let callback = {
|
||||
onUsageResult(request) {
|
||||
site.quotaUsage = request.usage;
|
||||
site.quotaUsage = request.result.usage;
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ const UPDATE_TIME_PREF = "browser.safebrowsing.provider.mozilla.nextupdatetime";
|
|||
var gBlocklistManager = {
|
||||
_type: "",
|
||||
_blockLists: [],
|
||||
_brandShortName : null,
|
||||
_brandShortName: null,
|
||||
_bundle: null,
|
||||
_tree: null,
|
||||
|
||||
|
|
|
@ -16,12 +16,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
|
|||
"resource://gre/modules/ContextualIdentityService.jsm");
|
||||
|
||||
var gCookiesWindow = {
|
||||
_cm : Components.classes["@mozilla.org/cookiemanager;1"]
|
||||
.getService(Components.interfaces.nsICookieManager),
|
||||
_hosts : {},
|
||||
_hostOrder : [],
|
||||
_tree : null,
|
||||
_bundle : null,
|
||||
_cm: Components.classes["@mozilla.org/cookiemanager;1"]
|
||||
.getService(Components.interfaces.nsICookieManager),
|
||||
_hosts: {},
|
||||
_hostOrder: [],
|
||||
_tree: null,
|
||||
_bundle: null,
|
||||
|
||||
init() {
|
||||
var os = Components.classes["@mozilla.org/observer-service;1"]
|
||||
|
@ -194,12 +194,12 @@ var gCookiesWindow = {
|
|||
},
|
||||
|
||||
_view: {
|
||||
_filtered : false,
|
||||
_filterSet : [],
|
||||
_filtered: false,
|
||||
_filterSet: [],
|
||||
_filterValue: "",
|
||||
_rowCount : 0,
|
||||
_cacheValid : 0,
|
||||
_cacheItems : [],
|
||||
_rowCount: 0,
|
||||
_cacheValid: 0,
|
||||
_cacheItems: [],
|
||||
get rowCount() {
|
||||
return this._rowCount;
|
||||
},
|
||||
|
@ -225,7 +225,7 @@ var gCookiesWindow = {
|
|||
return currHost;
|
||||
hostIndex = count;
|
||||
|
||||
var cacheEntry = { "start" : i, "count" : count };
|
||||
var cacheEntry = { "start": i, "count": count };
|
||||
var cacheStart = count;
|
||||
|
||||
if (currHost.open) {
|
||||
|
@ -446,11 +446,11 @@ var gCookiesWindow = {
|
|||
|
||||
_addCookie(aStrippedHost, aCookie, aHostCount) {
|
||||
if (!(aStrippedHost in this._hosts) || !this._hosts[aStrippedHost]) {
|
||||
this._hosts[aStrippedHost] = { cookies : [],
|
||||
rawHost : aStrippedHost,
|
||||
level : 0,
|
||||
open : false,
|
||||
container : true };
|
||||
this._hosts[aStrippedHost] = { cookies: [],
|
||||
rawHost: aStrippedHost,
|
||||
level: 0,
|
||||
open: false,
|
||||
container: true };
|
||||
this._hostOrder.push(aStrippedHost);
|
||||
++aHostCount.value;
|
||||
}
|
||||
|
@ -460,16 +460,16 @@ var gCookiesWindow = {
|
|||
},
|
||||
|
||||
_makeCookieObject(aStrippedHost, aCookie) {
|
||||
var c = { name : aCookie.name,
|
||||
value : aCookie.value,
|
||||
isDomain : aCookie.isDomain,
|
||||
host : aCookie.host,
|
||||
rawHost : aStrippedHost,
|
||||
path : aCookie.path,
|
||||
isSecure : aCookie.isSecure,
|
||||
expires : aCookie.expires,
|
||||
level : 1,
|
||||
container : false,
|
||||
var c = { name: aCookie.name,
|
||||
value: aCookie.value,
|
||||
isDomain: aCookie.isDomain,
|
||||
host: aCookie.host,
|
||||
rawHost: aStrippedHost,
|
||||
path: aCookie.path,
|
||||
isSecure: aCookie.isSecure,
|
||||
expires: aCookie.expires,
|
||||
level: 1,
|
||||
container: false,
|
||||
originAttributes: aCookie.originAttributes };
|
||||
return c;
|
||||
},
|
||||
|
@ -497,12 +497,9 @@ var gCookiesWindow = {
|
|||
formatExpiresString(aExpires) {
|
||||
if (aExpires) {
|
||||
var date = new Date(1000 * aExpires);
|
||||
const locale = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Components.interfaces.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global", true);
|
||||
const dtOptions = { year: "numeric", month: "long", day: "numeric",
|
||||
hour: "numeric", minute: "numeric", second: "numeric" };
|
||||
return date.toLocaleString(locale, dtOptions);
|
||||
return date.toLocaleString(undefined, dtOptions);
|
||||
}
|
||||
return this._bundle.getString("expireAtEndOfSession");
|
||||
},
|
||||
|
@ -739,7 +736,7 @@ var gCookiesWindow = {
|
|||
}
|
||||
},
|
||||
|
||||
_lastSortProperty : "",
|
||||
_lastSortProperty: "",
|
||||
_lastSortAscending: false,
|
||||
sort(aProperty) {
|
||||
var ascending = (aProperty == this._lastSortProperty) ? !this._lastSortAscending : true;
|
||||
|
|
|
@ -0,0 +1,798 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from preferences.js */
|
||||
|
||||
// Load DownloadUtils module for convertByteUnits
|
||||
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SiteDataManager",
|
||||
"resource:///modules/SiteDataManager.jsm");
|
||||
|
||||
const PREF_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
|
||||
|
||||
var gAdvancedPane = {
|
||||
_inited: false,
|
||||
|
||||
/**
|
||||
* Brings the appropriate tab to the front and initializes various bits of UI.
|
||||
*/
|
||||
init() {
|
||||
function setEventListener(aId, aEventType, aCallback) {
|
||||
document.getElementById(aId)
|
||||
.addEventListener(aEventType, aCallback.bind(gAdvancedPane));
|
||||
}
|
||||
|
||||
this._inited = true;
|
||||
var advancedPrefs = document.getElementById("advancedPrefs");
|
||||
|
||||
var preference = document.getElementById("browser.preferences.advanced.selectedTabIndex");
|
||||
if (preference.value !== null)
|
||||
advancedPrefs.selectedIndex = preference.value;
|
||||
|
||||
if (AppConstants.MOZ_UPDATER) {
|
||||
let onUnload = function() {
|
||||
window.removeEventListener("unload", onUnload);
|
||||
Services.prefs.removeObserver("app.update.", this);
|
||||
}.bind(this);
|
||||
window.addEventListener("unload", onUnload);
|
||||
Services.prefs.addObserver("app.update.", this, false);
|
||||
this.updateReadPrefs();
|
||||
}
|
||||
this.updateOfflineApps();
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
this.initSubmitCrashes();
|
||||
}
|
||||
this.initTelemetry();
|
||||
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
|
||||
this.initSubmitHealthReport();
|
||||
}
|
||||
this.updateOnScreenKeyboardVisibility();
|
||||
this.updateCacheSizeInputField();
|
||||
this.updateActualCacheSize();
|
||||
this.updateActualAppCacheSize();
|
||||
|
||||
if (Services.prefs.getBoolPref("browser.storageManager.enabled")) {
|
||||
Services.obs.addObserver(this, "sitedatamanager:sites-updated", false);
|
||||
let unload = () => {
|
||||
window.removeEventListener("unload", unload);
|
||||
Services.obs.removeObserver(this, "sitedatamanager:sites-updated");
|
||||
};
|
||||
window.addEventListener("unload", unload);
|
||||
SiteDataManager.updateSites();
|
||||
setEventListener("clearSiteDataButton", "command",
|
||||
gAdvancedPane.clearSiteData);
|
||||
setEventListener("siteDataSettings", "command",
|
||||
gAdvancedPane.showSiteDataSettings);
|
||||
|
||||
let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
|
||||
document.getElementById("siteDataLearnMoreLink").setAttribute("href", url);
|
||||
}
|
||||
|
||||
setEventListener("layers.acceleration.disabled", "change",
|
||||
gAdvancedPane.updateHardwareAcceleration);
|
||||
setEventListener("advancedPrefs", "select",
|
||||
gAdvancedPane.tabSelectionChanged);
|
||||
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
|
||||
setEventListener("submitHealthReportBox", "command",
|
||||
gAdvancedPane.updateSubmitHealthReport);
|
||||
}
|
||||
|
||||
setEventListener("connectionSettings", "command",
|
||||
gAdvancedPane.showConnections);
|
||||
setEventListener("clearCacheButton", "command",
|
||||
gAdvancedPane.clearCache);
|
||||
setEventListener("clearOfflineAppCacheButton", "command",
|
||||
gAdvancedPane.clearOfflineAppCache);
|
||||
setEventListener("offlineNotifyExceptions", "command",
|
||||
gAdvancedPane.showOfflineExceptions);
|
||||
setEventListener("offlineAppsList", "select",
|
||||
gAdvancedPane.offlineAppSelected);
|
||||
let bundlePrefs = document.getElementById("bundlePreferences");
|
||||
document.getElementById("offlineAppsList")
|
||||
.style.height = bundlePrefs.getString("offlineAppsList.height");
|
||||
setEventListener("offlineAppsListRemove", "command",
|
||||
gAdvancedPane.removeOfflineApp);
|
||||
if (AppConstants.MOZ_UPDATER) {
|
||||
setEventListener("updateRadioGroup", "command",
|
||||
gAdvancedPane.updateWritePrefs);
|
||||
setEventListener("showUpdateHistory", "command",
|
||||
gAdvancedPane.showUpdates);
|
||||
}
|
||||
setEventListener("viewCertificatesButton", "command",
|
||||
gAdvancedPane.showCertificates);
|
||||
setEventListener("viewSecurityDevicesButton", "command",
|
||||
gAdvancedPane.showSecurityDevices);
|
||||
setEventListener("cacheSize", "change",
|
||||
gAdvancedPane.updateCacheSizePref);
|
||||
|
||||
if (AppConstants.MOZ_WIDGET_GTK) {
|
||||
// GTK tabbox' allow the scroll wheel to change the selected tab,
|
||||
// but we don't want this behavior for the in-content preferences.
|
||||
let tabsElement = document.getElementById("tabsElement");
|
||||
tabsElement.addEventListener("DOMMouseScroll", event => {
|
||||
event.stopPropagation();
|
||||
}, true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Stores the identity of the current tab in preferences so that the selected
|
||||
* tab can be persisted between openings of the preferences window.
|
||||
*/
|
||||
tabSelectionChanged() {
|
||||
if (!this._inited)
|
||||
return;
|
||||
var advancedPrefs = document.getElementById("advancedPrefs");
|
||||
var preference = document.getElementById("browser.preferences.advanced.selectedTabIndex");
|
||||
|
||||
// tabSelectionChanged gets called twice due to the selectedIndex being set
|
||||
// by both the selectedItem and selectedPanel callstacks. This guard is used
|
||||
// to prevent double-counting in Telemetry.
|
||||
if (preference.valueFromPreferences != advancedPrefs.selectedIndex) {
|
||||
Services.telemetry
|
||||
.getHistogramById("FX_PREFERENCES_CATEGORY_OPENED")
|
||||
.add(telemetryBucketForCategory("advanced"));
|
||||
}
|
||||
|
||||
preference.valueFromPreferences = advancedPrefs.selectedIndex;
|
||||
},
|
||||
|
||||
// GENERAL TAB
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* accessibility.browsewithcaret
|
||||
* - true enables keyboard navigation and selection within web pages using a
|
||||
* visible caret, false uses normal keyboard navigation with no caret
|
||||
* accessibility.typeaheadfind
|
||||
* - when set to true, typing outside text areas and input boxes will
|
||||
* automatically start searching for what's typed within the current
|
||||
* document; when set to false, no search action happens
|
||||
* ui.osk.enabled
|
||||
* - when set to true, subject to other conditions, we may sometimes invoke
|
||||
* an on-screen keyboard when a text input is focused.
|
||||
* (Currently Windows-only, and depending on prefs, may be Windows-8-only)
|
||||
* general.autoScroll
|
||||
* - when set to true, clicking the scroll wheel on the mouse activates a
|
||||
* mouse mode where moving the mouse down scrolls the document downward with
|
||||
* speed correlated with the distance of the cursor from the original
|
||||
* position at which the click occurred (and likewise with movement upward);
|
||||
* if false, this behavior is disabled
|
||||
* general.smoothScroll
|
||||
* - set to true to enable finer page scrolling than line-by-line on page-up,
|
||||
* page-down, and other such page movements
|
||||
* layout.spellcheckDefault
|
||||
* - an integer:
|
||||
* 0 disables spellchecking
|
||||
* 1 enables spellchecking, but only for multiline text fields
|
||||
* 2 enables spellchecking for all text fields
|
||||
*/
|
||||
|
||||
/**
|
||||
* Stores the original value of the spellchecking preference to enable proper
|
||||
* restoration if unchanged (since we're mapping a tristate onto a checkbox).
|
||||
*/
|
||||
_storedSpellCheck: 0,
|
||||
|
||||
/**
|
||||
* Returns true if any spellchecking is enabled and false otherwise, caching
|
||||
* the current value to enable proper pref restoration if the checkbox is
|
||||
* never changed.
|
||||
*/
|
||||
readCheckSpelling() {
|
||||
var pref = document.getElementById("layout.spellcheckDefault");
|
||||
this._storedSpellCheck = pref.value;
|
||||
|
||||
return (pref.value != 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the value of the spellchecking preference represented by UI,
|
||||
* preserving the preference's "hidden" value if the preference is
|
||||
* unchanged and represents a value not strictly allowed in UI.
|
||||
*/
|
||||
writeCheckSpelling() {
|
||||
var checkbox = document.getElementById("checkSpelling");
|
||||
if (checkbox.checked) {
|
||||
if (this._storedSpellCheck == 2) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* security.OCSP.enabled is an integer value for legacy reasons.
|
||||
* A value of 1 means OCSP is enabled. Any other value means it is disabled.
|
||||
*/
|
||||
readEnableOCSP() {
|
||||
var preference = document.getElementById("security.OCSP.enabled");
|
||||
// This is the case if the preference is the default value.
|
||||
if (preference.value === undefined) {
|
||||
return true;
|
||||
}
|
||||
return preference.value == 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* See documentation for readEnableOCSP.
|
||||
*/
|
||||
writeEnableOCSP() {
|
||||
var checkbox = document.getElementById("enableOCSP");
|
||||
return checkbox.checked ? 1 : 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* When the user toggles the layers.acceleration.disabled pref,
|
||||
* sync its new value to the gfx.direct2d.disabled pref too.
|
||||
*/
|
||||
updateHardwareAcceleration() {
|
||||
if (AppConstants.platform == "win") {
|
||||
var fromPref = document.getElementById("layers.acceleration.disabled");
|
||||
var toPref = document.getElementById("gfx.direct2d.disabled");
|
||||
toPref.value = fromPref.value;
|
||||
}
|
||||
},
|
||||
|
||||
// DATA CHOICES TAB
|
||||
|
||||
/**
|
||||
* Set up or hide the Learn More links for various data collection options
|
||||
*/
|
||||
_setupLearnMoreLink(pref, element) {
|
||||
// set up the Learn More link with the correct URL
|
||||
let url = Services.prefs.getCharPref(pref);
|
||||
let el = document.getElementById(element);
|
||||
|
||||
if (url) {
|
||||
el.setAttribute("href", url);
|
||||
} else {
|
||||
el.setAttribute("hidden", "true");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
initSubmitCrashes() {
|
||||
this._setupLearnMoreLink("toolkit.crashreporter.infoURL",
|
||||
"crashReporterLearnMore");
|
||||
},
|
||||
|
||||
/**
|
||||
* The preference/checkbox is configured in XUL.
|
||||
*
|
||||
* In all cases, set up the Learn More link sanely.
|
||||
*/
|
||||
initTelemetry() {
|
||||
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
|
||||
this._setupLearnMoreLink("toolkit.telemetry.infoURL", "telemetryLearnMore");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the status of the telemetry controls based on the input argument.
|
||||
* @param {Boolean} aEnabled False disables the controls, true enables them.
|
||||
*/
|
||||
setTelemetrySectionEnabled(aEnabled) {
|
||||
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
|
||||
// If FHR is disabled, additional data sharing should be disabled as well.
|
||||
let disabled = !aEnabled;
|
||||
document.getElementById("submitTelemetryBox").disabled = disabled;
|
||||
if (disabled) {
|
||||
// If we disable FHR, untick the telemetry checkbox.
|
||||
Services.prefs.setBoolPref("toolkit.telemetry.enabled", false);
|
||||
}
|
||||
document.getElementById("telemetryDataDesc").disabled = disabled;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the health report service reference and checkbox.
|
||||
*/
|
||||
initSubmitHealthReport() {
|
||||
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
|
||||
this._setupLearnMoreLink("datareporting.healthreport.infoURL", "FHRLearnMore");
|
||||
|
||||
let checkbox = document.getElementById("submitHealthReportBox");
|
||||
|
||||
if (Services.prefs.prefIsLocked(PREF_UPLOAD_ENABLED)) {
|
||||
checkbox.setAttribute("disabled", "true");
|
||||
return;
|
||||
}
|
||||
|
||||
checkbox.checked = Services.prefs.getBoolPref(PREF_UPLOAD_ENABLED);
|
||||
this.setTelemetrySectionEnabled(checkbox.checked);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the health report preference with state from checkbox.
|
||||
*/
|
||||
updateSubmitHealthReport() {
|
||||
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
|
||||
let checkbox = document.getElementById("submitHealthReportBox");
|
||||
Services.prefs.setBoolPref(PREF_UPLOAD_ENABLED, checkbox.checked);
|
||||
this.setTelemetrySectionEnabled(checkbox.checked);
|
||||
}
|
||||
},
|
||||
|
||||
updateOnScreenKeyboardVisibility() {
|
||||
if (AppConstants.platform == "win") {
|
||||
let minVersion = Services.prefs.getBoolPref("ui.osk.require_win10") ? 10 : 6.2;
|
||||
if (Services.vc.compare(Services.sysinfo.getProperty("version"), minVersion) >= 0) {
|
||||
document.getElementById("useOnScreenKeyboard").hidden = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// NETWORK TAB
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* browser.cache.disk.capacity
|
||||
* - the size of the browser cache in KB
|
||||
* - Only used if browser.cache.disk.smart_size.enabled is disabled
|
||||
*/
|
||||
|
||||
/**
|
||||
* Displays a dialog in which proxy settings may be changed.
|
||||
*/
|
||||
showConnections() {
|
||||
gSubDialog.open("chrome://browser/content/preferences/connection.xul");
|
||||
},
|
||||
|
||||
showSiteDataSettings() {
|
||||
gSubDialog.open("chrome://browser/content/preferences/siteDataSettings.xul");
|
||||
},
|
||||
|
||||
updateTotalSiteDataSize() {
|
||||
SiteDataManager.getTotalUsage()
|
||||
.then(usage => {
|
||||
let size = DownloadUtils.convertByteUnits(usage);
|
||||
let prefStrBundle = document.getElementById("bundlePreferences");
|
||||
let totalSiteDataSizeLabel = document.getElementById("totalSiteDataSize");
|
||||
totalSiteDataSizeLabel.textContent = prefStrBundle.getFormattedString("totalSiteDataSize", size);
|
||||
let siteDataGroup = document.getElementById("siteDataGroup");
|
||||
siteDataGroup.hidden = false;
|
||||
});
|
||||
},
|
||||
|
||||
// Retrieves the amount of space currently used by disk cache
|
||||
updateActualCacheSize() {
|
||||
var actualSizeLabel = document.getElementById("actualDiskCacheSize");
|
||||
var prefStrBundle = document.getElementById("bundlePreferences");
|
||||
|
||||
// Needs to root the observer since cache service keeps only a weak reference.
|
||||
this.observer = {
|
||||
onNetworkCacheDiskConsumption(consumption) {
|
||||
var size = DownloadUtils.convertByteUnits(consumption);
|
||||
// The XBL binding for the string bundle may have been destroyed if
|
||||
// the page was closed before this callback was executed.
|
||||
if (!prefStrBundle.getFormattedString) {
|
||||
return;
|
||||
}
|
||||
actualSizeLabel.value = prefStrBundle.getFormattedString("actualDiskCacheSize", size);
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Components.interfaces.nsICacheStorageConsumptionObserver,
|
||||
Components.interfaces.nsISupportsWeakReference
|
||||
])
|
||||
};
|
||||
|
||||
actualSizeLabel.value = prefStrBundle.getString("actualDiskCacheSizeCalculated");
|
||||
|
||||
try {
|
||||
var cacheService =
|
||||
Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Components.interfaces.nsICacheStorageService);
|
||||
cacheService.asyncGetDiskConsumption(this.observer);
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
// Retrieves the amount of space currently used by offline cache
|
||||
updateActualAppCacheSize() {
|
||||
var visitor = {
|
||||
onCacheStorageInfo(aEntryCount, aConsumption, aCapacity, aDiskDirectory) {
|
||||
var actualSizeLabel = document.getElementById("actualAppCacheSize");
|
||||
var sizeStrings = DownloadUtils.convertByteUnits(aConsumption);
|
||||
var prefStrBundle = document.getElementById("bundlePreferences");
|
||||
// The XBL binding for the string bundle may have been destroyed if
|
||||
// the page was closed before this callback was executed.
|
||||
if (!prefStrBundle.getFormattedString) {
|
||||
return;
|
||||
}
|
||||
var sizeStr = prefStrBundle.getFormattedString("actualAppCacheSize", sizeStrings);
|
||||
actualSizeLabel.value = sizeStr;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
var cacheService =
|
||||
Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Components.interfaces.nsICacheStorageService);
|
||||
var storage = cacheService.appCacheStorage(LoadContextInfo.default, null);
|
||||
storage.asyncVisitStorage(visitor, false);
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
updateCacheSizeUI(smartSizeEnabled) {
|
||||
document.getElementById("useCacheBefore").disabled = smartSizeEnabled;
|
||||
document.getElementById("cacheSize").disabled = smartSizeEnabled;
|
||||
document.getElementById("useCacheAfter").disabled = smartSizeEnabled;
|
||||
},
|
||||
|
||||
readSmartSizeEnabled() {
|
||||
// The smart_size.enabled preference element is inverted="true", so its
|
||||
// value is the opposite of the actual pref value
|
||||
var disabled = document.getElementById("browser.cache.disk.smart_size.enabled").value;
|
||||
this.updateCacheSizeUI(!disabled);
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts the cache size from units of KB to units of MB and stores it in
|
||||
* the textbox element.
|
||||
*/
|
||||
updateCacheSizeInputField() {
|
||||
let cacheSizeElem = document.getElementById("cacheSize");
|
||||
let cachePref = document.getElementById("browser.cache.disk.capacity");
|
||||
cacheSizeElem.value = cachePref.value / 1024;
|
||||
if (cachePref.locked)
|
||||
cacheSizeElem.disabled = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the cache size preference once user enters a new value.
|
||||
* We intentionally do not set preference="browser.cache.disk.capacity"
|
||||
* onto the textbox directly, as that would update the pref at each keypress
|
||||
* not only after the final value is entered.
|
||||
*/
|
||||
updateCacheSizePref() {
|
||||
let cacheSizeElem = document.getElementById("cacheSize");
|
||||
let cachePref = document.getElementById("browser.cache.disk.capacity");
|
||||
// Converts the cache size as specified in UI (in MB) to KB.
|
||||
let intValue = parseInt(cacheSizeElem.value, 10);
|
||||
cachePref.value = isNaN(intValue) ? 0 : intValue * 1024;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the cache.
|
||||
*/
|
||||
clearCache() {
|
||||
try {
|
||||
var cache = Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Components.interfaces.nsICacheStorageService);
|
||||
cache.clear();
|
||||
} catch (ex) {}
|
||||
this.updateActualCacheSize();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the application cache.
|
||||
*/
|
||||
clearOfflineAppCache() {
|
||||
Components.utils.import("resource:///modules/offlineAppCache.jsm");
|
||||
OfflineAppCacheHelper.clear();
|
||||
|
||||
this.updateActualAppCacheSize();
|
||||
this.updateOfflineApps();
|
||||
},
|
||||
|
||||
clearSiteData() {
|
||||
let flags =
|
||||
Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
|
||||
Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 +
|
||||
Services.prompt.BUTTON_POS_0_DEFAULT;
|
||||
let prefStrBundle = document.getElementById("bundlePreferences");
|
||||
let title = prefStrBundle.getString("clearSiteDataPromptTitle");
|
||||
let text = prefStrBundle.getString("clearSiteDataPromptText");
|
||||
let btn0Label = prefStrBundle.getString("clearSiteDataNow");
|
||||
|
||||
let result = Services.prompt.confirmEx(
|
||||
window, title, text, flags, btn0Label, null, null, null, {});
|
||||
if (result == 0) {
|
||||
SiteDataManager.removeAll();
|
||||
}
|
||||
},
|
||||
|
||||
readOfflineNotify() {
|
||||
var pref = document.getElementById("browser.offline-apps.notify");
|
||||
var button = document.getElementById("offlineNotifyExceptions");
|
||||
button.disabled = !pref.value;
|
||||
return pref.value;
|
||||
},
|
||||
|
||||
showOfflineExceptions() {
|
||||
var bundlePreferences = document.getElementById("bundlePreferences");
|
||||
var params = { blockVisible: false,
|
||||
sessionVisible: false,
|
||||
allowVisible: false,
|
||||
prefilledHost: "",
|
||||
permissionType: "offline-app",
|
||||
manageCapability: Components.interfaces.nsIPermissionManager.DENY_ACTION,
|
||||
windowTitle: bundlePreferences.getString("offlinepermissionstitle"),
|
||||
introText: bundlePreferences.getString("offlinepermissionstext") };
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
null, params);
|
||||
},
|
||||
|
||||
// XXX: duplicated in browser.js
|
||||
_getOfflineAppUsage(perm, groups) {
|
||||
let cacheService = Cc["@mozilla.org/network/application-cache-service;1"].
|
||||
getService(Ci.nsIApplicationCacheService);
|
||||
if (!groups) {
|
||||
try {
|
||||
groups = cacheService.getGroups();
|
||||
} catch (ex) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
let usage = 0;
|
||||
for (let group of groups) {
|
||||
let uri = Services.io.newURI(group);
|
||||
if (perm.matchesURI(uri, true)) {
|
||||
let cache = cacheService.getActiveCache(group);
|
||||
usage += cache.usage;
|
||||
}
|
||||
}
|
||||
|
||||
return usage;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the list of offline applications
|
||||
*/
|
||||
updateOfflineApps() {
|
||||
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager);
|
||||
|
||||
var list = document.getElementById("offlineAppsList");
|
||||
while (list.firstChild) {
|
||||
list.firstChild.remove();
|
||||
}
|
||||
|
||||
var groups;
|
||||
try {
|
||||
var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
|
||||
getService(Components.interfaces.nsIApplicationCacheService);
|
||||
groups = cacheService.getGroups();
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bundle = document.getElementById("bundlePreferences");
|
||||
|
||||
var enumerator = pm.enumerator;
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var perm = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission);
|
||||
if (perm.type == "offline-app" &&
|
||||
perm.capability != Components.interfaces.nsIPermissionManager.DEFAULT_ACTION &&
|
||||
perm.capability != Components.interfaces.nsIPermissionManager.DENY_ACTION) {
|
||||
var row = document.createElement("listitem");
|
||||
row.id = "";
|
||||
row.className = "offlineapp";
|
||||
row.setAttribute("origin", perm.principal.origin);
|
||||
var converted = DownloadUtils.
|
||||
convertByteUnits(this._getOfflineAppUsage(perm, groups));
|
||||
row.setAttribute("usage",
|
||||
bundle.getFormattedString("offlineAppUsage",
|
||||
converted));
|
||||
list.appendChild(row);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
offlineAppSelected() {
|
||||
var removeButton = document.getElementById("offlineAppsListRemove");
|
||||
var list = document.getElementById("offlineAppsList");
|
||||
if (list.selectedItem) {
|
||||
removeButton.setAttribute("disabled", "false");
|
||||
} else {
|
||||
removeButton.setAttribute("disabled", "true");
|
||||
}
|
||||
},
|
||||
|
||||
removeOfflineApp() {
|
||||
var list = document.getElementById("offlineAppsList");
|
||||
var item = list.selectedItem;
|
||||
var origin = item.getAttribute("origin");
|
||||
var principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin);
|
||||
|
||||
var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
var flags = prompts.BUTTON_TITLE_IS_STRING * prompts.BUTTON_POS_0 +
|
||||
prompts.BUTTON_TITLE_CANCEL * prompts.BUTTON_POS_1;
|
||||
|
||||
var bundle = document.getElementById("bundlePreferences");
|
||||
var title = bundle.getString("offlineAppRemoveTitle");
|
||||
var prompt = bundle.getFormattedString("offlineAppRemovePrompt", [principal.URI.prePath]);
|
||||
var confirm = bundle.getString("offlineAppRemoveConfirm");
|
||||
var result = prompts.confirmEx(window, title, prompt, flags, confirm,
|
||||
null, null, null, {});
|
||||
if (result != 0)
|
||||
return;
|
||||
|
||||
// get the permission
|
||||
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager);
|
||||
var perm = pm.getPermissionObject(principal, "offline-app", true);
|
||||
if (perm) {
|
||||
// clear offline cache entries
|
||||
try {
|
||||
var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
|
||||
getService(Components.interfaces.nsIApplicationCacheService);
|
||||
var groups = cacheService.getGroups();
|
||||
for (var i = 0; i < groups.length; i++) {
|
||||
var uri = Services.io.newURI(groups[i]);
|
||||
if (perm.matchesURI(uri, true)) {
|
||||
var cache = cacheService.getActiveCache(groups[i]);
|
||||
cache.discard();
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
pm.removePermission(perm);
|
||||
}
|
||||
list.removeChild(item);
|
||||
gAdvancedPane.offlineAppSelected();
|
||||
this.updateActualAppCacheSize();
|
||||
},
|
||||
|
||||
// UPDATE TAB
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* app.update.enabled
|
||||
* - true if updates to the application are enabled, false otherwise
|
||||
* app.update.auto
|
||||
* - true if updates should be automatically downloaded and installed and
|
||||
* false if the user should be asked what he wants to do when an update is
|
||||
* available
|
||||
* extensions.update.enabled
|
||||
* - true if updates to extensions and themes are enabled, false otherwise
|
||||
* browser.search.update
|
||||
* - true if updates to search engines are enabled, false otherwise
|
||||
*/
|
||||
|
||||
/**
|
||||
* Selects the item of the radiogroup based on the pref values and locked
|
||||
* states.
|
||||
*
|
||||
* UI state matrix for update preference conditions
|
||||
*
|
||||
* UI Components: Preferences
|
||||
* Radiogroup i = app.update.enabled
|
||||
* ii = app.update.auto
|
||||
*
|
||||
* Disabled states:
|
||||
* Element pref value locked disabled
|
||||
* radiogroup i t/f f false
|
||||
* i t/f *t* *true*
|
||||
* ii t/f f false
|
||||
* ii t/f *t* *true*
|
||||
*/
|
||||
updateReadPrefs() {
|
||||
if (AppConstants.MOZ_UPDATER) {
|
||||
var enabledPref = document.getElementById("app.update.enabled");
|
||||
var autoPref = document.getElementById("app.update.auto");
|
||||
var radiogroup = document.getElementById("updateRadioGroup");
|
||||
|
||||
if (!enabledPref.value) // Don't care for autoPref.value in this case.
|
||||
radiogroup.value = "manual"; // 3. Never check for updates.
|
||||
else if (autoPref.value) // enabledPref.value && autoPref.value
|
||||
radiogroup.value = "auto"; // 1. Automatically install updates
|
||||
else // enabledPref.value && !autoPref.value
|
||||
radiogroup.value = "checkOnly"; // 2. Check, but let me choose
|
||||
|
||||
var canCheck = Components.classes["@mozilla.org/updates/update-service;1"].
|
||||
getService(Components.interfaces.nsIApplicationUpdateService).
|
||||
canCheckForUpdates;
|
||||
// canCheck is false if the enabledPref is false and locked,
|
||||
// or the binary platform or OS version is not known.
|
||||
// A locked pref is sufficient to disable the radiogroup.
|
||||
radiogroup.disabled = !canCheck || enabledPref.locked || autoPref.locked;
|
||||
|
||||
if (AppConstants.MOZ_MAINTENANCE_SERVICE) {
|
||||
// Check to see if the maintenance service is installed.
|
||||
// If it is don't show the preference at all.
|
||||
var installed;
|
||||
try {
|
||||
var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
|
||||
.createInstance(Components.interfaces.nsIWindowsRegKey);
|
||||
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Mozilla\\MaintenanceService",
|
||||
wrk.ACCESS_READ | wrk.WOW64_64);
|
||||
installed = wrk.readIntValue("Installed");
|
||||
wrk.close();
|
||||
} catch (e) {
|
||||
}
|
||||
if (installed != 1) {
|
||||
document.getElementById("useService").hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the pref values based on the selected item of the radiogroup.
|
||||
*/
|
||||
updateWritePrefs() {
|
||||
if (AppConstants.MOZ_UPDATER) {
|
||||
var enabledPref = document.getElementById("app.update.enabled");
|
||||
var autoPref = document.getElementById("app.update.auto");
|
||||
var radiogroup = document.getElementById("updateRadioGroup");
|
||||
switch (radiogroup.value) {
|
||||
case "auto": // 1. Automatically install updates for Desktop only
|
||||
enabledPref.value = true;
|
||||
autoPref.value = true;
|
||||
break;
|
||||
case "checkOnly": // 2. Check, but let me choose
|
||||
enabledPref.value = true;
|
||||
autoPref.value = false;
|
||||
break;
|
||||
case "manual": // 3. Never check for updates.
|
||||
enabledPref.value = false;
|
||||
autoPref.value = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the history of installed updates.
|
||||
*/
|
||||
showUpdates() {
|
||||
gSubDialog.open("chrome://mozapps/content/update/history.xul");
|
||||
},
|
||||
|
||||
// ENCRYPTION TAB
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* security.default_personal_cert
|
||||
* - a string:
|
||||
* "Select Automatically" select a certificate automatically when a site
|
||||
* requests one
|
||||
* "Ask Every Time" present a dialog to the user so he can select
|
||||
* the certificate to use on a site which
|
||||
* requests one
|
||||
*/
|
||||
|
||||
/**
|
||||
* Displays the user's certificates and associated options.
|
||||
*/
|
||||
showCertificates() {
|
||||
gSubDialog.open("chrome://pippki/content/certManager.xul");
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a dialog from which the user can manage his security devices.
|
||||
*/
|
||||
showSecurityDevices() {
|
||||
gSubDialog.open("chrome://pippki/content/device_manager.xul");
|
||||
},
|
||||
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (AppConstants.MOZ_UPDATER) {
|
||||
switch (aTopic) {
|
||||
case "nsPref:changed":
|
||||
this.updateReadPrefs();
|
||||
break;
|
||||
|
||||
case "sitedatamanager:sites-updated":
|
||||
this.updateTotalSiteDataSize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
|
@ -0,0 +1,436 @@
|
|||
# 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/.
|
||||
|
||||
<!-- Advanced panel -->
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/advanced.js"/>
|
||||
|
||||
<preferences id="advancedPreferences" hidden="true" data-category="paneAdvanced">
|
||||
<preference id="browser.preferences.advanced.selectedTabIndex"
|
||||
name="browser.preferences.advanced.selectedTabIndex"
|
||||
type="int"/>
|
||||
|
||||
<!-- General tab -->
|
||||
<preference id="accessibility.browsewithcaret"
|
||||
name="accessibility.browsewithcaret"
|
||||
type="bool"/>
|
||||
<preference id="accessibility.typeaheadfind"
|
||||
name="accessibility.typeaheadfind"
|
||||
type="bool"/>
|
||||
<preference id="accessibility.blockautorefresh"
|
||||
name="accessibility.blockautorefresh"
|
||||
type="bool"/>
|
||||
#ifdef XP_WIN
|
||||
<preference id="ui.osk.enabled"
|
||||
name="ui.osk.enabled"
|
||||
type="bool"/>
|
||||
#endif
|
||||
|
||||
<preference id="general.autoScroll"
|
||||
name="general.autoScroll"
|
||||
type="bool"/>
|
||||
<preference id="general.smoothScroll"
|
||||
name="general.smoothScroll"
|
||||
type="bool"/>
|
||||
<preference id="layers.acceleration.disabled"
|
||||
name="layers.acceleration.disabled"
|
||||
type="bool"
|
||||
inverted="true"/>
|
||||
#ifdef XP_WIN
|
||||
<preference id="gfx.direct2d.disabled"
|
||||
name="gfx.direct2d.disabled"
|
||||
type="bool"
|
||||
inverted="true"/>
|
||||
#endif
|
||||
<preference id="layout.spellcheckDefault"
|
||||
name="layout.spellcheckDefault"
|
||||
type="int"/>
|
||||
|
||||
#ifdef MOZ_TELEMETRY_REPORTING
|
||||
<preference id="toolkit.telemetry.enabled"
|
||||
name="toolkit.telemetry.enabled"
|
||||
type="bool"/>
|
||||
#endif
|
||||
|
||||
<!-- Data Choices tab -->
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
<preference id="browser.crashReports.unsubmittedCheck.autoSubmit"
|
||||
name="browser.crashReports.unsubmittedCheck.autoSubmit"
|
||||
type="bool"/>
|
||||
#endif
|
||||
|
||||
<!-- Network tab -->
|
||||
<preference id="browser.cache.disk.capacity"
|
||||
name="browser.cache.disk.capacity"
|
||||
type="int"/>
|
||||
<preference id="browser.offline-apps.notify"
|
||||
name="browser.offline-apps.notify"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="browser.cache.disk.smart_size.enabled"
|
||||
name="browser.cache.disk.smart_size.enabled"
|
||||
inverted="true"
|
||||
type="bool"/>
|
||||
|
||||
<!-- Update tab -->
|
||||
#ifdef MOZ_UPDATER
|
||||
<preference id="app.update.enabled"
|
||||
name="app.update.enabled"
|
||||
type="bool"/>
|
||||
<preference id="app.update.auto"
|
||||
name="app.update.auto"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="app.update.disable_button.showUpdateHistory"
|
||||
name="app.update.disable_button.showUpdateHistory"
|
||||
type="bool"/>
|
||||
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
<preference id="app.update.service.enabled"
|
||||
name="app.update.service.enabled"
|
||||
type="bool"/>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
<preference id="browser.search.update"
|
||||
name="browser.search.update"
|
||||
type="bool"/>
|
||||
|
||||
<!-- Certificates tab -->
|
||||
<preference id="security.default_personal_cert"
|
||||
name="security.default_personal_cert"
|
||||
type="string"/>
|
||||
|
||||
<preference id="security.disable_button.openCertManager"
|
||||
name="security.disable_button.openCertManager"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="security.disable_button.openDeviceManager"
|
||||
name="security.disable_button.openDeviceManager"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="security.OCSP.enabled"
|
||||
name="security.OCSP.enabled"
|
||||
type="int"/>
|
||||
</preferences>
|
||||
|
||||
#ifdef HAVE_SHELL_SERVICE
|
||||
<stringbundle id="bundleShell" src="chrome://browser/locale/shellservice.properties"/>
|
||||
<stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
|
||||
#endif
|
||||
<stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences-old/preferences.properties"/>
|
||||
|
||||
<hbox id="header-advanced"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneAdvanced">
|
||||
<label class="header-name" flex="1">&paneAdvanced.title;</label>
|
||||
<html:a class="help-button" target="_blank" aria-label="&helpButton.label;"></html:a>
|
||||
</hbox>
|
||||
|
||||
<tabbox id="advancedPrefs"
|
||||
handleCtrlTab="false"
|
||||
handleCtrlPageUpDown="false"
|
||||
flex="1"
|
||||
data-category="paneAdvanced"
|
||||
hidden="true">
|
||||
|
||||
<tabs id="tabsElement">
|
||||
<tab id="generalTab" label="&generalTab.label;"/>
|
||||
#ifdef MOZ_DATA_REPORTING
|
||||
<tab id="dataChoicesTab" label="&dataChoicesTab.label;"/>
|
||||
#endif
|
||||
<tab id="networkTab" label="&networkTab.label;"/>
|
||||
<tab id="updateTab" label="&updateTab.label;"/>
|
||||
<tab id="encryptionTab" label="&certificateTab.label;"/>
|
||||
</tabs>
|
||||
|
||||
<tabpanels flex="1">
|
||||
|
||||
<!-- General -->
|
||||
<tabpanel id="generalPanel" orient="vertical">
|
||||
<!-- Accessibility -->
|
||||
<groupbox id="accessibilityGroup" align="start">
|
||||
<caption><label>&accessibility.label;</label></caption>
|
||||
|
||||
#ifdef XP_WIN
|
||||
<checkbox id="useOnScreenKeyboard"
|
||||
hidden="true"
|
||||
label="&useOnScreenKeyboard.label;"
|
||||
accesskey="&useOnScreenKeyboard.accesskey;"
|
||||
preference="ui.osk.enabled"/>
|
||||
#endif
|
||||
<checkbox id="useCursorNavigation"
|
||||
label="&useCursorNavigation.label;"
|
||||
accesskey="&useCursorNavigation.accesskey;"
|
||||
preference="accessibility.browsewithcaret"/>
|
||||
<checkbox id="searchStartTyping"
|
||||
label="&searchOnStartTyping.label;"
|
||||
accesskey="&searchOnStartTyping.accesskey;"
|
||||
preference="accessibility.typeaheadfind"/>
|
||||
<checkbox id="blockAutoRefresh"
|
||||
label="&blockAutoReload.label;"
|
||||
accesskey="&blockAutoReload.accesskey;"
|
||||
preference="accessibility.blockautorefresh"/>
|
||||
</groupbox>
|
||||
<!-- Browsing -->
|
||||
<groupbox id="browsingGroup" align="start">
|
||||
<caption><label>&browsing.label;</label></caption>
|
||||
|
||||
<checkbox id="useAutoScroll"
|
||||
label="&useAutoScroll.label;"
|
||||
accesskey="&useAutoScroll.accesskey;"
|
||||
preference="general.autoScroll"/>
|
||||
<checkbox id="useSmoothScrolling"
|
||||
label="&useSmoothScrolling.label;"
|
||||
accesskey="&useSmoothScrolling.accesskey;"
|
||||
preference="general.smoothScroll"/>
|
||||
<checkbox id="allowHWAccel"
|
||||
label="&allowHWAccel.label;"
|
||||
accesskey="&allowHWAccel.accesskey;"
|
||||
preference="layers.acceleration.disabled"/>
|
||||
<checkbox id="checkSpelling"
|
||||
label="&checkUserSpelling.label;"
|
||||
accesskey="&checkUserSpelling.accesskey;"
|
||||
onsyncfrompreference="return gAdvancedPane.readCheckSpelling();"
|
||||
onsynctopreference="return gAdvancedPane.writeCheckSpelling();"
|
||||
preference="layout.spellcheckDefault"/>
|
||||
</groupbox>
|
||||
</tabpanel>
|
||||
#ifdef MOZ_DATA_REPORTING
|
||||
<!-- Data Choices -->
|
||||
<tabpanel id="dataChoicesPanel" orient="vertical">
|
||||
#ifdef MOZ_TELEMETRY_REPORTING
|
||||
<groupbox>
|
||||
<caption>
|
||||
<checkbox id="submitHealthReportBox" label="&enableHealthReport.label;"
|
||||
accesskey="&enableHealthReport.accesskey;"/>
|
||||
</caption>
|
||||
<vbox>
|
||||
<hbox class="indent" flex="1">
|
||||
<label flex="1">&healthReportDesc.label;</label>
|
||||
<label id="FHRLearnMore" flex="1"
|
||||
class="learnMore text-link">&healthReportLearnMore.label;</label>
|
||||
</hbox>
|
||||
<hbox class="indent">
|
||||
<groupbox flex="1">
|
||||
<caption>
|
||||
<checkbox id="submitTelemetryBox" preference="toolkit.telemetry.enabled"
|
||||
label="&enableTelemetryData.label;"
|
||||
accesskey="&enableTelemetryData.accesskey;"/>
|
||||
</caption>
|
||||
<hbox class="indent" flex="1">
|
||||
<label id="telemetryDataDesc" flex="1">&telemetryDesc.label;</label>
|
||||
<label id="telemetryLearnMore" flex="1"
|
||||
class="learnMore text-link">&telemetryLearnMore.label;</label>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
#endif
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
<groupbox>
|
||||
<caption>
|
||||
<checkbox id="automaticallySubmitCrashesBox"
|
||||
preference="browser.crashReports.unsubmittedCheck.autoSubmit"
|
||||
label="&alwaysSubmitCrashReports.label;"
|
||||
accesskey="&alwaysSubmitCrashReports.accesskey;"/>
|
||||
</caption>
|
||||
<hbox class="indent" flex="1">
|
||||
<label flex="1">&crashReporterDesc2.label;</label>
|
||||
<label id="crashReporterLearnMore" flex="1"
|
||||
class="learnMore text-link">&crashReporterLearnMore.label;</label>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
#endif
|
||||
</tabpanel>
|
||||
#endif
|
||||
|
||||
<!-- Network -->
|
||||
<tabpanel id="networkPanel" orient="vertical">
|
||||
|
||||
<!-- Connection -->
|
||||
<groupbox id="connectionGroup">
|
||||
<caption><label>&connection.label;</label></caption>
|
||||
|
||||
<hbox align="center">
|
||||
<description flex="1" control="connectionSettings">&connectionDesc.label;</description>
|
||||
<button id="connectionSettings" icon="network" label="&connectionSettings.label;"
|
||||
accesskey="&connectionSettings.accesskey;"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<!-- Cache -->
|
||||
<groupbox id="cacheGroup">
|
||||
<caption><label>&httpCache.label;</label></caption>
|
||||
|
||||
<hbox align="center">
|
||||
<label id="actualDiskCacheSize" flex="1"/>
|
||||
<button id="clearCacheButton" icon="clear"
|
||||
label="&clearCacheNow.label;" accesskey="&clearCacheNow.accesskey;"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<checkbox preference="browser.cache.disk.smart_size.enabled"
|
||||
id="allowSmartSize"
|
||||
onsyncfrompreference="return gAdvancedPane.readSmartSizeEnabled();"
|
||||
label="&overrideSmartCacheSize.label;"
|
||||
accesskey="&overrideSmartCacheSize.accesskey;"/>
|
||||
</hbox>
|
||||
<hbox align="center" class="indent">
|
||||
<label id="useCacheBefore" control="cacheSize"
|
||||
accesskey="&limitCacheSizeBefore.accesskey;">
|
||||
&limitCacheSizeBefore.label;
|
||||
</label>
|
||||
<textbox id="cacheSize" type="number" size="4" max="1024"
|
||||
aria-labelledby="useCacheBefore cacheSize useCacheAfter"/>
|
||||
<label id="useCacheAfter" flex="1">&limitCacheSizeAfter.label;</label>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<!-- Offline apps -->
|
||||
<groupbox id="offlineGroup">
|
||||
<caption><label>&offlineStorage2.label;</label></caption>
|
||||
|
||||
<hbox align="center">
|
||||
<label id="actualAppCacheSize" flex="1"/>
|
||||
<button id="clearOfflineAppCacheButton" icon="clear"
|
||||
label="&clearOfflineAppCacheNow.label;" accesskey="&clearOfflineAppCacheNow.accesskey;"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<checkbox id="offlineNotify"
|
||||
label="&offlineStorageNotify.label;" accesskey="&offlineStorageNotify.accesskey;"
|
||||
preference="browser.offline-apps.notify"
|
||||
onsyncfrompreference="return gAdvancedPane.readOfflineNotify();"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="offlineNotifyExceptions"
|
||||
label="&offlineStorageNotifyExceptions.label;"
|
||||
accesskey="&offlineStorageNotifyExceptions.accesskey;"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<vbox flex="1">
|
||||
<label id="offlineAppsListLabel">&offlineAppsList2.label;</label>
|
||||
<listbox id="offlineAppsList"
|
||||
flex="1"
|
||||
aria-labelledby="offlineAppsListLabel">
|
||||
</listbox>
|
||||
</vbox>
|
||||
<vbox pack="end">
|
||||
<button id="offlineAppsListRemove"
|
||||
disabled="true"
|
||||
label="&offlineAppsListRemove.label;"
|
||||
accesskey="&offlineAppsListRemove.accesskey;"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<!-- Site Data -->
|
||||
<groupbox id="siteDataGroup" hidden="true">
|
||||
<caption><label>&siteData.label;</label></caption>
|
||||
|
||||
<hbox align="baseline">
|
||||
<label id="totalSiteDataSize"></label>
|
||||
<label id="siteDataLearnMoreLink" class="learnMore text-link" value="&siteDataLearnMoreLink.label;"></label>
|
||||
<spacer flex="1" />
|
||||
<button id="clearSiteDataButton" icon="clear"
|
||||
label="&clearSiteData.label;" accesskey="&clearSiteData.accesskey;"/>
|
||||
</hbox>
|
||||
<vbox align="end">
|
||||
<button id="siteDataSettings"
|
||||
label="&siteDataSettings.label;"
|
||||
accesskey="&siteDataSettings.accesskey;"/>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
</tabpanel>
|
||||
|
||||
<!-- Update -->
|
||||
<tabpanel id="updatePanel" orient="vertical">
|
||||
#ifdef MOZ_UPDATER
|
||||
<groupbox id="updateApp" align="start">
|
||||
<caption><label>&updateApplication.label;</label></caption>
|
||||
<radiogroup id="updateRadioGroup" align="start">
|
||||
<radio id="autoDesktop"
|
||||
value="auto"
|
||||
label="&updateAuto1.label;"
|
||||
accesskey="&updateAuto1.accesskey;"/>
|
||||
<radio value="checkOnly"
|
||||
label="&updateCheckChoose.label;"
|
||||
accesskey="&updateCheckChoose.accesskey;"/>
|
||||
<radio value="manual"
|
||||
label="&updateManual.label;"
|
||||
accesskey="&updateManual.accesskey;"/>
|
||||
</radiogroup>
|
||||
<separator class="thin"/>
|
||||
<hbox>
|
||||
<button id="showUpdateHistory"
|
||||
label="&updateHistory.label;"
|
||||
accesskey="&updateHistory.accesskey;"
|
||||
preference="app.update.disable_button.showUpdateHistory"/>
|
||||
</hbox>
|
||||
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
<checkbox id="useService"
|
||||
label="&useService.label;"
|
||||
accesskey="&useService.accesskey;"
|
||||
preference="app.update.service.enabled"/>
|
||||
#endif
|
||||
</groupbox>
|
||||
#endif
|
||||
<groupbox id="updateOthers" align="start">
|
||||
<caption><label>&autoUpdateOthers.label;</label></caption>
|
||||
<checkbox id="enableSearchUpdate"
|
||||
label="&enableSearchUpdate.label;"
|
||||
accesskey="&enableSearchUpdate.accesskey;"
|
||||
preference="browser.search.update"/>
|
||||
</groupbox>
|
||||
</tabpanel>
|
||||
|
||||
<!-- Certificates -->
|
||||
<tabpanel id="encryptionPanel" orient="vertical">
|
||||
<groupbox id="certSelection" align="start">
|
||||
<caption><label>&certPersonal.label;</label></caption>
|
||||
<description id="CertSelectionDesc" control="certSelection">&certPersonal.description;</description>
|
||||
|
||||
<!--
|
||||
The values on these radio buttons may look like l12y issues, but
|
||||
they're not - this preference uses *those strings* as its values.
|
||||
I KID YOU NOT.
|
||||
-->
|
||||
<radiogroup id="certSelection"
|
||||
preftype="string"
|
||||
preference="security.default_personal_cert"
|
||||
aria-labelledby="CertSelectionDesc">
|
||||
<radio label="&selectCerts.auto;"
|
||||
accesskey="&selectCerts.auto.accesskey;"
|
||||
value="Select Automatically"/>
|
||||
<radio label="&selectCerts.ask;"
|
||||
accesskey="&selectCerts.ask.accesskey;"
|
||||
value="Ask Every Time"/>
|
||||
</radiogroup>
|
||||
</groupbox>
|
||||
<separator/>
|
||||
<checkbox id="enableOCSP"
|
||||
label="&enableOCSP.label;"
|
||||
accesskey="&enableOCSP.accesskey;"
|
||||
onsyncfrompreference="return gAdvancedPane.readEnableOCSP();"
|
||||
onsynctopreference="return gAdvancedPane.writeEnableOCSP();"
|
||||
preference="security.OCSP.enabled"/>
|
||||
<separator/>
|
||||
<hbox>
|
||||
<button id="viewCertificatesButton"
|
||||
flex="1"
|
||||
label="&viewCerts.label;"
|
||||
accesskey="&viewCerts.accesskey;"
|
||||
preference="security.disable_button.openCertManager"/>
|
||||
<button id="viewSecurityDevicesButton"
|
||||
flex="1"
|
||||
label="&viewSecurityDevices.label;"
|
||||
accesskey="&viewSecurityDevices.accesskey;"
|
||||
preference="security.disable_button.openDeviceManager"/>
|
||||
<hbox flex="10"/>
|
||||
</hbox>
|
||||
</tabpanel>
|
||||
</tabpanels>
|
||||
</tabbox>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,95 @@
|
|||
# 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/.
|
||||
|
||||
<!-- Applications panel -->
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/applications.js"/>
|
||||
|
||||
<preferences id="feedsPreferences" hidden="true" data-category="paneApplications">
|
||||
<preference id="browser.feeds.handler"
|
||||
name="browser.feeds.handler"
|
||||
type="string"/>
|
||||
<preference id="browser.feeds.handler.default"
|
||||
name="browser.feeds.handler.default"
|
||||
type="string"/>
|
||||
<preference id="browser.feeds.handlers.application"
|
||||
name="browser.feeds.handlers.application"
|
||||
type="file"/>
|
||||
<preference id="browser.feeds.handlers.webservice"
|
||||
name="browser.feeds.handlers.webservice"
|
||||
type="string"/>
|
||||
|
||||
<preference id="browser.videoFeeds.handler"
|
||||
name="browser.videoFeeds.handler"
|
||||
type="string"/>
|
||||
<preference id="browser.videoFeeds.handler.default"
|
||||
name="browser.videoFeeds.handler.default"
|
||||
type="string"/>
|
||||
<preference id="browser.videoFeeds.handlers.application"
|
||||
name="browser.videoFeeds.handlers.application"
|
||||
type="file"/>
|
||||
<preference id="browser.videoFeeds.handlers.webservice"
|
||||
name="browser.videoFeeds.handlers.webservice"
|
||||
type="string"/>
|
||||
|
||||
<preference id="browser.audioFeeds.handler"
|
||||
name="browser.audioFeeds.handler"
|
||||
type="string"/>
|
||||
<preference id="browser.audioFeeds.handler.default"
|
||||
name="browser.audioFeeds.handler.default"
|
||||
type="string"/>
|
||||
<preference id="browser.audioFeeds.handlers.application"
|
||||
name="browser.audioFeeds.handlers.application"
|
||||
type="file"/>
|
||||
<preference id="browser.audioFeeds.handlers.webservice"
|
||||
name="browser.audioFeeds.handlers.webservice"
|
||||
type="string"/>
|
||||
|
||||
<preference id="pref.downloads.disable_button.edit_actions"
|
||||
name="pref.downloads.disable_button.edit_actions"
|
||||
type="bool"/>
|
||||
</preferences>
|
||||
|
||||
<keyset data-category="paneApplications">
|
||||
<!-- Ctrl+f/k focus the search box in the Applications pane.
|
||||
These <key>s have oncommand attributes because of bug 371900. -->
|
||||
<key key="&focusSearch1.key;" modifiers="accel" id="focusSearch1" oncommand=";"/>
|
||||
<key key="&focusSearch2.key;" modifiers="accel" id="focusSearch2" oncommand=";"/>
|
||||
</keyset>
|
||||
|
||||
<hbox id="header-applications"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneApplications">
|
||||
<label class="header-name" flex="1">&paneApplications.title;</label>
|
||||
<html:a class="help-button" target="_blank" aria-label="&helpButton.label;"></html:a>
|
||||
</hbox>
|
||||
|
||||
<vbox id="applicationsContent"
|
||||
data-category="paneApplications"
|
||||
hidden="true"
|
||||
flex="1">
|
||||
<hbox>
|
||||
<textbox id="filter" flex="1"
|
||||
type="search"
|
||||
placeholder="&filter.emptytext;"
|
||||
aria-controls="handlersView"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<richlistbox id="handlersView" orient="vertical" persist="lastSelectedType"
|
||||
preference="pref.downloads.disable_button.edit_actions"
|
||||
flex="1">
|
||||
<listheader equalsize="always">
|
||||
<treecol id="typeColumn" label="&typeColumn.label;" value="type"
|
||||
accesskey="&typeColumn.accesskey;" persist="sortDirection"
|
||||
flex="1" sortDirection="ascending"/>
|
||||
<treecol id="actionColumn" label="&actionColumn2.label;" value="action"
|
||||
accesskey="&actionColumn2.accesskey;" persist="sortDirection"
|
||||
flex="1"/>
|
||||
</listheader>
|
||||
</richlistbox>
|
||||
</vbox>
|
|
@ -0,0 +1,99 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from preferences.js */
|
||||
|
||||
Components.utils.import("resource://gre/modules/AppConstants.jsm");
|
||||
Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm");
|
||||
|
||||
const containersBundle = Services.strings.createBundle("chrome://browser/locale/preferences-old/containers.properties");
|
||||
|
||||
const defaultContainerIcon = "fingerprint";
|
||||
const defaultContainerColor = "blue";
|
||||
|
||||
let gContainersPane = {
|
||||
|
||||
init() {
|
||||
this._list = document.getElementById("containersView");
|
||||
|
||||
document.getElementById("backContainersLink").addEventListener("click", function() {
|
||||
gotoPref("privacy");
|
||||
});
|
||||
|
||||
this._rebuildView();
|
||||
},
|
||||
|
||||
_rebuildView() {
|
||||
const containers = ContextualIdentityService.getPublicIdentities();
|
||||
while (this._list.firstChild) {
|
||||
this._list.firstChild.remove();
|
||||
}
|
||||
for (let container of containers) {
|
||||
let item = document.createElement("richlistitem");
|
||||
item.setAttribute("containerName", ContextualIdentityService.getUserContextLabel(container.userContextId));
|
||||
item.setAttribute("containerIcon", container.icon);
|
||||
item.setAttribute("containerColor", container.color);
|
||||
item.setAttribute("userContextId", container.userContextId);
|
||||
|
||||
this._list.appendChild(item);
|
||||
}
|
||||
},
|
||||
|
||||
onRemoveClick(button) {
|
||||
let userContextId = parseInt(button.getAttribute("value"), 10);
|
||||
|
||||
let count = ContextualIdentityService.countContainerTabs(userContextId);
|
||||
if (count > 0) {
|
||||
let bundlePreferences = document.getElementById("bundlePreferences");
|
||||
|
||||
let title = bundlePreferences.getString("removeContainerAlertTitle");
|
||||
let message = PluralForm.get(count, bundlePreferences.getString("removeContainerMsg"))
|
||||
.replace("#S", count)
|
||||
let okButton = bundlePreferences.getString("removeContainerOkButton");
|
||||
let cancelButton = bundlePreferences.getString("removeContainerButton2");
|
||||
|
||||
let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
|
||||
(Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1);
|
||||
|
||||
let rv = Services.prompt.confirmEx(window, title, message, buttonFlags,
|
||||
okButton, cancelButton, null, null, {});
|
||||
if (rv != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContextualIdentityService.closeContainerTabs(userContextId);
|
||||
}
|
||||
|
||||
ContextualIdentityService.remove(userContextId);
|
||||
this._rebuildView();
|
||||
},
|
||||
|
||||
onPreferenceClick(button) {
|
||||
this.openPreferenceDialog(button.getAttribute("value"));
|
||||
},
|
||||
|
||||
onAddButtonClick(button) {
|
||||
this.openPreferenceDialog(null);
|
||||
},
|
||||
|
||||
openPreferenceDialog(userContextId) {
|
||||
let identity = {
|
||||
name: "",
|
||||
icon: defaultContainerIcon,
|
||||
color: defaultContainerColor
|
||||
};
|
||||
let title;
|
||||
if (userContextId) {
|
||||
identity = ContextualIdentityService.getPublicIdentityFromId(userContextId);
|
||||
// This is required to get the translation string from defaults
|
||||
identity.name = ContextualIdentityService.getUserContextLabel(identity.userContextId);
|
||||
title = containersBundle.formatStringFromName("containers.updateContainerTitle", [identity.name], 1);
|
||||
}
|
||||
|
||||
const params = { userContextId, identity, windowTitle: title };
|
||||
gSubDialog.open("chrome://browser/content/preferences/containers.xul",
|
||||
null, params);
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
# 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/.
|
||||
|
||||
<!-- Containers panel -->
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/containers.js"/>
|
||||
|
||||
<preferences id="containerPreferences" hidden="true" data-category="paneContainer">
|
||||
<!-- Containers -->
|
||||
<preference id="privacy.userContext.enabled"
|
||||
name="privacy.userContext.enabled"
|
||||
type="bool"/>
|
||||
|
||||
</preferences>
|
||||
|
||||
<hbox hidden="true"
|
||||
class="container-header-links"
|
||||
data-category="paneContainers">
|
||||
<label class="text-link" id="backContainersLink" value="&backLink.label;" />
|
||||
</hbox>
|
||||
|
||||
<hbox id="header-containers"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneContainers">
|
||||
<label class="header-name" flex="1">&paneContainers.title;</label>
|
||||
<button class="help-button"
|
||||
aria-label="&helpButton.label;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Containers -->
|
||||
<groupbox id="browserContainersGroup" data-category="paneContainers" hidden="true">
|
||||
<vbox id="browserContainersbox">
|
||||
|
||||
<richlistbox id="containersView" orient="vertical" persist="lastSelectedType"
|
||||
flex="1">
|
||||
<listheader equalsize="always">
|
||||
<treecol id="typeColumn" value="type"
|
||||
persist="sortDirection"
|
||||
flex="1" sortDirection="ascending"/>
|
||||
<treecol id="actionColumn" value="action"
|
||||
persist="sortDirection"
|
||||
flex="1"/>
|
||||
</listheader>
|
||||
</richlistbox>
|
||||
</vbox>
|
||||
<vbox>
|
||||
<hbox flex="1">
|
||||
<button onclick="gContainersPane.onAddButtonClick();" accesskey="&addButton.accesskey;" label="&addButton.label;"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</groupbox>
|
|
@ -0,0 +1,283 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from preferences.js */
|
||||
/* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "AlertsServiceDND", function() {
|
||||
try {
|
||||
let alertsService = Cc["@mozilla.org/alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService)
|
||||
.QueryInterface(Ci.nsIAlertsDoNotDisturb);
|
||||
// This will throw if manualDoNotDisturb isn't implemented.
|
||||
alertsService.manualDoNotDisturb;
|
||||
return alertsService;
|
||||
} catch (ex) {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
var gContentPane = {
|
||||
init() {
|
||||
function setEventListener(aId, aEventType, aCallback) {
|
||||
document.getElementById(aId)
|
||||
.addEventListener(aEventType, aCallback.bind(gContentPane));
|
||||
}
|
||||
|
||||
// Initializes the fonts dropdowns displayed in this pane.
|
||||
this._rebuildFonts();
|
||||
var menulist = document.getElementById("defaultFont");
|
||||
if (menulist.selectedIndex == -1) {
|
||||
menulist.value = FontBuilder.readFontSelection(menulist);
|
||||
}
|
||||
|
||||
// Show translation preferences if we may:
|
||||
const prefName = "browser.translation.ui.show";
|
||||
if (Services.prefs.getBoolPref(prefName)) {
|
||||
let row = document.getElementById("translationBox");
|
||||
row.removeAttribute("hidden");
|
||||
// Showing attribution only for Bing Translator.
|
||||
Components.utils.import("resource:///modules/translation/Translation.jsm");
|
||||
if (Translation.translationEngine == "bing") {
|
||||
document.getElementById("bingAttribution").removeAttribute("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
if (AlertsServiceDND) {
|
||||
let notificationsDoNotDisturbRow =
|
||||
document.getElementById("notificationsDoNotDisturbRow");
|
||||
notificationsDoNotDisturbRow.removeAttribute("hidden");
|
||||
if (AlertsServiceDND.manualDoNotDisturb) {
|
||||
let notificationsDoNotDisturb =
|
||||
document.getElementById("notificationsDoNotDisturb");
|
||||
notificationsDoNotDisturb.setAttribute("checked", true);
|
||||
}
|
||||
}
|
||||
|
||||
setEventListener("font.language.group", "change",
|
||||
gContentPane._rebuildFonts);
|
||||
setEventListener("notificationsPolicyButton", "command",
|
||||
gContentPane.showNotificationExceptions);
|
||||
setEventListener("popupPolicyButton", "command",
|
||||
gContentPane.showPopupExceptions);
|
||||
setEventListener("advancedFonts", "command",
|
||||
gContentPane.configureFonts);
|
||||
setEventListener("colors", "command",
|
||||
gContentPane.configureColors);
|
||||
setEventListener("chooseLanguage", "command",
|
||||
gContentPane.showLanguages);
|
||||
setEventListener("translationAttributionImage", "click",
|
||||
gContentPane.openTranslationProviderAttribution);
|
||||
setEventListener("translateButton", "command",
|
||||
gContentPane.showTranslationExceptions);
|
||||
setEventListener("notificationsDoNotDisturb", "command",
|
||||
gContentPane.toggleDoNotDisturbNotifications);
|
||||
|
||||
let notificationInfoURL =
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") + "push";
|
||||
document.getElementById("notificationsPolicyLearnMore").setAttribute("href",
|
||||
notificationInfoURL);
|
||||
|
||||
let drmInfoURL =
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") + "drm-content";
|
||||
document.getElementById("playDRMContentLink").setAttribute("href", drmInfoURL);
|
||||
let emeUIEnabled = Services.prefs.getBoolPref("browser.eme.ui.enabled");
|
||||
// Force-disable/hide on WinXP:
|
||||
if (navigator.platform.toLowerCase().startsWith("win")) {
|
||||
emeUIEnabled = emeUIEnabled && parseFloat(Services.sysinfo.get("version")) >= 6;
|
||||
}
|
||||
if (!emeUIEnabled) {
|
||||
// Don't want to rely on .hidden for the toplevel groupbox because
|
||||
// of the pane hiding/showing code potentially interfering:
|
||||
document.getElementById("drmGroup").setAttribute("style", "display: none !important");
|
||||
}
|
||||
},
|
||||
|
||||
// UTILITY FUNCTIONS
|
||||
|
||||
/**
|
||||
* Utility function to enable/disable the button specified by aButtonID based
|
||||
* on the value of the Boolean preference specified by aPreferenceID.
|
||||
*/
|
||||
updateButtons(aButtonID, aPreferenceID) {
|
||||
var button = document.getElementById(aButtonID);
|
||||
var preference = document.getElementById(aPreferenceID);
|
||||
button.disabled = preference.value != true;
|
||||
return undefined;
|
||||
},
|
||||
|
||||
// BEGIN UI CODE
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* dom.disable_open_during_load
|
||||
* - true if popups are blocked by default, false otherwise
|
||||
*/
|
||||
|
||||
// NOTIFICATIONS
|
||||
|
||||
/**
|
||||
* Displays the notifications exceptions dialog where specific site notification
|
||||
* preferences can be set.
|
||||
*/
|
||||
showNotificationExceptions() {
|
||||
let bundlePreferences = document.getElementById("bundlePreferences");
|
||||
let params = { permissionType: "desktop-notification" };
|
||||
params.windowTitle = bundlePreferences.getString("notificationspermissionstitle");
|
||||
params.introText = bundlePreferences.getString("notificationspermissionstext4");
|
||||
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
"resizable=yes", params);
|
||||
|
||||
try {
|
||||
Services.telemetry
|
||||
.getHistogramById("WEB_NOTIFICATION_EXCEPTIONS_OPENED").add();
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
|
||||
// POP-UPS
|
||||
|
||||
/**
|
||||
* Displays the popup exceptions dialog where specific site popup preferences
|
||||
* can be set.
|
||||
*/
|
||||
showPopupExceptions() {
|
||||
var bundlePreferences = document.getElementById("bundlePreferences");
|
||||
var params = { blockVisible: false, sessionVisible: false, allowVisible: true,
|
||||
prefilledHost: "", permissionType: "popup" }
|
||||
params.windowTitle = bundlePreferences.getString("popuppermissionstitle");
|
||||
params.introText = bundlePreferences.getString("popuppermissionstext");
|
||||
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
"resizable=yes", params);
|
||||
},
|
||||
|
||||
// FONTS
|
||||
|
||||
/**
|
||||
* Populates the default font list in UI.
|
||||
*/
|
||||
_rebuildFonts() {
|
||||
var preferences = document.getElementById("contentPreferences");
|
||||
// Ensure preferences are "visible" to ensure bindings work.
|
||||
preferences.hidden = false;
|
||||
// Force flush:
|
||||
preferences.clientHeight;
|
||||
var langGroupPref = document.getElementById("font.language.group");
|
||||
this._selectDefaultLanguageGroup(langGroupPref.value,
|
||||
this._readDefaultFontTypeForLanguage(langGroupPref.value) == "serif");
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
_selectDefaultLanguageGroup(aLanguageGroup, aIsSerif) {
|
||||
const kFontNameFmtSerif = "font.name.serif.%LANG%";
|
||||
const kFontNameFmtSansSerif = "font.name.sans-serif.%LANG%";
|
||||
const kFontNameListFmtSerif = "font.name-list.serif.%LANG%";
|
||||
const kFontNameListFmtSansSerif = "font.name-list.sans-serif.%LANG%";
|
||||
const kFontSizeFmtVariable = "font.size.variable.%LANG%";
|
||||
|
||||
var preferences = document.getElementById("contentPreferences");
|
||||
var prefs = [{ format: aIsSerif ? kFontNameFmtSerif : kFontNameFmtSansSerif,
|
||||
type: "fontname",
|
||||
element: "defaultFont",
|
||||
fonttype: aIsSerif ? "serif" : "sans-serif" },
|
||||
{ format: aIsSerif ? kFontNameListFmtSerif : kFontNameListFmtSansSerif,
|
||||
type: "unichar",
|
||||
element: null,
|
||||
fonttype: aIsSerif ? "serif" : "sans-serif" },
|
||||
{ format: kFontSizeFmtVariable,
|
||||
type: "int",
|
||||
element: "defaultFontSize",
|
||||
fonttype: null }];
|
||||
for (var i = 0; i < prefs.length; ++i) {
|
||||
var preference = document.getElementById(prefs[i].format.replace(/%LANG%/, aLanguageGroup));
|
||||
if (!preference) {
|
||||
preference = document.createElement("preference");
|
||||
var name = prefs[i].format.replace(/%LANG%/, aLanguageGroup);
|
||||
preference.id = name;
|
||||
preference.setAttribute("name", name);
|
||||
preference.setAttribute("type", prefs[i].type);
|
||||
preferences.appendChild(preference);
|
||||
}
|
||||
|
||||
if (!prefs[i].element)
|
||||
continue;
|
||||
|
||||
var element = document.getElementById(prefs[i].element);
|
||||
if (element) {
|
||||
element.setAttribute("preference", preference.id);
|
||||
|
||||
if (prefs[i].fonttype)
|
||||
FontBuilder.buildFontList(aLanguageGroup, prefs[i].fonttype, element);
|
||||
|
||||
preference.setElementValue(element);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the type of the current default font for the language denoted by
|
||||
* aLanguageGroup.
|
||||
*/
|
||||
_readDefaultFontTypeForLanguage(aLanguageGroup) {
|
||||
const kDefaultFontType = "font.default.%LANG%";
|
||||
var defaultFontTypePref = kDefaultFontType.replace(/%LANG%/, aLanguageGroup);
|
||||
var preference = document.getElementById(defaultFontTypePref);
|
||||
if (!preference) {
|
||||
preference = document.createElement("preference");
|
||||
preference.id = defaultFontTypePref;
|
||||
preference.setAttribute("name", defaultFontTypePref);
|
||||
preference.setAttribute("type", "string");
|
||||
preference.setAttribute("onchange", "gContentPane._rebuildFonts();");
|
||||
document.getElementById("contentPreferences").appendChild(preference);
|
||||
}
|
||||
return preference.value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the fonts dialog, where web page font names and sizes can be
|
||||
* configured.
|
||||
*/
|
||||
configureFonts() {
|
||||
gSubDialog.open("chrome://browser/content/preferences/fonts.xul", "resizable=no");
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the colors dialog, where default web page/link/etc. colors can be
|
||||
* configured.
|
||||
*/
|
||||
configureColors() {
|
||||
gSubDialog.open("chrome://browser/content/preferences/colors.xul", "resizable=no");
|
||||
},
|
||||
|
||||
// LANGUAGES
|
||||
|
||||
/**
|
||||
* Shows a dialog in which the preferred language for web content may be set.
|
||||
*/
|
||||
showLanguages() {
|
||||
gSubDialog.open("chrome://browser/content/preferences/languages.xul");
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the translation exceptions dialog where specific site and language
|
||||
* translation preferences can be set.
|
||||
*/
|
||||
showTranslationExceptions() {
|
||||
gSubDialog.open("chrome://browser/content/preferences/translation.xul");
|
||||
},
|
||||
|
||||
openTranslationProviderAttribution() {
|
||||
Components.utils.import("resource:///modules/translation/Translation.jsm");
|
||||
Translation.openProviderAttribution();
|
||||
},
|
||||
|
||||
toggleDoNotDisturbNotifications(event) {
|
||||
AlertsServiceDND.manualDoNotDisturb = event.target.checked;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,207 @@
|
|||
# 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/.
|
||||
|
||||
<!-- Content panel -->
|
||||
|
||||
<preferences id="contentPreferences" hidden="true" data-category="paneContent">
|
||||
|
||||
<!-- DRM content -->
|
||||
<preference id="media.eme.enabled"
|
||||
name="media.eme.enabled"
|
||||
type="bool"/>
|
||||
|
||||
<!-- Popups -->
|
||||
<preference id="dom.disable_open_during_load"
|
||||
name="dom.disable_open_during_load"
|
||||
type="bool"/>
|
||||
|
||||
<!-- Fonts -->
|
||||
<preference id="font.language.group"
|
||||
name="font.language.group"
|
||||
type="wstring"/>
|
||||
|
||||
<!-- Languages -->
|
||||
<preference id="browser.translation.detectLanguage"
|
||||
name="browser.translation.detectLanguage"
|
||||
type="bool"/>
|
||||
</preferences>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mozapps/content/preferences/fontbuilder.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/content.js"/>
|
||||
|
||||
<hbox id="header-content"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneContent">
|
||||
<label class="header-name" flex="1">&paneContent.title;</label>
|
||||
<html:a class="help-button" target="_blank" aria-label="&helpButton.label;"></html:a>
|
||||
</hbox>
|
||||
|
||||
<groupbox id="drmGroup" data-category="paneContent" hidden="true">
|
||||
<caption><label>&drmContent.label;</label></caption>
|
||||
<grid id="contentGrid2">
|
||||
<columns>
|
||||
<column flex="1"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows id="contentRows-2">
|
||||
<row id="playDRMContentRow">
|
||||
<hbox align="center">
|
||||
<checkbox id="playDRMContent" preference="media.eme.enabled"
|
||||
label="&playDRMContent.label;" accesskey="&playDRMContent.accesskey;"/>
|
||||
<label id="playDRMContentLink" class="learnMore text-link" value="&playDRMContent.learnMore.label;"/>
|
||||
</hbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
|
||||
<groupbox id="notificationsGroup" data-category="paneContent" hidden="true">
|
||||
<caption><label>¬ificationsPolicy.label;</label></caption>
|
||||
<grid>
|
||||
<columns>
|
||||
<column flex="1"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row id="notificationsPolicyRow" align="center">
|
||||
<hbox align="start">
|
||||
<label id="notificationsPolicy">¬ificationsPolicyDesc3.label;</label>
|
||||
<label id="notificationsPolicyLearnMore"
|
||||
class="learnMore text-link"
|
||||
value="¬ificationsPolicyLearnMore.label;"/>
|
||||
</hbox>
|
||||
<hbox pack="end">
|
||||
<button id="notificationsPolicyButton" label="¬ificationsPolicyButton.label;"
|
||||
accesskey="¬ificationsPolicyButton.accesskey;"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row id="notificationsDoNotDisturbRow" hidden="true">
|
||||
<vbox align="start">
|
||||
<checkbox id="notificationsDoNotDisturb" label="¬ificationsDoNotDisturb.label;"
|
||||
accesskey="¬ificationsDoNotDisturb.accesskey;"/>
|
||||
<label id="notificationsDoNotDisturbDetails"
|
||||
class="indent"
|
||||
value="¬ificationsDoNotDisturbDetails.value;"/>
|
||||
</vbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
|
||||
<groupbox id="miscGroup" data-category="paneContent" hidden="true">
|
||||
<caption><label>&popups.label;</label></caption>
|
||||
<grid id="contentGrid">
|
||||
<columns>
|
||||
<column flex="1"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows id="contentRows-1">
|
||||
<row id="popupPolicyRow">
|
||||
<vbox align="start">
|
||||
<checkbox id="popupPolicy" preference="dom.disable_open_during_load"
|
||||
label="&blockPopups.label;" accesskey="&blockPopups.accesskey;"
|
||||
onsyncfrompreference="return gContentPane.updateButtons('popupPolicyButton',
|
||||
'dom.disable_open_during_load');"/>
|
||||
</vbox>
|
||||
<hbox pack="end">
|
||||
<button id="popupPolicyButton" label="&popupExceptions.label;"
|
||||
accesskey="&popupExceptions.accesskey;"/>
|
||||
</hbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
|
||||
<!-- Fonts and Colors -->
|
||||
<groupbox id="fontsGroup" data-category="paneContent" hidden="true">
|
||||
<caption><label>&fontsAndColors.label;</label></caption>
|
||||
|
||||
<grid id="fontsGrid">
|
||||
<columns>
|
||||
<column flex="1"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows id="fontsRows">
|
||||
<row id="fontRow">
|
||||
<hbox align="center">
|
||||
<label control="defaultFont" accesskey="&defaultFont.accesskey;">&defaultFont.label;</label>
|
||||
<menulist id="defaultFont" delayprefsave="true"/>
|
||||
<label id="defaultFontSizeLabel" control="defaultFontSize" accesskey="&defaultSize.accesskey;">&defaultSize.label;</label>
|
||||
<menulist id="defaultFontSize" delayprefsave="true">
|
||||
<menupopup>
|
||||
<menuitem value="9" label="9"/>
|
||||
<menuitem value="10" label="10"/>
|
||||
<menuitem value="11" label="11"/>
|
||||
<menuitem value="12" label="12"/>
|
||||
<menuitem value="13" label="13"/>
|
||||
<menuitem value="14" label="14"/>
|
||||
<menuitem value="15" label="15"/>
|
||||
<menuitem value="16" label="16"/>
|
||||
<menuitem value="17" label="17"/>
|
||||
<menuitem value="18" label="18"/>
|
||||
<menuitem value="20" label="20"/>
|
||||
<menuitem value="22" label="22"/>
|
||||
<menuitem value="24" label="24"/>
|
||||
<menuitem value="26" label="26"/>
|
||||
<menuitem value="28" label="28"/>
|
||||
<menuitem value="30" label="30"/>
|
||||
<menuitem value="32" label="32"/>
|
||||
<menuitem value="34" label="34"/>
|
||||
<menuitem value="36" label="36"/>
|
||||
<menuitem value="40" label="40"/>
|
||||
<menuitem value="44" label="44"/>
|
||||
<menuitem value="48" label="48"/>
|
||||
<menuitem value="56" label="56"/>
|
||||
<menuitem value="64" label="64"/>
|
||||
<menuitem value="72" label="72"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
<button id="advancedFonts" icon="select-font"
|
||||
label="&advancedFonts.label;"
|
||||
accesskey="&advancedFonts.accesskey;"/>
|
||||
</row>
|
||||
<row id="colorsRow">
|
||||
<hbox/>
|
||||
<button id="colors" icon="select-color"
|
||||
label="&colors.label;"
|
||||
accesskey="&colors.accesskey;"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
|
||||
<!-- Languages -->
|
||||
<groupbox id="languagesGroup" data-category="paneContent" hidden="true">
|
||||
<caption><label>&languages.label;</label></caption>
|
||||
|
||||
<hbox id="languagesBox" align="center">
|
||||
<description flex="1" control="chooseLanguage">&chooseLanguage.label;</description>
|
||||
<button id="chooseLanguage"
|
||||
label="&chooseButton.label;"
|
||||
accesskey="&chooseButton.accesskey;"/>
|
||||
</hbox>
|
||||
|
||||
<hbox id="translationBox" hidden="true">
|
||||
<hbox align="center" flex="1">
|
||||
<checkbox id="translate" preference="browser.translation.detectLanguage"
|
||||
label="&translateWebPages.label;." accesskey="&translateWebPages.accesskey;"
|
||||
onsyncfrompreference="return gContentPane.updateButtons('translateButton',
|
||||
'browser.translation.detectLanguage');"/>
|
||||
<hbox id="bingAttribution" hidden="true">
|
||||
<label>&translation.options.attribution.beforeLogo;</label>
|
||||
<separator orient="vertical" class="thin"/>
|
||||
<image id="translationAttributionImage" aria-label="Microsoft Translator"
|
||||
src="chrome://browser/content/microsoft-translator-attribution.png"/>
|
||||
<separator orient="vertical" class="thin"/>
|
||||
<label>&translation.options.attribution.afterLogo;</label>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<button id="translateButton" label="&translateExceptions.label;"
|
||||
accesskey="&translateExceptions.accesskey;"/>
|
||||
</hbox>
|
||||
</groupbox>
|
|
@ -0,0 +1,18 @@
|
|||
# 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/.
|
||||
|
||||
browser.jar:
|
||||
content/browser/preferences/in-content-old/preferences.js
|
||||
* content/browser/preferences/in-content-old/preferences.xul
|
||||
content/browser/preferences/in-content-old/subdialogs.js
|
||||
|
||||
content/browser/preferences/in-content-old/main.js
|
||||
content/browser/preferences/in-content-old/privacy.js
|
||||
content/browser/preferences/in-content-old/containers.js
|
||||
content/browser/preferences/in-content-old/advanced.js
|
||||
content/browser/preferences/in-content-old/applications.js
|
||||
content/browser/preferences/in-content-old/content.js
|
||||
content/browser/preferences/in-content-old/sync.js
|
||||
content/browser/preferences/in-content-old/security.js
|
||||
content/browser/preferences/in-content-old/search.js
|
|
@ -0,0 +1,699 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from preferences.js */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Downloads.jsm");
|
||||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
Components.utils.import("resource:///modules/ShellService.jsm");
|
||||
Components.utils.import("resource:///modules/TransientPrefs.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
|
||||
if (AppConstants.E10S_TESTING_ONLY) {
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
|
||||
"resource://gre/modules/UpdateUtils.jsm");
|
||||
}
|
||||
|
||||
var gMainPane = {
|
||||
/**
|
||||
* Initialization of this.
|
||||
*/
|
||||
init() {
|
||||
function setEventListener(aId, aEventType, aCallback) {
|
||||
document.getElementById(aId)
|
||||
.addEventListener(aEventType, aCallback.bind(gMainPane));
|
||||
}
|
||||
|
||||
if (AppConstants.HAVE_SHELL_SERVICE) {
|
||||
this.updateSetDefaultBrowser();
|
||||
if (AppConstants.platform == "win") {
|
||||
// In Windows 8 we launch the control panel since it's the only
|
||||
// way to get all file type association prefs. So we don't know
|
||||
// when the user will select the default. We refresh here periodically
|
||||
// in case the default changes. On other Windows OS's defaults can also
|
||||
// be set while the prefs are open.
|
||||
window.setInterval(this.updateSetDefaultBrowser.bind(this), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// set up the "use current page" label-changing listener
|
||||
this._updateUseCurrentButton();
|
||||
window.addEventListener("focus", this._updateUseCurrentButton.bind(this));
|
||||
|
||||
this.updateBrowserStartupLastSession();
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
// Functionality for "Show tabs in taskbar" on Windows 7 and up.
|
||||
try {
|
||||
let sysInfo = Cc["@mozilla.org/system-info;1"].
|
||||
getService(Ci.nsIPropertyBag2);
|
||||
let ver = parseFloat(sysInfo.getProperty("version"));
|
||||
let showTabsInTaskbar = document.getElementById("showTabsInTaskbar");
|
||||
showTabsInTaskbar.hidden = ver < 6.1;
|
||||
} catch (ex) {}
|
||||
}
|
||||
|
||||
// The "closing multiple tabs" and "opening multiple tabs might slow down
|
||||
// &brandShortName;" warnings provide options for not showing these
|
||||
// warnings again. When the user disabled them, we provide checkboxes to
|
||||
// re-enable the warnings.
|
||||
if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnClose"))
|
||||
document.getElementById("warnCloseMultiple").hidden = true;
|
||||
if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnOpen"))
|
||||
document.getElementById("warnOpenMany").hidden = true;
|
||||
|
||||
setEventListener("browser.privatebrowsing.autostart", "change",
|
||||
gMainPane.updateBrowserStartupLastSession);
|
||||
setEventListener("browser.download.dir", "change",
|
||||
gMainPane.displayDownloadDirPref);
|
||||
if (AppConstants.HAVE_SHELL_SERVICE) {
|
||||
setEventListener("setDefaultButton", "command",
|
||||
gMainPane.setDefaultBrowser);
|
||||
}
|
||||
setEventListener("useCurrent", "command",
|
||||
gMainPane.setHomePageToCurrent);
|
||||
setEventListener("useBookmark", "command",
|
||||
gMainPane.setHomePageToBookmark);
|
||||
setEventListener("restoreDefaultHomePage", "command",
|
||||
gMainPane.restoreDefaultHomePage);
|
||||
setEventListener("chooseFolder", "command",
|
||||
gMainPane.chooseFolder);
|
||||
|
||||
if (AppConstants.E10S_TESTING_ONLY) {
|
||||
setEventListener("e10sAutoStart", "command",
|
||||
gMainPane.enableE10SChange);
|
||||
let e10sCheckbox = document.getElementById("e10sAutoStart");
|
||||
|
||||
let e10sPref = document.getElementById("browser.tabs.remote.autostart");
|
||||
let e10sTempPref = document.getElementById("e10sTempPref");
|
||||
let e10sForceEnable = document.getElementById("e10sForceEnable");
|
||||
|
||||
let preffedOn = e10sPref.value || e10sTempPref.value || e10sForceEnable.value;
|
||||
|
||||
if (preffedOn) {
|
||||
// The checkbox is checked if e10s is preffed on and enabled.
|
||||
e10sCheckbox.checked = Services.appinfo.browserTabsRemoteAutostart;
|
||||
|
||||
// but if it's force disabled, then the checkbox is disabled.
|
||||
e10sCheckbox.disabled = !Services.appinfo.browserTabsRemoteAutostart;
|
||||
}
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_DEV_EDITION) {
|
||||
let uAppData = OS.Constants.Path.userApplicationDataDir;
|
||||
let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
|
||||
|
||||
setEventListener("separateProfileMode", "command", gMainPane.separateProfileModeChange);
|
||||
let separateProfileModeCheckbox = document.getElementById("separateProfileMode");
|
||||
setEventListener("getStarted", "click", gMainPane.onGetStarted);
|
||||
|
||||
OS.File.stat(ignoreSeparateProfile).then(() => separateProfileModeCheckbox.checked = false,
|
||||
() => separateProfileModeCheckbox.checked = true);
|
||||
}
|
||||
|
||||
// Notify observers that the UI is now ready
|
||||
Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService)
|
||||
.notifyObservers(window, "main-pane-loaded", null);
|
||||
},
|
||||
|
||||
enableE10SChange() {
|
||||
if (AppConstants.E10S_TESTING_ONLY) {
|
||||
let e10sCheckbox = document.getElementById("e10sAutoStart");
|
||||
let e10sPref = document.getElementById("browser.tabs.remote.autostart");
|
||||
let e10sTempPref = document.getElementById("e10sTempPref");
|
||||
|
||||
let prefsToChange;
|
||||
if (e10sCheckbox.checked) {
|
||||
// Enabling e10s autostart
|
||||
prefsToChange = [e10sPref];
|
||||
} else {
|
||||
// Disabling e10s autostart
|
||||
prefsToChange = [e10sPref];
|
||||
if (e10sTempPref.value) {
|
||||
prefsToChange.push(e10sTempPref);
|
||||
}
|
||||
}
|
||||
|
||||
let buttonIndex = confirmRestartPrompt(e10sCheckbox.checked, 0,
|
||||
true, false);
|
||||
if (buttonIndex == CONFIRM_RESTART_PROMPT_RESTART_NOW) {
|
||||
for (let prefToChange of prefsToChange) {
|
||||
prefToChange.value = e10sCheckbox.checked;
|
||||
}
|
||||
|
||||
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
|
||||
}
|
||||
|
||||
// Revert the checkbox in case we didn't quit
|
||||
e10sCheckbox.checked = e10sPref.value || e10sTempPref.value;
|
||||
}
|
||||
},
|
||||
|
||||
separateProfileModeChange() {
|
||||
if (AppConstants.MOZ_DEV_EDITION) {
|
||||
function quitApp() {
|
||||
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestartNotSameProfile);
|
||||
}
|
||||
function revertCheckbox(error) {
|
||||
separateProfileModeCheckbox.checked = !separateProfileModeCheckbox.checked;
|
||||
if (error) {
|
||||
Cu.reportError("Failed to toggle separate profile mode: " + error);
|
||||
}
|
||||
}
|
||||
function createOrRemoveSpecialDevEditionFile(onSuccess) {
|
||||
let uAppData = OS.Constants.Path.userApplicationDataDir;
|
||||
let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
|
||||
|
||||
if (separateProfileModeCheckbox.checked) {
|
||||
OS.File.remove(ignoreSeparateProfile).then(onSuccess, revertCheckbox);
|
||||
} else {
|
||||
OS.File.writeAtomic(ignoreSeparateProfile, new Uint8Array()).then(onSuccess, revertCheckbox);
|
||||
}
|
||||
}
|
||||
|
||||
let separateProfileModeCheckbox = document.getElementById("separateProfileMode");
|
||||
let button_index = confirmRestartPrompt(separateProfileModeCheckbox.checked,
|
||||
0, false, true);
|
||||
switch (button_index) {
|
||||
case CONFIRM_RESTART_PROMPT_CANCEL:
|
||||
revertCheckbox();
|
||||
return;
|
||||
case CONFIRM_RESTART_PROMPT_RESTART_NOW:
|
||||
const Cc = Components.classes, Ci = Components.interfaces;
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
|
||||
"restart");
|
||||
if (!cancelQuit.data) {
|
||||
createOrRemoveSpecialDevEditionFile(quitApp);
|
||||
return;
|
||||
}
|
||||
|
||||
// Revert the checkbox in case we didn't quit
|
||||
revertCheckbox();
|
||||
return;
|
||||
case CONFIRM_RESTART_PROMPT_RESTART_LATER:
|
||||
createOrRemoveSpecialDevEditionFile();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onGetStarted(aEvent) {
|
||||
if (AppConstants.MOZ_DEV_EDITION) {
|
||||
const Cc = Components.classes, Ci = Components.interfaces;
|
||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Ci.nsIWindowMediator);
|
||||
let win = wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
if (win) {
|
||||
let accountsTab = win.gBrowser.addTab("about:accounts?action=signin&entrypoint=dev-edition-setup");
|
||||
win.gBrowser.selectedTab = accountsTab;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// HOME PAGE
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* browser.startup.homepage
|
||||
* - the user's home page, as a string; if the home page is a set of tabs,
|
||||
* this will be those URLs separated by the pipe character "|"
|
||||
* browser.startup.page
|
||||
* - what page(s) to show when the user starts the application, as an integer:
|
||||
*
|
||||
* 0: a blank page
|
||||
* 1: the home page (as set by the browser.startup.homepage pref)
|
||||
* 2: the last page the user visited (DEPRECATED)
|
||||
* 3: windows and tabs from the last session (a.k.a. session restore)
|
||||
*
|
||||
* The deprecated option is not exposed in UI; however, if the user has it
|
||||
* selected and doesn't change the UI for this preference, the deprecated
|
||||
* option is preserved.
|
||||
*/
|
||||
|
||||
syncFromHomePref() {
|
||||
let homePref = document.getElementById("browser.startup.homepage");
|
||||
|
||||
// If the pref is set to about:home or about:newtab, set the value to ""
|
||||
// to show the placeholder text (about:home title) rather than
|
||||
// exposing those URLs to users.
|
||||
let defaultBranch = Services.prefs.getDefaultBranch("");
|
||||
let defaultValue = defaultBranch.getComplexValue("browser.startup.homepage",
|
||||
Ci.nsIPrefLocalizedString).data;
|
||||
let currentValue = homePref.value.toLowerCase();
|
||||
if (currentValue == "about:home" ||
|
||||
(currentValue == defaultValue && currentValue == "about:newtab")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// If the pref is actually "", show about:blank. The actual home page
|
||||
// loading code treats them the same, and we don't want the placeholder text
|
||||
// to be shown.
|
||||
if (homePref.value == "")
|
||||
return "about:blank";
|
||||
|
||||
// Otherwise, show the actual pref value.
|
||||
return undefined;
|
||||
},
|
||||
|
||||
syncToHomePref(value) {
|
||||
// If the value is "", use about:home.
|
||||
if (value == "")
|
||||
return "about:home";
|
||||
|
||||
// Otherwise, use the actual textbox value.
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the home page to the current displayed page (or frontmost tab, if the
|
||||
* most recent browser window contains multiple tabs), updating preference
|
||||
* window UI to reflect this.
|
||||
*/
|
||||
setHomePageToCurrent() {
|
||||
let homePage = document.getElementById("browser.startup.homepage");
|
||||
let tabs = this._getTabsForHomePage();
|
||||
function getTabURI(t) {
|
||||
return t.linkedBrowser.currentURI.spec;
|
||||
}
|
||||
|
||||
// FIXME Bug 244192: using dangerous "|" joiner!
|
||||
if (tabs.length)
|
||||
homePage.value = tabs.map(getTabURI).join("|");
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a dialog in which the user can select a bookmark to use as home
|
||||
* page. If the user selects a bookmark, that bookmark's name is displayed in
|
||||
* UI and the bookmark's address is stored to the home page preference.
|
||||
*/
|
||||
setHomePageToBookmark() {
|
||||
var rv = { urls: null, names: null };
|
||||
gSubDialog.open("chrome://browser/content/preferences/selectBookmark.xul",
|
||||
"resizable=yes, modal=yes", rv,
|
||||
this._setHomePageToBookmarkClosed.bind(this, rv));
|
||||
},
|
||||
|
||||
_setHomePageToBookmarkClosed(rv, aEvent) {
|
||||
if (aEvent.detail.button != "accept")
|
||||
return;
|
||||
if (rv.urls && rv.names) {
|
||||
var homePage = document.getElementById("browser.startup.homepage");
|
||||
|
||||
// XXX still using dangerous "|" joiner!
|
||||
homePage.value = rv.urls.join("|");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Switches the "Use Current Page" button between its singular and plural
|
||||
* forms.
|
||||
*/
|
||||
_updateUseCurrentButton() {
|
||||
let useCurrent = document.getElementById("useCurrent");
|
||||
|
||||
|
||||
let tabs = this._getTabsForHomePage();
|
||||
|
||||
if (tabs.length > 1)
|
||||
useCurrent.label = useCurrent.getAttribute("label2");
|
||||
else
|
||||
useCurrent.label = useCurrent.getAttribute("label1");
|
||||
|
||||
// In this case, the button's disabled state is set by preferences.xml.
|
||||
let prefName = "pref.browser.homepage.disable_button.current_page";
|
||||
if (document.getElementById(prefName).locked)
|
||||
return;
|
||||
|
||||
useCurrent.disabled = !tabs.length
|
||||
},
|
||||
|
||||
_getTabsForHomePage() {
|
||||
var win;
|
||||
var tabs = [];
|
||||
|
||||
const Cc = Components.classes, Ci = Components.interfaces;
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Ci.nsIWindowMediator);
|
||||
win = wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
if (win && win.document.documentElement
|
||||
.getAttribute("windowtype") == "navigator:browser") {
|
||||
// We should only include visible & non-pinned tabs
|
||||
|
||||
tabs = win.gBrowser.visibleTabs.slice(win.gBrowser._numPinnedTabs);
|
||||
tabs = tabs.filter(this.isNotAboutPreferences);
|
||||
}
|
||||
|
||||
return tabs;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check to see if a tab is not about:preferences
|
||||
*/
|
||||
isNotAboutPreferences(aElement, aIndex, aArray) {
|
||||
return !aElement.linkedBrowser.currentURI.spec.startsWith("about:preferences");
|
||||
},
|
||||
|
||||
/**
|
||||
* Restores the default home page as the user's home page.
|
||||
*/
|
||||
restoreDefaultHomePage() {
|
||||
var homePage = document.getElementById("browser.startup.homepage");
|
||||
homePage.value = homePage.defaultValue;
|
||||
},
|
||||
|
||||
// DOWNLOADS
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* browser.download.useDownloadDir - bool
|
||||
* True - Save files directly to the folder configured via the
|
||||
* browser.download.folderList preference.
|
||||
* False - Always ask the user where to save a file and default to
|
||||
* browser.download.lastDir when displaying a folder picker dialog.
|
||||
* browser.download.dir - local file handle
|
||||
* A local folder the user may have selected for downloaded files to be
|
||||
* saved. Migration of other browser settings may also set this path.
|
||||
* This folder is enabled when folderList equals 2.
|
||||
* browser.download.lastDir - local file handle
|
||||
* May contain the last folder path accessed when the user browsed
|
||||
* via the file save-as dialog. (see contentAreaUtils.js)
|
||||
* browser.download.folderList - int
|
||||
* Indicates the location users wish to save downloaded files too.
|
||||
* It is also used to display special file labels when the default
|
||||
* download location is either the Desktop or the Downloads folder.
|
||||
* Values:
|
||||
* 0 - The desktop is the default download location.
|
||||
* 1 - The system's downloads folder is the default download location.
|
||||
* 2 - The default download location is elsewhere as specified in
|
||||
* browser.download.dir.
|
||||
* browser.download.downloadDir
|
||||
* deprecated.
|
||||
* browser.download.defaultFolder
|
||||
* deprecated.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enables/disables the folder field and Browse button based on whether a
|
||||
* default download directory is being used.
|
||||
*/
|
||||
readUseDownloadDir() {
|
||||
var downloadFolder = document.getElementById("downloadFolder");
|
||||
var chooseFolder = document.getElementById("chooseFolder");
|
||||
var preference = document.getElementById("browser.download.useDownloadDir");
|
||||
downloadFolder.disabled = !preference.value || preference.locked;
|
||||
chooseFolder.disabled = !preference.value || preference.locked;
|
||||
|
||||
// don't override the preference's value in UI
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a file picker in which the user can choose the location where
|
||||
* downloads are automatically saved, updating preferences and UI in
|
||||
* response to the choice, if one is made.
|
||||
*/
|
||||
chooseFolder() {
|
||||
return this.chooseFolderTask().catch(Components.utils.reportError);
|
||||
},
|
||||
chooseFolderTask: Task.async(function* () {
|
||||
let bundlePreferences = document.getElementById("bundlePreferences");
|
||||
let title = bundlePreferences.getString("chooseDownloadFolderTitle");
|
||||
let folderListPref = document.getElementById("browser.download.folderList");
|
||||
let currentDirPref = yield this._indexToFolder(folderListPref.value);
|
||||
let defDownloads = yield this._indexToFolder(1);
|
||||
let fp = Components.classes["@mozilla.org/filepicker;1"].
|
||||
createInstance(Components.interfaces.nsIFilePicker);
|
||||
|
||||
fp.init(window, title, Components.interfaces.nsIFilePicker.modeGetFolder);
|
||||
fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
|
||||
// First try to open what's currently configured
|
||||
if (currentDirPref && currentDirPref.exists()) {
|
||||
fp.displayDirectory = currentDirPref;
|
||||
} else if (defDownloads && defDownloads.exists()) {
|
||||
// Try the system's download dir
|
||||
fp.displayDirectory = defDownloads;
|
||||
} else {
|
||||
// Fall back to Desktop
|
||||
fp.displayDirectory = yield this._indexToFolder(0);
|
||||
}
|
||||
|
||||
let result = yield new Promise(resolve => fp.open(resolve));
|
||||
if (result != Components.interfaces.nsIFilePicker.returnOK) {
|
||||
return;
|
||||
}
|
||||
|
||||
let downloadDirPref = document.getElementById("browser.download.dir");
|
||||
downloadDirPref.value = fp.file;
|
||||
folderListPref.value = yield this._folderToIndex(fp.file);
|
||||
// Note, the real prefs will not be updated yet, so dnld manager's
|
||||
// userDownloadsDirectory may not return the right folder after
|
||||
// this code executes. displayDownloadDirPref will be called on
|
||||
// the assignment above to update the UI.
|
||||
}),
|
||||
|
||||
/**
|
||||
* Initializes the download folder display settings based on the user's
|
||||
* preferences.
|
||||
*/
|
||||
displayDownloadDirPref() {
|
||||
this.displayDownloadDirPrefTask().catch(Components.utils.reportError);
|
||||
|
||||
// don't override the preference's value in UI
|
||||
return undefined;
|
||||
},
|
||||
|
||||
displayDownloadDirPrefTask: Task.async(function* () {
|
||||
var folderListPref = document.getElementById("browser.download.folderList");
|
||||
var bundlePreferences = document.getElementById("bundlePreferences");
|
||||
var downloadFolder = document.getElementById("downloadFolder");
|
||||
var currentDirPref = document.getElementById("browser.download.dir");
|
||||
|
||||
// Used in defining the correct path to the folder icon.
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var fph = ios.getProtocolHandler("file")
|
||||
.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
|
||||
var iconUrlSpec;
|
||||
|
||||
// Display a 'pretty' label or the path in the UI.
|
||||
if (folderListPref.value == 2) {
|
||||
// Custom path selected and is configured
|
||||
downloadFolder.label = this._getDisplayNameOfFile(currentDirPref.value);
|
||||
iconUrlSpec = fph.getURLSpecFromFile(currentDirPref.value);
|
||||
} else if (folderListPref.value == 1) {
|
||||
// 'Downloads'
|
||||
// In 1.5, this pointed to a folder we created called 'My Downloads'
|
||||
// and was available as an option in the 1.5 drop down. On XP this
|
||||
// was in My Documents, on OSX it was in User Docs. In 2.0, we did
|
||||
// away with the drop down option, although the special label was
|
||||
// still supported for the folder if it existed. Because it was
|
||||
// not exposed it was rarely used.
|
||||
// With 3.0, a new desktop folder - 'Downloads' was introduced for
|
||||
// platforms and versions that don't support a default system downloads
|
||||
// folder. See nsDownloadManager for details.
|
||||
downloadFolder.label = bundlePreferences.getString("downloadsFolderName");
|
||||
iconUrlSpec = fph.getURLSpecFromFile(yield this._indexToFolder(1));
|
||||
} else {
|
||||
// 'Desktop'
|
||||
downloadFolder.label = bundlePreferences.getString("desktopFolderName");
|
||||
iconUrlSpec = fph.getURLSpecFromFile(yield this._getDownloadsFolder("Desktop"));
|
||||
}
|
||||
downloadFolder.image = "moz-icon://" + iconUrlSpec + "?size=16";
|
||||
}),
|
||||
|
||||
/**
|
||||
* Returns the textual path of a folder in readable form.
|
||||
*/
|
||||
_getDisplayNameOfFile(aFolder) {
|
||||
// TODO: would like to add support for 'Downloads on Macintosh HD'
|
||||
// for OS X users.
|
||||
return aFolder ? aFolder.path : "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the Downloads folder. If aFolder is "Desktop", then the Downloads
|
||||
* folder returned is the desktop folder; otherwise, it is a folder whose name
|
||||
* indicates that it is a download folder and whose path is as determined by
|
||||
* the XPCOM directory service via the download manager's attribute
|
||||
* defaultDownloadsDirectory.
|
||||
*
|
||||
* @throws if aFolder is not "Desktop" or "Downloads"
|
||||
*/
|
||||
_getDownloadsFolder: Task.async(function* (aFolder) {
|
||||
switch (aFolder) {
|
||||
case "Desktop":
|
||||
var fileLoc = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties);
|
||||
return fileLoc.get("Desk", Components.interfaces.nsILocalFile);
|
||||
case "Downloads":
|
||||
let downloadsDir = yield Downloads.getSystemDownloadsDirectory();
|
||||
return new FileUtils.File(downloadsDir);
|
||||
}
|
||||
throw "ASSERTION FAILED: folder type should be 'Desktop' or 'Downloads'";
|
||||
}),
|
||||
|
||||
/**
|
||||
* Determines the type of the given folder.
|
||||
*
|
||||
* @param aFolder
|
||||
* the folder whose type is to be determined
|
||||
* @returns integer
|
||||
* 0 if aFolder is the Desktop or is unspecified,
|
||||
* 1 if aFolder is the Downloads folder,
|
||||
* 2 otherwise
|
||||
*/
|
||||
_folderToIndex: Task.async(function* (aFolder) {
|
||||
if (!aFolder || aFolder.equals(yield this._getDownloadsFolder("Desktop")))
|
||||
return 0;
|
||||
else if (aFolder.equals(yield this._getDownloadsFolder("Downloads")))
|
||||
return 1;
|
||||
return 2;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Converts an integer into the corresponding folder.
|
||||
*
|
||||
* @param aIndex
|
||||
* an integer
|
||||
* @returns the Desktop folder if aIndex == 0,
|
||||
* the Downloads folder if aIndex == 1,
|
||||
* the folder stored in browser.download.dir
|
||||
*/
|
||||
_indexToFolder: Task.async(function* (aIndex) {
|
||||
switch (aIndex) {
|
||||
case 0:
|
||||
return yield this._getDownloadsFolder("Desktop");
|
||||
case 1:
|
||||
return yield this._getDownloadsFolder("Downloads");
|
||||
}
|
||||
var currentDirPref = document.getElementById("browser.download.dir");
|
||||
return currentDirPref.value;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Hide/show the "Show my windows and tabs from last time" option based
|
||||
* on the value of the browser.privatebrowsing.autostart pref.
|
||||
*/
|
||||
updateBrowserStartupLastSession() {
|
||||
let pbAutoStartPref = document.getElementById("browser.privatebrowsing.autostart");
|
||||
let startupPref = document.getElementById("browser.startup.page");
|
||||
let menu = document.getElementById("browserStartupPage");
|
||||
let option = document.getElementById("browserStartupLastSession");
|
||||
if (pbAutoStartPref.value) {
|
||||
option.setAttribute("disabled", "true");
|
||||
if (option.selected) {
|
||||
menu.selectedItem = document.getElementById("browserStartupHomePage");
|
||||
}
|
||||
} else {
|
||||
option.removeAttribute("disabled");
|
||||
startupPref.updateElements(); // select the correct index in the startup menulist
|
||||
}
|
||||
},
|
||||
|
||||
// TABS
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* browser.link.open_newwindow - int
|
||||
* Determines where links targeting new windows should open.
|
||||
* Values:
|
||||
* 1 - Open in the current window or tab.
|
||||
* 2 - Open in a new window.
|
||||
* 3 - Open in a new tab in the most recent window.
|
||||
* browser.tabs.loadInBackground - bool
|
||||
* True - Whether browser should switch to a new tab opened from a link.
|
||||
* browser.tabs.warnOnClose - bool
|
||||
* True - If when closing a window with multiple tabs the user is warned and
|
||||
* allowed to cancel the action, false to just close the window.
|
||||
* browser.tabs.warnOnOpen - bool
|
||||
* True - Whether the user should be warned when trying to open a lot of
|
||||
* tabs at once (e.g. a large folder of bookmarks), allowing to
|
||||
* cancel the action.
|
||||
* browser.taskbar.previews.enable - bool
|
||||
* True - Tabs are to be shown in Windows 7 taskbar.
|
||||
* False - Only the window is to be shown in Windows 7 taskbar.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines where a link which opens a new window will open.
|
||||
*
|
||||
* @returns |true| if such links should be opened in new tabs
|
||||
*/
|
||||
readLinkTarget() {
|
||||
var openNewWindow = document.getElementById("browser.link.open_newwindow");
|
||||
return openNewWindow.value != 2;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines where a link which opens a new window will open.
|
||||
*
|
||||
* @returns 2 if such links should be opened in new windows,
|
||||
* 3 if such links should be opened in new tabs
|
||||
*/
|
||||
writeLinkTarget() {
|
||||
var linkTargeting = document.getElementById("linkTargeting");
|
||||
return linkTargeting.checked ? 3 : 2;
|
||||
},
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* browser.shell.checkDefault
|
||||
* - true if a default-browser check (and prompt to make it so if necessary)
|
||||
* occurs at startup, false otherwise
|
||||
*/
|
||||
|
||||
/**
|
||||
* Show button for setting browser as default browser or information that
|
||||
* browser is already the default browser.
|
||||
*/
|
||||
updateSetDefaultBrowser() {
|
||||
if (AppConstants.HAVE_SHELL_SERVICE) {
|
||||
let shellSvc = getShellService();
|
||||
let defaultBrowserBox = document.getElementById("defaultBrowserBox");
|
||||
if (!shellSvc) {
|
||||
defaultBrowserBox.hidden = true;
|
||||
return;
|
||||
}
|
||||
let setDefaultPane = document.getElementById("setDefaultPane");
|
||||
let isDefault = shellSvc.isDefaultBrowser(false, true);
|
||||
setDefaultPane.selectedIndex = isDefault ? 1 : 0;
|
||||
let alwaysCheck = document.getElementById("alwaysCheckDefault");
|
||||
alwaysCheck.disabled = alwaysCheck.disabled ||
|
||||
isDefault && alwaysCheck.checked;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set browser as the operating system default browser.
|
||||
*/
|
||||
setDefaultBrowser() {
|
||||
if (AppConstants.HAVE_SHELL_SERVICE) {
|
||||
let alwaysCheckPref = document.getElementById("browser.shell.checkDefaultBrowser");
|
||||
alwaysCheckPref.value = true;
|
||||
|
||||
let shellSvc = getShellService();
|
||||
if (!shellSvc)
|
||||
return;
|
||||
try {
|
||||
shellSvc.setDefaultBrowser(true, false);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
let selectedIndex = shellSvc.isDefaultBrowser(false, true) ? 1 : 0;
|
||||
document.getElementById("setDefaultPane").selectedIndex = selectedIndex;
|
||||
}
|
||||
},
|
||||
};
|
|
@ -0,0 +1,301 @@
|
|||
# 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/.
|
||||
|
||||
<!-- General panel -->
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/main.js"/>
|
||||
|
||||
<preferences id="mainPreferences" hidden="true" data-category="paneGeneral">
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
<preference id="browser.tabs.remote.autostart"
|
||||
name="browser.tabs.remote.autostart"
|
||||
type="bool"/>
|
||||
<preference id="e10sTempPref"
|
||||
name="browser.tabs.remote.autostart.2"
|
||||
type="bool"/>
|
||||
<preference id="e10sForceEnable"
|
||||
name="browser.tabs.remote.force-enable"
|
||||
type="bool"/>
|
||||
#endif
|
||||
|
||||
<!-- Startup -->
|
||||
<preference id="browser.startup.page"
|
||||
name="browser.startup.page"
|
||||
type="int"/>
|
||||
<preference id="browser.startup.homepage"
|
||||
name="browser.startup.homepage"
|
||||
type="wstring"/>
|
||||
|
||||
#ifdef HAVE_SHELL_SERVICE
|
||||
<preference id="browser.shell.checkDefaultBrowser"
|
||||
name="browser.shell.checkDefaultBrowser"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="pref.general.disable_button.default_browser"
|
||||
name="pref.general.disable_button.default_browser"
|
||||
type="bool"/>
|
||||
#endif
|
||||
|
||||
<preference id="pref.browser.homepage.disable_button.current_page"
|
||||
name="pref.browser.homepage.disable_button.current_page"
|
||||
type="bool"/>
|
||||
<preference id="pref.browser.homepage.disable_button.bookmark_page"
|
||||
name="pref.browser.homepage.disable_button.bookmark_page"
|
||||
type="bool"/>
|
||||
<preference id="pref.browser.homepage.disable_button.restore_default"
|
||||
name="pref.browser.homepage.disable_button.restore_default"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="browser.privatebrowsing.autostart"
|
||||
name="browser.privatebrowsing.autostart"
|
||||
type="bool"/>
|
||||
|
||||
<!-- Downloads -->
|
||||
<preference id="browser.download.useDownloadDir"
|
||||
name="browser.download.useDownloadDir"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="browser.download.folderList"
|
||||
name="browser.download.folderList"
|
||||
type="int"/>
|
||||
<preference id="browser.download.dir"
|
||||
name="browser.download.dir"
|
||||
type="file"/>
|
||||
<!-- Tab preferences
|
||||
Preferences:
|
||||
|
||||
browser.link.open_newwindow
|
||||
1 opens such links in the most recent window or tab,
|
||||
2 opens such links in a new window,
|
||||
3 opens such links in a new tab
|
||||
browser.tabs.loadInBackground
|
||||
- true if display should switch to a new tab which has been opened from a
|
||||
link, false if display shouldn't switch
|
||||
browser.tabs.warnOnClose
|
||||
- true if when closing a window with multiple tabs the user is warned and
|
||||
allowed to cancel the action, false to just close the window
|
||||
browser.tabs.warnOnOpen
|
||||
- true if the user should be warned if he attempts to open a lot of tabs at
|
||||
once (e.g. a large folder of bookmarks), false otherwise
|
||||
browser.taskbar.previews.enable
|
||||
- true if tabs are to be shown in the Windows 7 taskbar
|
||||
-->
|
||||
|
||||
<preference id="browser.link.open_newwindow"
|
||||
name="browser.link.open_newwindow"
|
||||
type="int"/>
|
||||
<preference id="browser.tabs.loadInBackground"
|
||||
name="browser.tabs.loadInBackground"
|
||||
type="bool"
|
||||
inverted="true"/>
|
||||
<preference id="browser.tabs.warnOnClose"
|
||||
name="browser.tabs.warnOnClose"
|
||||
type="bool"/>
|
||||
<preference id="browser.tabs.warnOnOpen"
|
||||
name="browser.tabs.warnOnOpen"
|
||||
type="bool"/>
|
||||
<preference id="browser.sessionstore.restore_on_demand"
|
||||
name="browser.sessionstore.restore_on_demand"
|
||||
type="bool"/>
|
||||
#ifdef XP_WIN
|
||||
<preference id="browser.taskbar.previews.enable"
|
||||
name="browser.taskbar.previews.enable"
|
||||
type="bool"/>
|
||||
#endif
|
||||
<preference id="browser.ctrlTab.previews"
|
||||
name="browser.ctrlTab.previews"
|
||||
type="bool"/>
|
||||
</preferences>
|
||||
|
||||
<hbox id="header-general"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1">&paneGeneral.title;</label>
|
||||
<html:a class="help-button" target="_blank" aria-label="&helpButton.label;"></html:a>
|
||||
</hbox>
|
||||
|
||||
<!-- Startup -->
|
||||
<groupbox id="startupGroup"
|
||||
data-category="paneGeneral"
|
||||
hidden="true">
|
||||
<caption><label>&startup.label;</label></caption>
|
||||
|
||||
#ifdef MOZ_DEV_EDITION
|
||||
<vbox id="separateProfileBox">
|
||||
<checkbox id="separateProfileMode"
|
||||
label="&separateProfileMode.label;"/>
|
||||
<hbox align="center" class="indent">
|
||||
<label id="useFirefoxSync">&useFirefoxSync.label;</label>
|
||||
<label id="getStarted" class="text-link">&getStarted.label;</label>
|
||||
</hbox>
|
||||
</vbox>
|
||||
#endif
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
<checkbox id="e10sAutoStart"
|
||||
label="&e10sEnabled.label;"/>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SHELL_SERVICE
|
||||
<vbox id="defaultBrowserBox">
|
||||
<hbox align="center">
|
||||
<checkbox id="alwaysCheckDefault" preference="browser.shell.checkDefaultBrowser"
|
||||
label="&alwaysCheckDefault2.label;" accesskey="&alwaysCheckDefault2.accesskey;"/>
|
||||
</hbox>
|
||||
<deck id="setDefaultPane">
|
||||
<hbox align="center" class="indent">
|
||||
<label id="isNotDefaultLabel" flex="1">&isNotDefault.label;</label>
|
||||
<button id="setDefaultButton"
|
||||
label="&setAsMyDefaultBrowser2.label;" accesskey="&setAsMyDefaultBrowser2.accesskey;"
|
||||
preference="pref.general.disable_button.default_browser"/>
|
||||
</hbox>
|
||||
<hbox align="center" class="indent">
|
||||
<label id="isDefaultLabel" flex="1">&isDefault.label;</label>
|
||||
</hbox>
|
||||
</deck>
|
||||
<separator class="thin"/>
|
||||
</vbox>
|
||||
#endif
|
||||
|
||||
<html:table id="startupTable">
|
||||
<html:tr>
|
||||
<html:td class="label-cell">
|
||||
<label accesskey="&startupPage.accesskey;"
|
||||
control="browserStartupPage">&startupPage.label;</label>
|
||||
</html:td>
|
||||
<html:td class="content-cell">
|
||||
<menulist id="browserStartupPage"
|
||||
class="content-cell-item"
|
||||
preference="browser.startup.page">
|
||||
<menupopup>
|
||||
<menuitem label="&startupUserHomePage.label;"
|
||||
value="1"
|
||||
id="browserStartupHomePage"/>
|
||||
<menuitem label="&startupBlankPage.label;"
|
||||
value="0"
|
||||
id="browserStartupBlank"/>
|
||||
<menuitem label="&startupPrevSession.label;"
|
||||
value="3"
|
||||
id="browserStartupLastSession"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</html:td>
|
||||
</html:tr>
|
||||
<html:tr>
|
||||
<html:td class="label-cell">
|
||||
<label accesskey="&homepage.accesskey;"
|
||||
control="browserHomePage">&homepage.label;</label>
|
||||
</html:td>
|
||||
<html:td class="content-cell">
|
||||
<textbox id="browserHomePage"
|
||||
class="padded uri-element content-cell-item"
|
||||
type="autocomplete"
|
||||
autocompletesearch="unifiedcomplete"
|
||||
onsyncfrompreference="return gMainPane.syncFromHomePref();"
|
||||
onsynctopreference="return gMainPane.syncToHomePref(this.value);"
|
||||
placeholder="&abouthome.pageTitle;"
|
||||
preference="browser.startup.homepage"/>
|
||||
</html:td>
|
||||
</html:tr>
|
||||
<html:tr>
|
||||
<html:td class="label-cell" />
|
||||
<html:td class="content-cell homepage-buttons">
|
||||
<button id="useCurrent"
|
||||
class="content-cell-item"
|
||||
label=""
|
||||
accesskey="&useCurrentPage.accesskey;"
|
||||
label1="&useCurrentPage.label;"
|
||||
label2="&useMultiple.label;"
|
||||
preference="pref.browser.homepage.disable_button.current_page"/>
|
||||
<button id="useBookmark"
|
||||
class="content-cell-item"
|
||||
label="&chooseBookmark.label;"
|
||||
accesskey="&chooseBookmark.accesskey;"
|
||||
preference="pref.browser.homepage.disable_button.bookmark_page"/>
|
||||
<button id="restoreDefaultHomePage"
|
||||
class="content-cell-item"
|
||||
label="&restoreDefault.label;"
|
||||
accesskey="&restoreDefault.accesskey;"
|
||||
preference="pref.browser.homepage.disable_button.restore_default"/>
|
||||
</html:td>
|
||||
</html:tr>
|
||||
</html:table>
|
||||
</groupbox>
|
||||
|
||||
<!-- Downloads -->
|
||||
<groupbox id="downloadsGroup"
|
||||
data-category="paneGeneral"
|
||||
hidden="true">
|
||||
<caption><label>&downloads.label;</label></caption>
|
||||
|
||||
<radiogroup id="saveWhere"
|
||||
preference="browser.download.useDownloadDir"
|
||||
onsyncfrompreference="return gMainPane.readUseDownloadDir();">
|
||||
<hbox id="saveToRow">
|
||||
<radio id="saveTo"
|
||||
value="true"
|
||||
label="&saveTo.label;"
|
||||
accesskey="&saveTo.accesskey;"
|
||||
aria-labelledby="saveTo downloadFolder"/>
|
||||
<filefield id="downloadFolder"
|
||||
flex="1"
|
||||
preference="browser.download.folderList"
|
||||
preference-editable="true"
|
||||
aria-labelledby="saveTo"
|
||||
onsyncfrompreference="return gMainPane.displayDownloadDirPref();"/>
|
||||
<button id="chooseFolder"
|
||||
#ifdef XP_MACOSX
|
||||
accesskey="&chooseFolderMac.accesskey;"
|
||||
label="&chooseFolderMac.label;"
|
||||
#else
|
||||
accesskey="&chooseFolderWin.accesskey;"
|
||||
label="&chooseFolderWin.label;"
|
||||
#endif
|
||||
/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<radio id="alwaysAsk"
|
||||
value="false"
|
||||
label="&alwaysAskWhere.label;"
|
||||
accesskey="&alwaysAskWhere.accesskey;"/>
|
||||
</hbox>
|
||||
</radiogroup>
|
||||
</groupbox>
|
||||
|
||||
<!-- Tab preferences -->
|
||||
<groupbox data-category="paneGeneral"
|
||||
hidden="true" align="start">
|
||||
<caption><label>&tabsGroup.label;</label></caption>
|
||||
|
||||
<checkbox id="ctrlTabRecentlyUsedOrder" label="&ctrlTabRecentlyUsedOrder.label;"
|
||||
accesskey="&ctrlTabRecentlyUsedOrder.accesskey;"
|
||||
preference="browser.ctrlTab.previews"/>
|
||||
|
||||
<checkbox id="linkTargeting" label="&newWindowsAsTabs.label;"
|
||||
accesskey="&newWindowsAsTabs.accesskey;"
|
||||
preference="browser.link.open_newwindow"
|
||||
onsyncfrompreference="return gMainPane.readLinkTarget();"
|
||||
onsynctopreference="return gMainPane.writeLinkTarget();"/>
|
||||
|
||||
<checkbox id="warnCloseMultiple" label="&warnOnCloseMultipleTabs.label;"
|
||||
accesskey="&warnOnCloseMultipleTabs.accesskey;"
|
||||
preference="browser.tabs.warnOnClose"/>
|
||||
|
||||
<checkbox id="warnOpenMany" label="&warnOnOpenManyTabs.label;"
|
||||
accesskey="&warnOnOpenManyTabs.accesskey;"
|
||||
preference="browser.tabs.warnOnOpen"/>
|
||||
|
||||
<checkbox id="switchToNewTabs" label="&switchLinksToNewTabs.label;"
|
||||
accesskey="&switchLinksToNewTabs.accesskey;"
|
||||
preference="browser.tabs.loadInBackground"/>
|
||||
|
||||
#ifdef XP_WIN
|
||||
<checkbox id="showTabsInTaskbar" label="&showTabsInTaskbar.label;"
|
||||
accesskey="&showTabsInTaskbar.accesskey;"
|
||||
preference="browser.taskbar.previews.enable"/>
|
||||
#endif
|
||||
</groupbox>
|
|
@ -0,0 +1,13 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
|
||||
DEFINES['HAVE_SHELL_SERVICE'] = 1
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
|
@ -0,0 +1,313 @@
|
|||
/* - 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/. */
|
||||
|
||||
// Import globals from the files imported by the .xul files.
|
||||
/* import-globals-from subdialogs.js */
|
||||
/* import-globals-from advanced.js */
|
||||
/* import-globals-from main.js */
|
||||
/* import-globals-from search.js */
|
||||
/* import-globals-from containers.js */
|
||||
/* import-globals-from content.js */
|
||||
/* import-globals-from privacy.js */
|
||||
/* import-globals-from applications.js */
|
||||
/* import-globals-from security.js */
|
||||
/* import-globals-from sync.js */
|
||||
/* import-globals-from ../../../base/content/utilityOverlay.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
var gLastHash = "";
|
||||
|
||||
var gCategoryInits = new Map();
|
||||
function init_category_if_required(category) {
|
||||
let categoryInfo = gCategoryInits.get(category);
|
||||
if (!categoryInfo) {
|
||||
throw "Unknown in-content prefs category! Can't init " + category;
|
||||
}
|
||||
if (categoryInfo.inited) {
|
||||
return;
|
||||
}
|
||||
categoryInfo.init();
|
||||
}
|
||||
|
||||
function register_module(categoryName, categoryObject) {
|
||||
gCategoryInits.set(categoryName, {
|
||||
inited: false,
|
||||
init() {
|
||||
categoryObject.init();
|
||||
this.inited = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", init_all, {once: true});
|
||||
|
||||
function init_all() {
|
||||
document.documentElement.instantApply = true;
|
||||
|
||||
gSubDialog.init();
|
||||
register_module("paneGeneral", gMainPane);
|
||||
register_module("paneSearch", gSearchPane);
|
||||
register_module("panePrivacy", gPrivacyPane);
|
||||
register_module("paneContainers", gContainersPane);
|
||||
register_module("paneAdvanced", gAdvancedPane);
|
||||
register_module("paneApplications", gApplicationsPane);
|
||||
register_module("paneContent", gContentPane);
|
||||
register_module("paneSync", gSyncPane);
|
||||
register_module("paneSecurity", gSecurityPane);
|
||||
|
||||
let categories = document.getElementById("categories");
|
||||
categories.addEventListener("select", event => gotoPref(event.target.value));
|
||||
|
||||
document.documentElement.addEventListener("keydown", function(event) {
|
||||
if (event.keyCode == KeyEvent.DOM_VK_TAB) {
|
||||
categories.setAttribute("keyboard-navigation", "true");
|
||||
}
|
||||
});
|
||||
categories.addEventListener("mousedown", function() {
|
||||
this.removeAttribute("keyboard-navigation");
|
||||
});
|
||||
|
||||
window.addEventListener("hashchange", onHashChange);
|
||||
gotoPref();
|
||||
|
||||
init_dynamic_padding();
|
||||
|
||||
var initFinished = new CustomEvent("Initialized", {
|
||||
"bubbles": true,
|
||||
"cancelable": true
|
||||
});
|
||||
document.dispatchEvent(initFinished);
|
||||
|
||||
categories = categories.querySelectorAll("richlistitem.category");
|
||||
for (let category of categories) {
|
||||
let name = internalPrefCategoryNameToFriendlyName(category.value);
|
||||
let helpSelector = `#header-${name} > .help-button`;
|
||||
let helpButton = document.querySelector(helpSelector);
|
||||
helpButton.setAttribute("href", getHelpLinkURL(category.getAttribute("helpTopic")));
|
||||
}
|
||||
|
||||
// Wait until initialization of all preferences are complete before
|
||||
// notifying observers that the UI is now ready.
|
||||
Services.obs.notifyObservers(window, "advanced-pane-loaded", null);
|
||||
}
|
||||
|
||||
// Make the space above the categories list shrink on low window heights
|
||||
function init_dynamic_padding() {
|
||||
let categories = document.getElementById("categories");
|
||||
let catPadding = Number.parseInt(getComputedStyle(categories)
|
||||
.getPropertyValue("padding-top"));
|
||||
let fullHeight = categories.lastElementChild.getBoundingClientRect().bottom;
|
||||
let mediaRule = `
|
||||
@media (max-height: ${fullHeight}px) {
|
||||
#categories {
|
||||
padding-top: calc(100vh - ${fullHeight - catPadding}px);
|
||||
}
|
||||
}
|
||||
`;
|
||||
let mediaStyle = document.createElementNS("http://www.w3.org/1999/xhtml", "html:style");
|
||||
mediaStyle.setAttribute("type", "text/css");
|
||||
mediaStyle.appendChild(document.createCDATASection(mediaRule));
|
||||
document.documentElement.appendChild(mediaStyle);
|
||||
}
|
||||
|
||||
function telemetryBucketForCategory(category) {
|
||||
switch (category) {
|
||||
case "general":
|
||||
case "search":
|
||||
case "content":
|
||||
case "applications":
|
||||
case "privacy":
|
||||
case "security":
|
||||
case "sync":
|
||||
return category;
|
||||
case "advanced":
|
||||
let advancedPaneTabs = document.getElementById("advancedPrefs");
|
||||
switch (advancedPaneTabs.selectedTab.id) {
|
||||
case "generalTab":
|
||||
return "advancedGeneral";
|
||||
case "dataChoicesTab":
|
||||
return "advancedDataChoices";
|
||||
case "networkTab":
|
||||
return "advancedNetwork";
|
||||
case "updateTab":
|
||||
return "advancedUpdates";
|
||||
case "encryptionTab":
|
||||
return "advancedCerts";
|
||||
}
|
||||
// fall-through for unknown.
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
function onHashChange() {
|
||||
gotoPref();
|
||||
}
|
||||
|
||||
function gotoPref(aCategory) {
|
||||
let categories = document.getElementById("categories");
|
||||
const kDefaultCategoryInternalName = categories.firstElementChild.value;
|
||||
let hash = document.location.hash;
|
||||
let category = aCategory || hash.substr(1) || kDefaultCategoryInternalName;
|
||||
category = friendlyPrefCategoryNameToInternalName(category);
|
||||
|
||||
// Updating the hash (below) or changing the selected category
|
||||
// will re-enter gotoPref.
|
||||
if (gLastHash == category)
|
||||
return;
|
||||
let item = categories.querySelector(".category[value=" + category + "]");
|
||||
if (!item) {
|
||||
category = kDefaultCategoryInternalName;
|
||||
item = categories.querySelector(".category[value=" + category + "]");
|
||||
}
|
||||
|
||||
try {
|
||||
init_category_if_required(category);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error initializing preference category " + category + ": " + ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
let friendlyName = internalPrefCategoryNameToFriendlyName(category);
|
||||
if (gLastHash || category != kDefaultCategoryInternalName) {
|
||||
document.location.hash = friendlyName;
|
||||
}
|
||||
// Need to set the gLastHash before setting categories.selectedItem since
|
||||
// the categories 'select' event will re-enter the gotoPref codepath.
|
||||
gLastHash = category;
|
||||
categories.selectedItem = item;
|
||||
window.history.replaceState(category, document.title);
|
||||
search(category, "data-category");
|
||||
let mainContent = document.querySelector(".main-content");
|
||||
mainContent.scrollTop = 0;
|
||||
|
||||
Services.telemetry
|
||||
.getHistogramById("FX_PREFERENCES_CATEGORY_OPENED")
|
||||
.add(telemetryBucketForCategory(friendlyName));
|
||||
}
|
||||
|
||||
function search(aQuery, aAttribute) {
|
||||
let mainPrefPane = document.getElementById("mainPrefPane");
|
||||
let elements = mainPrefPane.children;
|
||||
for (let element of elements) {
|
||||
let attributeValue = element.getAttribute(aAttribute);
|
||||
element.hidden = (attributeValue != aQuery);
|
||||
}
|
||||
|
||||
let keysets = mainPrefPane.getElementsByTagName("keyset");
|
||||
for (let element of keysets) {
|
||||
let attributeValue = element.getAttribute(aAttribute);
|
||||
if (attributeValue == aQuery)
|
||||
element.removeAttribute("disabled");
|
||||
else
|
||||
element.setAttribute("disabled", true);
|
||||
}
|
||||
}
|
||||
|
||||
function helpButtonCommand() {
|
||||
let pane = history.state;
|
||||
let categories = document.getElementById("categories");
|
||||
let helpTopic = categories.querySelector(".category[value=" + pane + "]")
|
||||
.getAttribute("helpTopic");
|
||||
openHelpLink(helpTopic);
|
||||
}
|
||||
|
||||
function friendlyPrefCategoryNameToInternalName(aName) {
|
||||
if (aName.startsWith("pane"))
|
||||
return aName;
|
||||
return "pane" + aName.substring(0, 1).toUpperCase() + aName.substr(1);
|
||||
}
|
||||
|
||||
// This function is duplicated inside of utilityOverlay.js's openPreferences.
|
||||
function internalPrefCategoryNameToFriendlyName(aName) {
|
||||
return (aName || "").replace(/^pane./, function(toReplace) { return toReplace[4].toLowerCase(); });
|
||||
}
|
||||
|
||||
// Put up a confirm dialog with "ok to restart", "revert without restarting"
|
||||
// and "restart later" buttons and returns the index of the button chosen.
|
||||
// We can choose not to display the "restart later", or "revert" buttons,
|
||||
// altough the later still lets us revert by using the escape key.
|
||||
//
|
||||
// The constants are useful to interpret the return value of the function.
|
||||
const CONFIRM_RESTART_PROMPT_RESTART_NOW = 0;
|
||||
const CONFIRM_RESTART_PROMPT_CANCEL = 1;
|
||||
const CONFIRM_RESTART_PROMPT_RESTART_LATER = 2;
|
||||
function confirmRestartPrompt(aRestartToEnable, aDefaultButtonIndex,
|
||||
aWantRevertAsCancelButton,
|
||||
aWantRestartLaterButton) {
|
||||
let brandName = document.getElementById("bundleBrand").getString("brandShortName");
|
||||
let bundle = document.getElementById("bundlePreferences");
|
||||
let msg = bundle.getFormattedString(aRestartToEnable ?
|
||||
"featureEnableRequiresRestart" :
|
||||
"featureDisableRequiresRestart",
|
||||
[brandName]);
|
||||
let title = bundle.getFormattedString("shouldRestartTitle", [brandName]);
|
||||
let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
|
||||
|
||||
// Set up the first (index 0) button:
|
||||
let button0Text = bundle.getFormattedString("okToRestartButton", [brandName]);
|
||||
let buttonFlags = (Services.prompt.BUTTON_POS_0 *
|
||||
Services.prompt.BUTTON_TITLE_IS_STRING);
|
||||
|
||||
|
||||
// Set up the second (index 1) button:
|
||||
let button1Text = null;
|
||||
if (aWantRevertAsCancelButton) {
|
||||
button1Text = bundle.getString("revertNoRestartButton");
|
||||
buttonFlags += (Services.prompt.BUTTON_POS_1 *
|
||||
Services.prompt.BUTTON_TITLE_IS_STRING);
|
||||
} else {
|
||||
buttonFlags += (Services.prompt.BUTTON_POS_1 *
|
||||
Services.prompt.BUTTON_TITLE_CANCEL);
|
||||
}
|
||||
|
||||
// Set up the third (index 2) button:
|
||||
let button2Text = null;
|
||||
if (aWantRestartLaterButton) {
|
||||
button2Text = bundle.getString("restartLater");
|
||||
buttonFlags += (Services.prompt.BUTTON_POS_2 *
|
||||
Services.prompt.BUTTON_TITLE_IS_STRING);
|
||||
}
|
||||
|
||||
switch (aDefaultButtonIndex) {
|
||||
case 0:
|
||||
buttonFlags += Services.prompt.BUTTON_POS_0_DEFAULT;
|
||||
break;
|
||||
case 1:
|
||||
buttonFlags += Services.prompt.BUTTON_POS_1_DEFAULT;
|
||||
break;
|
||||
case 2:
|
||||
buttonFlags += Services.prompt.BUTTON_POS_2_DEFAULT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
let buttonIndex = prompts.confirmEx(window, title, msg, buttonFlags,
|
||||
button0Text, button1Text, button2Text,
|
||||
null, {});
|
||||
|
||||
// If we have the second confirmation dialog for restart, see if the user
|
||||
// cancels out at that point.
|
||||
if (buttonIndex == CONFIRM_RESTART_PROMPT_RESTART_NOW) {
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
|
||||
"restart");
|
||||
if (cancelQuit.data) {
|
||||
buttonIndex = CONFIRM_RESTART_PROMPT_CANCEL;
|
||||
}
|
||||
}
|
||||
return buttonIndex;
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/in-content/common.css"?>
|
||||
<?xml-stylesheet
|
||||
href="chrome://browser/skin/preferences/in-content/preferences.css"?>
|
||||
<?xml-stylesheet
|
||||
href="chrome://browser/content/preferences/handlers.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/applications.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/in-content-old/search.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/in-content-old/containers.css"?>
|
||||
|
||||
<!DOCTYPE page [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
<!ENTITY % globalPreferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
|
||||
<!ENTITY % preferencesDTD SYSTEM
|
||||
"chrome://browser/locale/preferences-old/preferences.dtd">
|
||||
<!ENTITY % privacyDTD SYSTEM "chrome://browser/locale/preferences-old/privacy.dtd">
|
||||
<!ENTITY % tabsDTD SYSTEM "chrome://browser/locale/preferences-old/tabs.dtd">
|
||||
<!ENTITY % searchDTD SYSTEM "chrome://browser/locale/preferences-old/search.dtd">
|
||||
<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
|
||||
<!ENTITY % syncDTD SYSTEM "chrome://browser/locale/preferences-old/sync.dtd">
|
||||
<!ENTITY % securityDTD SYSTEM
|
||||
"chrome://browser/locale/preferences-old/security.dtd">
|
||||
<!ENTITY % containersDTD SYSTEM
|
||||
"chrome://browser/locale/preferences-old/containers.dtd">
|
||||
<!ENTITY % sanitizeDTD SYSTEM "chrome://browser/locale/sanitize.dtd">
|
||||
<!ENTITY % mainDTD SYSTEM "chrome://browser/locale/preferences-old/main.dtd">
|
||||
<!ENTITY % aboutHomeDTD SYSTEM "chrome://browser/locale/aboutHome.dtd">
|
||||
<!ENTITY % contentDTD SYSTEM "chrome://browser/locale/preferences-old/content.dtd">
|
||||
<!ENTITY % applicationsDTD SYSTEM
|
||||
"chrome://browser/locale/preferences-old/applications.dtd">
|
||||
<!ENTITY % advancedDTD SYSTEM
|
||||
"chrome://browser/locale/preferences-old/advanced.dtd">
|
||||
%brandDTD;
|
||||
%globalPreferencesDTD;
|
||||
%preferencesDTD;
|
||||
%privacyDTD;
|
||||
%tabsDTD;
|
||||
%searchDTD;
|
||||
%syncBrandDTD;
|
||||
%syncDTD;
|
||||
%securityDTD;
|
||||
%containersDTD;
|
||||
%sanitizeDTD;
|
||||
%mainDTD;
|
||||
%aboutHomeDTD;
|
||||
%contentDTD;
|
||||
%applicationsDTD;
|
||||
%advancedDTD;
|
||||
]>
|
||||
|
||||
#ifdef XP_WIN
|
||||
#define USE_WIN_TITLE_STYLE
|
||||
#endif
|
||||
|
||||
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
disablefastfind="true"
|
||||
#ifdef USE_WIN_TITLE_STYLE
|
||||
title="&prefWindow.titleWin;">
|
||||
#else
|
||||
title="&prefWindow.title;">
|
||||
#endif
|
||||
|
||||
<html:link rel="shortcut icon"
|
||||
href="chrome://browser/skin/preferences/in-content-old/favicon.ico"/>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/utilityOverlay.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/preferences.js"/>
|
||||
<script src="chrome://browser/content/preferences/in-content-old/subdialogs.js"/>
|
||||
|
||||
<stringbundle id="bundleBrand"
|
||||
src="chrome://branding/locale/brand.properties"/>
|
||||
<stringbundle id="bundlePreferences"
|
||||
src="chrome://browser/locale/preferences-old/preferences.properties"/>
|
||||
|
||||
<stringbundleset id="appManagerBundleset">
|
||||
<stringbundle id="appManagerBundle"
|
||||
src="chrome://browser/locale/preferences-old/applicationManager.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<stack flex="1">
|
||||
<hbox flex="1">
|
||||
|
||||
<!-- category list -->
|
||||
<richlistbox id="categories">
|
||||
<richlistitem id="category-general"
|
||||
class="category"
|
||||
value="paneGeneral"
|
||||
helpTopic="prefs-main"
|
||||
tooltiptext="&paneGeneral.title;"
|
||||
align="center">
|
||||
<image class="category-icon"/>
|
||||
<label class="category-name" flex="1">&paneGeneral.title;</label>
|
||||
</richlistitem>
|
||||
|
||||
<richlistitem id="category-search"
|
||||
class="category"
|
||||
value="paneSearch"
|
||||
helpTopic="prefs-search"
|
||||
tooltiptext="&paneSearch.title;"
|
||||
align="center">
|
||||
<image class="category-icon"/>
|
||||
<label class="category-name" flex="1">&paneSearch.title;</label>
|
||||
</richlistitem>
|
||||
|
||||
<richlistitem id="category-content"
|
||||
class="category"
|
||||
value="paneContent"
|
||||
helpTopic="prefs-content"
|
||||
tooltiptext="&paneContent.title;"
|
||||
align="center">
|
||||
<image class="category-icon"/>
|
||||
<label class="category-name" flex="1">&paneContent.title;</label>
|
||||
</richlistitem>
|
||||
|
||||
<richlistitem id="category-application"
|
||||
class="category"
|
||||
value="paneApplications"
|
||||
helpTopic="prefs-applications"
|
||||
tooltiptext="&paneApplications.title;"
|
||||
align="center">
|
||||
<image class="category-icon"/>
|
||||
<label class="category-name" flex="1">&paneApplications.title;</label>
|
||||
</richlistitem>
|
||||
|
||||
<richlistitem id="category-privacy"
|
||||
class="category"
|
||||
value="panePrivacy"
|
||||
helpTopic="prefs-privacy"
|
||||
tooltiptext="&panePrivacy.title;"
|
||||
align="center">
|
||||
<image class="category-icon"/>
|
||||
<label class="category-name" flex="1">&panePrivacy.title;</label>
|
||||
</richlistitem>
|
||||
|
||||
<richlistitem id="category-containers"
|
||||
class="category"
|
||||
value="paneContainers"
|
||||
helpTopic="prefs-containers"
|
||||
hidden="true"/>
|
||||
|
||||
<richlistitem id="category-security"
|
||||
class="category"
|
||||
value="paneSecurity"
|
||||
helpTopic="prefs-security"
|
||||
tooltiptext="&paneSecurity.title;"
|
||||
align="center">
|
||||
<image class="category-icon"/>
|
||||
<label class="category-name" flex="1">&paneSecurity.title;</label>
|
||||
</richlistitem>
|
||||
|
||||
<richlistitem id="category-sync"
|
||||
class="category"
|
||||
value="paneSync"
|
||||
helpTopic="prefs-weave"
|
||||
tooltiptext="&paneSync.title;"
|
||||
align="center">
|
||||
<image class="category-icon"/>
|
||||
<label class="category-name" flex="1">&paneSync.title;</label>
|
||||
</richlistitem>
|
||||
|
||||
<richlistitem id="category-advanced"
|
||||
class="category"
|
||||
value="paneAdvanced"
|
||||
helpTopic="prefs-advanced-general"
|
||||
tooltiptext="&paneAdvanced.title;"
|
||||
align="center">
|
||||
<image class="category-icon"/>
|
||||
<label class="category-name" flex="1">&paneAdvanced.title;</label>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
<keyset>
|
||||
<!-- Disable the findbar because it doesn't work properly.
|
||||
Remove this keyset once bug 1094240 ("disablefastfind" attribute
|
||||
broken in e10s mode) is fixed. -->
|
||||
<key key="&focusSearch1.key;" modifiers="accel" id="focusSearch1" oncommand=";"/>
|
||||
</keyset>
|
||||
|
||||
<vbox class="main-content" flex="1">
|
||||
<prefpane id="mainPrefPane">
|
||||
#include main.xul
|
||||
#include search.xul
|
||||
#include privacy.xul
|
||||
#include containers.xul
|
||||
#include advanced.xul
|
||||
#include applications.xul
|
||||
#include content.xul
|
||||
#include security.xul
|
||||
#include sync.xul
|
||||
</prefpane>
|
||||
</vbox>
|
||||
|
||||
</hbox>
|
||||
|
||||
<vbox id="dialogOverlay" align="center" pack="center">
|
||||
<groupbox id="dialogBox"
|
||||
orient="vertical"
|
||||
pack="end"
|
||||
role="dialog"
|
||||
aria-labelledby="dialogTitle">
|
||||
<caption flex="1" align="center">
|
||||
<label id="dialogTitle" flex="1"></label>
|
||||
<button id="dialogClose"
|
||||
class="close-icon"
|
||||
aria-label="&preferencesCloseButton.label;"/>
|
||||
</caption>
|
||||
<browser id="dialogFrame"
|
||||
name="dialogFrame"
|
||||
autoscroll="false"
|
||||
disablehistory="true"/>
|
||||
</groupbox>
|
||||
</vbox>
|
||||
</stack>
|
||||
</page>
|
|
@ -0,0 +1,698 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from preferences.js */
|
||||
|
||||
Components.utils.import("resource://gre/modules/AppConstants.jsm");
|
||||
Components.utils.import("resource://gre/modules/PluralForm.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
|
||||
"resource://gre/modules/ContextualIdentityService.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
|
||||
var gPrivacyPane = {
|
||||
|
||||
/**
|
||||
* Whether the use has selected the auto-start private browsing mode in the UI.
|
||||
*/
|
||||
_autoStartPrivateBrowsing: false,
|
||||
|
||||
/**
|
||||
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
|
||||
*/
|
||||
_shouldPromptForRestart: true,
|
||||
|
||||
/**
|
||||
* Show the Tracking Protection UI depending on the
|
||||
* privacy.trackingprotection.ui.enabled pref, and linkify its Learn More link
|
||||
*/
|
||||
_initTrackingProtection() {
|
||||
if (!Services.prefs.getBoolPref("privacy.trackingprotection.ui.enabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
let link = document.getElementById("trackingProtectionLearnMore");
|
||||
let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "tracking-protection";
|
||||
link.setAttribute("href", url);
|
||||
|
||||
this.trackingProtectionReadPrefs();
|
||||
|
||||
document.getElementById("trackingprotectionbox").hidden = false;
|
||||
document.getElementById("trackingprotectionpbmbox").hidden = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Linkify the Learn More link of the Private Browsing Mode Tracking
|
||||
* Protection UI.
|
||||
*/
|
||||
_initTrackingProtectionPBM() {
|
||||
let link = document.getElementById("trackingProtectionPBMLearnMore");
|
||||
let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "tracking-protection-pbm";
|
||||
link.setAttribute("href", url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize autocomplete to ensure prefs are in sync.
|
||||
*/
|
||||
_initAutocomplete() {
|
||||
Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
|
||||
.getService(Components.interfaces.mozIPlacesAutoComplete);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the Containers UI depending on the privacy.userContext.ui.enabled pref.
|
||||
*/
|
||||
_initBrowserContainers() {
|
||||
if (!Services.prefs.getBoolPref("privacy.userContext.ui.enabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
let link = document.getElementById("browserContainersLearnMore");
|
||||
link.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "containers";
|
||||
|
||||
document.getElementById("browserContainersbox").hidden = false;
|
||||
|
||||
document.getElementById("browserContainersCheckbox").checked =
|
||||
Services.prefs.getBoolPref("privacy.userContext.enabled");
|
||||
},
|
||||
|
||||
_checkBrowserContainers(event) {
|
||||
let checkbox = document.getElementById("browserContainersCheckbox");
|
||||
if (checkbox.checked) {
|
||||
Services.prefs.setBoolPref("privacy.userContext.enabled", true);
|
||||
return;
|
||||
}
|
||||
|
||||
let count = ContextualIdentityService.countContainerTabs();
|
||||
if (count == 0) {
|
||||
Services.prefs.setBoolPref("privacy.userContext.enabled", false);
|
||||
return;
|
||||
}
|
||||
|
||||
let bundlePreferences = document.getElementById("bundlePreferences");
|
||||
|
||||
let title = bundlePreferences.getString("disableContainersAlertTitle");
|
||||
let message = PluralForm.get(count, bundlePreferences.getString("disableContainersMsg"))
|
||||
.replace("#S", count)
|
||||
let okButton = PluralForm.get(count, bundlePreferences.getString("disableContainersOkButton"))
|
||||
.replace("#S", count)
|
||||
let cancelButton = bundlePreferences.getString("disableContainersButton2");
|
||||
|
||||
let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
|
||||
(Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1);
|
||||
|
||||
let rv = Services.prompt.confirmEx(window, title, message, buttonFlags,
|
||||
okButton, cancelButton, null, null, {});
|
||||
if (rv == 0) {
|
||||
ContextualIdentityService.closeContainerTabs();
|
||||
Services.prefs.setBoolPref("privacy.userContext.enabled", false);
|
||||
return;
|
||||
}
|
||||
|
||||
checkbox.checked = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up the UI for the number of days of history to keep, and updates the
|
||||
* label of the "Clear Now..." button.
|
||||
*/
|
||||
init() {
|
||||
function setEventListener(aId, aEventType, aCallback) {
|
||||
document.getElementById(aId)
|
||||
.addEventListener(aEventType, aCallback.bind(gPrivacyPane));
|
||||
}
|
||||
|
||||
this._updateSanitizeSettingsButton();
|
||||
this.initializeHistoryMode();
|
||||
this.updateHistoryModePane();
|
||||
this.updatePrivacyMicroControls();
|
||||
this.initAutoStartPrivateBrowsingReverter();
|
||||
this._initTrackingProtection();
|
||||
this._initTrackingProtectionPBM();
|
||||
this._initAutocomplete();
|
||||
this._initBrowserContainers();
|
||||
|
||||
setEventListener("privacy.sanitize.sanitizeOnShutdown", "change",
|
||||
gPrivacyPane._updateSanitizeSettingsButton);
|
||||
setEventListener("browser.privatebrowsing.autostart", "change",
|
||||
gPrivacyPane.updatePrivacyMicroControls);
|
||||
setEventListener("historyMode", "command", function() {
|
||||
gPrivacyPane.updateHistoryModePane();
|
||||
gPrivacyPane.updateHistoryModePrefs();
|
||||
gPrivacyPane.updatePrivacyMicroControls();
|
||||
gPrivacyPane.updateAutostart();
|
||||
});
|
||||
setEventListener("historyRememberClear", "click", function() {
|
||||
gPrivacyPane.clearPrivateDataNow(false);
|
||||
return false;
|
||||
});
|
||||
setEventListener("historyRememberCookies", "click", function() {
|
||||
gPrivacyPane.showCookies();
|
||||
return false;
|
||||
});
|
||||
setEventListener("historyDontRememberClear", "click", function() {
|
||||
gPrivacyPane.clearPrivateDataNow(true);
|
||||
return false;
|
||||
});
|
||||
setEventListener("doNotTrackSettings", "click", function() {
|
||||
gPrivacyPane.showDoNotTrackSettings();
|
||||
return false;
|
||||
});
|
||||
setEventListener("privateBrowsingAutoStart", "command",
|
||||
gPrivacyPane.updateAutostart);
|
||||
setEventListener("cookieExceptions", "command",
|
||||
gPrivacyPane.showCookieExceptions);
|
||||
setEventListener("showCookiesButton", "command",
|
||||
gPrivacyPane.showCookies);
|
||||
setEventListener("clearDataSettings", "command",
|
||||
gPrivacyPane.showClearPrivateDataSettings);
|
||||
setEventListener("trackingProtectionRadioGroup", "command",
|
||||
gPrivacyPane.trackingProtectionWritePrefs);
|
||||
setEventListener("trackingProtectionExceptions", "command",
|
||||
gPrivacyPane.showTrackingProtectionExceptions);
|
||||
setEventListener("changeBlockList", "command",
|
||||
gPrivacyPane.showBlockLists);
|
||||
setEventListener("changeBlockListPBM", "command",
|
||||
gPrivacyPane.showBlockLists);
|
||||
setEventListener("browserContainersCheckbox", "command",
|
||||
gPrivacyPane._checkBrowserContainers);
|
||||
setEventListener("browserContainersSettings", "command",
|
||||
gPrivacyPane.showContainerSettings);
|
||||
},
|
||||
|
||||
// TRACKING PROTECTION MODE
|
||||
|
||||
/**
|
||||
* Selects the right item of the Tracking Protection radiogroup.
|
||||
*/
|
||||
trackingProtectionReadPrefs() {
|
||||
let enabledPref = document.getElementById("privacy.trackingprotection.enabled");
|
||||
let pbmPref = document.getElementById("privacy.trackingprotection.pbmode.enabled");
|
||||
let radiogroup = document.getElementById("trackingProtectionRadioGroup");
|
||||
|
||||
// Global enable takes precedence over enabled in Private Browsing.
|
||||
if (enabledPref.value) {
|
||||
radiogroup.value = "always";
|
||||
} else if (pbmPref.value) {
|
||||
radiogroup.value = "private";
|
||||
} else {
|
||||
radiogroup.value = "never";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the pref values based on the selected item of the radiogroup.
|
||||
*/
|
||||
trackingProtectionWritePrefs() {
|
||||
let enabledPref = document.getElementById("privacy.trackingprotection.enabled");
|
||||
let pbmPref = document.getElementById("privacy.trackingprotection.pbmode.enabled");
|
||||
let radiogroup = document.getElementById("trackingProtectionRadioGroup");
|
||||
|
||||
switch (radiogroup.value) {
|
||||
case "always":
|
||||
enabledPref.value = true;
|
||||
pbmPref.value = true;
|
||||
break;
|
||||
case "private":
|
||||
enabledPref.value = false;
|
||||
pbmPref.value = true;
|
||||
break;
|
||||
case "never":
|
||||
enabledPref.value = false;
|
||||
pbmPref.value = false;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
// HISTORY MODE
|
||||
|
||||
/**
|
||||
* The list of preferences which affect the initial history mode settings.
|
||||
* If the auto start private browsing mode pref is active, the initial
|
||||
* history mode would be set to "Don't remember anything".
|
||||
* If ALL of these preferences are set to the values that correspond
|
||||
* to keeping some part of history, and the auto-start
|
||||
* private browsing mode is not active, the initial history mode would be
|
||||
* set to "Remember everything".
|
||||
* Otherwise, the initial history mode would be set to "Custom".
|
||||
*
|
||||
* Extensions adding their own preferences can set values here if needed.
|
||||
*/
|
||||
prefsForKeepingHistory: {
|
||||
"places.history.enabled": true, // History is enabled
|
||||
"browser.formfill.enable": true, // Form information is saved
|
||||
"network.cookie.cookieBehavior": 0, // All cookies are enabled
|
||||
"network.cookie.lifetimePolicy": 0, // Cookies use supplied lifetime
|
||||
"privacy.sanitize.sanitizeOnShutdown": false, // Private date is NOT cleared on shutdown
|
||||
},
|
||||
|
||||
/**
|
||||
* The list of control IDs which are dependent on the auto-start private
|
||||
* browsing setting, such that in "Custom" mode they would be disabled if
|
||||
* the auto-start private browsing checkbox is checked, and enabled otherwise.
|
||||
*
|
||||
* Extensions adding their own controls can append their IDs to this array if needed.
|
||||
*/
|
||||
dependentControls: [
|
||||
"rememberHistory",
|
||||
"rememberForms",
|
||||
"keepUntil",
|
||||
"keepCookiesUntil",
|
||||
"alwaysClear",
|
||||
"clearDataSettings"
|
||||
],
|
||||
|
||||
/**
|
||||
* Check whether preferences values are set to keep history
|
||||
*
|
||||
* @param aPrefs an array of pref names to check for
|
||||
* @returns boolean true if all of the prefs are set to keep history,
|
||||
* false otherwise
|
||||
*/
|
||||
_checkHistoryValues(aPrefs) {
|
||||
for (let pref of Object.keys(aPrefs)) {
|
||||
if (document.getElementById(pref).value != aPrefs[pref])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the history mode menulist based on the privacy preferences
|
||||
*/
|
||||
initializeHistoryMode() {
|
||||
let mode;
|
||||
let getVal = aPref => document.getElementById(aPref).value;
|
||||
|
||||
if (getVal("privacy.history.custom"))
|
||||
mode = "custom";
|
||||
else if (this._checkHistoryValues(this.prefsForKeepingHistory)) {
|
||||
if (getVal("browser.privatebrowsing.autostart"))
|
||||
mode = "dontremember";
|
||||
else
|
||||
mode = "remember";
|
||||
} else
|
||||
mode = "custom";
|
||||
|
||||
document.getElementById("historyMode").value = mode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the selected pane based on the history mode menulist
|
||||
*/
|
||||
updateHistoryModePane() {
|
||||
let selectedIndex = -1;
|
||||
switch (document.getElementById("historyMode").value) {
|
||||
case "remember":
|
||||
selectedIndex = 0;
|
||||
break;
|
||||
case "dontremember":
|
||||
selectedIndex = 1;
|
||||
break;
|
||||
case "custom":
|
||||
selectedIndex = 2;
|
||||
break;
|
||||
}
|
||||
document.getElementById("historyPane").selectedIndex = selectedIndex;
|
||||
document.getElementById("privacy.history.custom").value = selectedIndex == 2;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the private browsing auto-start pref and the history mode
|
||||
* micro-management prefs based on the history mode menulist
|
||||
*/
|
||||
updateHistoryModePrefs() {
|
||||
let pref = document.getElementById("browser.privatebrowsing.autostart");
|
||||
switch (document.getElementById("historyMode").value) {
|
||||
case "remember":
|
||||
if (pref.value)
|
||||
pref.value = false;
|
||||
|
||||
// select the remember history option if needed
|
||||
let rememberHistoryCheckbox = document.getElementById("rememberHistory");
|
||||
if (!rememberHistoryCheckbox.checked)
|
||||
rememberHistoryCheckbox.checked = true;
|
||||
|
||||
// select the remember forms history option
|
||||
document.getElementById("browser.formfill.enable").value = true;
|
||||
|
||||
// select the allow cookies option
|
||||
document.getElementById("network.cookie.cookieBehavior").value = 0;
|
||||
// select the cookie lifetime policy option
|
||||
document.getElementById("network.cookie.lifetimePolicy").value = 0;
|
||||
|
||||
// select the clear on close option
|
||||
document.getElementById("privacy.sanitize.sanitizeOnShutdown").value = false;
|
||||
break;
|
||||
case "dontremember":
|
||||
if (!pref.value)
|
||||
pref.value = true;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the privacy micro-management controls based on the
|
||||
* value of the private browsing auto-start checkbox.
|
||||
*/
|
||||
updatePrivacyMicroControls() {
|
||||
if (document.getElementById("historyMode").value == "custom") {
|
||||
let disabled = this._autoStartPrivateBrowsing =
|
||||
document.getElementById("privateBrowsingAutoStart").checked;
|
||||
this.dependentControls.forEach(function(aElement) {
|
||||
let control = document.getElementById(aElement);
|
||||
let preferenceId = control.getAttribute("preference");
|
||||
if (!preferenceId) {
|
||||
let dependentControlId = control.getAttribute("control");
|
||||
if (dependentControlId) {
|
||||
let dependentControl = document.getElementById(dependentControlId);
|
||||
preferenceId = dependentControl.getAttribute("preference");
|
||||
}
|
||||
}
|
||||
|
||||
let preference = preferenceId ? document.getElementById(preferenceId) : {};
|
||||
control.disabled = disabled || preference.locked;
|
||||
});
|
||||
|
||||
// adjust the cookie controls status
|
||||
this.readAcceptCookies();
|
||||
let lifetimePolicy = document.getElementById("network.cookie.lifetimePolicy").value;
|
||||
if (lifetimePolicy != Ci.nsICookieService.ACCEPT_NORMALLY &&
|
||||
lifetimePolicy != Ci.nsICookieService.ACCEPT_SESSION &&
|
||||
lifetimePolicy != Ci.nsICookieService.ACCEPT_FOR_N_DAYS) {
|
||||
lifetimePolicy = Ci.nsICookieService.ACCEPT_NORMALLY;
|
||||
}
|
||||
document.getElementById("keepCookiesUntil").value = disabled ? 2 : lifetimePolicy;
|
||||
|
||||
// adjust the checked state of the sanitizeOnShutdown checkbox
|
||||
document.getElementById("alwaysClear").checked = disabled ? false :
|
||||
document.getElementById("privacy.sanitize.sanitizeOnShutdown").value;
|
||||
|
||||
// adjust the checked state of the remember history checkboxes
|
||||
document.getElementById("rememberHistory").checked = disabled ? false :
|
||||
document.getElementById("places.history.enabled").value;
|
||||
document.getElementById("rememberForms").checked = disabled ? false :
|
||||
document.getElementById("browser.formfill.enable").value;
|
||||
|
||||
if (!disabled) {
|
||||
// adjust the Settings button for sanitizeOnShutdown
|
||||
this._updateSanitizeSettingsButton();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// PRIVATE BROWSING
|
||||
|
||||
/**
|
||||
* Initialize the starting state for the auto-start private browsing mode pref reverter.
|
||||
*/
|
||||
initAutoStartPrivateBrowsingReverter() {
|
||||
let mode = document.getElementById("historyMode");
|
||||
let autoStart = document.getElementById("privateBrowsingAutoStart");
|
||||
this._lastMode = mode.selectedIndex;
|
||||
this._lastCheckState = autoStart.hasAttribute("checked");
|
||||
},
|
||||
|
||||
_lastMode: null,
|
||||
_lastCheckState: null,
|
||||
updateAutostart() {
|
||||
let mode = document.getElementById("historyMode");
|
||||
let autoStart = document.getElementById("privateBrowsingAutoStart");
|
||||
let pref = document.getElementById("browser.privatebrowsing.autostart");
|
||||
if ((mode.value == "custom" && this._lastCheckState == autoStart.checked) ||
|
||||
(mode.value == "remember" && !this._lastCheckState) ||
|
||||
(mode.value == "dontremember" && this._lastCheckState)) {
|
||||
// These are all no-op changes, so we don't need to prompt.
|
||||
this._lastMode = mode.selectedIndex;
|
||||
this._lastCheckState = autoStart.hasAttribute("checked");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._shouldPromptForRestart) {
|
||||
// We're performing a revert. Just let it happen.
|
||||
return;
|
||||
}
|
||||
|
||||
let buttonIndex = confirmRestartPrompt(autoStart.checked, 1,
|
||||
true, false);
|
||||
if (buttonIndex == CONFIRM_RESTART_PROMPT_RESTART_NOW) {
|
||||
pref.value = autoStart.hasAttribute("checked");
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Ci.nsIAppStartup);
|
||||
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
|
||||
return;
|
||||
}
|
||||
|
||||
this._shouldPromptForRestart = false;
|
||||
|
||||
if (this._lastCheckState) {
|
||||
autoStart.checked = "checked";
|
||||
} else {
|
||||
autoStart.removeAttribute("checked");
|
||||
}
|
||||
pref.value = autoStart.hasAttribute("checked");
|
||||
mode.selectedIndex = this._lastMode;
|
||||
mode.doCommand();
|
||||
|
||||
this._shouldPromptForRestart = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays fine-grained, per-site preferences for tracking protection.
|
||||
*/
|
||||
showTrackingProtectionExceptions() {
|
||||
let bundlePreferences = document.getElementById("bundlePreferences");
|
||||
let params = {
|
||||
permissionType: "trackingprotection",
|
||||
hideStatusColumn: true,
|
||||
windowTitle: bundlePreferences.getString("trackingprotectionpermissionstitle"),
|
||||
introText: bundlePreferences.getString("trackingprotectionpermissionstext"),
|
||||
};
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
null, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays container panel for customising and adding containers.
|
||||
*/
|
||||
showContainerSettings() {
|
||||
gotoPref("containers");
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the available block lists for tracking protection.
|
||||
*/
|
||||
showBlockLists() {
|
||||
var bundlePreferences = document.getElementById("bundlePreferences");
|
||||
let brandName = document.getElementById("bundleBrand")
|
||||
.getString("brandShortName");
|
||||
var params = { brandShortName: brandName,
|
||||
windowTitle: bundlePreferences.getString("blockliststitle"),
|
||||
introText: bundlePreferences.getString("blockliststext") };
|
||||
gSubDialog.open("chrome://browser/content/preferences/blocklists.xul",
|
||||
null, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the Do Not Track settings dialog.
|
||||
*/
|
||||
showDoNotTrackSettings() {
|
||||
gSubDialog.open("chrome://browser/content/preferences/donottrack.xul",
|
||||
"resizable=no");
|
||||
},
|
||||
|
||||
// HISTORY
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* places.history.enabled
|
||||
* - whether history is enabled or not
|
||||
* browser.formfill.enable
|
||||
* - true if entries in forms and the search bar should be saved, false
|
||||
* otherwise
|
||||
*/
|
||||
|
||||
// COOKIES
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* network.cookie.cookieBehavior
|
||||
* - determines how the browser should handle cookies:
|
||||
* 0 means enable all cookies
|
||||
* 1 means reject all third party cookies
|
||||
* 2 means disable all cookies
|
||||
* 3 means reject third party cookies unless at least one is already set for the eTLD
|
||||
* see netwerk/cookie/src/nsCookieService.cpp for details
|
||||
* network.cookie.lifetimePolicy
|
||||
* - determines how long cookies are stored:
|
||||
* 0 means keep cookies until they expire
|
||||
* 2 means keep cookies until the browser is closed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reads the network.cookie.cookieBehavior preference value and
|
||||
* enables/disables the rest of the cookie UI accordingly, returning true
|
||||
* if cookies are enabled.
|
||||
*/
|
||||
readAcceptCookies() {
|
||||
var pref = document.getElementById("network.cookie.cookieBehavior");
|
||||
var acceptThirdPartyLabel = document.getElementById("acceptThirdPartyLabel");
|
||||
var acceptThirdPartyMenu = document.getElementById("acceptThirdPartyMenu");
|
||||
var keepUntil = document.getElementById("keepUntil");
|
||||
var menu = document.getElementById("keepCookiesUntil");
|
||||
|
||||
// enable the rest of the UI for anything other than "disable all cookies"
|
||||
var acceptCookies = (pref.value != 2);
|
||||
|
||||
acceptThirdPartyLabel.disabled = acceptThirdPartyMenu.disabled = !acceptCookies;
|
||||
keepUntil.disabled = menu.disabled = this._autoStartPrivateBrowsing || !acceptCookies;
|
||||
|
||||
return acceptCookies;
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables/disables the "keep until" label and menulist in response to the
|
||||
* "accept cookies" checkbox being checked or unchecked.
|
||||
*/
|
||||
writeAcceptCookies() {
|
||||
var accept = document.getElementById("acceptCookies");
|
||||
var acceptThirdPartyMenu = document.getElementById("acceptThirdPartyMenu");
|
||||
|
||||
// if we're enabling cookies, automatically select 'accept third party always'
|
||||
if (accept.checked)
|
||||
acceptThirdPartyMenu.selectedIndex = 0;
|
||||
|
||||
return accept.checked ? 0 : 2;
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts between network.cookie.cookieBehavior and the third-party cookie UI
|
||||
*/
|
||||
readAcceptThirdPartyCookies() {
|
||||
var pref = document.getElementById("network.cookie.cookieBehavior");
|
||||
switch (pref.value) {
|
||||
case 0:
|
||||
return "always";
|
||||
case 1:
|
||||
return "never";
|
||||
case 2:
|
||||
return "never";
|
||||
case 3:
|
||||
return "visited";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
writeAcceptThirdPartyCookies() {
|
||||
var accept = document.getElementById("acceptThirdPartyMenu").selectedItem;
|
||||
switch (accept.value) {
|
||||
case "always":
|
||||
return 0;
|
||||
case "visited":
|
||||
return 3;
|
||||
case "never":
|
||||
return 1;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays fine-grained, per-site preferences for cookies.
|
||||
*/
|
||||
showCookieExceptions() {
|
||||
var bundlePreferences = document.getElementById("bundlePreferences");
|
||||
var params = { blockVisible: true,
|
||||
sessionVisible: true,
|
||||
allowVisible: true,
|
||||
prefilledHost: "",
|
||||
permissionType: "cookie",
|
||||
windowTitle: bundlePreferences.getString("cookiepermissionstitle"),
|
||||
introText: bundlePreferences.getString("cookiepermissionstext") };
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
null, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays all the user's cookies in a dialog.
|
||||
*/
|
||||
showCookies(aCategory) {
|
||||
gSubDialog.open("chrome://browser/content/preferences/cookies.xul");
|
||||
},
|
||||
|
||||
// CLEAR PRIVATE DATA
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* privacy.sanitize.sanitizeOnShutdown
|
||||
* - true if the user's private data is cleared on startup according to the
|
||||
* Clear Private Data settings, false otherwise
|
||||
*/
|
||||
|
||||
/**
|
||||
* Displays the Clear Private Data settings dialog.
|
||||
*/
|
||||
showClearPrivateDataSettings() {
|
||||
gSubDialog.open("chrome://browser/content/preferences/sanitize.xul", "resizable=no");
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Displays a dialog from which individual parts of private data may be
|
||||
* cleared.
|
||||
*/
|
||||
clearPrivateDataNow(aClearEverything) {
|
||||
var ts = document.getElementById("privacy.sanitize.timeSpan");
|
||||
var timeSpanOrig = ts.value;
|
||||
|
||||
if (aClearEverything) {
|
||||
ts.value = 0;
|
||||
}
|
||||
|
||||
gSubDialog.open("chrome://browser/content/sanitize.xul", "resizable=no", null, () => {
|
||||
// reset the timeSpan pref
|
||||
if (aClearEverything) {
|
||||
ts.value = timeSpanOrig;
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(null, "clear-private-data", null);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables or disables the "Settings..." button depending
|
||||
* on the privacy.sanitize.sanitizeOnShutdown preference value
|
||||
*/
|
||||
_updateSanitizeSettingsButton() {
|
||||
var settingsButton = document.getElementById("clearDataSettings");
|
||||
var sanitizeOnShutdownPref = document.getElementById("privacy.sanitize.sanitizeOnShutdown");
|
||||
|
||||
settingsButton.disabled = !sanitizeOnShutdownPref.value;
|
||||
},
|
||||
|
||||
// CONTAINERS
|
||||
|
||||
/*
|
||||
* preferences:
|
||||
*
|
||||
* privacy.userContext.enabled
|
||||
* - true if containers is enabled
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enables/disables the Settings button used to configure containers
|
||||
*/
|
||||
readBrowserContainersCheckbox() {
|
||||
var pref = document.getElementById("privacy.userContext.enabled");
|
||||
var settings = document.getElementById("browserContainersSettings");
|
||||
|
||||
settings.disabled = !pref.value;
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,311 @@
|
|||
# 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/.
|
||||
|
||||
<!-- Privacy panel -->
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/privacy.js"/>
|
||||
|
||||
<preferences id="privacyPreferences" hidden="true" data-category="panePrivacy">
|
||||
|
||||
<!-- Tracking -->
|
||||
<preference id="privacy.trackingprotection.enabled"
|
||||
name="privacy.trackingprotection.enabled"
|
||||
type="bool"/>
|
||||
<preference id="privacy.trackingprotection.pbmode.enabled"
|
||||
name="privacy.trackingprotection.pbmode.enabled"
|
||||
type="bool"/>
|
||||
|
||||
<!-- XXX button prefs -->
|
||||
<preference id="pref.privacy.disable_button.cookie_exceptions"
|
||||
name="pref.privacy.disable_button.cookie_exceptions"
|
||||
type="bool"/>
|
||||
<preference id="pref.privacy.disable_button.view_cookies"
|
||||
name="pref.privacy.disable_button.view_cookies"
|
||||
type="bool"/>
|
||||
<preference id="pref.privacy.disable_button.change_blocklist"
|
||||
name="pref.privacy.disable_button.change_blocklist"
|
||||
type="bool"/>
|
||||
<preference id="pref.privacy.disable_button.tracking_protection_exceptions"
|
||||
name="pref.privacy.disable_button.tracking_protection_exceptions"
|
||||
type="bool"/>
|
||||
|
||||
<!-- Location Bar -->
|
||||
<preference id="browser.urlbar.autocomplete.enabled"
|
||||
name="browser.urlbar.autocomplete.enabled"
|
||||
type="bool"/>
|
||||
<preference id="browser.urlbar.suggest.bookmark"
|
||||
name="browser.urlbar.suggest.bookmark"
|
||||
type="bool"/>
|
||||
<preference id="browser.urlbar.suggest.history"
|
||||
name="browser.urlbar.suggest.history"
|
||||
type="bool"/>
|
||||
<preference id="browser.urlbar.suggest.openpage"
|
||||
name="browser.urlbar.suggest.openpage"
|
||||
type="bool"/>
|
||||
|
||||
<!-- History -->
|
||||
<preference id="places.history.enabled"
|
||||
name="places.history.enabled"
|
||||
type="bool"/>
|
||||
<preference id="browser.formfill.enable"
|
||||
name="browser.formfill.enable"
|
||||
type="bool"/>
|
||||
<preference id="privacy.history.custom"
|
||||
name="privacy.history.custom"
|
||||
type="bool"/>
|
||||
<!-- Cookies -->
|
||||
<preference id="network.cookie.cookieBehavior"
|
||||
name="network.cookie.cookieBehavior"
|
||||
type="int"/>
|
||||
<preference id="network.cookie.lifetimePolicy"
|
||||
name="network.cookie.lifetimePolicy"
|
||||
type="int"/>
|
||||
<preference id="network.cookie.blockFutureCookies"
|
||||
name="network.cookie.blockFutureCookies"
|
||||
type="bool"/>
|
||||
<!-- Clear Private Data -->
|
||||
<preference id="privacy.sanitize.sanitizeOnShutdown"
|
||||
name="privacy.sanitize.sanitizeOnShutdown"
|
||||
type="bool"/>
|
||||
<preference id="privacy.sanitize.timeSpan"
|
||||
name="privacy.sanitize.timeSpan"
|
||||
type="int"/>
|
||||
<!-- Private Browsing -->
|
||||
<preference id="browser.privatebrowsing.autostart"
|
||||
name="browser.privatebrowsing.autostart"
|
||||
type="bool"/>
|
||||
</preferences>
|
||||
|
||||
<hbox id="header-privacy"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="panePrivacy">
|
||||
<label class="header-name" flex="1">&panePrivacy.title;</label>
|
||||
<html:a class="help-button" target="_blank" aria-label="&helpButton.label;"></html:a>
|
||||
</hbox>
|
||||
|
||||
<!-- Tracking -->
|
||||
<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true">
|
||||
<vbox id="trackingprotectionbox" hidden="true">
|
||||
<hbox align="start">
|
||||
<vbox>
|
||||
<caption><label>&trackingProtectionHeader.label;
|
||||
<label id="trackingProtectionLearnMore" class="learnMore text-link"
|
||||
value="&trackingProtectionLearnMore.label;"/>
|
||||
</label></caption>
|
||||
<radiogroup id="trackingProtectionRadioGroup">
|
||||
<radio value="always"
|
||||
label="&trackingProtectionAlways.label;"
|
||||
accesskey="&trackingProtectionAlways.accesskey;"/>
|
||||
<radio value="private"
|
||||
label="&trackingProtectionPrivate.label;"
|
||||
accesskey="&trackingProtectionPrivate.accesskey;"/>
|
||||
<radio value="never"
|
||||
label="&trackingProtectionNever.label;"
|
||||
accesskey="&trackingProtectionNever.accesskey;"/>
|
||||
</radiogroup>
|
||||
</vbox>
|
||||
<spacer flex="1" />
|
||||
<vbox>
|
||||
<button id="trackingProtectionExceptions"
|
||||
label="&trackingProtectionExceptions.label;"
|
||||
accesskey="&trackingProtectionExceptions.accesskey;"
|
||||
preference="pref.privacy.disable_button.tracking_protection_exceptions"/>
|
||||
<button id="changeBlockList"
|
||||
label="&changeBlockList.label;"
|
||||
accesskey="&changeBlockList.accesskey;"
|
||||
preference="pref.privacy.disable_button.change_blocklist"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox id="trackingprotectionpbmbox">
|
||||
<caption><label>&tracking.label;</label></caption>
|
||||
<hbox align="center">
|
||||
<checkbox id="trackingProtectionPBM"
|
||||
preference="privacy.trackingprotection.pbmode.enabled"
|
||||
accesskey="&trackingProtectionPBM5.accesskey;"
|
||||
label="&trackingProtectionPBM5.label;" />
|
||||
<label id="trackingProtectionPBMLearnMore"
|
||||
class="learnMore text-link"
|
||||
value="&trackingProtectionPBMLearnMore.label;"/>
|
||||
<spacer flex="1" />
|
||||
<button id="changeBlockListPBM"
|
||||
label="&changeBlockList.label;" accesskey="&changeBlockList.accesskey;"
|
||||
preference="pref.privacy.disable_button.change_blocklist"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox>
|
||||
<description>&doNotTrack.pre.label;<label
|
||||
class="text-link" id="doNotTrackSettings"
|
||||
>&doNotTrack.settings.label;</label>&doNotTrack.post.label;</description>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
|
||||
<!-- History -->
|
||||
<groupbox id="historyGroup" data-category="panePrivacy" hidden="true">
|
||||
<caption><label>&history.label;</label></caption>
|
||||
<hbox align="center">
|
||||
<label id="historyModeLabel"
|
||||
control="historyMode"
|
||||
accesskey="&historyHeader.pre.accesskey;">&historyHeader.pre.label;
|
||||
</label>
|
||||
<menulist id="historyMode">
|
||||
<menupopup>
|
||||
<menuitem label="&historyHeader.remember.label;" value="remember"/>
|
||||
<menuitem label="&historyHeader.dontremember.label;" value="dontremember"/>
|
||||
<menuitem label="&historyHeader.custom.label;" value="custom"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<label>&historyHeader.post.label;</label>
|
||||
</hbox>
|
||||
<deck id="historyPane">
|
||||
<vbox id="historyRememberPane">
|
||||
<hbox align="center" flex="1">
|
||||
<vbox flex="1">
|
||||
<description>&rememberDescription.label;</description>
|
||||
<separator class="thin"/>
|
||||
<description>&rememberActions.pre.label;<label
|
||||
class="text-link" id="historyRememberClear"
|
||||
>&rememberActions.clearHistory.label;</label>&rememberActions.middle.label;<label
|
||||
class="text-link" id="historyRememberCookies"
|
||||
>&rememberActions.removeCookies.label;</label>&rememberActions.post.label;</description>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox id="historyDontRememberPane">
|
||||
<hbox align="center" flex="1">
|
||||
<vbox flex="1">
|
||||
<description>&dontrememberDescription.label;</description>
|
||||
<separator class="thin"/>
|
||||
<description>&dontrememberActions.pre.label;<label
|
||||
class="text-link" id="historyDontRememberClear"
|
||||
>&dontrememberActions.clearHistory.label;</label>&dontrememberActions.post.label;</description>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox id="historyCustomPane">
|
||||
<separator class="thin"/>
|
||||
<vbox>
|
||||
<vbox align="start">
|
||||
<checkbox id="privateBrowsingAutoStart"
|
||||
label="&privateBrowsingPermanent2.label;"
|
||||
accesskey="&privateBrowsingPermanent2.accesskey;"
|
||||
preference="browser.privatebrowsing.autostart"/>
|
||||
</vbox>
|
||||
<vbox class="indent">
|
||||
<vbox align="start">
|
||||
<checkbox id="rememberHistory"
|
||||
label="&rememberHistory2.label;"
|
||||
accesskey="&rememberHistory2.accesskey;"
|
||||
preference="places.history.enabled"/>
|
||||
<checkbox id="rememberForms"
|
||||
label="&rememberSearchForm.label;"
|
||||
accesskey="&rememberSearchForm.accesskey;"
|
||||
preference="browser.formfill.enable"/>
|
||||
</vbox>
|
||||
<hbox id="cookiesBox">
|
||||
<checkbox id="acceptCookies" label="&acceptCookies.label;"
|
||||
preference="network.cookie.cookieBehavior"
|
||||
accesskey="&acceptCookies.accesskey;"
|
||||
onsyncfrompreference="return gPrivacyPane.readAcceptCookies();"
|
||||
onsynctopreference="return gPrivacyPane.writeAcceptCookies();"/>
|
||||
<spacer flex="1" />
|
||||
<button id="cookieExceptions"
|
||||
label="&cookieExceptions.label;" accesskey="&cookieExceptions.accesskey;"
|
||||
preference="pref.privacy.disable_button.cookie_exceptions"/>
|
||||
</hbox>
|
||||
<hbox id="acceptThirdPartyRow"
|
||||
class="indent"
|
||||
align="center">
|
||||
<label id="acceptThirdPartyLabel" control="acceptThirdPartyMenu"
|
||||
accesskey="&acceptThirdParty.pre.accesskey;">&acceptThirdParty.pre.label;</label>
|
||||
<menulist id="acceptThirdPartyMenu" preference="network.cookie.cookieBehavior"
|
||||
onsyncfrompreference="return gPrivacyPane.readAcceptThirdPartyCookies();"
|
||||
onsynctopreference="return gPrivacyPane.writeAcceptThirdPartyCookies();">
|
||||
<menupopup>
|
||||
<menuitem label="&acceptThirdParty.always.label;" value="always"/>
|
||||
<menuitem label="&acceptThirdParty.visited.label;" value="visited"/>
|
||||
<menuitem label="&acceptThirdParty.never.label;" value="never"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
<hbox id="keepRow"
|
||||
class="indent"
|
||||
align="center">
|
||||
<label id="keepUntil"
|
||||
control="keepCookiesUntil"
|
||||
accesskey="&keepUntil.accesskey;">&keepUntil.label;</label>
|
||||
<menulist id="keepCookiesUntil"
|
||||
preference="network.cookie.lifetimePolicy">
|
||||
<menupopup>
|
||||
<menuitem label="&expire.label;" value="0"/>
|
||||
<menuitem label="&close.label;" value="2"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<spacer flex="1"/>
|
||||
<button id="showCookiesButton"
|
||||
label="&showCookies.label;" accesskey="&showCookies.accesskey;"
|
||||
preference="pref.privacy.disable_button.view_cookies"/>
|
||||
</hbox>
|
||||
<hbox id="clearDataBox"
|
||||
align="center">
|
||||
<checkbox id="alwaysClear"
|
||||
preference="privacy.sanitize.sanitizeOnShutdown"
|
||||
label="&clearOnClose.label;"
|
||||
accesskey="&clearOnClose.accesskey;"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="clearDataSettings" label="&clearOnCloseSettings.label;"
|
||||
accesskey="&clearOnCloseSettings.accesskey;"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</deck>
|
||||
</groupbox>
|
||||
|
||||
<!-- Location Bar -->
|
||||
<groupbox id="locationBarGroup"
|
||||
data-category="panePrivacy"
|
||||
hidden="true">
|
||||
<caption><label>&locationBar.label;</label></caption>
|
||||
<label id="locationBarSuggestionLabel">&locbar.suggest.label;</label>
|
||||
<checkbox id="historySuggestion" label="&locbar.history.label;"
|
||||
accesskey="&locbar.history.accesskey;"
|
||||
preference="browser.urlbar.suggest.history"/>
|
||||
<checkbox id="bookmarkSuggestion" label="&locbar.bookmarks.label;"
|
||||
accesskey="&locbar.bookmarks.accesskey;"
|
||||
preference="browser.urlbar.suggest.bookmark"/>
|
||||
<checkbox id="openpageSuggestion" label="&locbar.openpage.label;"
|
||||
accesskey="&locbar.openpage.accesskey;"
|
||||
preference="browser.urlbar.suggest.openpage"/>
|
||||
<label class="text-link" onclick="gotoPref('search')">
|
||||
&suggestionSettings.label;
|
||||
</label>
|
||||
</groupbox>
|
||||
|
||||
<!-- Containers -->
|
||||
<groupbox id="browserContainersGroup" data-category="panePrivacy" hidden="true">
|
||||
<vbox id="browserContainersbox" hidden="true">
|
||||
<caption><label>&browserContainersHeader.label;
|
||||
<label id="browserContainersLearnMore" class="learnMore text-link"
|
||||
value="&browserContainersLearnMore.label;"/>
|
||||
</label></caption>
|
||||
<hbox align="start">
|
||||
<vbox>
|
||||
<checkbox id="browserContainersCheckbox"
|
||||
label="&browserContainersEnabled.label;"
|
||||
accesskey="&browserContainersEnabled.accesskey;"
|
||||
preference="privacy.userContext.enabled"
|
||||
onsyncfrompreference="return gPrivacyPane.readBrowserContainersCheckbox();"/>
|
||||
</vbox>
|
||||
<spacer flex="1"/>
|
||||
<vbox>
|
||||
<button id="browserContainersSettings"
|
||||
label="&browserContainersSettings.label;"
|
||||
accesskey="&browserContainersSettings.accesskey;"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</groupbox>
|
|
@ -0,0 +1,604 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from preferences.js */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
const ENGINE_FLAVOR = "text/x-moz-search-engine";
|
||||
|
||||
var gEngineView = null;
|
||||
|
||||
var gSearchPane = {
|
||||
|
||||
/**
|
||||
* Initialize autocomplete to ensure prefs are in sync.
|
||||
*/
|
||||
_initAutocomplete() {
|
||||
Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
|
||||
.getService(Components.interfaces.mozIPlacesAutoComplete);
|
||||
},
|
||||
|
||||
init() {
|
||||
gEngineView = new EngineView(new EngineStore());
|
||||
document.getElementById("engineList").view = gEngineView;
|
||||
this.buildDefaultEngineDropDown();
|
||||
|
||||
let addEnginesLink = document.getElementById("addEngines");
|
||||
let searchEnginesURL = Services.wm.getMostRecentWindow("navigator:browser")
|
||||
.BrowserSearch.searchEnginesURL;
|
||||
addEnginesLink.setAttribute("href", searchEnginesURL);
|
||||
|
||||
window.addEventListener("click", this);
|
||||
window.addEventListener("command", this);
|
||||
window.addEventListener("dragstart", this);
|
||||
window.addEventListener("keypress", this);
|
||||
window.addEventListener("select", this);
|
||||
window.addEventListener("blur", this, true);
|
||||
|
||||
Services.obs.addObserver(this, "browser-search-engine-modified", false);
|
||||
window.addEventListener("unload", () => {
|
||||
Services.obs.removeObserver(this, "browser-search-engine-modified");
|
||||
});
|
||||
|
||||
this._initAutocomplete();
|
||||
|
||||
let suggestsPref =
|
||||
document.getElementById("browser.search.suggest.enabled");
|
||||
suggestsPref.addEventListener("change", () => {
|
||||
this.updateSuggestsCheckbox();
|
||||
});
|
||||
this.updateSuggestsCheckbox();
|
||||
},
|
||||
|
||||
updateSuggestsCheckbox() {
|
||||
let suggestsPref =
|
||||
document.getElementById("browser.search.suggest.enabled");
|
||||
let permanentPB =
|
||||
Services.prefs.getBoolPref("browser.privatebrowsing.autostart");
|
||||
let urlbarSuggests = document.getElementById("urlBarSuggestion");
|
||||
urlbarSuggests.disabled = !suggestsPref.value || permanentPB;
|
||||
|
||||
let urlbarSuggestsPref =
|
||||
document.getElementById("browser.urlbar.suggest.searches");
|
||||
urlbarSuggests.checked = urlbarSuggestsPref.value;
|
||||
if (urlbarSuggests.disabled) {
|
||||
urlbarSuggests.checked = false;
|
||||
}
|
||||
|
||||
let permanentPBLabel =
|
||||
document.getElementById("urlBarSuggestionPermanentPBLabel");
|
||||
permanentPBLabel.hidden = urlbarSuggests.hidden || !permanentPB;
|
||||
},
|
||||
|
||||
buildDefaultEngineDropDown() {
|
||||
// This is called each time something affects the list of engines.
|
||||
let list = document.getElementById("defaultEngine");
|
||||
// Set selection to the current default engine.
|
||||
let currentEngine = Services.search.currentEngine.name;
|
||||
|
||||
// If the current engine isn't in the list any more, select the first item.
|
||||
let engines = gEngineView._engineStore._engines;
|
||||
if (!engines.some(e => e.name == currentEngine))
|
||||
currentEngine = engines[0].name;
|
||||
|
||||
// Now clean-up and rebuild the list.
|
||||
list.removeAllItems();
|
||||
gEngineView._engineStore._engines.forEach(e => {
|
||||
let item = list.appendItem(e.name);
|
||||
item.setAttribute("class", "menuitem-iconic searchengine-menuitem menuitem-with-favicon");
|
||||
if (e.iconURI) {
|
||||
item.setAttribute("image", e.iconURI.spec);
|
||||
}
|
||||
item.engine = e;
|
||||
if (e.name == currentEngine)
|
||||
list.selectedItem = item;
|
||||
});
|
||||
},
|
||||
|
||||
handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "click":
|
||||
if (aEvent.target.id != "engineChildren" &&
|
||||
!aEvent.target.classList.contains("searchEngineAction")) {
|
||||
let engineList = document.getElementById("engineList");
|
||||
// We don't want to toggle off selection while editing keyword
|
||||
// so proceed only when the input field is hidden.
|
||||
// We need to check that engineList.view is defined here
|
||||
// because the "click" event listener is on <window> and the
|
||||
// view might have been destroyed if the pane has been navigated
|
||||
// away from.
|
||||
if (engineList.inputField.hidden && engineList.view) {
|
||||
let selection = engineList.view.selection;
|
||||
if (selection.count > 0) {
|
||||
selection.toggleSelect(selection.currentIndex);
|
||||
}
|
||||
engineList.blur();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "command":
|
||||
switch (aEvent.target.id) {
|
||||
case "":
|
||||
if (aEvent.target.parentNode &&
|
||||
aEvent.target.parentNode.parentNode &&
|
||||
aEvent.target.parentNode.parentNode.id == "defaultEngine") {
|
||||
gSearchPane.setDefaultEngine();
|
||||
}
|
||||
break;
|
||||
case "restoreDefaultSearchEngines":
|
||||
gSearchPane.onRestoreDefaults();
|
||||
break;
|
||||
case "removeEngineButton":
|
||||
Services.search.removeEngine(gEngineView.selectedEngine.originalEngine);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "dragstart":
|
||||
if (aEvent.target.id == "engineChildren") {
|
||||
onDragEngineStart(aEvent);
|
||||
}
|
||||
break;
|
||||
case "keypress":
|
||||
if (aEvent.target.id == "engineList") {
|
||||
gSearchPane.onTreeKeyPress(aEvent);
|
||||
}
|
||||
break;
|
||||
case "select":
|
||||
if (aEvent.target.id == "engineList") {
|
||||
gSearchPane.onTreeSelect();
|
||||
}
|
||||
break;
|
||||
case "blur":
|
||||
if (aEvent.target.id == "engineList" &&
|
||||
aEvent.target.inputField == document.getBindingParent(aEvent.originalTarget)) {
|
||||
gSearchPane.onInputBlur();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
observe(aEngine, aTopic, aVerb) {
|
||||
if (aTopic == "browser-search-engine-modified") {
|
||||
aEngine.QueryInterface(Components.interfaces.nsISearchEngine);
|
||||
switch (aVerb) {
|
||||
case "engine-added":
|
||||
gEngineView._engineStore.addEngine(aEngine);
|
||||
gEngineView.rowCountChanged(gEngineView.lastIndex, 1);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
break;
|
||||
case "engine-changed":
|
||||
gEngineView._engineStore.reloadIcons();
|
||||
gEngineView.invalidate();
|
||||
break;
|
||||
case "engine-removed":
|
||||
gSearchPane.remove(aEngine);
|
||||
break;
|
||||
case "engine-current":
|
||||
// If the user is going through the drop down using up/down keys, the
|
||||
// dropdown may still be open (eg. on Windows) when engine-current is
|
||||
// fired, so rebuilding the list unconditionally would get in the way.
|
||||
let selectedEngine =
|
||||
document.getElementById("defaultEngine").selectedItem.engine;
|
||||
if (selectedEngine.name != aEngine.name)
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
break;
|
||||
case "engine-default":
|
||||
// Not relevant
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onInputBlur(aEvent) {
|
||||
let tree = document.getElementById("engineList");
|
||||
if (!tree.hasAttribute("editing"))
|
||||
return;
|
||||
|
||||
// Accept input unless discarded.
|
||||
let accept = aEvent.charCode != KeyEvent.DOM_VK_ESCAPE;
|
||||
tree.stopEditing(accept);
|
||||
},
|
||||
|
||||
onTreeSelect() {
|
||||
document.getElementById("removeEngineButton").disabled =
|
||||
!gEngineView.isEngineSelectedAndRemovable();
|
||||
},
|
||||
|
||||
onTreeKeyPress(aEvent) {
|
||||
let index = gEngineView.selectedIndex;
|
||||
let tree = document.getElementById("engineList");
|
||||
if (tree.hasAttribute("editing"))
|
||||
return;
|
||||
|
||||
if (aEvent.charCode == KeyEvent.DOM_VK_SPACE) {
|
||||
// Space toggles the checkbox.
|
||||
let newValue = !gEngineView._engineStore.engines[index].shown;
|
||||
gEngineView.setCellValue(index, tree.columns.getFirstColumn(),
|
||||
newValue.toString());
|
||||
// Prevent page from scrolling on the space key.
|
||||
aEvent.preventDefault();
|
||||
} else {
|
||||
let isMac = Services.appinfo.OS == "Darwin";
|
||||
if ((isMac && aEvent.keyCode == KeyEvent.DOM_VK_RETURN) ||
|
||||
(!isMac && aEvent.keyCode == KeyEvent.DOM_VK_F2)) {
|
||||
tree.startEditing(index, tree.columns.getLastColumn());
|
||||
} else if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE ||
|
||||
(isMac && aEvent.shiftKey &&
|
||||
aEvent.keyCode == KeyEvent.DOM_VK_BACK_SPACE &&
|
||||
gEngineView.isEngineSelectedAndRemovable())) {
|
||||
// Delete and Shift+Backspace (Mac) removes selected engine.
|
||||
Services.search.removeEngine(gEngineView.selectedEngine.originalEngine);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onRestoreDefaults() {
|
||||
let num = gEngineView._engineStore.restoreDefaultEngines();
|
||||
gEngineView.rowCountChanged(0, num);
|
||||
gEngineView.invalidate();
|
||||
},
|
||||
|
||||
showRestoreDefaults(aEnable) {
|
||||
document.getElementById("restoreDefaultSearchEngines").disabled = !aEnable;
|
||||
},
|
||||
|
||||
remove(aEngine) {
|
||||
let index = gEngineView._engineStore.removeEngine(aEngine);
|
||||
gEngineView.rowCountChanged(index, -1);
|
||||
gEngineView.invalidate();
|
||||
gEngineView.selection.select(Math.min(index, gEngineView.lastIndex));
|
||||
gEngineView.ensureRowIsVisible(gEngineView.currentIndex);
|
||||
document.getElementById("engineList").focus();
|
||||
},
|
||||
|
||||
editKeyword: Task.async(function* (aEngine, aNewKeyword) {
|
||||
let keyword = aNewKeyword.trim();
|
||||
if (keyword) {
|
||||
let eduplicate = false;
|
||||
let dupName = "";
|
||||
|
||||
// Check for duplicates in Places keywords.
|
||||
let bduplicate = !!(yield PlacesUtils.keywords.fetch(keyword));
|
||||
|
||||
// Check for duplicates in changes we haven't committed yet
|
||||
let engines = gEngineView._engineStore.engines;
|
||||
for (let engine of engines) {
|
||||
if (engine.alias == keyword &&
|
||||
engine.name != aEngine.name) {
|
||||
eduplicate = true;
|
||||
dupName = engine.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the user if they have chosen an existing engine/bookmark keyword
|
||||
if (eduplicate || bduplicate) {
|
||||
let strings = document.getElementById("engineManagerBundle");
|
||||
let dtitle = strings.getString("duplicateTitle");
|
||||
let bmsg = strings.getString("duplicateBookmarkMsg");
|
||||
let emsg = strings.getFormattedString("duplicateEngineMsg", [dupName]);
|
||||
|
||||
Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gEngineView._engineStore.changeEngine(aEngine, "alias", keyword);
|
||||
gEngineView.invalidate();
|
||||
return true;
|
||||
}),
|
||||
|
||||
saveOneClickEnginesList() {
|
||||
let hiddenList = [];
|
||||
for (let engine of gEngineView._engineStore.engines) {
|
||||
if (!engine.shown)
|
||||
hiddenList.push(engine.name);
|
||||
}
|
||||
document.getElementById("browser.search.hiddenOneOffs").value =
|
||||
hiddenList.join(",");
|
||||
},
|
||||
|
||||
setDefaultEngine() {
|
||||
Services.search.currentEngine =
|
||||
document.getElementById("defaultEngine").selectedItem.engine;
|
||||
}
|
||||
};
|
||||
|
||||
function onDragEngineStart(event) {
|
||||
var selectedIndex = gEngineView.selectedIndex;
|
||||
var tree = document.getElementById("engineList");
|
||||
var row = { }, col = { }, child = { };
|
||||
tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, child);
|
||||
if (selectedIndex >= 0 && !gEngineView.isCheckBox(row.value, col.value)) {
|
||||
event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
|
||||
event.dataTransfer.effectAllowed = "move";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function EngineStore() {
|
||||
let pref = document.getElementById("browser.search.hiddenOneOffs").value;
|
||||
this.hiddenList = pref ? pref.split(",") : [];
|
||||
|
||||
this._engines = Services.search.getVisibleEngines().map(this._cloneEngine, this);
|
||||
this._defaultEngines = Services.search.getDefaultEngines().map(this._cloneEngine, this);
|
||||
|
||||
// check if we need to disable the restore defaults button
|
||||
var someHidden = this._defaultEngines.some(e => e.hidden);
|
||||
gSearchPane.showRestoreDefaults(someHidden);
|
||||
}
|
||||
EngineStore.prototype = {
|
||||
_engines: null,
|
||||
_defaultEngines: null,
|
||||
|
||||
get engines() {
|
||||
return this._engines;
|
||||
},
|
||||
set engines(val) {
|
||||
this._engines = val;
|
||||
return val;
|
||||
},
|
||||
|
||||
_getIndexForEngine(aEngine) {
|
||||
return this._engines.indexOf(aEngine);
|
||||
},
|
||||
|
||||
_getEngineByName(aName) {
|
||||
return this._engines.find(engine => engine.name == aName);
|
||||
},
|
||||
|
||||
_cloneEngine(aEngine) {
|
||||
var clonedObj = {};
|
||||
for (var i in aEngine)
|
||||
clonedObj[i] = aEngine[i];
|
||||
clonedObj.originalEngine = aEngine;
|
||||
clonedObj.shown = this.hiddenList.indexOf(clonedObj.name) == -1;
|
||||
return clonedObj;
|
||||
},
|
||||
|
||||
// Callback for Array's some(). A thisObj must be passed to some()
|
||||
_isSameEngine(aEngineClone) {
|
||||
return aEngineClone.originalEngine == this.originalEngine;
|
||||
},
|
||||
|
||||
addEngine(aEngine) {
|
||||
this._engines.push(this._cloneEngine(aEngine));
|
||||
},
|
||||
|
||||
moveEngine(aEngine, aNewIndex) {
|
||||
if (aNewIndex < 0 || aNewIndex > this._engines.length - 1)
|
||||
throw new Error("ES_moveEngine: invalid aNewIndex!");
|
||||
var index = this._getIndexForEngine(aEngine);
|
||||
if (index == -1)
|
||||
throw new Error("ES_moveEngine: invalid engine?");
|
||||
|
||||
if (index == aNewIndex)
|
||||
return; // nothing to do
|
||||
|
||||
// Move the engine in our internal store
|
||||
var removedEngine = this._engines.splice(index, 1)[0];
|
||||
this._engines.splice(aNewIndex, 0, removedEngine);
|
||||
|
||||
Services.search.moveEngine(aEngine.originalEngine, aNewIndex);
|
||||
},
|
||||
|
||||
removeEngine(aEngine) {
|
||||
if (this._engines.length == 1) {
|
||||
throw new Error("Cannot remove last engine!");
|
||||
}
|
||||
|
||||
let engineName = aEngine.name;
|
||||
let index = this._engines.findIndex(element => element.name == engineName);
|
||||
|
||||
if (index == -1)
|
||||
throw new Error("invalid engine?");
|
||||
|
||||
let removedEngine = this._engines.splice(index, 1)[0];
|
||||
|
||||
if (this._defaultEngines.some(this._isSameEngine, removedEngine))
|
||||
gSearchPane.showRestoreDefaults(true);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
return index;
|
||||
},
|
||||
|
||||
restoreDefaultEngines() {
|
||||
var added = 0;
|
||||
|
||||
for (var i = 0; i < this._defaultEngines.length; ++i) {
|
||||
var e = this._defaultEngines[i];
|
||||
|
||||
// If the engine is already in the list, just move it.
|
||||
if (this._engines.some(this._isSameEngine, e)) {
|
||||
this.moveEngine(this._getEngineByName(e.name), i);
|
||||
} else {
|
||||
// Otherwise, add it back to our internal store
|
||||
|
||||
// The search service removes the alias when an engine is hidden,
|
||||
// so clear any alias we may have cached before unhiding the engine.
|
||||
e.alias = "";
|
||||
|
||||
this._engines.splice(i, 0, e);
|
||||
let engine = e.originalEngine;
|
||||
engine.hidden = false;
|
||||
Services.search.moveEngine(engine, i);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
Services.search.resetToOriginalDefaultEngine();
|
||||
gSearchPane.showRestoreDefaults(false);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
return added;
|
||||
},
|
||||
|
||||
changeEngine(aEngine, aProp, aNewValue) {
|
||||
var index = this._getIndexForEngine(aEngine);
|
||||
if (index == -1)
|
||||
throw new Error("invalid engine?");
|
||||
|
||||
this._engines[index][aProp] = aNewValue;
|
||||
aEngine.originalEngine[aProp] = aNewValue;
|
||||
},
|
||||
|
||||
reloadIcons() {
|
||||
this._engines.forEach(function(e) {
|
||||
e.uri = e.originalEngine.uri;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function EngineView(aEngineStore) {
|
||||
this._engineStore = aEngineStore;
|
||||
}
|
||||
EngineView.prototype = {
|
||||
_engineStore: null,
|
||||
tree: null,
|
||||
|
||||
get lastIndex() {
|
||||
return this.rowCount - 1;
|
||||
},
|
||||
get selectedIndex() {
|
||||
var seln = this.selection;
|
||||
if (seln.getRangeCount() > 0) {
|
||||
var min = {};
|
||||
seln.getRangeAt(0, min, {});
|
||||
return min.value;
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
get selectedEngine() {
|
||||
return this._engineStore.engines[this.selectedIndex];
|
||||
},
|
||||
|
||||
// Helpers
|
||||
rowCountChanged(index, count) {
|
||||
this.tree.rowCountChanged(index, count);
|
||||
},
|
||||
|
||||
invalidate() {
|
||||
this.tree.invalidate();
|
||||
},
|
||||
|
||||
ensureRowIsVisible(index) {
|
||||
this.tree.ensureRowIsVisible(index);
|
||||
},
|
||||
|
||||
getSourceIndexFromDrag(dataTransfer) {
|
||||
return parseInt(dataTransfer.getData(ENGINE_FLAVOR));
|
||||
},
|
||||
|
||||
isCheckBox(index, column) {
|
||||
return column.id == "engineShown";
|
||||
},
|
||||
|
||||
isEngineSelectedAndRemovable() {
|
||||
return this.selectedIndex != -1 && this.lastIndex != 0;
|
||||
},
|
||||
|
||||
// nsITreeView
|
||||
get rowCount() {
|
||||
return this._engineStore.engines.length;
|
||||
},
|
||||
|
||||
getImageSrc(index, column) {
|
||||
if (column.id == "engineName") {
|
||||
if (this._engineStore.engines[index].iconURI)
|
||||
return this._engineStore.engines[index].iconURI.spec;
|
||||
|
||||
if (window.devicePixelRatio > 1)
|
||||
return "chrome://browser/skin/search-engine-placeholder@2x.png";
|
||||
return "chrome://browser/skin/search-engine-placeholder.png";
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
|
||||
getCellText(index, column) {
|
||||
if (column.id == "engineName")
|
||||
return this._engineStore.engines[index].name;
|
||||
else if (column.id == "engineKeyword")
|
||||
return this._engineStore.engines[index].alias;
|
||||
return "";
|
||||
},
|
||||
|
||||
setTree(tree) {
|
||||
this.tree = tree;
|
||||
},
|
||||
|
||||
canDrop(targetIndex, orientation, dataTransfer) {
|
||||
var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
|
||||
return (sourceIndex != -1 &&
|
||||
sourceIndex != targetIndex &&
|
||||
sourceIndex != targetIndex + orientation);
|
||||
},
|
||||
|
||||
drop(dropIndex, orientation, dataTransfer) {
|
||||
var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
|
||||
var sourceEngine = this._engineStore.engines[sourceIndex];
|
||||
|
||||
const nsITreeView = Components.interfaces.nsITreeView;
|
||||
if (dropIndex > sourceIndex) {
|
||||
if (orientation == nsITreeView.DROP_BEFORE)
|
||||
dropIndex--;
|
||||
} else if (orientation == nsITreeView.DROP_AFTER) {
|
||||
dropIndex++;
|
||||
}
|
||||
|
||||
this._engineStore.moveEngine(sourceEngine, dropIndex);
|
||||
gSearchPane.showRestoreDefaults(true);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
|
||||
// Redraw, and adjust selection
|
||||
this.invalidate();
|
||||
this.selection.select(dropIndex);
|
||||
},
|
||||
|
||||
selection: null,
|
||||
getRowProperties(index) { return ""; },
|
||||
getCellProperties(index, column) { return ""; },
|
||||
getColumnProperties(column) { return ""; },
|
||||
isContainer(index) { return false; },
|
||||
isContainerOpen(index) { return false; },
|
||||
isContainerEmpty(index) { return false; },
|
||||
isSeparator(index) { return false; },
|
||||
isSorted(index) { return false; },
|
||||
getParentIndex(index) { return -1; },
|
||||
hasNextSibling(parentIndex, index) { return false; },
|
||||
getLevel(index) { return 0; },
|
||||
getProgressMode(index, column) { },
|
||||
getCellValue(index, column) {
|
||||
if (column.id == "engineShown")
|
||||
return this._engineStore.engines[index].shown;
|
||||
return undefined;
|
||||
},
|
||||
toggleOpenState(index) { },
|
||||
cycleHeader(column) { },
|
||||
selectionChanged() { },
|
||||
cycleCell(row, column) { },
|
||||
isEditable(index, column) { return column.id != "engineName"; },
|
||||
isSelectable(index, column) { return false; },
|
||||
setCellValue(index, column, value) {
|
||||
if (column.id == "engineShown") {
|
||||
this._engineStore.engines[index].shown = value == "true";
|
||||
gEngineView.invalidate();
|
||||
gSearchPane.saveOneClickEnginesList();
|
||||
}
|
||||
},
|
||||
setCellText(index, column, value) {
|
||||
if (column.id == "engineKeyword") {
|
||||
gSearchPane.editKeyword(this._engineStore.engines[index], value)
|
||||
.then(valid => {
|
||||
if (!valid)
|
||||
document.getElementById("engineList").startEditing(index, column);
|
||||
});
|
||||
}
|
||||
},
|
||||
performAction(action) { },
|
||||
performActionOnRow(action, index) { },
|
||||
performActionOnCell(action, index, column) { }
|
||||
};
|
|
@ -0,0 +1,86 @@
|
|||
<preferences id="searchPreferences" hidden="true" data-category="paneSearch">
|
||||
|
||||
<preference id="browser.search.suggest.enabled"
|
||||
name="browser.search.suggest.enabled"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="browser.urlbar.suggest.searches"
|
||||
name="browser.urlbar.suggest.searches"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="browser.search.hiddenOneOffs"
|
||||
name="browser.search.hiddenOneOffs"
|
||||
type="unichar"/>
|
||||
|
||||
</preferences>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/search.js"/>
|
||||
|
||||
<stringbundle id="engineManagerBundle" src="chrome://browser/locale/engineManager.properties"/>
|
||||
|
||||
<hbox id="header-search"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneSearch">
|
||||
<label class="header-name" flex="1">&paneSearch.title;</label>
|
||||
<html:a class="help-button" target="_blank" aria-label="&helpButton.label;"></html:a>
|
||||
</hbox>
|
||||
|
||||
<!-- Default Search Engine -->
|
||||
<groupbox id="defaultEngineGroup" align="start" data-category="paneSearch">
|
||||
<caption label="&defaultSearchEngine.label;"/>
|
||||
<label>&chooseYourDefaultSearchEngine.label;</label>
|
||||
<menulist id="defaultEngine">
|
||||
<menupopup/>
|
||||
</menulist>
|
||||
<checkbox id="suggestionsInSearchFieldsCheckbox"
|
||||
label="&provideSearchSuggestions.label;"
|
||||
accesskey="&provideSearchSuggestions.accesskey;"
|
||||
preference="browser.search.suggest.enabled"/>
|
||||
<vbox class="indent">
|
||||
<checkbox id="urlBarSuggestion" label="&showURLBarSuggestions.label;"
|
||||
accesskey="&showURLBarSuggestions.accesskey;"
|
||||
preference="browser.urlbar.suggest.searches"/>
|
||||
<hbox id="urlBarSuggestionPermanentPBLabel"
|
||||
align="center" class="indent">
|
||||
<label flex="1">&urlBarSuggestionsPermanentPB.label;</label>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
|
||||
<groupbox id="oneClickSearchProvidersGroup" data-category="paneSearch">
|
||||
<caption label="&oneClickSearchEngines.label;"/>
|
||||
<label>&chooseWhichOneToDisplay.label;</label>
|
||||
|
||||
<tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
|
||||
seltype="single">
|
||||
<treechildren id="engineChildren" flex="1"/>
|
||||
<treecols>
|
||||
<treecol id="engineShown" type="checkbox" editable="true" sortable="false"/>
|
||||
<treecol id="engineName" flex="4" label="&engineNameColumn.label;" sortable="false"/>
|
||||
<treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"
|
||||
sortable="false"/>
|
||||
</treecols>
|
||||
</tree>
|
||||
|
||||
<hbox>
|
||||
<button id="restoreDefaultSearchEngines"
|
||||
label="&restoreDefaultSearchEngines.label;"
|
||||
accesskey="&restoreDefaultSearchEngines.accesskey;"
|
||||
/>
|
||||
<spacer flex="1"/>
|
||||
<button id="removeEngineButton"
|
||||
class="searchEngineAction"
|
||||
label="&removeEngine.label;"
|
||||
accesskey="&removeEngine.accesskey;"
|
||||
disabled="true"
|
||||
/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<hbox id="addEnginesBox" pack="start">
|
||||
<label id="addEngines" class="text-link" value="&addMoreSearchEngines.label;"/>
|
||||
</hbox>
|
||||
</groupbox>
|
|
@ -0,0 +1,292 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from preferences.js */
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
|
||||
"resource://gre/modules/LoginHelper.jsm");
|
||||
|
||||
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
var gSecurityPane = {
|
||||
_pane: null,
|
||||
|
||||
/**
|
||||
* Initializes master password UI.
|
||||
*/
|
||||
init() {
|
||||
function setEventListener(aId, aEventType, aCallback) {
|
||||
document.getElementById(aId)
|
||||
.addEventListener(aEventType, aCallback.bind(gSecurityPane));
|
||||
}
|
||||
|
||||
this._pane = document.getElementById("paneSecurity");
|
||||
this._initMasterPasswordUI();
|
||||
this._initSafeBrowsing();
|
||||
|
||||
setEventListener("addonExceptions", "command",
|
||||
gSecurityPane.showAddonExceptions);
|
||||
setEventListener("passwordExceptions", "command",
|
||||
gSecurityPane.showPasswordExceptions);
|
||||
setEventListener("useMasterPassword", "command",
|
||||
gSecurityPane.updateMasterPasswordButton);
|
||||
setEventListener("changeMasterPassword", "command",
|
||||
gSecurityPane.changeMasterPassword);
|
||||
setEventListener("showPasswords", "command",
|
||||
gSecurityPane.showPasswords);
|
||||
},
|
||||
|
||||
// ADD-ONS
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* xpinstall.whitelist.required
|
||||
* - true if a site must be added to a site whitelist before extensions
|
||||
* provided by the site may be installed from it, false if the extension
|
||||
* may be directly installed after a confirmation dialog
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enables/disables the add-ons Exceptions button depending on whether
|
||||
* or not add-on installation warnings are displayed.
|
||||
*/
|
||||
readWarnAddonInstall() {
|
||||
var warn = document.getElementById("xpinstall.whitelist.required");
|
||||
var exceptions = document.getElementById("addonExceptions");
|
||||
|
||||
exceptions.disabled = !warn.value;
|
||||
|
||||
// don't override the preference value
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the exceptions lists for add-on installation warnings.
|
||||
*/
|
||||
showAddonExceptions() {
|
||||
var bundlePrefs = document.getElementById("bundlePreferences");
|
||||
|
||||
var params = this._addonParams;
|
||||
if (!params.windowTitle || !params.introText) {
|
||||
params.windowTitle = bundlePrefs.getString("addons_permissions_title");
|
||||
params.introText = bundlePrefs.getString("addonspermissionstext");
|
||||
}
|
||||
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
null, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Parameters for the add-on install permissions dialog.
|
||||
*/
|
||||
_addonParams:
|
||||
{
|
||||
blockVisible: false,
|
||||
sessionVisible: false,
|
||||
allowVisible: true,
|
||||
prefilledHost: "",
|
||||
permissionType: "install"
|
||||
},
|
||||
|
||||
// PASSWORDS
|
||||
|
||||
/*
|
||||
* Preferences:
|
||||
*
|
||||
* signon.rememberSignons
|
||||
* - true if passwords are remembered, false otherwise
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enables/disables the Exceptions button used to configure sites where
|
||||
* passwords are never saved. When browser is set to start in Private
|
||||
* Browsing mode, the "Remember passwords" UI is useless, so we disable it.
|
||||
*/
|
||||
readSavePasswords() {
|
||||
var pref = document.getElementById("signon.rememberSignons");
|
||||
var excepts = document.getElementById("passwordExceptions");
|
||||
|
||||
if (PrivateBrowsingUtils.permanentPrivateBrowsing) {
|
||||
document.getElementById("savePasswords").disabled = true;
|
||||
excepts.disabled = true;
|
||||
return false;
|
||||
}
|
||||
excepts.disabled = !pref.value;
|
||||
// don't override pref value in UI
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a dialog in which the user can view and modify the list of sites
|
||||
* where passwords are never saved.
|
||||
*/
|
||||
showPasswordExceptions() {
|
||||
var bundlePrefs = document.getElementById("bundlePreferences");
|
||||
var params = {
|
||||
blockVisible: true,
|
||||
sessionVisible: false,
|
||||
allowVisible: false,
|
||||
hideStatusColumn: true,
|
||||
prefilledHost: "",
|
||||
permissionType: "login-saving",
|
||||
windowTitle: bundlePrefs.getString("savedLoginsExceptions_title"),
|
||||
introText: bundlePrefs.getString("savedLoginsExceptions_desc")
|
||||
};
|
||||
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
null, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes master password UI: the "use master password" checkbox, selects
|
||||
* the master password button to show, and enables/disables it as necessary.
|
||||
* The master password is controlled by various bits of NSS functionality, so
|
||||
* the UI for it can't be controlled by the normal preference bindings.
|
||||
*/
|
||||
_initMasterPasswordUI() {
|
||||
var noMP = !LoginHelper.isMasterPasswordSet();
|
||||
|
||||
var button = document.getElementById("changeMasterPassword");
|
||||
button.disabled = noMP;
|
||||
|
||||
var checkbox = document.getElementById("useMasterPassword");
|
||||
checkbox.checked = !noMP;
|
||||
},
|
||||
|
||||
_initSafeBrowsing() {
|
||||
let enableSafeBrowsing = document.getElementById("enableSafeBrowsing");
|
||||
let blockDownloads = document.getElementById("blockDownloads");
|
||||
let blockUncommonUnwanted = document.getElementById("blockUncommonUnwanted");
|
||||
|
||||
let safeBrowsingPhishingPref = document.getElementById("browser.safebrowsing.phishing.enabled");
|
||||
let safeBrowsingMalwarePref = document.getElementById("browser.safebrowsing.malware.enabled");
|
||||
|
||||
let blockDownloadsPref = document.getElementById("browser.safebrowsing.downloads.enabled");
|
||||
let malwareTable = document.getElementById("urlclassifier.malwareTable");
|
||||
|
||||
let blockUnwantedPref = document.getElementById("browser.safebrowsing.downloads.remote.block_potentially_unwanted");
|
||||
let blockUncommonPref = document.getElementById("browser.safebrowsing.downloads.remote.block_uncommon");
|
||||
|
||||
enableSafeBrowsing.addEventListener("command", function() {
|
||||
safeBrowsingPhishingPref.value = enableSafeBrowsing.checked;
|
||||
safeBrowsingMalwarePref.value = enableSafeBrowsing.checked;
|
||||
|
||||
if (enableSafeBrowsing.checked) {
|
||||
blockDownloads.removeAttribute("disabled");
|
||||
if (blockDownloads.checked) {
|
||||
blockUncommonUnwanted.removeAttribute("disabled");
|
||||
}
|
||||
} else {
|
||||
blockDownloads.setAttribute("disabled", "true");
|
||||
blockUncommonUnwanted.setAttribute("disabled", "true");
|
||||
}
|
||||
});
|
||||
|
||||
blockDownloads.addEventListener("command", function() {
|
||||
blockDownloadsPref.value = blockDownloads.checked;
|
||||
if (blockDownloads.checked) {
|
||||
blockUncommonUnwanted.removeAttribute("disabled");
|
||||
} else {
|
||||
blockUncommonUnwanted.setAttribute("disabled", "true");
|
||||
}
|
||||
});
|
||||
|
||||
blockUncommonUnwanted.addEventListener("command", function() {
|
||||
blockUnwantedPref.value = blockUncommonUnwanted.checked;
|
||||
blockUncommonPref.value = blockUncommonUnwanted.checked;
|
||||
|
||||
let malware = malwareTable.value
|
||||
.split(",")
|
||||
.filter(x => x !== "goog-unwanted-shavar" && x !== "test-unwanted-simple");
|
||||
|
||||
if (blockUncommonUnwanted.checked) {
|
||||
malware.push("goog-unwanted-shavar");
|
||||
malware.push("test-unwanted-simple");
|
||||
}
|
||||
|
||||
// sort alphabetically to keep the pref consistent
|
||||
malware.sort();
|
||||
|
||||
malwareTable.value = malware.join(",");
|
||||
});
|
||||
|
||||
// set initial values
|
||||
|
||||
enableSafeBrowsing.checked = safeBrowsingPhishingPref.value && safeBrowsingMalwarePref.value;
|
||||
if (!enableSafeBrowsing.checked) {
|
||||
blockDownloads.setAttribute("disabled", "true");
|
||||
blockUncommonUnwanted.setAttribute("disabled", "true");
|
||||
}
|
||||
|
||||
blockDownloads.checked = blockDownloadsPref.value;
|
||||
if (!blockDownloadsPref.value) {
|
||||
blockUncommonUnwanted.setAttribute("disabled", "true");
|
||||
}
|
||||
|
||||
blockUncommonUnwanted.checked = blockUnwantedPref.value && blockUncommonPref.value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables/disables the master password button depending on the state of the
|
||||
* "use master password" checkbox, and prompts for master password removal if
|
||||
* one is set.
|
||||
*/
|
||||
updateMasterPasswordButton() {
|
||||
var checkbox = document.getElementById("useMasterPassword");
|
||||
var button = document.getElementById("changeMasterPassword");
|
||||
button.disabled = !checkbox.checked;
|
||||
|
||||
// unchecking the checkbox should try to immediately remove the master
|
||||
// password, because it's impossible to non-destructively remove the master
|
||||
// password used to encrypt all the passwords without providing it (by
|
||||
// design), and it would be extremely odd to pop up that dialog when the
|
||||
// user closes the prefwindow and saves his settings
|
||||
if (!checkbox.checked)
|
||||
this._removeMasterPassword();
|
||||
else
|
||||
this.changeMasterPassword();
|
||||
|
||||
this._initMasterPasswordUI();
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the "remove master password" dialog to allow the user to remove
|
||||
* the current master password. When the dialog is dismissed, master password
|
||||
* UI is automatically updated.
|
||||
*/
|
||||
_removeMasterPassword() {
|
||||
var secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].
|
||||
getService(Ci.nsIPKCS11ModuleDB);
|
||||
if (secmodDB.isFIPSEnabled) {
|
||||
var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].
|
||||
getService(Ci.nsIPromptService);
|
||||
var bundle = document.getElementById("bundlePreferences");
|
||||
promptService.alert(window,
|
||||
bundle.getString("pw_change_failed_title"),
|
||||
bundle.getString("pw_change2empty_in_fips_mode"));
|
||||
this._initMasterPasswordUI();
|
||||
} else {
|
||||
gSubDialog.open("chrome://mozapps/content/preferences/removemp.xul",
|
||||
null, null, this._initMasterPasswordUI.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a dialog in which the master password may be changed.
|
||||
*/
|
||||
changeMasterPassword() {
|
||||
gSubDialog.open("chrome://mozapps/content/preferences/changemp.xul",
|
||||
"resizable=no", null, this._initMasterPasswordUI.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the sites where the user has saved passwords and the associated login
|
||||
* information.
|
||||
*/
|
||||
showPasswords() {
|
||||
gSubDialog.open("chrome://passwordmgr/content/passwordManager.xul");
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,131 @@
|
|||
# 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/.
|
||||
|
||||
<!-- Security panel -->
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/security.js"/>
|
||||
|
||||
<preferences id="securityPreferences" hidden="true" data-category="paneSecurity">
|
||||
<!-- XXX buttons -->
|
||||
<preference id="pref.privacy.disable_button.view_passwords"
|
||||
name="pref.privacy.disable_button.view_passwords"
|
||||
type="bool"/>
|
||||
<preference id="pref.privacy.disable_button.view_passwords_exceptions"
|
||||
name="pref.privacy.disable_button.view_passwords_exceptions"
|
||||
type="bool"/>
|
||||
|
||||
<!-- Add-ons, malware, phishing -->
|
||||
<preference id="xpinstall.whitelist.required"
|
||||
name="xpinstall.whitelist.required"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="browser.safebrowsing.malware.enabled"
|
||||
name="browser.safebrowsing.malware.enabled"
|
||||
type="bool"/>
|
||||
<preference id="browser.safebrowsing.phishing.enabled"
|
||||
name="browser.safebrowsing.phishing.enabled"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="browser.safebrowsing.downloads.enabled"
|
||||
name="browser.safebrowsing.downloads.enabled"
|
||||
type="bool"/>
|
||||
|
||||
<preference id="urlclassifier.malwareTable"
|
||||
name="urlclassifier.malwareTable"
|
||||
type="string"/>
|
||||
|
||||
<preference id="browser.safebrowsing.downloads.remote.block_potentially_unwanted"
|
||||
name="browser.safebrowsing.downloads.remote.block_potentially_unwanted"
|
||||
type="bool"/>
|
||||
<preference id="browser.safebrowsing.downloads.remote.block_uncommon"
|
||||
name="browser.safebrowsing.downloads.remote.block_uncommon"
|
||||
type="bool"/>
|
||||
|
||||
<!-- Passwords -->
|
||||
<preference id="signon.rememberSignons" name="signon.rememberSignons" type="bool"/>
|
||||
|
||||
</preferences>
|
||||
|
||||
<hbox id="header-security"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneSecurity">
|
||||
<label class="header-name" flex="1">&paneSecurity.title;</label>
|
||||
<html:a class="help-button" target="_blank" aria-label="&helpButton.label;"></html:a>
|
||||
</hbox>
|
||||
|
||||
<!-- addons, forgery (phishing) UI -->
|
||||
<groupbox id="addonsPhishingGroup" data-category="paneSecurity" hidden="true">
|
||||
<caption><label>&general.label;</label></caption>
|
||||
|
||||
<hbox id="addonInstallBox">
|
||||
<checkbox id="warnAddonInstall"
|
||||
label="&warnOnAddonInstall.label;"
|
||||
accesskey="&warnOnAddonInstall.accesskey;"
|
||||
preference="xpinstall.whitelist.required"
|
||||
onsyncfrompreference="return gSecurityPane.readWarnAddonInstall();"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="addonExceptions"
|
||||
label="&addonExceptions.label;"
|
||||
accesskey="&addonExceptions.accesskey;"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
<vbox align="start">
|
||||
<checkbox id="enableSafeBrowsing"
|
||||
label="&enableSafeBrowsing.label;"
|
||||
accesskey="&enableSafeBrowsing.accesskey;" />
|
||||
<vbox class="indent">
|
||||
<checkbox id="blockDownloads"
|
||||
label="&blockDownloads.label;"
|
||||
accesskey="&blockDownloads.accesskey;" />
|
||||
<checkbox id="blockUncommonUnwanted"
|
||||
label="&blockUncommonAndUnwanted.label;"
|
||||
accesskey="&blockUncommonAndUnwanted.accesskey;" />
|
||||
</vbox>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
|
||||
<!-- Passwords -->
|
||||
<groupbox id="passwordsGroup" orient="vertical" data-category="paneSecurity" hidden="true">
|
||||
<caption><label>&logins.label;</label></caption>
|
||||
|
||||
<hbox id="savePasswordsBox">
|
||||
<checkbox id="savePasswords"
|
||||
label="&rememberLogins.label;" accesskey="&rememberLogins.accesskey;"
|
||||
preference="signon.rememberSignons"
|
||||
onsyncfrompreference="return gSecurityPane.readSavePasswords();"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="passwordExceptions"
|
||||
label="&passwordExceptions.label;"
|
||||
accesskey="&passwordExceptions.accesskey;"
|
||||
preference="pref.privacy.disable_button.view_passwords_exceptions"/>
|
||||
</hbox>
|
||||
<grid id="passwordGrid">
|
||||
<columns>
|
||||
<column flex="1"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows id="passwordRows">
|
||||
<row id="masterPasswordRow">
|
||||
<hbox id="masterPasswordBox">
|
||||
<checkbox id="useMasterPassword"
|
||||
label="&useMasterPassword.label;"
|
||||
accesskey="&useMasterPassword.accesskey;"/>
|
||||
<spacer flex="1"/>
|
||||
</hbox>
|
||||
<button id="changeMasterPassword"
|
||||
label="&changeMasterPassword.label;"
|
||||
accesskey="&changeMasterPassword.accesskey;"/>
|
||||
</row>
|
||||
<row id="showPasswordRow">
|
||||
<hbox id="showPasswordsBox"/>
|
||||
<button id="showPasswords"
|
||||
label="&savedLogins.label;" accesskey="&savedLogins.accesskey;"
|
||||
preference="pref.privacy.disable_button.view_passwords"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
|
@ -0,0 +1,438 @@
|
|||
/* - 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/. */
|
||||
|
||||
/* import-globals-from ../../../base/content/utilityOverlay.js */
|
||||
/* import-globals-from preferences.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
var gSubDialog = {
|
||||
_closingCallback: null,
|
||||
_closingEvent: null,
|
||||
_isClosing: false,
|
||||
_frame: null,
|
||||
_overlay: null,
|
||||
_box: null,
|
||||
_openedURL: null,
|
||||
_injectedStyleSheets: [
|
||||
"chrome://browser/skin/preferences/preferences.css",
|
||||
"chrome://global/skin/in-content-old/common.css",
|
||||
"chrome://browser/skin/preferences/in-content-old/preferences.css",
|
||||
"chrome://browser/skin/preferences/in-content-old/dialog.css",
|
||||
],
|
||||
_resizeObserver: null,
|
||||
|
||||
init() {
|
||||
this._frame = document.getElementById("dialogFrame");
|
||||
this._overlay = document.getElementById("dialogOverlay");
|
||||
this._box = document.getElementById("dialogBox");
|
||||
this._closeButton = document.getElementById("dialogClose");
|
||||
},
|
||||
|
||||
updateTitle(aEvent) {
|
||||
if (aEvent.target != gSubDialog._frame.contentDocument)
|
||||
return;
|
||||
document.getElementById("dialogTitle").textContent = gSubDialog._frame.contentDocument.title;
|
||||
},
|
||||
|
||||
injectXMLStylesheet(aStylesheetURL) {
|
||||
let contentStylesheet = this._frame.contentDocument.createProcessingInstruction(
|
||||
"xml-stylesheet",
|
||||
'href="' + aStylesheetURL + '" type="text/css"'
|
||||
);
|
||||
this._frame.contentDocument.insertBefore(contentStylesheet,
|
||||
this._frame.contentDocument.documentElement);
|
||||
},
|
||||
|
||||
open(aURL, aFeatures = null, aParams = null, aClosingCallback = null) {
|
||||
// If we're already open/opening on this URL, do nothing.
|
||||
if (this._openedURL == aURL && !this._isClosing) {
|
||||
return;
|
||||
}
|
||||
// If we're open on some (other) URL or we're closing, open when closing has finished.
|
||||
if (this._openedURL || this._isClosing) {
|
||||
if (!this._isClosing) {
|
||||
this.close();
|
||||
}
|
||||
let args = Array.from(arguments);
|
||||
this._closingPromise.then(() => {
|
||||
this.open.apply(this, args);
|
||||
});
|
||||
return;
|
||||
}
|
||||
this._addDialogEventListeners();
|
||||
|
||||
let features = (aFeatures ? aFeatures + "," : "") + "resizable,dialog=no,centerscreen";
|
||||
let dialog = window.openDialog(aURL, "dialogFrame", features, aParams);
|
||||
if (aClosingCallback) {
|
||||
this._closingCallback = aClosingCallback.bind(dialog);
|
||||
}
|
||||
|
||||
this._closingEvent = null;
|
||||
this._isClosing = false;
|
||||
this._openedURL = aURL;
|
||||
|
||||
features = features.replace(/,/g, "&");
|
||||
let featureParams = new URLSearchParams(features.toLowerCase());
|
||||
this._box.setAttribute("resizable", featureParams.has("resizable") &&
|
||||
featureParams.get("resizable") != "no" &&
|
||||
featureParams.get("resizable") != "0");
|
||||
},
|
||||
|
||||
close(aEvent = null) {
|
||||
if (this._isClosing) {
|
||||
return;
|
||||
}
|
||||
this._isClosing = true;
|
||||
this._closingPromise = new Promise(resolve => {
|
||||
this._resolveClosePromise = resolve;
|
||||
});
|
||||
|
||||
if (this._closingCallback) {
|
||||
try {
|
||||
this._closingCallback.call(null, aEvent);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
this._closingCallback = null;
|
||||
}
|
||||
|
||||
this._removeDialogEventListeners();
|
||||
|
||||
this._overlay.style.visibility = "";
|
||||
// Clear the sizing inline styles.
|
||||
this._frame.removeAttribute("style");
|
||||
// Clear the sizing attributes
|
||||
this._box.removeAttribute("width");
|
||||
this._box.removeAttribute("height");
|
||||
this._box.style.removeProperty("min-height");
|
||||
this._box.style.removeProperty("min-width");
|
||||
|
||||
setTimeout(() => {
|
||||
// Unload the dialog after the event listeners run so that the load of about:blank isn't
|
||||
// cancelled by the ESC <key>.
|
||||
let onBlankLoad = e => {
|
||||
if (this._frame.contentWindow.location.href == "about:blank") {
|
||||
this._frame.removeEventListener("load", onBlankLoad);
|
||||
// We're now officially done closing, so update the state to reflect that.
|
||||
this._openedURL = null;
|
||||
this._isClosing = false;
|
||||
this._resolveClosePromise();
|
||||
}
|
||||
};
|
||||
this._frame.addEventListener("load", onBlankLoad);
|
||||
this._frame.loadURI("about:blank");
|
||||
}, 0);
|
||||
},
|
||||
|
||||
handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "command":
|
||||
this._frame.contentWindow.close();
|
||||
break;
|
||||
case "dialogclosing":
|
||||
this._onDialogClosing(aEvent);
|
||||
break;
|
||||
case "DOMTitleChanged":
|
||||
this.updateTitle(aEvent);
|
||||
break;
|
||||
case "DOMFrameContentLoaded":
|
||||
this._onContentLoaded(aEvent);
|
||||
break;
|
||||
case "load":
|
||||
this._onLoad(aEvent);
|
||||
break;
|
||||
case "unload":
|
||||
this._onUnload(aEvent);
|
||||
break;
|
||||
case "keydown":
|
||||
this._onKeyDown(aEvent);
|
||||
break;
|
||||
case "focus":
|
||||
this._onParentWinFocus(aEvent);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/* Private methods */
|
||||
|
||||
_onUnload(aEvent) {
|
||||
if (aEvent.target.location.href == this._openedURL) {
|
||||
this._frame.contentWindow.close();
|
||||
}
|
||||
},
|
||||
|
||||
_onContentLoaded(aEvent) {
|
||||
if (aEvent.target != this._frame || aEvent.target.contentWindow.location == "about:blank") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let styleSheetURL of this._injectedStyleSheets) {
|
||||
this.injectXMLStylesheet(styleSheetURL);
|
||||
}
|
||||
|
||||
// Provide the ability for the dialog to know that it is being loaded "in-content".
|
||||
this._frame.contentDocument.documentElement.setAttribute("subdialog", "true");
|
||||
|
||||
this._frame.contentWindow.addEventListener("dialogclosing", this);
|
||||
|
||||
let oldResizeBy = this._frame.contentWindow.resizeBy;
|
||||
this._frame.contentWindow.resizeBy = function(resizeByWidth, resizeByHeight) {
|
||||
// Only handle resizeByHeight currently.
|
||||
let frameHeight = gSubDialog._frame.clientHeight;
|
||||
let boxMinHeight = parseFloat(getComputedStyle(gSubDialog._box).minHeight, 10);
|
||||
|
||||
gSubDialog._frame.style.height = (frameHeight + resizeByHeight) + "px";
|
||||
gSubDialog._box.style.minHeight = (boxMinHeight + resizeByHeight) + "px";
|
||||
|
||||
oldResizeBy.call(gSubDialog._frame.contentWindow, resizeByWidth, resizeByHeight);
|
||||
};
|
||||
|
||||
// Make window.close calls work like dialog closing.
|
||||
let oldClose = this._frame.contentWindow.close;
|
||||
this._frame.contentWindow.close = function() {
|
||||
var closingEvent = gSubDialog._closingEvent;
|
||||
if (!closingEvent) {
|
||||
closingEvent = new CustomEvent("dialogclosing", {
|
||||
bubbles: true,
|
||||
detail: { button: null },
|
||||
});
|
||||
|
||||
gSubDialog._frame.contentWindow.dispatchEvent(closingEvent);
|
||||
}
|
||||
|
||||
gSubDialog.close(closingEvent);
|
||||
oldClose.call(gSubDialog._frame.contentWindow);
|
||||
};
|
||||
|
||||
// XXX: Hack to make focus during the dialog's load functions work. Make the element visible
|
||||
// sooner in DOMContentLoaded but mostly invisible instead of changing visibility just before
|
||||
// the dialog's load event.
|
||||
this._overlay.style.visibility = "visible";
|
||||
this._overlay.style.opacity = "0.01";
|
||||
},
|
||||
|
||||
_onLoad(aEvent) {
|
||||
if (aEvent.target.contentWindow.location == "about:blank") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do this on load to wait for the CSS to load and apply before calculating the size.
|
||||
let docEl = this._frame.contentDocument.documentElement;
|
||||
|
||||
let groupBoxTitle = document.getAnonymousElementByAttribute(this._box, "class", "groupbox-title");
|
||||
let groupBoxTitleHeight = groupBoxTitle.clientHeight +
|
||||
parseFloat(getComputedStyle(groupBoxTitle).borderBottomWidth);
|
||||
|
||||
let groupBoxBody = document.getAnonymousElementByAttribute(this._box, "class", "groupbox-body");
|
||||
// These are deduced from styles which we don't change, so it's safe to get them now:
|
||||
let boxVerticalPadding = 2 * parseFloat(getComputedStyle(groupBoxBody).paddingTop);
|
||||
let boxHorizontalPadding = 2 * parseFloat(getComputedStyle(groupBoxBody).paddingLeft);
|
||||
let boxHorizontalBorder = 2 * parseFloat(getComputedStyle(this._box).borderLeftWidth);
|
||||
let boxVerticalBorder = 2 * parseFloat(getComputedStyle(this._box).borderTopWidth);
|
||||
|
||||
// The difference between the frame and box shouldn't change, either:
|
||||
let boxRect = this._box.getBoundingClientRect();
|
||||
let frameRect = this._frame.getBoundingClientRect();
|
||||
let frameSizeDifference = (frameRect.top - boxRect.top) + (boxRect.bottom - frameRect.bottom);
|
||||
|
||||
// Then determine and set a bunch of width stuff:
|
||||
let frameMinWidth = docEl.style.width || docEl.scrollWidth + "px";
|
||||
let frameWidth = docEl.getAttribute("width") ? docEl.getAttribute("width") + "px" :
|
||||
frameMinWidth;
|
||||
this._frame.style.width = frameWidth;
|
||||
this._box.style.minWidth = "calc(" +
|
||||
(boxHorizontalBorder + boxHorizontalPadding) +
|
||||
"px + " + frameMinWidth + ")";
|
||||
|
||||
// Now do the same but for the height. We need to do this afterwards because otherwise
|
||||
// XUL assumes we'll optimize for height and gives us "wrong" values which then are no
|
||||
// longer correct after we set the width:
|
||||
let frameMinHeight = docEl.style.height || docEl.scrollHeight + "px";
|
||||
let frameHeight = docEl.getAttribute("height") ? docEl.getAttribute("height") + "px" :
|
||||
frameMinHeight;
|
||||
|
||||
// Now check if the frame height we calculated is possible at this window size,
|
||||
// accounting for titlebar, padding/border and some spacing.
|
||||
let maxHeight = window.innerHeight - frameSizeDifference - 30;
|
||||
// Do this with a frame height in pixels...
|
||||
let comparisonFrameHeight;
|
||||
if (frameHeight.endsWith("em")) {
|
||||
let fontSize = parseFloat(getComputedStyle(this._frame).fontSize);
|
||||
comparisonFrameHeight = parseFloat(frameHeight, 10) * fontSize;
|
||||
} else if (frameHeight.endsWith("px")) {
|
||||
comparisonFrameHeight = parseFloat(frameHeight, 10);
|
||||
} else {
|
||||
Cu.reportError("This dialog (" + this._frame.contentWindow.location.href + ") " +
|
||||
"set a height in non-px-non-em units ('" + frameHeight + "'), " +
|
||||
"which is likely to lead to bad sizing in in-content preferences. " +
|
||||
"Please consider changing this.");
|
||||
comparisonFrameHeight = parseFloat(frameHeight);
|
||||
}
|
||||
|
||||
if (comparisonFrameHeight > maxHeight) {
|
||||
// If the height is bigger than that of the window, we should let the contents scroll:
|
||||
frameHeight = maxHeight + "px";
|
||||
frameMinHeight = maxHeight + "px";
|
||||
let containers = this._frame.contentDocument.querySelectorAll(".largeDialogContainer");
|
||||
for (let container of containers) {
|
||||
container.classList.add("doScroll");
|
||||
}
|
||||
}
|
||||
|
||||
this._frame.style.height = frameHeight;
|
||||
this._box.style.minHeight = "calc(" +
|
||||
(boxVerticalBorder + groupBoxTitleHeight + boxVerticalPadding) +
|
||||
"px + " + frameMinHeight + ")";
|
||||
|
||||
this._overlay.style.visibility = "visible";
|
||||
this._overlay.style.opacity = ""; // XXX: focus hack continued from _onContentLoaded
|
||||
|
||||
if (this._box.getAttribute("resizable") == "true") {
|
||||
this._resizeObserver = new MutationObserver(this._onResize);
|
||||
this._resizeObserver.observe(this._box, {attributes: true});
|
||||
}
|
||||
|
||||
this._trapFocus();
|
||||
},
|
||||
|
||||
_onResize(mutations) {
|
||||
let frame = gSubDialog._frame;
|
||||
// The width and height styles are needed for the initial
|
||||
// layout of the frame, but afterward they need to be removed
|
||||
// or their presence will restrict the contents of the <browser>
|
||||
// from resizing to a smaller size.
|
||||
frame.style.removeProperty("width");
|
||||
frame.style.removeProperty("height");
|
||||
|
||||
let docEl = frame.contentDocument.documentElement;
|
||||
let persistedAttributes = docEl.getAttribute("persist");
|
||||
if (!persistedAttributes ||
|
||||
(!persistedAttributes.includes("width") &&
|
||||
!persistedAttributes.includes("height"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let mutation of mutations) {
|
||||
if (mutation.attributeName == "width") {
|
||||
docEl.setAttribute("width", docEl.scrollWidth);
|
||||
} else if (mutation.attributeName == "height") {
|
||||
docEl.setAttribute("height", docEl.scrollHeight);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onDialogClosing(aEvent) {
|
||||
this._frame.contentWindow.removeEventListener("dialogclosing", this);
|
||||
this._closingEvent = aEvent;
|
||||
},
|
||||
|
||||
_onKeyDown(aEvent) {
|
||||
if (aEvent.currentTarget == window && aEvent.keyCode == aEvent.DOM_VK_ESCAPE &&
|
||||
!aEvent.defaultPrevented) {
|
||||
this.close(aEvent);
|
||||
return;
|
||||
}
|
||||
if (aEvent.keyCode != aEvent.DOM_VK_TAB ||
|
||||
aEvent.ctrlKey || aEvent.altKey || aEvent.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fm = Services.focus;
|
||||
|
||||
function isLastFocusableElement(el) {
|
||||
// XXXgijs unfortunately there is no way to get the last focusable element without asking
|
||||
// the focus manager to move focus to it.
|
||||
let rv = el == fm.moveFocus(gSubDialog._frame.contentWindow, null, fm.MOVEFOCUS_LAST, 0);
|
||||
fm.setFocus(el, 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
let forward = !aEvent.shiftKey;
|
||||
// check if focus is leaving the frame (incl. the close button):
|
||||
if ((aEvent.target == this._closeButton && !forward) ||
|
||||
(isLastFocusableElement(aEvent.originalTarget) && forward)) {
|
||||
aEvent.preventDefault();
|
||||
aEvent.stopImmediatePropagation();
|
||||
let parentWin = this._getBrowser().ownerGlobal;
|
||||
if (forward) {
|
||||
fm.moveFocus(parentWin, null, fm.MOVEFOCUS_FIRST, fm.FLAG_BYKEY);
|
||||
} else {
|
||||
// Somehow, moving back 'past' the opening doc is not trivial. Cheat by doing it in 2 steps:
|
||||
fm.moveFocus(window, null, fm.MOVEFOCUS_ROOT, fm.FLAG_BYKEY);
|
||||
fm.moveFocus(parentWin, null, fm.MOVEFOCUS_BACKWARD, fm.FLAG_BYKEY);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onParentWinFocus(aEvent) {
|
||||
// Explicitly check for the focus target of |window| to avoid triggering this when the window
|
||||
// is refocused
|
||||
if (aEvent.target != this._closeButton && aEvent.target != window) {
|
||||
this._closeButton.focus();
|
||||
}
|
||||
},
|
||||
|
||||
_addDialogEventListeners() {
|
||||
// Make the close button work.
|
||||
this._closeButton.addEventListener("command", this);
|
||||
|
||||
// DOMTitleChanged isn't fired on the frame, only on the chromeEventHandler
|
||||
let chromeBrowser = this._getBrowser();
|
||||
chromeBrowser.addEventListener("DOMTitleChanged", this, true);
|
||||
|
||||
// Similarly DOMFrameContentLoaded only fires on the top window
|
||||
window.addEventListener("DOMFrameContentLoaded", this, true);
|
||||
|
||||
// Wait for the stylesheets injected during DOMContentLoaded to load before showing the dialog
|
||||
// otherwise there is a flicker of the stylesheet applying.
|
||||
this._frame.addEventListener("load", this);
|
||||
|
||||
chromeBrowser.addEventListener("unload", this, true);
|
||||
// Ensure we get <esc> keypresses even if nothing in the subdialog is focusable
|
||||
// (happens on OS X when only text inputs and lists are focusable, and
|
||||
// the subdialog only has checkboxes/radiobuttons/buttons)
|
||||
window.addEventListener("keydown", this, true);
|
||||
},
|
||||
|
||||
_removeDialogEventListeners() {
|
||||
let chromeBrowser = this._getBrowser();
|
||||
chromeBrowser.removeEventListener("DOMTitleChanged", this, true);
|
||||
chromeBrowser.removeEventListener("unload", this, true);
|
||||
|
||||
this._closeButton.removeEventListener("command", this);
|
||||
|
||||
window.removeEventListener("DOMFrameContentLoaded", this, true);
|
||||
this._frame.removeEventListener("load", this);
|
||||
this._frame.contentWindow.removeEventListener("dialogclosing", this);
|
||||
window.removeEventListener("keydown", this, true);
|
||||
if (this._resizeObserver) {
|
||||
this._resizeObserver.disconnect();
|
||||
this._resizeObserver = null;
|
||||
}
|
||||
this._untrapFocus();
|
||||
},
|
||||
|
||||
_trapFocus() {
|
||||
let fm = Services.focus;
|
||||
fm.moveFocus(this._frame.contentWindow, null, fm.MOVEFOCUS_FIRST, 0);
|
||||
this._frame.contentDocument.addEventListener("keydown", this, true);
|
||||
this._closeButton.addEventListener("keydown", this);
|
||||
|
||||
window.addEventListener("focus", this, true);
|
||||
},
|
||||
|
||||
_untrapFocus() {
|
||||
this._frame.contentDocument.removeEventListener("keydown", this, true);
|
||||
this._closeButton.removeEventListener("keydown", this);
|
||||
window.removeEventListener("focus", this);
|
||||
},
|
||||
|
||||
_getBrowser() {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,492 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from preferences.js */
|
||||
|
||||
Components.utils.import("resource://services-sync/main.js");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function() {
|
||||
return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {});
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
|
||||
"resource://gre/modules/FxAccounts.jsm");
|
||||
|
||||
const FXA_PAGE_LOGGED_OUT = 0;
|
||||
const FXA_PAGE_LOGGED_IN = 1;
|
||||
|
||||
// Indexes into the "login status" deck.
|
||||
// We are in a successful verified state - everything should work!
|
||||
const FXA_LOGIN_VERIFIED = 0;
|
||||
// We have logged in to an unverified account.
|
||||
const FXA_LOGIN_UNVERIFIED = 1;
|
||||
// We are logged in locally, but the server rejected our credentials.
|
||||
const FXA_LOGIN_FAILED = 2;
|
||||
|
||||
var gSyncPane = {
|
||||
prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs",
|
||||
"engine.tabs", "engine.history"],
|
||||
|
||||
get page() {
|
||||
return document.getElementById("weavePrefsDeck").selectedIndex;
|
||||
},
|
||||
|
||||
set page(val) {
|
||||
document.getElementById("weavePrefsDeck").selectedIndex = val;
|
||||
},
|
||||
|
||||
init() {
|
||||
this._setupEventListeners();
|
||||
|
||||
// If the Service hasn't finished initializing, wait for it.
|
||||
let xps = Components.classes["@mozilla.org/weave/service;1"]
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
|
||||
if (xps.ready) {
|
||||
this._init();
|
||||
return;
|
||||
}
|
||||
|
||||
// it may take some time before we can determine what provider to use
|
||||
// and the state of that provider, so show the "please wait" page.
|
||||
this._showLoadPage(xps);
|
||||
|
||||
let onUnload = function() {
|
||||
window.removeEventListener("unload", onUnload);
|
||||
try {
|
||||
Services.obs.removeObserver(onReady, "weave:service:ready");
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
let onReady = function() {
|
||||
Services.obs.removeObserver(onReady, "weave:service:ready");
|
||||
window.removeEventListener("unload", onUnload);
|
||||
this._init();
|
||||
}.bind(this);
|
||||
|
||||
Services.obs.addObserver(onReady, "weave:service:ready", false);
|
||||
window.addEventListener("unload", onUnload);
|
||||
|
||||
xps.ensureLoaded();
|
||||
},
|
||||
|
||||
_showLoadPage(xps) {
|
||||
let username = Services.prefs.getCharPref("services.sync.username", "");
|
||||
if (!username) {
|
||||
this.page = FXA_PAGE_LOGGED_OUT;
|
||||
return;
|
||||
}
|
||||
|
||||
// Use cached values while we wait for the up-to-date values
|
||||
let cachedComputerName = Services.prefs.getCharPref("services.sync.client.name", "");
|
||||
document.getElementById("fxaEmailAddress1").textContent = username;
|
||||
this._populateComputerName(cachedComputerName);
|
||||
this.page = FXA_PAGE_LOGGED_IN;
|
||||
},
|
||||
|
||||
_init() {
|
||||
let topics = ["weave:service:login:error",
|
||||
"weave:service:login:finish",
|
||||
"weave:service:start-over:finish",
|
||||
"weave:service:setup-complete",
|
||||
"weave:service:logout:finish",
|
||||
FxAccountsCommon.ONVERIFIED_NOTIFICATION,
|
||||
FxAccountsCommon.ONLOGIN_NOTIFICATION,
|
||||
FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION,
|
||||
];
|
||||
// Add the observers now and remove them on unload
|
||||
// XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
|
||||
// of `this`. Fix in a followup. (bug 583347)
|
||||
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);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "_accountsStringBundle", () => {
|
||||
return Services.strings.createBundle("chrome://browser/locale/accounts.properties");
|
||||
});
|
||||
|
||||
let url = Services.prefs.getCharPref("identity.mobilepromo.android") + "sync-preferences";
|
||||
document.getElementById("fxaMobilePromo-android").setAttribute("href", url);
|
||||
document.getElementById("fxaMobilePromo-android-hasFxaAccount").setAttribute("href", url);
|
||||
url = Services.prefs.getCharPref("identity.mobilepromo.ios") + "sync-preferences";
|
||||
document.getElementById("fxaMobilePromo-ios").setAttribute("href", url);
|
||||
document.getElementById("fxaMobilePromo-ios-hasFxaAccount").setAttribute("href", url);
|
||||
|
||||
document.getElementById("tosPP-small-ToS").setAttribute("href", Weave.Svc.Prefs.get("fxa.termsURL"));
|
||||
document.getElementById("tosPP-small-PP").setAttribute("href", Weave.Svc.Prefs.get("fxa.privacyURL"));
|
||||
|
||||
fxAccounts.promiseAccountsManageURI(this._getEntryPoint()).then(accountsManageURI => {
|
||||
document.getElementById("verifiedManage").setAttribute("href", accountsManageURI);
|
||||
});
|
||||
|
||||
this.updateWeavePrefs();
|
||||
|
||||
this._initProfileImageUI();
|
||||
},
|
||||
|
||||
_toggleComputerNameControls(editMode) {
|
||||
let textbox = document.getElementById("fxaSyncComputerName");
|
||||
textbox.disabled = !editMode;
|
||||
document.getElementById("fxaChangeDeviceName").hidden = editMode;
|
||||
document.getElementById("fxaCancelChangeDeviceName").hidden = !editMode;
|
||||
document.getElementById("fxaSaveChangeDeviceName").hidden = !editMode;
|
||||
},
|
||||
|
||||
_focusComputerNameTextbox() {
|
||||
let textbox = document.getElementById("fxaSyncComputerName");
|
||||
let valLength = textbox.value.length;
|
||||
textbox.focus();
|
||||
textbox.setSelectionRange(valLength, valLength);
|
||||
},
|
||||
|
||||
_blurComputerNameTextbox() {
|
||||
document.getElementById("fxaSyncComputerName").blur();
|
||||
},
|
||||
|
||||
_focusAfterComputerNameTextbox() {
|
||||
// Focus the most appropriate element that's *not* the "computer name" box.
|
||||
Services.focus.moveFocus(window,
|
||||
document.getElementById("fxaSyncComputerName"),
|
||||
Services.focus.MOVEFOCUS_FORWARD, 0);
|
||||
},
|
||||
|
||||
_updateComputerNameValue(save) {
|
||||
if (save) {
|
||||
let textbox = document.getElementById("fxaSyncComputerName");
|
||||
Weave.Service.clientsEngine.localName = textbox.value;
|
||||
}
|
||||
this._populateComputerName(Weave.Service.clientsEngine.localName);
|
||||
},
|
||||
|
||||
_setupEventListeners() {
|
||||
function setEventListener(aId, aEventType, aCallback) {
|
||||
document.getElementById(aId)
|
||||
.addEventListener(aEventType, aCallback.bind(gSyncPane));
|
||||
}
|
||||
|
||||
setEventListener("fxaChangeDeviceName", "command", function() {
|
||||
this._toggleComputerNameControls(true);
|
||||
this._focusComputerNameTextbox();
|
||||
});
|
||||
setEventListener("fxaCancelChangeDeviceName", "command", function() {
|
||||
// We explicitly blur the textbox because of bug 75324, then after
|
||||
// changing the state of the buttons, force focus to whatever the focus
|
||||
// manager thinks should be next (which on the mac, depends on an OSX
|
||||
// keyboard access preference)
|
||||
this._blurComputerNameTextbox();
|
||||
this._toggleComputerNameControls(false);
|
||||
this._updateComputerNameValue(false);
|
||||
this._focusAfterComputerNameTextbox();
|
||||
});
|
||||
setEventListener("fxaSaveChangeDeviceName", "command", function() {
|
||||
// Work around bug 75324 - see above.
|
||||
this._blurComputerNameTextbox();
|
||||
this._toggleComputerNameControls(false);
|
||||
this._updateComputerNameValue(true);
|
||||
this._focusAfterComputerNameTextbox();
|
||||
});
|
||||
setEventListener("noFxaSignUp", "command", function() {
|
||||
gSyncPane.signUp();
|
||||
return false;
|
||||
});
|
||||
setEventListener("noFxaSignIn", "command", function() {
|
||||
gSyncPane.signIn();
|
||||
return false;
|
||||
});
|
||||
setEventListener("fxaUnlinkButton", "command", function() {
|
||||
gSyncPane.unlinkFirefoxAccount(true);
|
||||
});
|
||||
setEventListener("verifyFxaAccount", "command",
|
||||
gSyncPane.verifyFirefoxAccount);
|
||||
setEventListener("unverifiedUnlinkFxaAccount", "command", function() {
|
||||
/* no warning as account can't have previously synced */
|
||||
gSyncPane.unlinkFirefoxAccount(false);
|
||||
});
|
||||
setEventListener("rejectReSignIn", "command",
|
||||
gSyncPane.reSignIn);
|
||||
setEventListener("rejectUnlinkFxaAccount", "command", function() {
|
||||
gSyncPane.unlinkFirefoxAccount(true);
|
||||
});
|
||||
setEventListener("fxaSyncComputerName", "keypress", function(e) {
|
||||
if (e.keyCode == KeyEvent.DOM_VK_RETURN) {
|
||||
document.getElementById("fxaSaveChangeDeviceName").click();
|
||||
} else if (e.keyCode == KeyEvent.DOM_VK_ESCAPE) {
|
||||
document.getElementById("fxaCancelChangeDeviceName").click();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_initProfileImageUI() {
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled")) {
|
||||
document.getElementById("fxaProfileImage").hidden = false;
|
||||
}
|
||||
} catch (e) { }
|
||||
},
|
||||
|
||||
updateWeavePrefs() {
|
||||
let service = Components.classes["@mozilla.org/weave/service;1"]
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
|
||||
let displayNameLabel = document.getElementById("fxaDisplayName");
|
||||
let fxaEmailAddress1Label = document.getElementById("fxaEmailAddress1");
|
||||
fxaEmailAddress1Label.hidden = false;
|
||||
displayNameLabel.hidden = true;
|
||||
|
||||
let profileInfoEnabled = Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled", false);
|
||||
|
||||
// determine the fxa status...
|
||||
this._showLoadPage(service);
|
||||
|
||||
fxAccounts.getSignedInUser().then(data => {
|
||||
if (!data) {
|
||||
this.page = FXA_PAGE_LOGGED_OUT;
|
||||
return false;
|
||||
}
|
||||
this.page = FXA_PAGE_LOGGED_IN;
|
||||
// We are logged in locally, but maybe we are in a state where the
|
||||
// server rejected our credentials (eg, password changed on the server)
|
||||
let fxaLoginStatus = document.getElementById("fxaLoginStatus");
|
||||
let syncReady;
|
||||
// Not Verfied implies login error state, so check that first.
|
||||
if (!data.verified) {
|
||||
fxaLoginStatus.selectedIndex = FXA_LOGIN_UNVERIFIED;
|
||||
syncReady = false;
|
||||
// So we think we are logged in, so login problems are next.
|
||||
// (Although if the Sync identity manager is still initializing, we
|
||||
// ignore login errors and assume all will eventually be good.)
|
||||
// LOGIN_FAILED_LOGIN_REJECTED explicitly means "you must log back in".
|
||||
// All other login failures are assumed to be transient and should go
|
||||
// away by themselves, so aren't reflected here.
|
||||
} else if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) {
|
||||
fxaLoginStatus.selectedIndex = FXA_LOGIN_FAILED;
|
||||
syncReady = false;
|
||||
// Else we must be golden (or in an error state we expect to magically
|
||||
// resolve itself)
|
||||
} else {
|
||||
fxaLoginStatus.selectedIndex = FXA_LOGIN_VERIFIED;
|
||||
syncReady = true;
|
||||
}
|
||||
fxaEmailAddress1Label.textContent = data.email;
|
||||
document.getElementById("fxaEmailAddress2").textContent = data.email;
|
||||
document.getElementById("fxaEmailAddress3").textContent = data.email;
|
||||
this._populateComputerName(Weave.Service.clientsEngine.localName);
|
||||
let engines = document.getElementById("fxaSyncEngines")
|
||||
for (let checkbox of engines.querySelectorAll("checkbox")) {
|
||||
checkbox.disabled = !syncReady;
|
||||
}
|
||||
document.getElementById("fxaChangeDeviceName").disabled = !syncReady;
|
||||
|
||||
// Clear the profile image (if any) of the previously logged in account.
|
||||
document.getElementById("fxaProfileImage").style.removeProperty("list-style-image");
|
||||
|
||||
// If the account is verified the next promise in the chain will
|
||||
// fetch profile data.
|
||||
return data.verified;
|
||||
}).then(isVerified => {
|
||||
if (isVerified) {
|
||||
return fxAccounts.getSignedInUserProfile();
|
||||
}
|
||||
return null;
|
||||
}).then(data => {
|
||||
let fxaLoginStatus = document.getElementById("fxaLoginStatus");
|
||||
if (data && profileInfoEnabled) {
|
||||
if (data.displayName) {
|
||||
fxaLoginStatus.setAttribute("hasName", true);
|
||||
displayNameLabel.hidden = false;
|
||||
displayNameLabel.textContent = data.displayName;
|
||||
} else {
|
||||
fxaLoginStatus.removeAttribute("hasName");
|
||||
}
|
||||
if (data.avatar) {
|
||||
let bgImage = "url(\"" + data.avatar + "\")";
|
||||
let profileImageElement = document.getElementById("fxaProfileImage");
|
||||
profileImageElement.style.listStyleImage = bgImage;
|
||||
|
||||
let img = new Image();
|
||||
img.onerror = () => {
|
||||
// Clear the image if it has trouble loading. Since this callback is asynchronous
|
||||
// we check to make sure the image is still the same before we clear it.
|
||||
if (profileImageElement.style.listStyleImage === bgImage) {
|
||||
profileImageElement.style.removeProperty("list-style-image");
|
||||
}
|
||||
};
|
||||
img.src = data.avatar;
|
||||
}
|
||||
} else {
|
||||
fxaLoginStatus.removeAttribute("hasName");
|
||||
}
|
||||
}, err => {
|
||||
FxAccountsCommon.log.error(err);
|
||||
}).catch(err => {
|
||||
// If we get here something's really busted
|
||||
Cu.reportError(String(err));
|
||||
});
|
||||
},
|
||||
|
||||
_getEntryPoint() {
|
||||
let params = new URLSearchParams(document.URL.split("#")[0].split("?")[1] || "");
|
||||
return params.get("entrypoint") || "preferences";
|
||||
},
|
||||
|
||||
_openAboutAccounts(action) {
|
||||
let entryPoint = this._getEntryPoint();
|
||||
let params = new URLSearchParams();
|
||||
if (action) {
|
||||
params.set("action", action);
|
||||
}
|
||||
params.set("entrypoint", entryPoint);
|
||||
|
||||
this.replaceTabWithUrl("about:accounts?" + params);
|
||||
},
|
||||
|
||||
openContentInBrowser(url, options) {
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
if (!win) {
|
||||
openUILinkIn(url, "tab");
|
||||
return;
|
||||
}
|
||||
win.switchToTabHavingURI(url, true, options);
|
||||
},
|
||||
|
||||
// Replace the current tab with the specified URL.
|
||||
replaceTabWithUrl(url) {
|
||||
// Get the <browser> element hosting us.
|
||||
let browser = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
// And tell it to load our URL.
|
||||
browser.loadURI(url);
|
||||
},
|
||||
|
||||
signUp() {
|
||||
this._openAboutAccounts("signup");
|
||||
},
|
||||
|
||||
signIn() {
|
||||
this._openAboutAccounts("signin");
|
||||
},
|
||||
|
||||
reSignIn() {
|
||||
this._openAboutAccounts("reauth");
|
||||
},
|
||||
|
||||
|
||||
clickOrSpaceOrEnterPressed(event) {
|
||||
// Note: charCode is deprecated, but 'char' not yet implemented.
|
||||
// Replace charCode with char when implemented, see Bug 680830
|
||||
return ((event.type == "click" && event.button == 0) ||
|
||||
(event.type == "keypress" &&
|
||||
(event.charCode == KeyEvent.DOM_VK_SPACE || event.keyCode == KeyEvent.DOM_VK_RETURN)));
|
||||
},
|
||||
|
||||
openChangeProfileImage(event) {
|
||||
if (this.clickOrSpaceOrEnterPressed(event)) {
|
||||
fxAccounts.promiseAccountsChangeProfileURI(this._getEntryPoint(), "avatar")
|
||||
.then(url => {
|
||||
this.openContentInBrowser(url, {
|
||||
replaceQueryString: true
|
||||
});
|
||||
});
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
openManageFirefoxAccount(event) {
|
||||
if (this.clickOrSpaceOrEnterPressed(event)) {
|
||||
this.manageFirefoxAccount();
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
manageFirefoxAccount() {
|
||||
fxAccounts.promiseAccountsManageURI(this._getEntryPoint())
|
||||
.then(url => {
|
||||
this.openContentInBrowser(url, {
|
||||
replaceQueryString: true
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
verifyFirefoxAccount() {
|
||||
let showVerifyNotification = (data) => {
|
||||
let isError = !data;
|
||||
let maybeNot = isError ? "Not" : "";
|
||||
let sb = this._accountsStringBundle;
|
||||
let title = sb.GetStringFromName("verification" + maybeNot + "SentTitle");
|
||||
let email = !isError && data ? data.email : "";
|
||||
let body = sb.formatStringFromName("verification" + maybeNot + "SentBody", [email], 1);
|
||||
new Notification(title, { body })
|
||||
}
|
||||
|
||||
let onError = () => {
|
||||
showVerifyNotification();
|
||||
};
|
||||
|
||||
let onSuccess = data => {
|
||||
if (data) {
|
||||
showVerifyNotification(data);
|
||||
} else {
|
||||
onError();
|
||||
}
|
||||
};
|
||||
|
||||
fxAccounts.resendVerificationEmail()
|
||||
.then(fxAccounts.getSignedInUser, onError)
|
||||
.then(onSuccess, onError);
|
||||
},
|
||||
|
||||
unlinkFirefoxAccount(confirm) {
|
||||
if (confirm) {
|
||||
// We use a string bundle shared with aboutAccounts.
|
||||
let sb = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties");
|
||||
let disconnectLabel = sb.GetStringFromName("disconnect.label");
|
||||
let title = sb.GetStringFromName("disconnect.verify.title");
|
||||
let body = sb.GetStringFromName("disconnect.verify.bodyHeading") +
|
||||
"\n\n" +
|
||||
sb.GetStringFromName("disconnect.verify.bodyText");
|
||||
let ps = Services.prompt;
|
||||
let buttonFlags = (ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING) +
|
||||
(ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL) +
|
||||
ps.BUTTON_POS_1_DEFAULT;
|
||||
|
||||
let factory = Cc["@mozilla.org/prompter;1"]
|
||||
.getService(Ci.nsIPromptFactory);
|
||||
let prompt = factory.getPrompt(window, Ci.nsIPrompt);
|
||||
let bag = prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
|
||||
bag.setPropertyAsBool("allowTabModal", true);
|
||||
|
||||
let pressed = prompt.confirmEx(title, body, buttonFlags,
|
||||
disconnectLabel, null, null, null, {});
|
||||
|
||||
if (pressed != 0) { // 0 is the "continue" button
|
||||
return;
|
||||
}
|
||||
}
|
||||
fxAccounts.signOut().then(() => {
|
||||
this.updateWeavePrefs();
|
||||
});
|
||||
},
|
||||
|
||||
_populateComputerName(value) {
|
||||
let textbox = document.getElementById("fxaSyncComputerName");
|
||||
if (!textbox.hasAttribute("placeholder")) {
|
||||
textbox.setAttribute("placeholder",
|
||||
Weave.Utils.getDefaultDeviceName());
|
||||
}
|
||||
textbox.value = value;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,225 @@
|
|||
# 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/.
|
||||
|
||||
<!-- Sync panel -->
|
||||
|
||||
<preferences id="syncEnginePrefs" hidden="true" data-category="paneSync">
|
||||
<preference id="engine.addons"
|
||||
name="services.sync.engine.addons"
|
||||
type="bool"/>
|
||||
<preference id="engine.bookmarks"
|
||||
name="services.sync.engine.bookmarks"
|
||||
type="bool"/>
|
||||
<preference id="engine.history"
|
||||
name="services.sync.engine.history"
|
||||
type="bool"/>
|
||||
<preference id="engine.tabs"
|
||||
name="services.sync.engine.tabs"
|
||||
type="bool"/>
|
||||
<preference id="engine.prefs"
|
||||
name="services.sync.engine.prefs"
|
||||
type="bool"/>
|
||||
<preference id="engine.passwords"
|
||||
name="services.sync.engine.passwords"
|
||||
type="bool"/>
|
||||
</preferences>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/preferences/in-content-old/sync.js"/>
|
||||
|
||||
<hbox id="header-sync"
|
||||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneSync">
|
||||
<label class="header-name" flex="1">&paneSync.title;</label>
|
||||
<html:a class="help-button text-link" target="_blank" aria-label="&helpButton.label;"></html:a>
|
||||
</hbox>
|
||||
|
||||
<deck id="weavePrefsDeck" data-category="paneSync" hidden="true">
|
||||
<vbox id="noFxaAccount">
|
||||
<hbox>
|
||||
<vbox id="fxaContentWrapper">
|
||||
<groupbox id="noFxaGroup">
|
||||
<vbox>
|
||||
<label id="noFxaCaption">&signedOut.caption;</label>
|
||||
<description id="noFxaDescription" flex="1">&signedOut.description;</description>
|
||||
<hbox class="fxaAccountBox">
|
||||
<vbox>
|
||||
<image class="fxaFirefoxLogo"/>
|
||||
</vbox>
|
||||
<vbox flex="1">
|
||||
<label id="signedOutAccountBoxTitle">&signedOut.accountBox.title;</label>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="noFxaSignUp" label="&signedOut.accountBox.create;" accesskey="&signedOut.accountBox.create.accesskey;"></button>
|
||||
<button id="noFxaSignIn" label="&signedOut.accountBox.signin;" accesskey="&signedOut.accountBox.signin.accesskey;"></button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
</vbox>
|
||||
<vbox>
|
||||
<html:img class="fxaSyncIllustration" src="chrome://browser/skin/fxa/sync-illustration.svg#blueFill"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<label class="fxaMobilePromo">
|
||||
&mobilePromo3.start;<!-- We put these comments to avoid inserting white spaces
|
||||
--><label id="fxaMobilePromo-android"
|
||||
class="androidLink text-link"><!--
|
||||
-->&mobilePromo3.androidLink;</label><!--
|
||||
-->&mobilePromo3.iOSBefore;<!--
|
||||
--><label id="fxaMobilePromo-ios"
|
||||
class="iOSLink text-link"><!--
|
||||
-->&mobilePromo3.iOSLink;</label><!--
|
||||
-->&mobilePromo3.end;
|
||||
</label>
|
||||
</vbox>
|
||||
|
||||
<vbox id="hasFxaAccount">
|
||||
<hbox>
|
||||
<vbox id="fxaContentWrapper">
|
||||
<groupbox id="fxaGroup">
|
||||
<caption><label>&syncBrand.fxAccount.label;</label></caption>
|
||||
<deck id="fxaLoginStatus">
|
||||
|
||||
<!-- logged in and verified and all is good -->
|
||||
<hbox id="fxaLoginVerified" class="fxaAccountBox">
|
||||
<vbox align="center" pack="center">
|
||||
<image id="fxaProfileImage" class="actionable"
|
||||
role="button"
|
||||
onclick="gSyncPane.openChangeProfileImage(event);" hidden="true"
|
||||
onkeypress="gSyncPane.openChangeProfileImage(event);"
|
||||
tooltiptext="&profilePicture.tooltip;"/>
|
||||
</vbox>
|
||||
<vbox flex="1" pack="center">
|
||||
<label id="fxaDisplayName" hidden="true"/>
|
||||
<label id="fxaEmailAddress1"/>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="fxaUnlinkButton" label="&disconnect.label;" accesskey="&disconnect.accesskey;"/>
|
||||
<html:a id="verifiedManage" target="_blank"
|
||||
accesskey="&verifiedManage.accesskey;"
|
||||
onkeypress="gSyncPane.openManageFirefoxAccount(event);"><!--
|
||||
-->&verifiedManage.label;</html:a>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
<!-- logged in to an unverified account -->
|
||||
<hbox id="fxaLoginUnverified" class="fxaAccountBox">
|
||||
<vbox>
|
||||
<image id="fxaProfileImage"/>
|
||||
</vbox>
|
||||
<vbox flex="1">
|
||||
<hbox>
|
||||
<vbox><image id="fxaLoginRejectedWarning"/></vbox>
|
||||
<description flex="1">
|
||||
&signedInUnverified.beforename.label;
|
||||
<label id="fxaEmailAddress2"/>
|
||||
&signedInUnverified.aftername.label;
|
||||
</description>
|
||||
</hbox>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="verifyFxaAccount" label="&verify.label;" accesskey="&verify.accesskey;"></button>
|
||||
<button id="unverifiedUnlinkFxaAccount" label="&forget.label;" accesskey="&forget.accesskey;"></button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
<!-- logged in locally but server rejected credentials -->
|
||||
<hbox id="fxaLoginRejected" class="fxaAccountBox">
|
||||
<vbox>
|
||||
<image id="fxaProfileImage"/>
|
||||
</vbox>
|
||||
<vbox flex="1">
|
||||
<hbox>
|
||||
<vbox><image id="fxaLoginRejectedWarning"/></vbox>
|
||||
<description flex="1">
|
||||
&signedInLoginFailure.beforename.label;
|
||||
<label id="fxaEmailAddress3"/>
|
||||
&signedInLoginFailure.aftername.label;
|
||||
</description>
|
||||
</hbox>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="rejectReSignIn" label="&signIn.label;" accesskey="&signIn.accesskey;"></button>
|
||||
<button id="rejectUnlinkFxaAccount" label="&forget.label;" accesskey="&forget.accesskey;"></button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</deck>
|
||||
</groupbox>
|
||||
<groupbox id="syncOptions">
|
||||
<caption><label>&signedIn.engines.label;</label></caption>
|
||||
<hbox id="fxaSyncEngines">
|
||||
<vbox align="start" flex="1">
|
||||
<checkbox label="&engine.tabs.label2;"
|
||||
accesskey="&engine.tabs.accesskey;"
|
||||
preference="engine.tabs"/>
|
||||
<checkbox label="&engine.bookmarks.label;"
|
||||
accesskey="&engine.bookmarks.accesskey;"
|
||||
preference="engine.bookmarks"/>
|
||||
<checkbox label="&engine.passwords.label;"
|
||||
accesskey="&engine.passwords.accesskey;"
|
||||
preference="engine.passwords"/>
|
||||
</vbox>
|
||||
<vbox align="start" flex="1">
|
||||
<checkbox label="&engine.history.label;"
|
||||
accesskey="&engine.history.accesskey;"
|
||||
preference="engine.history"/>
|
||||
<checkbox label="&engine.addons.label;"
|
||||
accesskey="&engine.addons.accesskey;"
|
||||
preference="engine.addons"/>
|
||||
<checkbox label="&engine.prefs.label;"
|
||||
accesskey="&engine.prefs.accesskey;"
|
||||
preference="engine.prefs"/>
|
||||
</vbox>
|
||||
<spacer/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</vbox>
|
||||
<vbox>
|
||||
<html:img class="fxaSyncIllustration" src="chrome://browser/skin/fxa/sync-illustration.svg#blueFill"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<groupbox>
|
||||
<caption>
|
||||
<label control="fxaSyncComputerName">
|
||||
&fxaSyncDeviceName.label;
|
||||
</label>
|
||||
</caption>
|
||||
<hbox id="fxaDeviceName">
|
||||
<textbox id="fxaSyncComputerName" disabled="true"/>
|
||||
<hbox>
|
||||
<button id="fxaChangeDeviceName"
|
||||
label="&changeSyncDeviceName.label;"
|
||||
accesskey="&changeSyncDeviceName.accesskey;"/>
|
||||
<button id="fxaCancelChangeDeviceName"
|
||||
label="&cancelChangeSyncDeviceName.label;"
|
||||
accesskey="&cancelChangeSyncDeviceName.accesskey;"
|
||||
hidden="true"/>
|
||||
<button id="fxaSaveChangeDeviceName"
|
||||
label="&saveChangeSyncDeviceName.label;"
|
||||
accesskey="&saveChangeSyncDeviceName.accesskey;"
|
||||
hidden="true"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
<label class="fxaMobilePromo">
|
||||
&mobilePromo3.start;<!-- We put these comments to avoid inserting white spaces
|
||||
--><label class="androidLink text-link" id="fxaMobilePromo-android-hasFxaAccount"><!--
|
||||
-->&mobilePromo3.androidLink;</label><!--
|
||||
-->&mobilePromo3.iOSBefore;<!--
|
||||
--><label class="iOSLink text-link" id="fxaMobilePromo-ios-hasFxaAccount"><!--
|
||||
-->&mobilePromo3.iOSLink;</label><!--
|
||||
-->&mobilePromo3.end;
|
||||
</label>
|
||||
<vbox id="tosPP-small" align="start">
|
||||
<label id="tosPP-small-ToS" class="text-link">
|
||||
&prefs.tosLink.label;
|
||||
</label>
|
||||
<label id="tosPP-small-PP" class="text-link">
|
||||
&fxaPrivacyNotice.link.label;
|
||||
</label>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</deck>
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/browser-test"
|
||||
]
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
privacypane_tests_perwindow.js
|
||||
site_data_test.html
|
||||
|
||||
[browser_applications_selection.js]
|
||||
[browser_advanced_siteData.js]
|
||||
[browser_advanced_update.js]
|
||||
skip-if = !updater
|
||||
[browser_basic_rebuild_fonts_test.js]
|
||||
[browser_bug410900.js]
|
||||
[browser_bug705422.js]
|
||||
[browser_bug731866.js]
|
||||
[browser_bug795764_cachedisabled.js]
|
||||
[browser_bug1018066_resetScrollPosition.js]
|
||||
[browser_bug1020245_openPreferences_to_paneContent.js]
|
||||
[browser_bug1184989_prevent_scrolling_when_preferences_flipped.js]
|
||||
support-files =
|
||||
browser_bug1184989_prevent_scrolling_when_preferences_flipped.xul
|
||||
[browser_change_app_handler.js]
|
||||
skip-if = os != "win" # This test tests the windows-specific app selection dialog, so can't run on non-Windows
|
||||
[browser_connection.js]
|
||||
[browser_connection_bug388287.js]
|
||||
[browser_cookies_exceptions.js]
|
||||
[browser_defaultbrowser_alwayscheck.js]
|
||||
[browser_healthreport.js]
|
||||
skip-if = true || !healthreport # Bug 1185403 for the "true"
|
||||
[browser_homepages_filter_aboutpreferences.js]
|
||||
[browser_notifications_do_not_disturb.js]
|
||||
[browser_permissions_urlFieldHidden.js]
|
||||
[browser_proxy_backup.js]
|
||||
[browser_privacypane_1.js]
|
||||
[browser_privacypane_3.js]
|
||||
[browser_privacypane_4.js]
|
||||
[browser_privacypane_5.js]
|
||||
[browser_privacypane_8.js]
|
||||
[browser_sanitizeOnShutdown_prefLocked.js]
|
||||
[browser_searchsuggestions.js]
|
||||
[browser_security.js]
|
||||
[browser_subdialogs.js]
|
||||
support-files =
|
||||
subdialog.xul
|
||||
subdialog2.xul
|
||||
[browser_telemetry.js]
|
||||
# Skip this test on Android as FHR and Telemetry are separate systems there.
|
||||
skip-if = !healthreport || !telemetry || (os == 'linux' && debug) || (os == 'android')
|
|
@ -0,0 +1,649 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
/* import-globals-from ../../../../../testing/modules/sinon-1.16.1.js */
|
||||
Services.scriptloader.loadSubScript("resource://testing-common/sinon-1.16.1.js");
|
||||
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_ORIGIN = "http://" + TEST_HOST;
|
||||
const TEST_BASE_URL = TEST_ORIGIN + "/browser/browser/components/preferences/in-content-old/tests/";
|
||||
const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
|
||||
|
||||
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
|
||||
const { SiteDataManager } = Cu.import("resource:///modules/SiteDataManager.jsm", {});
|
||||
const { OfflineAppCacheHelper } = Cu.import("resource:///modules/offlineAppCache.jsm", {});
|
||||
|
||||
const mockOfflineAppCacheHelper = {
|
||||
clear: null,
|
||||
|
||||
originalClear: null,
|
||||
|
||||
register() {
|
||||
this.originalClear = OfflineAppCacheHelper.clear;
|
||||
this.clear = sinon.spy();
|
||||
OfflineAppCacheHelper.clear = this.clear;
|
||||
},
|
||||
|
||||
unregister() {
|
||||
OfflineAppCacheHelper.clear = this.originalClear;
|
||||
}
|
||||
};
|
||||
|
||||
const mockSiteDataManager = {
|
||||
sites: new Map([
|
||||
[
|
||||
"https://account.xyz.com/",
|
||||
{
|
||||
usage: 1024 * 200,
|
||||
host: "account.xyz.com",
|
||||
status: Ci.nsIPermissionManager.ALLOW_ACTION
|
||||
}
|
||||
],
|
||||
[
|
||||
"https://shopping.xyz.com/",
|
||||
{
|
||||
usage: 1024 * 100,
|
||||
host: "shopping.xyz.com",
|
||||
status: Ci.nsIPermissionManager.DENY_ACTION
|
||||
}
|
||||
],
|
||||
[
|
||||
"https://video.bar.com/",
|
||||
{
|
||||
usage: 1024 * 20,
|
||||
host: "video.bar.com",
|
||||
status: Ci.nsIPermissionManager.ALLOW_ACTION
|
||||
}
|
||||
],
|
||||
[
|
||||
"https://music.bar.com/",
|
||||
{
|
||||
usage: 1024 * 10,
|
||||
host: "music.bar.com",
|
||||
status: Ci.nsIPermissionManager.DENY_ACTION
|
||||
}
|
||||
],
|
||||
[
|
||||
"https://books.foo.com/",
|
||||
{
|
||||
usage: 1024 * 2,
|
||||
host: "books.foo.com",
|
||||
status: Ci.nsIPermissionManager.ALLOW_ACTION
|
||||
}
|
||||
],
|
||||
[
|
||||
"https://news.foo.com/",
|
||||
{
|
||||
usage: 1024,
|
||||
host: "news.foo.com",
|
||||
status: Ci.nsIPermissionManager.DENY_ACTION
|
||||
}
|
||||
]
|
||||
]),
|
||||
|
||||
_originalGetSites: null,
|
||||
|
||||
getSites() {
|
||||
let list = [];
|
||||
this.sites.forEach((data, origin) => {
|
||||
list.push({
|
||||
usage: data.usage,
|
||||
status: data.status,
|
||||
uri: NetUtil.newURI(origin)
|
||||
});
|
||||
});
|
||||
return Promise.resolve(list);
|
||||
},
|
||||
|
||||
register() {
|
||||
this._originalGetSites = SiteDataManager.getSites;
|
||||
SiteDataManager.getSites = this.getSites.bind(this);
|
||||
},
|
||||
|
||||
unregister() {
|
||||
SiteDataManager.getSites = this._originalGetSites;
|
||||
}
|
||||
};
|
||||
|
||||
function addPersistentStoragePerm(origin) {
|
||||
let uri = NetUtil.newURI(origin);
|
||||
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
Services.perms.addFromPrincipal(principal, "persistent-storage", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
|
||||
function removePersistentStoragePerm(origin) {
|
||||
let uri = NetUtil.newURI(origin);
|
||||
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
Services.perms.removeFromPrincipal(principal, "persistent-storage");
|
||||
}
|
||||
|
||||
function getPersistentStoragePermStatus(origin) {
|
||||
let uri = NetUtil.newURI(origin);
|
||||
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
return Services.perms.testExactPermissionFromPrincipal(principal, "persistent-storage");
|
||||
}
|
||||
|
||||
function getQuotaUsage(origin) {
|
||||
return new Promise(resolve => {
|
||||
let uri = NetUtil.newURI(origin);
|
||||
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
Services.qms.getUsageForPrincipal(principal, request => resolve(request.result.usage));
|
||||
});
|
||||
}
|
||||
|
||||
// XXX: The intermittent bug 1331851
|
||||
// The implementation of nsICacheStorageConsumptionObserver must be passed as weak referenced,
|
||||
// so we must hold this observer here well. If we didn't, there would be a chance that
|
||||
// in Linux debug test run the observer was released before the operation at gecko was completed
|
||||
// (may be because of a relatively quicker GC cycle or a relatively slower operation).
|
||||
// As a result of that, we would never get the cache usage we want so the test would fail from timeout.
|
||||
const cacheUsageGetter = {
|
||||
_promise: null,
|
||||
_resolve: null,
|
||||
get() {
|
||||
if (!this._promise) {
|
||||
this._promise = new Promise(resolve => {
|
||||
this._resolve = resolve;
|
||||
Services.cache2.asyncGetDiskConsumption(this);
|
||||
});
|
||||
}
|
||||
return this._promise;
|
||||
},
|
||||
// nsICacheStorageConsumptionObserver implementations
|
||||
onNetworkCacheDiskConsumption(usage) {
|
||||
cacheUsageGetter._promise = null;
|
||||
cacheUsageGetter._resolve(usage);
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Components.interfaces.nsICacheStorageConsumptionObserver,
|
||||
Components.interfaces.nsISupportsWeakReference
|
||||
]),
|
||||
};
|
||||
|
||||
function openSettingsDialog() {
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let settingsBtn = doc.getElementById("siteDataSettings");
|
||||
let dialogOverlay = doc.getElementById("dialogOverlay");
|
||||
let dialogLoadPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
|
||||
let dialogInitPromise = TestUtils.topicObserved("sitedata-settings-init", () => true);
|
||||
let fullyLoadPromise = Promise.all([ dialogLoadPromise, dialogInitPromise ]).then(() => {
|
||||
is(dialogOverlay.style.visibility, "visible", "The Settings dialog should be visible");
|
||||
});
|
||||
settingsBtn.doCommand();
|
||||
return fullyLoadPromise;
|
||||
}
|
||||
|
||||
function promiseSettingsDialogClose() {
|
||||
return new Promise(resolve => {
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let dialogOverlay = doc.getElementById("dialogOverlay");
|
||||
let win = content.gSubDialog._frame.contentWindow;
|
||||
win.addEventListener("unload", function unload() {
|
||||
if (win.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
|
||||
isnot(dialogOverlay.style.visibility, "visible", "The Settings dialog should be hidden");
|
||||
resolve();
|
||||
}
|
||||
}, { once: true });
|
||||
});
|
||||
}
|
||||
|
||||
function promiseSitesUpdated() {
|
||||
return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true);
|
||||
}
|
||||
|
||||
function promiseCookiesCleared() {
|
||||
return TestUtils.topicObserved("cookie-changed", (subj, data) => {
|
||||
return data === "cleared";
|
||||
});
|
||||
}
|
||||
|
||||
function assertSitesListed(doc, origins) {
|
||||
let frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
let removeBtn = frameDoc.getElementById("removeSelected");
|
||||
let removeAllBtn = frameDoc.getElementById("removeAll");
|
||||
let sitesList = frameDoc.getElementById("sitesList");
|
||||
let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
|
||||
is(totalSitesNumber, origins.length, "Should list the right sites number");
|
||||
origins.forEach(origin => {
|
||||
let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
|
||||
let host = site.getAttribute("host");
|
||||
ok(origin.includes(host), `Should list the site of ${origin}`);
|
||||
});
|
||||
is(removeBtn.disabled, false, "Should enable the removeSelected button");
|
||||
is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
delete window.sinon;
|
||||
delete window.setImmediate;
|
||||
delete window.clearImmediate;
|
||||
mockOfflineAppCacheHelper.unregister();
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
|
||||
addPersistentStoragePerm(TEST_ORIGIN);
|
||||
|
||||
yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_BASE_URL + "site_data_test.html");
|
||||
yield waitForEvent(gBrowser.selectedBrowser.contentWindow, "test-indexedDB-done");
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
|
||||
|
||||
// Test the initial states
|
||||
let cacheUsage = yield cacheUsageGetter.get();
|
||||
let quotaUsage = yield getQuotaUsage(TEST_ORIGIN);
|
||||
let totalUsage = yield SiteDataManager.getTotalUsage();
|
||||
Assert.greater(cacheUsage, 0, "The cache usage should not be 0");
|
||||
Assert.greater(quotaUsage, 0, "The quota usage should not be 0");
|
||||
Assert.greater(totalUsage, 0, "The total usage should not be 0");
|
||||
|
||||
// Test cancelling "Clear All Data"
|
||||
// Click "Clear All Data" button and then cancel
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let cancelPromise = promiseAlertDialogOpen("cancel");
|
||||
let clearBtn = doc.getElementById("clearSiteDataButton");
|
||||
clearBtn.doCommand();
|
||||
yield cancelPromise;
|
||||
|
||||
// Test the items are not removed
|
||||
let status = getPersistentStoragePermStatus(TEST_ORIGIN);
|
||||
is(status, Ci.nsIPermissionManager.ALLOW_ACTION, "Should not remove permission");
|
||||
|
||||
cacheUsage = yield cacheUsageGetter.get();
|
||||
quotaUsage = yield getQuotaUsage(TEST_ORIGIN);
|
||||
totalUsage = yield SiteDataManager.getTotalUsage();
|
||||
Assert.greater(cacheUsage, 0, "The cache usage should not be 0");
|
||||
Assert.greater(quotaUsage, 0, "The quota usage should not be 0");
|
||||
Assert.greater(totalUsage, 0, "The total usage should not be 0");
|
||||
// Test cancelling "Clear All Data" ends
|
||||
|
||||
// Test accepting "Clear All Data"
|
||||
// Click "Clear All Data" button and then accept
|
||||
let acceptPromise = promiseAlertDialogOpen("accept");
|
||||
let updatePromise = promiseSitesUpdated();
|
||||
let cookiesClearedPromise = promiseCookiesCleared();
|
||||
|
||||
mockOfflineAppCacheHelper.register();
|
||||
clearBtn.doCommand();
|
||||
yield acceptPromise;
|
||||
yield updatePromise;
|
||||
mockOfflineAppCacheHelper.unregister();
|
||||
|
||||
// Test all the items are removed
|
||||
yield cookiesClearedPromise;
|
||||
|
||||
ok(mockOfflineAppCacheHelper.clear.calledOnce, "Should clear app cache");
|
||||
|
||||
status = getPersistentStoragePermStatus(TEST_ORIGIN);
|
||||
is(status, Ci.nsIPermissionManager.UNKNOWN_ACTION, "Should remove permission");
|
||||
|
||||
cacheUsage = yield cacheUsageGetter.get();
|
||||
quotaUsage = yield getQuotaUsage(TEST_ORIGIN);
|
||||
totalUsage = yield SiteDataManager.getTotalUsage();
|
||||
is(cacheUsage, 0, "The cahce usage should be removed");
|
||||
is(quotaUsage, 0, "The quota usage should be removed");
|
||||
is(totalUsage, 0, "The total usage should be removed");
|
||||
// Test accepting "Clear All Data" ends
|
||||
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
|
||||
|
||||
mockSiteDataManager.register();
|
||||
let updatePromise = promiseSitesUpdated();
|
||||
yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
|
||||
yield updatePromise;
|
||||
yield openSettingsDialog();
|
||||
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let dialogFrame = doc.getElementById("dialogFrame");
|
||||
let frameDoc = dialogFrame.contentDocument;
|
||||
let hostCol = frameDoc.getElementById("hostCol");
|
||||
let usageCol = frameDoc.getElementById("usageCol");
|
||||
let statusCol = frameDoc.getElementById("statusCol");
|
||||
let sitesList = frameDoc.getElementById("sitesList");
|
||||
let mockSites = mockSiteDataManager.sites;
|
||||
|
||||
// Test default sorting
|
||||
assertSortByHost("ascending");
|
||||
|
||||
// Test sorting on the host column
|
||||
hostCol.click();
|
||||
assertSortByHost("descending");
|
||||
hostCol.click();
|
||||
assertSortByHost("ascending");
|
||||
|
||||
// Test sorting on the permission status column
|
||||
statusCol.click();
|
||||
assertSortByStatus("ascending");
|
||||
statusCol.click();
|
||||
assertSortByStatus("descending");
|
||||
|
||||
// Test sorting on the usage column
|
||||
usageCol.click();
|
||||
assertSortByUsage("ascending");
|
||||
usageCol.click();
|
||||
assertSortByUsage("descending");
|
||||
|
||||
mockSiteDataManager.unregister();
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
function assertSortByHost(order) {
|
||||
let siteItems = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = 0; i < siteItems.length - 1; ++i) {
|
||||
let aOrigin = siteItems[i].getAttribute("data-origin");
|
||||
let bOrigin = siteItems[i + 1].getAttribute("data-origin");
|
||||
let a = mockSites.get(aOrigin);
|
||||
let b = mockSites.get(bOrigin);
|
||||
let result = a.host.localeCompare(b.host);
|
||||
if (order == "ascending") {
|
||||
Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by host");
|
||||
} else {
|
||||
Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by host");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertSortByStatus(order) {
|
||||
let siteItems = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = 0; i < siteItems.length - 1; ++i) {
|
||||
let aOrigin = siteItems[i].getAttribute("data-origin");
|
||||
let bOrigin = siteItems[i + 1].getAttribute("data-origin");
|
||||
let a = mockSites.get(aOrigin);
|
||||
let b = mockSites.get(bOrigin);
|
||||
let result = a.status - b.status;
|
||||
if (order == "ascending") {
|
||||
Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by permission status");
|
||||
} else {
|
||||
Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by permission status");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertSortByUsage(order) {
|
||||
let siteItems = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = 0; i < siteItems.length - 1; ++i) {
|
||||
let aOrigin = siteItems[i].getAttribute("data-origin");
|
||||
let bOrigin = siteItems[i + 1].getAttribute("data-origin");
|
||||
let a = mockSites.get(aOrigin);
|
||||
let b = mockSites.get(bOrigin);
|
||||
let result = a.usage - b.usage;
|
||||
if (order == "ascending") {
|
||||
Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by usage");
|
||||
} else {
|
||||
Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by usage");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
|
||||
|
||||
mockSiteDataManager.register();
|
||||
let updatePromise = promiseSitesUpdated();
|
||||
yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
|
||||
yield updatePromise;
|
||||
yield openSettingsDialog();
|
||||
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
let searchBox = frameDoc.getElementById("searchBox");
|
||||
let mockOrigins = Array.from(mockSiteDataManager.sites.keys());
|
||||
|
||||
searchBox.value = "xyz";
|
||||
searchBox.doCommand();
|
||||
assertSitesListed(doc, mockOrigins.filter(o => o.includes("xyz")));
|
||||
|
||||
searchBox.value = "bar";
|
||||
searchBox.doCommand();
|
||||
assertSitesListed(doc, mockOrigins.filter(o => o.includes("bar")));
|
||||
|
||||
searchBox.value = "";
|
||||
searchBox.doCommand();
|
||||
assertSitesListed(doc, mockOrigins);
|
||||
|
||||
mockSiteDataManager.unregister();
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
// Test selecting and removing all sites one by one
|
||||
add_task(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
|
||||
let fakeOrigins = [
|
||||
"https://news.foo.com/",
|
||||
"https://mails.bar.com/",
|
||||
"https://videos.xyz.com/",
|
||||
"https://books.foo.com/",
|
||||
"https://account.bar.com/",
|
||||
"https://shopping.xyz.com/"
|
||||
];
|
||||
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
|
||||
|
||||
let updatePromise = promiseSitesUpdated();
|
||||
yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
|
||||
yield updatePromise;
|
||||
yield openSettingsDialog();
|
||||
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let frameDoc = null;
|
||||
let saveBtn = null;
|
||||
let cancelBtn = null;
|
||||
let settingsDialogClosePromise = null;
|
||||
|
||||
// Test the initial state
|
||||
assertAllSitesListed();
|
||||
|
||||
// Test the "Cancel" button
|
||||
settingsDialogClosePromise = promiseSettingsDialogClose();
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
cancelBtn = frameDoc.getElementById("cancel");
|
||||
removeAllSitesOneByOne();
|
||||
assertAllSitesNotListed();
|
||||
cancelBtn.doCommand();
|
||||
yield settingsDialogClosePromise;
|
||||
yield openSettingsDialog();
|
||||
assertAllSitesListed();
|
||||
|
||||
// Test the "Save Changes" button but cancelling save
|
||||
let cancelPromise = promiseAlertDialogOpen("cancel");
|
||||
settingsDialogClosePromise = promiseSettingsDialogClose();
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
saveBtn = frameDoc.getElementById("save");
|
||||
removeAllSitesOneByOne();
|
||||
assertAllSitesNotListed();
|
||||
saveBtn.doCommand();
|
||||
yield cancelPromise;
|
||||
yield settingsDialogClosePromise;
|
||||
yield openSettingsDialog();
|
||||
assertAllSitesListed();
|
||||
|
||||
// Test the "Save Changes" button and accepting save
|
||||
let acceptPromise = promiseAlertDialogOpen("accept");
|
||||
settingsDialogClosePromise = promiseSettingsDialogClose();
|
||||
updatePromise = promiseSitesUpdated();
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
saveBtn = frameDoc.getElementById("save");
|
||||
removeAllSitesOneByOne();
|
||||
assertAllSitesNotListed();
|
||||
saveBtn.doCommand();
|
||||
yield acceptPromise;
|
||||
yield settingsDialogClosePromise;
|
||||
yield updatePromise;
|
||||
yield openSettingsDialog();
|
||||
assertAllSitesNotListed();
|
||||
|
||||
// Always clean up the fake origins
|
||||
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
function removeAllSitesOneByOne() {
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
let removeBtn = frameDoc.getElementById("removeSelected");
|
||||
let sitesList = frameDoc.getElementById("sitesList");
|
||||
let sites = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = sites.length - 1; i >= 0; --i) {
|
||||
sites[i].click();
|
||||
removeBtn.doCommand();
|
||||
}
|
||||
}
|
||||
|
||||
function assertAllSitesListed() {
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
let removeBtn = frameDoc.getElementById("removeSelected");
|
||||
let removeAllBtn = frameDoc.getElementById("removeAll");
|
||||
let sitesList = frameDoc.getElementById("sitesList");
|
||||
let sites = sitesList.getElementsByTagName("richlistitem");
|
||||
is(sites.length, fakeOrigins.length, "Should list all sites");
|
||||
is(removeBtn.disabled, false, "Should enable the removeSelected button");
|
||||
is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
|
||||
}
|
||||
|
||||
function assertAllSitesNotListed() {
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
let removeBtn = frameDoc.getElementById("removeSelected");
|
||||
let removeAllBtn = frameDoc.getElementById("removeAll");
|
||||
let sitesList = frameDoc.getElementById("sitesList");
|
||||
let sites = sitesList.getElementsByTagName("richlistitem");
|
||||
is(sites.length, 0, "Should not list all sites");
|
||||
is(removeBtn.disabled, true, "Should disable the removeSelected button");
|
||||
is(removeAllBtn.disabled, true, "Should disable the removeAllBtn button");
|
||||
}
|
||||
});
|
||||
|
||||
// Test selecting and removing partial sites
|
||||
add_task(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
|
||||
let fakeOrigins = [
|
||||
"https://news.foo.com/",
|
||||
"https://mails.bar.com/",
|
||||
"https://videos.xyz.com/",
|
||||
"https://books.foo.com/",
|
||||
"https://account.bar.com/",
|
||||
"https://shopping.xyz.com/"
|
||||
];
|
||||
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
|
||||
|
||||
let updatePromise = promiseSitesUpdated();
|
||||
yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
|
||||
yield updatePromise;
|
||||
yield openSettingsDialog();
|
||||
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let frameDoc = null;
|
||||
let saveBtn = null;
|
||||
let cancelBtn = null;
|
||||
let removeDialogOpenPromise = null;
|
||||
let settingsDialogClosePromise = null;
|
||||
|
||||
// Test the initial state
|
||||
assertSitesListed(doc, fakeOrigins);
|
||||
|
||||
// Test the "Cancel" button
|
||||
settingsDialogClosePromise = promiseSettingsDialogClose();
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
cancelBtn = frameDoc.getElementById("cancel");
|
||||
removeSelectedSite(fakeOrigins.slice(0, 4));
|
||||
assertSitesListed(doc, fakeOrigins.slice(4));
|
||||
cancelBtn.doCommand();
|
||||
yield settingsDialogClosePromise;
|
||||
yield openSettingsDialog();
|
||||
assertSitesListed(doc, fakeOrigins);
|
||||
|
||||
// Test the "Save Changes" button but canceling save
|
||||
removeDialogOpenPromise = promiseWindowDialogOpen("cancel", REMOVE_DIALOG_URL);
|
||||
settingsDialogClosePromise = promiseSettingsDialogClose();
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
saveBtn = frameDoc.getElementById("save");
|
||||
removeSelectedSite(fakeOrigins.slice(0, 4));
|
||||
assertSitesListed(doc, fakeOrigins.slice(4));
|
||||
saveBtn.doCommand();
|
||||
yield removeDialogOpenPromise;
|
||||
yield settingsDialogClosePromise;
|
||||
yield openSettingsDialog();
|
||||
assertSitesListed(doc, fakeOrigins);
|
||||
|
||||
// Test the "Save Changes" button and accepting save
|
||||
removeDialogOpenPromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
|
||||
settingsDialogClosePromise = promiseSettingsDialogClose();
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
saveBtn = frameDoc.getElementById("save");
|
||||
removeSelectedSite(fakeOrigins.slice(0, 4));
|
||||
assertSitesListed(doc, fakeOrigins.slice(4));
|
||||
saveBtn.doCommand();
|
||||
yield removeDialogOpenPromise;
|
||||
yield settingsDialogClosePromise;
|
||||
yield openSettingsDialog();
|
||||
assertSitesListed(doc, fakeOrigins.slice(4));
|
||||
|
||||
// Always clean up the fake origins
|
||||
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
function removeSelectedSite(origins) {
|
||||
frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
let removeBtn = frameDoc.getElementById("removeSelected");
|
||||
let sitesList = frameDoc.getElementById("sitesList");
|
||||
origins.forEach(origin => {
|
||||
let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
|
||||
if (site) {
|
||||
site.click();
|
||||
removeBtn.doCommand();
|
||||
} else {
|
||||
ok(false, `Should not select and remove inexisted site of ${origin}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
|
||||
let fakeOrigins = [
|
||||
"https://news.foo.com/",
|
||||
"https://books.foo.com/",
|
||||
"https://mails.bar.com/",
|
||||
"https://account.bar.com/",
|
||||
"https://videos.xyz.com/",
|
||||
"https://shopping.xyz.com/"
|
||||
];
|
||||
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
|
||||
|
||||
let updatePromise = promiseSitesUpdated();
|
||||
yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
|
||||
yield updatePromise;
|
||||
yield openSettingsDialog();
|
||||
|
||||
// Search "foo" to only list foo.com sites
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let frameDoc = doc.getElementById("dialogFrame").contentDocument;
|
||||
let searchBox = frameDoc.getElementById("searchBox");
|
||||
searchBox.value = "foo";
|
||||
searchBox.doCommand();
|
||||
assertSitesListed(doc, fakeOrigins.slice(0, 2));
|
||||
|
||||
// Test only removing all visible sites listed
|
||||
updatePromise = promiseSitesUpdated();
|
||||
let acceptRemovePromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
|
||||
let settingsDialogClosePromise = promiseSettingsDialogClose();
|
||||
let removeAllBtn = frameDoc.getElementById("removeAll");
|
||||
let saveBtn = frameDoc.getElementById("save");
|
||||
removeAllBtn.doCommand();
|
||||
saveBtn.doCommand();
|
||||
yield acceptRemovePromise;
|
||||
yield settingsDialogClosePromise;
|
||||
yield updatePromise;
|
||||
yield openSettingsDialog();
|
||||
assertSitesListed(doc, fakeOrigins.slice(2));
|
||||
|
||||
// Always clean up the fake origins
|
||||
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
|
@ -0,0 +1,155 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
|
||||
const mockUpdateManager = {
|
||||
contractId: "@mozilla.org/updates/update-manager;1",
|
||||
|
||||
_mockClassId: uuidGenerator.generateUUID(),
|
||||
|
||||
_originalClassId: "",
|
||||
|
||||
_originalFactory: null,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateManager]),
|
||||
|
||||
createInstance(outer, iiD) {
|
||||
if (outer) {
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
return this.QueryInterface(iiD);
|
||||
},
|
||||
|
||||
register() {
|
||||
let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
if (!registrar.isCIDRegistered(this._mockClassId)) {
|
||||
this._originalClassId = registrar.contractIDToCID(this.contractId);
|
||||
this._originalFactory = Cm.getClassObject(Cc[this.contractId], Ci.nsIFactory);
|
||||
registrar.unregisterFactory(this._originalClassId, this._originalFactory);
|
||||
registrar.registerFactory(this._mockClassId, "Unregister after testing", this.contractId, this);
|
||||
}
|
||||
},
|
||||
|
||||
unregister() {
|
||||
let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.unregisterFactory(this._mockClassId, this);
|
||||
registrar.registerFactory(this._originalClassId, "", this.contractId, this._originalFactory);
|
||||
},
|
||||
|
||||
get updateCount() {
|
||||
return this._updates.length;
|
||||
},
|
||||
|
||||
getUpdateAt(index) {
|
||||
return this._updates[index];
|
||||
},
|
||||
|
||||
_updates: [
|
||||
{
|
||||
name: "Firefox Developer Edition 49.0a2",
|
||||
statusText: "The Update was successfully installed",
|
||||
buildID: "20160728004010",
|
||||
type: "minor",
|
||||
installDate: 1469763105156,
|
||||
detailsURL: "https://www.mozilla.org/firefox/aurora/"
|
||||
},
|
||||
{
|
||||
name: "Firefox Developer Edition 43.0a2",
|
||||
statusText: "The Update was successfully installed",
|
||||
buildID: "20150929004011",
|
||||
type: "minor",
|
||||
installDate: 1443585886224,
|
||||
detailsURL: "https://www.mozilla.org/firefox/aurora/"
|
||||
},
|
||||
{
|
||||
name: "Firefox Developer Edition 42.0a2",
|
||||
statusText: "The Update was successfully installed",
|
||||
buildID: "20150920004018",
|
||||
type: "major",
|
||||
installDate: 1442818147544,
|
||||
detailsURL: "https://www.mozilla.org/firefox/aurora/"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
function resetPreferences() {
|
||||
Services.prefs.clearUserPref("browser.search.update");
|
||||
}
|
||||
|
||||
function formatInstallDate(sec) {
|
||||
var date = new Date(sec);
|
||||
const dtOptions = { year: "numeric", month: "long", day: "numeric",
|
||||
hour: "numeric", minute: "numeric", second: "numeric" };
|
||||
return date.toLocaleString(undefined, dtOptions);
|
||||
}
|
||||
|
||||
registerCleanupFunction(resetPreferences);
|
||||
|
||||
add_task(function*() {
|
||||
yield openPreferencesViaOpenPreferencesAPI("advanced", "updateTab", { leaveOpen: true });
|
||||
resetPreferences();
|
||||
Services.prefs.setBoolPref("browser.search.update", false);
|
||||
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let enableSearchUpdate = doc.getElementById("enableSearchUpdate");
|
||||
is_element_visible(enableSearchUpdate, "Check search update preference is visible");
|
||||
|
||||
// Ensure that the update pref dialog reflects the actual pref value.
|
||||
ok(!enableSearchUpdate.checked, "Ensure search updates are disabled");
|
||||
Services.prefs.setBoolPref("browser.search.update", true);
|
||||
ok(enableSearchUpdate.checked, "Ensure search updates are enabled");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
mockUpdateManager.register();
|
||||
|
||||
yield openPreferencesViaOpenPreferencesAPI("advanced", "updateTab", { leaveOpen: true });
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
|
||||
let showBtn = doc.getElementById("showUpdateHistory");
|
||||
let dialogOverlay = doc.getElementById("dialogOverlay");
|
||||
|
||||
// Test the dialog window opens
|
||||
is(dialogOverlay.style.visibility, "", "The dialog should be invisible");
|
||||
showBtn.doCommand();
|
||||
yield promiseLoadSubDialog("chrome://mozapps/content/update/history.xul");
|
||||
is(dialogOverlay.style.visibility, "visible", "The dialog should be visible");
|
||||
|
||||
let dialogFrame = doc.getElementById("dialogFrame");
|
||||
let frameDoc = dialogFrame.contentDocument;
|
||||
let updates = frameDoc.querySelectorAll("update");
|
||||
|
||||
// Test the update history numbers are correct
|
||||
is(updates.length, mockUpdateManager.updateCount, "The update count is incorrect.");
|
||||
|
||||
// Test the updates are displayed correctly
|
||||
let update = null;
|
||||
let updateData = null;
|
||||
for (let i = 0; i < updates.length; ++i) {
|
||||
update = updates[i];
|
||||
updateData = mockUpdateManager.getUpdateAt(i);
|
||||
|
||||
is(update.name, updateData.name + " (" + updateData.buildID + ")", "Wrong update name");
|
||||
is(update.type, updateData.type == "major" ? "New Version" : "Security Update", "Wrong update type");
|
||||
is(update.installDate, formatInstallDate(updateData.installDate), "Wrong update installDate");
|
||||
is(update.detailsURL, updateData.detailsURL, "Wrong update detailsURL");
|
||||
is(update.status, updateData.statusText, "Wrong update status");
|
||||
}
|
||||
|
||||
// Test the dialog window closes
|
||||
let closeBtn = doc.getElementById("dialogClose");
|
||||
closeBtn.doCommand();
|
||||
is(dialogOverlay.style.visibility, "", "The dialog should be invisible");
|
||||
|
||||
mockUpdateManager.unregister();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
|
@ -0,0 +1,79 @@
|
|||
var win;
|
||||
var feedItem;
|
||||
var container;
|
||||
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
add_task(function* setup() {
|
||||
yield openPreferencesViaOpenPreferencesAPI("applications", null, {leaveOpen: true});
|
||||
info("Preferences page opened on the applications pane.");
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* getFeedItem() {
|
||||
win = gBrowser.selectedBrowser.contentWindow;
|
||||
|
||||
container = win.document.getElementById("handlersView");
|
||||
feedItem = container.querySelector("richlistitem[type='application/vnd.mozilla.maybe.feed']");
|
||||
Assert.ok(feedItem, "feedItem is present in handlersView.");
|
||||
})
|
||||
|
||||
add_task(function* selectInternalOptionForFeed() {
|
||||
// Select the item.
|
||||
feedItem.scrollIntoView();
|
||||
container.selectItem(feedItem);
|
||||
Assert.ok(feedItem.selected, "Should be able to select our item.");
|
||||
|
||||
// Wait for the menu.
|
||||
let list = yield waitForCondition(() =>
|
||||
win.document.getAnonymousElementByAttribute(feedItem, "class", "actionsMenu"));
|
||||
info("Got list after item was selected");
|
||||
|
||||
// Find the "Add Live bookmarks option".
|
||||
let chooseItems = list.getElementsByAttribute("action", Ci.nsIHandlerInfo.handleInternally);
|
||||
Assert.equal(chooseItems.length, 1, "Should only be one action to handle internally");
|
||||
|
||||
// Select the option.
|
||||
let cmdEvent = win.document.createEvent("xulcommandevent");
|
||||
cmdEvent.initCommandEvent("command", true, true, win, 0, false, false, false, false, null);
|
||||
chooseItems[0].dispatchEvent(cmdEvent);
|
||||
|
||||
// Check that we display the correct result.
|
||||
list = yield waitForCondition(() =>
|
||||
win.document.getAnonymousElementByAttribute(feedItem, "class", "actionsMenu"));
|
||||
info("Got list after item was selected");
|
||||
Assert.ok(list.selectedItem, "Should have a selected item.");
|
||||
Assert.equal(list.selectedItem.getAttribute("action"),
|
||||
Ci.nsIHandlerInfo.handleInternally,
|
||||
"Newly selected item should be the expected one.");
|
||||
});
|
||||
|
||||
// This builds on the previous selectInternalOptionForFeed task.
|
||||
add_task(function* reselectInternalOptionForFeed() {
|
||||
// Now select a different option in the list - use the pdf item as that doesn't
|
||||
// need to load any favicons.
|
||||
let anotherItem = container.querySelector("richlistitem[type='application/pdf']");
|
||||
|
||||
container.selectItem(anotherItem);
|
||||
|
||||
// Wait for the menu so that we don't hit race conditions.
|
||||
yield waitForCondition(() =>
|
||||
win.document.getAnonymousElementByAttribute(anotherItem, "class", "actionsMenu"));
|
||||
info("Got list after item was selected");
|
||||
|
||||
// Now select the feed item again, and check what it is displaying.
|
||||
container.selectItem(feedItem);
|
||||
|
||||
let list = yield waitForCondition(() =>
|
||||
win.document.getAnonymousElementByAttribute(feedItem, "class", "actionsMenu"));
|
||||
info("Got list after item was selected");
|
||||
|
||||
Assert.ok(list.selectedItem,
|
||||
"Should have a selected item");
|
||||
Assert.equal(list.selectedItem.getAttribute("action"),
|
||||
Ci.nsIHandlerInfo.handleInternally,
|
||||
"Selected item should still be the same as the previously selected item.");
|
||||
});
|
|
@ -0,0 +1,76 @@
|
|||
Services.prefs.setBoolPref("browser.preferences.instantApply", true);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("browser.preferences.instantApply");
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
yield openPreferencesViaOpenPreferencesAPI("paneContent", null, {leaveOpen: true});
|
||||
let doc = gBrowser.contentDocument;
|
||||
var langGroup = Services.prefs.getComplexValue("font.language.group", Ci.nsIPrefLocalizedString).data
|
||||
is(doc.getElementById("font.language.group").value, langGroup,
|
||||
"Language group should be set correctly.");
|
||||
|
||||
let defaultFontType = Services.prefs.getCharPref("font.default." + langGroup);
|
||||
let fontFamily = Services.prefs.getCharPref("font.name." + defaultFontType + "." + langGroup);
|
||||
let fontFamilyField = doc.getElementById("defaultFont");
|
||||
is(fontFamilyField.value, fontFamily, "Font family should be set correctly.");
|
||||
|
||||
let defaultFontSize = Services.prefs.getIntPref("font.size.variable." + langGroup);
|
||||
let fontSizeField = doc.getElementById("defaultFontSize");
|
||||
is(fontSizeField.value, defaultFontSize, "Font size should be set correctly.");
|
||||
|
||||
doc.getElementById("advancedFonts").click();
|
||||
let win = yield promiseLoadSubDialog("chrome://browser/content/preferences/fonts.xul");
|
||||
doc = win.document;
|
||||
|
||||
// Simulate a dumb font backend.
|
||||
win.FontBuilder._enumerator = {
|
||||
_list: ["MockedFont1", "MockedFont2", "MockedFont3"],
|
||||
EnumerateFonts(lang, type, list) {
|
||||
return this._list;
|
||||
},
|
||||
EnumerateAllFonts() {
|
||||
return this._list;
|
||||
},
|
||||
getDefaultFont() { return null; },
|
||||
getStandardFamilyName(name) { return name; },
|
||||
};
|
||||
win.FontBuilder._allFonts = null;
|
||||
win.FontBuilder._langGroupSupported = false;
|
||||
|
||||
let langGroupElement = doc.getElementById("font.language.group");
|
||||
let selectLangsField = doc.getElementById("selectLangs");
|
||||
let serifField = doc.getElementById("serif");
|
||||
let armenian = "x-armn";
|
||||
let western = "x-western";
|
||||
|
||||
langGroupElement.value = armenian;
|
||||
selectLangsField.value = armenian;
|
||||
is(serifField.value, "", "Font family should not be set.");
|
||||
|
||||
langGroupElement.value = western;
|
||||
selectLangsField.value = western;
|
||||
|
||||
// Simulate a font backend supporting language-specific enumeration.
|
||||
// NB: FontBuilder has cached the return value from EnumerateAllFonts(),
|
||||
// so _allFonts will always have 3 elements regardless of subsequent
|
||||
// _list changes.
|
||||
win.FontBuilder._enumerator._list = ["MockedFont2"];
|
||||
|
||||
langGroupElement.value = armenian;
|
||||
selectLangsField.value = armenian;
|
||||
is(serifField.value, "MockedFont2", "Font family should be set.");
|
||||
|
||||
langGroupElement.value = western;
|
||||
selectLangsField.value = western;
|
||||
|
||||
// Simulate a system that has no fonts for the specified language.
|
||||
win.FontBuilder._enumerator._list = [];
|
||||
|
||||
langGroupElement.value = armenian;
|
||||
selectLangsField.value = armenian;
|
||||
is(serifField.value, "", "Font family should not be set.");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var originalWindowHeight;
|
||||
registerCleanupFunction(function() {
|
||||
window.resizeTo(window.outerWidth, originalWindowHeight);
|
||||
while (gBrowser.tabs[1])
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
originalWindowHeight = window.outerHeight;
|
||||
window.resizeTo(window.outerWidth, 300);
|
||||
let prefs = yield openPreferencesViaOpenPreferencesAPI("paneApplications", undefined, {leaveOpen: true});
|
||||
is(prefs.selectedPane, "paneApplications", "Applications pane was selected");
|
||||
let mainContent = gBrowser.contentDocument.querySelector(".main-content");
|
||||
mainContent.scrollTop = 50;
|
||||
is(mainContent.scrollTop, 50, "main-content should be scrolled 50 pixels");
|
||||
|
||||
gBrowser.contentWindow.gotoPref("paneGeneral");
|
||||
is(mainContent.scrollTop, 0,
|
||||
"Switching to a different category should reset the scroll position");
|
||||
});
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Services.prefs.setBoolPref("browser.preferences.instantApply", true);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("browser.preferences.instantApply");
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
let prefs = yield openPreferencesViaOpenPreferencesAPI("paneContent");
|
||||
is(prefs.selectedPane, "paneContent", "Content pane was selected");
|
||||
prefs = yield openPreferencesViaOpenPreferencesAPI("advanced", "updateTab");
|
||||
is(prefs.selectedPane, "paneAdvanced", "Advanced pane was selected");
|
||||
is(prefs.selectedAdvancedTab, "updateTab", "The update tab within the advanced prefs should be selected");
|
||||
prefs = yield openPreferencesViaHash("privacy");
|
||||
is(prefs.selectedPane, "panePrivacy", "Privacy pane is selected when hash is 'privacy'");
|
||||
prefs = yield openPreferencesViaOpenPreferencesAPI("nonexistant-category");
|
||||
is(prefs.selectedPane, "paneGeneral", "General pane is selected by default when a nonexistant-category is requested");
|
||||
prefs = yield openPreferencesViaHash("nonexistant-category");
|
||||
is(prefs.selectedPane, "paneGeneral", "General pane is selected when hash is a nonexistant-category");
|
||||
prefs = yield openPreferencesViaHash();
|
||||
is(prefs.selectedPane, "paneGeneral", "General pane is selected by default");
|
||||
});
|
||||
|
||||
function openPreferencesViaHash(aPane) {
|
||||
let deferred = Promise.defer();
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:preferences" + (aPane ? "#" + aPane : ""));
|
||||
let newTabBrowser = gBrowser.selectedBrowser;
|
||||
|
||||
newTabBrowser.addEventListener("Initialized", function() {
|
||||
newTabBrowser.contentWindow.addEventListener("load", function() {
|
||||
let win = gBrowser.contentWindow;
|
||||
let selectedPane = win.history.state;
|
||||
gBrowser.removeCurrentTab();
|
||||
deferred.resolve({selectedPane});
|
||||
}, {once: true});
|
||||
}, {capture: true, once: true});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
|
||||
const {Utils} = Cu.import("resource://gre/modules/sessionstore/Utils.jsm", {});
|
||||
const triggeringPrincipal_base64 = Utils.SERIALIZED_SYSTEMPRINCIPAL;
|
||||
|
||||
add_task(function* () {
|
||||
waitForExplicitFinish();
|
||||
|
||||
const tabURL = getRootDirectory(gTestPath) + "browser_bug1184989_prevent_scrolling_when_preferences_flipped.xul";
|
||||
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser, url: tabURL }, function* (browser) {
|
||||
let doc = browser.contentDocument;
|
||||
let container = doc.getElementById("container");
|
||||
|
||||
// Test button
|
||||
let button = doc.getElementById("button");
|
||||
button.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
yield checkPageScrolling(container, "button");
|
||||
|
||||
// Test checkbox
|
||||
let checkbox = doc.getElementById("checkbox");
|
||||
checkbox.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
ok(checkbox.checked, "Checkbox is checked");
|
||||
yield checkPageScrolling(container, "checkbox");
|
||||
|
||||
// Test listbox
|
||||
let listbox = doc.getElementById("listbox");
|
||||
let listitem = doc.getElementById("listitem");
|
||||
listbox.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
ok(listitem.selected, "Listitem is selected");
|
||||
yield checkPageScrolling(container, "listbox");
|
||||
|
||||
// Test radio
|
||||
let radiogroup = doc.getElementById("radiogroup");
|
||||
radiogroup.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
yield checkPageScrolling(container, "radio");
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:preferences#search" }, function* (browser) {
|
||||
let doc = browser.contentDocument;
|
||||
let container = doc.getElementsByClassName("main-content")[0];
|
||||
|
||||
// Test search
|
||||
let engineList = doc.getElementById("engineList");
|
||||
engineList.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
is(engineList.view.selection.currentIndex, 0, "Search engineList is selected");
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
yield checkPageScrolling(container, "search engineList");
|
||||
});
|
||||
|
||||
// Test session restore
|
||||
const CRASH_URL = "about:mozilla";
|
||||
const CRASH_FAVICON = "chrome://branding/content/icon32.png";
|
||||
const CRASH_SHENTRY = {url: CRASH_URL};
|
||||
const CRASH_TAB = {entries: [CRASH_SHENTRY], image: CRASH_FAVICON};
|
||||
const CRASH_STATE = {windows: [{tabs: [CRASH_TAB]}]};
|
||||
|
||||
const TAB_URL = "about:sessionrestore";
|
||||
const TAB_FORMDATA = {url: TAB_URL, id: {sessionData: CRASH_STATE}};
|
||||
const TAB_SHENTRY = {url: TAB_URL, triggeringPrincipal_base64};
|
||||
const TAB_STATE = {entries: [TAB_SHENTRY], formdata: TAB_FORMDATA};
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
|
||||
// Fake a post-crash tab
|
||||
ss.setTabState(tab, JSON.stringify(TAB_STATE));
|
||||
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
|
||||
// Make body scrollable
|
||||
doc.body.style.height = (doc.body.clientHeight + 100) + "px";
|
||||
|
||||
let tabList = doc.getElementById("tabList");
|
||||
tabList.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
yield checkPageScrolling(doc.documentElement, "session restore");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
|
||||
function checkPageScrolling(container, type) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
is(container.scrollTop, 0, "Page should not scroll when " + type + " flipped");
|
||||
resolve();
|
||||
}, 0);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
XUL Widget Test for Bug 1184989
|
||||
-->
|
||||
<page title="Bug 1184989 Test"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<vbox id="container" style="height: 200px; overflow: auto;">
|
||||
<vbox style="height: 500px;">
|
||||
<hbox>
|
||||
<button id="button" label="button" />
|
||||
</hbox>
|
||||
|
||||
<hbox>
|
||||
<checkbox id="checkbox" label="checkbox" />
|
||||
</hbox>
|
||||
|
||||
<hbox style="height: 50px;">
|
||||
<listbox id="listbox">
|
||||
<listitem id="listitem" label="listitem" />
|
||||
<listitem label="listitem" />
|
||||
</listbox>
|
||||
</hbox>
|
||||
|
||||
<hbox>
|
||||
<radiogroup id="radiogroup">
|
||||
<radio id="radio" label="radio" />
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
</page>
|
|
@ -0,0 +1,46 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Setup a phony handler to ensure the app pane will be populated.
|
||||
var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
|
||||
createInstance(Ci.nsIWebHandlerApp);
|
||||
handler.name = "App pane alive test";
|
||||
handler.uriTemplate = "http://test.mozilla.org/%s";
|
||||
|
||||
var extps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
|
||||
getService(Ci.nsIExternalProtocolService);
|
||||
var info = extps.getProtocolHandlerInfo("apppanetest");
|
||||
info.possibleApplicationHandlers.appendElement(handler, false);
|
||||
|
||||
var hserv = Cc["@mozilla.org/uriloader/handler-service;1"].
|
||||
getService(Ci.nsIHandlerService);
|
||||
hserv.store(info);
|
||||
|
||||
openPreferencesViaOpenPreferencesAPI("applications", null, {leaveOpen: true}).then(
|
||||
() => runTest(gBrowser.selectedBrowser.contentWindow)
|
||||
);
|
||||
}
|
||||
|
||||
function runTest(win) {
|
||||
var rbox = win.document.getElementById("handlersView");
|
||||
ok(rbox, "handlersView is present");
|
||||
|
||||
var items = rbox && rbox.getElementsByTagName("richlistitem");
|
||||
ok(items && items.length > 0, "App handler list populated");
|
||||
|
||||
var handlerAdded = false;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].getAttribute("type") == "apppanetest")
|
||||
handlerAdded = true;
|
||||
}
|
||||
ok(handlerAdded, "apppanetest protocol handler was successfully added");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче