diff --git a/locales/en-US/browser/browser/zen-general.ftl b/locales/en-US/browser/browser/zen-general.ftl index 9eb37a583..37a35a77b 100644 --- a/locales/en-US/browser/browser/zen-general.ftl +++ b/locales/en-US/browser/browser/zen-general.ftl @@ -89,3 +89,8 @@ zen-site-data-get-addons = .label = Add Extensions zen-site-data-site-settings = .label = All Site Settings + +zen-site-data-setting-site-protection = Site Protection + +zen-site-data-panel-feature-callout-title = A new home for add-ons, permissions, and more +zen-site-data-panel-feature-callout-subtitle = Click the icon to manage site settings, view security info, access extensions, and perform common actions. diff --git a/prefs/browser.yaml b/prefs/browser.yaml index 30aa603e9..7c8c8dfcd 100644 --- a/prefs/browser.yaml +++ b/prefs/browser.yaml @@ -78,6 +78,7 @@ value: false - name: browser.tabs.groups.hoverPreview.enabled + locked: true value: false - name: browser.tabs.closeWindowWithLastTab diff --git a/src/browser/base/content/browser-siteIdentity-js.patch b/src/browser/base/content/browser-siteIdentity-js.patch index 0da25c7ce..ac751474b 100644 --- a/src/browser/base/content/browser-siteIdentity-js.patch +++ b/src/browser/base/content/browser-siteIdentity-js.patch @@ -1,8 +1,20 @@ diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js -index 65354e0ad3097e10de72f36e257c94472524baf7..bc9527ec9ddfab11c0839398d3f3953872ad9632 100644 +index 65354e0ad3097e10de72f36e257c94472524baf7..866cf5672f30f81a1d8e061c9af0c1af5fbb5fb2 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js -@@ -834,7 +834,7 @@ var gIdentityHandler = { +@@ -453,11 +453,6 @@ var gIdentityHandler = { + // avoid a pretty ugly transition. Also hide it even + // if the update resulted in no site data, to keep the + // illusion that clicking the button had an effect. +- let hidden = new Promise(c => { +- this._identityPopup.addEventListener("popuphidden", c, { once: true }); +- }); +- PanelMultiView.hidePopup(this._identityPopup); +- await hidden; + + let baseDomain = SiteDataManager.getBaseDomainFromHost(this._uri.host); + if (SiteDataManager.promptSiteDataRemoval(window, [baseDomain])) { +@@ -834,7 +829,7 @@ var gIdentityHandler = { // This is a secure internal Firefox page. this._identityBox.className = "chromeUI"; let brandBundle = document.getElementById("bundle_brand"); @@ -11,7 +23,7 @@ index 65354e0ad3097e10de72f36e257c94472524baf7..bc9527ec9ddfab11c0839398d3f39538 } else if (this._pageExtensionPolicy) { // This is a WebExtension page. this._identityBox.className = "extensionPage"; -@@ -1163,6 +1163,12 @@ var gIdentityHandler = { +@@ -1163,6 +1158,12 @@ var gIdentityHandler = { } } diff --git a/src/browser/components/BrowserContentHandler-sys-mjs.patch b/src/browser/components/BrowserContentHandler-sys-mjs.patch deleted file mode 100644 index 4d2cdfa8f..000000000 --- a/src/browser/components/BrowserContentHandler-sys-mjs.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/browser/components/BrowserContentHandler.sys.mjs b/browser/components/BrowserContentHandler.sys.mjs -index aeb53582c895d3d495dca2702da3043cf761714c..86859f25ac9c0cb20da24d1f84775f99c9092016 100644 ---- a/browser/components/BrowserContentHandler.sys.mjs -+++ b/browser/components/BrowserContentHandler.sys.mjs -@@ -1276,6 +1276,7 @@ function maybeRecordToHandleTelemetry(uri, isLaunch) { - ".avif", - ".htm", - ".html", -+ ".jxl", - ".pdf", - ".shtml", - ".xht", diff --git a/src/browser/themes/shared/zen-icons/icons.css b/src/browser/themes/shared/zen-icons/icons.css index e5c7002bd..0acac3084 100644 --- a/src/browser/themes/shared/zen-icons/icons.css +++ b/src/browser/themes/shared/zen-icons/icons.css @@ -327,7 +327,8 @@ #urlbar-input-container[pageproxystate='valid'] > #tracking-protection-icon-container > #tracking-protection-icon-box - > #tracking-protection-icon { + > #tracking-protection-icon, +.zen-permission-shield-icon { list-style-image: url('tracking-protection.svg') !important; } @@ -481,7 +482,7 @@ } #identity-permission-box, -#identity-box:not([pageproxystate='invalid']) #identity-icon-box, +#identity-box:not([pageproxystate='invalid']) #identity-icon-box:not([open]), #identity-box[pageproxystate='invalid'] #zen-site-data-icon-button { display: none !important; } diff --git a/src/zen/common/ZenUIMigration.sys.mjs b/src/zen/common/ZenUIMigration.sys.mjs index 52fba005d..c073c59c5 100644 --- a/src/zen/common/ZenUIMigration.sys.mjs +++ b/src/zen/common/ZenUIMigration.sys.mjs @@ -6,7 +6,7 @@ const { AppConstants } = ChromeUtils.importESModule('resource://gre/modules/AppC class nsZenUIMigration { PREF_NAME = 'zen.ui.migration.version'; - MIGRATION_VERSION = 4; + MIGRATION_VERSION = 5; init(isNewProfile) { if (!isNewProfile) { @@ -85,6 +85,10 @@ class nsZenUIMigration { Services.prefs.getBoolPref('zen.theme.use-sysyem-colors', false) ); } + + _migrateV5() { + Services.prefs.setBoolPref('zen.site-data-panel.show-callout', true); + } } export var gZenUIMigration = new nsZenUIMigration(); diff --git a/src/zen/urlbar/ZenSiteDataPanel.sys.mjs b/src/zen/urlbar/ZenSiteDataPanel.sys.mjs index c42bd84d0..4ceab2229 100644 --- a/src/zen/urlbar/ZenSiteDataPanel.sys.mjs +++ b/src/zen/urlbar/ZenSiteDataPanel.sys.mjs @@ -4,9 +4,16 @@ import { AppConstants } from 'resource://gre/modules/AppConstants.sys.mjs'; +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + FeatureCallout: 'resource:///modules/asrouter/FeatureCallout.sys.mjs', +}); + export class nsZenSiteDataPanel { #iconMap = { install: 'extension', + 'site-protection': 'shield', }; constructor(window) { @@ -25,7 +32,7 @@ export class nsZenSiteDataPanel { `); this.anchor = button.querySelector('#zen-site-data-icon-button'); - this.document.getElementById('identity-icon-box').after(button); + this.document.getElementById('identity-icon-box').before(button); this.window.gUnifiedExtensions._button = this.anchor; this.document @@ -36,6 +43,7 @@ export class nsZenSiteDataPanel { this.document.getElementById('unified-extensions-panel-template').remove(); this.#initEventListeners(); + this.#maybeShowFeatureCallout(); } #initEventListeners() { @@ -159,7 +167,7 @@ export class nsZenSiteDataPanel { permissions .map(function (permission) { let [id, key] = permission.id.split(SitePermissions.PERM_KEY_DELIMITER); - if (id == '3rdPartyFrameStorage') { + if (id == '3rdPartyFrameStorage' || id == '3rdPartyStorage') { return key; } return null; @@ -237,6 +245,20 @@ export class nsZenSiteDataPanel { } } + // Add site protection permissions if needed. + const { gProtectionsHandler } = this.window; + if ( + gBrowser.currentURI.schemeIs('http') || + gBrowser.currentURI.schemeIs('https') || + gBrowser.currentURI.schemeIs('ftp') + ) { + permissions.push({ + id: 'site-protection', + state: gProtectionsHandler.hasException ? SitePermissions.BLOCK : SitePermissions.ALLOW, + scope: SitePermissions.SCOPE_PERSISTENT, + }); + } + list.innerHTML = ''; for (let permission of permissions) { let [id, key] = permission.id.split(SitePermissions.PERM_KEY_DELIMITER); @@ -307,10 +329,11 @@ export class nsZenSiteDataPanel { nameLabel.setAttribute('flex', '1'); nameLabel.setAttribute('class', 'permission-popup-permission-label'); let label = SitePermissions.getPermissionLabel(permission.id); - if (label === null) { - return null; + if (label) { + nameLabel.textContent = label; + } else { + this.document.l10n.setAttributes(nameLabel, 'zen-site-data-setting-' + idNoSuffix); } - nameLabel.textContent = label; labelContainer.appendChild(nameLabel); let stateLabel = this.document.createXULElement('label'); @@ -338,7 +361,7 @@ export class nsZenSiteDataPanel { break; } case 'zen-site-data-security-info': { - this.window.displaySecurityInfo(); + this.window.gIdentityHandler._openPopup(event); break; } case 'zen-site-data-actions': { @@ -399,7 +422,16 @@ export class nsZenSiteDataPanel { return; } - SitePermissions.setForPrincipal(gBrowser.contentPrincipal, permission.id, newState); + if (permission.id === 'site-protection') { + const { gProtectionsHandler } = this.window; + if (newState === SitePermissions.BLOCK) { + gProtectionsHandler.disableForCurrentPage(); + } else { + gProtectionsHandler.enableForCurrentPage(); + } + } else { + SitePermissions.setForPrincipal(gBrowser.contentPrincipal, permission.id, newState); + } label.parentNode.setAttribute('state', newState == SitePermissions.ALLOW ? 'allow' : 'block'); label @@ -445,4 +477,85 @@ export class nsZenSiteDataPanel { break; } } + + async #maybeShowFeatureCallout() { + const kPref = 'zen.site-data-panel.show-callout'; + if (!Services.prefs.getBoolPref(kPref, false)) { + return; + } + Services.prefs.setBoolPref(kPref, false); + const { FeatureCallout } = lazy; + const { gBrowser, gZenWorkspaces } = this.window; + await gZenWorkspaces.promiseInitialized; + await new Promise((resolve) => { + const checkEmptyTab = () => { + if (!gBrowser.selectedTab.hasAttribute('zen-empty-tab')) { + resolve(); + return; + } + this.window.addEventListener('TabSelect', checkEmptyTab, { once: true }); + }; + checkEmptyTab(); + }); + this.anchor.setAttribute('open', 'true'); + const callout = new FeatureCallout({ + win: this.window, + location: 'chrome', + context: 'chrome', + browser: gBrowser.selectedBrowser, + theme: { preset: 'chrome' }, + }); + this.window.setTimeout(() => { + callout.showFeatureCallout({ + id: 'ZEN_EXTENSIONS_PANEL_MOVE_CALLOUT', + template: 'feature_callout', + groups: ['cfr'], + content: { + id: 'ZEN_EXTENSIONS_PANEL_MOVE_CALLOUT', + template: 'multistage', + backdrop: 'transparent', + transitions: false, + screens: [ + { + id: 'ZEN_EXTENSIONS_PANEL_MOVE_CALLOUT_HORIZONTAL', + anchors: [ + { + selector: '#zen-site-data-icon-button', + panel_position: { + anchor_attachment: 'bottomcenter', + callout_attachment: 'topleft', + }, + }, + { + selector: '#identity-icon-box', + panel_position: { + anchor_attachment: 'bottomcenter', + callout_attachment: 'topleft', + }, + }, + ], + content: { + position: 'callout', + width: '355px', + padding: 16, + title: { + string_id: 'zen-site-data-panel-feature-callout-title', + }, + subtitle: { + string_id: 'zen-site-data-panel-feature-callout-subtitle', + }, + dismiss_button: { + action: { + dismiss: true, + }, + background: true, + size: 'small', + }, + }, + }, + ], + }, + }); + }, 500); + } }