From c381d3deee85d411ed0226a48a5d67f88f0ba47a Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Wed, 19 May 2021 18:22:38 -0400 Subject: [PATCH] Add adoptedCallback to work around Firefox Native CE bug (#34455) See https://output.jsbin.com/yuwojok/29/quiet for a working demo of the bug. When we construct a CustomElement in one document, then insert it into another document (as we do with A4A ads), Firefox incorrectly resets the prototype of our CE instance to `HTMLElement.prototype`. Luckily, we can fix this by listening for the `adoptedCallback`, which fires just after Firefox resets the prototype. If we detect a broken prototype chain, we can correct it before any other code can notice. See https://output.jsbin.com/datajos/5/quiet for a demo of the fix. --- src/custom-element.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/custom-element.js b/src/custom-element.js index 685649914dd3..18a3e5b604cc 100644 --- a/src/custom-element.js +++ b/src/custom-element.js @@ -98,7 +98,20 @@ export function createCustomElementClass(win, elementConnectedCallback) { ); // It's necessary to create a subclass, because the same "base" class cannot // be registered to multiple custom elements. - class CustomAmpElement extends BaseCustomElement {} + class CustomAmpElement extends BaseCustomElement { + /** + * adoptedCallback is only called when using a Native implementation of Custom Elements V1. + * Our polyfill does not call this method. + */ + adoptedCallback() { + // Work around an issue with Firefox changing the prototype of our + // already constructed element to the new document's HTMLElement. + if (Object.getPrototypeOf(this) !== customAmpElementProto) { + Object.setPrototypeOf(this, customAmpElementProto); + } + } + } + const customAmpElementProto = CustomAmpElement.prototype; return /** @type {typeof AmpElement} */ (CustomAmpElement); }