forked from mirrors/gecko-dev
The issue here is that authorStyleDisabledDefault persists on the BrowsingContext. This means it stays set/unset if the BC navigates same-origin (including reloads). But the actor was keeping its own copy, on the actor, and the actor gets destroyed in those circumstances, leading to the frontend and the internal state no longer being in sync. This patch addresses this by no longer keeping our own state and just reading the browsingcontext's field directly. This is a tiny bit hackish because technically, whether this is the 'default' is not the same as whether the author style is actually disabled, but in practice the child actor always sets the two at the same time, and it is the simpler fix (vs. trying to mirror state to the parent some more). Differential Revision: https://phabricator.services.mozilla.com/D183188
125 lines
4.1 KiB
JavaScript
125 lines
4.1 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
|
* 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 */
|
|
|
|
var gPageStyleMenu = {
|
|
_getStyleSheetInfo(browser) {
|
|
let actor =
|
|
browser.browsingContext.currentWindowGlobal?.getActor("PageStyle");
|
|
let styleSheetInfo;
|
|
if (actor) {
|
|
styleSheetInfo = actor.getSheetInfo();
|
|
} else {
|
|
// Fallback if the actor is missing or we don't have a window global.
|
|
// It's unlikely things will work well but let's be optimistic,
|
|
// rather than throwing exceptions immediately.
|
|
styleSheetInfo = {
|
|
filteredStyleSheets: [],
|
|
preferredStyleSheetSet: true,
|
|
};
|
|
}
|
|
return styleSheetInfo;
|
|
},
|
|
|
|
fillPopup(menuPopup) {
|
|
let styleSheetInfo = this._getStyleSheetInfo(gBrowser.selectedBrowser);
|
|
var noStyle = menuPopup.firstElementChild;
|
|
var persistentOnly = noStyle.nextElementSibling;
|
|
var sep = persistentOnly.nextElementSibling;
|
|
while (sep.nextElementSibling) {
|
|
menuPopup.removeChild(sep.nextElementSibling);
|
|
}
|
|
|
|
let styleSheets = styleSheetInfo.filteredStyleSheets;
|
|
var currentStyleSheets = {};
|
|
var styleDisabled =
|
|
!!gBrowser.selectedBrowser.browsingContext?.authorStyleDisabledDefault;
|
|
var haveAltSheets = false;
|
|
var altStyleSelected = false;
|
|
|
|
for (let currentStyleSheet of styleSheets) {
|
|
if (!currentStyleSheet.disabled) {
|
|
altStyleSelected = true;
|
|
}
|
|
|
|
haveAltSheets = true;
|
|
|
|
let lastWithSameTitle = null;
|
|
if (currentStyleSheet.title in currentStyleSheets) {
|
|
lastWithSameTitle = currentStyleSheets[currentStyleSheet.title];
|
|
}
|
|
|
|
if (!lastWithSameTitle) {
|
|
let menuItem = document.createXULElement("menuitem");
|
|
menuItem.setAttribute("type", "radio");
|
|
menuItem.setAttribute("label", currentStyleSheet.title);
|
|
menuItem.setAttribute("data", currentStyleSheet.title);
|
|
menuItem.setAttribute(
|
|
"checked",
|
|
!currentStyleSheet.disabled && !styleDisabled
|
|
);
|
|
menuItem.setAttribute(
|
|
"oncommand",
|
|
"gPageStyleMenu.switchStyleSheet(this.getAttribute('data'));"
|
|
);
|
|
menuPopup.appendChild(menuItem);
|
|
currentStyleSheets[currentStyleSheet.title] = menuItem;
|
|
} else if (currentStyleSheet.disabled) {
|
|
lastWithSameTitle.removeAttribute("checked");
|
|
}
|
|
}
|
|
|
|
noStyle.setAttribute("checked", styleDisabled);
|
|
persistentOnly.setAttribute("checked", !altStyleSelected && !styleDisabled);
|
|
persistentOnly.hidden = styleSheetInfo.preferredStyleSheetSet
|
|
? haveAltSheets
|
|
: false;
|
|
sep.hidden = (noStyle.hidden && persistentOnly.hidden) || !haveAltSheets;
|
|
},
|
|
|
|
/**
|
|
* Send a message to all PageStyleParents by walking the BrowsingContext tree.
|
|
* @param message
|
|
* The string message to send to each PageStyleChild.
|
|
* @param data
|
|
* The data to send to each PageStyleChild within the message.
|
|
*/
|
|
_sendMessageToAll(message, data) {
|
|
let contextsToVisit = [gBrowser.selectedBrowser.browsingContext];
|
|
while (contextsToVisit.length) {
|
|
let currentContext = contextsToVisit.pop();
|
|
let global = currentContext.currentWindowGlobal;
|
|
|
|
if (!global) {
|
|
continue;
|
|
}
|
|
|
|
let actor = global.getActor("PageStyle");
|
|
actor.sendAsyncMessage(message, data);
|
|
|
|
contextsToVisit.push(...currentContext.children);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Switch the stylesheet of all documents in the current browser.
|
|
* @param title The title of the stylesheet to switch to.
|
|
*/
|
|
switchStyleSheet(title) {
|
|
let sheetData = this._getStyleSheetInfo(gBrowser.selectedBrowser);
|
|
for (let sheet of sheetData.filteredStyleSheets) {
|
|
sheet.disabled = sheet.title !== title;
|
|
}
|
|
this._sendMessageToAll("PageStyle:Switch", { title });
|
|
},
|
|
|
|
/**
|
|
* Disable all stylesheets. Called with View > Page Style > No Style.
|
|
*/
|
|
disableStyle() {
|
|
this._sendMessageToAll("PageStyle:Disable", {});
|
|
},
|
|
};
|