diff options
Diffstat (limited to 'application')
52 files changed, 869 insertions, 397 deletions
diff --git a/application/palemoon/app/profile/palemoon.js b/application/palemoon/app/profile/palemoon.js index ee4a95d38..20919eca4 100644 --- a/application/palemoon/app/profile/palemoon.js +++ b/application/palemoon/app/profile/palemoon.js @@ -756,6 +756,7 @@ pref("goanna.handlerService.allowRegisterFromDifferentHost", false); pref("browser.geolocation.warning.infoURL", "http://www.palemoon.org/info-url/geolocation.shtml"); pref("browser.mixedcontent.warning.infoURL", "http://www.palemoon.org/info-url/mixedcontent.shtml"); +pref("browser.push.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/push/"); pref("browser.EULA.version", 3); pref("browser.rights.version", 3); diff --git a/application/palemoon/base/content/browser-fullScreen.js b/application/palemoon/base/content/browser-fullScreen.js index 400340e77..73b10ae85 100644 --- a/application/palemoon/base/content/browser-fullScreen.js +++ b/application/palemoon/base/content/browser-fullScreen.js @@ -354,11 +354,10 @@ var FullScreen = { "fullscreen", Services.perms.ALLOW_ACTION, Services.perms.EXPIRE_SESSION); - let host = uri.host; var onFullscreenchange = function onFullscreenchange(event) { if (event.target == document && document.mozFullScreenElement == null) { // The chrome document has left fullscreen. Remove the temporary permission grant. - Services.perms.remove(host, "fullscreen"); + Services.perms.remove(uri, "fullscreen"); document.removeEventListener("mozfullscreenchange", onFullscreenchange); } } diff --git a/application/palemoon/base/content/browser-plugins.js b/application/palemoon/base/content/browser-plugins.js index 769ac6d8a..838268203 100644 --- a/application/palemoon/base/content/browser-plugins.js +++ b/application/palemoon/base/content/browser-plugins.js @@ -470,28 +470,12 @@ var gPluginHandler = { } }, - // Match the behaviour of nsPermissionManager - _getHostFromPrincipal: function PH_getHostFromPrincipal(principal) { - if (!principal.URI || principal.URI.schemeIs("moz-nullprincipal")) { - return "(null)"; - } - - try { - if (principal.URI.host) - return principal.URI.host; - } catch (e) {} - - return principal.origin; - }, - _makeCenterActions: function PH_makeCenterActions(notification) { let contentWindow = notification.browser.contentWindow; let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); let principal = contentWindow.document.nodePrincipal; - // This matches the behavior of nsPermssionManager, used for display purposes only - let principalHost = this._getHostFromPrincipal(principal); let centerActions = []; let pluginsFound = new Set(); @@ -517,11 +501,11 @@ var gPluginHandler = { let permissionObj = Services.perms. getPermissionObject(principal, pluginInfo.permissionString, false); if (permissionObj) { - pluginInfo.pluginPermissionHost = permissionObj.host; + pluginInfo.pluginPermissionPrePath = permissionObj.principal.originNoSuffix; pluginInfo.pluginPermissionType = permissionObj.expireType; } else { - pluginInfo.pluginPermissionHost = principalHost; + pluginInfo.pluginPermissionPrePath = principal.originNoSuffix; pluginInfo.pluginPermissionType = undefined; } diff --git a/application/palemoon/base/content/browser.js b/application/palemoon/base/content/browser.js index 5fe475338..bfdc1e30b 100644 --- a/application/palemoon/base/content/browser.js +++ b/application/palemoon/base/content/browser.js @@ -86,14 +86,8 @@ this.__defineSetter__("AddonManager", function (val) { return this.AddonManager = val; }); -this.__defineGetter__("PluralForm", function() { - Cu.import("resource://gre/modules/PluralForm.jsm"); - return this.PluralForm; -}); -this.__defineSetter__("PluralForm", function (val) { - delete this.PluralForm; - return this.PluralForm = val; -}); +XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", + "resource://gre/modules/PluralForm.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils", "resource:///modules/AboutHomeUtils.jsm"); diff --git a/application/palemoon/base/content/pageinfo/pageInfo.js b/application/palemoon/base/content/pageinfo/pageInfo.js index 83f0ddb91..6b02bc370 100644 --- a/application/palemoon/base/content/pageinfo/pageInfo.js +++ b/application/palemoon/base/content/pageinfo/pageInfo.js @@ -1112,8 +1112,9 @@ var imagePermissionObserver = { var row = getSelectedRow(imageTree); var item = gImageView.data[row][COL_IMAGE_NODE]; var url = gImageView.data[row][COL_IMAGE_ADDRESS]; - if (makeURI(url).host == permission.host) + if (permission.matchesURI(makeURI(url), true)) { makeBlockImage(url); + } } } } diff --git a/application/palemoon/base/content/pageinfo/permissions.js b/application/palemoon/base/content/pageinfo/permissions.js index 2fa0cc303..68261ce6e 100644 --- a/application/palemoon/base/content/pageinfo/permissions.js +++ b/application/palemoon/base/content/pageinfo/permissions.js @@ -98,7 +98,7 @@ var permissionObserver = { if (aTopic == "perm-changed") { var permission = aSubject.QueryInterface( Components.interfaces.nsIPermission); - if (permission.host == gPermURI.host) { + if (permission.matchesURI(gPermURI, true)) { if (permission.type in gPermObj) initRow(permission.type); else if (permission.type.startsWith("plugin")) @@ -119,7 +119,7 @@ function onLoadPermission(principal) gPermURI = uri; gPermPrincipal = principal; var hostText = document.getElementById("hostText"); - hostText.value = gPermURI.host; + hostText.value = gPermURI.prePath; for (var i in gPermObj) initRow(i); diff --git a/application/palemoon/base/content/urlbarBindings.xml b/application/palemoon/base/content/urlbarBindings.xml index 3d22b2de4..985769ec2 100644 --- a/application/palemoon/base/content/urlbarBindings.xml +++ b/application/palemoon/base/content/urlbarBindings.xml @@ -1370,8 +1370,8 @@ return; } - let host = gPluginHandler._getHostFromPrincipal(this.notification.browser.contentWindow.document.nodePrincipal); - this._setupDescription("pluginActivateMultiple.message", null, host); + let prePath = this.notification.browser.contentWindow.document.nodePrincipal.URI.prePath; + this._setupDescription("pluginActivateMultiple.message", null, prePath); var showBox = document.getAnonymousElementByAttribute(this, "anonid", "plugin-notification-showbox"); @@ -1410,7 +1410,7 @@ <method name="_setupSingleState"> <body><![CDATA[ var action = this.notification.options.centerActions[0]; - var host = action.pluginPermissionHost; + var prePath = action.pluginPermissionPrePath; let label, linkLabel, linkUrl, button1, button2; @@ -1505,7 +1505,7 @@ Cu.reportError(Error("Unexpected blocklist state")); } } - this._setupDescription(label, action.pluginName, host); + this._setupDescription(label, action.pluginName, prePath); this._setupLink(linkLabel, action.detailsLink); this._primaryButton.label = gNavigatorBundle.getString(button1.label); @@ -1526,7 +1526,7 @@ <method name="_setupDescription"> <parameter name="baseString" /> <parameter name="pluginName" /> <!-- null for the multiple-plugin case --> - <parameter name="host" /> + <parameter name="prePath" /> <body><![CDATA[ var bsn = this._brandShortName; var span = document.getAnonymousElementByAttribute(this, "anonid", "click-to-play-plugins-notification-description"); @@ -1534,17 +1534,17 @@ span.removeChild(span.lastChild); } - var args = ["__host__", this._brandShortName]; + var args = ["__prepath__", this._brandShortName]; if (pluginName) { args.unshift(pluginName); } var bases = gNavigatorBundle.getFormattedString(baseString, args). - split("__host__", 2); + split("__prepath__", 2); span.appendChild(document.createTextNode(bases[0])); - var hostSpan = document.createElementNS("http://www.w3.org/1999/xhtml", "em"); - hostSpan.appendChild(document.createTextNode(host)); - span.appendChild(hostSpan); + var prePathSpan = document.createElementNS("http://www.w3.org/1999/xhtml", "em"); + prePathSpan.appendChild(document.createTextNode(prePath)); + span.appendChild(prePathSpan); span.appendChild(document.createTextNode(bases[1] + " ")); ]]></body> </method> diff --git a/application/palemoon/components/nsBrowserGlue.js b/application/palemoon/components/nsBrowserGlue.js index 225cddd52..6563df4e6 100644 --- a/application/palemoon/components/nsBrowserGlue.js +++ b/application/palemoon/components/nsBrowserGlue.js @@ -39,6 +39,9 @@ Cu.import("resource://gre/modules/Services.jsm"); ["DateTimePickerHelper", "resource://gre/modules/DateTimePickerHelper.jsm"], ].forEach(([name, resource]) => XPCOMUtils.defineLazyModuleGetter(this, name, resource)); +XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", + "@mozilla.org/alerts-service;1", "nsIAlertsService"); + const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; @@ -825,16 +828,6 @@ BrowserGlue.prototype = { if (actions.indexOf("showAlert") == -1) return; - let notifier; - try { - notifier = Cc["@mozilla.org/alerts-service;1"]. - getService(Ci.nsIAlertsService); - } - catch (e) { - // nsIAlertsService is not available for this platform - return; - } - let title = getNotifyString({propName: "alertTitle", stringName: "puAlertTitle", stringParams: [appName]}); @@ -856,10 +849,11 @@ BrowserGlue.prototype = { try { // This will throw NS_ERROR_NOT_AVAILABLE if the notification cannot // be displayed per the idl. - notifier.showAlertNotification(null, title, text, - true, url, clickCallback); + AlertsService.showAlertNotification(null, title, text, + true, url, clickCallback); } catch (e) { + Cu.reportError(e); } }, @@ -1191,7 +1185,7 @@ BrowserGlue.prototype = { }, _migrateUI: function BG__migrateUI() { - const UI_VERSION = 15; + const UI_VERSION = 17; const BROWSER_DOCURL = "chrome://browser/content/browser.xul#"; let currentUIVersion = 0; try { @@ -1386,6 +1380,10 @@ BrowserGlue.prototype = { } } + if (currentUIVersion < 17) { + this._notifyNotificationsUpgrade(); + } + if (this._dirty) this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush(); @@ -1396,6 +1394,52 @@ BrowserGlue.prototype = { Services.prefs.setIntPref("browser.migration.version", UI_VERSION); }, + _hasExistingNotificationPermission: function BG__hasExistingNotificationPermission() { + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); + if (permission.type == "desktop-notification") { + return true; + } + } + return false; + }, + + _notifyNotificationsUpgrade: function BG__notifyNotificationsUpgrade() { + if (!this._hasExistingNotificationPermission()) { + return; + } + function clickCallback(subject, topic, data) { + if (topic != "alertclickcallback") + return; + let win = RecentWindow.getMostRecentBrowserWindow(); + win.openUILinkIn(data, "tab"); + } + // Show the application icon for XUL notifications. We assume system-level + // notifications will include their own icon. + let imageURL = this._hasSystemAlertsService() ? "" : + "chrome://branding/content/about-logo.png"; + let title = gBrowserBundle.GetStringFromName("webNotifications.upgradeTitle"); + let text = gBrowserBundle.GetStringFromName("webNotifications.upgradeBody"); + let url = Services.urlFormatter.formatURLPref("browser.push.warning.infoURL"); + + try { + AlertsService.showAlertNotification(imageURL, title, text, + true, url, clickCallback); + } + catch (e) { + Cu.reportError(e); + } + }, + + _hasSystemAlertsService: function() { + try { + return !!Cc["@mozilla.org/system-alerts-service;1"].getService( + Ci.nsIAlertsService); + } catch (e) {} + return false; + }, + _getPersist: function BG__getPersist(aSource, aProperty) { var target = this._dataSource.GetTarget(aSource, aProperty, true); if (target instanceof Ci.nsIRDFLiteral) @@ -1645,6 +1689,16 @@ ContentPermissionPrompt.prototype = { return chromeWin; }, + _getBrowserForRequest: function (aRequest) { + let requestingWindow = aRequest.window.top; + // find the requesting browser or iframe + let browser = requestingWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .chromeEventHandler; + return browser; + }, + /** * Show a permission prompt. * @@ -1809,30 +1863,49 @@ ContentPermissionPrompt.prototype = { var message = browserBundle.formatStringFromName("webNotifications.showFromSite", [requestingURI.host], 1); - var actions = [ - { - stringId: "webNotifications.showForSession", - action: Ci.nsIPermissionManager.ALLOW_ACTION, - expireType: Ci.nsIPermissionManager.EXPIRE_SESSION, - callback: function() {}, - }, - { - stringId: "webNotifications.alwaysShow", - action: Ci.nsIPermissionManager.ALLOW_ACTION, - expireType: null, - callback: function() {}, - }, - { - stringId: "webNotifications.neverShow", - action: Ci.nsIPermissionManager.DENY_ACTION, - expireType: null, - callback: function() {}, - }, - ]; + var actions; + + var browser = this._getBrowserForRequest(aRequest); + // Only show "allow for session" in PB mode, we don't + // support "allow for session" in non-PB mode. + if (PrivateBrowsingUtils.isBrowserPrivate(browser)) { + actions = [ + { + stringId: "webNotifications.showForSession", + action: Ci.nsIPermissionManager.ALLOW_ACTION, + expireType: Ci.nsIPermissionManager.EXPIRE_SESSION, + callback: function() {}, + }, + ]; + } else { + actions = [ + { + stringId: "webNotifications.showForSession", + action: Ci.nsIPermissionManager.ALLOW_ACTION, + expireType: Ci.nsIPermissionManager.EXPIRE_SESSION, + callback: function() {}, + }, + { + stringId: "webNotifications.alwaysShow", + action: Ci.nsIPermissionManager.ALLOW_ACTION, + expireType: null, + callback: function() {}, + }, + { + stringId: "webNotifications.neverShow", + action: Ci.nsIPermissionManager.DENY_ACTION, + expireType: null, + callback: function() {}, + }, + ]; + } + var options = { + learnMoreURL: Services.urlFormatter.formatURLPref("browser.push.warning.infoURL"), + }; this._showPrompt(aRequest, message, "desktop-notification", actions, "web-notifications", - "web-notifications-notification-icon", null); + "web-notifications-notification-icon", options); }, _promptPointerLock: function CPP_promtPointerLock(aRequest, autoAllow) { @@ -1875,7 +1948,6 @@ ContentPermissionPrompt.prototype = { }, prompt: function CPP_prompt(request) { - // Only allow exactly one permission rquest here. let types = request.types.QueryInterface(Ci.nsIArray); if (types.length != 1) { @@ -1921,15 +1993,15 @@ ContentPermissionPrompt.prototype = { // Show the prompt. switch (perm.type) { - case "geolocation": - this._promptGeo(request); - break; - case "desktop-notification": - this._promptWebNotifications(request); - break; - case "pointerLock": - this._promptPointerLock(request, autoAllow); - break; + case "geolocation": + this._promptGeo(request); + break; + case "desktop-notification": + this._promptWebNotifications(request); + break; + case "pointerLock": + this._promptPointerLock(request, autoAllow); + break; } }, diff --git a/application/palemoon/components/preferences/aboutPermissions.js b/application/palemoon/components/preferences/aboutPermissions.js index 31b48f88e..531bb061f 100644 --- a/application/palemoon/components/preferences/aboutPermissions.js +++ b/application/palemoon/components/preferences/aboutPermissions.js @@ -2,17 +2,25 @@ * 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/. */ +"use strict"; + var Ci = Components.interfaces; var Cc = Components.classes; var Cu = Components.utils; +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/PluralForm.jsm"); Cu.import("resource://gre/modules/DownloadUtils.jsm"); Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/ForgetAboutSite.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", + "resource://gre/modules/PluralForm.jsm"); + +var gSecMan = Cc["@mozilla.org/scriptsecuritymanager;1"]. + getService(Ci.nsIScriptSecurityManager); + var gFaviconService = Cc["@mozilla.org/browser/favicon-service;1"]. getService(Ci.nsIFaviconService); @@ -22,7 +30,7 @@ var gPlacesDatabase = Cc["@mozilla.org/browser/nav-history-service;1"]. clone(true); var gSitesStmt = gPlacesDatabase.createAsyncStatement( - "SELECT get_unreversed_host(rev_host) AS host " + + "SELECT url " + "FROM moz_places " + "WHERE rev_host > '.' " + "AND visit_count > 0 " + @@ -54,14 +62,11 @@ const MASTER_PASSWORD_MESSAGE = "User canceled master password entry"; const TEST_EXACT_PERM_TYPES = ["desktop-notification", "geo", "pointerLock"]; /** - * Site object represents a single site, uniquely identified by a host. + * Site object represents a single site, uniquely identified by a principal. */ -function Site(host) { - this.host = host; +function Site(principal) { + this.principal = principal; this.listitem = null; - - this.httpURI = NetUtil.newURI("http://" + this.host); - this.httpsURI = NetUtil.newURI("https://" + this.host); } Site.prototype = { @@ -83,16 +88,10 @@ Site.prototype = { } } - // Try to find favicon for both URIs, but always prefer the https favicon. - gFaviconService.getFaviconURLForPage(this.httpsURI, function(aURI) { + // Get the favicon for the origin + gFaviconService.getFaviconURLForPage(this.principal.URI, function (aURI) { if (aURI) { invokeCallback(aURI); - } else { - gFaviconService.getFaviconURLForPage(this.httpURI, function(aURI) { - if (aURI) { - invokeCallback(aURI); - } - }); } }.bind(this)); }, @@ -104,7 +103,9 @@ Site.prototype = { * A function that takes the visit count (a number) as a parameter. */ getVisitCount: function Site_getVisitCount(aCallback) { - let rev_host = this.host.split("").reverse().join("") + "."; + // XXX This won't be a very reliable system, as it will count both http: and https: visits + // Unfortunately, I don't think that there is a much better way to do it right now. + let rev_host = this.principal.URI.host.split("").reverse().join("") + "."; gVisitStmt.params.rev_host = rev_host; gVisitStmt.executeAsync({ handleResult: function(aResults) { @@ -147,9 +148,9 @@ Site.prototype = { let permissionValue; if (TEST_EXACT_PERM_TYPES.indexOf(aType) == -1) { - permissionValue = Services.perms.testPermission(this.httpURI, aType); + permissionValue = Services.perms.testPermissionFromPrincipal(this.principal, aType); } else { - permissionValue = Services.perms.testExactPermission(this.httpURI, aType); + permissionValue = Services.perms.testExactPermissionFromPrincipal(this.principal, aType); } aResultObj.value = permissionValue; @@ -187,9 +188,7 @@ Site.prototype = { } } - // Using httpURI is kind of bogus, but the permission manager stores - // the permission for the host, so the right thing happens in the end. - Services.perms.add(this.httpURI, aType, aPerm); + Services.perms.addFromPrincipal(this.principal, aType, aPerm); }, /** @@ -200,7 +199,7 @@ Site.prototype = { * e.g. "cookie", "geo", "indexedDB", "popup", "image" */ clearPermission: function Site_clearPermission(aType) { - Services.perms.remove(this.host, aType); + Services.perms.removeFromPrincipal(this.principal, aType); }, /** @@ -210,11 +209,9 @@ Site.prototype = { */ get logins() { try { - let httpLogins = Services.logins.findLogins( - {}, this.httpURI.prePath, "", ""); - let httpsLogins = Services.logins.findLogins( - {}, this.httpsURI.prePath, "", ""); - return httpLogins.concat(httpsLogins); + let logins = Services.logins.findLogins({}, + this.principal.originNoSuffix, "", ""); + return logins; } catch (e) { if (!e.message.includes(MASTER_PASSWORD_MESSAGE)) { Cu.reportError("AboutPermissions: " + e); @@ -227,8 +224,7 @@ Site.prototype = { // Only say that login saving is blocked if it is blocked for both // http and https. try { - return Services.logins.getLoginSavingEnabled(this.httpURI.prePath) && - Services.logins.getLoginSavingEnabled(this.httpsURI.prePath); + return Services.logins.getLoginSavingEnabled(this.principal.originNoSuffix); } catch (e) { if (!e.message.includes(MASTER_PASSWORD_MESSAGE)) { Cu.reportError("AboutPermissions: " + e); @@ -239,8 +235,7 @@ Site.prototype = { set loginSavingEnabled(isEnabled) { try { - Services.logins.setLoginSavingEnabled(this.httpURI.prePath, isEnabled); - Services.logins.setLoginSavingEnabled(this.httpsURI.prePath, isEnabled); + Services.logins.setLoginSavingEnabled(this.principal.originNoSuffix, isEnabled); } catch (e) { if (!e.message.includes(MASTER_PASSWORD_MESSAGE)) { Cu.reportError("AboutPermissions: " + e); @@ -279,7 +274,11 @@ Site.prototype = { * Removes all data from the browser corresponding to the site. */ forgetSite: function Site_forgetSite() { - ForgetAboutSite.removeDataFromDomain(this.host) + // XXX This removes data for an entire domain, rather than just + // an origin. This may produce confusing results, as data will + // be cleared for the http:// as well as the https:// domain + // if you try to forget the https:// site. + ForgetAboutSite.removeDataFromDomain(this.principal.URI.host) .catch(Cu.reportError); } } @@ -461,10 +460,18 @@ var AboutPermissions = { LIST_BUILD_DELAY: 100, // delay between intervals /** - * Stores a mapping of host strings to Site objects. + * Stores a mapping of origin strings to Site objects. */ _sites: {}, + /** + * Using a getter for sitesFilter to avoid races with tests. + */ + get sitesFilter () { + delete this.sitesFilter; + return this.sitesFilter = document.getElementById("sites-filter"); + }, + sitesList: null, _selectedSite: null, @@ -721,9 +728,9 @@ var AboutPermissions = { break; } let permission = aSubject.QueryInterface(Ci.nsIPermission); - // We can't compare selectedSite.host and permission.host here because - // we need to handle the case where a parent domain was changed in - // a way that affects the subdomain. + // We can't compare selectedSite.principal and permission.principal here + // because we need to handle the case where a parent domain was changed + // in a way that affects the subdomain. if (this._supportedPermissions.indexOf(permission.type) != -1) { this.updatePermission(permission.type); } @@ -798,8 +805,11 @@ var AboutPermissions = { AboutPermissions.startSitesListBatch(); let row; while (row = aResults.getNextRow()) { - let host = row.getResultByName("host"); - AboutPermissions.addHost(host); + let spec = row.getResultByName("url"); + let uri = NetUtil.newURI(spec); + let principal = gSecMan.getNoAppCodebasePrincipal(uri); + + AboutPermissions.addPrincipal(principal); } AboutPermissions.endSitesListBatch(); }, @@ -853,7 +863,8 @@ var AboutPermissions = { // i.e.: "chrome://weave" (Sync) if (!aLogin.hostname.startsWith(schemeChrome + ":")) { let uri = NetUtil.newURI(aLogin.hostname); - this.addHost(uri.host); + let principal = gSecMan.getNoAppCodebasePrincipal(uri); + this.addPrincipal(principal); } } catch (e) { Cu.reportError("AboutPermissions: " + e); @@ -869,7 +880,8 @@ var AboutPermissions = { // i.e.: "chrome://weave" (Sync) if (!aHostname.startsWith(schemeChrome + ":")) { let uri = NetUtil.newURI(aHostname); - this.addHost(uri.host); + let principal = gSecMan.getNoAppCodebasePrincipal(uri); + this.addPrincipal(principal); } } catch (e) { Cu.reportError("AboutPermissions: " + e); @@ -887,7 +899,7 @@ var AboutPermissions = { let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); // Only include sites with exceptions set for supported permission types. if (this._supportedPermissions.indexOf(permission.type) != -1) { - this.addHost(permission.host); + this.addPrincipal(permission.principal); } itemCnt++; } @@ -898,15 +910,15 @@ var AboutPermissions = { /** * Creates a new Site and adds it to _sites if it's not already there. * - * @param aHost - * A host string. + * @param aPrincipal + * A principal. */ - addHost: function(aHost) { - if (aHost in this._sites) { + addPrincipal: function(aPrincipal) { + if (aPrincipal.origin in this._sites) { return; } - let site = new Site(aHost); - this._sites[aHost] = site; + let site = new Site(aPrincipal); + this._sites[aPrincipal.origin] = site; this.addToSitesList(site); }, @@ -919,7 +931,7 @@ var AboutPermissions = { addToSitesList: function(aSite) { let item = document.createElement("richlistitem"); item.setAttribute("class", "site"); - item.setAttribute("value", aSite.host); + item.setAttribute("value", aSite.principal.origin); aSite.getFavicon(function(aURL) { item.setAttribute("favicon", aURL); @@ -927,9 +939,8 @@ var AboutPermissions = { aSite.listitem = item; // Make sure to only display relevant items when list is filtered. - let filterValue = - document.getElementById("sites-filter").value.toLowerCase(); - item.collapsed = aSite.host.toLowerCase().indexOf(filterValue) == -1; + let filterValue = this.sitesFilter.value.toLowerCase(); + item.collapsed = aSite.principal.origin.toLowerCase().indexOf(filterValue) == -1; (this._listFragment || this.sitesList).appendChild(item); }, @@ -951,8 +962,7 @@ var AboutPermissions = { */ filterSitesList: function() { let siteItems = this.sitesList.children; - let filterValue = - document.getElementById("sites-filter").value.toLowerCase(); + let filterValue = this.sitesFilter.value.toLowerCase(); if (filterValue == "") { for (let i = 0, iLen = siteItems.length; i < iLen; i++) { @@ -983,9 +993,9 @@ var AboutPermissions = { * The host string corresponding to the site to delete. */ deleteFromSitesList: function(aHost) { - for (let host in this._sites) { - let site = this._sites[host]; - if (site.host.hasRootDomain(aHost)) { + for (let origin in this._sites) { + let site = this._sites[origin]; + if (site.principal.URI.host.hasRootDomain(aHost)) { if (site == this._selectedSite) { // Replace site-specific interface with "All Sites" interface. this.sitesList.selectedItem = @@ -993,7 +1003,7 @@ var AboutPermissions = { } this.sitesList.removeChild(site.listitem); - delete this._sites[site.host]; + delete this._sites[site.principal.origin]; } } }, @@ -1009,9 +1019,9 @@ var AboutPermissions = { return; } - let host = event.target.value; - let site = this._selectedSite = this._sites[host]; - document.getElementById("site-label").value = host; + let origin = event.target.value; + let site = this._selectedSite = this._sites[origin]; + document.getElementById("site-label").value = origin; document.getElementById("header-deck").selectedPanel = document.getElementById("site-header"); @@ -1245,19 +1255,19 @@ var AboutPermissions = { * Opens password manager dialog. */ managePasswords: function() { - let selectedHost = ""; + let selectedOrigin = ""; if (this._selectedSite) { - selectedHost = this._selectedSite.host; + selectedOrigin = this._selectedSite.principal.URI.prePath; } let win = Services.wm.getMostRecentWindow("Toolkit:PasswordManager"); if (win) { - win.setFilter(selectedHost); + win.setFilter(selectedOrigin); win.focus(); } else { window.openDialog("chrome://passwordmgr/content/passwordManager.xul", "Toolkit:PasswordManager", "", - {filterString : selectedHost}); + {filterString : selectedOrigin}); } }, @@ -1313,10 +1323,12 @@ var AboutPermissions = { * Opens cookie manager dialog. */ manageCookies: function() { + // Cookies are stored by-host, and thus we filter the cookie window + // using only the host of the selected principal's origin let selectedHost = ""; let selectedDomain = ""; if (this._selectedSite) { - selectedHost = this._selectedSite.host; + selectedHost = this._selectedSite.principal.URI.host; selectedDomain = this.domainFromHost(selectedHost); } @@ -1328,6 +1340,13 @@ var AboutPermissions = { window.openDialog("chrome://browser/content/preferences/cookies.xul", "Browser:Cookies", "", {filterString : selectedDomain}); } + }, + + /** + * Focusses the filter box. + */ + focusFilterBox: function() { + this.sitesFilter.focus(); } } diff --git a/application/palemoon/components/preferences/aboutPermissions.xul b/application/palemoon/components/preferences/aboutPermissions.xul index bd5a205c7..c099161f2 100644 --- a/application/palemoon/components/preferences/aboutPermissions.xul +++ b/application/palemoon/components/preferences/aboutPermissions.xul @@ -25,6 +25,10 @@ <script type="application/javascript" src="chrome://browser/content/preferences/aboutPermissions.js"/> + <keyset> + <key key="&focusSearch.key;" modifiers="accel" oncommand="AboutPermissions.focusFilterBox();"/> + </keyset> + <hbox flex="1" id="permissions-header"> <label id="permissions-pagetitle">&permissionsManager.title;</label> </hbox> @@ -390,7 +394,6 @@ </hbox> </vbox> </hbox> - </vbox> </hbox> diff --git a/application/palemoon/components/preferences/advanced.js b/application/palemoon/components/preferences/advanced.js index 429a0c419..0803496fe 100644 --- a/application/palemoon/components/preferences/advanced.js +++ b/application/palemoon/components/preferences/advanced.js @@ -8,6 +8,7 @@ Components.utils.import("resource://gre/modules/DownloadUtils.jsm"); Components.utils.import("resource://gre/modules/ctypes.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/LoadContextInfo.jsm"); +Components.utils.import("resource://gre/modules/BrowserUtils.jsm"); var gAdvancedPane = { _inited: false, @@ -377,7 +378,7 @@ var gAdvancedPane = { }, // XXX: duplicated in browser.js - _getOfflineAppUsage: function (host, groups) + _getOfflineAppUsage: function (perm, groups) { var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"]. getService(Components.interfaces.nsIApplicationCacheService); @@ -390,7 +391,7 @@ var gAdvancedPane = { var usage = 0; for (var i = 0; i < groups.length; i++) { var uri = ios.newURI(groups[i], null, null); - if (uri.asciiHost == host) { + if (perm.matchesURI(uri, true)) { var cache = cacheService.getActiveCache(groups[i]); usage += cache.usage; } @@ -427,9 +428,9 @@ var gAdvancedPane = { var row = document.createElement("listitem"); row.id = ""; row.className = "offlineapp"; - row.setAttribute("host", perm.host); + row.setAttribute("origin", perm.principal.origin); var converted = DownloadUtils. - convertByteUnits(this._getOfflineAppUsage(perm.host, groups)); + convertByteUnits(this._getOfflineAppUsage(perm, groups)); row.setAttribute("usage", bundle.getFormattedString("offlineAppUsage", converted)); @@ -453,7 +454,8 @@ var gAdvancedPane = { { var list = document.getElementById("offlineAppsList"); var item = list.selectedItem; - var host = item.getAttribute("host"); + var origin = item.getAttribute("origin"); + var principal = BrowserUtils.principalFromOrigin(origin); var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService); @@ -462,35 +464,34 @@ var gAdvancedPane = { var bundle = document.getElementById("bundlePreferences"); var title = bundle.getString("offlineAppRemoveTitle"); - var prompt = bundle.getFormattedString("offlineAppRemovePrompt", [host]); + 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; - // clear offline cache entries - var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"]. - getService(Components.interfaces.nsIApplicationCacheService); - var ios = Components.classes["@mozilla.org/network/io-service;1"]. - getService(Components.interfaces.nsIIOService); - var groups = cacheService.getGroups(); - for (var i = 0; i < groups.length; i++) { - var uri = ios.newURI(groups[i], null, null); - if (uri.asciiHost == host) { + // get the permission + var pm = Components.classes["@mozilla.org/permissionmanager;1"] + .getService(Components.interfaces.nsIPermissionManager); + var perm = pm.getPermissionObject(principal, "offline-app"); + 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], null, null); + if (perm.matchesURI(uri, true)) { var cache = cacheService.getActiveCache(groups[i]); cache.discard(); + } } - } - - // remove the permission - var pm = Components.classes["@mozilla.org/permissionmanager;1"] - .getService(Components.interfaces.nsIPermissionManager); - pm.remove(host, "offline-app", - Components.interfaces.nsIPermissionManager.ALLOW_ACTION); - pm.remove(host, "offline-app", - Components.interfaces.nsIOfflineCacheUpdateService.ALLOW_NO_WARN); + } catch (e) {} + pm.removePermission(perm); + } list.removeChild(item); gAdvancedPane.offlineAppSelected(); this.updateActualAppCacheSize(); diff --git a/application/palemoon/components/preferences/cookies.js b/application/palemoon/components/preferences/cookies.js index ea7e7d4e2..4ef30d48e 100644 --- a/application/palemoon/components/preferences/cookies.js +++ b/application/palemoon/components/preferences/cookies.js @@ -5,6 +5,8 @@ const nsICookie = Components.interfaces.nsICookie; +Components.utils.import("resource://gre/modules/PluralForm.jsm"); + var gCookiesWindow = { _cm : Components.classes["@mozilla.org/cookiemanager;1"] .getService(Components.interfaces.nsICookieManager), @@ -24,6 +26,11 @@ var gCookiesWindow = { this._bundle = document.getElementById("bundlePreferences"); this._tree = document.getElementById("cookiesList"); + let removeAllCookies = document.getElementById("removeAllCookies"); + removeAllCookies.setAttribute("accesskey", this._bundle.getString("removeAllCookies.accesskey")); + let removeSelectedCookies = document.getElementById("removeSelectedCookies"); + removeSelectedCookies.setAttribute("accesskey", this._bundle.getString("removeSelectedCookies.accesskey")); + this._populateList(true); document.getElementById("filter").focus(); @@ -558,12 +565,12 @@ var gCookiesWindow = { if (item && seln.count == 1 && item.container && item.open) selectedCookieCount += 2; - var removeCookie = document.getElementById("removeCookie"); - var removeCookies = document.getElementById("removeCookies"); - removeCookie.parentNode.selectedPanel = - selectedCookieCount == 1 ? removeCookie : removeCookies; + let buttonLabel = this._bundle.getString("removeSelectedCookies.label"); + let removeSelectedCookies = document.getElementById("removeSelectedCookies"); + removeSelectedCookies.label = PluralForm.get(selectedCookieCount, buttonLabel) + .replace("#1", selectedCookieCount); - removeCookie.disabled = removeCookies.disabled = !(seln.count > 0); + removeSelectedCookies.disabled = !(seln.count > 0); }, performDeletion: function gCookiesWindow_performDeletion(deleteItems) { @@ -725,8 +732,13 @@ var gCookiesWindow = { }, onCookieKeyPress: function (aEvent) { - if (aEvent.keyCode == 46) + if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE +#ifdef XP_MACOSX + || aEvent.keyCode == KeyEvent.DOM_VK_BACK_SPACE +#endif + ) { this.deleteCookie(); + } }, _lastSortProperty : "", @@ -868,7 +880,17 @@ var gCookiesWindow = { }, _updateRemoveAllButton: function gCookiesWindow__updateRemoveAllButton() { - document.getElementById("removeAllCookies").disabled = this._view._rowCount == 0; + let removeAllCookies = document.getElementById("removeAllCookies"); + removeAllCookies.disabled = this._view._rowCount == 0; + + let labelStringID = "removeAllCookies.label"; + let accessKeyStringID = "removeAllCookies.accesskey"; + if (this._view._filtered) { + labelStringID = "removeAllShownCookies.label"; + accessKeyStringID = "removeAllShownCookies.accesskey"; + } + removeAllCookies.setAttribute("label", this._bundle.getString(labelStringID)); + removeAllCookies.setAttribute("accesskey", this._bundle.getString(accessKeyStringID)); }, filter: function () { diff --git a/application/palemoon/components/preferences/cookies.xul b/application/palemoon/components/preferences/cookies.xul index 8ff0d90ec..60725e9d8 100644 --- a/application/palemoon/components/preferences/cookies.xul +++ b/application/palemoon/components/preferences/cookies.xul @@ -91,16 +91,9 @@ </vbox> <hbox align="end"> <hbox class="actionButtons" flex="1"> - <deck oncommand="gCookiesWindow.deleteCookie();"> - <button id="removeCookie" disabled="true" icon="remove" - label="&button.removecookie.label;" - accesskey="&button.removecookie.accesskey;"/> - <button id="removeCookies" disabled="true" icon="remove" - label="&button.removecookies.label;" - accesskey="&button.removecookie.accesskey;"/> - </deck> + <button id="removeSelectedCookies" disabled="true" icon="clear" + oncommand="gCookiesWindow.deleteCookie();"/> <button id="removeAllCookies" disabled="true" icon="clear" - label="&button.removeallcookies.label;" accesskey="&button.removeallcookies.accesskey;" oncommand="gCookiesWindow.deleteAllCookies();"/> <spacer flex="1"/> #ifndef XP_MACOSX diff --git a/application/palemoon/components/preferences/handlers.xml b/application/palemoon/components/preferences/handlers.xml index d60792803..5fb915cee 100644 --- a/application/palemoon/components/preferences/handlers.xml +++ b/application/palemoon/components/preferences/handlers.xml @@ -72,7 +72,7 @@ extends="chrome://global/content/bindings/listbox.xml#listitem"> <content> <children> - <xul:listcell xbl:inherits="label=host"/> + <xul:listcell xbl:inherits="label=origin"/> <xul:listcell xbl:inherits="label=usage"/> </children> </content> diff --git a/application/palemoon/components/preferences/jar.mn b/application/palemoon/components/preferences/jar.mn index a27784305..798a2dae4 100644 --- a/application/palemoon/components/preferences/jar.mn +++ b/application/palemoon/components/preferences/jar.mn @@ -15,7 +15,7 @@ browser.jar: * content/browser/preferences/applicationManager.js * content/browser/preferences/colors.xul * content/browser/preferences/cookies.xul - content/browser/preferences/cookies.js +* content/browser/preferences/cookies.js content/browser/preferences/content.xul content/browser/preferences/content.js * content/browser/preferences/connection.xul @@ -28,8 +28,8 @@ browser.jar: content/browser/preferences/languages.js * content/browser/preferences/main.xul content/browser/preferences/main.js -* content/browser/preferences/permissions.xul - content/browser/preferences/permissions.js + content/browser/preferences/permissions.xul +* content/browser/preferences/permissions.js * content/browser/preferences/preferences.xul content/browser/preferences/privacy.xul content/browser/preferences/privacy.js diff --git a/application/palemoon/components/preferences/permissions.js b/application/palemoon/components/preferences/permissions.js index 785e26d5e..4b1bf41b2 100644 --- a/application/palemoon/components/preferences/permissions.js +++ b/application/palemoon/components/preferences/permissions.js @@ -3,38 +3,40 @@ * 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/. */ +Components.utils.import("resource://gre/modules/Services.jsm"); + const nsIPermissionManager = Components.interfaces.nsIPermissionManager; const nsICookiePermission = Components.interfaces.nsICookiePermission; const NOTIFICATION_FLUSH_PERMISSIONS = "flush-pending-permissions"; -function Permission(host, rawHost, type, capability, perm) +function Permission(principal, type, capability) { - this.host = host; - this.rawHost = rawHost; + this.principal = principal; + this.origin = principal.origin; this.type = type; this.capability = capability; - this.perm = perm; } var gPermissionManager = { - _type : "", - _permissions : [], - _pm : Components.classes["@mozilla.org/permissionmanager;1"] - .getService(Components.interfaces.nsIPermissionManager), - _bundle : null, - _tree : null, - + _type : "", + _permissions : [], + _permissionsToAdd : new Map(), + _permissionsToDelete : new Map(), + _bundle : null, + _tree : null, + _observerRemoved : false, + _view: { _rowCount: 0, - get rowCount() - { - return this._rowCount; + get rowCount() + { + return this._rowCount; }, getCellText: function (aRow, aColumn) { if (aColumn.id == "siteCol") - return gPermissionManager._permissions[aRow].rawHost; + return gPermissionManager._permissions[aRow].origin; else if (aColumn.id == "statusCol") return gPermissionManager._permissions[aRow].capability; return ""; @@ -57,7 +59,7 @@ var gPermissionManager = { return ""; } }, - + _getCapabilityString: function (aCapability) { var stringKey = null; @@ -77,44 +79,66 @@ var gPermissionManager = { } return this._bundle.getString(stringKey); }, - + addPermission: function (aCapability) { var textbox = document.getElementById("url"); - var host = textbox.value.replace(/^\s*([-\w]*:\/+)?/, ""); // trim any leading space and scheme + var input_url = textbox.value.replace(/^\s*/, ""); // trim any leading space + let principal; try { - var ioService = Components.classes["@mozilla.org/network/io-service;1"] - .getService(Components.interfaces.nsIIOService); - var uri = ioService.newURI("http://"+host, null, null); - host = uri.host; + // The origin accessor on the principal object will throw if the + // principal doesn't have a canonical origin representation. This will + // help catch cases where the URI parser parsed something like + // `localhost:8080` as having the scheme `localhost`, rather than being + // an invalid URI. A canonical origin representation is required by the + // permission manager for storage, so this won't prevent any valid + // permissions from being entered by the user. + let uri; + try { + uri = Services.io.newURI(input_url, null, null); + principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri); + // If we have ended up with an unknown scheme, the following will throw. + principal.origin; + } catch(ex) { + uri = Services.io.newURI("http://" + input_url, null, null); + principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri); + // If we have ended up with an unknown scheme, the following will throw. + principal.origin; + } } catch(ex) { - var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] - .getService(Components.interfaces.nsIPromptService); var message = this._bundle.getString("invalidURI"); var title = this._bundle.getString("invalidURITitle"); - promptService.alert(window, title, message); + Services.prompt.alert(window, title, message); return; } var capabilityString = this._getCapabilityString(aCapability); // check whether the permission already exists, if not, add it - var exists = false; + let permissionExists = false; + let capabilityExists = false; for (var i = 0; i < this._permissions.length; ++i) { - if (this._permissions[i].rawHost == host) { - // Avoid calling the permission manager if the capability settings are - // the same. Otherwise allow the call to the permissions manager to - // update the listbox for us. - exists = this._permissions[i].perm == aCapability; + if (this._permissions[i].principal.equals(principal)) { + permissionExists = true; + capabilityExists = this._permissions[i].capability == capabilityString; + if (!capabilityExists) { + this._permissions[i].capability = capabilityString; + } break; } } - if (!exists) { - host = (host.charAt(0) == ".") ? host.substring(1,host.length) : host; - var uri = ioService.newURI("http://" + host, null, null); - this._pm.add(uri, this._type, aCapability); + + let permissionParams = {principal: principal, type: this._type, capability: aCapability}; + if (!permissionExists) { + this._permissionsToAdd.set(principal.origin, permissionParams); + this._addPermission(permissionParams); + } + else if (!capabilityExists) { + this._permissionsToAdd.set(principal.origin, permissionParams); + this._handleCapabilityChange(); } + textbox.value = ""; textbox.focus(); @@ -124,14 +148,58 @@ var gPermissionManager = { // enable "remove all" button as needed document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0; }, - + + _removePermission: function(aPermission) + { + this._removePermissionFromList(aPermission.principal); + + // If this permission was added during this session, let's remove + // it from the pending adds list to prevent calls to the + // permission manager. + let isNewPermission = this._permissionsToAdd.delete(aPermission.principal.origin); + + if (!isNewPermission) { + this._permissionsToDelete.set(aPermission.principal.origin, aPermission); + } + + }, + + _handleCapabilityChange: function () + { + // Re-do the sort, if the status changed from Block to Allow + // or vice versa, since if we're sorted on status, we may no + // longer be in order. + if (this._lastPermissionSortColumn == "statusCol") { + this._resortPermissions(); + } + this._tree.treeBoxObject.invalidate(); + }, + + _addPermission: function(aPermission) + { + this._addPermissionToList(aPermission); + ++this._view._rowCount; + this._tree.treeBoxObject.rowCountChanged(this._view.rowCount - 1, 1); + // Re-do the sort, since we inserted this new item at the end. + this._resortPermissions(); + }, + + _resortPermissions: function() + { + gTreeUtils.sort(this._tree, this._view, this._permissions, + this._lastPermissionSortColumn, + this._permissionsComparator, + this._lastPermissionSortColumn, + !this._lastPermissionSortAscending); // keep sort direction + }, + onHostInput: function (aSiteField) { document.getElementById("btnSession").disabled = !aSiteField.value; document.getElementById("btnBlock").disabled = !aSiteField.value; document.getElementById("btnAllow").disabled = !aSiteField.value; }, - + onWindowKeyPress: function (aEvent) { if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE) @@ -143,14 +211,14 @@ var gPermissionManager = { if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN) document.getElementById("btnAllow").click(); }, - + onLoad: function () { this._bundle = document.getElementById("bundlePreferences"); var params = window.arguments[0]; this.init(params); }, - + init: function (aParams) { if (this._type) { @@ -160,14 +228,14 @@ var gPermissionManager = { this._type = aParams.permissionType; this._manageCapability = aParams.manageCapability; - + var permissionsText = document.getElementById("permissionsText"); while (permissionsText.hasChildNodes()) permissionsText.removeChild(permissionsText.firstChild); permissionsText.appendChild(document.createTextNode(aParams.introText)); document.title = aParams.windowTitle; - + document.getElementById("btnBlock").hidden = !aParams.blockVisible; document.getElementById("btnSession").hidden = !aParams.sessionVisible; document.getElementById("btnAllow").hidden = !aParams.allowVisible; @@ -183,64 +251,64 @@ var gPermissionManager = { var urlLabel = document.getElementById("urlLabel"); urlLabel.hidden = !urlFieldVisible; - var os = Components.classes["@mozilla.org/observer-service;1"] - .getService(Components.interfaces.nsIObserverService); - os.notifyObservers(null, NOTIFICATION_FLUSH_PERMISSIONS, this._type); - os.addObserver(this, "perm-changed", false); + let treecols = document.getElementsByTagName("treecols")[0]; + treecols.addEventListener("click", event => { + if (event.target.nodeName != "treecol" || event.button != 0) { + return; + } + + let sortField = event.target.getAttribute("data-field-name"); + if (!sortField) { + return; + } + + gPermissionManager.onPermissionSort(sortField); + }); + + Services.obs.notifyObservers(null, NOTIFICATION_FLUSH_PERMISSIONS, this._type); + Services.obs.addObserver(this, "perm-changed", false); this._loadPermissions(); - + urlField.focus(); }, - + uninit: function () { - var os = Components.classes["@mozilla.org/observer-service;1"] - .getService(Components.interfaces.nsIObserverService); - os.removeObserver(this, "perm-changed"); + if (!this._observerRemoved) { + Services.obs.removeObserver(this, "perm-changed"); + + this._observerRemoved = true; + } }, - + observe: function (aSubject, aTopic, aData) { if (aTopic == "perm-changed") { var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission); + + // Ignore unrelated permission types. + if (permission.type != this._type) + return; + if (aData == "added") { - this._addPermissionToList(permission); - ++this._view._rowCount; - this._tree.treeBoxObject.rowCountChanged(this._view.rowCount - 1, 1); - // Re-do the sort, since we inserted this new item at the end. - gTreeUtils.sort(this._tree, this._view, this._permissions, - this._lastPermissionSortColumn, - this._permissionsComparator, - this._lastPermissionSortColumn, - !this._lastPermissionSortAscending); // keep sort direction + this._addPermission(permission); } else if (aData == "changed") { for (var i = 0; i < this._permissions.length; ++i) { - if (this._permissions[i].host == permission.host) { + if (permission.matches(this._permissions[i].principal, true)) { this._permissions[i].capability = this._getCapabilityString(permission.capability); break; } } - // Re-do the sort, if the status changed from Block to Allow - // or vice versa, since if we're sorted on status, we may no - // longer be in order. - if (this._lastPermissionSortColumn == "statusCol") { - gTreeUtils.sort(this._tree, this._view, this._permissions, - this._lastPermissionSortColumn, - this._permissionsComparator, - this._lastPermissionSortColumn, - !this._lastPermissionSortAscending); // keep sort direction - } - this._tree.treeBoxObject.invalidate(); + this._handleCapabilityChange(); + } + else if (aData == "deleted") { + this._removePermissionFromList(permission.principal); } - // No UI other than this window causes this method to be sent a "deleted" - // notification, so we don't need to implement it since Delete is handled - // directly by the Permission Removal handlers. If that ever changes, those - // implementations will have to move into here. } }, - + onPermissionSelected: function () { var hasSelection = this._tree.view.selection.count > 0; @@ -257,8 +325,8 @@ var gPermissionManager = { gTreeUtils.deleteSelectedItems(this._tree, this._view, this._permissions, removedPermissions); for (var i = 0; i < removedPermissions.length; ++i) { var p = removedPermissions[i]; - this._pm.remove(p.host, p.type); - } + this._removePermission(p); + } document.getElementById("removePermission").disabled = !this._permissions.length; document.getElementById("removeAllPermissions").disabled = !this._permissions.length; }, @@ -271,18 +339,23 @@ var gPermissionManager = { gTreeUtils.deleteAll(this._tree, this._view, this._permissions, removedPermissions); for (var i = 0; i < removedPermissions.length; ++i) { var p = removedPermissions[i]; - this._pm.remove(p.host, p.type); - } + this._removePermission(p); + } document.getElementById("removePermission").disabled = true; document.getElementById("removeAllPermissions").disabled = true; }, - + onPermissionKeyPress: function (aEvent) { - if (aEvent.keyCode == 46) + if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE +#ifdef XP_MACOSX + || aEvent.keyCode == KeyEvent.DOM_VK_BACK_SPACE +#endif + ) { this.onPermissionDeleted(); + } }, - + _lastPermissionSortColumn: "", _lastPermissionSortAscending: false, _permissionsComparator : function (a, b) @@ -293,16 +366,34 @@ var gPermissionManager = { onPermissionSort: function (aColumn) { - this._lastPermissionSortAscending = gTreeUtils.sort(this._tree, - this._view, + this._lastPermissionSortAscending = gTreeUtils.sort(this._tree, + this._view, this._permissions, aColumn, this._permissionsComparator, - this._lastPermissionSortColumn, + this._lastPermissionSortColumn, this._lastPermissionSortAscending); this._lastPermissionSortColumn = aColumn; }, - + + onApplyChanges: function() + { + // Stop observing permission changes since we are about + // to write out the pending adds/deletes and don't need + // to update the UI + this.uninit(); + + for (let permissionParams of this._permissionsToAdd.values()) { + Services.perms.addFromPrincipal(permissionParams.principal, permissionParams.type, permissionParams.capability); + } + + for (let p of this._permissionsToDelete.values()) { + Services.perms.removeFromPrincipal(p.principal, p.type); + } + + window.close(); + }, + _loadPermissions: function () { this._tree = document.getElementById("permissionsTree"); @@ -310,48 +401,59 @@ var gPermissionManager = { // load permissions into a table var count = 0; - var enumerator = this._pm.enumerator; + var enumerator = Services.perms.enumerator; while (enumerator.hasMoreElements()) { var nextPermission = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission); this._addPermissionToList(nextPermission); } - + this._view._rowCount = this._permissions.length; // sort and display the table this._tree.view = this._view; - this.onPermissionSort("rawHost"); + this.onPermissionSort("origin"); // disable "remove all" button if there are none document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0; }, - + _addPermissionToList: function (aPermission) { if (aPermission.type == this._type && (!this._manageCapability || (aPermission.capability == this._manageCapability))) { - var host = aPermission.host; + var principal = aPermission.principal; var capabilityString = this._getCapabilityString(aPermission.capability); - var p = new Permission(host, - (host.charAt(0) == ".") ? host.substring(1,host.length) : host, + var p = new Permission(principal, aPermission.type, - capabilityString, - aPermission.capability); + capabilityString); this._permissions.push(p); - } + } }, - - setHost: function (aHost) + + _removePermissionFromList: function (aPrincipal) + { + for (let i = 0; i < this._permissions.length; ++i) { + if (this._permissions[i].principal.equals(aPrincipal)) { + this._permissions.splice(i, 1); + this._view._rowCount--; + this._tree.treeBoxObject.rowCountChanged(this._view.rowCount - 1, -1); + this._tree.treeBoxObject.invalidate(); + break; + } + } + }, + + setOrigin: function (aOrigin) { - document.getElementById("url").value = aHost; + document.getElementById("url").value = aOrigin; } }; -function setHost(aHost) +function setOrigin(aOrigin) { - gPermissionManager.setHost(aHost); + gPermissionManager.setOrigin(aOrigin); } function initWithParams(aParams) diff --git a/application/palemoon/components/preferences/permissions.xul b/application/palemoon/components/preferences/permissions.xul index fd550e8f7..33806cc27 100644 --- a/application/palemoon/components/preferences/permissions.xul +++ b/application/palemoon/components/preferences/permissions.xul @@ -1,12 +1,12 @@ <?xml version="1.0"?> -# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -# 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/. +<!-- -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- --> +<!-- 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/" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?> +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?> <!DOCTYPE dialog SYSTEM "chrome://browser/locale/preferences/permissions.dtd" > @@ -35,7 +35,7 @@ <separator class="thin"/> <label id="urlLabel" control="url" value="&address.label;" accesskey="&address.accesskey;"/> <hbox align="start"> - <textbox id="url" flex="1" + <textbox id="url" flex="1" oninput="gPermissionManager.onHostInput(event.target);" onkeypress="gPermissionManager.onHostKeyPress(event);"/> </hbox> @@ -54,30 +54,32 @@ onselect="gPermissionManager.onPermissionSelected();"> <treecols> <treecol id="siteCol" label="&treehead.sitename.label;" flex="3" - onclick="gPermissionManager.onPermissionSort('rawHost');" persist="width"/> + data-field-name="origin" persist="width"/> <splitter class="tree-splitter"/> <treecol id="statusCol" label="&treehead.status.label;" flex="1" - onclick="gPermissionManager.onPermissionSort('capability');" persist="width"/> + data-field-name="capability" persist="width"/> </treecols> <treechildren/> </tree> </vbox> - <hbox align="end"> - <hbox class="actionButtons" flex="1"> + <vbox> + <hbox class="actionButtons" align="left" flex="1"> <button id="removePermission" disabled="true" accesskey="&removepermission.accesskey;" icon="remove" label="&removepermission.label;" oncommand="gPermissionManager.onPermissionDeleted();"/> <button id="removeAllPermissions" icon="clear" label="&removeallpermissions.label;" - accesskey="&removeallpermissions.accesskey;" + accesskey="&removeallpermissions.accesskey;" oncommand="gPermissionManager.onAllPermissionsDeleted();"/> - <spacer flex="1"/> -#ifndef XP_MACOSX + </hbox> + <spacer flex="1"/> + <hbox class="actionButtons" align="right" flex="1"> <button oncommand="close();" icon="close" - label="&button.close.label;" accesskey="&button.close.accesskey;"/> -#endif + label="&button.cancel.label;" accesskey="&button.cancel.accesskey;" /> + <button id="btnApplyChanges" oncommand="gPermissionManager.onApplyChanges();" icon="save" + label="&button.ok.label;" accesskey="&button.ok.accesskey;"/> </hbox> <resizer type="window" dir="bottomend"/> - </hbox> + </vbox> </window> diff --git a/application/palemoon/components/preferences/security.js b/application/palemoon/components/preferences/security.js index 56664bf66..9d5f302a2 100644 --- a/application/palemoon/components/preferences/security.js +++ b/application/palemoon/components/preferences/security.js @@ -131,9 +131,21 @@ var gSecurityPane = { */ showPasswordExceptions: function () { + let bundlePrefs = document.getElementById("bundlePreferences"); + let params = { + blockVisible: true, + sessionVisible: false, + allowVisible: false, + hideStatusColumn: true, + prefilledHost: "", + permissionType: "login-saving", + windowTitle: bundlePrefs.getString("savedLoginsExceptions_title"), + introText: bundlePrefs.getString("savedLoginsExceptions_desc") + }; + document.documentElement.openWindow("Toolkit:PasswordManagerExceptions", - "chrome://passwordmgr/content/passwordManagerExceptions.xul", - "", null); + "chrome://browser/content/preferences/permissions.xul", + null, params); }, /** diff --git a/application/palemoon/locales/en-US/chrome/browser/browser.properties b/application/palemoon/locales/en-US/chrome/browser/browser.properties index 518f1b0de..7f1c88a88 100644 --- a/application/palemoon/locales/en-US/chrome/browser/browser.properties +++ b/application/palemoon/locales/en-US/chrome/browser/browser.properties @@ -305,6 +305,10 @@ webNotifications.alwaysShow.accesskey=A webNotifications.neverShow=Always Block Notifications webNotifications.neverShow.accesskey=N webNotifications.showFromSite=Would you like to show notifications from %S? +# LOCALIZATION NOTE (webNotifications.upgradeTitle): When using native notifications on OS X, the title may be truncated around 32 characters. +webNotifications.upgradeTitle=Upgraded notifications +# LOCALIZATION NOTE (webNotifications.upgradeBody): When using native notifications on OS X, the body may be truncated around 100 characters in some views. +webNotifications.upgradeBody=You can now receive notifications from sites that are not currently loaded. Click to learn more. # Pointer lock UI diff --git a/application/palemoon/locales/en-US/chrome/browser/preferences/aboutPermissions.dtd b/application/palemoon/locales/en-US/chrome/browser/preferences/aboutPermissions.dtd index ff1da3dd0..9e36520c8 100644 --- a/application/palemoon/locales/en-US/chrome/browser/preferences/aboutPermissions.dtd +++ b/application/palemoon/locales/en-US/chrome/browser/preferences/aboutPermissions.dtd @@ -54,3 +54,5 @@ <!ENTITY fullscreen.label "Fullscreen"> <!ENTITY pointerLock.label "Hide the Mouse Pointer"> + +<!ENTITY focusSearch.key "f"> diff --git a/application/palemoon/locales/en-US/chrome/browser/preferences/cookies.dtd b/application/palemoon/locales/en-US/chrome/browser/preferences/cookies.dtd index 06f57c435..c83331328 100644 --- a/application/palemoon/locales/en-US/chrome/browser/preferences/cookies.dtd +++ b/application/palemoon/locales/en-US/chrome/browser/preferences/cookies.dtd @@ -7,11 +7,6 @@ <!ENTITY cookiesonsystem.label "The following cookies are stored on your computer:"> <!ENTITY cookiename.label "Cookie Name"> <!ENTITY cookiedomain.label "Site"> -<!ENTITY button.removecookies.label "Remove Cookies"> -<!ENTITY button.removecookie.label "Remove Cookie"> -<!ENTITY button.removecookie.accesskey "R"> -<!ENTITY button.removeallcookies.label "Remove All Cookies"> -<!ENTITY button.removeallcookies.accesskey "A"> <!ENTITY props.name.label "Name:"> <!ENTITY props.value.label "Content:"> diff --git a/application/palemoon/locales/en-US/chrome/browser/preferences/permissions.dtd b/application/palemoon/locales/en-US/chrome/browser/preferences/permissions.dtd index f6a9c466c..e61228b76 100644 --- a/application/palemoon/locales/en-US/chrome/browser/preferences/permissions.dtd +++ b/application/palemoon/locales/en-US/chrome/browser/preferences/permissions.dtd @@ -3,7 +3,7 @@ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> <!ENTITY window.title "Exceptions"> -<!ENTITY window.width "36em"> +<!ENTITY window.width "45em"> <!ENTITY treehead.sitename.label "Site"> <!ENTITY treehead.status.label "Status"> @@ -21,6 +21,8 @@ <!ENTITY allow.accesskey "A"> <!ENTITY windowClose.key "w"> -<!ENTITY button.close.label "Close"> -<!ENTITY button.close.accesskey "C"> +<!ENTITY button.cancel.label "Cancel"> +<!ENTITY button.cancel.accesskey "C"> +<!ENTITY button.ok.label "Save Changes"> +<!ENTITY button.ok.accesskey "S"> diff --git a/application/palemoon/locales/en-US/chrome/browser/preferences/preferences.properties b/application/palemoon/locales/en-US/chrome/browser/preferences/preferences.properties index 826f1463d..3eebbcbec 100644 --- a/application/palemoon/locales/en-US/chrome/browser/preferences/preferences.properties +++ b/application/palemoon/locales/en-US/chrome/browser/preferences/preferences.properties @@ -15,7 +15,7 @@ labelDefaultFont=Default (%S) #### Permissions Manager -cookiepermissionstext=You can specify which websites are always or never allowed to use cookies. Type the exact address of the site you want to manage and then click Block, Allow for Session, or Allow. +cookiepermissionstext=You can specify which websites are always or never allowed to use cookies. Type the exact address of the site you want to manage and then click Block, Allow for Session, or Allow. cookiepermissionstitle=Exceptions - Cookies addonspermissionstext=You can specify which websites are allowed to install add-ons. Type the exact address of the site you want to allow and then click Allow. addons_permissions_title=Allowed Sites - Add-ons Installation @@ -23,6 +23,8 @@ popuppermissionstext=You can specify which websites are allowed to open pop-up w popuppermissionstitle=Allowed Sites - Pop-ups invalidURI=Please enter a valid hostname invalidURITitle=Invalid Hostname Entered +savedLoginsExceptions_title=Exceptions - Saved Logins +savedLoginsExceptions_desc=Logins for the following sites will not be saved: #### Master Password @@ -93,9 +95,30 @@ noCookieSelected=<no cookie selected> cookiesAll=The following cookies are stored on your computer: cookiesFiltered=The following cookies match your search: +# LOCALIZATION NOTE (removeAllCookies, removeAllShownCookies): +# removeAllCookies and removeAllShownCookies are both used on the same one button, +# never displayed together and can share the same accesskey. +# When only partial cookies are shown as a result of keyword search, +# removeAllShownCookies is displayed as button label. +# removeAllCookies is displayed when no keyword search and all cookies are shown. +removeAllCookies.label=Remove All +removeAllCookies.accesskey=A +removeAllShownCookies.label=Remove All Shown +removeAllShownCookies.accesskey=A + +# LOCALIZATION NOTE (removeSelectedCookies): +# Semicolon-separated list of plural forms. See: +# http://developer.mozilla.org/en/docs/Localization_and_Plurals +# If you need to display the number of selected elements in your language, +# you can use #1 in your localization as a placeholder for the number. +# For example this is the English string with numbers: +# removeSelectedCookied=Remove #1 Selected;Remove #1 Selected +removeSelectedCookies.label=Remove Selected;Remove Selected +removeSelectedCookies.accesskey=R + #### Offline apps offlineAppRemoveTitle=Remove offline website data -offlineAppRemovePrompt=After removing this data, %S will not be available offline. Are you sure you want to remove this offline website? +offlineAppRemovePrompt=After removing this data, %S will not be available offline. Are you sure you want to remove this offline website? offlineAppRemoveConfirm=Remove offline data # LOCALIZATION NOTE: The next string is for the disk usage of the diff --git a/application/palemoon/modules/PopupNotifications.jsm b/application/palemoon/modules/PopupNotifications.jsm index 15c8915ed..0cb970230 100644 --- a/application/palemoon/modules/PopupNotifications.jsm +++ b/application/palemoon/modules/PopupNotifications.jsm @@ -12,6 +12,7 @@ const NOTIFICATION_EVENT_DISMISSED = "dismissed"; const NOTIFICATION_EVENT_REMOVED = "removed"; const NOTIFICATION_EVENT_SHOWING = "showing"; const NOTIFICATION_EVENT_SHOWN = "shown"; +const NOTIFICATION_EVENT_SWAPPING = "swapping"; const ICON_SELECTOR = ".notification-anchor-icon"; const ICON_ATTRIBUTE_SHOWING = "showing"; @@ -237,9 +238,23 @@ PopupNotifications.prototype = { * tabs) * "removed": notification has been removed (due to * location change or user action) + * "showing": notification is about to be shown + * (this can be fired multiple times as + * notifications are dismissed and re-shown) * "shown": notification has been shown (this can be fired * multiple times as notifications are dismissed * and re-shown) + * "swapping": the docshell of the browser that created + * the notification is about to be swapped to + * another browser. A second parameter contains + * the browser that is receiving the docshell, + * so that the event callback can transfer stuff + * specific to this notification. + * If the callback returns true, the notification + * will be moved to the new browser. + * If the callback isn't implemented, returns false, + * or doesn't return any value, the notification + * will be removed. * neverShow: Indicate that no popup should be shown for this * notification. Useful for just showing the anchor icon. * removeOnDismissal: @@ -829,13 +844,60 @@ PopupNotifications.prototype = { this._update(notifications, anchor); }, - _fireCallback: function PopupNotifications_fireCallback(n, event) { + _swapBrowserNotifications: function PopupNotifications_swapBrowserNoficications(ourBrowser, otherBrowser) { + // When swaping browser docshells (e.g. dragging tab to new window) we need + // to update our notification map. + + let ourNotifications = this._getNotificationsForBrowser(ourBrowser); + let other = otherBrowser.ownerDocument.defaultView.PopupNotifications; + if (!other) { + if (ourNotifications.length > 0) + Cu.reportError("unable to swap notifications: otherBrowser doesn't support notifications"); + return; + } + let otherNotifications = other._getNotificationsForBrowser(otherBrowser); + if (ourNotifications.length < 1 && otherNotifications.length < 1) { + // No notification to swap. + return; + } + + otherNotifications = otherNotifications.filter(n => { + if (this._fireCallback(n, NOTIFICATION_EVENT_SWAPPING, ourBrowser)) { + n.browser = ourBrowser; + n.owner = this; + return true; + } + other._fireCallback(n, NOTIFICATION_EVENT_REMOVED); + return false; + }); + + ourNotifications = ourNotifications.filter(n => { + if (this._fireCallback(n, NOTIFICATION_EVENT_SWAPPING, otherBrowser)) { + n.browser = otherBrowser; + n.owner = other; + return true; + } + this._fireCallback(n, NOTIFICATION_EVENT_REMOVED); + return false; + }); + + this._setNotificationsForBrowser(otherBrowser, ourNotifications); + other._setNotificationsForBrowser(ourBrowser, otherNotifications); + + if (otherNotifications.length > 0) + this._update(otherNotifications, otherNotifications[0].anchorElement); + if (ourNotifications.length > 0) + other._update(ourNotifications, ourNotifications[0].anchorElement); + }, + + _fireCallback: function PopupNotifications_fireCallback(n, event, ...args) { try { if (n.options.eventCallback) - n.options.eventCallback.call(n, event); + return n.options.eventCallback.call(n, event, ...args); } catch (error) { Cu.reportError(error); } + return undefined; }, _onPopupHidden: function PopupNotifications_onPopupHidden(event) { diff --git a/application/palemoon/modules/webrtcUI.jsm b/application/palemoon/modules/webrtcUI.jsm index c957bfd9a..819ca181f 100644 --- a/application/palemoon/modules/webrtcUI.jsm +++ b/application/palemoon/modules/webrtcUI.jsm @@ -11,9 +11,11 @@ const Cc = Components.classes; const Ci = Components.interfaces; Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/PluralForm.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", + "resource://gre/modules/PluralForm.jsm"); + XPCOMUtils.defineLazyServiceGetter(this, "MediaManagerService", "@mozilla.org/mediaManagerService;1", "nsIMediaManagerService"); @@ -128,62 +130,14 @@ function prompt(aWindowID, aCallID, aAudioRequested, aVideoRequested, aDevices) let message = stringBundle.getFormattedString("getUserMedia.share" + requestType + ".message", [ host ]); - function listDevices(menupopup, devices) { - while (menupopup.lastChild) - menupopup.removeChild(menupopup.lastChild); - - let deviceIndex = 0; - for (let device of devices) { - addDeviceToList(menupopup, device.name, deviceIndex); - deviceIndex++; - } - } - - function addDeviceToList(menupopup, deviceName, deviceIndex) { - let menuitem = chromeDoc.createElement("menuitem"); - menuitem.setAttribute("value", deviceIndex); - menuitem.setAttribute("label", deviceName); - menuitem.setAttribute("tooltiptext", deviceName); - menupopup.appendChild(menuitem); - } - - chromeDoc.getElementById("webRTC-selectCamera").hidden = !videoDevices.length; - chromeDoc.getElementById("webRTC-selectMicrophone").hidden = !audioDevices.length; - - let camMenupopup = chromeDoc.getElementById("webRTC-selectCamera-menupopup"); - let micMenupopup = chromeDoc.getElementById("webRTC-selectMicrophone-menupopup"); - listDevices(camMenupopup, videoDevices); - listDevices(micMenupopup, audioDevices); - if (requestType == "CameraAndMicrophone") { - addDeviceToList(camMenupopup, stringBundle.getString("getUserMedia.noVideo.label"), "-1"); - addDeviceToList(micMenupopup, stringBundle.getString("getUserMedia.noAudio.label"), "-1"); - } - let mainAction = { label: PluralForm.get(requestType == "CameraAndMicrophone" ? 2 : 1, stringBundle.getString("getUserMedia.shareSelectedDevices.label")), accessKey: stringBundle.getString("getUserMedia.shareSelectedDevices.accesskey"), - callback: function () { - let allowedDevices = Cc["@mozilla.org/supports-array;1"] - .createInstance(Ci.nsISupportsArray); - if (videoDevices.length) { - let videoDeviceIndex = chromeDoc.getElementById("webRTC-selectCamera-menulist").value; - if (videoDeviceIndex != "-1") - allowedDevices.AppendElement(videoDevices[videoDeviceIndex]); - } - if (audioDevices.length) { - let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value; - if (audioDeviceIndex != "-1") - allowedDevices.AppendElement(audioDevices[audioDeviceIndex]); - } - - if (allowedDevices.Count() == 0) { - denyRequest(aCallID); - return; - } - - Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID); - } + // The real callback will be set during the "showing" event. The + // empty function here is so that PopupNotifications.show doesn't + // reject the action. + callback: function() {} }; let secondaryActions = [{ @@ -194,7 +148,72 @@ function prompt(aWindowID, aCallID, aAudioRequested, aVideoRequested, aDevices) } }]; - let options = null; + let options = { + eventCallback: function(aTopic, aNewBrowser) { + if (aTopic == "swapping") + return true; + + if (aTopic != "showing") + return false; + + let chromeDoc = this.browser.ownerDocument; + + function listDevices(menupopup, devices) { + while (menupopup.lastChild) + menupopup.removeChild(menupopup.lastChild); + + let deviceIndex = 0; + for (let device of devices) { + addDeviceToList(menupopup, device.name, deviceIndex); + deviceIndex++; + } + } + + function addDeviceToList(menupopup, deviceName, deviceIndex) { + let menuitem = chromeDoc.createElement("menuitem"); + menuitem.setAttribute("value", deviceIndex); + menuitem.setAttribute("label", deviceName); + menuitem.setAttribute("tooltiptext", deviceName); + menupopup.appendChild(menuitem); + } + + chromeDoc.getElementById("webRTC-selectCamera").hidden = !videoDevices.length; + chromeDoc.getElementById("webRTC-selectMicrophone").hidden = !audioDevices.length; + + let camMenupopup = chromeDoc.getElementById("webRTC-selectCamera-menupopup"); + let micMenupopup = chromeDoc.getElementById("webRTC-selectMicrophone-menupopup"); + listDevices(camMenupopup, videoDevices); + listDevices(micMenupopup, audioDevices); + if (requestType == "CameraAndMicrophone") { + let stringBundle = chromeDoc.defaultView.gNavigatorBundle; + addDeviceToList(camMenupopup, stringBundle.getString("getUserMedia.noVideo.label"), "-1"); + addDeviceToList(micMenupopup, stringBundle.getString("getUserMedia.noAudio.label"), "-1"); + } + + this.mainAction.callback = function() { + let allowedDevices = Cc["@mozilla.org/supports-array;1"] + .createInstance(Ci.nsISupportsArray); + if (videoDevices.length) { + let videoDeviceIndex = chromeDoc.getElementById("webRTC-selectCamera-menulist").value; + if (videoDeviceIndex != "-1") + allowedDevices.AppendElement(videoDevices[videoDeviceIndex]); + } + if (audioDevices.length) { + let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value; + if (audioDeviceIndex != "-1") + allowedDevices.AppendElement(audioDevices[audioDeviceIndex]); + } + + if (allowedDevices.Count() == 0) { + denyRequest(aCallID); + return; + } + + Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID); + }; + return true; + } + }; chromeWin.PopupNotifications.show(browser, "webRTC-shareDevices", message, "webRTC-shareDevices-notification-icon", mainAction, @@ -254,7 +273,8 @@ function showBrowserSpecificIndicator(aBrowser) { }]; let options = { hideNotNow: true, - dismissed: true + dismissed: true, + eventCallback: function(aTopic) aTopic == "swapping" }; chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingDevices", message, "webRTC-sharingDevices-notification-icon", mainAction, diff --git a/application/palemoon/themes/linux/Push-16.png b/application/palemoon/themes/linux/Push-16.png Binary files differnew file mode 100644 index 000000000..082b17781 --- /dev/null +++ b/application/palemoon/themes/linux/Push-16.png diff --git a/application/palemoon/themes/linux/Push-64.png b/application/palemoon/themes/linux/Push-64.png Binary files differnew file mode 100644 index 000000000..6e09ab9c3 --- /dev/null +++ b/application/palemoon/themes/linux/Push-64.png diff --git a/application/palemoon/themes/linux/browser.css b/application/palemoon/themes/linux/browser.css index 4f4964db8..131a63a90 100644 --- a/application/palemoon/themes/linux/browser.css +++ b/application/palemoon/themes/linux/browser.css @@ -1169,6 +1169,10 @@ toolbar[iconsize="small"] #webrtc-status-button { list-style-image: url(chrome://browser/skin/Geolocation-64.png); } +.popup-notification-icon[popupid="push"] { + list-style-image: url(chrome://browser/skin/Push-64.png); +} + .popup-notification-icon[popupid="xpinstall-disabled"], .popup-notification-icon[popupid="addon-progress"], .popup-notification-icon[popupid="addon-install-cancelled"], @@ -1288,6 +1292,10 @@ toolbar[iconsize="small"] #webrtc-status-button { list-style-image: url(chrome://browser/skin/Geolocation-16.png); } +#push-notification-icon { + list-style-image: url(chrome://browser/skin/Push-16.png); +} + #addons-notification-icon { list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png); } @@ -1374,7 +1382,18 @@ toolbar[iconsize="small"] #webrtc-status-button { .web-notifications-notification-icon, #web-notifications-notification-icon { - list-style-image: url(chrome://browser/skin/notification-16.png); + list-style-image: url(chrome://browser/skin/web-notifications-tray.svg); + -moz-image-region: rect(0, 16px, 16px, 0); +} + +.web-notifications-notification-icon:hover, +#web-notifications-notification-icon:hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +.web-notifications-notification-icon:hover:active, +#web-notifications-notification-icon:hover:active { + -moz-image-region: rect(0, 48px, 16px, 32px); } #pointerLock-notification-icon { diff --git a/application/palemoon/themes/linux/jar.mn b/application/palemoon/themes/linux/jar.mn index 7e67d0129..3c2ac406e 100644 --- a/application/palemoon/themes/linux/jar.mn +++ b/application/palemoon/themes/linux/jar.mn @@ -36,8 +36,6 @@ browser.jar: skin/classic/browser/mixed-content-blocked-64.png skin/classic/browser/monitor.png skin/classic/browser/monitor_16-10.png - skin/classic/browser/notification-16.png - skin/classic/browser/notification-64.png * skin/classic/browser/pageInfo.css skin/classic/browser/pageInfo.png skin/classic/browser/page-livemarks.png @@ -54,6 +52,8 @@ browser.jar: skin/classic/browser/Toolbar.png skin/classic/browser/Toolbar-small.png skin/classic/browser/urlbar-arrow.png + skin/classic/browser/web-notifications-icon.svg + skin/classic/browser/web-notifications-tray.svg #ifdef MOZ_WEBRTC skin/classic/browser/webRTC-shareDevice-16.png skin/classic/browser/webRTC-shareDevice-64.png diff --git a/application/palemoon/themes/linux/notification-16.png b/application/palemoon/themes/linux/notification-16.png Binary files differdeleted file mode 100644 index 6b2df7341..000000000 --- a/application/palemoon/themes/linux/notification-16.png +++ /dev/null diff --git a/application/palemoon/themes/linux/notification-64.png b/application/palemoon/themes/linux/notification-64.png Binary files differdeleted file mode 100644 index a01d0ab77..000000000 --- a/application/palemoon/themes/linux/notification-64.png +++ /dev/null diff --git a/application/palemoon/themes/linux/preferences/aboutPermissions.css b/application/palemoon/themes/linux/preferences/aboutPermissions.css index 406568831..224c88018 100644 --- a/application/palemoon/themes/linux/preferences/aboutPermissions.css +++ b/application/palemoon/themes/linux/preferences/aboutPermissions.css @@ -90,7 +90,7 @@ list-style-image: url(chrome://global/skin/icons/question-64.png); } .pref-icon[type="desktop-notification"] { - list-style-image: url(chrome://browser/skin/notification-64.png); + list-style-image: url(chrome://browser/skin/web-notifications-icon.svg); } .pref-icon[type="install"] { list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png); diff --git a/application/palemoon/themes/linux/web-notifications-icon.svg b/application/palemoon/themes/linux/web-notifications-icon.svg new file mode 100644 index 000000000..f7186c727 --- /dev/null +++ b/application/palemoon/themes/linux/web-notifications-icon.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="64" height="64" viewBox="0 0 64 64"> + <defs> + <style> + .icon { + fill: #a6a6a6; + fill-rule: evenodd; + } + </style> + </defs> + <path d="M57,48 L46,48 L46,60.016 L32.482,48 L7,48 C5.343,48 4,46.657 4,45 L4,11.031 C4,9.374 5.343,8.031 7,8.031 L57,8.031 C58.657,8.031 60,9.374 60,11.031 L60,45 C60,46.657 58.657,48 57,48 ZM36,16.031 C36,14.927 35.105,14.031 34,14.031 L30,14.031 C28.895,14.031 28,14.927 28,16.031 L28,30.031 C28,31.136 28.895,32.031 30,32.031 L34,32.031 C35.105,32.031 36,31.136 36,30.031 L36,16.031 ZM36,37.5 C36,36.672 35.328,36 34.5,36 L29.5,36 C28.672,36 28,36.672 28,37.5 L28,40.5 C28,41.328 28.672,42 29.5,42 L34.5,42 C35.328,42 36,41.328 36,40.5 L36,37.5 Z" class="icon"/> +</svg> diff --git a/application/palemoon/themes/linux/web-notifications-tray.svg b/application/palemoon/themes/linux/web-notifications-tray.svg new file mode 100644 index 000000000..314026a10 --- /dev/null +++ b/application/palemoon/themes/linux/web-notifications-tray.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="16" viewBox="0 0 96 32"> + <defs> + <style> + .style-icon-notification { + fill: #666666; + } + .style-icon-notification.hover { + fill: #808080; + } + .style-icon-notification.active { + fill: #4d4d4d; + } + </style> + <path id="shape-notifcations-push" d="M27,23.969 L24,23.969 L24,29.977 L17.241,23.969 L5,23.969 C3.343,23.969 2,22.626 2,20.969 L2,6.969 C2,5.312 3.343,3.969 5,3.969 L27,3.969 C28.657,3.969 30,5.312 30,6.969 L30,20.969 C30,22.626 28.657,23.969 27,23.969 ZM18,8.969 C18,7.864 17.105,6.969 16,6.969 C14.895,6.969 14,7.864 14,8.969 L14,13.969 C14,15.073 14.895,15.969 16,15.969 C17.105,15.969 18,15.073 18,13.969 L18,8.969 ZM16.5,17.969 L15.5,17.969 C14.672,17.969 14,18.640 14,19.469 C14,20.297 14.672,20.969 15.5,20.969 L16.5,20.969 C17.328,20.969 18,20.297 18,19.469 C18,18.640 17.328,17.969 16.5,17.969 Z"/> + </defs> + <use xlink:href="#shape-notifcations-push" class="style-icon-notification"/> + <use xlink:href="#shape-notifcations-push" transform="translate(32)" class="style-icon-notification hover"/> + <use xlink:href="#shape-notifcations-push" transform="translate(64)" class="style-icon-notification active"/> +</svg> diff --git a/application/palemoon/themes/osx/Push-16.png b/application/palemoon/themes/osx/Push-16.png Binary files differnew file mode 100644 index 000000000..54ef8f8ea --- /dev/null +++ b/application/palemoon/themes/osx/Push-16.png diff --git a/application/palemoon/themes/osx/Push-64.png b/application/palemoon/themes/osx/Push-64.png Binary files differnew file mode 100644 index 000000000..099b9c76f --- /dev/null +++ b/application/palemoon/themes/osx/Push-64.png diff --git a/application/palemoon/themes/osx/browser.css b/application/palemoon/themes/osx/browser.css index 8d709d8e1..58443fa76 100644 --- a/application/palemoon/themes/osx/browser.css +++ b/application/palemoon/themes/osx/browser.css @@ -1975,6 +1975,10 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { list-style-image: url(chrome://browser/skin/Geolocation-16.png); } +#push-notification-icon { + list-style-image: url(chrome://browser/skin/Push-16.png); +} + #addons-notification-icon { list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png); } @@ -2061,7 +2065,18 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { .web-notifications-notification-icon, #web-notifications-notification-icon { - list-style-image: url(chrome://browser/skin/notification-16.png); + list-style-image: url(chrome://browser/skin/web-notifications-tray.svg); + -moz-image-region: rect(0, 16px, 16px, 0); +} + +.web-notifications-notification-icon:hover, +#web-notifications-notification-icon:hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +.web-notifications-notification-icon:hover:active, +#web-notifications-notification-icon:hover:active { + -moz-image-region: rect(0, 48px, 16px, 32px); } #pointerLock-notification-icon { diff --git a/application/palemoon/themes/osx/jar.mn b/application/palemoon/themes/osx/jar.mn index 186cd8a75..a085c5f81 100644 --- a/application/palemoon/themes/osx/jar.mn +++ b/application/palemoon/themes/osx/jar.mn @@ -41,8 +41,6 @@ browser.jar: skin/classic/browser/mixed-content-blocked-64.png skin/classic/browser/monitor.png skin/classic/browser/monitor_16-10.png - skin/classic/browser/notification-16.png - skin/classic/browser/notification-64.png skin/classic/browser/pageInfo.css skin/classic/browser/pageInfo.png skin/classic/browser/page-livemarks.png @@ -70,6 +68,8 @@ browser.jar: skin/classic/browser/urlbar-history-dropmarker.png skin/classic/browser/webapps-16.png skin/classic/browser/webapps-64.png + skin/classic/browser/web-notifications-icon.svg + skin/classic/browser/web-notifications-tray.svg skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png) skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png) skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png) diff --git a/application/palemoon/themes/osx/notification-16.png b/application/palemoon/themes/osx/notification-16.png Binary files differdeleted file mode 100644 index 6b2df7341..000000000 --- a/application/palemoon/themes/osx/notification-16.png +++ /dev/null diff --git a/application/palemoon/themes/osx/notification-64.png b/application/palemoon/themes/osx/notification-64.png Binary files differdeleted file mode 100644 index a01d0ab77..000000000 --- a/application/palemoon/themes/osx/notification-64.png +++ /dev/null diff --git a/application/palemoon/themes/osx/preferences/aboutPermissions.css b/application/palemoon/themes/osx/preferences/aboutPermissions.css index cfb941bbb..a97e71e04 100644 --- a/application/palemoon/themes/osx/preferences/aboutPermissions.css +++ b/application/palemoon/themes/osx/preferences/aboutPermissions.css @@ -93,7 +93,7 @@ list-style-image: url(chrome://global/skin/icons/question-64.png); } .pref-icon[type="desktop-notification"] { - list-style-image: url(chrome://browser/skin/notification-64.png); + list-style-image: url(chrome://browser/skin/web-notifications-icon.svg); } .pref-icon[type="install"] { list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png); diff --git a/application/palemoon/themes/osx/web-notifications-icon.svg b/application/palemoon/themes/osx/web-notifications-icon.svg new file mode 100644 index 000000000..f7186c727 --- /dev/null +++ b/application/palemoon/themes/osx/web-notifications-icon.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="64" height="64" viewBox="0 0 64 64"> + <defs> + <style> + .icon { + fill: #a6a6a6; + fill-rule: evenodd; + } + </style> + </defs> + <path d="M57,48 L46,48 L46,60.016 L32.482,48 L7,48 C5.343,48 4,46.657 4,45 L4,11.031 C4,9.374 5.343,8.031 7,8.031 L57,8.031 C58.657,8.031 60,9.374 60,11.031 L60,45 C60,46.657 58.657,48 57,48 ZM36,16.031 C36,14.927 35.105,14.031 34,14.031 L30,14.031 C28.895,14.031 28,14.927 28,16.031 L28,30.031 C28,31.136 28.895,32.031 30,32.031 L34,32.031 C35.105,32.031 36,31.136 36,30.031 L36,16.031 ZM36,37.5 C36,36.672 35.328,36 34.5,36 L29.5,36 C28.672,36 28,36.672 28,37.5 L28,40.5 C28,41.328 28.672,42 29.5,42 L34.5,42 C35.328,42 36,41.328 36,40.5 L36,37.5 Z" class="icon"/> +</svg> diff --git a/application/palemoon/themes/osx/web-notifications-tray.svg b/application/palemoon/themes/osx/web-notifications-tray.svg new file mode 100644 index 000000000..314026a10 --- /dev/null +++ b/application/palemoon/themes/osx/web-notifications-tray.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="16" viewBox="0 0 96 32"> + <defs> + <style> + .style-icon-notification { + fill: #666666; + } + .style-icon-notification.hover { + fill: #808080; + } + .style-icon-notification.active { + fill: #4d4d4d; + } + </style> + <path id="shape-notifcations-push" d="M27,23.969 L24,23.969 L24,29.977 L17.241,23.969 L5,23.969 C3.343,23.969 2,22.626 2,20.969 L2,6.969 C2,5.312 3.343,3.969 5,3.969 L27,3.969 C28.657,3.969 30,5.312 30,6.969 L30,20.969 C30,22.626 28.657,23.969 27,23.969 ZM18,8.969 C18,7.864 17.105,6.969 16,6.969 C14.895,6.969 14,7.864 14,8.969 L14,13.969 C14,15.073 14.895,15.969 16,15.969 C17.105,15.969 18,15.073 18,13.969 L18,8.969 ZM16.5,17.969 L15.5,17.969 C14.672,17.969 14,18.640 14,19.469 C14,20.297 14.672,20.969 15.5,20.969 L16.5,20.969 C17.328,20.969 18,20.297 18,19.469 C18,18.640 17.328,17.969 16.5,17.969 Z"/> + </defs> + <use xlink:href="#shape-notifcations-push" class="style-icon-notification"/> + <use xlink:href="#shape-notifcations-push" transform="translate(32)" class="style-icon-notification hover"/> + <use xlink:href="#shape-notifcations-push" transform="translate(64)" class="style-icon-notification active"/> +</svg> diff --git a/application/palemoon/themes/windows/Push-16.png b/application/palemoon/themes/windows/Push-16.png Binary files differnew file mode 100644 index 000000000..d710e7336 --- /dev/null +++ b/application/palemoon/themes/windows/Push-16.png diff --git a/application/palemoon/themes/windows/Push-64.png b/application/palemoon/themes/windows/Push-64.png Binary files differnew file mode 100644 index 000000000..27fecb858 --- /dev/null +++ b/application/palemoon/themes/windows/Push-64.png diff --git a/application/palemoon/themes/windows/browser.css b/application/palemoon/themes/windows/browser.css index 1c51accae..3d519ba85 100644 --- a/application/palemoon/themes/windows/browser.css +++ b/application/palemoon/themes/windows/browser.css @@ -2548,7 +2548,18 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { .web-notifications-notification-icon, #web-notifications-notification-icon { - list-style-image: url(chrome://browser/skin/notification-16.png); + list-style-image: url(chrome://browser/skin/web-notifications-tray.svg); + -moz-image-region: rect(0, 16px, 16px, 0); +} + +.web-notifications-notification-icon:hover, +#web-notifications-notification-icon:hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +.web-notifications-notification-icon:hover:active, +#web-notifications-notification-icon:hover:active { + -moz-image-region: rect(0, 48px, 16px, 32px); } #pointerLock-notification-icon { diff --git a/application/palemoon/themes/windows/jar.mn b/application/palemoon/themes/windows/jar.mn index a66714b13..8c0d9a5cc 100644 --- a/application/palemoon/themes/windows/jar.mn +++ b/application/palemoon/themes/windows/jar.mn @@ -42,8 +42,6 @@ browser.jar: skin/classic/browser/mixed-content-blocked-64.png skin/classic/browser/monitor.png skin/classic/browser/monitor_16-10.png - skin/classic/browser/notification-16.png - skin/classic/browser/notification-64.png skin/classic/browser/pageInfo.css skin/classic/browser/pageInfo.png skin/classic/browser/page-livemarks.png (feeds/feedIcon16.png) @@ -72,6 +70,8 @@ browser.jar: skin/classic/browser/urlbar-history-dropmarker.png skin/classic/browser/webapps-16.png skin/classic/browser/webapps-64.png + skin/classic/browser/web-notifications-icon.svg + skin/classic/browser/web-notifications-tray.svg skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png) skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png) skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png) diff --git a/application/palemoon/themes/windows/notification-16.png b/application/palemoon/themes/windows/notification-16.png Binary files differdeleted file mode 100644 index 6b2df7341..000000000 --- a/application/palemoon/themes/windows/notification-16.png +++ /dev/null diff --git a/application/palemoon/themes/windows/notification-64.png b/application/palemoon/themes/windows/notification-64.png Binary files differdeleted file mode 100644 index a01d0ab77..000000000 --- a/application/palemoon/themes/windows/notification-64.png +++ /dev/null diff --git a/application/palemoon/themes/windows/preferences/aboutPermissions.css b/application/palemoon/themes/windows/preferences/aboutPermissions.css index d9db6ccbf..73b8d6e14 100644 --- a/application/palemoon/themes/windows/preferences/aboutPermissions.css +++ b/application/palemoon/themes/windows/preferences/aboutPermissions.css @@ -93,7 +93,7 @@ list-style-image: url(chrome://global/skin/icons/question-48.png); } .pref-icon[type="desktop-notification"] { - list-style-image: url(chrome://browser/skin/notification-64.png); + list-style-image: url(chrome://browser/skin/web-notifications-icon.svg); } .pref-icon[type="install"] { list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-48.png); diff --git a/application/palemoon/themes/windows/web-notifications-icon.svg b/application/palemoon/themes/windows/web-notifications-icon.svg new file mode 100644 index 000000000..f7186c727 --- /dev/null +++ b/application/palemoon/themes/windows/web-notifications-icon.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="64" height="64" viewBox="0 0 64 64"> + <defs> + <style> + .icon { + fill: #a6a6a6; + fill-rule: evenodd; + } + </style> + </defs> + <path d="M57,48 L46,48 L46,60.016 L32.482,48 L7,48 C5.343,48 4,46.657 4,45 L4,11.031 C4,9.374 5.343,8.031 7,8.031 L57,8.031 C58.657,8.031 60,9.374 60,11.031 L60,45 C60,46.657 58.657,48 57,48 ZM36,16.031 C36,14.927 35.105,14.031 34,14.031 L30,14.031 C28.895,14.031 28,14.927 28,16.031 L28,30.031 C28,31.136 28.895,32.031 30,32.031 L34,32.031 C35.105,32.031 36,31.136 36,30.031 L36,16.031 ZM36,37.5 C36,36.672 35.328,36 34.5,36 L29.5,36 C28.672,36 28,36.672 28,37.5 L28,40.5 C28,41.328 28.672,42 29.5,42 L34.5,42 C35.328,42 36,41.328 36,40.5 L36,37.5 Z" class="icon"/> +</svg> diff --git a/application/palemoon/themes/windows/web-notifications-tray.svg b/application/palemoon/themes/windows/web-notifications-tray.svg new file mode 100644 index 000000000..314026a10 --- /dev/null +++ b/application/palemoon/themes/windows/web-notifications-tray.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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/. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="16" viewBox="0 0 96 32"> + <defs> + <style> + .style-icon-notification { + fill: #666666; + } + .style-icon-notification.hover { + fill: #808080; + } + .style-icon-notification.active { + fill: #4d4d4d; + } + </style> + <path id="shape-notifcations-push" d="M27,23.969 L24,23.969 L24,29.977 L17.241,23.969 L5,23.969 C3.343,23.969 2,22.626 2,20.969 L2,6.969 C2,5.312 3.343,3.969 5,3.969 L27,3.969 C28.657,3.969 30,5.312 30,6.969 L30,20.969 C30,22.626 28.657,23.969 27,23.969 ZM18,8.969 C18,7.864 17.105,6.969 16,6.969 C14.895,6.969 14,7.864 14,8.969 L14,13.969 C14,15.073 14.895,15.969 16,15.969 C17.105,15.969 18,15.073 18,13.969 L18,8.969 ZM16.5,17.969 L15.5,17.969 C14.672,17.969 14,18.640 14,19.469 C14,20.297 14.672,20.969 15.5,20.969 L16.5,20.969 C17.328,20.969 18,20.297 18,19.469 C18,18.640 17.328,17.969 16.5,17.969 Z"/> + </defs> + <use xlink:href="#shape-notifcations-push" class="style-icon-notification"/> + <use xlink:href="#shape-notifcations-push" transform="translate(32)" class="style-icon-notification hover"/> + <use xlink:href="#shape-notifcations-push" transform="translate(64)" class="style-icon-notification active"/> +</svg> |