Monday, June 16, 2014

A Tag Named apply-author-styles


It occurs to me that, in the absence of the now-deprecated applyAuthorStyles in Polymer, it might be nice to have an <apply-author-styles> tag in Polymer. That is, if I define my custom polymer elements with <apply-author-styles>:
<link rel="import"
      href="apply-author-styles.html">
<script src="../bower_components/snap.svg/dist/snap.svg.js"></script>
<polymer-element name="x-pizza">
  <template>
    <apply-author-styles></apply-author-styles>
    <!-- ... --->
  </template>
  <script src="x_pizza.js"></script>
</polymer-element>
Then native elements (e.g. buttons) should pick up whatever crazy styles are defined in the top level document:



I figured out how to apply “author” styles over the past two nights. Now it is mostly a question of “if” and “how” to accomplish the same from a child custom element.

To find out, I remove all of the previous nights' code from my custom pizza building <x-pizza> Polymer element. With apply-author-styles.html imported and <apply-author-styles> in <x-pizza>'s <template> tag as from the beginning of this post, I am ready to start on the actual <apply-author-styles> Polymer definition.

I begin with the <polymer-element> definition in apply-author-styles.html:
<link rel="import"
      href="../bower_components/core-ajax/core-ajax.html">
<polymer-element name="apply-author-styles">
  <script src="apply_author_styles.js"></script>
</polymer-element>
This is simple enough. I import <core-ajax> to fetch the original parent page for comparison (as done last night). The rest sources the apply_author_styles.js backing class definition—there is no UI presence for this element.

With that out of the way, I start the JavaScript definition finding the main page document and the shadow root of the element that I am targeting:
Polymer('apply-author-styles', {
  attached: function() {
    this.parent = this.parentNode;
    this.authorDocument = this.ownerDocument;
    this.fetchOriginalOwnerDocument();
  },
  // ...
});
I need the parent node for access to the shadow root of the element that is holding <apply-author-styles>. I need the main document so that I only apply styles from the original, un-JavaScripted source. To get access, I fetch it with another, core Polymer element, <core-ajax> and, once I get it I start applying styles:
Polymer('apply-author-styles', {
  attached: function() {
    // ...
    this.fetchOriginalOwnerDocument();
  },

  fetchOriginalOwnerDocument: function() {
    var doc = this.originalAuthorDocument = document.createElement('core-ajax');
    doc.addEventListener('core-complete', this.addExternalCss.bind(this));
    doc.url = this.authorDocument.location.href;
    doc.go();
  },
  // ...
});
The addExternalCss() method is nearly identical to yesterday's version:
Polymer('apply-author-styles', {
  // ...
  fetchOriginalOwnerDocument: function() {
    var doc = this.originalAuthorDocument = document.createElement('core-ajax');
    doc.addEventListener('core-complete', this.addExternalCss.bind(this));
    doc.url = this.authorDocument.location.href;
    doc.go();
  },

  addExternalCss: function() {
    for (var i=0; i<this.authorDocument.head.children.length; i++) {
      var el = this.authorDocument.head.children[i];
      if (!this._isSupportedTag(el)) continue;
      if (!this._isFromOriginalAuthorDocument(el)) continue;

      var clone = el.cloneNode(true);
      if (clone.href != 'undefined') {
        clone.href = new URL(clone.href, document.baseURI).href;
      }
      this.parent.appendChild(clone);
    }

    // TODO: is this really the best way to handle this?
    this.element.convertSheetsToStyles(this.parent);
  },
  // ...
});
I gain access to Polymer's convertSheetsToStyles() method, which creates Polymer-ready versions of the various styles that are copied into the shadow root of <x-pizza>, not through <x-pizza>, but through <apple-author-styles>. I call that method with <x-pizza>'s shadow root, which feels a little wrong… except that it works

Not only does it work in Chrome, but in Firefox and even Internet Explorer:



So it looks like applyAuthorStyles is back—now in Polymer custom element form.

Without further ado… I introduce apply-author-styles.


Day #95

2 comments:

  1. Hey Chris,


    Have you had a chance to play around with core-style at all? The source is heavily commented so you can read through all that it's doing.
    https://github.com/Polymer/core-style/blob/master/core-style.html

    It's an experiment to see if we can improve the theming situation.

    ReplyDelete
    Replies
    1. Gah! It's so hard to keep up with all the cool stuff coming out of this project... I'll definitely take a closer look. Thanks :)

      Delete