https://slides.com/tylergraf/is-it-finally-time
<PUBLIC:COMPONENT>
<PUBLIC:ATTACH EVENT="onmouseover" ONEVENT="DoStuff()" />
<PUBLIC:ATTACH EVENT="onmouseout" ONEVENT="Restore()" />
<SCRIPT LANGUAGE="JScript">
var normalColor, normalSpacing;
function DoStuff()
{
// save original values
normalColor = runtimeStyle.color;
normalSpacing= runtimeStyle.letterSpacing;
runtimeStyle.color = "red";
runtimeStyle.letterSpacing = 2;
}
function Restore()
{
// restore original values
runtimeStyle.color = normalColor;
runtimeStyle.letterSpacing = normalSpacing;
}
</SCRIPT>
</PUBLIC:COMPONENT>
Open Sourced
<binding id="slideshow">
<content>
<xul:vbox flex="1">
<xul:deck xbl:inherits="selectedIndex" selectedIndex="0" flex="1">
<children/>
</xul:deck>
<xul:hbox>
<xul:button xbl:inherits="label=previoustext"
oncommand="parentNode.parentNode.parentNode.page--;"/>
<xul:description flex="1"/>
<xul:button xbl:inherits="label=nexttext"
oncommand="parentNode.parentNode.parentNode.page++;"/>
</xul:hbox>
</xul:vbox>
</content>
<implementation>
<constructor>
var totalpages=this.childNodes.length;
document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1]
.setAttribute("value",(this.page+1)+" of "+totalpages);
</constructor>
<property name="page"
onget="return parseInt(document.getAnonymousNodes(this)[0].childNodes[0].getAttribute('selectedIndex'));"
onset="return this.setPage(val);"/>
<method name="setPage">
<parameter name="newidx"/>
<body>
<![CDATA[
var thedeck=document.getAnonymousNodes(this)[0].childNodes[0];
var totalpages=this.childNodes.length;
if (newidx<0) return 0;
if (newidx>=totalpages) return totalpages;
thedeck.setAttribute("selectedIndex",newidx);
document.getAnonymousNodes(this)[0].childNodes[1].childNodes[1]
.setAttribute("value",(newidx+1)+" of "+totalpages);
return newidx;
]]>
</body>
</method>
</implementation>
</binding>
any lib (jquery) - doesn't look like a component
their proposal - looks like a component
custom elements v1
Classes
Traits & Interfaces
Traceur (transpiler)
Deferreds (Promises)
async/await
Object.observe()
TC39 "Stages" model
CSS Variables
CSS Mixins
Hierarchal CSS
CSS OM
Shadow Styling
Web Animations
Polyfills
<template id="party">
<h1>Party Hard</h1>
<img src="giphy.gif" alt="Party Hard">
</template>
let partyTemplate = document.createElement('template');
partyTemplate.innerHTML = `
<h1>Party Hard</h1>
<img src="giphy.gif" alt="Party Hard">
`;
let clone = document.importNode(partyTemplate.content,true);
document.body.appendChild(clone);
in HTML
in JS
Stamping
class FSPerson extends HTMLElement {
static get observedAttributes(){
return ['name','gender'];
}
connectedCallback(){
// called when added to DOM
}
attributeChangedCallback(name, oldValue, newValue){
// called when an observed attribute changes
}
disconnectedCallback(){
// called when removed from DOM
}
}
window.customElements.define('fs-person', FSPerson);
<fs-person name="Tyler" gender="male"></fs-person>
const shadowRoot = header.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<h1>Hello Shadow DOM</h1>
`;
<link rel="import" href="./fs-person.html">
<link rel="import" href="./fs-person.html">
<fs-person name="Tyler" gender="male"></fs-person>
<fs-person name="Lindsey" gender="female"></fs-person>
<template>
<style>
:host {
display: block;
}
.gender {
display: inline-block;
height: 10px;
width: 10px;
background: #000;
}
.male {
background: blue;
}
.female {
background: pink;
}
</style>
<span class="gender"></span>
<span id="name"></span>
</template>
<script>
let fsPersonTemplate = document.currentScript.ownerDocument.querySelector('template');
class FSPerson extends HTMLElement {
static get observedAttributes(){
return ['name','gender'];
}
constructor(){
super();
this.attachShadow({mode: 'open'});
let clone = document.importNode(fsPersonTemplate.content, true);
this.shadowRoot.appendChild(clone);
}
attributeChangedCallback(attr, oldValue, newValue){
if(attr === 'name'){
this.shadowRoot.querySelector('#name').textContent = newValue;
}
if(attr === 'gender'){
let gender = this.shadowRoot.querySelector('.gender');
gender.classList.remove('female','male')
gender.classList.add(newValue);
}
}
}
window.customElements.define('fs-person', FSPerson);
</script>
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="fs-person">
<template>
<style>
:host {
display: block;
}
.gender {
display: inline-block;
height: 10px;
width: 10px;
background: #000;
}
.male {
background: blue;
}
.female {
background: pink;
}
</style>
<span class$="gender [[gender]]"></span>
<span id="name">[[name]]</span>
</template>
<script>
(function () {
Polymer({
is: 'fs-person',
properties: {
name: {
type: String
},
gender: {
type: String,
value: 'male'
}
},
attached: function () {
//called when added to DOM
},
detached: function() {
//called when removed from DOM
}
});
})();
</script>
</dom-module>
<template is="dom-if" if="[[hasGender]]">
<span>I'm a [[gender]]</span>
</template>
<template is="dom-repeat" items="[[people]]">
<fs-person name="[[item.name]]"></fs-person>
</template>
Repeat
if
<h3 data-test$="person-header">People</h3>
<fs-person name="Sam"></fs-person>
properties and attributes
<input value="{{nameValue::input}}">
double data bindings
Polymer({
is: 'fs-person',
properties: {
name: {
type: String,
notify: true
},
gender: {
type: String,
reflectToAttrubute: true,
value: 'male'
}
}
});
Polymer({
observers: [
'_nameObserver(name, gender)'
],
_nameObserver: function(name, gender){
// do stuff when both name and gender change
}
});
Observers
Keeps properties and attributes in sync
class FSPerson extends HTMLElement {
static get observedAttributes(){return ['name','gender']}
attributeChangedCallback(name, old, val){
if(name){
this._name = val;
this._changeNameInTemplate(val);
}
}
}
Native
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<dom-module id="fs-person">
<template>
<style>
:host {
display: block;
}
.gender {
display: inline-block;
height: 10px;
width: 10px;
background: #000;
}
.male {
background: blue;
}
.female {
background: pink;
}
</style>
<span class$="gender [[gender]]"></span>
<span id="name">[[name]]</span>
</template>
<script>
class FSPerson extends Polymer.Element {
static get is() {return 'fs-person'}
static get properties() {
return {
name: {
type: String
},
gender: {
type: String,
value: 'male'
}
}
}
connectedCallback(){
// called when added from DOM
}
disconnectedCallback(){
// called when removed from DOM
}
};
window.customElements.define('fs-person', FSPerson);
</script>
</dom-module>
import {PolymerElement, html} from '../node_modules/@polymer/polymer/polymer-element.js'
class FSPerson extends PolymerElement {
static get template() {
return html`
<style>
:host {
display: block;
}
.gender {
display: inline-block;
height: 10px;
width: 10px;
background: #000;
}
.male {
background: blue;
}
.female {
background: pink;
}
</style>
<span class$="gender [[gender]]"></span>
<span id="name">[[name]]</span>
`;
}
static get is() {return 'fs-person'}
static get properties() {
return {
name: {
type: String
},
gender: {
type: String,
value: 'male'
}
}
}
connectedCallback(){
// called when added from DOM
}
disconnectedCallback(){
// called when removed from DOM
}
}
window.customElements.define('fs-person', FSPerson);
import {LitElement, html} from '../node_modules/@polymer/lit-element/lit-element.js'
class FSPerson extends LitElement {
render() {
return html`
<style>
:host {
display: block;
}
.gender {
display: inline-block;
height: 10px;
width: 10px;
background: #000;
}
.male {
background: blue;
}
.female {
background: pink;
}
</style>
<span class="gender ${this.gender}"></span>
<span id="name">${this.name}</span>
`;
}
static get properties() {
return {
name: {
type: String
},
gender: {
type: String
}
}
}
}
window.customElements.define('fs-person', FSPerson);