Bug 1397876 - Import Custom Elements polyfill and stub out the panel and arrowpanel bindings draft
authorBrian Grinstead <bgrinstead@mozilla.com>
Thu, 07 Sep 2017 12:58:01 -0700
changeset 660884 5acb5aac04e01366c15c53c7a9930ec4e6a92da5
parent 660738 37b95547f0d27565452136d16b2df2857be840f6
child 730417 fb2729a3f877dc78ebe802c5688adfc5ea7b9f28
push id78592
push userbgrinstead@mozilla.com
push dateThu, 07 Sep 2017 19:58:10 +0000
bugs1397876
milestone57.0a1
Bug 1397876 - Import Custom Elements polyfill and stub out the panel and arrowpanel bindings The hamburger menu seems to work, but other panels don't (customize popup, awesomebar). Steps I took to build this: * Pull down polyfill from https://github.com/bgrins/custom-elements/tree/firefox-browser-chrome (includes fixes for XUL docs) * Elements are pseudo generated from https://github.com/bgrins/xbl-analysis/tree/gh-pages/elements MozReview-Commit-ID: iZTULEIwYY
browser/base/content/browser.xul
browser/base/content/customelements/base-element.js
browser/base/content/customelements/custom-elements-polyfill.js
browser/base/content/customelements/custom-elements.js
browser/base/content/customelements/firefox-panel.js
browser/base/jar.mn
browser/themes/shared/browser.inc.css
browser/themes/shared/customelements/custom-elements.inc.css
browser/themes/shared/jar.inc.mn
toolkit/content/xul.css
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -6,16 +6,17 @@
 # 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/.
 
 <?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/usercontext/usercontext.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/controlcenter/panel.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/customizableui/panelUI.css" type="text/css"?>
+<?xml-stylesheet href="chrome://global/skin/popup.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
 
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
 
 # All DTD information is stored in a separate file so that it can be shared by
 # hiddenWindow.xul.
@@ -69,17 +70,16 @@
   Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", this);
 </script>
 
 # All sets except for popupsets (commands, keys, stringbundles and broadcasters) *must* go into the
 # browser-sets.inc file for sharing with hiddenWindow.xul.
 #define FULL_BROWSER_WINDOW
 #include browser-sets.inc
 #undef FULL_BROWSER_WINDOW
-
   <popupset id="mainPopupSet">
     <menupopup id="tabContextMenu"
                onpopupshowing="if (event.target == this) TabContextMenu.updateContextMenu(this);"
                onpopuphidden="if (event.target == this) TabContextMenu.contextTab = null;">
       <menuitem id="context_reloadTab" label="&reloadTab.label;" accesskey="&reloadTab.accesskey;"
                 oncommand="gBrowser.reloadTab(TabContextMenu.contextTab);"/>
       <menuitem id="context_toggleMuteTab" oncommand="TabContextMenu.contextTab.toggleMuteAudio();"/>
       <menuseparator/>
@@ -729,17 +729,16 @@
              fullscreentoolbar="true" mode="icons" customizable="true"
              iconsize="small"
              customizationtarget="nav-bar-customization-target"
              overflowable="true"
              overflowbutton="nav-bar-overflow-button"
              overflowtarget="widget-overflow-list"
              overflowpanel="widget-overflow"
              context="toolbar-context-menu">
-
       <hbox id="nav-bar-customization-target" flex="1">
         <toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                        label="&backCmd.label;"
                        removable="false" overflows="false"
                        keepbroadcastattributeswhencustomizing="true"
                        command="Browser:BackOrBackDuplicate"
                        onclick="checkForMiddleClick(this, event);"
                        tooltip="back-button-tooltip"
@@ -1266,9 +1265,10 @@
   </vbox>
 
 </vbox>
 # <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck.
 #     Introducing the iframe dynamically, as needed, was found to be better than
 #     starting with an empty iframe here in browser.xul from a Ts standpoint.
 </deck>
 
+<script src="chrome://browser/content/customelements/custom-elements.js"></script>
 </window>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/customelements/base-element.js
