2. Horacio Gonzalez
Spaniard lost in Brittany, Java developer,
dreamer and all-around geek
• Senior Software Engineer at Crédit Mutuel Arkea
o Currently...
• Leader of the FinistJUG and the
BreizhBeans community
http://lostinbrittany.org/
+Horacio.Gonzalez
@LostInBrittany
5. At the beginning we had the thick client
• Widget : basic building blocks of your UI
o
Encapsultation
o
Reutilisation
In thick client you create your UI by widget assembling
Image : Wikipedia
6. Web development was unlike thick-client
• HTML/CSS/JS didn't support widgets
o
Page where the building blocks
Web apps were page oriented
Image : IBM
7. GWT gave back widgets to web devs
• GWT uses a thick-client-like development paradigm
o
Widgets, properties, events
GWT web apps are widget oriented :
Single-page apps
Image : GWT Mail sample app
8. Single-page apps are a current trend
• From UX POV single-page apps are richer
o
But making them without widgets is painful
HTML/CSS/JS needed a widget standard
Image : Ken Schultz comedy juggler
10. Web Components : a W3C standard
• Web Components standard is being worked at W3C
o
We all know what this means
o
Clue : HTML5
They will work for years, bickering and fighting
Browsers and devs will use the WiP document
11. Example : the Google+ button
• If you want to place a Google+ button in your page
<!-- Place this tag where you want the +1 button to render. -->
<div class="g-plusone" data-annotation="inline" data-width="300"></div>
<!-- Place this tag after the last +1 button tag. -->
<script type="text/javascript">
(function() {
var po = document.createElement('script');
po.type = 'text/javascript';
po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(po, s);
})();
</script>
12. Example : the Google+ button
• And what I would like is simple
<g:plusone></g:plusone>
13. Example : the Google+ button
• To be fair, Google already makes it simpler
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"> </script>
...
<g:plusone></g:plusone>
• They create directives with JS to emulate components
o AngularJS approach
o Respecting the spirit of the future standard
o Working in current browsers
14. Another example : the RIB
• If you're French, you know what a RIB is
o
A banking account identification number
• To show a RIB in HTML:
o All styling, all surface control must be done elsewhere by CSS and JS
• What I would like
o A semantic tag
o With encapsulated styling and surface controlling
<div class="rib">58496 87451 00014500269 74</div>
<x-rib banque=58496 guichet=87451 compte=00014500269 cle=74> </x-rib>
15. But we already can do that!
• In most modern frameworks we can already do
components, in a way or another
o And all those ways are different!
o Using different JavaScript libraries
o Almost no component sharing between frameworks
• W3C's works aim to make a standard way
o Supported natively by all browsers
o Allowing for component reuse
16. The 5 pillars of the Web Components
• Templates
• Shadow DOM
• Custom Elements
• Decorators
• Imports
18. Templates
• A reusable model
o Contains markup intended to be used later
<template id="commentTemplate">
<div>
<img src="">
<div class="comment-text"></div>
</div>
</template>
19. Templates before <template>
• How did we do templating before
o Using display:none or hidden
o Putting it inside a script
o Type unknown to browser, it isn't interpretated
o Markup easily recovered via .innerHTML and reused
o Approach used by many template engines
<div id="commentTemplate" class="comment" hidden>
<img src="">
<div class="comment-text"></div>
</div>
<script id="commentTemplate" type="text/template">
<div class="comment">
<img src="">
<div class="comment-text"></div>
</div>
</script>
20. • Uniformising those approach with a new tag
<template id="commentTemplate">
<div>
<img src="">
<div class="comment-text"></div>
</div>
</template>
• Content inside the tag is parsed but not interpreted
o HTML not shown
o Resources are not loaded
o Scripts not executed
The <template> tag
21. Template instantiation
• Using JavaScript
<template id="commentTemplate">
<div>
<img src="">
<div class="comment-text"></div>
</div>
</template>
<script>
function addComment(imageUrl, text) {
var t = document.querySelector("#commentTemplate");
var comment = t.content.cloneNode(true);
// Populate content.
comment.querySelector('img').src = imageUrl;
comment.querySelector('.comment-text').textContent = text;
document.body.appendChild(comment);
}
</script>
23. Encapsulation
• Each component should have
o Public interface
o Private inner code
• When using a component
o You manipulate the interface only
o You don't need to know anything about inner code
o No conflict between inner code and outside code
25. Browsers already use encapsulation
• Considerer this simple slider
o How is is done inside?
o With HTML, CSS and JS!
o It has a movable element, I can recover it's position
o Why cannot see it in DOM tree?
• Browsers hide DOM sub-trees for standard components
o They have a public interface and hidden inner code
• That's Shadow DOM!
<input id="foo" type="range">
<video width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
</video>
Image: Springfield Punx
26. My name is DOM, Shadow DOM
• Shadow DOM: ability of the browser to
o
Include a DOM subtree into the rendering
o
But not into the main document DOM tree
• In Chome you can see the Shadow DOM
o By activating the option in Inspector
28. Shadow DOM is already here
• Browser use it everyday...
o For their inner needs
o Not exposed to developers
• Web Components makes Shadow DOM available
o You can use it for your own components
Image: Springfield Punx
29. Using Shadow DOM
• There is a host element
o A normal element in DOM tree
• A shadow root is associated to the host
o Using the createShadowRoot method
o The shadow root is the root of the hidden DOM tree
Image: W3C
30. Using Shadow DOM
• Quick and dirty Shadow DOM
o DOM tree only shows <div id="emptyHost"></div>
o Rendered HTML shows Not empty anymore!
o Markup in innerHTML is ugly
<div id="emptyHost"></div>
<script>
var host = document.querySelector('#emptyHost');
var root = host.createShadowRoot();
root.innerHTML = "<h1>Not empty anymore!</h4>";
</script>
31. Using Shadow DOM
• Shadow DOM with templates
<template id="commentTemplate">
<div>
<img src="">
<div class="comment-text"></div>
</div>
</template>
<script>
function addComment(imageUrl, text) { ... }
</script>
<div id="emptyHost"></div>
<script>
var host = document.querySelector('#emptyHost');
var root = host.createShadowRoot();
root.appendChild = addComment("http://lostinbrittany.org/avatar.png",
"This is a nice comment made by a nice guy");
</script>
32. • HTML elements are compositional
o You can put a button inside a table
• Shadow DOM elements need to be compositional
o Insertion points in the Shadow DOM
Separate content from presentation
<template id="commentTemplate">
<div class="comment">
<img src="">
<div class="comment-text">
<content></content>
</div>
</div>
<style> ... </style>
</template>
...
<div id="aComment">
<h1>Ceci est un commentaire</h1>
</div>
Result :
<div id="aComment">
#documentFragment
<div class="comment">
<img src="">
<div class="comment-text">
<h1>Ceci est un
commentaire</h1>
</div>
</div>
<style> ... </style>
</div>
33. • More granularity can be added :
Separate content from presentation
<template id="commentTemplate">
<div class="comment">
<div class="comment-img">
<content select="img"></content>
</div>
<div class="comment-author">
<content select="div"></content>
</div>
<div class="comment-text">
<content select="text"></content>
</div>
</div>
<style> ... </style>
</template>
...
<div id="aComment">
<div class="author">Horacio</div>
<img src="http://example.com/avatar.png"/>
<div class="text">Ceci est un commentaire</div>
</div>
Result :
<div id="aComment">
#documentFragment
<div class="comment">
<div class="comment-img">
<img src="">
</div>
<div class="comment-author">
Horacio
</div>
<div class="comment-text">
Ceci est un commentaire
</div>
</div>
<style> ... </style>
</div>
Why does it work for author?
Invitation model, first match
34. Shadow DOM et CSS
• CSS defined in the Shadow DOM remains there
• Outside styles don't affect Shadowed content
<h1>This is a title</h1>
<div id="widget">
#document-fragment
<style>
div {border: solid 1px red;}
h1 {color: blue;}
</style>
<h1>And this is widget title</h1>
<div>Widget content here</div>
</div>
This is a title
And this is widget title
Widget content here
35. Shadow DOM et CSS
• Styling the host element : @host
<template id="template">
<style>
@host {
button {
border-radius: 5px;
}
}
</style>
<content></content>
</template>
<button id="host">My Button</button>
<script>
var host = document.querySelector('#host');
var root = host.createShadowRoot();
var shadowContent =
document.querySelector("#template").content.cloneNode(true);
root.appendChild = shadowContent;
</script>
My Button
36. Shadow DOM et CSS
• Inheriting and resetting styles in Shadow DOM content
o
.resetStyleInheritance
false (default) : properties are inherited
true : inheritable properties are reset to initial
o
.applyAuthorStyles
false (default) : author styles aren't applied
true: author styles bleed into the content
• widget theming
37. Shadow DOM et CSS
• Inheritance Cheat Sheet
Image : HTML5 Rocks' Web Components 201
39. Custom elements : the <element> tag
• An element encloses template, lifecycle and behaviour
o Templates done with <template> tag
<element name="tick-tock-clock">
<template>
<style>
// Here the nice style of our nice clock
</style>
<span id="hh"></span>
<span id="sep">:</span>
<span id="mm"></span>
</template>
</element>
40. • Livecycle defined with 3 callbacks
o readyCallback: called after the element is created
o insertedCallback: called after the element is inserted into a document
o removedCallback: called after the element is removed
Custom elements : the <element> tag
<element name="tick-tock-clock">
<template> ... </template>
<script>
function aFunctionToStartTheClock() { ... }
function aFunctionToStopTheClock() { ... }
({
readyCallback: function () {
this._root = this.createShadowRoot();
this._root.appendChild(template.content.cloneNode());
if (this.parentElement) {
start.call(this);
}
},
insertedCallback: aFunctionToStartTheClock(),
removedCallback: aFunctionToStopTheClock()
});
</script>
</element>
41. • If an element extends another, instantiation with is keyword
Custom elements : instantiation
<element extends="button" name="fancy-button"> ... </element>
<button is="fancy-button">Do something fancy</button>
• If an element doesn't extends, its name becomes a custom tag
<element name="myShinyElement"> ... </element>
<myShinyElement>Do something fancy</myShinyElement>
43. • Custom elements can be loaded from external files
o
Using the link tag:
o Only <decorator> and <element> are interpreted
o The DOM of this document is available to script
o Documents are retrieved according to cross-origin policies
Polymer
<link rel="import" href="goodies.html">
45. • Provide developers a way to react to changes in DOM
Mutation Observers
// select the target node
var target = document.querySelector('#some-id');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type);
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
// later, you can stop observing
observer.disconnect();
• Replace MutationEvents
o Increased performance
46. • Observe and notify of mutations to JavaScript objects
o Properties added, updated, deleted or reconfigurated
Object.observe
function log( change ) {
console.log( "What Changed? ", change.name );
console.log( "How did it change? ", change.type );
console.log( "What is the present value? ", change.object[ change.name ] );
}
var o = {};
// Specify |o| as an observable object
Object.observe(o, function( changes ) {
changes.forEach( log );
});
o.who = "Rick";
/*
What Changed? who
How did it change? new
What is the present value? Rick
*/
• Part of ECMA 6
47. Can I use?
If not, why are you telling us all this sh*t?
49. • New Google project
o Introduced in Google I/O 2013
o New type of library for the web
o Built on top of Web Components
o Designed to leverage the evolving web platform
• What does it means ?
o Polymer is comprised of two efforts :
o A core platform to give Web Component capabilities to modern browsers
Shims for all modern browsers
Shared with Mozilla x-tag project
o A next-generation web framework built upon this core platform
Called the Polymer.
Polymer
51. • Principes:
o Everything is a component
Encapsulation is needed for a component oriented application
o Extreme pragmatism
Boilerplate is bad
Anything repetitive should be re-factored into a component
• Handled by Polymer itself or
• Added into the browser platform itself
o Salt to taste
Use as much or as little of the framework as you wish.
• You want polyfills only : load polymer-all/platform/platform.js
• You want extra bits : load polymer-all/polymer/polymer.js
o Polymer elements
Polymer
52. • Platform technologies are already functional
o You can use it to add templates, shadow DOM, custom elements and
imports to your app
• Lots of examples in the site
Polymer
53. • X-Tag is a small JavaScript library
o
created and supported by Mozilla
o
that brings Web Components capabilities
o
to all modern browsers.
• Polymer vs X-tags ?
o
Different features and approaches
o
Mozilla and Google are collaborating
o
building the shared polyfills platform
X-Tags
54. • AngularJS directives allow to create custom elements
o Similar but different to Web Components
AngularJS
angular.module('ng').directive('testElem', function () {
return {
restrict: 'A',
template: '<div class="mydirectiveclass"><h1>hello...</h1><p ng-repeat="obj
in arr">{{obj}}</p></div>',
//templateUrl: '/partials/template.html',
link: function (scope, iterStartElement, attr) {
$(".mydirectiveclass").css({'background-color' : 'yellow'});
scope.arr = ["mikhail", "is", "the", "best"];
}
};
});
o
First line declares the directive testElem
o
The element name will be test-elem
55. • AngularJS directives allow to create custom elements
o Similar but different to Web Components
AngularJS
angular.module('ng').directive('testElem', function () {
return {
restrict: 'A',
template: '<div class="mydirectiveclass"><h1>hello...</h1><p ng-repeat="obj
in arr">{{obj}}</p></div>',
//templateUrl: '/partials/template.html',
link: function (scope, iterStartElement, attr) {
$(".mydirectiveclass").css({'background-color' : 'yellow'});
scope.arr = ["mikhail", "is", "the", "best"];
}
};
});
o
Restrict defines the element scope :
o
E: a DOM element with a custom name, <my-directive>
o
A: a DOM element with custom attribute, <div my-directive="exp">
o
C: invocation via a class, <div class="my-directive: exp">
o
M: invocation via a comment,
o
<!-- directive: my-directive exp -->
56. • AngularJS directives allow to create custom elements
o Similar but different to Web Components
AngularJS
angular.module('ng').directive('testElem', function () {
return {
restrict: 'A',
template: '<div class="mydirectiveclass"><h1>hello...</h1><p ng-repeat="obj
in arr">{{obj}}</p></div>',
//templateUrl: '/partials/template.html',
link: function (scope, iterStartElement, attr) {
$(".mydirectiveclass").css({'background-color' : 'yellow'});
scope.arr = ["mikhail", "is", "the", "best"];
}
};
});
o
template: HTML string of that the element will be replaced by
o templateUrl: (optional) the template HTML inside another file
o link: the linking function
o After the template has been loaded, this function is called
to establish the AngularJS scope
any last-minute effects
• jQuery animation or other logic.
57. • Using the custom elements
AngularJS
<!doctype html>
<html>
<head>
<title>Directive Test</title>
<script type="text/javascript" src="jquery.min.js" ></script>
<script type="text/javascript" src="angular.min.js"></script>
<script type="text/javascript" src="mydirectives.js"></script>
</head>
<body ng-app>
<div test-elem></div>
</body>
</html>