Bug: CFR's alt_anchor_id is not used when the anchor_id element is hidden or in the customization palette
Status: RESOLVED
Priority: P2
Resolution: FIXED
Created: 2023-05-15 17:13:51+00:00
Resolved: 2023-07-31 15:28:22+00:00

I think `alt_anchor_id` should serve as a general fallback for `anchor_id`, but in fact it's [only used](https://searchfox.org/mozilla-central/rev/eb07633057d66ab25f9db4c5900eeb6913da7579/browser/components/newtab/lib/CFRPageActions.jsm#811-822) in one very specific circumstance — the `anchor_id` element is...
1. A customizable widget
2. Placed in the nav bar toolbar and overflown into the widget overflow list, or placed in the permanent widget overflow list

This is a pretty narrow condition since there are lots of other circumstances where a desired anchor element could be hidden. In particular, for bug 1828170, the spec calls for the CFR to be anchored to the FxA profile toolbarbutton, but this is a removable customizable widget. It can easily be placed in the customization palette, in which case its `areaType` is `null`.

So, if we use it for `anchor_id` and use the app menu button for `alt_anchor_id`, it won't end up anchoring to the app menu button if the profile button was removed from the toolbar. I think we're going to try that anyway in the hopes of uplifting the fix for this. If we can't uplift in time, we can resort to using the app menu button as `anchor_id` instead of the profile button.

In other cases, the button may be hidden for other reasons. For example we might want to point to the FxA profile button if it's visible, and to something else if it's not — but it's only visible when the user is signed in, along with the other conditions I mentioned earlier. In this rollout that's not an issue since the message should only target signed-in users. But hypothetically there are lots of cases where an anchor element could be hidden.

Edit: Another possibility is that the anchor is a widget with `showInPrivateBrowsing` and therefore won't render in PBM, which could potentially cause problems since we're allowing CFRs to display in PBM in bug 1818249.

I'm proposing that we just refactor the logic to work like this:

1. Search for the `anchor_id` in the DOM
2. If it exists, it's not hidden by CSS, and it's either (not a customizable widget OR its `areaType` is neither `null` nor `"panel"`), use `anchor_id`
3. Otherwise, search for the `alt_anchor_id` in the DOM (if it's present in the message)
4. If it exists, it's not hidden by CSS, and it's either (not a customizable widget OR its `areaType` is neither `null` nor `"panel"`), use `alt_anchor_id`
5. Otherwise, use `this.container` (the `#contextual-feature-recommendation` box)

```js
const getVisibleElement = id => {
  const element = id && this.window.document.getElementById(id);
  if (!element) {
    return null;
  }
  const { visibility, display } = this.window.getComputedStyle(element);
  if (visibility !== "visible" || display === "none") {
    return null;
  }
  let widget = lazy.CustomizableUI.getWidget(id);
  if (widget && (widget.areaType.includes("panel") || !widget.areaType)) {
    return null;
  }
  return element;
};

browser.cfrpopupnotificationanchor =
  getVisibleElement(content.anchor_id) ||
  getVisibleElement(content.alt_anchor_id) ||
  this.container;
```