@@ -0,0 +1,154 @@
+
+
+// https://html.spec.whatwg.org/multipage/scripting.html#custom-elements-autonomous-example
+
+class BaseElement extends XULElement {
+  constructor() {
+    super();
+    this.observerConnector = new ObserverConnector(this);
+    this.inheritsConnector = new InheritsConnector(this);
+  }
+
+  connectedCallback() {
+
+  }
+
+  disconnectedCallback() {
+
+  }
+
+  static get observedAttributes() { return ["observes"]; }
+
+  attributeChangedCallback(name, oldValue, newValue) {
+    if (name === "observes") {
+      this.observerConnector.watch(newValue);
+    }
+  }
+}
+
+function InheritsConnector(host) {
+  this._host = host;
+  this._nodesToAttributes = new Map();
+  this.watch();
+}
+InheritsConnector.prototype.destroy = function() {
+
+}
+InheritsConnector.prototype.setInherits = function(node) {
+  let inherits = node.getAttribute("inherits");
+  if (inherits) {
+    this._nodesToAttributes.set(node, inherits.split(','));
+  }
+}
+InheritsConnector.prototype.copyAttribute = function(attributeName) {
+  if (attributeName === "id") {
+    return;
+  }
+
+  for (let [node, list] of this._nodesToAttributes.entries()) {
+    // Handle both inherits="accesskey" and inherits="text=label"
+    list.forEach(a => {
+      if (a === attributeName) {
+        if (a === "checked") {
+          node.checked = this._host.hasAttribute(a) && this._host.getAttribute(a) != "false";
+        } else {
+          node.setAttribute(a, this._host.getAttribute(a));
+        }
+      } else if (a.endsWith('=' + attributeName)) {
+        let mapFrom = a.split('=')[1];
+        let mapTo = a.split('=')[0];
+        if (mapTo === "text") {
+          node.textContent = this._host.getAttribute(mapFrom);
+        } else {
+          node.setAttribute(mapTo, this._host.getAttribute(mapFrom));
+        }
+      }
+    });
+  }
+};
+
+InheritsConnector.prototype.watch = function() {
+  if (this._observer) {
+    this._observer.disconnect();
+    this._observer = null;
+  }
+
+  this._observer = new MutationObserver(mutations => {
+    mutations.forEach(mutation => {
+      if (mutation.type === "childList") {
+        mutation.addedNodes.forEach(added => {
+          if (added.nodeType !== 1) {
+            return;
+          }
+          this.setInherits(added);
+          [...added.querySelectorAll("[inherits]")].forEach(child => this.setInherits(child));
+          for (var i = 0; i < this._host.attributes.length; i++) {
+            var attrib = this._host.attributes[i];
+            this.copyAttribute(attrib.name);
+          }
+        });
+      }
+
+      if (mutation.type === "attributes" && mutation.target === this._host) {
+        this.copyAttribute(mutation.attributeName);
+      }
+    });
+
+    // this.copyAttributes();
+  });
+  this._observer.observe(this._host, {
+    attributes: true,
+    subtree: true,
+    childList: true,
+  });
+
+}
+
+function ObserverConnector(host) {
+  this._host = host;
+}
+ObserverConnector.prototype.destroy = function() {
+
+}
+
+ObserverConnector.prototype.copyAttributes = function() {
+  if (!this._observeTarget) {
+    return;
+  }
+
+  for (var i = 0; i < this._observeTarget.attributes.length; i++) {
+    var attrib = this._observeTarget.attributes[i];
+    if (attrib.name !== "id") {
+      this._host.setAttribute(attrib.name, attrib.value);
+    }
+  }
+}
+
+ObserverConnector.prototype.watch = function(targetID) {
+  if (this._observer) {
+    this._observer.disconnect();
+    this._observer = null;
+  }
+
+  // XXX: What is hitting this case?
+  if (!targetID) {
+    return;
+  }
+
+  this._observeTarget = document.getElementById(targetID);
+  if (this._observeTarget) {
+    this._observer = new MutationObserver(mutations => {
+      mutations.forEach(mutation => {
+        if (!this._observeTarget.hasAttribute(mutation.attributeName)) {
+          this.removeAttribute(mutation.attributeName);
+        }
+      });
+
+      this.copyAttributes();
+    });
+    this._observer.observe(this._observeTarget, {
+      attributes: true,
+    });
+    this.copyAttributes();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/customelements/custom-elements-polyfill.js
@@ -0,0 +1,48 @@
+(function(){
+'use strict';var g={},h=new function(){};g.default=h;var k={},l=new Set("annotation-xml color-profile font-face font-face-src font-face-uri font-face-format font-face-name missing-glyph".split(" "));k.isValidCustomElementName=function(b){return!l.has(b)&&!0};k.isConnected=function(b){var a=b.isConnected;if(void 0!==a)return a;for(;b&&!(b.__CE_isImportDocument||b instanceof Document);)b=b.parentNode||(window.ShadowRoot&&b instanceof ShadowRoot?b.host:void 0);return!(!b||!(b.__CE_isImportDocument||b instanceof Document))};
+k.walkDeepDescendantElements=function(b,a,f){void 0===f&&new Set;f=Components.interfaces;var c=Components.classes["@mozilla.org/inspector/deep-tree-walker;1"].createInstance(Components.interfaces.inIDeepTreeWalker);c.showAnonymousContent=!0;c.showSubDocuments=!1;c.showDocumentsAsNodes=!1;c.init(b,f.nsIDOMNodeFilter.SHOW_ELEMENT);for(a(b);c.nextNode();)c.currentNode instanceof Element&&a(c.currentNode)};k.setPropertyUnchecked=function(b,a,f){b[a]=f};var m={default:{custom:1,failed:2}};var r={};function t(){this._localNameToDefinition=new Map;this._constructorToDefinition=new Map;this._patches=[];this._hasPatches=!1}t.prototype.setDefinition=function(b,a){this._localNameToDefinition.set(b,a);this._constructorToDefinition.set(a.constructor,a)};t.prototype.localNameToDefinition=function(b){return this._localNameToDefinition.get(b)};t.prototype.constructorToDefinition=function(b){return this._constructorToDefinition.get(b)};t.prototype.addPatch=function(b){this._hasPatches=!0;this._patches.push(b)};
+t.prototype.patchTree=function(b){var a=this;this._hasPatches&&k.walkDeepDescendantElements(b,function(b){return a.patch(b)})};t.prototype.patch=function(b){if(this._hasPatches&&!b.__CE_patched){b.__CE_patched=!0;for(var a=0;a<this._patches.length;a++)this._patches[a](b)}};t.prototype.connectTree=function(b){var a=[];k.walkDeepDescendantElements(b,function(b){return a.push(b)});for(b=0;b<a.length;b++){var f=a[b];f.__CE_state===m.default.custom?this.connectedCallback(f):this.upgradeElement(f)}};
+t.prototype.disconnectTree=function(b){var a=[];k.walkDeepDescendantElements(b,function(b){return a.push(b)});for(b=0;b<a.length;b++){var f=a[b];f.__CE_state===m.default.custom&&this.disconnectedCallback(f)}};
+t.prototype.patchAndUpgradeTree=function(b,a){a=void 0===a?{}:a;var f=this,c=a.visitedImports||new Set,e=a.upgrade||function(b){return f.upgradeElement(b)},d=[];k.walkDeepDescendantElements(b,function(b){if("link"===b.localName&&"import"===b.getAttribute("rel")){var a=b.import;a instanceof Node&&"complete"===a.readyState?(a.__CE_isImportDocument=!0,a.__CE_hasRegistry=!0):b.addEventListener("load",function(){var a=b.import;a.__CE_documentLoadHandled||(a.__CE_documentLoadHandled=!0,a.__CE_isImportDocument=
+!0,a.__CE_hasRegistry=!0,new Set(c),c.delete(a),f.patchAndUpgradeTree(a,{visitedImports:c,upgrade:e}))})}else d.push(b)},c);if(this._hasPatches)for(b=0;b<d.length;b++)this.patch(d[b]);for(b=0;b<d.length;b++)e(d[b])};
+t.prototype.upgradeElement=function(b){if(void 0===b.__CE_state){var a=this.localNameToDefinition(b.localName);if(a){a.constructionStack.push(b);var f=a.constructor;try{try{if(new f!==b)throw Error("The custom element constructor did not produce the element being upgraded.");}finally{a.constructionStack.pop()}}catch(d){throw b.__CE_state=m.default.failed,d;}b.__CE_state=m.default.custom;b.__CE_definition=a;if(a.attributeChangedCallback)for(a=a.observedAttributes,f=0;f<a.length;f++){var c=a[f],e=b.getAttribute(c);
+null!==e&&this.attributeChangedCallback(b,c,null,e,null)}k.isConnected(b)&&this.connectedCallback(b)}}};t.prototype.connectedCallback=function(b){var a=b.__CE_definition;a.connectedCallback&&a.connectedCallback.call(b)};t.prototype.disconnectedCallback=function(b){var a=b.__CE_definition;a.disconnectedCallback&&a.disconnectedCallback.call(b)};
+t.prototype.attributeChangedCallback=function(b,a,f,c,e){var d=b.__CE_definition;d.attributeChangedCallback&&-1<d.observedAttributes.indexOf(a)&&d.attributeChangedCallback.call(b,a,f,c,e)};r.default=t;var u={};function v(b,a){this._internals=b;this._document=a;this._observer=void 0;this._internals.patchAndUpgradeTree(this._document);"loading"===this._document.readyState&&(this._observer=new MutationObserver(this._handleMutations.bind(this)),this._observer.observe(this._document,{childList:!0,subtree:!0}))}v.prototype.disconnect=function(){this._observer&&this._observer.disconnect()};
+v.prototype._handleMutations=function(b){var a=this._document.readyState;"interactive"!==a&&"complete"!==a||this.disconnect();for(a=0;a<b.length;a++)for(var f=b[a].addedNodes,c=0;c<f.length;c++)this._internals.patchAndUpgradeTree(f[c])};u.default=v;var w={};function x(){var b=this;this._resolve=this._value=void 0;this._promise=new Promise(function(a){b._resolve=a;b._value&&a(b._value)})}x.prototype.resolve=function(b){if(this._value)throw Error("Already resolved.");this._value=b;this._resolve&&this._resolve(b)};x.prototype.toPromise=function(){return this._promise};w.default=x;var y={};function z(b){this._elementDefinitionIsRunning=!1;this._internals=b;this._whenDefinedDeferred=new Map;this._flushCallback=function(b){return b()};this._flushPending=!1;this._pendingDefinitions=[];this._documentConstructionObserver=new u.default(b,document)}
+z.prototype.define=function(b,a){var f=this;if(!(a instanceof Function))throw new TypeError("Custom element constructors must be functions.");if(!k.isValidCustomElementName(b))throw new SyntaxError("The element name '"+b+"' is not valid.");if(this._internals.localNameToDefinition(b))throw Error("A custom element with name '"+b+"' has already been defined.");if(this._elementDefinitionIsRunning)throw Error("A custom element is already being defined.");this._elementDefinitionIsRunning=!0;var c,e,d,q,
+p;try{var n=function(b){var a=B[b];if(void 0!==a&&!(a instanceof Function))throw Error("The '"+b+"' callback must be a function.");return a},B=a.prototype;if(!(B instanceof Object))throw new TypeError("The custom element constructor's prototype is not an object.");c=n("connectedCallback");e=n("disconnectedCallback");d=n("adoptedCallback");q=n("attributeChangedCallback");p=a.observedAttributes||[]}catch(L){return}finally{this._elementDefinitionIsRunning=!1}this._pendingDefinitions.push({localName:b,
+constructor:a,connectedCallback:c,disconnectedCallback:e,adoptedCallback:d,attributeChangedCallback:q,observedAttributes:p,constructionStack:[]});this._flushPending||(this._flushPending=!0,this._flushCallback(function(){return f._flush()}))};
+z.prototype._flush=function(){var b=this;if(!1!==this._flushPending){this._flushPending=!1;for(var a=this._pendingDefinitions,f=new Map,c=0;c<a.length;c++)f.set(a[c].localName,[]);for(this._internals.patchAndUpgradeTree(document,{upgrade:function(a){b._internals.upgradeElement(a);if(void 0===a.__CE_state){var e=f.get(a.localName);e&&e.push(a)}}});0<a.length;){var e=a.shift(),c=e.localName;this._internals.setDefinition(c,e);for(var e=f.get(e.localName),d=0;d<e.length;d++)this._internals.upgradeElement(e[d]);
+(c=this._whenDefinedDeferred.get(c))&&c.resolve(void 0)}}};z.prototype.get=function(b){if(b=this._internals.localNameToDefinition(b))return b.constructor};
+z.prototype.whenDefined=function(b){if(!k.isValidCustomElementName(b))return Promise.reject(new SyntaxError("'"+b+"' is not a valid custom element name."));var a=this._whenDefinedDeferred.get(b);if(a)return a.toPromise();a=new w.default;this._whenDefinedDeferred.set(b,a);this._internals.localNameToDefinition(b)&&!this._pendingDefinitions.some(function(a){return a.localName===b})&&a.resolve(void 0);return a.toPromise()};
+z.prototype.polyfillWrapFlushCallback=function(b){this._documentConstructionObserver.disconnect();var a=this._flushCallback;this._flushCallback=function(f){return b(function(){return a(f)})}};window.CustomElementRegistry=z;z.prototype.define=z.prototype.define;z.prototype.get=z.prototype.get;z.prototype.whenDefined=z.prototype.whenDefined;z.prototype.polyfillWrapFlushCallback=z.prototype.polyfillWrapFlushCallback;y.default=z;var A={},C={Document_createElement:window.Document.prototype.createElement,Document_createElementNS:window.Document.prototype.createElementNS,Document_importNode:window.Document.prototype.importNode,Document_prepend:window.Document.prototype.prepend,Document_append:window.Document.prototype.append,Node_cloneNode:window.Node.prototype.cloneNode,Node_appendChild:window.Node.prototype.appendChild,Node_insertBefore:window.Node.prototype.insertBefore,Node_removeChild:window.Node.prototype.removeChild,
+Node_replaceChild:window.Node.prototype.replaceChild,Node_textContent:Object.getOwnPropertyDescriptor(window.Node.prototype,"textContent"),Element_attachShadow:window.Element.prototype.attachShadow,Element_innerHTML:Object.getOwnPropertyDescriptor(window.Element.prototype,"innerHTML"),Element_getAttribute:window.Element.prototype.getAttribute,Element_setAttribute:window.Element.prototype.setAttribute,Element_removeAttribute:window.Element.prototype.removeAttribute,Element_getAttributeNS:window.Element.prototype.getAttributeNS,
+Element_setAttributeNS:window.Element.prototype.setAttributeNS,Element_removeAttributeNS:window.Element.prototype.removeAttributeNS,Element_insertAdjacentElement:window.Element.prototype.insertAdjacentElement,Element_prepend:window.Element.prototype.prepend,Element_append:window.Element.prototype.append,Element_before:window.Element.prototype.before,Element_after:window.Element.prototype.after,Element_replaceWith:window.Element.prototype.replaceWith,Element_remove:window.Element.prototype.remove,
+XULElement:window.XULElement,XULElement_innerHTML:Object.getOwnPropertyDescriptor(window.XULElement.prototype,"innerHTML"),XULElement_insertAdjacentElement:window.XULElement.prototype.insertAdjacentElement};A.default=C;var D={default:function(b){window.XULElement=function(){function a(){var a=this.constructor,c=b.constructorToDefinition(a);if(!c)throw Error("The custom element being constructed was not registered with `customElements`.");var e=c.constructionStack;if(0===e.length)return e=A.default.Document_createElement.call(document,c.localName),Object.setPrototypeOf(e,a.prototype),e.__CE_state=m.default.custom,e.__CE_definition=c,b.patch(e),e;var c=e.length-1,d=e[c];if(d===g.default)throw Error("The XULElement constructor was either called reentrantly for this constructor or called multiple times.");
+e[c]=g.default;Object.setPrototypeOf(d,a.prototype);b.patch(d);return d}a.prototype=A.default.XULElement.prototype;return a}()}};var E={default:function(b,a,f){a.prepend=function(a){for(var e=[],d=0;d<arguments.length;++d)e[d-0]=arguments[d];d=e.filter(function(b){return b instanceof Node&&k.isConnected(b)});f.prepend.apply(this,e);for(var c=0;c<d.length;c++)b.disconnectTree(d[c]);if(k.isConnected(this))for(d=0;d<e.length;d++)c=e[d],c instanceof Element&&b.connectTree(c)};a.append=function(a){for(var e=[],d=0;d<arguments.length;++d)e[d-0]=arguments[d];d=e.filter(function(b){return b instanceof Node&&k.isConnected(b)});f.append.apply(this,
+e);for(var c=0;c<d.length;c++)b.disconnectTree(d[c]);if(k.isConnected(this))for(d=0;d<e.length;d++)c=e[d],c instanceof Element&&b.connectTree(c)}}};var F={default:function(b){k.setPropertyUnchecked(Document.prototype,"createElement",function(a){if(this.__CE_hasRegistry){var f=b.localNameToDefinition(a);if(f)return new f.constructor}a=A.default.Document_createElement.call(this,a);b.patch(a);return a});k.setPropertyUnchecked(Document.prototype,"importNode",function(a,f){a=A.default.Document_importNode.call(this,a,f);this.__CE_hasRegistry?b.patchAndUpgradeTree(a):b.patchTree(a);return a});k.setPropertyUnchecked(Document.prototype,"createElementNS",
+function(a,f){if(this.__CE_hasRegistry&&(null===a||"http://www.w3.org/1999/xhtml"===a)){var c=b.localNameToDefinition(f);if(c)return new c.constructor}a=A.default.Document_createElementNS.call(this,a,f);b.patch(a);return a});E.default(b,Document.prototype,{prepend:A.default.Document_prepend,append:A.default.Document_append})}};var G={default:function(b){function a(a,c){Object.defineProperty(a,"textContent",{enumerable:c.enumerable,configurable:!0,get:c.get,set:function(a){if(this.nodeType===Node.TEXT_NODE)c.set.call(this,a);else{var d=void 0;if(this.firstChild){var e=this.childNodes,f=e.length;if(0<f&&k.isConnected(this))for(var d=Array(f),n=0;n<f;n++)d[n]=e[n]}c.set.call(this,a);if(d)for(a=0;a<d.length;a++)b.disconnectTree(d[a])}}})}k.setPropertyUnchecked(Node.prototype,"insertBefore",function(a,c){if(a instanceof DocumentFragment){var e=
+Array.prototype.slice.apply(a.childNodes);a=A.default.Node_insertBefore.call(this,a,c);if(k.isConnected(this))for(c=0;c<e.length;c++)b.connectTree(e[c]);return a}e=k.isConnected(a);c=A.default.Node_insertBefore.call(this,a,c);e&&b.disconnectTree(a);k.isConnected(this)&&b.connectTree(a);return c});k.setPropertyUnchecked(Node.prototype,"appendChild",function(a){if(a instanceof DocumentFragment){var c=Array.prototype.slice.apply(a.childNodes);a=A.default.Node_appendChild.call(this,a);if(k.isConnected(this))for(var e=
+0;e<c.length;e++)b.connectTree(c[e]);return a}c=k.isConnected(a);e=A.default.Node_appendChild.call(this,a);c&&b.disconnectTree(a);k.isConnected(this)&&b.connectTree(a);return e});k.setPropertyUnchecked(Node.prototype,"cloneNode",function(a){a=A.default.Node_cloneNode.call(this,a);this.ownerDocument.__CE_hasRegistry?b.patchAndUpgradeTree(a):b.patchTree(a);return a});k.setPropertyUnchecked(Node.prototype,"removeChild",function(a){var c=k.isConnected(a),e=A.default.Node_removeChild.call(this,a);c&&b.disconnectTree(a);
+return e});k.setPropertyUnchecked(Node.prototype,"replaceChild",function(a,c){if(a instanceof DocumentFragment){var e=Array.prototype.slice.apply(a.childNodes);a=A.default.Node_replaceChild.call(this,a,c);if(k.isConnected(this))for(b.disconnectTree(c),c=0;c<e.length;c++)b.connectTree(e[c]);return a}var e=k.isConnected(a),d=A.default.Node_replaceChild.call(this,a,c),f=k.isConnected(this);f&&b.disconnectTree(c);e&&b.disconnectTree(a);f&&b.connectTree(a);return d});A.default.Node_textContent&&A.default.Node_textContent.get?
+a(Node.prototype,A.default.Node_textContent):b.addPatch(function(b){a(b,{enumerable:!0,configurable:!0,get:function(){for(var a=[],b=0;b<this.childNodes.length;b++)a.push(this.childNodes[b].textContent);return a.join("")},set:function(a){for(;this.firstChild;)A.default.Node_removeChild.call(this,this.firstChild);A.default.Node_appendChild.call(this,document.createTextNode(a))}})})}};var H={default:function(b,a,f){a.before=function(a){for(var e=[],d=0;d<arguments.length;++d)e[d-0]=arguments[d];d=e.filter(function(a){return a instanceof Node&&k.isConnected(a)});f.before.apply(this,e);for(var c=0;c<d.length;c++)b.disconnectTree(d[c]);if(k.isConnected(this))for(d=0;d<e.length;d++)c=e[d],c instanceof Element&&b.connectTree(c)};a.after=function(a){for(var e=[],d=0;d<arguments.length;++d)e[d-0]=arguments[d];d=e.filter(function(a){return a instanceof Node&&k.isConnected(a)});f.after.apply(this,
+e);for(var c=0;c<d.length;c++)b.disconnectTree(d[c]);if(k.isConnected(this))for(d=0;d<e.length;d++)c=e[d],c instanceof Element&&b.connectTree(c)};a.replaceWith=function(a){for(var e=[],d=0;d<arguments.length;++d)e[d-0]=arguments[d];var d=e.filter(function(a){return a instanceof Node&&k.isConnected(a)}),c=k.isConnected(this);f.replaceWith.apply(this,e);for(var p=0;p<d.length;p++)b.disconnectTree(d[p]);if(c)for(b.disconnectTree(this),d=0;d<e.length;d++)c=e[d],c instanceof Element&&b.connectTree(c)};
+a.remove=function(){var a=k.isConnected(this);f.remove.call(this);a&&b.disconnectTree(this)}}};var I={default:function(b){function a(a,d){Object.defineProperty(a,"innerHTML",{enumerable:d.enumerable,configurable:!0,get:d.get,set:function(a){var e=this,c=void 0;k.isConnected(this)&&(c=[],k.walkDeepDescendantElements(this,function(a){a!==e&&c.push(a)}));d.set.call(this,a);if(c)for(var f=0;f<c.length;f++){var q=c[f];q.__CE_state===m.default.custom&&b.disconnectedCallback(q)}this.ownerDocument.__CE_hasRegistry?b.patchAndUpgradeTree(this):b.patchTree(this);return a}})}function f(a,d){k.setPropertyUnchecked(a,
+"insertAdjacentElement",function(a,c){var e=k.isConnected(c);a=d.call(this,a,c);e&&b.disconnectTree(c);k.isConnected(a)&&b.connectTree(c);return a})}A.default.Element_attachShadow?k.setPropertyUnchecked(Element.prototype,"attachShadow",function(a){return this.__CE_shadowRoot=a=A.default.Element_attachShadow.call(this,a)}):console.warn("Custom Elements: `Element#attachShadow` was not patched.");if(A.default.Element_innerHTML&&A.default.Element_innerHTML.get)a(Element.prototype,A.default.Element_innerHTML);
+else if(A.default.XULElement_innerHTML&&A.default.XULElement_innerHTML.get)a(XULElement.prototype,A.default.XULElement_innerHTML);else{var c=A.default.Document_createElement.call(document,"div");b.addPatch(function(b){a(b,{enumerable:!0,configurable:!0,get:function(){return A.default.Node_cloneNode.call(this,!0).innerHTML},set:function(a){var b="template"===this.localName?this.content:this;for(c.innerHTML=a;0<b.childNodes.length;)A.default.Node_removeChild.call(b,b.childNodes[0]);for(;0<c.childNodes.length;)A.default.Node_appendChild.call(b,
+c.childNodes[0])}})})}k.setPropertyUnchecked(Element.prototype,"setAttribute",function(a,c){if(this.__CE_state!==m.default.custom)return A.default.Element_setAttribute.call(this,a,c);var d=A.default.Element_getAttribute.call(this,a);A.default.Element_setAttribute.call(this,a,c);c=A.default.Element_getAttribute.call(this,a);b.attributeChangedCallback(this,a,d,c,null)});k.setPropertyUnchecked(Element.prototype,"setAttributeNS",function(a,c,f){if(this.__CE_state!==m.default.custom)return A.default.Element_setAttributeNS.call(this,
+a,c,f);var d=A.default.Element_getAttributeNS.call(this,a,c);A.default.Element_setAttributeNS.call(this,a,c,f);f=A.default.Element_getAttributeNS.call(this,a,c);b.attributeChangedCallback(this,c,d,f,a)});k.setPropertyUnchecked(Element.prototype,"removeAttribute",function(a){if(this.__CE_state!==m.default.custom)return A.default.Element_removeAttribute.call(this,a);var c=A.default.Element_getAttribute.call(this,a);A.default.Element_removeAttribute.call(this,a);null!==c&&b.attributeChangedCallback(this,
+a,c,null,null)});k.setPropertyUnchecked(Element.prototype,"removeAttributeNS",function(a,c){if(this.__CE_state!==m.default.custom)return A.default.Element_removeAttributeNS.call(this,a,c);var d=A.default.Element_getAttributeNS.call(this,a,c);A.default.Element_removeAttributeNS.call(this,a,c);var e=A.default.Element_getAttributeNS.call(this,a,c);d!==e&&b.attributeChangedCallback(this,c,d,e,a)});A.default.XULElement_insertAdjacentElement?f(XULElement.prototype,A.default.XULElement_insertAdjacentElement):
+A.default.Element_insertAdjacentElement?f(Element.prototype,A.default.Element_insertAdjacentElement):console.warn("Custom Elements: `Element#insertAdjacentElement` was not patched.");E.default(b,Element.prototype,{prepend:A.default.Element_prepend,append:A.default.Element_append});H.default(b,Element.prototype,{before:A.default.Element_before,after:A.default.Element_after,replaceWith:A.default.Element_replaceWith,remove:A.default.Element_remove})}};/*
+
+ Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
+ This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ Code distributed by Google as part of the polymer project is also
+ subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+*/
+var J=window.customElements;if(!J||J.forcePolyfill||"function"!=typeof J.define||"function"!=typeof J.get){var K=new r.default;D.default(K);F.default(K);G.default(K);I.default(K);document.__CE_hasRegistry=!0;var customElements=new y.default(K);Object.defineProperty(window,"customElements",{configurable:!0,enumerable:!0,value:customElements})};
+}).call(self);
+
+//# sourceMappingURL=custom-elements.min.js.map
new file mode 100644
--- /dev/null
+++ b/browser/base/content/customelements/custom-elements.js
@@ -0,0 +1,3 @@
+#include custom-elements-polyfill.js
+#include base-element.js
+#include firefox-panel.js
new file mode 100644
--- /dev/null
+++ b/browser/base/content/customelements/firefox-panel.js
@@ -0,0 +1,540 @@
+// XXX: "downloadsPanel" doesn't get recognized by CE polyfill (xul overlay?)
+
+
+
+class FirefoxPopupBase extends BaseElement {
+
+  // XXX: Do we need to generateQI for nsIDOMXULPopupElement? The hamburger menu
+  // seems to open without this.
+  // get QueryInterface() {
+  //   return XPCOMUtils.generateQI([Ci.nsIDOMXULPopupElement]);
+  // }
+
+  constructor() {
+    super();
+  }
+  connectedCallback() {
+    console.log(this, "connected");
+
+    let comment = document.createComment("Creating firefox-popup-base");
+    this.prepend(comment);
+  }
+  disconnectedCallback() {}
+
+  set label(val) {
+    this.setAttribute("label", val);
+    return val;
+  }
+
+  get label() {
+    return this.getAttribute("label");
+  }
+
+  set position(val) {
+    this.setAttribute("position", val);
+    return val;
+  }
+
+  get position() {
+    return this.getAttribute("position");
+  }
+
+  get popupBoxObject() {
+    return this.boxObject;
+  }
+
+  get state() {
+    return this.popupBoxObject.popupState;
+  }
+
+  get triggerNode() {
+    return this.popupBoxObject.triggerNode;
+  }
+
+  get anchorNode() {
+    return this.popupBoxObject.anchorNode;
+  }
+
+  set autoPosition(val) {
+    return (this.popupBoxObject.autoPosition = val);
+  }
+
+  get autoPosition() {
+    return this.popupBoxObject.autoPosition;
+  }
+
+  get alignmentPosition() {
+    return this.popupBoxObject.alignmentPosition;
+  }
+
+  get alignmentOffset() {
+    return this.popupBoxObject.alignmentOffset;
+  }
+  openPopup(
+    aAnchorElement,
+    aPosition,
+    aX,
+    aY,
+    aIsContextMenu,
+    aAttributesOverride,
+    aTriggerEvent
+  ) {
+    // Allow for passing an options object as the second argument.
+    if (
+      arguments.length == 2 &&
+      arguments[1] != null &&
+      typeof arguments[1] == "object"
+    ) {
+      let params = arguments[1];
+      aPosition = params.position;
+      aX = params.x;
+      aY = params.y;
+      aIsContextMenu = params.isContextMenu;
+      aAttributesOverride = params.attributesOverride;
+      aTriggerEvent = params.triggerEvent;
+    }
+
+    dump(`openPopup ${aX} ${aY} ${this.popupBoxObject.openPopup}\n`);
+    try {
+      var popupBox = this.popupBoxObject;
+      if (popupBox)
+        popupBox.openPopup(
+          aAnchorElement,
+          aPosition,
+          aX,
+          aY,
+          aIsContextMenu,
+          aAttributesOverride,
+          aTriggerEvent
+        );
+    } catch (e) {
+      dump(`Caught ${e} \n`);
+    }
+  }
+  openPopupAtScreen(aX, aY, aIsContextMenu, aTriggerEvent) {
+    try {
+      var popupBox = this.popupBoxObject;
+      if (popupBox)
+        popupBox.openPopupAtScreen(aX, aY, aIsContextMenu, aTriggerEvent);
+    } catch (e) {}
+  }
+  openPopupAtScreenRect(
+    aPosition,
+    aX,
+    aY,
+    aWidth,
+    aHeight,
+    aIsContextMenu,
+    aAttributesOverride,
+    aTriggerEvent
+  ) {
+    try {
+      var popupBox = this.popupBoxObject;
+      if (popupBox)
+        popupBox.openPopupAtScreenRect(
+          aPosition,
+          aX,
+          aY,
+          aWidth,
+          aHeight,
+          aIsContextMenu,
+          aAttributesOverride,
+          aTriggerEvent
+        );
+    } catch (e) {}
+  }
+  showPopup(element, xpos, ypos, popuptype, anchoralignment, popupalignment) {
+    var popupBox = null;
+    var menuBox = null;
+    try {
+      popupBox = this.popupBoxObject;
+    } catch (e) {}
+    try {
+      menuBox = this.parentNode.boxObject;
+    } catch (e) {}
+    if (menuBox instanceof MenuBoxObject) menuBox.openMenu(true);
+    else if (popupBox)
+      popupBox.showPopup(
+        element,
+        this,
+        xpos,
+        ypos,
+        popuptype,
+        anchoralignment,
+        popupalignment
+      );
+  }
+  hidePopup(cancel) {
+    var popupBox = null;
+    var menuBox = null;
+    try {
+      popupBox = this.popupBoxObject;
+    } catch (e) {}
+    try {
+      menuBox = this.parentNode.boxObject;
+    } catch (e) {}
+    if (menuBox instanceof MenuBoxObject) menuBox.openMenu(false);
+    else if (popupBox instanceof PopupBoxObject) popupBox.hidePopup(cancel);
+  }
+  enableKeyboardNavigator(aEnableKeyboardNavigator) {
+    this.popupBoxObject.enableKeyboardNavigator(aEnableKeyboardNavigator);
+  }
+  enableRollup(aEnableRollup) {
+    this.popupBoxObject.enableRollup(aEnableRollup);
+  }
+  sizeTo(aWidth, aHeight) {
+    this.popupBoxObject.sizeTo(aWidth, aHeight);
+  }
+  moveTo(aLeft, aTop) {
+    this.popupBoxObject.moveTo(aLeft, aTop);
+  }
+  moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride) {
+    this.popupBoxObject.moveToAnchor(
+      aAnchorElement,
+      aPosition,
+      aX,
+      aY,
+      aAttributesOverride
+    );
+  }
+  getOuterScreenRect() {
+    return this.popupBoxObject.getOuterScreenRect();
+  }
+  setConstraintRect(aRect) {
+    this.popupBoxObject.setConstraintRect(aRect);
+  }
+}
+customElements.define("firefox-popup-base", FirefoxPopupBase);
+
+
+class FirefoxPanel extends FirefoxPopupBase {
+
+
+  // XXX: Do we need to generateQI for nsIDOMXULPopupElement? The hamburger menu
+  // seems to open without this.
+  // get QueryInterface() {
+  //   return XPCOMUtils.generateQI([Ci.nsIDOMXULPopupElement]);
+  // }
+
+  constructor() {
+    super();
+  }
+  connectedCallback() {
+    super.connectedCallback();
+    dump(`connectedCallback FirefoxPanel ${this.id}\n`);
+
+    let comment = document.createComment("Creating firefox-panel");
+    this.prepend(comment);
+
+    Object.defineProperty(this, "_prevFocus", {
+      configurable: true,
+      enumerable: true,
+      get() {
+        delete this._prevFocus;
+        return (this._prevFocus = 0);
+      },
+      set(val) {
+        delete this._prevFocus;
+        return (this._prevFocus = val);
+      }
+    });
+    Object.defineProperty(this, "_dragBindingAlive", {
+      configurable: true,
+      enumerable: true,
+      get() {
+        delete this._dragBindingAlive;
+        return (this._dragBindingAlive = true);
+      },
+      set(val) {
+        delete this._dragBindingAlive;
+        return (this._dragBindingAlive = val);
+      }
+    });
+
+    if (this.getAttribute("backdrag") == "true" && !this._draggableStarted) {
+      this._draggableStarted = true;
+      try {
+        let tmp = {};
+        Components.utils.import(
+          "resource://gre/modules/WindowDraggingUtils.jsm",
+          tmp
+        );
+        let draghandle = new tmp.WindowDraggingElement(this);
+        draghandle.mouseDownCheck = function() {
+          return this._dragBindingAlive;
+        };
+      } catch (e) {}
+    }
+
+    this.addEventListener("popupshowing", event => {
+      // Capture the previous focus before has a chance to get set inside the panel
+      try {
+        this._prevFocus = Components.utils.getWeakReference(
+          document.commandDispatcher.focusedElement
+        );
+        if (this._prevFocus.get()) return;
+      } catch (ex) {}
+
+      this._prevFocus = Components.utils.getWeakReference(
+        document.activeElement
+      );
+    });
+
+    this.addEventListener("popupshown", event => {
+      // Fire event for accessibility APIs
+      var alertEvent = document.createEvent("Events");
+      alertEvent.initEvent("AlertActive", true, true);
+      this.dispatchEvent(alertEvent);
+    });
+
+    this.addEventListener("popuphiding", event => {
+      try {
+        this._currentFocus = document.commandDispatcher.focusedElement;
+      } catch (e) {
+        this._currentFocus = document.activeElement;
+      }
+    });
+
+    this.addEventListener("popuphidden", event => {
+      function doFocus() {
+        // Focus was set on an element inside this panel,
+        // so we need to move it back to where it was previously
+        try {
+          let fm = Components.classes[
+            "@mozilla.org/focus-manager;1"
+          ].getService(Components.interfaces.nsIFocusManager);
+          fm.setFocus(prevFocus, fm.FLAG_NOSCROLL);
+        } catch (e) {
+          prevFocus.focus();
+        }
+      }
+      var currentFocus = this._currentFocus;
+      var prevFocus = this._prevFocus ? this._prevFocus.get() : null;
+      this._currentFocus = null;
+      this._prevFocus = null;
+
+      // Avoid changing focus if focus changed while we hide the popup
+      // (This can happen e.g. if the popup is hiding as a result of a
+      // click/keypress that focused something)
+      let nowFocus;
+      try {
+        nowFocus = document.commandDispatcher.focusedElement;
+      } catch (e) {
+        nowFocus = document.activeElement;
+      }
+      if (nowFocus && nowFocus != currentFocus) return;
+
+      if (prevFocus && this.getAttribute("norestorefocus") != "true") {
+        // Try to restore focus
+        try {
+          if (document.commandDispatcher.focusedWindow != window) return; // Focus has already been set to a window outside of this panel
+        } catch (ex) {}
+
+        if (!currentFocus) {
+          doFocus();
+          return;
+        }
+        while (currentFocus) {
+          if (currentFocus == this) {
+            doFocus();
+            return;
+          }
+          currentFocus = currentFocus.parentNode;
+        }
+      }
+    });
+
+    // Special case for other bindings like arrowpanel, because platform has code
+    // looking for the 'panel' tag but custom elements don't let us register an element
+    // based on an attribute value. So we need to fold in the arrow functionality in that case.
+    if (this.getAttribute("type") === "arrow") {
+      dump(`Got an arrow popup ${this.id}\n`);
+      ArrowPanelConnectedCallback.call(this);
+    }
+  }
+  disconnectedCallback() {}
+}
+
+customElements.define("panel", FirefoxPanel);
+
+
+function ArrowPanelConnectedCallback() {
+  console.log(this, "connected");
+
+  // XXX: This simulates the <children> tag inside the panel-arrowcontent
+  let frag = document.createElement("box");
+  frag.innerHTML = `<vbox anonid="container" class="panel-arrowcontainer" flex="1" inherits="side,panelopen">
+<box anonid="arrowbox" class="panel-arrowbox">
+<image anonid="arrow" class="panel-arrow" inherits="side">
+</image>
+</box>
+<box class="panel-arrowcontent" inherits="side,align,dir,orient,pack" flex="1">
+</box>
+</vbox>`
+
+  let nodes = [...this.childNodes];
+  for (var i = 0; i < nodes.length; i++) {
+    dump("Adding " + i + " " + nodes[i].localName + "\n");
+    frag.querySelector(".panel-arrowcontent").appendChild(nodes[i]);
+  }
+
+  this.innerHTML = '';
+
+  nodes = [...frag.childNodes];
+  for (var i = 0; i < nodes.length; i++) {
+    this.appendChild(nodes[i]);
+  }
+
+  let comment = document.createComment("Creating firefox-arrowpanel");
+  this.prepend(comment);
+
+  Object.defineProperty(this, "_fadeTimer", {
+    configurable: true,
+    enumerable: true,
+    get() {
+      delete this._fadeTimer;
+      return (this._fadeTimer = null);
+    },
+    set(val) {
+      delete this._fadeTimer;
+      return (this._fadeTimer = val);
+    }
+  });
+
+  this.addEventListener("popupshowing", event => {
+    dump("popupshowing\n");
+    var arrow = this.querySelector("[anonid=arrow]");
+    arrow.hidden = this.anchorNode == null;
+    this.querySelector("[anonid=arrowbox]").style.removeProperty("transform");
+
+    this.adjustArrowPosition();
+
+    if (this.getAttribute("animate") != "false") {
+      this.setAttribute("animate", "open");
+      // the animating attribute prevents user interaction during transition
+      // it is removed when popupshown fires
+      this.setAttribute("animating", "true");
+    }
+
+    // set fading
+    var fade = this.getAttribute("fade");
+    var fadeDelay = 0;
+    if (fade == "fast") {
+      fadeDelay = 1;
+    } else if (fade == "slow") {
+      fadeDelay = 4000;
+    } else {
+      return;
+    }
+
+    this._fadeTimer = setTimeout(() => this.hidePopup(true), fadeDelay, this);
+  });
+
+  this.addEventListener("popuphiding", event => {
+    dump("popuphiding\n");
+    let animate = this.getAttribute("animate") != "false";
+
+    if (this._fadeTimer) {
+      clearTimeout(this._fadeTimer);
+      if (animate) {
+        this.setAttribute("animate", "fade");
+      }
+    } else if (animate) {
+      this.setAttribute("animate", "cancel");
+    }
+  });
+
+  this.addEventListener("popupshown", event => {
+    dump("popupshown\n");
+    this.removeAttribute("animating");
+    this.setAttribute("panelopen", "true");
+  });
+
+  this.addEventListener("popuphidden", event => {
+    dump("popuphidden\n");
+    this.removeAttribute("panelopen");
+    if (this.getAttribute("animate") != "false") {
+      this.removeAttribute("animate");
+    }
+  });
+
+  this.addEventListener("popuppositioned", event => {
+    dump("popuppositioned\n");
+    this.adjustArrowPosition();
+  });
+
+  this.sizeTo = (aWidth, aHeight) => {
+    this.popupBoxObject.sizeTo(aWidth, aHeight);
+    if (this.state == "open") {
+      this.adjustArrowPosition();
+    }
+  }
+
+  this.moveToAnchor = (aAnchorElement, aPosition, aX, aY, aAttributesOverride) => {
+    this.popupBoxObject.moveToAnchor(
+      aAnchorElement,
+      aPosition,
+      aX,
+      aY,
+      aAttributesOverride
+    );
+  }
+
+
+  this.adjustArrowPosition = () => {
+    var anchor = this.anchorNode;
+    if (!anchor) {
+      return;
+    }
+
+    var container = this.querySelector("[anonid=container]");
+    var arrowbox = this.querySelector("[anonid=arrowbox]");
+
+    var position = this.alignmentPosition;
+    var offset = this.alignmentOffset;
+
+    this.setAttribute("arrowposition", position);
+
+    if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) {
+      container.orient = "horizontal";
+      arrowbox.orient = "vertical";
+      if (position.indexOf("_after") > 0) {
+        arrowbox.pack = "end";
+      } else {
+        arrowbox.pack = "start";
+      }
+      arrowbox.style.transform = "translate(0, " + -offset + "px)";
+
+      // The assigned side stays the same regardless of direction.
+      var isRTL = window.getComputedStyle(this).direction == "rtl";
+
+      if (position.indexOf("start_") == 0) {
+        container.dir = "reverse";
+        this.setAttribute("side", isRTL ? "left" : "right");
+      } else {
+        container.dir = "";
+        this.setAttribute("side", isRTL ? "right" : "left");
+      }
+    } else if (
+      position.indexOf("before_") == 0 ||
+      position.indexOf("after_") == 0
+    ) {
+      container.orient = "";
+      arrowbox.orient = "";
+      if (position.indexOf("_end") > 0) {
+        arrowbox.pack = "end";
+      } else {
+        arrowbox.pack = "start";
+      }
+      arrowbox.style.transform = "translate(" + -offset + "px, 0)";
+
+      if (position.indexOf("before_") == 0) {
+        container.dir = "reverse";
+        this.setAttribute("side", "bottom");
+      } else {
+        container.dir = "";
+        this.setAttribute("side", "top");
+      }
+    }
+  }
+}
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -86,16 +86,17 @@ browser.jar:
         content/browser/browser-tabsintitlebar.js       (content/browser-tabsintitlebar.js)
 #else
         content/browser/browser-tabsintitlebar.js       (content/browser-tabsintitlebar-stub.js)
 #endif
         content/browser/browser-thumbnails.js         (content/browser-thumbnails.js)
         content/browser/browser-trackingprotection.js (content/browser-trackingprotection.js)
         content/browser/tab-content.js                (content/tab-content.js)
         content/browser/content.js                    (content/content.js)
