зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1596897 - Moved permission list from site identity to separate permission panel. r=johannh
- Added a new permission panel managed by the gPermissionPanel object - Updated identity-box to separate identity and permission section Differential Revision: https://phabricator.services.mozilla.com/D99892
This commit is contained in:
Родитель
7ce5240dfe
Коммит
6445d181dc
|
@ -206,6 +206,12 @@ var gIdentityHandler = {
|
|||
delete this._identityBox;
|
||||
return (this._identityBox = document.getElementById("identity-box"));
|
||||
},
|
||||
get _identityIconBox() {
|
||||
delete this._identityIconBox;
|
||||
return (this._identityIconBox = document.getElementById(
|
||||
"identity-icon-box"
|
||||
));
|
||||
},
|
||||
get _identityPopupMultiView() {
|
||||
delete this._identityPopupMultiView;
|
||||
return (this._identityPopupMultiView = document.getElementById(
|
||||
|
@ -295,30 +301,6 @@ var gIdentityHandler = {
|
|||
delete this._identityIcon;
|
||||
return (this._identityIcon = document.getElementById("identity-icon"));
|
||||
},
|
||||
get _permissionList() {
|
||||
delete this._permissionList;
|
||||
return (this._permissionList = document.getElementById(
|
||||
"identity-popup-permission-list"
|
||||
));
|
||||
},
|
||||
get _defaultPermissionAnchor() {
|
||||
delete this._defaultPermissionAnchor;
|
||||
return (this._defaultPermissionAnchor = document.getElementById(
|
||||
"identity-popup-permission-list-default-anchor"
|
||||
));
|
||||
},
|
||||
get _permissionEmptyHint() {
|
||||
delete this._permissionEmptyHint;
|
||||
return (this._permissionEmptyHint = document.getElementById(
|
||||
"identity-popup-permission-empty-hint"
|
||||
));
|
||||
},
|
||||
get _permissionReloadHint() {
|
||||
delete this._permissionReloadHint;
|
||||
return (this._permissionReloadHint = document.getElementById(
|
||||
"identity-popup-permission-reload-hint"
|
||||
));
|
||||
},
|
||||
get _popupExpander() {
|
||||
delete this._popupExpander;
|
||||
return (this._popupExpander = document.getElementById(
|
||||
|
@ -331,32 +313,6 @@ var gIdentityHandler = {
|
|||
"identity-popup-clear-sitedata-footer"
|
||||
));
|
||||
},
|
||||
get _permissionAnchors() {
|
||||
delete this._permissionAnchors;
|
||||
let permissionAnchors = {};
|
||||
for (let anchor of document.getElementById("blocked-permissions-container")
|
||||
.children) {
|
||||
permissionAnchors[anchor.getAttribute("data-permission-id")] = anchor;
|
||||
}
|
||||
return (this._permissionAnchors = permissionAnchors);
|
||||
},
|
||||
|
||||
get _geoSharingIcon() {
|
||||
delete this._geoSharingIcon;
|
||||
return (this._geoSharingIcon = document.getElementById("geo-sharing-icon"));
|
||||
},
|
||||
|
||||
get _xrSharingIcon() {
|
||||
delete this._xrSharingIcon;
|
||||
return (this._xrSharingIcon = document.getElementById("xr-sharing-icon"));
|
||||
},
|
||||
|
||||
get _webRTCSharingIcon() {
|
||||
delete this._webRTCSharingIcon;
|
||||
return (this._webRTCSharingIcon = document.getElementById(
|
||||
"webrtc-sharing-icon"
|
||||
));
|
||||
},
|
||||
|
||||
get _insecureConnectionIconEnabled() {
|
||||
delete this._insecureConnectionIconEnabled;
|
||||
|
@ -465,10 +421,6 @@ var gIdentityHandler = {
|
|||
event.stopPropagation();
|
||||
},
|
||||
|
||||
openPermissionPreferences() {
|
||||
openPreferences("privacy-permissions");
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for mouseclicks on the "More Information" button in the
|
||||
* "identity-popup" panel.
|
||||
|
@ -699,8 +651,9 @@ var gIdentityHandler = {
|
|||
this.refreshIdentityBlock();
|
||||
// Handle a location change while the Control Center is focused
|
||||
// by closing the popup (bug 1207542)
|
||||
if (shouldHidePopup && this._popupInitialized) {
|
||||
PanelMultiView.hidePopup(this._identityPopup);
|
||||
if (shouldHidePopup) {
|
||||
this.hidePopup();
|
||||
gPermissionPanel.hidePopup();
|
||||
}
|
||||
|
||||
// NOTE: We do NOT update the identity popup (the control center) when
|
||||
|
@ -733,46 +686,6 @@ var gIdentityHandler = {
|
|||
}
|
||||
},
|
||||
|
||||
updateSharingIndicator() {
|
||||
let tab = gBrowser.selectedTab;
|
||||
this._sharingState = tab._sharingState;
|
||||
|
||||
this._webRTCSharingIcon.removeAttribute("paused");
|
||||
this._webRTCSharingIcon.removeAttribute("sharing");
|
||||
this._geoSharingIcon.removeAttribute("sharing");
|
||||
this._xrSharingIcon.removeAttribute("sharing");
|
||||
|
||||
if (this._sharingState) {
|
||||
if (
|
||||
this._sharingState &&
|
||||
this._sharingState.webRTC &&
|
||||
this._sharingState.webRTC.sharing
|
||||
) {
|
||||
this._webRTCSharingIcon.setAttribute(
|
||||
"sharing",
|
||||
this._sharingState.webRTC.sharing
|
||||
);
|
||||
|
||||
if (this._sharingState.webRTC.paused) {
|
||||
this._webRTCSharingIcon.setAttribute("paused", "true");
|
||||
}
|
||||
}
|
||||
if (this._sharingState.geo) {
|
||||
this._geoSharingIcon.setAttribute("sharing", this._sharingState.geo);
|
||||
}
|
||||
if (this._sharingState.xr) {
|
||||
this._xrSharingIcon.setAttribute("sharing", this._sharingState.xr);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._popupInitialized && this._identityPopup.state != "closed") {
|
||||
this.updateSitePermissions();
|
||||
PanelView.forNode(
|
||||
this._identityPopupMainView
|
||||
).descriptionHeightWorkaround();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempt to provide proper IDN treatment for host names
|
||||
*/
|
||||
|
@ -986,50 +899,6 @@ var gIdentityHandler = {
|
|||
this._identityIconLabel.collapsed = !icon_label;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the permissions block in the identity block.
|
||||
*/
|
||||
_refreshPermissionIcons() {
|
||||
let permissionAnchors = this._permissionAnchors;
|
||||
|
||||
// hide all permission icons
|
||||
for (let icon of Object.values(permissionAnchors)) {
|
||||
icon.removeAttribute("showing");
|
||||
}
|
||||
|
||||
// keeps track if we should show an indicator that there are active permissions
|
||||
let hasGrantedPermissions = false;
|
||||
|
||||
// show permission icons
|
||||
let permissions = SitePermissions.getAllForBrowser(
|
||||
gBrowser.selectedBrowser
|
||||
);
|
||||
for (let permission of permissions) {
|
||||
if (
|
||||
permission.state == SitePermissions.BLOCK ||
|
||||
permission.state == SitePermissions.AUTOPLAY_BLOCKED_ALL
|
||||
) {
|
||||
let icon = permissionAnchors[permission.id];
|
||||
if (icon) {
|
||||
icon.setAttribute("showing", "true");
|
||||
}
|
||||
} else if (permission.state != SitePermissions.UNKNOWN) {
|
||||
hasGrantedPermissions = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasGrantedPermissions) {
|
||||
this._identityBox.classList.add("grantedPermissions");
|
||||
}
|
||||
|
||||
// Show blocked popup icon in the identity-box if popups are blocked
|
||||
// irrespective of popup permission capability value.
|
||||
if (gBrowser.selectedBrowser.popupBlocker.getBlockedPopupCount()) {
|
||||
let icon = permissionAnchors.popup;
|
||||
icon.setAttribute("showing", "true");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the identity block user interface with the data from this object.
|
||||
*/
|
||||
|
@ -1045,12 +914,13 @@ var gIdentityHandler = {
|
|||
// This will also filter out intermediate about:blank loads to avoid
|
||||
// flickering the identity block and doing unnecessary work.
|
||||
if (this._hasInvalidPageProxyState()) {
|
||||
gPermissionPanel.hidePermissionIcons();
|
||||
return;
|
||||
}
|
||||
|
||||
this._refreshIdentityIcons();
|
||||
|
||||
this._refreshPermissionIcons();
|
||||
gPermissionPanel.refreshPermissionIcons();
|
||||
|
||||
// Hide the shield icon if it is a chrome page.
|
||||
gProtectionsHandler._trackingProtectionIconContainer.classList.toggle(
|
||||
|
@ -1252,9 +1122,6 @@ var gIdentityHandler = {
|
|||
this._identityPopupContentOwner.textContent = owner;
|
||||
this._identityPopupContentSupp.textContent = supplemental;
|
||||
this._identityPopupContentVerif.textContent = verifier;
|
||||
|
||||
// Update per-site permissions section.
|
||||
this.updateSitePermissions();
|
||||
},
|
||||
|
||||
setURI(uri) {
|
||||
|
@ -1309,39 +1176,11 @@ var gIdentityHandler = {
|
|||
return; // Left click, space or enter only
|
||||
}
|
||||
|
||||
// Don't allow left click, space or enter if the location has been modified,
|
||||
// so long as we're not sharing any devices.
|
||||
// If we are sharing a device, the identity block is prevented by CSS from
|
||||
// being focused (and therefore, interacted with) by the user. However, we
|
||||
// want to allow opening the identity popup from the device control menu,
|
||||
// which calls click() on the identity button, so we don't return early.
|
||||
if (
|
||||
!this._sharingState &&
|
||||
gURLBar.getAttribute("pageproxystate") != "valid"
|
||||
) {
|
||||
// Don't allow left click, space or enter if the location has been modified.
|
||||
if (gURLBar.getAttribute("pageproxystate") != "valid") {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are in DOM full-screen, exit it before showing the identity popup
|
||||
// (see bug 1557041)
|
||||
if (document.fullscreen) {
|
||||
// Open the identity popup after DOM full-screen exit
|
||||
// We need to wait for the exit event and after that wait for the fullscreen exit transition to complete
|
||||
// If we call _openPopup before the full-screen transition ends it can get cancelled
|
||||
// Only waiting for painted is not sufficient because we could still be in the full-screen enter transition.
|
||||
this._exitedEventReceived = false;
|
||||
this._event = event;
|
||||
Services.obs.addObserver(this, "fullscreen-painted");
|
||||
window.addEventListener(
|
||||
"MozDOMFullscreen:Exited",
|
||||
() => {
|
||||
this._exitedEventReceived = true;
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
document.exitFullscreen();
|
||||
return;
|
||||
}
|
||||
this._openPopup(event);
|
||||
},
|
||||
|
||||
|
@ -1349,14 +1188,11 @@ var gIdentityHandler = {
|
|||
// Make the popup available.
|
||||
this._initializePopup();
|
||||
|
||||
// Remove the reload hint that we show after a user has cleared a permission.
|
||||
this._permissionReloadHint.setAttribute("hidden", "true");
|
||||
|
||||
// Update the popup strings
|
||||
this.refreshIdentityPopup();
|
||||
|
||||
// Add the "open" attribute to the identity box for styling
|
||||
this._identityBox.setAttribute("open", "true");
|
||||
this._identityIconBox.setAttribute("open", "true");
|
||||
|
||||
// Check the panel state of other panels. Hide them if needed.
|
||||
let openPanels = Array.from(document.querySelectorAll("panel[openpanel]"));
|
||||
|
@ -1365,7 +1201,7 @@ var gIdentityHandler = {
|
|||
}
|
||||
|
||||
// Now open the popup, anchored off the primary chrome element
|
||||
PanelMultiView.openPopup(this._identityPopup, this._identityIcon, {
|
||||
PanelMultiView.openPopup(this._identityPopup, this._identityIconBox, {
|
||||
position: "bottomcenter topleft",
|
||||
triggerEvent: event,
|
||||
}).catch(Cu.reportError);
|
||||
|
@ -1380,7 +1216,7 @@ var gIdentityHandler = {
|
|||
onPopupHidden(event) {
|
||||
if (event.target == this._identityPopup) {
|
||||
window.removeEventListener("focus", this, true);
|
||||
this._identityBox.removeAttribute("open");
|
||||
this._identityIconBox.removeAttribute("open");
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1416,15 +1252,6 @@ var gIdentityHandler = {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "fullscreen-painted": {
|
||||
if (subject != window || !this._exitedEventReceived) {
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(this, "fullscreen-painted");
|
||||
this._openPopup(this._event);
|
||||
delete this._event;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1500,16 +1327,6 @@ var gIdentityHandler = {
|
|||
gURLBar.view.close();
|
||||
},
|
||||
|
||||
onLocationChange() {
|
||||
if (this._popupInitialized && this._identityPopup.state != "closed") {
|
||||
this._permissionReloadHint.setAttribute("hidden", "true");
|
||||
|
||||
if (this._isPermissionListEmpty()) {
|
||||
this._permissionEmptyHint.removeAttribute("hidden");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_updateAttribute(elem, attr, value) {
|
||||
if (value) {
|
||||
elem.setAttribute(attr, value);
|
||||
|
@ -1517,598 +1334,4 @@ var gIdentityHandler = {
|
|||
elem.removeAttribute(attr);
|
||||
}
|
||||
},
|
||||
|
||||
_isPermissionListEmpty() {
|
||||
return !this._permissionList.querySelectorAll(
|
||||
".identity-popup-permission-item"
|
||||
).length;
|
||||
},
|
||||
|
||||
updateSitePermissions() {
|
||||
let permissionItemSelector = [
|
||||
".identity-popup-permission-item, .identity-popup-permission-item-container",
|
||||
];
|
||||
this._permissionList
|
||||
.querySelectorAll(permissionItemSelector)
|
||||
.forEach(e => e.remove());
|
||||
|
||||
let permissions = SitePermissions.getAllPermissionDetailsForBrowser(
|
||||
gBrowser.selectedBrowser
|
||||
);
|
||||
|
||||
if (this._sharingState && this._sharingState.geo) {
|
||||
let geoPermission = permissions.find(perm => perm.id === "geo");
|
||||
if (geoPermission) {
|
||||
geoPermission.sharingState = true;
|
||||
} else {
|
||||
permissions.push({
|
||||
id: "geo",
|
||||
state: SitePermissions.ALLOW,
|
||||
scope: SitePermissions.SCOPE_REQUEST,
|
||||
sharingState: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this._sharingState && this._sharingState.xr) {
|
||||
let xrPermission = permissions.find(perm => perm.id === "xr");
|
||||
if (xrPermission) {
|
||||
xrPermission.sharingState = true;
|
||||
} else {
|
||||
permissions.push({
|
||||
id: "xr",
|
||||
state: SitePermissions.ALLOW,
|
||||
scope: SitePermissions.SCOPE_REQUEST,
|
||||
sharingState: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this._sharingState && this._sharingState.webRTC) {
|
||||
let webrtcState = this._sharingState.webRTC;
|
||||
// If WebRTC device or screen permissions are in use, we need to find
|
||||
// the associated permission item to set the sharingState field.
|
||||
for (let id of ["camera", "microphone", "screen"]) {
|
||||
if (webrtcState[id]) {
|
||||
let found = false;
|
||||
for (let permission of permissions) {
|
||||
if (permission.id != id) {
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
permission.sharingState = webrtcState[id];
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
// If the permission item we were looking for doesn't exist,
|
||||
// the user has temporarily allowed sharing and we need to add
|
||||
// an item in the permissions array to reflect this.
|
||||
permissions.push({
|
||||
id,
|
||||
state: SitePermissions.ALLOW,
|
||||
scope: SitePermissions.SCOPE_REQUEST,
|
||||
sharingState: webrtcState[id],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let totalBlockedPopups = gBrowser.selectedBrowser.popupBlocker.getBlockedPopupCount();
|
||||
let hasBlockedPopupIndicator = false;
|
||||
for (let permission of permissions) {
|
||||
let [id, key] = permission.id.split(SitePermissions.PERM_KEY_DELIMITER);
|
||||
|
||||
if (id == "storage-access") {
|
||||
// Ignore storage access permissions here, they are made visible inside
|
||||
// the Content Blocking UI.
|
||||
continue;
|
||||
}
|
||||
|
||||
let item;
|
||||
let anchor =
|
||||
this._permissionList.querySelector(`[anchorfor="${id}"]`) ||
|
||||
this._defaultPermissionAnchor;
|
||||
|
||||
if (id == "open-protocol-handler") {
|
||||
let permContainer = this._createProtocolHandlerPermissionItem(
|
||||
permission,
|
||||
key
|
||||
);
|
||||
if (permContainer) {
|
||||
anchor.appendChild(permContainer);
|
||||
}
|
||||
} else {
|
||||
item = this._createPermissionItem({
|
||||
permission,
|
||||
isContainer: id == "geo" || id == "xr",
|
||||
nowrapLabel: id == "3rdPartyStorage",
|
||||
});
|
||||
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
anchor.appendChild(item);
|
||||
}
|
||||
|
||||
if (id == "popup" && totalBlockedPopups) {
|
||||
this._createBlockedPopupIndicator(totalBlockedPopups);
|
||||
hasBlockedPopupIndicator = true;
|
||||
} else if (id == "geo" && permission.state === SitePermissions.ALLOW) {
|
||||
this._createGeoLocationLastAccessIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
if (totalBlockedPopups && !hasBlockedPopupIndicator) {
|
||||
let permission = {
|
||||
id: "popup",
|
||||
state: SitePermissions.getDefault("popup"),
|
||||
scope: SitePermissions.SCOPE_PERSISTENT,
|
||||
};
|
||||
let item = this._createPermissionItem({ permission });
|
||||
this._defaultPermissionAnchor.appendChild(item);
|
||||
this._createBlockedPopupIndicator(totalBlockedPopups);
|
||||
}
|
||||
|
||||
// Show a placeholder text if there's no permission and no reload hint.
|
||||
if (
|
||||
this._isPermissionListEmpty() &&
|
||||
this._permissionReloadHint.hasAttribute("hidden")
|
||||
) {
|
||||
this._permissionEmptyHint.removeAttribute("hidden");
|
||||
} else {
|
||||
this._permissionEmptyHint.setAttribute("hidden", "true");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a permission item based on the supplied options and returns it.
|
||||
* It is up to the caller to actually insert the element somewhere.
|
||||
*
|
||||
* @param permission - An object containing information representing the
|
||||
* permission, typically obtained via SitePermissions.jsm
|
||||
* @param isContainer - If true, the permission item will be added to a vbox
|
||||
* and the vbox will be returned.
|
||||
* @param permClearButton - Whether to show an "x" button to clear the permission
|
||||
* @param showStateLabel - Whether to show a label indicating the current status
|
||||
* of the permission e.g. "Temporary Allowed"
|
||||
* @param idNoSuffix - Some permission types have additional information suffixed
|
||||
* to the ID - callers can pass the unsuffixed ID via this
|
||||
* parameter to indicate the permission type manually.
|
||||
* @param nowrapLabel - Whether to prevent the permission item's label from
|
||||
* wrapping its text content. This allows styling text-overflow
|
||||
* and is useful for e.g. 3rdPartyStorage permissions whose
|
||||
* labels are origins - which could be of any length.
|
||||
*/
|
||||
_createPermissionItem({
|
||||
permission,
|
||||
isContainer = false,
|
||||
permClearButton = true,
|
||||
showStateLabel = true,
|
||||
idNoSuffix = permission.id,
|
||||
nowrapLabel = false,
|
||||
}) {
|
||||
let container = document.createXULElement("hbox");
|
||||
container.setAttribute("class", "identity-popup-permission-item");
|
||||
container.setAttribute("align", "center");
|
||||
container.setAttribute("role", "group");
|
||||
|
||||
let img = document.createXULElement("image");
|
||||
img.classList.add("identity-popup-permission-icon", idNoSuffix + "-icon");
|
||||
if (
|
||||
permission.state == SitePermissions.BLOCK ||
|
||||
permission.state == SitePermissions.AUTOPLAY_BLOCKED_ALL
|
||||
) {
|
||||
img.classList.add("blocked-permission-icon");
|
||||
}
|
||||
|
||||
if (
|
||||
permission.sharingState ==
|
||||
Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED ||
|
||||
(idNoSuffix == "screen" &&
|
||||
permission.sharingState &&
|
||||
!permission.sharingState.includes("Paused"))
|
||||
) {
|
||||
img.classList.add("in-use");
|
||||
|
||||
// Synchronize control center and identity block blinking animations.
|
||||
window
|
||||
.promiseDocumentFlushed(() => {
|
||||
let sharingIconBlink = this._webRTCSharingIcon.getAnimations()[0];
|
||||
let imgBlink = img.getAnimations()[0];
|
||||
return [sharingIconBlink, imgBlink];
|
||||
})
|
||||
.then(([sharingIconBlink, imgBlink]) => {
|
||||
if (sharingIconBlink && imgBlink) {
|
||||
imgBlink.startTime = sharingIconBlink.startTime;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let nameLabel = document.createXULElement("label");
|
||||
nameLabel.setAttribute("flex", "1");
|
||||
nameLabel.setAttribute("class", "identity-popup-permission-label");
|
||||
let label = SitePermissions.getPermissionLabel(idNoSuffix);
|
||||
if (label === null) {
|
||||
return null;
|
||||
}
|
||||
if (nowrapLabel) {
|
||||
nameLabel.setAttribute("value", label);
|
||||
nameLabel.setAttribute("tooltiptext", label);
|
||||
nameLabel.setAttribute("crop", "end");
|
||||
} else {
|
||||
nameLabel.textContent = label;
|
||||
}
|
||||
let nameLabelId = "identity-popup-permission-label-" + idNoSuffix;
|
||||
nameLabel.setAttribute("id", nameLabelId);
|
||||
|
||||
let isPolicyPermission = [
|
||||
SitePermissions.SCOPE_POLICY,
|
||||
SitePermissions.SCOPE_GLOBAL,
|
||||
].includes(permission.scope);
|
||||
|
||||
if (
|
||||
(idNoSuffix == "popup" && !isPolicyPermission) ||
|
||||
idNoSuffix == "autoplay-media"
|
||||
) {
|
||||
let menulist = document.createXULElement("menulist");
|
||||
let menupopup = document.createXULElement("menupopup");
|
||||
let block = document.createXULElement("vbox");
|
||||
block.setAttribute("id", "identity-popup-popup-container");
|
||||
block.setAttribute("class", "identity-popup-permission-item-container");
|
||||
menulist.setAttribute("sizetopopup", "none");
|
||||
menulist.setAttribute("id", "identity-popup-popup-menulist");
|
||||
|
||||
for (let state of SitePermissions.getAvailableStates(idNoSuffix)) {
|
||||
let menuitem = document.createXULElement("menuitem");
|
||||
// We need to correctly display the default/unknown state, which has its
|
||||
// own integer value (0) but represents one of the other states.
|
||||
if (state == SitePermissions.getDefault(idNoSuffix)) {
|
||||
menuitem.setAttribute("value", "0");
|
||||
} else {
|
||||
menuitem.setAttribute("value", state);
|
||||
}
|
||||
|
||||
menuitem.setAttribute(
|
||||
"label",
|
||||
SitePermissions.getMultichoiceStateLabel(idNoSuffix, state)
|
||||
);
|
||||
menupopup.appendChild(menuitem);
|
||||
}
|
||||
|
||||
menulist.appendChild(menupopup);
|
||||
|
||||
if (permission.state == SitePermissions.getDefault(idNoSuffix)) {
|
||||
menulist.value = "0";
|
||||
} else {
|
||||
menulist.value = permission.state;
|
||||
}
|
||||
|
||||
// Avoiding listening to the "select" event on purpose. See Bug 1404262.
|
||||
menulist.addEventListener("command", () => {
|
||||
SitePermissions.setForPrincipal(
|
||||
gBrowser.contentPrincipal,
|
||||
idNoSuffix,
|
||||
menulist.selectedItem.value
|
||||
);
|
||||
});
|
||||
|
||||
container.appendChild(img);
|
||||
container.appendChild(nameLabel);
|
||||
container.appendChild(menulist);
|
||||
container.setAttribute("aria-labelledby", nameLabelId);
|
||||
block.appendChild(container);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
container.appendChild(img);
|
||||
container.appendChild(nameLabel);
|
||||
let labelledBy = nameLabelId;
|
||||
|
||||
if (showStateLabel) {
|
||||
let stateLabel = this._createStateLabel(permission, idNoSuffix);
|
||||
container.appendChild(stateLabel);
|
||||
labelledBy += " " + stateLabel.id;
|
||||
}
|
||||
|
||||
container.setAttribute("aria-labelledby", labelledBy);
|
||||
|
||||
/* We return the permission item here without a remove button if the permission is a
|
||||
SCOPE_POLICY or SCOPE_GLOBAL permission. Policy permissions cannot be
|
||||
removed/changed for the duration of the browser session. */
|
||||
if (isPolicyPermission) {
|
||||
return container;
|
||||
}
|
||||
|
||||
if (isContainer) {
|
||||
let block = document.createXULElement("vbox");
|
||||
block.setAttribute("id", "identity-popup-" + idNoSuffix + "-container");
|
||||
block.setAttribute("class", "identity-popup-permission-item-container");
|
||||
|
||||
if (permClearButton) {
|
||||
let button = this._createPermissionClearButton(permission, block);
|
||||
container.appendChild(button);
|
||||
}
|
||||
|
||||
block.appendChild(container);
|
||||
return block;
|
||||
}
|
||||
|
||||
if (permClearButton) {
|
||||
let button = this._createPermissionClearButton(permission, container);
|
||||
container.appendChild(button);
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
_createStateLabel(aPermission, idNoSuffix) {
|
||||
let label = document.createXULElement("label");
|
||||
label.setAttribute("flex", "1");
|
||||
label.setAttribute("class", "identity-popup-permission-state-label");
|
||||
let labelId = "identity-popup-permission-state-label-" + idNoSuffix;
|
||||
label.setAttribute("id", labelId);
|
||||
let { state, scope } = aPermission;
|
||||
// If the user did not permanently allow this device but it is currently
|
||||
// used, set the variables to display a "temporarily allowed" info.
|
||||
if (state != SitePermissions.ALLOW && aPermission.sharingState) {
|
||||
state = SitePermissions.ALLOW;
|
||||
scope = SitePermissions.SCOPE_REQUEST;
|
||||
}
|
||||
label.textContent = SitePermissions.getCurrentStateLabel(
|
||||
state,
|
||||
idNoSuffix,
|
||||
scope
|
||||
);
|
||||
return label;
|
||||
},
|
||||
|
||||
_removePermPersistentAllow(principal, id) {
|
||||
let perm = SitePermissions.getForPrincipal(principal, id);
|
||||
if (
|
||||
perm.state == SitePermissions.ALLOW &&
|
||||
perm.scope == SitePermissions.SCOPE_PERSISTENT
|
||||
) {
|
||||
SitePermissions.removeFromPrincipal(principal, id);
|
||||
}
|
||||
},
|
||||
|
||||
_createPermissionClearButton(
|
||||
aPermission,
|
||||
container,
|
||||
clearCallback = () => {}
|
||||
) {
|
||||
let button = document.createXULElement("button");
|
||||
button.setAttribute("class", "identity-popup-permission-remove-button");
|
||||
let tooltiptext = gNavigatorBundle.getString("permissions.remove.tooltip");
|
||||
button.setAttribute("tooltiptext", tooltiptext);
|
||||
button.addEventListener("command", () => {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
container.remove();
|
||||
if (aPermission.sharingState) {
|
||||
if (aPermission.id === "geo" || aPermission.id === "xr") {
|
||||
let origins = browser.getDevicePermissionOrigins(aPermission.id);
|
||||
for (let origin of origins) {
|
||||
let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
|
||||
origin
|
||||
);
|
||||
this._removePermPersistentAllow(principal, aPermission.id);
|
||||
}
|
||||
origins.clear();
|
||||
} else if (
|
||||
["camera", "microphone", "screen"].includes(aPermission.id)
|
||||
) {
|
||||
let windowId = this._sharingState.webRTC.windowId;
|
||||
if (aPermission.id == "screen") {
|
||||
windowId = "screen:" + windowId;
|
||||
} else {
|
||||
// If we set persistent permissions or the sharing has
|
||||
// started due to existing persistent permissions, we need
|
||||
// to handle removing these even for frames with different hostnames.
|
||||
let origins = browser.getDevicePermissionOrigins("webrtc");
|
||||
for (let origin of origins) {
|
||||
// It's not possible to stop sharing one of camera/microphone
|
||||
// without the other.
|
||||
let principal;
|
||||
for (let id of ["camera", "microphone"]) {
|
||||
if (this._sharingState.webRTC[id]) {
|
||||
if (!principal) {
|
||||
principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
|
||||
origin
|
||||
);
|
||||
}
|
||||
this._removePermPersistentAllow(principal, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let bc = this._sharingState.webRTC.browsingContext;
|
||||
bc.currentWindowGlobal
|
||||
.getActor("WebRTC")
|
||||
.sendAsyncMessage("webrtc:StopSharing", windowId);
|
||||
webrtcUI.forgetActivePermissionsFromBrowser(gBrowser.selectedBrowser);
|
||||
}
|
||||
}
|
||||
SitePermissions.removeFromPrincipal(
|
||||
gBrowser.contentPrincipal,
|
||||
aPermission.id,
|
||||
browser
|
||||
);
|
||||
|
||||
this._permissionReloadHint.removeAttribute("hidden");
|
||||
PanelView.forNode(
|
||||
this._identityPopupMainView
|
||||
).descriptionHeightWorkaround();
|
||||
|
||||
if (aPermission.id === "geo") {
|
||||
gBrowser.updateBrowserSharing(browser, { geo: false });
|
||||
} else if (aPermission.id === "xr") {
|
||||
gBrowser.updateBrowserSharing(browser, { xr: false });
|
||||
}
|
||||
|
||||
clearCallback();
|
||||
});
|
||||
|
||||
return button;
|
||||
},
|
||||
|
||||
_getGeoLocationLastAccess() {
|
||||
return new Promise(resolve => {
|
||||
let lastAccess = null;
|
||||
ContentPrefService2.getByDomainAndName(
|
||||
gBrowser.currentURI.spec,
|
||||
"permissions.geoLocation.lastAccess",
|
||||
gBrowser.selectedBrowser.loadContext,
|
||||
{
|
||||
handleResult(pref) {
|
||||
lastAccess = pref.value;
|
||||
},
|
||||
handleCompletion() {
|
||||
resolve(lastAccess);
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
async _createGeoLocationLastAccessIndicator() {
|
||||
let lastAccessStr = await this._getGeoLocationLastAccess();
|
||||
let geoContainer = document.getElementById("identity-popup-geo-container");
|
||||
|
||||
// Check whether geoContainer still exists.
|
||||
// We are async, the identity popup could have been closed already.
|
||||
// Also check if it is already populated with a time label.
|
||||
// This can happen if we update the permission panel multiple times in a
|
||||
// short timeframe.
|
||||
if (
|
||||
lastAccessStr == null ||
|
||||
!geoContainer ||
|
||||
document.getElementById("geo-access-indicator-item")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let lastAccess = new Date(lastAccessStr);
|
||||
if (isNaN(lastAccess)) {
|
||||
Cu.reportError("Invalid timestamp for last geolocation access");
|
||||
return;
|
||||
}
|
||||
|
||||
let icon = document.createXULElement("image");
|
||||
icon.setAttribute("class", "popup-subitem");
|
||||
|
||||
let indicator = document.createXULElement("hbox");
|
||||
indicator.setAttribute("class", "identity-popup-permission-item");
|
||||
indicator.setAttribute("align", "center");
|
||||
indicator.setAttribute("id", "geo-access-indicator-item");
|
||||
|
||||
let timeFormat = new Services.intl.RelativeTimeFormat(undefined, {});
|
||||
|
||||
let text = document.createXULElement("label");
|
||||
text.setAttribute("flex", "1");
|
||||
text.setAttribute("class", "identity-popup-permission-label");
|
||||
|
||||
text.textContent = gNavigatorBundle.getFormattedString(
|
||||
"geolocationLastAccessIndicatorText",
|
||||
[timeFormat.formatBestUnit(lastAccess)]
|
||||
);
|
||||
|
||||
indicator.appendChild(icon);
|
||||
indicator.appendChild(text);
|
||||
|
||||
geoContainer.appendChild(indicator);
|
||||
},
|
||||
|
||||
_createProtocolHandlerPermissionItem(permission, key) {
|
||||
let container = document.getElementById(
|
||||
"identity-popup-open-protocol-handler-container"
|
||||
);
|
||||
let initialCall;
|
||||
|
||||
if (!container) {
|
||||
// First open-protocol-handler permission, create container.
|
||||
container = this._createPermissionItem({
|
||||
permission,
|
||||
isContainer: true,
|
||||
permClearButton: false,
|
||||
showStateLabel: false,
|
||||
idNoSuffix: "open-protocol-handler",
|
||||
});
|
||||
initialCall = true;
|
||||
}
|
||||
|
||||
let icon = document.createXULElement("image");
|
||||
icon.setAttribute("class", "popup-subitem-no-arrow");
|
||||
|
||||
let item = document.createXULElement("hbox");
|
||||
item.setAttribute("class", "identity-popup-permission-item");
|
||||
item.setAttribute("align", "center");
|
||||
|
||||
let text = document.createXULElement("label");
|
||||
text.setAttribute("flex", "1");
|
||||
text.setAttribute("class", "identity-popup-permission-label-subitem");
|
||||
|
||||
text.textContent = gNavigatorBundle.getFormattedString(
|
||||
"openProtocolHandlerPermissionEntryLabel",
|
||||
[key]
|
||||
);
|
||||
|
||||
let stateLabel = this._createStateLabel(
|
||||
permission,
|
||||
"open-protocol-handler"
|
||||
);
|
||||
|
||||
item.appendChild(text);
|
||||
item.appendChild(stateLabel);
|
||||
|
||||
let button = this._createPermissionClearButton(permission, item, () => {
|
||||
// When we're clearing the last open-protocol-handler permission, clean up
|
||||
// the empty container.
|
||||
// (<= 1 because the heading item is also a child of the container)
|
||||
if (container.childElementCount <= 1) {
|
||||
container.remove();
|
||||
}
|
||||
});
|
||||
item.appendChild(button);
|
||||
|
||||
container.appendChild(item);
|
||||
|
||||
// If container already exists in permission list, don't return it again.
|
||||
return initialCall && container;
|
||||
},
|
||||
|
||||
_createBlockedPopupIndicator(aTotalBlockedPopups) {
|
||||
let indicator = document.createXULElement("hbox");
|
||||
indicator.setAttribute("class", "identity-popup-permission-item");
|
||||
indicator.setAttribute("align", "center");
|
||||
indicator.setAttribute("id", "blocked-popup-indicator-item");
|
||||
|
||||
let icon = document.createXULElement("image");
|
||||
icon.setAttribute("class", "popup-subitem");
|
||||
|
||||
let text = document.createXULElement("label", { is: "text-link" });
|
||||
text.setAttribute("flex", "1");
|
||||
text.setAttribute("class", "identity-popup-permission-label");
|
||||
|
||||
let messageBase = gNavigatorBundle.getString(
|
||||
"popupShowBlockedPopupsIndicatorText"
|
||||
);
|
||||
let message = PluralForm.get(aTotalBlockedPopups, messageBase).replace(
|
||||
"#1",
|
||||
aTotalBlockedPopups
|
||||
);
|
||||
text.textContent = message;
|
||||
|
||||
text.addEventListener("click", () => {
|
||||
gBrowser.selectedBrowser.popupBlocker.unblockAllPopups();
|
||||
});
|
||||
|
||||
indicator.appendChild(icon);
|
||||
indicator.appendChild(text);
|
||||
|
||||
document
|
||||
.getElementById("identity-popup-popup-container")
|
||||
.appendChild(indicator);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,958 @@
|
|||
/* 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/. */
|
||||
|
||||
/* eslint-env mozilla/browser-window */
|
||||
|
||||
/**
|
||||
* Utility object to handle manipulations of the identity permission indicators
|
||||
* in the UI.
|
||||
*/
|
||||
var gPermissionPanel = {
|
||||
_popupInitialized: false,
|
||||
_initializePopup() {
|
||||
if (!this._popupInitialized) {
|
||||
let wrapper = document.getElementById("template-permission-popup");
|
||||
wrapper.replaceWith(wrapper.content);
|
||||
this._popupInitialized = true;
|
||||
}
|
||||
},
|
||||
|
||||
hidePopup() {
|
||||
if (this._popupInitialized) {
|
||||
PanelMultiView.hidePopup(this._permissionPopup);
|
||||
}
|
||||
},
|
||||
|
||||
// smart getters
|
||||
get _identityPermissionBox() {
|
||||
delete this._identityPermissionBox;
|
||||
return (this._identityPermissionBox = document.getElementById(
|
||||
"identity-permission-box"
|
||||
));
|
||||
},
|
||||
get _permissionGrantedIcon() {
|
||||
delete this._permissionGrantedIcon;
|
||||
return (this._permissionGrantedIcon = document.getElementById(
|
||||
"permissions-granted-icon"
|
||||
));
|
||||
},
|
||||
get _permissionPopup() {
|
||||
if (!this._popupInitialized) {
|
||||
return null;
|
||||
}
|
||||
delete this._permissionPopup;
|
||||
return (this._permissionPopup = document.getElementById(
|
||||
"permission-popup"
|
||||
));
|
||||
},
|
||||
get _permissionPopupMainView() {
|
||||
delete this._permissionPopupPopupMainView;
|
||||
return (this._permissionPopupPopupMainView = document.getElementById(
|
||||
"permission-popup-mainView"
|
||||
));
|
||||
},
|
||||
get _permissionPopupMainViewHeaderLabel() {
|
||||
delete this._permissionPopupMainViewHeaderLabel;
|
||||
return (this._permissionPopupMainViewHeaderLabel = document.getElementById(
|
||||
"permission-popup-mainView-panel-header-span"
|
||||
));
|
||||
},
|
||||
get _permissionList() {
|
||||
delete this._permissionList;
|
||||
return (this._permissionList = document.getElementById(
|
||||
"permission-popup-permission-list"
|
||||
));
|
||||
},
|
||||
get _defaultPermissionAnchor() {
|
||||
delete this._defaultPermissionAnchor;
|
||||
return (this._defaultPermissionAnchor = document.getElementById(
|
||||
"permission-popup-permission-list-default-anchor"
|
||||
));
|
||||
},
|
||||
get _permissionReloadHint() {
|
||||
delete this._permissionReloadHint;
|
||||
return (this._permissionReloadHint = document.getElementById(
|
||||
"permission-popup-permission-reload-hint"
|
||||
));
|
||||
},
|
||||
get _permissionAnchors() {
|
||||
delete this._permissionAnchors;
|
||||
let permissionAnchors = {};
|
||||
for (let anchor of document.getElementById("blocked-permissions-container")
|
||||
.children) {
|
||||
permissionAnchors[anchor.getAttribute("data-permission-id")] = anchor;
|
||||
}
|
||||
return (this._permissionAnchors = permissionAnchors);
|
||||
},
|
||||
|
||||
get _geoSharingIcon() {
|
||||
delete this._geoSharingIcon;
|
||||
return (this._geoSharingIcon = document.getElementById("geo-sharing-icon"));
|
||||
},
|
||||
|
||||
get _xrSharingIcon() {
|
||||
delete this._xrSharingIcon;
|
||||
return (this._xrSharingIcon = document.getElementById("xr-sharing-icon"));
|
||||
},
|
||||
|
||||
get _webRTCSharingIcon() {
|
||||
delete this._webRTCSharingIcon;
|
||||
return (this._webRTCSharingIcon = document.getElementById(
|
||||
"webrtc-sharing-icon"
|
||||
));
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh the contents of the permission popup. This includes the headline
|
||||
* and the list of permissions.
|
||||
*/
|
||||
_refreshPermissionPopup() {
|
||||
let host = gIdentityHandler.getHostForDisplay();
|
||||
|
||||
// Update header label
|
||||
this._permissionPopupMainViewHeaderLabel.textContent = gNavigatorBundle.getFormattedString(
|
||||
"permissions.header",
|
||||
[host]
|
||||
);
|
||||
|
||||
// Refresh the permission list
|
||||
this.updateSitePermissions();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by gIdentityHandler to hide permission icons for invalid proxy
|
||||
* state.
|
||||
*/
|
||||
hidePermissionIcons() {
|
||||
this._identityPermissionBox.removeAttribute("hasGrantedPermissions");
|
||||
this._identityPermissionBox.removeAttribute("hasPermissionIcon");
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the permissions icons in the identity block.
|
||||
* We show icons for blocked permissions / popups.
|
||||
*/
|
||||
refreshPermissionIcons() {
|
||||
let permissionAnchors = this._permissionAnchors;
|
||||
|
||||
// hide all permission icons
|
||||
for (let icon of Object.values(permissionAnchors)) {
|
||||
icon.removeAttribute("showing");
|
||||
}
|
||||
|
||||
// keeps track if we should show an indicator that there are active permissions
|
||||
let hasGrantedPermissions = false;
|
||||
let hasPermissionIcon = false;
|
||||
|
||||
// show permission icons
|
||||
let permissions = SitePermissions.getAllForBrowser(
|
||||
gBrowser.selectedBrowser
|
||||
);
|
||||
for (let permission of permissions) {
|
||||
if (
|
||||
permission.state == SitePermissions.BLOCK ||
|
||||
permission.state == SitePermissions.AUTOPLAY_BLOCKED_ALL
|
||||
) {
|
||||
let icon = permissionAnchors[permission.id];
|
||||
if (icon) {
|
||||
icon.setAttribute("showing", "true");
|
||||
hasPermissionIcon = true;
|
||||
}
|
||||
} else if (permission.state != SitePermissions.UNKNOWN) {
|
||||
hasGrantedPermissions = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Show blocked popup icon in the identity-box if popups are blocked
|
||||
// irrespective of popup permission capability value.
|
||||
if (gBrowser.selectedBrowser.popupBlocker.getBlockedPopupCount()) {
|
||||
let icon = permissionAnchors.popup;
|
||||
icon.setAttribute("showing", "true");
|
||||
hasPermissionIcon = true;
|
||||
}
|
||||
|
||||
this._identityPermissionBox.toggleAttribute(
|
||||
"hasGrantedPermissions",
|
||||
hasGrantedPermissions
|
||||
);
|
||||
this._identityPermissionBox.toggleAttribute(
|
||||
"hasPermissionIcon",
|
||||
hasPermissionIcon
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the permission popup.
|
||||
* @param {Event} event - Event which caused the popup to show.
|
||||
*/
|
||||
_openPopup(event) {
|
||||
// Make the popup available.
|
||||
this._initializePopup();
|
||||
|
||||
// Remove the reload hint that we show after a user has cleared a permission.
|
||||
this._permissionReloadHint.setAttribute("hidden", "true");
|
||||
|
||||
// Update the popup strings
|
||||
this._refreshPermissionPopup();
|
||||
|
||||
// Add the "open" attribute to the button in the identity box for styling
|
||||
this._identityPermissionBox.setAttribute("open", "true");
|
||||
|
||||
// Check the panel state of other panels. Hide them if needed.
|
||||
let openPanels = Array.from(document.querySelectorAll("panel[openpanel]"));
|
||||
for (let panel of openPanels) {
|
||||
PanelMultiView.hidePopup(panel);
|
||||
}
|
||||
|
||||
// Now open the popup, anchored off the primary chrome element
|
||||
PanelMultiView.openPopup(
|
||||
this._permissionPopup,
|
||||
this._identityPermissionBox,
|
||||
{
|
||||
position: "bottomcenter topleft",
|
||||
triggerEvent: event,
|
||||
}
|
||||
).catch(Cu.reportError);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update identity permission indicators based on sharing state of the
|
||||
* selected tab. This should be called externally whenever the sharing state
|
||||
* of the selected tab changes.
|
||||
*/
|
||||
updateSharingIndicator() {
|
||||
let tab = gBrowser.selectedTab;
|
||||
this._sharingState = tab._sharingState;
|
||||
|
||||
this._webRTCSharingIcon.removeAttribute("paused");
|
||||
this._webRTCSharingIcon.removeAttribute("sharing");
|
||||
this._geoSharingIcon.removeAttribute("sharing");
|
||||
this._xrSharingIcon.removeAttribute("sharing");
|
||||
|
||||
let hasSharingIcon = false;
|
||||
|
||||
if (this._sharingState) {
|
||||
if (this._sharingState.webRTC?.sharing) {
|
||||
this._webRTCSharingIcon.setAttribute(
|
||||
"sharing",
|
||||
this._sharingState.webRTC.sharing
|
||||
);
|
||||
hasSharingIcon = true;
|
||||
|
||||
if (this._sharingState.webRTC?.paused) {
|
||||
this._webRTCSharingIcon.setAttribute("paused", "true");
|
||||
}
|
||||
}
|
||||
if (this._sharingState.geo) {
|
||||
this._geoSharingIcon.setAttribute("sharing", this._sharingState.geo);
|
||||
hasSharingIcon = true;
|
||||
}
|
||||
if (this._sharingState.xr) {
|
||||
this._xrSharingIcon.setAttribute("sharing", this._sharingState.xr);
|
||||
hasSharingIcon = true;
|
||||
}
|
||||
}
|
||||
|
||||
this._identityPermissionBox.toggleAttribute(
|
||||
"hasSharingIcon",
|
||||
hasSharingIcon
|
||||
);
|
||||
|
||||
if (this._popupInitialized && this._permissionPopup.state != "closed") {
|
||||
this.updateSitePermissions();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Click handler for the permission-box element in primary chrome.
|
||||
*/
|
||||
handleIdentityButtonEvent(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
if (
|
||||
(event.type == "click" && event.button != 0) ||
|
||||
(event.type == "keypress" &&
|
||||
event.charCode != KeyEvent.DOM_VK_SPACE &&
|
||||
event.keyCode != KeyEvent.DOM_VK_RETURN)
|
||||
) {
|
||||
return; // Left click, space or enter only
|
||||
}
|
||||
|
||||
// Don't allow left click, space or enter if the location has been modified,
|
||||
// so long as we're not sharing any devices.
|
||||
// If we are sharing a device, the identity block is prevented by CSS from
|
||||
// being focused (and therefore, interacted with) by the user. However, we
|
||||
// want to allow opening the identity popup from the device control menu,
|
||||
// which calls click() on the identity button, so we don't return early.
|
||||
if (
|
||||
!this._sharingState &&
|
||||
gURLBar.getAttribute("pageproxystate") != "valid"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are in DOM fullscreen, exit it before showing the permission popup
|
||||
// (see bug 1557041)
|
||||
if (document.fullscreen) {
|
||||
// Open the identity popup after DOM fullscreen exit
|
||||
// We need to wait for the exit event and after that wait for the fullscreen exit transition to complete
|
||||
// If we call _openPopup before the fullscreen transition ends it can get cancelled
|
||||
// Only waiting for painted is not sufficient because we could still be in the fullscreen enter transition.
|
||||
this._exitedEventReceived = false;
|
||||
this._event = event;
|
||||
Services.obs.addObserver(this, "fullscreen-painted");
|
||||
window.addEventListener(
|
||||
"MozDOMFullscreen:Exited",
|
||||
() => {
|
||||
this._exitedEventReceived = true;
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
document.exitFullscreen();
|
||||
return;
|
||||
}
|
||||
|
||||
this._openPopup(event);
|
||||
},
|
||||
|
||||
onPopupShown(event) {
|
||||
if (event.target == this._permissionPopup) {
|
||||
window.addEventListener("focus", this, true);
|
||||
}
|
||||
},
|
||||
|
||||
onPopupHidden(event) {
|
||||
if (event.target == this._permissionPopup) {
|
||||
window.removeEventListener("focus", this, true);
|
||||
this._identityPermissionBox.removeAttribute("open");
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
let elem = document.activeElement;
|
||||
let position = elem.compareDocumentPosition(this._permissionPopup);
|
||||
|
||||
if (
|
||||
!(
|
||||
position &
|
||||
(Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_CONTAINED_BY)
|
||||
) &&
|
||||
!this._permissionPopup.hasAttribute("noautohide")
|
||||
) {
|
||||
// Hide the panel when focusing an element that is
|
||||
// neither an ancestor nor descendant unless the panel has
|
||||
// @noautohide (e.g. for a tour).
|
||||
PanelMultiView.hidePopup(this._permissionPopup);
|
||||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "fullscreen-painted": {
|
||||
if (subject != window || !this._exitedEventReceived) {
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(this, "fullscreen-painted");
|
||||
this._openPopup(this._event);
|
||||
delete this._event;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onLocationChange() {
|
||||
if (this._popupInitialized && this._permissionPopup.state != "closed") {
|
||||
this._permissionReloadHint.setAttribute("hidden", "true");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the permission list in the permissions popup.
|
||||
*/
|
||||
updateSitePermissions() {
|
||||
let permissionItemSelector = [
|
||||
".permission-popup-permission-item, .permission-popup-permission-item-container",
|
||||
];
|
||||
this._permissionList
|
||||
.querySelectorAll(permissionItemSelector)
|
||||
.forEach(e => e.remove());
|
||||
|
||||
let permissions = SitePermissions.getAllPermissionDetailsForBrowser(
|
||||
gBrowser.selectedBrowser
|
||||
);
|
||||
|
||||
this._sharingState = gBrowser.selectedTab._sharingState;
|
||||
|
||||
if (this._sharingState?.geo) {
|
||||
let geoPermission = permissions.find(perm => perm.id === "geo");
|
||||
if (geoPermission) {
|
||||
geoPermission.sharingState = true;
|
||||
} else {
|
||||
permissions.push({
|
||||
id: "geo",
|
||||
state: SitePermissions.ALLOW,
|
||||
scope: SitePermissions.SCOPE_REQUEST,
|
||||
sharingState: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this._sharingState?.xr) {
|
||||
let xrPermission = permissions.find(perm => perm.id === "xr");
|
||||
if (xrPermission) {
|
||||
xrPermission.sharingState = true;
|
||||
} else {
|
||||
permissions.push({
|
||||
id: "xr",
|
||||
state: SitePermissions.ALLOW,
|
||||
scope: SitePermissions.SCOPE_REQUEST,
|
||||
sharingState: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this._sharingState?.webRTC) {
|
||||
let webrtcState = this._sharingState.webRTC;
|
||||
// If WebRTC device or screen permissions are in use, we need to find
|
||||
// the associated permission item to set the sharingState field.
|
||||
for (let id of ["camera", "microphone", "screen"]) {
|
||||
if (webrtcState[id]) {
|
||||
let found = false;
|
||||
for (let permission of permissions) {
|
||||
if (permission.id != id) {
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
permission.sharingState = webrtcState[id];
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
// If the permission item we were looking for doesn't exist,
|
||||
// the user has temporarily allowed sharing and we need to add
|
||||
// an item in the permissions array to reflect this.
|
||||
permissions.push({
|
||||
id,
|
||||
state: SitePermissions.ALLOW,
|
||||
scope: SitePermissions.SCOPE_REQUEST,
|
||||
sharingState: webrtcState[id],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let totalBlockedPopups = gBrowser.selectedBrowser.popupBlocker.getBlockedPopupCount();
|
||||
let hasBlockedPopupIndicator = false;
|
||||
for (let permission of permissions) {
|
||||
let [id, key] = permission.id.split(SitePermissions.PERM_KEY_DELIMITER);
|
||||
|
||||
if (id == "storage-access") {
|
||||
// Ignore storage access permissions here, they are made visible inside
|
||||
// the Content Blocking UI.
|
||||
continue;
|
||||
}
|
||||
|
||||
let item;
|
||||
let anchor =
|
||||
this._permissionList.querySelector(`[anchorfor="${id}"]`) ||
|
||||
this._defaultPermissionAnchor;
|
||||
|
||||
if (id == "open-protocol-handler") {
|
||||
let permContainer = this._createProtocolHandlerPermissionItem(
|
||||
permission,
|
||||
key
|
||||
);
|
||||
if (permContainer) {
|
||||
anchor.appendChild(permContainer);
|
||||
}
|
||||
} else {
|
||||
item = this._createPermissionItem({
|
||||
permission,
|
||||
isContainer: id == "geo" || id == "xr",
|
||||
nowrapLabel: id == "3rdPartyStorage",
|
||||
});
|
||||
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
anchor.appendChild(item);
|
||||
}
|
||||
|
||||
if (id == "popup" && totalBlockedPopups) {
|
||||
this._createBlockedPopupIndicator(totalBlockedPopups);
|
||||
hasBlockedPopupIndicator = true;
|
||||
} else if (id == "geo" && permission.state === SitePermissions.ALLOW) {
|
||||
this._createGeoLocationLastAccessIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
if (totalBlockedPopups && !hasBlockedPopupIndicator) {
|
||||
let permission = {
|
||||
id: "popup",
|
||||
state: SitePermissions.getDefault("popup"),
|
||||
scope: SitePermissions.SCOPE_PERSISTENT,
|
||||
};
|
||||
let item = this._createPermissionItem({ permission });
|
||||
this._defaultPermissionAnchor.appendChild(item);
|
||||
this._createBlockedPopupIndicator(totalBlockedPopups);
|
||||
}
|
||||
|
||||
PanelView.forNode(
|
||||
this._permissionPopupMainView
|
||||
).descriptionHeightWorkaround();
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a permission item based on the supplied options and returns it.
|
||||
* It is up to the caller to actually insert the element somewhere.
|
||||
*
|
||||
* @param permission - An object containing information representing the
|
||||
* permission, typically obtained via SitePermissions.jsm
|
||||
* @param isContainer - If true, the permission item will be added to a vbox
|
||||
* and the vbox will be returned.
|
||||
* @param permClearButton - Whether to show an "x" button to clear the permission
|
||||
* @param showStateLabel - Whether to show a label indicating the current status
|
||||
* of the permission e.g. "Temporary Allowed"
|
||||
* @param idNoSuffix - Some permission types have additional information suffixed
|
||||
* to the ID - callers can pass the unsuffixed ID via this
|
||||
* parameter to indicate the permission type manually.
|
||||
* @param nowrapLabel - Whether to prevent the permission item's label from
|
||||
* wrapping its text content. This allows styling text-overflow
|
||||
* and is useful for e.g. 3rdPartyStorage permissions whose
|
||||
* labels are origins - which could be of any length.
|
||||
*/
|
||||
_createPermissionItem({
|
||||
permission,
|
||||
isContainer = false,
|
||||
permClearButton = true,
|
||||
showStateLabel = true,
|
||||
idNoSuffix = permission.id,
|
||||
nowrapLabel = false,
|
||||
}) {
|
||||
let container = document.createXULElement("hbox");
|
||||
container.setAttribute("class", "permission-popup-permission-item");
|
||||
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");
|
||||
}
|
||||
|
||||
if (
|
||||
permission.sharingState ==
|
||||
Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED ||
|
||||
(idNoSuffix == "screen" &&
|
||||
permission.sharingState &&
|
||||
!permission.sharingState.includes("Paused"))
|
||||
) {
|
||||
img.classList.add("in-use");
|
||||
|
||||
// Synchronize permission panel and identity block blinking animations.
|
||||
window
|
||||
.promiseDocumentFlushed(() => {
|
||||
let sharingIconBlink = this._webRTCSharingIcon.getAnimations()[0];
|
||||
let imgBlink = img.getAnimations()[0];
|
||||
return [sharingIconBlink, imgBlink];
|
||||
})
|
||||
.then(([sharingIconBlink, imgBlink]) => {
|
||||
if (sharingIconBlink && imgBlink) {
|
||||
imgBlink.startTime = sharingIconBlink.startTime;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let nameLabel = document.createXULElement("label");
|
||||
nameLabel.setAttribute("flex", "1");
|
||||
nameLabel.setAttribute("class", "permission-popup-permission-label");
|
||||
let label = SitePermissions.getPermissionLabel(idNoSuffix);
|
||||
if (label === null) {
|
||||
return null;
|
||||
}
|
||||
if (nowrapLabel) {
|
||||
nameLabel.setAttribute("value", label);
|
||||
nameLabel.setAttribute("tooltiptext", label);
|
||||
nameLabel.setAttribute("crop", "end");
|
||||
} else {
|
||||
nameLabel.textContent = label;
|
||||
}
|
||||
let nameLabelId = "permission-popup-permission-label-" + idNoSuffix;
|
||||
nameLabel.setAttribute("id", nameLabelId);
|
||||
|
||||
let isPolicyPermission = [
|
||||
SitePermissions.SCOPE_POLICY,
|
||||
SitePermissions.SCOPE_GLOBAL,
|
||||
].includes(permission.scope);
|
||||
|
||||
if (
|
||||
(idNoSuffix == "popup" && !isPolicyPermission) ||
|
||||
idNoSuffix == "autoplay-media"
|
||||
) {
|
||||
let menulist = document.createXULElement("menulist");
|
||||
let menupopup = document.createXULElement("menupopup");
|
||||
let block = document.createXULElement("vbox");
|
||||
block.setAttribute("id", "permission-popup-container");
|
||||
block.setAttribute("class", "permission-popup-permission-item-container");
|
||||
menulist.setAttribute("sizetopopup", "none");
|
||||
menulist.setAttribute("id", "permission-popup-menulist");
|
||||
|
||||
for (let state of SitePermissions.getAvailableStates(idNoSuffix)) {
|
||||
let menuitem = document.createXULElement("menuitem");
|
||||
// We need to correctly display the default/unknown state, which has its
|
||||
// own integer value (0) but represents one of the other states.
|
||||
if (state == SitePermissions.getDefault(idNoSuffix)) {
|
||||
menuitem.setAttribute("value", "0");
|
||||
} else {
|
||||
menuitem.setAttribute("value", state);
|
||||
}
|
||||
|
||||
menuitem.setAttribute(
|
||||
"label",
|
||||
SitePermissions.getMultichoiceStateLabel(idNoSuffix, state)
|
||||
);
|
||||
menupopup.appendChild(menuitem);
|
||||
}
|
||||
|
||||
menulist.appendChild(menupopup);
|
||||
|
||||
if (permission.state == SitePermissions.getDefault(idNoSuffix)) {
|
||||
menulist.value = "0";
|
||||
} else {
|
||||
menulist.value = permission.state;
|
||||
}
|
||||
|
||||
// Avoiding listening to the "select" event on purpose. See Bug 1404262.
|
||||
menulist.addEventListener("command", () => {
|
||||
SitePermissions.setForPrincipal(
|
||||
gBrowser.contentPrincipal,
|
||||
idNoSuffix,
|
||||
menulist.selectedItem.value
|
||||
);
|
||||
});
|
||||
|
||||
container.appendChild(img);
|
||||
container.appendChild(nameLabel);
|
||||
container.appendChild(menulist);
|
||||
container.setAttribute("aria-labelledby", nameLabelId);
|
||||
block.appendChild(container);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
container.appendChild(img);
|
||||
container.appendChild(nameLabel);
|
||||
let labelledBy = nameLabelId;
|
||||
|
||||
if (showStateLabel) {
|
||||
let stateLabel = this._createStateLabel(permission, idNoSuffix);
|
||||
container.appendChild(stateLabel);
|
||||
labelledBy += " " + stateLabel.id;
|
||||
}
|
||||
|
||||
container.setAttribute("aria-labelledby", labelledBy);
|
||||
|
||||
/* We return the permission item here without a remove button if the permission is a
|
||||
SCOPE_POLICY or SCOPE_GLOBAL permission. Policy permissions cannot be
|
||||
removed/changed for the duration of the browser session. */
|
||||
if (isPolicyPermission) {
|
||||
return container;
|
||||
}
|
||||
|
||||
if (isContainer) {
|
||||
let block = document.createXULElement("vbox");
|
||||
block.setAttribute("id", "permission-popup-" + idNoSuffix + "-container");
|
||||
block.setAttribute("class", "permission-popup-permission-item-container");
|
||||
|
||||
if (permClearButton) {
|
||||
let button = this._createPermissionClearButton(permission, block);
|
||||
container.appendChild(button);
|
||||
}
|
||||
|
||||
block.appendChild(container);
|
||||
return block;
|
||||
}
|
||||
|
||||
if (permClearButton) {
|
||||
let button = this._createPermissionClearButton(permission, container);
|
||||
container.appendChild(button);
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
_createStateLabel(aPermission, idNoSuffix) {
|
||||
let label = document.createXULElement("label");
|
||||
label.setAttribute("flex", "1");
|
||||
label.setAttribute("class", "permission-popup-permission-state-label");
|
||||
let labelId = "permission-popup-permission-state-label-" + idNoSuffix;
|
||||
label.setAttribute("id", labelId);
|
||||
let { state, scope } = aPermission;
|
||||
// If the user did not permanently allow this device but it is currently
|
||||
// used, set the variables to display a "temporarily allowed" info.
|
||||
if (state != SitePermissions.ALLOW && aPermission.sharingState) {
|
||||
state = SitePermissions.ALLOW;
|
||||
scope = SitePermissions.SCOPE_REQUEST;
|
||||
}
|
||||
label.textContent = SitePermissions.getCurrentStateLabel(
|
||||
state,
|
||||
idNoSuffix,
|
||||
scope
|
||||
);
|
||||
return label;
|
||||
},
|
||||
|
||||
_removePermPersistentAllow(principal, id) {
|
||||
let perm = SitePermissions.getForPrincipal(principal, id);
|
||||
if (
|
||||
perm.state == SitePermissions.ALLOW &&
|
||||
perm.scope == SitePermissions.SCOPE_PERSISTENT
|
||||
) {
|
||||
SitePermissions.removeFromPrincipal(principal, id);
|
||||
}
|
||||
},
|
||||
|
||||
_createPermissionClearButton(
|
||||
aPermission,
|
||||
container,
|
||||
clearCallback = () => {}
|
||||
) {
|
||||
let button = document.createXULElement("button");
|
||||
button.setAttribute("class", "permission-popup-permission-remove-button");
|
||||
let tooltiptext = gNavigatorBundle.getString("permissions.remove.tooltip");
|
||||
button.setAttribute("tooltiptext", tooltiptext);
|
||||
button.addEventListener("command", () => {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
container.remove();
|
||||
if (aPermission.sharingState) {
|
||||
if (aPermission.id === "geo" || aPermission.id === "xr") {
|
||||
let origins = browser.getDevicePermissionOrigins(aPermission.id);
|
||||
for (let origin of origins) {
|
||||
let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
|
||||
origin
|
||||
);
|
||||
this._removePermPersistentAllow(principal, aPermission.id);
|
||||
}
|
||||
origins.clear();
|
||||
} else if (
|
||||
["camera", "microphone", "screen"].includes(aPermission.id)
|
||||
) {
|
||||
let windowId = this._sharingState.webRTC.windowId;
|
||||
if (aPermission.id == "screen") {
|
||||
windowId = "screen:" + windowId;
|
||||
} else {
|
||||
// If we set persistent permissions or the sharing has
|
||||
// started due to existing persistent permissions, we need
|
||||
// to handle removing these even for frames with different hostnames.
|
||||
let origins = browser.getDevicePermissionOrigins("webrtc");
|
||||
for (let origin of origins) {
|
||||
// It's not possible to stop sharing one of camera/microphone
|
||||
// without the other.
|
||||
let principal;
|
||||
for (let id of ["camera", "microphone"]) {
|
||||
if (this._sharingState.webRTC[id]) {
|
||||
if (!principal) {
|
||||
principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
|
||||
origin
|
||||
);
|
||||
}
|
||||
this._removePermPersistentAllow(principal, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let bc = this._sharingState.webRTC.browsingContext;
|
||||
bc.currentWindowGlobal
|
||||
.getActor("WebRTC")
|
||||
.sendAsyncMessage("webrtc:StopSharing", windowId);
|
||||
webrtcUI.forgetActivePermissionsFromBrowser(gBrowser.selectedBrowser);
|
||||
}
|
||||
}
|
||||
SitePermissions.removeFromPrincipal(
|
||||
gBrowser.contentPrincipal,
|
||||
aPermission.id,
|
||||
browser
|
||||
);
|
||||
|
||||
this._permissionReloadHint.removeAttribute("hidden");
|
||||
PanelView.forNode(
|
||||
this._permissionPopupMainView
|
||||
).descriptionHeightWorkaround();
|
||||
|
||||
if (aPermission.id === "geo") {
|
||||
gBrowser.updateBrowserSharing(browser, { geo: false });
|
||||
} else if (aPermission.id === "xr") {
|
||||
gBrowser.updateBrowserSharing(browser, { xr: false });
|
||||
}
|
||||
|
||||
clearCallback();
|
||||
});
|
||||
|
||||
return button;
|
||||
},
|
||||
|
||||
_getGeoLocationLastAccess() {
|
||||
return new Promise(resolve => {
|
||||
let lastAccess = null;
|
||||
ContentPrefService2.getByDomainAndName(
|
||||
gBrowser.currentURI.spec,
|
||||
"permissions.geoLocation.lastAccess",
|
||||
gBrowser.selectedBrowser.loadContext,
|
||||
{
|
||||
handleResult(pref) {
|
||||
lastAccess = pref.value;
|
||||
},
|
||||
handleCompletion() {
|
||||
resolve(lastAccess);
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
async _createGeoLocationLastAccessIndicator() {
|
||||
let lastAccessStr = await this._getGeoLocationLastAccess();
|
||||
let geoContainer = document.getElementById(
|
||||
"permission-popup-geo-container"
|
||||
);
|
||||
|
||||
// Check whether geoContainer still exists.
|
||||
// We are async, the identity popup could have been closed already.
|
||||
// Also check if it is already populated with a time label.
|
||||
// This can happen if we update the permission panel multiple times in a
|
||||
// short timeframe.
|
||||
if (
|
||||
lastAccessStr == null ||
|
||||
!geoContainer ||
|
||||
document.getElementById("geo-access-indicator-item")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let lastAccess = new Date(lastAccessStr);
|
||||
if (isNaN(lastAccess)) {
|
||||
Cu.reportError("Invalid timestamp for last geolocation access");
|
||||
return;
|
||||
}
|
||||
|
||||
let icon = document.createXULElement("image");
|
||||
icon.setAttribute("class", "popup-subitem");
|
||||
|
||||
let indicator = document.createXULElement("hbox");
|
||||
indicator.setAttribute("class", "permission-popup-permission-item");
|
||||
indicator.setAttribute("align", "center");
|
||||
indicator.setAttribute("id", "geo-access-indicator-item");
|
||||
|
||||
let timeFormat = new Services.intl.RelativeTimeFormat(undefined, {});
|
||||
|
||||
let text = document.createXULElement("label");
|
||||
text.setAttribute("flex", "1");
|
||||
text.setAttribute("class", "permission-popup-permission-label");
|
||||
|
||||
text.textContent = gNavigatorBundle.getFormattedString(
|
||||
"geolocationLastAccessIndicatorText",
|
||||
[timeFormat.formatBestUnit(lastAccess)]
|
||||
);
|
||||
|
||||
indicator.appendChild(icon);
|
||||
indicator.appendChild(text);
|
||||
|
||||
geoContainer.appendChild(indicator);
|
||||
},
|
||||
|
||||
_createProtocolHandlerPermissionItem(permission, key) {
|
||||
let container = document.getElementById(
|
||||
"permission-popup-open-protocol-handler-container"
|
||||
);
|
||||
let initialCall;
|
||||
|
||||
if (!container) {
|
||||
// First open-protocol-handler permission, create container.
|
||||
container = this._createPermissionItem({
|
||||
permission,
|
||||
isContainer: true,
|
||||
permClearButton: false,
|
||||
showStateLabel: false,
|
||||
idNoSuffix: "open-protocol-handler",
|
||||
});
|
||||
initialCall = true;
|
||||
}
|
||||
|
||||
let icon = document.createXULElement("image");
|
||||
icon.setAttribute("class", "popup-subitem-no-arrow");
|
||||
|
||||
let item = document.createXULElement("hbox");
|
||||
item.setAttribute("class", "permission-popup-permission-item");
|
||||
item.setAttribute("align", "center");
|
||||
|
||||
let text = document.createXULElement("label");
|
||||
text.setAttribute("flex", "1");
|
||||
text.setAttribute("class", "permission-popup-permission-label-subitem");
|
||||
|
||||
text.textContent = gNavigatorBundle.getFormattedString(
|
||||
"openProtocolHandlerPermissionEntryLabel",
|
||||
[key]
|
||||
);
|
||||
|
||||
let stateLabel = this._createStateLabel(
|
||||
permission,
|
||||
"open-protocol-handler"
|
||||
);
|
||||
|
||||
item.appendChild(text);
|
||||
item.appendChild(stateLabel);
|
||||
|
||||
let button = this._createPermissionClearButton(permission, item, () => {
|
||||
// When we're clearing the last open-protocol-handler permission, clean up
|
||||
// the empty container.
|
||||
// (<= 1 because the heading item is also a child of the container)
|
||||
if (container.childElementCount <= 1) {
|
||||
container.remove();
|
||||
}
|
||||
});
|
||||
item.appendChild(button);
|
||||
|
||||
container.appendChild(item);
|
||||
|
||||
// If container already exists in permission list, don't return it again.
|
||||
return initialCall && container;
|
||||
},
|
||||
|
||||
_createBlockedPopupIndicator(aTotalBlockedPopups) {
|
||||
let indicator = document.createXULElement("hbox");
|
||||
indicator.setAttribute("class", "permission-popup-permission-item");
|
||||
indicator.setAttribute("align", "center");
|
||||
indicator.setAttribute("id", "blocked-popup-indicator-item");
|
||||
|
||||
let icon = document.createXULElement("image");
|
||||
icon.setAttribute("class", "popup-subitem");
|
||||
|
||||
let text = document.createXULElement("label", { is: "text-link" });
|
||||
text.setAttribute("flex", "1");
|
||||
text.setAttribute("class", "permission-popup-permission-label");
|
||||
|
||||
let messageBase = gNavigatorBundle.getString(
|
||||
"popupShowBlockedPopupsIndicatorText"
|
||||
);
|
||||
let message = PluralForm.get(aTotalBlockedPopups, messageBase).replace(
|
||||
"#1",
|
||||
aTotalBlockedPopups
|
||||
);
|
||||
text.textContent = message;
|
||||
|
||||
text.addEventListener("click", () => {
|
||||
gBrowser.selectedBrowser.popupBlocker.unblockAllPopups();
|
||||
});
|
||||
|
||||
indicator.appendChild(icon);
|
||||
indicator.appendChild(text);
|
||||
|
||||
document
|
||||
.getElementById("permission-popup-container")
|
||||
.appendChild(indicator);
|
||||
},
|
||||
};
|
|
@ -999,7 +999,7 @@ var ThirdPartyCookies = {
|
|||
}
|
||||
|
||||
let removeException = document.createXULElement("button");
|
||||
removeException.className = "identity-popup-permission-remove-button";
|
||||
removeException.className = "permission-popup-permission-remove-button";
|
||||
removeException.tooltipText = gNavigatorBundle.getFormattedString(
|
||||
"contentBlocking.cookiesView.removeButton.tooltip",
|
||||
[origin]
|
||||
|
|
|
@ -738,7 +738,7 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
|
|||
min-width: 280px;
|
||||
}
|
||||
|
||||
#identity-box {
|
||||
#identity-icon-box {
|
||||
max-width: calc(30px + 10em);
|
||||
}
|
||||
|
||||
|
@ -752,7 +752,7 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
|
|||
:root[customizing] #urlbar-container {
|
||||
min-width: 245px;
|
||||
}
|
||||
#identity-box {
|
||||
#identity-icon-box {
|
||||
max-width: 80px;
|
||||
}
|
||||
/* Contenxtual identity labels are user-customizable and can be very long,
|
||||
|
@ -779,7 +779,7 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
|
|||
#nav-bar[downloadsbuttonshown] #urlbar-container {
|
||||
min-width: 225px;
|
||||
}
|
||||
#identity-box {
|
||||
#identity-icon-box {
|
||||
max-width: 70px;
|
||||
}
|
||||
#urlbar-zoom-button {
|
||||
|
|
|
@ -165,6 +165,11 @@ XPCOMUtils.defineLazyScriptGetter(
|
|||
"gIdentityHandler",
|
||||
"chrome://browser/content/browser-siteIdentity.js"
|
||||
);
|
||||
XPCOMUtils.defineLazyScriptGetter(
|
||||
this,
|
||||
"gPermissionPanel",
|
||||
"chrome://browser/content/browser-sitePermissionPanel.js"
|
||||
);
|
||||
XPCOMUtils.defineLazyScriptGetter(
|
||||
this,
|
||||
"gProtectionsHandler",
|
||||
|
@ -1036,7 +1041,7 @@ var gPopupBlockerObserver = {
|
|||
return;
|
||||
}
|
||||
|
||||
gIdentityHandler.refreshIdentityBlock();
|
||||
gPermissionPanel.refreshPermissionIcons();
|
||||
|
||||
let popupCount = gBrowser.selectedBrowser.popupBlocker.getBlockedPopupCount();
|
||||
|
||||
|
@ -3480,6 +3485,7 @@ function BrowserReloadWithFlags(reloadFlags) {
|
|||
delete tab.linkedBrowser.authPromptAbuseCounter;
|
||||
}
|
||||
gIdentityHandler.hidePopup();
|
||||
gPermissionPanel.hidePopup();
|
||||
|
||||
let handlingUserInput = window.windowUtils.isHandlingUserInput;
|
||||
|
||||
|
@ -5150,7 +5156,7 @@ var XULBrowserWindow = {
|
|||
);
|
||||
}
|
||||
|
||||
gIdentityHandler.onLocationChange();
|
||||
gPermissionPanel.onLocationChange();
|
||||
|
||||
gProtectionsHandler.onLocationChange();
|
||||
|
||||
|
|
|
@ -632,6 +632,7 @@
|
|||
|
||||
#include ../../components/customizableui/content/panelUI.inc.xhtml
|
||||
#include ../../components/controlcenter/content/identityPanel.inc.xhtml
|
||||
#include ../../components/controlcenter/content/permissionPanel.inc.xhtml
|
||||
#include ../../components/controlcenter/content/protectionsPanel.inc.xhtml
|
||||
#include ../../components/downloads/content/downloadsPanel.inc.xhtml
|
||||
#include ../../../devtools/startup/enableDevToolsPopup.inc.xhtml
|
||||
|
@ -1864,18 +1865,29 @@
|
|||
<description id="tracking-protection-icon-tooltip-label" class="tooltip-label"/>
|
||||
</tooltip>
|
||||
</box>
|
||||
<box id="identity-box" role="button"
|
||||
<box id="identity-box"
|
||||
pageproxystate="invalid"
|
||||
ondragstart="gIdentityHandler.onDragStart(event);">
|
||||
<box id="identity-icon-box"
|
||||
role="button"
|
||||
align="center"
|
||||
data-l10n-id="urlbar-identity-button"
|
||||
pageproxystate="invalid"
|
||||
onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
|
||||
onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
|
||||
ondragstart="gIdentityHandler.onDragStart(event);">
|
||||
<image id="identity-icon"
|
||||
consumeanchor="identity-box"
|
||||
onclick="PageProxyClickHandler(event);"/>
|
||||
<image id="permissions-granted-icon"
|
||||
data-l10n-id="urlbar-permissions-granted"/>
|
||||
class="identity-box-button"
|
||||
onclick="gIdentityHandler.handleIdentityButtonEvent(event); PageProxyClickHandler(event);"
|
||||
onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);">
|
||||
<image id="identity-icon"/>
|
||||
<image id="remote-control-icon"
|
||||
data-l10n-id="urlbar-remote-control-notification-anchor"/>
|
||||
<label id="identity-icon-label" class="plain" crop="center" flex="1"/>
|
||||
</box>
|
||||
<box id="identity-permission-box"
|
||||
data-l10n-id="urlbar-permissions-granted"
|
||||
role="button"
|
||||
align="center"
|
||||
class="identity-box-button"
|
||||
onclick="gPermissionPanel.handleIdentityButtonEvent(event); PageProxyClickHandler(event);"
|
||||
onkeypress="gPermissionPanel.handleIdentityButtonEvent(event);">
|
||||
<image id="permissions-granted-icon"/>
|
||||
<box style="pointer-events: none;">
|
||||
<image class="sharing-icon" id="webrtc-sharing-icon"/>
|
||||
<image class="sharing-icon geo-icon" id="geo-sharing-icon"/>
|
||||
|
@ -1907,10 +1919,9 @@
|
|||
<image data-permission-id="install" class="blocked-permission-icon install-icon" role="button"
|
||||
data-l10n-id="urlbar-install-blocked"/>
|
||||
</box>
|
||||
</box>
|
||||
<box id="notification-popup-box"
|
||||
hidden="true"
|
||||
onmouseover="document.getElementById('identity-box').classList.add('no-hover');"
|
||||
onmouseout="document.getElementById('identity-box').classList.remove('no-hover');"
|
||||
align="center">
|
||||
<image id="default-notification-icon" class="notification-anchor-icon" role="button"
|
||||
data-l10n-id="urlbar-default-notification-anchor"/>
|
||||
|
@ -1957,9 +1968,6 @@
|
|||
<image id="storage-access-notification-icon" class="notification-anchor-icon storage-access-icon" role="button"
|
||||
data-l10n-id="urlbar-storage-access-anchor"/>
|
||||
</box>
|
||||
<image id="remote-control-icon"
|
||||
data-l10n-id="urlbar-remote-control-notification-anchor"/>
|
||||
<label id="identity-icon-label" class="plain" crop="center" flex="1"/>
|
||||
</box>
|
||||
<box id="urlbar-label-box" align="center">
|
||||
<label id="urlbar-label-switchtab" class="urlbar-label" data-l10n-id="urlbar-switch-to-tab"/>
|
||||
|
|
|
@ -1227,7 +1227,7 @@
|
|||
}
|
||||
|
||||
updateUserContextUIIndicator();
|
||||
gIdentityHandler.updateSharingIndicator();
|
||||
gPermissionPanel.updateSharingIndicator();
|
||||
|
||||
// Enable touch events to start a native dragging
|
||||
// session to allow the user to easily drag the selected tab.
|
||||
|
@ -1402,7 +1402,7 @@
|
|||
tab.removeAttribute("sharing");
|
||||
this._tabAttrModified(tab, ["sharing"]);
|
||||
if (aBrowser == this.selectedBrowser) {
|
||||
gIdentityHandler.updateSharingIndicator();
|
||||
gPermissionPanel.updateSharingIndicator();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1431,7 +1431,7 @@
|
|||
}
|
||||
|
||||
if (aBrowser == this.selectedBrowser) {
|
||||
gIdentityHandler.updateSharingIndicator();
|
||||
gPermissionPanel.updateSharingIndicator();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -4187,6 +4187,7 @@
|
|||
// Also reset DOS mitigations for the basic auth prompt on reload.
|
||||
delete browser.authPromptAbuseCounter;
|
||||
gIdentityHandler.hidePopup();
|
||||
gPermissionPanel.hidePopup();
|
||||
browser.reload();
|
||||
},
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ browser.jar:
|
|||
content/browser/browser-safebrowsing.js (content/browser-safebrowsing.js)
|
||||
content/browser/browser-sidebar.js (content/browser-sidebar.js)
|
||||
content/browser/browser-siteIdentity.js (content/browser-siteIdentity.js)
|
||||
content/browser/browser-sitePermissionPanel.js (content/browser-sitePermissionPanel.js)
|
||||
content/browser/browser-siteProtections.js (content/browser-siteProtections.js)
|
||||
content/browser/browser-sync.js (content/browser-sync.js)
|
||||
content/browser/browser-tabsintitlebar.js (content/browser-tabsintitlebar.js)
|
||||
|
|
|
@ -88,33 +88,6 @@
|
|||
oncommand="gIdentityHandler.showSecuritySubView();"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Permissions Section -->
|
||||
<hbox class="identity-popup-section"
|
||||
when-connection="not-secure secure secure-ev secure-cert-user-overridden file extension cert-error-page https-only-error-page">
|
||||
<vbox id="identity-popup-permissions-content" flex="1" role="group"
|
||||
aria-labelledby="identity-popup-permissions-headline">
|
||||
<hbox id="identity-popup-permissions-header" align="center">
|
||||
<label id="identity-popup-permissions-headline"
|
||||
role="heading" aria-level="2"
|
||||
data-l10n-id="identity-permissions"/>
|
||||
</hbox>
|
||||
<vbox id="identity-popup-permission-list">
|
||||
<vbox id="identity-popup-permission-list-default-anchor" class="identity-popup-permission-list-anchor"/>
|
||||
<vbox class="identity-popup-permission-list-anchor" anchorfor="3rdPartyStorage">
|
||||
<vbox id="identity-popup-storage-access-permission-list-header">
|
||||
<hbox align="center" role="group">
|
||||
<image class="identity-popup-permission-icon storage-access-icon"/>
|
||||
<label data-l10n-id="identity-permissions-storage-access-header" class="identity-popup-permission-header-label"/>
|
||||
</hbox>
|
||||
<description id="identity-popup-storage-access-permission-list-hint" data-l10n-id="identity-permissions-storage-access-hint"></description>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
<description id="identity-popup-permission-reload-hint" data-l10n-id="identity-permissions-reload-hint"></description>
|
||||
<description id="identity-popup-permission-empty-hint" data-l10n-id="identity-permissions-empty"></description>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
<!-- Clear Site Data Button -->
|
||||
<vbox hidden="true"
|
||||
id="identity-popup-clear-sitedata-footer"
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<!-- 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/. -->
|
||||
|
||||
<html:template id="template-permission-popup">
|
||||
<panel id="permission-popup"
|
||||
class="panel-no-padding"
|
||||
type="arrow"
|
||||
role="alertdialog"
|
||||
noautofocus="true"
|
||||
aria-labelledby="permission-popup-mainView-panel-header-span"
|
||||
onpopupshown="gPermissionPanel.onPopupShown(event);"
|
||||
onpopuphidden="gPermissionPanel.onPopupHidden(event);"
|
||||
orient="vertical">
|
||||
<panelmultiview id="permission-popup-multiView"
|
||||
mainViewId="permission-popup-mainView">
|
||||
<panelview id="permission-popup-mainView"
|
||||
role="document"
|
||||
descriptionheightworkaround="true">
|
||||
<vbox id="permission-popup-mainView-panel-header">
|
||||
<label>
|
||||
<html:span id="permission-popup-mainView-panel-header-span" role="heading" aria-level="1"/>
|
||||
</label>
|
||||
</vbox>
|
||||
<hbox class="permission-popup-section">
|
||||
<vbox id="permission-popup-permissions-content" flex="1" role="group">
|
||||
<vbox id="permission-popup-permission-list">
|
||||
<vbox id="permission-popup-permission-list-default-anchor" class="permission-popup-permission-list-anchor"/>
|
||||
<vbox class="permission-popup-permission-list-anchor" anchorfor="3rdPartyStorage">
|
||||
<vbox id="permission-popup-storage-access-permission-list-header">
|
||||
<hbox align="center" role="group">
|
||||
<image class="permission-popup-permission-icon storage-access-icon"/>
|
||||
<label data-l10n-id="identity-permissions-storage-access-header" class="permission-popup-permission-header-label"/>
|
||||
</hbox>
|
||||
<description id="permission-popup-storage-access-permission-list-hint" data-l10n-id="identity-permissions-storage-access-hint"></description>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
<description id="permission-popup-permission-reload-hint" data-l10n-id="identity-permissions-reload-hint"></description>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</panelview>
|
||||
</panelmultiview>
|
||||
</panel>
|
||||
</html:template>
|
|
@ -414,7 +414,11 @@ async function isBrowserShowingNotification() {
|
|||
|
||||
// tracking protection and identity box doorhangers
|
||||
if (
|
||||
["tracking-protection-icon-container", "identity-box"].some(
|
||||
[
|
||||
"tracking-protection-icon-container",
|
||||
"identity-icon-box",
|
||||
"identity-permission-box",
|
||||
].some(
|
||||
id => window.document.getElementById(id).getAttribute("open") == "true"
|
||||
)
|
||||
) {
|
||||
|
|
|
@ -307,13 +307,10 @@ identity-https-only-info-turn-on2 = Turn on HTTPS-Only Mode for this site if you
|
|||
identity-https-only-info-turn-off2 = If the page seems broken, you may want to turn off HTTPS-Only Mode for this site to reload using insecure HTTP.
|
||||
identity-https-only-info-no-upgrade = Unable to upgrade connection from HTTP.
|
||||
|
||||
identity-permissions =
|
||||
.value = Permissions
|
||||
identity-permissions-storage-access-header = Cross-site cookies
|
||||
identity-permissions-storage-access-hint = These parties can use cross-site cookies and site data while you are on this site.
|
||||
|
||||
identity-permissions-reload-hint = You may need to reload the page for changes to apply.
|
||||
identity-permissions-empty = You have not granted this site any special permissions.
|
||||
identity-clear-site-data =
|
||||
.label = Clear Cookies and Site Data…
|
||||
identity-connection-not-secure-security-view = You are not securely connected to this site.
|
||||
|
|
|
@ -983,6 +983,9 @@ captivePortal.infoMessage3 = You must log in to this network before you can acce
|
|||
# The button shows the portal login page tab when clicked.
|
||||
captivePortal.showLoginPage2 = Open Network Login Page
|
||||
|
||||
# LOCALIZATION NOTE (permissions.header):
|
||||
# %S is the hostname of the site that is being displayed.
|
||||
permissions.header = Permissions for %S
|
||||
permissions.remove.tooltip = Clear this permission and ask again
|
||||
|
||||
permissions.fullscreen.promptCanceled = Canceled pending permission requests: permission requests should not be issued before entering DOM fullscreen.
|
||||
|
|
|
@ -672,13 +672,15 @@ var webrtcUI = {
|
|||
aActiveStream.browser.focus();
|
||||
}
|
||||
browserWindow.focus();
|
||||
let identityBox = browserWindow.document.getElementById("identity-box");
|
||||
let permissionBox = browserWindow.document.getElementById(
|
||||
"identity-permission-box"
|
||||
);
|
||||
if (AppConstants.platform == "macosx" && !Services.focus.activeWindow) {
|
||||
browserWindow.addEventListener(
|
||||
"activate",
|
||||
function() {
|
||||
Services.tm.dispatchToMainThread(function() {
|
||||
identityBox.click();
|
||||
permissionBox.click();
|
||||
});
|
||||
},
|
||||
{ once: true }
|
||||
|
@ -688,7 +690,7 @@ var webrtcUI = {
|
|||
.activateApplication(true);
|
||||
return;
|
||||
}
|
||||
identityBox.click();
|
||||
permissionBox.click();
|
||||
},
|
||||
|
||||
updateWarningLabel(aMenuList) {
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
%include ../../shared/controlcenter/panel.inc.css
|
||||
|
||||
.identity-popup-expander > .button-box,
|
||||
.identity-popup-permission-remove-button > .button-box {
|
||||
.permission-popup-permission-remove-button > .button-box {
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.identity-popup-expander:-moz-focusring,
|
||||
.identity-popup-permission-remove-button:-moz-focusring {
|
||||
.permission-popup-permission-remove-button:-moz-focusring {
|
||||
outline: 1px -moz-dialogtext dotted;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
%include ../../shared/controlcenter/panel.inc.css
|
||||
|
||||
.identity-popup-expander:-moz-focusring,
|
||||
.identity-popup-permission-remove-button:-moz-focusring {
|
||||
.permission-popup-permission-remove-button:-moz-focusring {
|
||||
box-shadow: var(--focus-ring-box-shadow);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
%filter substitution
|
||||
%define identityBoxPaddingInline 6px
|
||||
%define identityBoxMarginInlineEnd 2px
|
||||
%define identityBoxMarginInline 3px
|
||||
%define lwtPopupBrighttextLinkColor #74c0ff
|
||||
%define themeTransition background-color 0.1s cubic-bezier(.17,.67,.83,.67)
|
||||
%define urlbarBreakoutExtend 2px
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
|
||||
#identity-popup,
|
||||
#permission-popup,
|
||||
#protections-popup {
|
||||
%if defined(XP_MACOSX) || defined(XP_WIN)
|
||||
font-size: 1.18em;
|
||||
|
@ -46,7 +47,8 @@
|
|||
|
||||
/* This is used by screenshots tests to hide intermittently different
|
||||
* identity popup shadows (see bug 1425253). */
|
||||
#identity-popup.no-shadow {
|
||||
#identity-popup.no-shadow,
|
||||
#permission-popup.no-shadow {
|
||||
-moz-window-shadow: none;
|
||||
}
|
||||
|
||||
|
@ -93,8 +95,10 @@
|
|||
}
|
||||
|
||||
#identity-popup-mainView,
|
||||
#permission-popup-mainView,
|
||||
#protections-popup-mainView,
|
||||
#identity-popup-mainView-panel-header,
|
||||
#permission-popup-mainView-panel-header,
|
||||
#protections-popup-mainView-panel-header {
|
||||
min-width: var(--popup-width);
|
||||
max-width: var(--popup-width);
|
||||
|
@ -110,6 +114,7 @@
|
|||
}
|
||||
|
||||
.identity-popup-section,
|
||||
.permission-popup-section,
|
||||
.protections-popup-section {
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
}
|
||||
|
@ -133,7 +138,6 @@
|
|||
margin-block: 0;
|
||||
}
|
||||
|
||||
#identity-popup-permissions-header,
|
||||
.identity-popup-security-connection,
|
||||
#identity-popup-security-description,
|
||||
#identity-popup-security-httpsonlymode {
|
||||
|
@ -171,32 +175,15 @@
|
|||
margin-inline: 0;
|
||||
}
|
||||
|
||||
#identity-popup-permissions-content {
|
||||
#permission-popup-permissions-content {
|
||||
padding-inline: 2em 1em;
|
||||
}
|
||||
|
||||
.identity-popup-security-content,
|
||||
#identity-popup-permissions-content {
|
||||
#permission-popup-permissions-content {
|
||||
padding-block: 1em;
|
||||
}
|
||||
|
||||
#identity-popup-permissions-header {
|
||||
background-image: url(chrome://browser/skin/permissions.svg);
|
||||
background-repeat: no-repeat;
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
#identity-popup-permissions-header:-moz-locale-dir(rtl) {
|
||||
background-position-x: right;
|
||||
}
|
||||
|
||||
#identity-popup-permissions-header,
|
||||
#identity-popup-permission-list {
|
||||
/* 16px icon width + 12px margin */
|
||||
padding-inline-start: 28px;
|
||||
}
|
||||
|
||||
#protections-popup-content {
|
||||
background-repeat: no-repeat;
|
||||
background-position: 1em 1em;
|
||||
|
@ -247,7 +234,6 @@
|
|||
|
||||
/* CONTENT */
|
||||
|
||||
#identity-popup-permissions-headline,
|
||||
.protections-popup-empty-label,
|
||||
.tracking-protection-button,
|
||||
.protections-popup-cookiesView-list-header,
|
||||
|
@ -265,6 +251,7 @@
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
#permission-popup-mainView-panel-header,
|
||||
#identity-popup-mainView-panel-header,
|
||||
#protections-popup-mainView-panel-header {
|
||||
min-height: 40px;
|
||||
|
@ -272,6 +259,7 @@
|
|||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
#permission-popup-mainView-panel-header,
|
||||
#identity-popup-mainView-panel-header {
|
||||
padding: var(--vertical-section-padding) var(--horizontal-padding);
|
||||
}
|
||||
|
@ -301,6 +289,7 @@
|
|||
background: radial-gradient(circle farthest-side at top left, #9059FF, #0250BB);
|
||||
}
|
||||
|
||||
#permission-popup-mainView-panel-header-span,
|
||||
#identity-popup-mainView-panel-header-span,
|
||||
#protections-popup-mainView-panel-header-span {
|
||||
font-weight: 600;
|
||||
|
@ -312,11 +301,13 @@
|
|||
margin-inline-start: 35px;
|
||||
}
|
||||
|
||||
#permission-popup-mainView-panel-header-span,
|
||||
#identity-popup-mainView-panel-header-span,
|
||||
#protections-popup-mainView-panel-header-span,
|
||||
#protections-popup-toast-panel-tp-on-desc,
|
||||
#protections-popup-toast-panel-tp-off-desc,
|
||||
#protections-popup .panel-header > label > span,
|
||||
#permission-popup .panel-header > label > span,
|
||||
#identity-popup .panel-header > label > span {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
|
@ -338,7 +329,7 @@
|
|||
fill-opacity: 1;
|
||||
}
|
||||
|
||||
#identity-popup-permissions-content > description,
|
||||
#permission-popup-permissions-content > description,
|
||||
#protections-popup-content > description {
|
||||
color: var(--panel-description-color);
|
||||
}
|
||||
|
@ -740,13 +731,13 @@ description#identity-popup-content-verifier,
|
|||
@supports -moz-bool-pref("layout.css.emulate-moz-box-with-flex") {
|
||||
/* The extra padding-bottom is there to work around XUL flex (Bug 1368281).
|
||||
This rule and the 1.5em above can both be removed once we are only using CSS flex. */
|
||||
#identity-popup-permissions-content {
|
||||
#permission-popup-permissions-content {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.protections-popup-category,
|
||||
.identity-popup-permission-item {
|
||||
.permission-popup-permission-item {
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
|
@ -758,24 +749,22 @@ description#identity-popup-content-verifier,
|
|||
display: none;
|
||||
}
|
||||
|
||||
.identity-popup-permission-item,
|
||||
#identity-popup-storage-access-permission-list-header {
|
||||
.permission-popup-permission-item,
|
||||
#permission-popup-storage-access-permission-list-header {
|
||||
padding-inline-end: 8px;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
#identity-popup-permission-reload-hint,
|
||||
#identity-popup-permission-empty-hint,
|
||||
#identity-popup-permission-list:not(:empty),
|
||||
#identity-popup-permission-list:empty + #identity-popup-storage-access-permission-list:not(:empty) {
|
||||
#permission-popup-permission-reload-hint,
|
||||
#permission-popup-permission-empty-hint {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.identity-popup-permission-list-anchor[anchorfor="3rdPartyStorage"] > vbox:only-child {
|
||||
.permission-popup-permission-list-anchor[anchorfor="3rdPartyStorage"] > vbox:only-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#identity-popup-storage-access-permission-list-hint {
|
||||
#permission-popup-storage-access-permission-list-hint {
|
||||
margin-top: 0.25em;
|
||||
font-size: 0.85em;
|
||||
/* Matches offset for items - 3px margin + 16px icon + 10px margin */
|
||||
|
@ -783,23 +772,23 @@ description#identity-popup-content-verifier,
|
|||
color: var(--panel-description-color);
|
||||
}
|
||||
|
||||
.identity-popup-permission-icon {
|
||||
.permission-popup-permission-icon {
|
||||
margin-inline-start: 3px;
|
||||
}
|
||||
|
||||
.protections-popup-category-icon,
|
||||
.identity-popup-permission-icon {
|
||||
.permission-popup-permission-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.identity-popup-permission-icon.in-use {
|
||||
.permission-popup-permission-icon.in-use {
|
||||
-moz-context-properties: fill;
|
||||
fill: rgb(224, 41, 29);
|
||||
animation: 1.5s ease identity-popup-permission-icon-in-use-blink infinite;
|
||||
animation: 1.5s ease permission-popup-permission-icon-in-use-blink infinite;
|
||||
}
|
||||
|
||||
@keyframes identity-popup-permission-icon-in-use-blink {
|
||||
@keyframes permission-popup-permission-icon-in-use-blink {
|
||||
50% { opacity: 0; }
|
||||
}
|
||||
|
||||
|
@ -808,24 +797,24 @@ description#identity-popup-content-verifier,
|
|||
margin-inline-start: 1em;
|
||||
}
|
||||
|
||||
.identity-popup-permission-label,
|
||||
.identity-popup-permission-header-label {
|
||||
.permission-popup-permission-label,
|
||||
.permission-popup-permission-header-label {
|
||||
margin-inline-start: 10px;
|
||||
}
|
||||
|
||||
.identity-popup-permission-label-subitem {
|
||||
.permission-popup-permission-label-subitem {
|
||||
/* Align label with other labels with icon. */
|
||||
/* icon width + icon inline margin + label inline margin */
|
||||
margin-inline-start: calc(16px + 3px + 10px);
|
||||
}
|
||||
|
||||
.protections-popup-category-state-label,
|
||||
.identity-popup-permission-state-label {
|
||||
.permission-popup-permission-state-label {
|
||||
margin-inline-end: 5px;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.identity-popup-permission-state-label {
|
||||
.permission-popup-permission-state-label {
|
||||
color: var(--panel-description-color);
|
||||
}
|
||||
|
||||
|
@ -833,7 +822,7 @@ description#identity-popup-content-verifier,
|
|||
visibility: hidden;
|
||||
}
|
||||
|
||||
.identity-popup-permission-remove-button {
|
||||
.permission-popup-permission-remove-button {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
margin-inline-start: 2px;
|
||||
|
@ -847,11 +836,11 @@ description#identity-popup-content-verifier,
|
|||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.identity-popup-permission-remove-button > .button-box {
|
||||
.permission-popup-permission-remove-button > .button-box {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.identity-popup-permission-remove-button > .button-box > .button-icon {
|
||||
.permission-popup-permission-remove-button > .button-box > .button-icon {
|
||||
margin: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
@ -860,20 +849,20 @@ description#identity-popup-content-verifier,
|
|||
fill: currentColor;
|
||||
}
|
||||
|
||||
.identity-popup-permission-remove-button > .button-box > .button-text {
|
||||
.permission-popup-permission-remove-button > .button-box > .button-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* swap foreground / background colors on hover */
|
||||
.identity-popup-permission-remove-button:not(:-moz-focusring):hover {
|
||||
.permission-popup-permission-remove-button:not(:-moz-focusring):hover {
|
||||
background-color: currentColor;
|
||||
}
|
||||
|
||||
.identity-popup-permission-remove-button:not(:-moz-focusring):hover > .button-box > .button-icon {
|
||||
.permission-popup-permission-remove-button:not(:-moz-focusring):hover > .button-box > .button-icon {
|
||||
fill: var(--arrowpanel-background);
|
||||
}
|
||||
|
||||
.identity-popup-permission-remove-button:not(:-moz-focusring):hover:active {
|
||||
.permission-popup-permission-remove-button:not(:-moz-focusring):hover:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
|
|
|
@ -184,6 +184,8 @@ panelmultiview[transitioning] > .panel-viewcontainer > .panel-viewstack > panelv
|
|||
#widget-overflow,
|
||||
#appMenu-popup,
|
||||
#customizationui-widget-panel,
|
||||
#identity-popup,
|
||||
#permission-popup,
|
||||
#protections-popup {
|
||||
margin-top: -6px;
|
||||
}
|
||||
|
@ -197,12 +199,6 @@ panelmultiview[transitioning] > .panel-viewcontainer > .panel-viewstack > panelv
|
|||
margin-top: calc(var(--toolbarbutton-inner-padding) - var(--urlbar-icon-padding) - 6px)
|
||||
}
|
||||
|
||||
/* The identity popup does not have any padding of its own,
|
||||
otherwise would use the same formula as above. */
|
||||
#identity-popup {
|
||||
margin-top: calc(var(--toolbarbutton-inner-padding) - 6px);
|
||||
}
|
||||
|
||||
/* The bookmarks toolbar is too thin to have the panels overlap 6px. */
|
||||
#downloadsPanel.bookmarks-toolbar,
|
||||
#widget-overflow.bookmarks-toolbar,
|
||||
|
|
|
@ -7,8 +7,14 @@
|
|||
%filter substitution
|
||||
|
||||
#identity-box {
|
||||
padding-inline: @identityBoxPaddingInline@;
|
||||
margin-inline-end: @identityBoxMarginInlineEnd@;
|
||||
margin-inline: @identityBoxMarginInline@;
|
||||
}
|
||||
|
||||
/* The tracking protection icon will be hidden if it is a chrome page. There
|
||||
will be only the brand icon in the url bar. We need to change the margin
|
||||
in order for the identity box to cover the whole urlbar start section. */
|
||||
#identity-box[pageproxystate="valid"].chromeUI {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
#identity-box,
|
||||
|
@ -19,19 +25,15 @@
|
|||
fill-opacity: .6;
|
||||
}
|
||||
|
||||
/* The tracking protection icon will be hidden if it is a chrome page. There
|
||||
will be only the brand icon in the url bar. So, we need to change the padding
|
||||
start for proper positing the icon. */
|
||||
#identity-box[pageproxystate="valid"].chromeUI {
|
||||
padding-inline-start: 8px;
|
||||
#identity-box[pageproxystate="invalid"] {
|
||||
margin-inline-end: calc(@identityBoxMarginInline@ + 2px);
|
||||
}
|
||||
|
||||
#urlbar.searchButton > #urlbar-input-container > #identity-box[pageproxystate="invalid"],
|
||||
#identity-box[pageproxystate="invalid"] > #permissions-granted-icon,
|
||||
#identity-box[pageproxystate="invalid"] > #blocked-permissions-container,
|
||||
#identity-box[pageproxystate="invalid"] > #identity-permission-box,
|
||||
#identity-box[pageproxystate="invalid"] > #notification-popup-box,
|
||||
#identity-box[pageproxystate="invalid"] > #identity-icon-label,
|
||||
#identity-box[pageproxystate="invalid"] > #remote-control-icon {
|
||||
#identity-box[pageproxystate="invalid"] #identity-icon-label,
|
||||
#identity-box[pageproxystate="invalid"] #remote-control-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -40,28 +42,32 @@
|
|||
-moz-user-focus: ignore;
|
||||
}
|
||||
|
||||
#identity-box:hover:not(.no-hover, [open=true]),
|
||||
.identity-box-button:hover:not([open=true]),
|
||||
#tracking-protection-icon-container:hover:not([open=true]) {
|
||||
background-color: hsla(0,0%,70%,.2);
|
||||
fill-opacity: .8;
|
||||
}
|
||||
|
||||
#identity-box:hover:active:not(.no-hover),
|
||||
#identity-box[open=true],
|
||||
.identity-box-button:hover:active,
|
||||
.identity-box-button[open=true],
|
||||
#tracking-protection-icon-container:hover:active,
|
||||
#tracking-protection-icon-container[open=true] {
|
||||
background-color: hsla(0,0%,70%,.3);
|
||||
fill-opacity: .8;
|
||||
}
|
||||
|
||||
#identity-box:not(:active):-moz-focusring,
|
||||
.identity-box-button:not(:active):-moz-focusring,
|
||||
#tracking-protection-icon-container:not(:active):-moz-focusring {
|
||||
outline: var(--toolbarbutton-focus-outline);
|
||||
outline-offset: -2px;
|
||||
-moz-outline-radius: var(--toolbarbutton-border-radius);
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].chromeUI > #identity-icon-label,
|
||||
.identity-box-button {
|
||||
padding-inline: calc(@identityBoxPaddingInline@ / 2);
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].chromeUI #identity-icon-label,
|
||||
.urlbar-label {
|
||||
opacity: .6;
|
||||
}
|
||||
|
@ -83,10 +89,10 @@
|
|||
border-image-slice: 1;
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].notSecureText,
|
||||
#identity-box[pageproxystate="valid"].chromeUI,
|
||||
#identity-box[pageproxystate="valid"].extensionPage {
|
||||
padding-inline-end: 8px;
|
||||
#identity-box[pageproxystate="valid"].notSecureText > #identity-icon-box,
|
||||
#identity-box[pageproxystate="valid"].chromeUI > #identity-icon-box,
|
||||
#identity-box[pageproxystate="valid"].extensionPage > #identity-icon-box {
|
||||
padding-inline: 8px;
|
||||
}
|
||||
|
||||
#urlbar-label-box {
|
||||
|
@ -116,10 +122,17 @@
|
|||
#blocked-permissions-container > .blocked-permission-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-inline-start: 4px;
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
}
|
||||
|
||||
.sharing-icon,
|
||||
#identity-icon,
|
||||
#tracking-protection-icon,
|
||||
.notification-anchor-icon,
|
||||
#blocked-permissions-container > .blocked-permission-icon {
|
||||
margin-inline-start: 4px;
|
||||
}
|
||||
|
||||
#tracking-protection-icon {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
@ -130,50 +143,51 @@
|
|||
list-style-image: url(chrome://global/skin/icons/identity-icon.svg);
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].chromeUI > #identity-icon {
|
||||
#identity-box[pageproxystate="valid"].chromeUI #identity-icon {
|
||||
list-style-image: url(chrome://branding/content/identity-icons-brand.svg);
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].localResource > #identity-icon {
|
||||
#identity-box[pageproxystate="valid"].localResource #identity-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/document.svg);
|
||||
}
|
||||
|
||||
#urlbar:not(.searchButton) > #urlbar-input-container > #identity-box[pageproxystate="invalid"] > #identity-icon {
|
||||
#urlbar:not(.searchButton) > #urlbar-input-container > #identity-box[pageproxystate="invalid"] #identity-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/search-glass.svg);
|
||||
fill-opacity: .4;
|
||||
}
|
||||
|
||||
#urlbar[actiontype="extension"] > #urlbar-input-container > #identity-box > #identity-icon {
|
||||
#urlbar[actiontype="extension"] > #urlbar-input-container > #identity-box #identity-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extension.svg);
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].extensionPage > #identity-icon {
|
||||
#identity-box[pageproxystate="valid"].extensionPage #identity-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extension.svg);
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].verifiedDomain > #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].mixedActiveBlocked > #identity-icon {
|
||||
#identity-box[pageproxystate="valid"].verifiedDomain #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].mixedActiveBlocked #identity-icon {
|
||||
list-style-image: url(chrome://browser/skin/connection-secure.svg);
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].verifiedDomain > #identity-icon:not([lock-icon-gray]),
|
||||
#identity-box[pageproxystate="valid"].mixedActiveBlocked > #identity-icon:not([lock-icon-gray]) {
|
||||
#identity-box[pageproxystate="valid"].verifiedDomain #identity-icon:not([lock-icon-gray]),
|
||||
#identity-box[pageproxystate="valid"].mixedActiveBlocked #identity-icon:not([lock-icon-gray]) {
|
||||
fill-opacity: 1;
|
||||
fill: #12BC00;
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].weakCipher > #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].mixedDisplayContent > #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].mixedDisplayContentLoadedActiveBlocked > #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].certUserOverridden > #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].certErrorPage > #identity-icon {
|
||||
#identity-box[pageproxystate="valid"].weakCipher #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].mixedDisplayContent #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].mixedDisplayContentLoadedActiveBlocked #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].certUserOverridden #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].certErrorPage #identity-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/connection-mixed-passive-loaded.svg);
|
||||
fill: unset;
|
||||
}
|
||||
|
||||
#identity-box[pageproxystate="valid"].notSecure > #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].mixedActiveContent > #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].httpsOnlyErrorPage > #identity-icon {
|
||||
|
||||
#identity-box[pageproxystate="valid"].notSecure #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].mixedActiveContent #identity-icon,
|
||||
#identity-box[pageproxystate="valid"].httpsOnlyErrorPage #identity-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/connection-mixed-active-loaded.svg);
|
||||
}
|
||||
|
||||
|
@ -181,10 +195,17 @@
|
|||
list-style-image: url(chrome://browser/skin/permissions.svg);
|
||||
}
|
||||
|
||||
#identity-box:not(.grantedPermissions) > #permissions-granted-icon {
|
||||
#identity-permission-box {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#identity-permission-box[open=true],
|
||||
#identity-permission-box[hasGrantedPermissions],
|
||||
#identity-permission-box[hasPermissionIcon],
|
||||
#identity-permission-box[hasSharingIcon] {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
/* SHARING ICON */
|
||||
|
||||
#webrtc-sharing-icon[sharing="camera"] {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
%endif
|
||||
|
||||
.popup-notification-icon,
|
||||
.identity-popup-permission-icon {
|
||||
.permission-popup-permission-icon {
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
fill-opacity: 0.6;
|
||||
|
@ -14,7 +14,6 @@
|
|||
#notification-popup-box {
|
||||
padding: 5px 0;
|
||||
margin: -5px 0;
|
||||
margin-inline-end: -5px;
|
||||
padding-inline-end: 5px;
|
||||
}
|
||||
|
||||
|
@ -259,8 +258,8 @@ html|*#webRTC-previewVideo {
|
|||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#identity-popup-popup-menulist,
|
||||
#identity-popup-popup-menulist > menupopup {
|
||||
#permission-popup-menulist,
|
||||
#permission-popup-menulist > menupopup {
|
||||
min-width: 6.5em;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
%filter substitution
|
||||
%define urlbarViewPadding 4px
|
||||
%define urlbarViewIconMarginEnd (@identityBoxPaddingInline@ + @identityBoxMarginInlineEnd@)
|
||||
%define urlbarViewIconMarginEnd (@identityBoxPaddingInline@ + @identityBoxMarginInline@)
|
||||
%define urlbarViewMarginInline 7px
|
||||
%define urlbarViewItemInlinePadding 6px
|
||||
%define urlbarViewFaviconWidth 16px
|
||||
|
@ -143,10 +143,10 @@
|
|||
}
|
||||
/* urlbarView-url is forced to be LTR for RTL locales, so set the padding based on the browser's directionality. */
|
||||
.urlbarView-results[wrap] > .urlbarView-row[has-url] > .urlbarView-row-inner > .urlbarView-url:-moz-locale-dir(ltr) {
|
||||
padding-left: calc(@urlbarViewItemInlinePadding@ + @identityBoxMarginInlineEnd@ + @urlbarViewFaviconWidth@);
|
||||
padding-left: calc(@urlbarViewItemInlinePadding@ + @identityBoxMarginInline@ + @urlbarViewFaviconWidth@);
|
||||
}
|
||||
.urlbarView-results[wrap] > .urlbarView-row[has-url] > .urlbarView-row-inner > .urlbarView-url:-moz-locale-dir(rtl) {
|
||||
padding-right: calc(@urlbarViewItemInlinePadding@ + @identityBoxMarginInlineEnd@ + @urlbarViewFaviconWidth@);
|
||||
padding-right: calc(@urlbarViewItemInlinePadding@ + @identityBoxMarginInline@ + @urlbarViewFaviconWidth@);
|
||||
}
|
||||
/* Note: switchtab entries show the url only in override mode,
|
||||
remotetab and sponsored ones only when selected or :hover. */
|
||||
|
@ -161,7 +161,7 @@
|
|||
}
|
||||
.urlbarView-results[wrap] > .urlbarView-row[type=tabtosearch] > .urlbarView-row-inner > .urlbarView-no-wrap > .urlbarView-action {
|
||||
flex-basis: 100%;
|
||||
margin-inline-start: calc(@urlbarViewItemInlinePadding@ + @identityBoxMarginInlineEnd@ + @urlbarViewFaviconWidth@);
|
||||
margin-inline-start: calc(@urlbarViewItemInlinePadding@ + @identityBoxMarginInline@ + @urlbarViewFaviconWidth@);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче