On Polymer and Smileys

... or Polysmileys ...
≧^◡^≦

Live coding magic happening on stage right now ;)

@CarmenPopoviciu

=^.^=

I <3 trampolines I'm happy around cakes

=^.^=

I ASCII smileys

fav ascii smiley

^_^

fav ascii smiley++

About this talk

The true heroes of this talk are:

(>‿◠)✌ Guilherme Rv Coelho <super-presentation>

☜(ˆ▽ˆ) Filipe Araujo <akyral-code>

ONE LAST WARNING!

This talk contains an overdose of smileys

^.^= ≥^.^≤ ≤^.^≥ (>‿◠)✌ ≧✯◡✯≦✌ ≧◠◡◠≦✌ ≧'◡'≦ =☽ ≧◔◡◔≦ ≧◉◡◉≦ ≧✯◡✯≦ ≧❂◡❂≦ ≧^◡^≦ ≧°◡°≦ ≧◡≦ (─‿‿─) ᵔ.ᵔ :◅) ≕) ≔) ≠) |:-) =) :) :-) ;) ;=) ;-) ж) ^o^ ^.^ ^.^) =^.^= :*) :-> (¬‿¬) ٩(●̮̮̃•)۶ ٩(̃-̮̮̃-)۶ (-̮̮̃•)۶ ٩(×̯×)۶ ٩(•̮̮̃-̃)۶ <(^,^)> (≧◡≦) 乂⍲‿⍲乂 〷◠‿◠〷 '☋' :=◑ ☋ Σ=) Ж-þ ^^. (‐^▽^‐) =D ≧❂◡❂≦ ≧^◡^≦ ≧°◡°≦ ≧◡≦ (─‿‿─) ☜(*▽*)☞ ☜(˚▽˚)☞ \ ˚▽˚ / ^o^ ^.^ ^.^) (• ◡•)| (>‿♥) ✿◕ ‿ ◕✿ ❀◕ ‿ ◕❀ ❁◕ ‿ ◕❁ %ᵕ‿‿ᵕ% (◡‿◡✿) (✿◠‿◠) ≧❀‿❀≦ ^.^= ≥^.^≤ ≤^.^≥ (>‿◠)✌ ≧✯◡✯≦✌ ≧◠◡◠≦✌ ≧'◡'≦ =☽ ≧◔◡◔≦ ≧◉◡◉≦ ≧✯◡✯≦ ✿◕ ‿ ◕✿ ❀◕ ‿ ◕❀ ≧❂◡❂≦ ≧^◡^≦ ≧°◡°≦ ≧◡≦ (─‿‿─) ᵔ.ᵔ :◅) ≕) ≔) ≠) |:-) =) :) :-) ;) ;=) ;-) ж) ^o^ ^.^ ^.^) =^.^= :*) :-> (¬‿¬) ٩(●̮̮̃•)۶ ٩(̃-̮̮̃-)۶ (-̮̮̃•)۶ ٩(×̯×)۶ ٩(•̮̮̃-̃)۶ <(^,^)> (≧◡≦) 乂⍲‿⍲乂 〷◠‿◠〷 '☋' :=◑ ☋ Σ=) Ж-þ ^^. (‐^▽^‐) =D ≧❂◡❂≦ ≧^◡^≦ ≧°◡°≦ ≧◡≦ (─‿‿─) ☜(*▽*)☞ ☜(˚▽˚)☞ ≕) ≔) ≠) |:-) =) :) :-) ;) ;=) \ ˚▽˚ / ^o^ ^.^ ^.^) (• ◡•)| (>‿♥) ✿◕ ‿ ◕✿ ❀◕ ‿ ◕❀ ❁◕ ‿ ◕❁ %ᵕ‿‿ᵕ% (◡‿◡✿) (✿◠‿◠) ≧❀‿❀≦ ^.^= ≥^.^≤ ≤^.^≥ (>‿◠)✌ ≧✯◡✯≦✌ ≧◠◡◠≦✌ ≧'◡'≦ =☽ ≧◔◡◔≦ ≧◉◡◉≦ ≧✯◡✯≦ ≧❂◡❂≦ ≧^◡^≦ ≧°◡°≦ ≧◡≦ (─‿‿─) ᵔ.ᵔ :◅) ≕) ≔) ≠) |:-) =) :) :-) ;) ;=) ;-) ж) ^o^ ^.^ ^.^) =^.^= :*) :-> (¬‿¬) ٩(●̮̮̃•)۶ ٩(̃-̮̮̃-)۶ (-̮̮̃•)۶ ٩(×̯×)۶ ٩(•̮̮̃-̃)۶ <(^,^)> (≧◡≦) 乂⍲‿⍲乂 〷◠‿◠〷 '☋' :=◑ ☋ Σ=) Ж-þ ^^. (‐^▽^‐) =D ≧❂◡❂≦ ≧^◡^≦ ≧°◡°≦ ≧◡≦ (─‿‿─) ☜(*▽*)☞ ☜(˚▽˚)☞ \ ˚▽˚ / ≕) ≔) ≠) |:-) =) :) :-) ;) ;=) (• ◡•)| (>‿♥) ✿◕ ‿ ◕✿ ❀◕ ‿ ◕❀ ❁◕ ‿ ◕❁ %ᵕ‿‿ᵕ% (◡‿◡✿) (✿◠‿◠) ≧❀‿❀≦ ≧❂◡❂≦ ≧^◡^≦ ≧°◡°≦ ≧◡≦ (─‿‿─) ✿◕ ‿ ◕✿ ❀◕ ‿ ◕❀ ❁◕ ‿ ◕❁

Web Components

Web Components

are a set of standards that allow for the creation of reusable widgets or components in web documents and web applications

Web Components Standards

Web Components Standards

Custom Elements

Allow authors to extend the HTML vocabulary and define their own, new, fully-featured DOM elements

<ascii-smile></ascii-smile>

Custom Elements give you

declarative, readable, meaningful, reusable, self sustainable

HTML Elements

Autonomous Custom Element Registration

Is the process of adding an element definition to a registry

document.registerElement('ascii-smile', // the type { // the prototype. HTMLElement/SVGElement by default prototype: Object.create(HTMLElement.prototype) } ); // returns a constructor function
<ascii-smile></ascii-smile>

Customized Built-In Elements

are Custom Elements that extend other existing elements

var AsciiSmileProto = Object.create(HTMLElement.prototype); ... document.registerElement('ascii-carmen-smile', { prototype: AsciiSmileProto, extends: 'ascii-smile' } );
<ascii-smile is="ascii-smile-carmen"></ascii-smile>

Lifecycle Callbacks

Web Components Standards

Templates

Enable you to store HTML data inside an HTML document. The content of a <template> element is parsed without interpreting it (no loading of images etc.)

❂.❂ Remember! ❂.❂

Declaring/Enabling a Template

<template id="template"> <style>...</style> <div> <h1>ASCII Heart</h1> <div><3</div> <img src="http://ascii-paradise/heart.jpg"> </div> </template> <script> var template = document.querySelector('#template'); var clone = document.importNode(template.content, true); var host = document.querySelector('#host'); host.appendChild(clone); </script> <div id="host"></div>

Web Components Standards

Shadow DOM

Shadow DOM encapsulates and hides the innards of a custom element inside a nested document.

Shadow DOM Concepts

let me show you something

¸.•*¨*•♫♪ⒸⓄⓄⓁ•*¨*•.¸ & ¸.•*¨*•♫♪ⒶⓌⒺⓈⓄⓂⒺ•*¨*•.¸

Web Components Standards

HTML Imports

is a way to include HTML documents in other HTML documents in a simple and declarative way

Declaring HTML Imports

<html> <!-- import referrer--> <head> <!-- URL = import location --> <!-- ascii-paradise.html = imported document --> <link rel="import" href="path/to/ascii-paradise.html"> </head> </html>

link.import

Including an import on a page returns a Document not its content

var content = document.querySelector('link[rel="import"]').import;

Let's give some ❤ to the Web

<ascii-heart></ascii-heart>

<template id="heart-template"> <style> ... </style> <div id="ascii-heart"><3</div> </template> <script> // thisDoc = ascii-heart.html var thisDoc = document._currentScript.ownerDocument; // mainDoc = index.html var mainDoc = document; var proto = Object.create(HTMLElement.prototype); proto.createdCallback = function() { var shadowRoot = this.createShadowRoot(); var template = thisDoc.querySelector('#heart-template'); var clone = thisDoc.importNode(template.content, true); shadowRoot.appendChild(clone); }; mainDoc.registerElement('ascii-heart', { prototype: proto }); </script>

And now for the moment when you're going to hate me

v0 vs v1

https://github.com/CarmenPopoviciu/web-components-resources

Polymer

Polymer

is a library built on top of the web components standards, that helps you build reusable components, faster and easier

Web Components Stack

Polymer features

Custom Element Registration

To register a custom element, use the Polymer function, and pass in the prototype for the new element

var ASCIIHeart = Polymer({ // element prototype is: 'ascii-heart', // tag name (mandatory) properties: {...}, ready: function() {...}, ... });
// imperative var asciiHeart = document.createElement('ascii-heart'); // or var asciiHeart = new ASCIIHeart();

Custom Element Registration

To register a custom element, use the Polymer function, and pass in the prototype for the new element

var ASCIIHeart = Polymer({ // element prototype is: 'ascii-heart', // tag name (mandatory) properties: {...}, ready: function() {...}, ... });
<!-- declarative --> <ascii-heart></ascii-heart>

Prototype chaining

The Polymer function sets up the prototype chain for your custom element, chaining it to the Polymer Base prototype (which provides Polymer value-added features)

Polymer.Base

Polymer.Base = { __isPolymerInstance__: true, _addFeature: function() { // pluggable features }, registerCallback: function() {...}, createdCallback: function() {...}, attachedCallback: function() {...}, detachedCallback: function() {..}, attributeChangedCallback: function() {...}, ... }; ... Polymer.Base = Polymer.Base .chainObject(Polymer.Base, HTMLElement.prototype);

Class-Style Constructor

allows creating a Custom Element without immediately registering it

// returns a constructor that can be passed to // document.registerElement to register your element var ASCIIHeart = Polymer.Class({ // same prototype argument as the Polymer function is: 'ascii-heart', created: function() { ... } ... });
document.registerElement('ascii-heart', ASCIIHeart);

Class-Style Constructor

allows creating a Custom Element without immediately registering it

// returns a constructor that can be passed to // document.registerElement to register your element var ASCIIHeart = Polymer.Class({ // same prototype argument as the Polymer function is: 'ascii-heart', created: function() { ... } ... });
var asciiHeart = new ASCIIHeart(); // or var asciiHeart = document.createElement('ascii-heart');

Type Extension Elements

var ASCIICarmenSmileBtn = Polymer({ is: 'ascii-carmen-smile-btn', extends: 'button' });
var asciiCarmenSmileBtn = document.createElement('button', 'ascii-carmen-smile-btn'); // or var asciiCarmenSmileBtn = new ASCIICarmenSmileBtn();
<button is="ascii-carmen-smile"></button>
ONLY native elements!!!

Lifecycle callbacks

Lifecycle callbacks

Lifecycle callbacks

Polymer({ is: 'ascii-heart', created: function() { /* createdCallback */ // Called when the element has been created, but before // property values are set and local DOM is initialized }, ready: function() { // Called after prop values are set & local DOM is initialized }, attached: function() { /* attachedCallback */ // Called after the element is attached to the document }, detached: function() { /* detachedCallback */ // Called after the element is detached from the document }, attributeChanged: function(name, type) { /* attributeChangedCallback*/ // Called when one of the element's attributes is changed } });

Local DOM

is the DOM that an element creates

Local DOM

Polymer supports multiple Local DOM implementations


Creating Local DOM

<dom-module> </dom-module>

Creating Local DOM

<dom-module> <template> <div id="heart"><3</div> </template> </dom-module>

Creating Local DOM

<dom-module > <template> <div id="heart"><3</div> </template> <script> Polymer({ is: }); </script> </dom-module>

Creating Local DOM

<dom-module id="ascii-heart"> <template> <div id="heart"><3</div> </template> <script> Polymer({ is: 'ascii-heart' }); </script> </dom-module>

Creating Local DOM

<dom-module id="ascii-heart"> <template> <div id="heart"><3</div> </template> </dom-module> <script> Polymer({ is: 'ascii-heart' }); </script>

Node finding

Node finding

<dom-module id="ascii-heart"> <template> <div id="heart"><3</div> </template> <script> Polymer({ is: 'ascii-heart', ready: function() { } }); </script> </dom-module>

Node finding

<dom-module id="ascii-heart"> <template> <div id="heart"><3</div> </template> <script> Polymer({ is: 'ascii-heart', ready: function() { this.$.heart.textContent = '<3 <3'; } }); </script> </dom-module>

Insertion Points

Polymer provides insertion points via the <content> element. This element supports a select attribute which filters nodes via a simple selector

Insertion Points

<ascii-shrug> <span class="my-face">◔◡◔</span> <span class="my-other-face">◔.◔</span> </ascii-shrug>
<dom-module id="ascii-shrug"> <template> <div class="right-arm">¯\_</div> <div class="face"> <content ></content> </div> <div class="left-arm">_/¯</div> </template> <script> Polymer({ is: 'ascii-shrug' }); </script> </dom-module>

Insertion Points

<ascii-shrug> <span class="my-face">◔◡◔</span> <span class="my-other-face">◔.◔</span> </ascii-shrug>
<dom-module id="ascii-shrug"> <template> <div class="right-arm">¯\_</div> <div class="face"> <content select=".my-face"></content> </div> <div class="left-arm">_/¯</div> </template> <script> Polymer({ is: 'ascii-shrug' }); </script> </dom-module>

DOM API

Polymer provides a custom API for manipulating DOM. Almost all of these methods and properties have the same signatures as their standard DOM equivalents

DOM API

Declared Properties

Are the public API of your element. Having declared properties on a custom element, allows a user to configure the property from markup

Declared Properties

<ascii-hello face="◉◡◉" waving-hand="left"></ascii-hello>
Polymer({ is: 'ascii-hello', ready: function() { } });

Declared Properties

<ascii-hello face="◉◡◉" waving-hand="left"></ascii-hello>
Polymer({ is: 'ascii-hello', properties: { face: String, wavingHand: { type: String, value: 'right' } }, ready: function() { // do smth with the properties; } });

Property keys

Data Binding

binds a property or sub-property of a custom element (the host element) to a property or attribute of an element in its local DOM (the child or target element)

Data Binding

<dom-module id="ascii-host"> <template> <ascii-smiley color="{{discoColor}}"></ascii-smiley> </template> <script> Polymer({ is: 'ascii-host', properties: { discoColor: String } }); </script> </dom-module>

Data Binding Annotations

That last one was a bit...confuuusing

Put on those party glasses

▧.▨ ≧✯◡✯≦✌

We've got some explaining to do

One-way Data Binding(downward)

<ascii-smiley color="[[discoColor]]"></ascii-smiley>
<script> Polymer({ is: 'ascii-smiley', properties: { color: { type: String, notify: true } } }); </script>
<!-- changes to hosts's "discoColor" propagate to child's "color" --> <!-- changes to child's "color" are ignored by host due to [[]] -->

One-way Data Binding(downward)

<ascii-smiley color="{{discoColor}}"></ascii-smiley>
<script> Polymer({ is: 'ascii-smiley', properties: { color: { type: String, notify: false } } }); </script>
<!-- changes to hosts's "discoColor" propagate to child's "color" --> <!-- host won't be notified by changes to child's "color" due to notify:falsey -->

One-way Data Binding(upward)

<ascii-smiley color="{{discoColor}}"></ascii-smiley>
<script> Polymer({ is: 'ascii-smiley', properties: { color: { type: String, notify: true, readOnly: true } } }); </script>
<!-- changes to hosts's "discoColor" are ignored by child due to readOnly:true --> <!-- changes to child's "color" propagate to host's "discoColor" -->

Two-way Data Binding

<ascii-smiley color="{{discoColor}}"></ascii-smiley>
<script> Polymer({ is: 'ascii-smiley', properties: { color: { type: String, notify: true } } }); </script>

Binding to text content

<dom-module id="ascii-paradise"> <template> <!-- Binding to text content --> {{greeting}} from ASCII Paradise! <!-- Binding to sub-properties --> <ascii-smiley face="{{smiley.face}}" smile-size="{{smiley.smileSize}}"></ascii-smiley> </template> <script> Polymer({ is: 'ascii-paradise', properties: { greeting: String, smiley: Object } }); </script> </dom-module>

Styling

Scoped styles should be provided via <style> tags placed inside the element’s local DOM <template>

<dom-module id="ascii-hello"> <template> <style> :host { /* host styles*/ } .right-arm { /* element with class "right-arm" styles*/ } </style> <div class="right-arm"></div> <div class="head"></div> </template> ... </dom-module>

Style Modules

are used to share style declarations between elements


<!-- ascii-heart-style.html --> <dom-module id="ascii-heart-style"> <template> <style> :host { color: red; } </style> </template> </dom-module>
<!-- ascii-heart.html --> <link rel="import" href="../ascii-heart-style.html"> <dom-module id="ascii-heart"> <template> <style is="custom-style" include="ascii-heart-style"></style> </template> ... </dom-module>

<ascii-heart></ascii-heart>

<template id="heart-template"> <style> ... </style> <div id="ascii-heart"><3</div> </template> <script> // thisDoc = ascii-heart.html var thisDoc = document._currentScript.ownerDocument; // mainDoc = index.html var mainDoc = document; var proto = Object.create(HTMLElement.prototype); proto.createdCallback = function() { var shadowRoot = this.createShadowRoot(); var template = thisDoc.querySelector('#heart-template'); var clone = thisDoc.importNode(template.content, true); shadowRoot.appendChild(clone); }; mainDoc.registerElement('ascii-heart', { prototype: proto }); </script> <dom-module id="ascii-heart"> <style> ... </style> <template> <div class="ascii-heart"><3</div> </template> </dom-module> <script> Polymer({ is: 'ascii-heart' }); </script>

Thank you!

≧◠◡◠≦✌