+*       content/browser/customelements/custom-elements.js (content/customelements/custom-elements.js)
         content/browser/default-theme-icon.svg        (content/default-theme-icon.svg)
         content/browser/defaultthemes/1.header.jpg    (content/defaultthemes/1.header.jpg)
         content/browser/defaultthemes/1.icon.jpg      (content/defaultthemes/1.icon.jpg)
         content/browser/defaultthemes/1.preview.jpg   (content/defaultthemes/1.preview.jpg)
         content/browser/defaultthemes/2.header.jpg    (content/defaultthemes/2.header.jpg)
         content/browser/defaultthemes/2.icon.jpg      (content/defaultthemes/2.icon.jpg)
         content/browser/defaultthemes/2.preview.jpg   (content/defaultthemes/2.preview.jpg)
         content/browser/defaultthemes/3.header.png    (content/defaultthemes/3.header.png)
--- a/browser/themes/shared/browser.inc.css
+++ b/browser/themes/shared/browser.inc.css
@@ -12,16 +12,17 @@
 :root[tabsintitlebar][sizemode=normal] #TabsToolbar
 %endif
 {
   padding-inline-start: 40px;
 }
 %endif
 
 %include downloads/indicator.inc.css
+%include customelements/custom-elements.inc.css
 
 /* Toolbar / content area border */
 
 #navigator-toolbox::after {
   content: "";
   display: -moz-box;
   border-bottom: 1px solid var(--toolbox-border-bottom-color);
 }
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/customelements/custom-elements.inc.css
@@ -0,0 +1,9 @@
+%if 0
+/* 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/. */
+%endif
+
+panel {
+  background: orange;
+}
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -23,16 +23,17 @@
 * skin/classic/browser/controlcenter/conn-not-secure.svg       (../shared/controlcenter/conn-not-secure.svg)
 * skin/classic/browser/controlcenter/connection.svg            (../shared/controlcenter/connection.svg)
 * skin/classic/browser/controlcenter/mcb-disabled.svg          (../shared/controlcenter/mcb-disabled.svg)
   skin/classic/browser/controlcenter/extension.svg             (../shared/controlcenter/extension.svg)
 * skin/classic/browser/controlcenter/permissions.svg           (../shared/controlcenter/permissions.svg)
 * skin/classic/browser/controlcenter/tracking-protection.svg   (../shared/controlcenter/tracking-protection.svg)
   skin/classic/browser/controlcenter/warning-gray.svg          (../shared/controlcenter/warning-gray.svg)
   skin/classic/browser/controlcenter/warning-yellow.svg        (../shared/controlcenter/warning-yellow.svg)
