From 8bd7d835b4ce424918d9cd9f5d7bdd02cefdcd3d Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Thu, 2 Oct 2025 12:02:00 +0200 Subject: [PATCH] feat: Finished permissions and addons, b=no-bug, c=common --- locales/en-US/browser/browser/zen-general.ftl | 5 + .../base/content/navigator-toolbox-js.patch | 38 +++++- .../base/content/zen-panels/site-data.inc | 8 +- .../CustomizableUI-sys-mjs.patch | 11 +- src/browser/themes/shared/zen-icons/icons.css | 4 +- src/zen/common/styles/zen-omnibox.css | 14 ++ src/zen/common/styles/zen-popup.css | 7 +- .../common/styles/zen-single-components.css | 81 ++++++++++- src/zen/urlbar/ZenSiteDataPanel.sys.mjs | 127 ++++++++++++++---- src/zen/zen.globals.js | 2 + 10 files changed, 255 insertions(+), 42 deletions(-) diff --git a/locales/en-US/browser/browser/zen-general.ftl b/locales/en-US/browser/browser/zen-general.ftl index bea40c496..f8fbf0879 100644 --- a/locales/en-US/browser/browser/zen-general.ftl +++ b/locales/en-US/browser/browser/zen-general.ftl @@ -67,3 +67,8 @@ urlbar-search-mode-zen_actions = Actions zen-site-data-settings = Settings zen-generic-manage = Manage +zen-generic-more = More + +# These labels will be used for the site data panel settings +zen-site-data-setting-allow = Allowed +zen-site-data-setting-block = Blocked diff --git a/src/browser/base/content/navigator-toolbox-js.patch b/src/browser/base/content/navigator-toolbox-js.patch index e775bcd15..167525ff8 100644 --- a/src/browser/base/content/navigator-toolbox-js.patch +++ b/src/browser/base/content/navigator-toolbox-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/base/content/navigator-toolbox.js b/browser/base/content/navigator-toolbox.js -index 413bad2a62058a1c434d6a44e927e44eb397289d..b621c586e679bb8686fe9a5e6743512e71604425 100644 +index 413bad2a62058a1c434d6a44e927e44eb397289d..472eab5d3bca2bc665920707a71105167cbe75ec 100644 --- a/browser/base/content/navigator-toolbox.js +++ b/browser/base/content/navigator-toolbox.js @@ -8,7 +8,7 @@ @@ -11,6 +11,24 @@ index 413bad2a62058a1c434d6a44e927e44eb397289d..b621c586e679bb8686fe9a5e6743512e const widgetOverflow = document.getElementById("widget-overflow"); function onPopupShowing(event) { +@@ -110,7 +110,7 @@ document.addEventListener( + #pageActionButton, + #downloads-button, + #fxa-toolbar-menu-button, +- #unified-extensions-button, ++ #zen-site-data-icon-button, + #library-button + `); + if (!element) { +@@ -138,7 +138,7 @@ document.addEventListener( + gSync.toggleAccountPanel(element, event); + break; + +- case "unified-extensions-button": ++ case "zen-site-data-icon-button": + gUnifiedExtensions.togglePanel(event); + break; + @@ -187,6 +187,7 @@ document.addEventListener( #reload-button , #urlbar-go-button, @@ -27,3 +45,21 @@ index 413bad2a62058a1c434d6a44e927e44eb397289d..b621c586e679bb8686fe9a5e6743512e gBrowser.handleNewTabMiddleClick(element, event); break; +@@ -317,7 +319,7 @@ document.addEventListener( + #pageActionButton, + #downloads-button, + #fxa-toolbar-menu-button, +- #unified-extensions-button, ++ #zen-site-data-icon-button, + #library-button + `); + if (!element) { +@@ -396,7 +398,7 @@ document.addEventListener( + gSync.toggleAccountPanel(element, event); + break; + +- case "unified-extensions-button": ++ case "zen-site-data-icon-button": + gUnifiedExtensions.togglePanel(event); + break; + diff --git a/src/browser/base/content/zen-panels/site-data.inc b/src/browser/base/content/zen-panels/site-data.inc index 920cfae00..aa0092a61 100644 --- a/src/browser/base/content/zen-panels/site-data.inc +++ b/src/browser/base/content/zen-panels/site-data.inc @@ -17,7 +17,7 @@ @@ -53,11 +53,11 @@ - + - + diff --git a/src/browser/components/customizableui/CustomizableUI-sys-mjs.patch b/src/browser/components/customizableui/CustomizableUI-sys-mjs.patch index 396dbf5a9..4635de61c 100644 --- a/src/browser/components/customizableui/CustomizableUI-sys-mjs.patch +++ b/src/browser/components/customizableui/CustomizableUI-sys-mjs.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/customizableui/CustomizableUI.sys.mjs b/browser/components/customizableui/CustomizableUI.sys.mjs -index 4f62449d670701c77c681ae36e00bae8bf2f636c..132c77e396cb259181ed13ca8ff784e0ade05e3b 100644 +index 4f62449d670701c77c681ae36e00bae8bf2f636c..ac542f33927f9de9040bab9cd98351a4d74ede4e 100644 --- a/browser/components/customizableui/CustomizableUI.sys.mjs +++ b/browser/components/customizableui/CustomizableUI.sys.mjs @@ -14,6 +14,7 @@ ChromeUtils.defineESModuleGetters(lazy, { @@ -10,6 +10,15 @@ index 4f62449d670701c77c681ae36e00bae8bf2f636c..132c77e396cb259181ed13ca8ff784e0 HomePage: "resource:///modules/HomePage.sys.mjs", PanelMultiView: "moz-src:///browser/components/customizableui/PanelMultiView.sys.mjs", +@@ -323,7 +324,7 @@ var CustomizableUIInternal = { + { + type: CustomizableUI.TYPE_PANEL, + defaultPlacements: [], +- anchor: "unified-extensions-button", ++ anchor: "zen-site-data-icon-button", + }, + false + ); @@ -333,19 +334,14 @@ var CustomizableUIInternal = { "back-button", "forward-button", diff --git a/src/browser/themes/shared/zen-icons/icons.css b/src/browser/themes/shared/zen-icons/icons.css index a7f516d8e..c31d16ae9 100644 --- a/src/browser/themes/shared/zen-icons/icons.css +++ b/src/browser/themes/shared/zen-icons/icons.css @@ -214,7 +214,8 @@ .search-setting-button > .button-box > .button-icon, #appMenu-settings-button, #PanelUI-zen-profiles-managePrfs, -.unified-extensions-item-open-menu.subviewbutton { +.unified-extensions-item-open-menu.subviewbutton, +.zen-site-data-permission-icon { list-style-image: url('settings.svg') !important; } @@ -475,6 +476,7 @@ #zen-site-data-icon { list-style-image: url('permissions.svg'); -moz-context-properties: fill, fill-opacity; + pointer-events: none; } .geo-icon { diff --git a/src/zen/common/styles/zen-omnibox.css b/src/zen/common/styles/zen-omnibox.css index 3be04ae0d..8d0c0e37b 100644 --- a/src/zen/common/styles/zen-omnibox.css +++ b/src/zen/common/styles/zen-omnibox.css @@ -120,6 +120,20 @@ border-radius: 10px !important; } } + + .identity-box-button { + opacity: 0; + transition: + opacity 0.2s, + visibility 0.2s; + visibility: collapse; + + #navigator-toolbox:hover &, + &[open] { + opacity: 1; + visibility: visible; + } + } } .urlbar-page-action, diff --git a/src/zen/common/styles/zen-popup.css b/src/zen/common/styles/zen-popup.css index ecc8b78f7..f5de08932 100644 --- a/src/zen/common/styles/zen-popup.css +++ b/src/zen/common/styles/zen-popup.css @@ -228,12 +228,7 @@ panel { .permission-popup-permission-item, #permission-popup-storage-access-permission-list-header { - margin-block: var(--uc-permission-item-margin-block); -} - -.permission-popup-permission-label, -.permission-popup-permission-header-label { - margin-inline-start: var(--uc-arrowpanel-menuicon-margin-inline); + padding-block: var(--uc-permission-item-margin-block); } #editBookmarkPanel > #editBookmarkHeaderSeparator, diff --git a/src/zen/common/styles/zen-single-components.css b/src/zen/common/styles/zen-single-components.css index fcc28bcb3..740b944f4 100644 --- a/src/zen/common/styles/zen-single-components.css +++ b/src/zen/common/styles/zen-single-components.css @@ -266,7 +266,7 @@ body > #confetti { #zen-unified-site-data-panel { --panel-padding: 0px; - --panel-width: 250px; + --panel-width: 228px; --menu-panel-width-wide: calc(var(--panel-width) - var(--panel-padding) * 2); --uei-icon-size: 14px; --arrowpanel-menuitem-border-radius: 10px; @@ -279,7 +279,7 @@ body > #confetti { #zen-site-data-addons { display: flex; flex-wrap: wrap; - gap: 6px; + gap: 8px; overflow: visible; .unified-extensions-item-name, @@ -302,8 +302,8 @@ body > #confetti { & > * { background-color: color-mix(in srgb, currentcolor 6%, transparent); - width: 42px; - height: 28px; + width: 46px; + height: 34px; margin: 0; justify-content: center; align-items: center; @@ -312,6 +312,10 @@ body > #confetti { background-color 0.1s ease-in-out, transform 0.12s ease-in-out; + & toolbarbutton { + background: transparent !important; + } + & .toolbarbutton-badge-stack { margin: 0; } @@ -346,6 +350,7 @@ body > #confetti { font-size: smaller; transition: opacity 0.15s ease-in-out; opacity: 0; + padding: 0px 4px; .zen-site-data-section:hover & { opacity: 0.8; @@ -356,3 +361,71 @@ body > #confetti { #zen-site-data-new-addon-button .toolbarbutton-text { display: none; } + +.permission-popup-permission-item { + gap: 6px; +} + +.permission-popup-permission-label { + margin: 0px; + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.permission-popup-permission-icon { + fill: var(--button-primary-color); + padding: 8px; + width: 34px; + height: 34px; + overflow: visible; + position: relative; + appearance: none; + + & label { + display: none; + } + + & image { + -moz-context-properties: fill; + z-index: 1; + } + + &::before { + content: ''; + position: absolute; + inset: 1px; + border-radius: 99px; + width: 32px; + height: 32px; + background: var(--button-primary-bgcolor); + opacity: 0.6; + transition: + transform 0.12s ease-in-out, + opacity 0.12s ease-in-out; + } + + .permission-popup-permission-item:hover &::before { + transform: scale(1.05); + } + + .permission-popup-permission-item:active:hover &::before { + transform: scale(0.95); + } + + .permission-popup-permission-item[state='allow'] &::before { + opacity: 1; + } +} + +.zen-permission-popup-permission-state-label { + opacity: 0.8; + font-size: smaller; + font-weight: 400; + margin: 0; +} + +#identity-box { + opacity: 0.6; +} diff --git a/src/zen/urlbar/ZenSiteDataPanel.sys.mjs b/src/zen/urlbar/ZenSiteDataPanel.sys.mjs index 199d243a4..0bb8d1ba5 100644 --- a/src/zen/urlbar/ZenSiteDataPanel.sys.mjs +++ b/src/zen/urlbar/ZenSiteDataPanel.sys.mjs @@ -14,12 +14,13 @@ export class nsZenSiteDataPanel { #init() { // Add a new button to the urlbar popup const button = this.window.MozXULElement.parseXULToFragment(` - + `); - this.anchor = button.querySelector('#zen-site-data-icon'); + this.anchor = button.querySelector('#zen-site-data-icon-button'); this.document.getElementById('identity-icon-box').after(button); + this.window.gUnifiedExtensions._button = this.anchor; // Remove the old permissions dialog this.document.getElementById('unified-extensions-panel-template').remove(); @@ -28,18 +29,12 @@ export class nsZenSiteDataPanel { } #initEventListeners() { - this.anchor.addEventListener('click', this); + this.panel.addEventListener('popupshowing', this); this.document .getElementById('zen-site-data-new-addon-button') .addEventListener('command', this); - } - - show(event) { - this.#preparePanel(); - - this.window.PanelMultiView.openPopup(this.panel, this.anchor, { - triggerEvent: event, - }); + this.document.getElementById('zen-site-data-manage-addons').addEventListener('click', this); + this.document.getElementById('zen-site-data-settings-more').addEventListener('click', this); } #preparePanel() { @@ -144,7 +139,6 @@ export class nsZenSiteDataPanel { } list.innerHTML = ''; - let totalBlockedPopups = gBrowser.selectedBrowser.popupBlocker.getBlockedPopupCount(); for (let permission of permissions) { let [id, key] = permission.id.split(SitePermissions.PERM_KEY_DELIMITER); @@ -154,6 +148,11 @@ export class nsZenSiteDataPanel { continue; } + if (permission.state == SitePermissions.PROMPT) { + // We don't display "ask" permissions in the site data panel. + continue; + } + let item = this.#createPermissionItem(id, key, permission); if (item) { list.appendChild(item); @@ -163,11 +162,25 @@ export class nsZenSiteDataPanel { section.hidden = list.childElementCount == 0; } + #getPermissionStateLabelId(permission) { + const { SitePermissions } = this.window; + switch (permission.state) { + // There should only be these types being displayed in the panel. + case SitePermissions.ALLOW: + return 'zen-site-data-setting-allow'; + case SitePermissions.BLOCK: + case SitePermissions.AUTOPLAY_BLOCKED_ALL: + return 'zen-site-data-setting-block'; + default: + return null; + } + } + #createPermissionItem(id, key, permission) { const { SitePermissions } = this.window; // Create a permission item for the site data panel. - let container = document.createXULElement('hbox'); + let container = this.document.createXULElement('hbox'); const idNoSuffix = permission.id; container.classList.add( 'permission-popup-permission-item', @@ -176,16 +189,19 @@ export class nsZenSiteDataPanel { container.setAttribute('align', 'center'); container.setAttribute('role', 'group'); - let img = document.createXULElement('image'); - img.classList.add('permission-popup-permission-icon', idNoSuffix + '-icon'); - if ( - permission.state == SitePermissions.BLOCK || - permission.state == SitePermissions.AUTOPLAY_BLOCKED_ALL - ) { - img.classList.add('blocked-permission-icon'); - } + container.setAttribute('state', permission.state == SitePermissions.ALLOW ? 'allow' : 'block'); - let nameLabel = document.createXULElement('label'); + let img = this.document.createXULElement('toolbarbutton'); + img.classList.add('permission-popup-permission-icon', 'zen-site-data-permission-icon'); + + let labelContainer = this.document.createXULElement('vbox'); + labelContainer.setAttribute('flex', '1'); + labelContainer.setAttribute('align', 'start'); + labelContainer.classList.add('permission-popup-permission-label-container'); + labelContainer._permission = permission; + labelContainer.addEventListener('click', this); + + let nameLabel = this.document.createXULElement('label'); nameLabel.setAttribute('flex', '1'); nameLabel.setAttribute('class', 'permission-popup-permission-label'); let label = SitePermissions.getPermissionLabel(permission.id); @@ -193,19 +209,77 @@ export class nsZenSiteDataPanel { return null; } nameLabel.textContent = label; + labelContainer.appendChild(nameLabel); + + let stateLabel = this.document.createXULElement('label'); + stateLabel.setAttribute('class', 'zen-permission-popup-permission-state-label'); + stateLabel.setAttribute('data-l10n-id', this.#getPermissionStateLabelId(permission)); + labelContainer.appendChild(stateLabel); container.appendChild(img); - container.appendChild(nameLabel); + container.appendChild(labelContainer); + return container; } #onCommandEvent(event) { const id = event.target.id; switch (id) { - case 'zen-site-data-new-addon-button': + case 'zen-site-data-new-addon-button': { + let amoUrl = Services.urlFormatter.formatURLPref('extensions.getAddons.link.url'); + const { switchToTabHavingURI } = this.window; + switchToTabHavingURI(amoUrl, true); + break; + } + } + } + + #onPermissionClick(label) { + const { SitePermissions, gBrowser } = this.window; + const permission = label._permission; + + let newState; + switch (permission.state) { + case SitePermissions.ALLOW: + newState = SitePermissions.BLOCK; + break; + case SitePermissions.BLOCK: + case SitePermissions.AUTOPLAY_BLOCKED_ALL: + newState = SitePermissions.ALLOW; + break; + default: + return; + } + + SitePermissions.setForPrincipal(gBrowser.contentPrincipal, permission.id, newState); + + label.parentNode.setAttribute('state', newState == SitePermissions.ALLOW ? 'allow' : 'block'); + label + .querySelector('.zen-permission-popup-permission-state-label') + .setAttribute('data-l10n-id', this.#getPermissionStateLabelId({ state: newState })); + label._permission.state = newState; + } + + #onClickEvent(event) { + const id = event.target.id; + switch (id) { + case 'zen-site-data-manage-addons': { const { BrowserAddonUI } = this.window; BrowserAddonUI.openAddonsMgr('addons://list/extension'); break; + } + case 'zen-site-data-settings-more': { + const { BrowserCommands } = this.window; + BrowserCommands.pageInfo(null, 'permTab'); + break; + } + default: { + const label = event.target.closest('.permission-popup-permission-label-container'); + if (label?._permission) { + this.#onPermissionClick(label); + } + break; + } } } @@ -213,11 +287,14 @@ export class nsZenSiteDataPanel { const type = event.type; switch (type) { case 'click': - this.show(event); + this.#onClickEvent(event); break; case 'command': this.#onCommandEvent(event); break; + case 'popupshowing': + this.#preparePanel(); + break; } } } diff --git a/src/zen/zen.globals.js b/src/zen/zen.globals.js index c8dc0987f..a225ca767 100644 --- a/src/zen/zen.globals.js +++ b/src/zen/zen.globals.js @@ -7,6 +7,8 @@ export default [ 'nsZenDOMOperatedFeature', 'nsZenPreloadedFeature', + 'nsZenSiteDataPanel', + 'ZenThemeModifier', 'ZenHasPolyfill',