+* skin/classic/browser/customelements/custom-elements.inc.css  (../shared/customelements/custom-elements.inc.css)
   skin/classic/browser/customizableui/menuPanel-customizeFinish.png  (../shared/customizableui/menuPanel-customizeFinish.png)
   skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png  (../shared/customizableui/menuPanel-customizeFinish@2x.png)
   skin/classic/browser/customizableui/empty-overflow-panel.png     (../shared/customizableui/empty-overflow-panel.png)
   skin/classic/browser/customizableui/empty-overflow-panel@2x.png  (../shared/customizableui/empty-overflow-panel@2x.png)
   skin/classic/browser/customizableui/density-compact.svg      (../shared/customizableui/density-compact.svg)
   skin/classic/browser/customizableui/density-normal.svg       (../shared/customizableui/density-normal.svg)
   skin/classic/browser/customizableui/density-touch.svg        (../shared/customizableui/density-touch.svg)
   skin/classic/browser/customizableui/subView-arrow-back-inverted.png  (../shared/customizableui/subView-arrow-back-inverted.png)
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -411,40 +411,42 @@ menuseparator {
 /* <popup> is deprecated.  Only <menupopup> and <tooltip> are still valid. */
 
 popup,
 menupopup {
   -moz-binding: url("chrome://global/content/bindings/popup.xml#popup");
   -moz-box-orient: vertical;
 }
 
+/*
 panel {
   -moz-binding: url("chrome://global/content/bindings/popup.xml#panel");
   -moz-box-orient: vertical;
 }
-
+*/
 popup,
 menupopup,
 panel,
 tooltip {
   display: -moz-popup;
   z-index: 2147483647;
   text-shadow: none;
 }
 
 tooltip {
   -moz-binding: url("chrome://global/content/bindings/popup.xml#tooltip");
   -moz-box-orient: vertical;
   white-space: pre-wrap;
   margin-top: 21px;
 }
 
+/*
 panel[type="arrow"] {
   -moz-binding: url("chrome://global/content/bindings/popup.xml#arrowpanel");
-}
+}*/
 
 %ifdef MOZ_WIDGET_COCOA
 
 /* On Mac, use the properties "-moz-window-transform" and "-moz-window-opacity"
    instead of "transform" and "opacity" for these animations.
    The -moz-window* properties apply to the whole window including the window's
    shadow, and they don't affect the window's "shape", so the system doesn't
    have to recompute the shadow shape during the animation. This makes them a