Extract Polymer preview and plunk it into the root

This commit is contained in:
Ian MacLeod
2014-11-19 09:52:25 -08:00
parent 8bbcae32dc
commit 0c22343e4c
398 changed files with 1 additions and 92459 deletions

2
.gitignore vendored
View File

@@ -1,2 +0,0 @@
/*.zip
/polymer/explainer/*.~vsdx

View File

@@ -1,8 +1 @@
neoprene
========
Experimental Super Spy Stuff
![](http://www.glydeamerica.com/wp-content/uploads/2013/08/top_secret.gif)
https://gist.github.com/sjmiles/c10a0d3ee33371b18b16
Mutation-2: 01: As with 00, but eschew normative ShadowDOM.

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,56 +0,0 @@
<svg><defs>
<g id="apps"><path d="M4,8h4V4H4V8z M10,20h4v-4h-4V20z M4,20h4v-4H4V20z M4,14h4v-4H4V14z M10,14h4v-4h-4V14z M16,4v4h4V4H16z M10,8h4V4h-4V8z M16,14h4v-4h-4V14z M16,20h4v-4h-4V20z"/></g>
<g id="archive"><path d="M20.5,5.2l-1.4-1.7C18.9,3.2,18.5,3,18,3H6C5.5,3,5.1,3.2,4.8,3.5L3.5,5.2C3.2,5.6,3,6,3,6.5V19c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V6.5C21,6,20.8,5.6,20.5,5.2z M12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5z M5.1,5l0.8-1h12l0.9,1H5.1z"/></g>
<g id="check-box-outline-blank"><path d="M19,5v14L5,19V5H19 M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3L19,3z"/></g>
<g id="check-box-outline"><path d="M7.9,10.1l-1.4,1.4L11,16L21,6l-1.4-1.4L11,13.2L7.9,10.1z M19,19L5,19V5h10V3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2v-8h-2V19z"/></g>
<g id="arrow-drop-down"><polygon points="7,10 12,15 17,10 "/></g>
<g id="info-outline"><path d="M11,17h2v-6h-2V17z M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z M11,9h2V7h-2V9z"/></g>
<g id="search"><path d="M15.5,14h-0.8l-0.3-0.3c1-1.1,1.6-2.6,1.6-4.2C16,5.9,13.1,3,9.5,3C5.9,3,3,5.9,3,9.5S5.9,16,9.5,16c1.6,0,3.1-0.6,4.2-1.6l0.3,0.3v0.8l5,5l1.5-1.5L15.5,14z M9.5,14C7,14,5,12,5,9.5S7,5,9.5,5C12,5,14,7,14,9.5S12,14,9.5,14z"/></g>
<g id="arrow-back"><path d="M20,11H7.8l5.6-5.6L12,4l-8,8l8,8l1.4-1.4L7.8,13H20V11z"/></g>
<g id="schedule"><path fill-opacity="0.9" d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10c5.5,0,10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8s3.6-8,8-8c4.4,0,8,3.6,8,8S16.4,20,12,20z"/><polygon fill-opacity="0.9" points="12.5,7 11,7 11,13 16.2,16.2 17,14.9 12.5,12.2 "/></g>
<g id="close"><polygon points="19,6.4 17.6,5 12,10.6 6.4,5 5,6.4 10.6,12 5,17.6 6.4,19 12,13.4 17.6,19 19,17.6 13.4,12 "/></g>
<g id="create"><path d="M3,17.2V21h3.8L17.8,9.9l-3.8-3.8L3,17.2z M20.7,7c0.4-0.4,0.4-1,0-1.4l-2.3-2.3c-0.4-0.4-1-0.4-1.4,0l-1.8,1.8l3.8,3.8L20.7,7z"/></g>
<g id="settings"><path d="M19.4,13c0-0.3,0.1-0.6,0.1-1s0-0.7-0.1-1l2.1-1.7c0.2-0.2,0.2-0.4,0.1-0.6l-2-3.5C19.5,5.1,19.3,5,19,5.1l-2.5,1c-0.5-0.4-1.1-0.7-1.7-1l-0.4-2.6C14.5,2.2,14.2,2,14,2h-4C9.8,2,9.5,2.2,9.5,2.4L9.1,5.1C8.5,5.3,8,5.7,7.4,6.1L5,5.1C4.7,5,4.5,5.1,4.3,5.3l-2,3.5C2.2,8.9,2.3,9.2,2.5,9.4L4.6,11c0,0.3-0.1,0.6-0.1,1s0,0.7,0.1,1l-2.1,1.7c-0.2,0.2-0.2,0.4-0.1,0.6l2,3.5C4.5,18.9,4.7,19,5,18.9l2.5-1c0.5,0.4,1.1,0.7,1.7,1l0.4,2.6c0,0.2,0.2,0.4,0.5,0.4h4c0.2,0,0.5-0.2,0.5-0.4l0.4-2.6c0.6-0.3,1.2-0.6,1.7-1l2.5,1c0.2,0.1,0.5,0,0.6-0.2l2-3.5c0.1-0.2,0.1-0.5-0.1-0.6L19.4,13z M12,15.5c-1.9,0-3.5-1.6-3.5-3.5s1.6-3.5,3.5-3.5s3.5,1.6,3.5,3.5S13.9,15.5,12,15.5z"/></g>
<g id="delete"><path d="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z M19,4h-3.5l-1-1h-5l-1,1H5v2h14V4z"/></g>
<g id="menu"><path d="M3,18h18v-2H3V18z M3,13h18v-2H3V13z M3,6v2h18V6H3z"/></g>
</defs></svg>
<script>
var doc = window.import;
var cloneIcon = function(id, size) {
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
var icon = doc.querySelector(id);
if (icon) {
svg.style.pointerEvents = 'none';
svg.style.display = 'block';
svg.setAttribute('height', '100%');
svg.setAttribute('width', '100%');
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
svg.setAttribute('viewBox', '0 0 24 24');
svg.appendChild(icon.cloneNode(true));
}
return svg;
};
var icons = {
apps: cloneIcon('#apps'),
archive: cloneIcon('#archive'),
box: cloneIcon('#check-box-outline-blank'),
checked: cloneIcon('#check-box-outline'),
drop: cloneIcon('#arrow-drop-down'),
'info-outline': cloneIcon('#info-outline'),
search: cloneIcon('#search'),
back: cloneIcon('#arrow-back'),
schedule: cloneIcon('#schedule'),
create: cloneIcon('#create'),
close: cloneIcon('#close'),
delete: cloneIcon('#delete'),
schedule: cloneIcon('#schedule'),
settings: cloneIcon('#settings'),
menu: cloneIcon('#menu')
};
</script>

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -1,9 +0,0 @@
# Names should be added to this file with this pattern:
#
# For individuals:
# Name <email address>
#
# For organizations:
# Organization <fnmatch pattern>
#
Google Inc. <*@google.com>

View File

@@ -1,203 +0,0 @@
[![Build status](http://www.polymer-project.org/build/observe-js/status.png "Build status")](http://build.chromium.org/p/client.polymer/waterfall) [![Analytics](https://ga-beacon.appspot.com/UA-39334307-2/Polymer/observe-js/README)](https://github.com/igrigorik/ga-beacon)
## Learn the tech
### Why observe-js?
observe-js is a library for observing changes in JavaScript data. It exposes a high-level API and uses Object.observe if available, and otherwise performs dirty-checking. observe-js requires ECMAScript 5.
### Observable
observe-js implements a set of observers (PathObserver, ArrayObserver, ObjectObserver, CompoundObserver, ObserverTransform) which all implement the Observable interface:
```JavaScript
{
// Begins observation. Value changes will be reported by invoking |changeFn| with |opt_receiver| as
// the target, if provided. Returns the initial value of the observation.
open: function(changeFn, opt_receiver) {},
// Report any changes now (does nothing if there are no changes to report).
deliver: function() {},
// If there are changes to report, ignore them. Returns the current value of the observation.
discardChanges: function() {},
// Ends observation. Frees resources and drops references to observed objects.
close: function() {}
}
```
### PathObserver
PathObserver observes a "value-at-a-path" from a given object:
```JavaScript
var obj = { foo: { bar: 'baz' } };
var observer = new PathObserver(obj, 'foo.bar');
observer.open(function(newValue, oldValue) {
// respond to obj.foo.bar having changed value.
});
```
PathObserver will report a change whenever the value obtained by the corresponding path expression (e.g. `obj.foo.bar`) would return a different value.
PathObserver also exposes a `setValue` method which attempts to update the underlying value. Setting the value does not affect notification state (in other words, a caller sets the value but does not `discardChanges`, the `changeFn` will be notified of the change).
```JavaScript
observer.setValue('boo');
assert(obj.foo.bar == 'boo');
```
Notes:
* If the path is ever unreachable, the value is considered to be `undefined`.
* If the path is empty (e.g. `''`), it is said to be the empty path and its value is its root object.
* PathObservation respects values on the prototype chain
### ArrayObserver
ArrayObserver observes the index-positions of an Array and reports changes as the minimal set of "splices" which would have had the same effect.
```JavaScript
var arr = [0, 1, 2, 4];
var observer = new ArrayObserver(arr);
observer.open(function(splices) {
// respond to changes to the elements of arr.
splices.forEach(function(splice) {
splice.index; // index position that the change occurred.
splice.removed; // an array of values representing the sequence of elements which were removed
splice.addedCount; // the number of elements which were inserted.
});
});
```
ArrayObserver also exposes a utility function: `applySplices`. The purpose of `applySplices` is to transform a copy of an old state of an array into a copy of its current state, given the current state and the splices reported from the ArrayObserver.
```JavaScript
AraryObserver.applySplices = function(previous, current, splices) { }
```
### ObjectObserver
ObjectObserver observes the set of own-properties of an object and their values.
```JavaScript
var myObj = { id: 1, foo: 'bar' };
var observer = new ObjectObserver(myObj);
observer.open(function(added, removed, changed, getOldValueFn) {
// respond to changes to the obj.
Object.keys(added).forEach(function(property) {
property; // a property which has been been added to obj
added[property]; // its value
});
Object.keys(removed).forEach(function(property) {
property; // a property which has been been removed from obj
getOldValueFn(property); // its old value
});
Object.keys(changed).forEach(function(property) {
property; // a property on obj which has changed value.
changed[property]; // its value
getOldValueFn(property); // its old value
});
});
```
### CompoundObserver
CompoundObserver allows simultaneous observation of multiple paths and/or Observables. It reports any and all changes in to the provided `changeFn` callback.
```JavaScript
var obj = {
a: 1,
b: 2,
};
var otherObj = { c: 3 };
var observer = new CompoundObserver();
observer.addPath(obj, 'a');
observer.addObserver(new PathObserver(obj, 'b'));
observer.addPath(otherObj, 'c');
observer.open(function(newValues, oldValues) {
// Use for-in to iterte which values have changed.
for (var i in oldValues) {
console.log('The ' + i + 'th value changed from: ' + newValues[i] + ' to: ' + oldValues[i]);
}
});
```
### ObserverTransform
ObserverTransform is used to dynamically transform observed value(s).
```JavaScript
var obj = { value: 10 };
var observer = new PathObserver(obj, 'value');
function getValue(value) { return value * 2 };
function setValue(value) { return value / 2 };
var transform = new ObserverTransform(observer, getValue, setValue);
// returns 20.
transform.open(function(newValue, oldValue) {
console.log('new: ' + newValue + ', old: ' + oldValue);
});
obj.value = 20;
transform.deliver(); // 'new: 40, old: 20'
transform.setValue(4); // obj.value === 2;
```
ObserverTransform can also be used to reduce a set of observed values to a single value:
```JavaScript
var obj = { a: 1, b: 2, c: 3 };
var observer = new CompoundObserver();
observer.addPath(obj, 'a');
observer.addPath(obj, 'b');
observer.addPath(obj, 'c');
var transform = new ObserverTransform(observer, fuction(values) {
var value = 0;
for (var i = 0; i < values.length; i++)
value += values[i]
return value;
});
// returns 6.
transform.open(function(newValue, oldValue) {
console.log('new: ' + newValue + ', old: ' + oldValue);
});
obj.a = 2;
obj.c = 10;
transform.deliver(); // 'new: 14, old: 6'
```
### Path objects
A path is an ECMAScript expression consisting only of identifiers (`myVal`), member accesses (`foo.bar`) and key lookup with literal values (`arr[0]` `obj['str-value'].bar.baz`).
`Path.get('foo.bar.baz')` returns a Path object which represents the path. Path objects have the following API:
```JavaScript
{
// Returns the current of the path from the provided object. If eval() is available, a compiled getter will be
// used for better performance.
getValueFrom: function(obj) { }
// Attempts to set the value of the path from the provided object. Returns true IFF the path was reachable and
// set.
setValueFrom: function(obj, newValue) { }
}
```
Path objects are interned (e.g. `assert(Path.get('foo.bar.baz') === Path.get('foo.bar.baz'));`) and are used internally to avoid excessive parsing of path strings. Observers which take path strings as arguments will also accept Path objects.
## About delivery of changes
observe-js is intended for use in environments which implement Object.observe, but it supports use in environments which do not.
If `Object.observe` is present, and observers have changes to report, their callbacks will be invoked at the end of the current turn (microtask). In a browser environment, this is generally at the end of an event.
If `Object.observe` is absent, `Platform.performMicrotaskCheckpoint()` must be called to trigger delivery of changes. If `Object.observe` is implemented, `Platform.performMicrotaskCheckpoint()` has no effect.

View File

@@ -1,183 +0,0 @@
/*
* Copyright (c) 2014 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
*/
(function(global) {
'use strict';
function now() {
return global.performance && typeof performance.now == 'function' ?
performance.now() : Date.now();
}
function checkpoint() {
if (global.Platform &&
typeof Platform.performMicrotaskCheckpoint == 'function') {
Platform.performMicrotaskCheckpoint();
}
}
// TODO(rafaelw): Add simple Promise polyfill for IE.
var TESTING_TICKS = 400;
var TICKS_PER_FRAME = 16;
var MAX_RUNS = 50;
function Benchmark(testingTicks, ticksPerFrame, maxRuns) {
this.testingTicks = testingTicks || TESTING_TICKS;
this.ticksPerFrame = ticksPerFrame || TICKS_PER_FRAME;
this.maxRuns = maxRuns || 50;
this.average = 0;
}
Benchmark.prototype = {
// Abstract API
setup: function(variation) {},
test: function() {
throw Error('Not test function found');
},
cleanup: function() {},
runOne: function(variation) {
this.setup(variation);
var before = now();
this.test(variation);
var self = this;
return Promise.resolve().then(function() {
checkpoint();
var after = now();
self.cleanup(variation);
return after - before;
});
},
runMany: function(count, variation) {
var self = this;
return new Promise(function(fulfill) {
var total = 0;
function next(time) {
if (!count) {
fulfill(total);
return;
}
self.runOne(variation).then(function(time) {
count--;
total += time;
next();
});
}
requestAnimationFrame(next);
});
},
runVariation: function(variation, reportFn) {
var self = this;
reportFn = reportFn || function() {}
return new Promise(function(fulfill) {
self.runMany(3, variation).then(function(time) {
return time/3;
}).then(function(estimate) {
var runsPerFrame = Math.ceil(self.ticksPerFrame / estimate);
var frames = Math.ceil(self.testingTicks / self.ticksPerFrame);
var maxFrames = Math.ceil(self.maxRuns / runsPerFrame);
frames = Math.min(frames, maxFrames);
var count = 0;
var total = 0;
function next() {
if (!frames) {
self.average = total / count;
self.dispose();
fulfill(self.average);
return;
}
self.runMany(runsPerFrame, variation).then(function(time) {
frames--;
total += time;
count += runsPerFrame;
reportFn(variation, count);
next();
});
}
next();
});
});
},
run: function(variations, reportFn) {
if (!Array.isArray(variations)) {
return this.runVariation(variations, reportFn);
}
var self = this;
variations = variations.slice();
return new Promise(function(fulfill) {
var results = [];
function next() {
if (!variations.length) {
fulfill(results);
return;
}
var variation = variations.shift();
self.runVariation(variation, reportFn).then(function(time) {
results.push(time);
next();
});
}
next();
});
}
};
function all(benchmarks, variations, statusFn) {
return new Promise(function(fulfill) {
var results = [];
var current;
function next() {
current = benchmarks.shift();
if (!current) {
fulfill(results);
return;
}
function update(variation, runs) {
statusFn(current, variation, runs);
}
current.run(variations, update).then(function(time) {
results.push(time);
next();
});
}
next();
});
}
global.Benchmark = Benchmark;
global.Benchmark.all = all;
})(this);

View File

@@ -1,40 +0,0 @@
/*
* Copyright (c) 2014 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 console = {
log: print
};
var requestAnimationFrame = function(callback) {
callback();
}
recordCount = 0;
var alert = print;
function reportResults(times) {
console.log(JSON.stringify(times));
}
function reportStatus(b, variation, count) {
console.log(b.objectCount + ' objects, ' + count + ' runs.');
}
var objectCounts = [ 4000, 8000, 16000 ];
var benchmarks = [];
objectCounts.forEach(function(objectCount, i) {
benchmarks.push(
new SetupPathBenchmark('', objectCount));
});
Benchmark.all(benchmarks, 0, reportStatus).then(reportResults);

View File

@@ -1,181 +0,0 @@
<html>
<!--
Copyright (c) 2014 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
-->
<head>
<title>Observation Benchmarks</title>
<meta charset="utf-8">
<script src="../src/observe.js"></script>
<script src="chartjs/Chart.js"></script>
<script src="benchmark.js"></script>
<script src="observation_benchmark.js"></script>
<style>
* {
font-family: arial, helvetica, sans-serif;
font-weight: 400;
}
body {
margin: 0;
padding: 0;
background-color: rgba(0, 0, 0, .1);
}
</style>
</head>
<body>
<h1>Observation Benchmarks</h1>
<select id="benchmarkSelect">
<option>ObjectBenchmark</option>
<option>SetupObjectBenchmark</option>
<option>ArrayBenchmark</option>
<option>SetupArrayBenchmark</option>
<option>PathBenchmark</option>
<option>SetupPathBenchmark</option>
</select>
<select id="configSelect">
</select>
<button id="go">Run Benchmarks</button>
<span>Object Count: </span>
<input id="objectCountInput" style="width: 200px" value="4000, 8000, 16000, 32000"><br>
<span>Mutation Count: </span>
<input id="mutationCountInput" style="width: 200px" value="0, 100, 200, 400, 800, 1600"><br>
<br>
<span id="status"></span>
<section style="width: 100%">
<article>
<div style="display:inline-block; padding-bottom: 20px">
Times in ms
</div>
<div style="display:inline-block">
<canvas id="times" width="800" height="400"></canvas>
</div>
<div style="display:inline-block">
<ul id="legendList">
</ul>
</div>
</article>
</section>
<h3 style="margin-left: 440px">Object Set Size</h3>
<script>
var benchmark;
var goButton = document.getElementById('go');
var objectCountInput = document.getElementById('objectCountInput');
var mutationCountInput = document.getElementById('mutationCountInput');
var statusSpan = document.getElementById('status');
var timesCanvas = document.getElementById('times');
var benchmarkSelect = document.getElementById('benchmarkSelect');
var configSelect = document.getElementById('configSelect');
function changeBenchmark() {
benchmark = window[benchmarkSelect.value];
configSelect.textContent = '';
benchmark.configs.forEach(function(config) {
var option = document.createElement('option');
option.textContent = config;
configSelect.appendChild(option);
});
document.title = benchmarkSelect.value;
}
benchmarkSelect.addEventListener('change', changeBenchmark);
changeBenchmark();
var ul = document.getElementById('legendList');
var colors = [
[0, 0, 255],
[138,43,226],
[165,42,42],
[100,149,237],
[220,20,60],
[184,134,11]
].map(function(rgb) {
return 'rgba(' + rgb.join(',') + ',.7)';
});
goButton.addEventListener('click', function() {
goButton.disabled = true;
goButton.textContent = 'Running...';
ul.textContent = '';
var objectCounts = objectCountInput.value.split(',').map(function(val) {
return Number(val);
});
var mutationCounts = mutationCountInput.value.split(',').map(function(val) {
return Number(val);
});
mutationCounts.forEach(function(count, i) {
var li = document.createElement('li');
li.textContent = count + ' mutations.'
li.style.color = colors[i];
ul.appendChild(li);
});
var results = [];
function benchmarkComplete(times) {
timesArray = [];
var index = 0;
mutationCounts.forEach(function(mutationCount, i) {
timesArray.push([]);
objectCounts.forEach(function(objectCount, j) {
timesArray[i][j] = times[j][i];
});
});
timesCanvas.height = 400;
timesCanvas.width = 800;
timesCanvas.setAttribute('style', '');
var ctx = timesCanvas.getContext("2d");
new Chart(ctx).Line({
labels: objectCounts,
datasets: timesArray.map(function(times, i) {
return {
fillColor: 'rgba(255, 255, 255, 0)',
strokeColor: colors[i],
pointColor: colors[i],
pointStrokeColor: "#fff",
data: times
};
})
}, {
bezierCurve: false
});
goButton.disabled = false;
goButton.textContent = 'Run Benchmarks';
statusSpan.textContent = '';
}
function updateStatus(benchmark, mutationCount, count) {
statusSpan.textContent = 'Testing: ' +
benchmark.objectCount + ' objects, ' +
mutationCount + ' mutations ... ' +
count + ' runs';
}
var benchmarks = objectCounts.map(function(objectCount) {
return new benchmark(configSelect.value, objectCount);
});
Benchmark.all(benchmarks, mutationCounts, updateStatus)
.then(benchmarkComplete);
});
</script>
</body>
</html>

View File

@@ -1,357 +0,0 @@
/*
* Copyright (c) 2014 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
*/
(function(global) {
'use strict';
var createObject = ('__proto__' in {}) ?
function(obj) { return obj; } :
function(obj) {
var proto = obj.__proto__;
if (!proto)
return obj;
var newObject = Object.create(proto);
Object.getOwnPropertyNames(obj).forEach(function(name) {
Object.defineProperty(newObject, name,
Object.getOwnPropertyDescriptor(obj, name));
});
return newObject;
};
function ObservationBenchmark(objectCount) {
Benchmark.call(this);
this.objectCount = objectCount;
}
ObservationBenchmark.prototype = createObject({
__proto__: Benchmark.prototype,
setup: function() {
this.mutations = 0;
if (this.objects)
return;
this.objects = [];
this.observers = [];
this.objectIndex = 0;
while (this.objects.length < this.objectCount) {
var obj = this.newObject();
this.objects.push(obj);
var observer = this.newObserver(obj);
observer.open(this.observerCallback, this);
this.observers.push(observer);
}
},
test: function(mutationCount) {
while (mutationCount > 0) {
var obj = this.objects[this.objectIndex];
mutationCount -= this.mutateObject(obj);
this.mutations++;
this.objectIndex++;
if (this.objectIndex == this.objects.length) {
this.objectIndex = 0;
}
}
},
cleanup: function() {
if (this.mutations !== 0)
alert('Error: mutationCount == ' + this.mutationCount);
this.mutations = 0;
},
dispose: function() {
this.objects = null;
while (this.observers.length) {
this.observers.pop().close();
}
this.observers = null;
if (Observer._allObserversCount != 0) {
alert('Observers leaked');
}
},
observerCallback: function() {
this.mutations--;
}
});
function SetupObservationBenchmark(objectCount) {
Benchmark.call(this);
this.objectCount = objectCount;
}
SetupObservationBenchmark.prototype = createObject({
__proto__: Benchmark.prototype,
setup: function() {
this.mutations = 0;
this.objects = [];
this.observers = [];
while (this.objects.length < this.objectCount) {
var obj = this.newObject();
this.objects.push(obj);
}
},
test: function() {
for (var i = 0; i < this.objects.length; i++) {
var obj = this.objects[i];
var observer = this.newObserver(obj);
observer.open(this.observerCallback, this);
this.observers.push(observer);
}
},
cleanup: function() {
while (this.observers.length) {
this.observers.pop().close();
}
if (Observer._allObserversCount != 0) {
alert('Observers leaked');
}
this.objects = null;
this.observers = null;
},
dispose: function() {
}
});
function ObjectBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
this.properties = [];
for (var i = 0; i < ObjectBenchmark.propertyCount; i++) {
this.properties.push(String.fromCharCode(97 + i));
}
}
ObjectBenchmark.configs = [];
ObjectBenchmark.propertyCount = 15;
ObjectBenchmark.prototype = createObject({
__proto__: ObservationBenchmark.prototype,
newObject: function() {
var obj = {};
for (var j = 0; j < ObjectBenchmark.propertyCount; j++)
obj[this.properties[j]] = j;
return obj;
},
newObserver: function(obj) {
return new ObjectObserver(obj);
},
mutateObject: function(obj) {
var size = Math.floor(ObjectBenchmark.propertyCount / 3);
for (var i = 0; i < size; i++) {
obj[this.properties[i]]++;
}
return size;
}
});
function SetupObjectBenchmark(config, objectCount) {
SetupObservationBenchmark.call(this, objectCount);
this.properties = [];
for (var i = 0; i < ObjectBenchmark.propertyCount; i++) {
this.properties.push(String.fromCharCode(97 + i));
}
}
SetupObjectBenchmark.configs = [];
SetupObjectBenchmark.propertyCount = 15;
SetupObjectBenchmark.prototype = createObject({
__proto__: SetupObservationBenchmark.prototype,
newObject: function() {
var obj = {};
for (var j = 0; j < SetupObjectBenchmark.propertyCount; j++)
obj[this.properties[j]] = j;
return obj;
},
newObserver: function(obj) {
return new ObjectObserver(obj);
}
});
function ArrayBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
var tokens = config.split('/');
this.operation = tokens[0];
this.undo = tokens[1];
};
ArrayBenchmark.configs = ['splice', 'update', 'push/pop', 'shift/unshift'];
ArrayBenchmark.elementCount = 100;
ArrayBenchmark.prototype = createObject({
__proto__: ObservationBenchmark.prototype,
newObject: function() {
var array = [];
for (var i = 0; i < ArrayBenchmark.elementCount; i++)
array.push(i);
return array;
},
newObserver: function(array) {
return new ArrayObserver(array);
},
mutateObject: function(array) {
switch (this.operation) {
case 'update':
var mutationsMade = 0;
var size = Math.floor(ArrayBenchmark.elementCount / 10);
for (var j = 0; j < size; j++) {
array[j*size] += 1;
mutationsMade++;
}
return mutationsMade;
case 'splice':
var size = Math.floor(ArrayBenchmark.elementCount / 5);
var removed = array.splice(size, size);
Array.prototype.splice.apply(array, [size*2, 0].concat(removed));
return size * 2;
default:
var val = array[this.undo]();
array[this.operation](val + 1);
return 2;
}
}
});
function SetupArrayBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
};
SetupArrayBenchmark.configs = [];
SetupArrayBenchmark.propertyCount = 15;
SetupArrayBenchmark.prototype = createObject({
__proto__: SetupObservationBenchmark.prototype,
newObject: function() {
var array = [];
for (var i = 0; i < ArrayBenchmark.elementCount; i++)
array.push(i);
return array;
},
newObserver: function(array) {
return new ArrayObserver(array);
}
});
function PathBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
this.leaf = config === 'leaf';
this.path = Path.get('foo.bar.baz');
this.firstPathProp = Path.get(this.path[0]);
}
PathBenchmark.configs = ['leaf', 'root'];
PathBenchmark.prototype = createObject({
__proto__: ObservationBenchmark.prototype,
newPath: function(parts, value) {
var obj = {};
var ref = obj;
var prop;
for (var i = 0; i < parts.length - 1; i++) {
prop = parts[i];
ref[prop] = {};
ref = ref[prop];
}
prop = parts[parts.length - 1];
ref[prop] = value;
return obj;
},
newObject: function() {
return this.newPath(this.path, 1);
},
newObserver: function(obj) {
return new PathObserver(obj, this.path);
},
mutateObject: function(obj) {
var val = this.path.getValueFrom(obj);
if (this.leaf) {
this.path.setValueFrom(obj, val + 1);
} else {
this.firstPathProp.setValueFrom(obj, this.newPath(this.path.slice(1), val + 1));
}
return 1;
}
});
function SetupPathBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
this.path = Path.get('foo.bar.baz');
}
SetupPathBenchmark.configs = [];
SetupPathBenchmark.prototype = createObject({
__proto__: SetupObservationBenchmark.prototype,
newPath: function(parts, value) {
var obj = {};
var ref = obj;
var prop;
for (var i = 0; i < parts.length - 1; i++) {
prop = parts[i];
ref[prop] = {};
ref = ref[prop];
}
prop = parts[parts.length - 1];
ref[prop] = value;
return obj;
},
newObject: function() {
return this.newPath(this.path, 1);
},
newObserver: function(obj) {
return new PathObserver(obj, this.path);
}
});
global.ObjectBenchmark = ObjectBenchmark;
global.SetupObjectBenchmark = SetupObjectBenchmark;
global.ArrayBenchmark = ArrayBenchmark;
global.SetupArrayBenchmark = SetupArrayBenchmark;
global.PathBenchmark = PathBenchmark;
global.SetupPathBenchmark = SetupPathBenchmark;
})(this);

View File

@@ -1,21 +0,0 @@
{
"name": "observe-js",
"homepage": "https://github.com/Polymer/observe-js",
"authors": [
"The Polymer Authors"
],
"description": "A library for observing Arrays, Objects and PathValues",
"main": "src/observe.js",
"keywords": [
"Object.observe"
],
"license": "BSD",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

View File

@@ -1,4 +0,0 @@
# This file is used by gcl to get repository specific information.
CODE_REVIEW_SERVER: https://codereview.appspot.com
VIEW_VC: https://github.com/Polymer/observe-js/commit/

View File

@@ -1,32 +0,0 @@
/*
* @license
* Copyright (c) 2014 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
*/
module.exports = function(karma) {
var common = require('../../tools/test/karma-common.conf.js');
karma.set(common.mixin_common_opts(karma, {
// base path, that will be used to resolve files and exclude
basePath: '../',
// list of files / patterns to load in the browser
files: [
'node_modules/chai/chai.js',
'conf/mocha.conf.js',
'src/observe.js',
'util/array_reduction.js',
'tests/*.js'
],
// list of files to exclude
exclude: [
'tests/d8_array_fuzzer.js',
'tests/d8_planner_test.js'
],
}));
};

View File

@@ -1,15 +0,0 @@
/*
* @license
* Copyright (c) 2014 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
*/
mocha.setup({
ui:'tdd',
ignoreLeaks: true
});
var assert = chai.assert;

View File

@@ -1,63 +0,0 @@
<!--
Copyright (c) 2014 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
-->
<script src="../change_summary.js"></script>
<script src="constrain.js"></script>
<script src="persist.js"></script>
<script src="mdv-object-observe/include.js"></script>
<h1>Circles</h1>
<div data-controller="CircleController">
<template iterate>
<div style="border: 1px solid black; margin: 8px">
<table>
<tr><td>radius:</td><td><input type="number" value="{{ radius }}"></td></tr>
<tr><td>area:</td><td><input type="number" value="{{ area }}"></td></tr>
<tr><td>circumference:</td><td><input type="number" value="{{ circumference }}"></td></tr>
</table>
<button data-action="click:delete">Delete</button>
</div>
</template>
<button data-action="click:add">New</button>
</div>
<script>
function Circle(radius) {
// circumference = 2*PI*radius
constrain(this, {
radius: function() { return this.circumference / (2*Math.PI); },
circumference: function() { return 2 * Math.PI * this.radius; }
});
// area = PI*r^2'
constrain(this, {
area: function() { return Math.PI * Math.pow(this.radius, 2); },
radius: function() { return Math.sqrt(this.area / Math.PI); }
});
if (radius)
this.radius = radius;
}
function CircleController(elm) {
this.circles = elm.model = persistDB.retrieve(Circle);
}
CircleController.prototype = {
delete: function(circle) {
var index = this.circles.indexOf(circle);
this.circles.splice(index, 1);
},
add: function() {
this.circles.push(new Circle());
}
}
</script>

View File

@@ -1,29 +0,0 @@
<!--
Copyright (c) 2014 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
-->
<h1>The world's simplest constraint-solver</h1>
<script src="constrain.js"></script>
<script>
function Circle(radius) {
// circumference = 2*PI*radius
constrain(this, {
radius: function() { return this.circumference / (2*Math.PI); },
circumference: function() { return 2 * Math.PI * this.radius; }
});
// area = PI*r^2'
constrain(this, {
area: function() { return Math.PI * Math.pow(this.radius, 2); },
radius: function() { return Math.sqrt(this.area / Math.PI); }
});
if (radius)
this.radius = radius;
}
</script>

View File

@@ -1,403 +0,0 @@
/*
* Copyright (c) 2014 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
*/
(function(global) {
/* This is a very simple version of the QuickPlan algorithm for solving
* mutli-variable contraints. (http://www.cs.utk.edu/~bvz/quickplan.html)
* The implementation varies from the standard described approach in a few ways:
*
* -There is no notion of constraint heirarchy. Here, all constraints are
* considered REQUIRED.
*
* -There is no "improvement" phase where rejected constraints are added back
* in an attempt to find a "better solution"
*
* -In place of the above two, a heuristic is used to pick the "weakest"
* free constraint to remove. A function, "stayFunc" is passed to the
* Variable class and is expected to return a priority value for the variable
* 0 being highest and 1, 2, 3, etc... being lower.
*
* I suspect these variations result in there being no guarentee of choosing the
* optimal solution, but it does seem to work well for the examples I've tested.
* Note also that the DeltaBlue planner can be used in a similar pattern,
* but it only supports single variable assignment.
*
* Note also that this is hacky and thrown together. Don't expect it to work
* much at all =-).
*/
function Map() {
this.map_ = new global.Map;
this.keys_ = [];
}
Map.prototype = {
get: function(key) {
return this.map_.get(key);
},
set: function(key, value) {
if (!this.map_.has(key))
this.keys_.push(key);
return this.map_.set(key, value);
},
has: function(key) {
return this.map_.has(key);
},
delete: function(key) {
this.keys_.splice(this.keys_.indexOf(key), 1);
this.map_.delete(key);
},
keys: function() {
return this.keys_.slice();
}
}
function Variable(property, stayFunc) {
this.property = property;
this.stayFunc = stayFunc || function() {
//console.log("Warning: using default stay func");
return 0;
};
this.methods = [];
};
Variable.prototype = {
addMethod: function(method) {
this.methods.push(method);
},
removeMethod: function(method) {
this.methods.splice(this.methods.indexOf(method), 1);
},
isFree: function() {
return this.methods.length <= 1;
},
get stayPriority() {
return this.stayFunc(this.property);
}
}
function Method(opts) {
opts = opts || {};
this.name = opts.name || 'function() { ... }';
this.outputs = opts.outputs || [];
this.f = opts.f || function() {
console.log('Warning: using default execution function');
};
};
Method.prototype = {
planned_: false,
variables_: [],
set planned(planned) {
this.planned_ = planned;
if (this.planned_) {
if (this.variables_) {
// Remove this method from all variables.
this.variables_.forEach(function(variable) {
variable.removeMethod(this);
}, this);
}
this.variables_ = null;
} else {
this.variables_ = null;
// Get & add this method to all variables.
if (this.constraint && this.constraint.planner) {
this.variables_ = this.outputs.map(function(output) {
var variable = this.constraint.planner.getVariable(output);
variable.addMethod(this);
return variable;
}, this);
}
}
},
get planned() {
return this.planned_;
},
isFree: function() {
// Return true only if all variables are free.
var variables = this.variables_;
for (var i = variables.length - 1; i >= 0; i--) {
if (!variables[i].isFree())
return false;
}
return true;
},
weakerOf: function(other) {
if (!other) {
return this;
}
// Prefer a method that assigns to fewer variables.
if (this.variables_.length != other.variables_.length) {
return this.variables_.length < other.variables_.length ? this : other;
}
// Note: A weaker stay priority is a higher number.
return this.getStayPriority() >= other.getStayPriority() ? this : other;
},
getStayPriority: function() {
// This returns the strongest (lowest) stay priority of this method's
// output variables.
return retval = this.variables_.reduce(function(min, variable) {
return Math.min(min, variable.stayPriority);
}, Infinity);
},
execute: function() {
console.log(JSON.stringify(this.outputs) + ' <= ' + this.name);
this.f();
}
};
function Constraint(methods, when) {
this.methods = methods;
this.when = when;
};
Constraint.prototype = {
executionMethod_: null,
set executionMethod(executionMethod) {
this.executionMethod_ = executionMethod;
var planned = !!this.executionMethod_;
this.methods.forEach(function(method) {
method.constraint = this;
method.planned = planned;
}, this);
},
get executionMethod() {
return this.executionMethod_;
},
getWeakestFreeMethod: function() {
var methods = this.methods;
var weakest = null;
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
if (method.isFree())
weakest = method.weakerOf(weakest);
}
return weakest;
},
execute: function() {
this.executionMethod.execute();
}
};
function Planner(object) {
this.object = object;
this.properties = {};
this.priority = []
var self = this;
this.stayFunc = function(property) {
if (self.object[property] === undefined)
return Infinity;
var index = self.priority.indexOf(property);
return index >= 0 ? index : Infinity;
}
Object.observe(this.object, internalCallback);
};
Planner.prototype = {
plan_: null,
deliverChanged: function(changeRecords) {
var needsResolve = false;
changeRecords.forEach(function(change) {
var property = change.name;
if (!(property in this.properties))
return;
var index = this.priority.indexOf(property);
if (index >= 0)
this.priority.splice(this.priority.indexOf(property), 1);
this.priority.unshift(property);
needsResolve = true;
}, this);
if (!needsResolve)
return;
console.log('Resolving: ' + Object.getPrototypeOf(changeRecords[0].object).constructor.name);
Object.unobserve(this.object, internalCallback);
this.execute();
console.log('...Done: ' + JSON.stringify(this.object));
Object.observe(this.object, internalCallback);
},
addConstraint: function(methods) {
methods.forEach(function(method) {
method.outputs.forEach(function(output) {
this.properties[output] = true;
}, this);
}, this);
var constraint = new Constraint(methods);
this.constraints = this.constraints || [];
if (this.constraints.indexOf(constraint) < 0) {
this.plan_ = null;
this.constraints.push(constraint);
}
return constraint;
},
removeConstraint: function(constraint) {
var index = this.constraints.indexOf(constraint);
if (index >= 0) {
this.plan_ = null;
var removed = this.constraints.splice(index, 1)[0];
}
return constraint;
},
getVariable: function(property) {
var index = this.properties_.indexOf(property);
if (index >= 0) {
return this.variables_[index];
}
this.properties_.push(property);
var variable = new Variable(property, this.stayFunc);
this.variables_.push(variable);
return variable;
},
get plan() {
if (this.plan_) {
return this.plan_;
}
this.plan_ = [];
this.properties_ = [];
this.variables_ = [];
var unplanned = this.constraints.filter(function(constraint) {
// Note: setting executionMethod must take place after setting planner.
if (constraint.when && !constraint.when()) {
// Conditional and currenty disabled => not in use.
constraint.planner = null;
constraint.executionMethod = null;
return false;
} else {
// In use.
constraint.planner = this;
constraint.executionMethod = null;
return true;
}
}, this);
while (unplanned.length > 0) {
var method = this.chooseNextMethod(unplanned);
if (!method) {
throw "Cycle detected";
}
var nextConstraint = method.constraint;
unplanned.splice(unplanned.indexOf(nextConstraint), 1);
this.plan_.unshift(nextConstraint);
nextConstraint.executionMethod = method;
}
return this.plan_;
},
chooseNextMethod: function(constraints) {
var weakest = null;
for (var i = 0; i < constraints.length; i++) {
var current = constraints[i].getWeakestFreeMethod();
weakest = current ? current.weakerOf(weakest) : weakest;
}
return weakest;
},
run: function() {
this.execute();
},
execute: function() {
this.plan_ = null;
this.executing = true;
this.plan.forEach(function(constraint) {
constraint.execute();
});
this.executing = false;
}
}
var planners = new WeakMap;
function internalCallback(changeRecords) {
var changeMap = new Map;
changeRecords.forEach(function(change) {
if (!planners.has(change.object))
return;
var changes = changeMap.get(change.object);
if (!changes) {
changeMap.set(change.object, [change]);
return;
}
changes.push(change);
});
changeMap.keys().forEach(function(object) {
planners.get(object).deliverChanged(changeMap.get(object));
});
}
// Register callback to assign delivery order.
var register = {};
Object.observe(register, internalCallback);
Object.unobserve(register, internalCallback);
global.constrain = function(obj, methodFunctions) {
var planner = planners.get(obj);
if (!planner) {
planner = new Planner(obj);
planners.set(obj, planner);
}
planner.addConstraint(Object.keys(methodFunctions).map(function(property) {
var func = methodFunctions[property];
return new Method({
name: func.toString(),
outputs: [ property ],
f: function() { obj[property] = func.apply(obj); }
});
}));
}
})(this);

View File

@@ -1,13 +0,0 @@
<!--
Copyright (c) 2014 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
-->
<h1>The worlds simplest persistence system</h1>
<script src="../change_summary.js"></script>
<script src="persist.js"></script>

View File

@@ -1,246 +0,0 @@
/*
* Copyright (c) 2014 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
*/
(function(global) {
function Set() {
this.set_ = new global.Set;
this.keys_ = [];
}
Set.prototype = {
add: function(key) {
if (!this.set_.has(key))
this.keys_.push(key);
return this.set_.add(key);
},
has: function(key) {
return this.set_.has(key);
},
delete: function(key) {
this.keys_.splice(this.keys_.indexOf(key), 1);
this.set_.delete(key);
},
keys: function() {
return this.keys_.slice();
}
}
var dbName = 'PersistObserved';
var version;
var db;
var storeNames = {};
function constructorName(objOrFunction) {
if (typeof objOrFunction == 'function')
return objOrFunction.name;
else
return Object.getPrototypeOf(objOrFunction).constructor.name;
}
function getKeyPath(constructor) {
return constructor.keyPath || 'id';
}
function onerror(e) {
console.log('Error: ' + e);
};
var postOpen = [];
function openDB() {
var request = webkitIndexedDB.open(dbName);
request.onerror = onerror;
request.onsuccess = function(e) {
db = e.target.result;
version = db.version || 0;
for (var i = 0; i < db.objectStoreNames.length; i++)
storeNames[db.objectStoreNames.item(i)] = true;
postOpen.forEach(function(action) {
action();
});
};
}
function handleChanged(changeRecords) {
changeRecords.forEach(function(change) {
persist(change.object);
});
}
var observer = new ChangeSummary(function(summaries) {
storeChanges = {};
function getChange(obj) {
var change = storeChanges[constructorName(obj)];
if (change)
return change;
change = {
keyPath: getKeyPath(obj),
needsAdd: new Set,
needsSave: new Set,
needsDelete: new Set
};
storeChanges[storeName] = change;
return change;
}
summaries.forEach(function(summary) {
if (!Array.isArray(summary.object)) {
getChange(summary.object).needsSave.add(summary.object);
return;
}
summary.arraySplices.forEach(function(splice) {
for (var i = 0; i < splice.removed.length; i++) {
var obj = splice.removed[i];
var change = getChange(obj);
if (change.needsAdd.has(obj))
change.needsAdd.delete(obj);
else
change.needsDelete.add(obj);
}
for (var i = splice.index; i < splice.index + splice.addedCount; i++) {
var obj = summary.object[i];
var change = getChange(obj);
if (change.needsDelete.has(obj))
change.needsDelete.delete(obj);
else
change.needsAdd.add(obj);
}
});
});
var storeNames = Object.keys(storeChanges);
console.log('Persisting: ' + JSON.stringify(storeNames));
var trans = db.transaction(storeNames, "readwrite");
trans.onerror = onerror;
trans.oncomplete = function() {
console.log('...complete');
}
storeNames.forEach(function(storeName) {
var change = storeChanges[storeName];
var store = trans.objectStore(storeName);
change.needsDelete.keys().forEach(function(obj) {
var request = store.delete(obj[change.keyPath]);
request.onerror = onerror;
request.onsuccess = function(e) {
console.log(' deleted: ' + JSON.stringify(obj));
delete obj[keyPath];
observer.unobserve(obj);
if (change.needsSave.has(obj))
change.needsSave.delete(obj);
};
});
change.needsSave.keys().forEach(function(obj) {
var request = store.put(obj);
request.onerror = onerror;
request.onsuccess = function(e) {
console.log(' saved: ' + JSON.stringify(obj));
};
});
change.needsAdd.keys().forEach(function(obj) {
obj[keyPath] = ++maxIds[storeName];
var request = store.put(obj);
request.onerror = onerror;
request.onsuccess = function(e) {
console.log(' created: ' + JSON.stringify(obj));
observer.observe(obj);
};
});
});
});
var maxIds = {};
global.persistDB = {};
global.persistDB.retrieve = function(constructor) {
var results = [];
var instance = new constructor();
keyPath = constructor.keyPath || 'id';
storeName = constructor.name;
maxIds[storeName] = maxIds[storeName] || 0;
function doRetrieve() {
console.log("Retrieving: " + storeName);
var trans = db.transaction([storeName]);
var store = trans.objectStore(storeName);
var keyRange = webkitIDBKeyRange.lowerBound(0);
var request = store.openCursor(keyRange);
request.onerror = onerror;
request.onsuccess = function(e) {
var result = e.target.result;
if (!!result == false) {
observer.observePropertySet(results);
console.log('...complete');
return;
}
var object = result.value;
maxIds[storeName] = Math.max(maxIds[storeName], object[keyPath]);
object.__proto__ = instance;
constructor.apply(object);
results.push(object);
observer.observe(object);
console.log(' => ' + JSON.stringify(object));
result.continue();
};
}
function createStore() {
console.log('Creating store: ' + storeName);
version++;
var request = db.setVersion(version);
request.onerror = onerror;
request.onsuccess = function(e) {
var store = db.createObjectStore(storeName, { keyPath: keyPath });
storeNames[storeName] = true;
e.target.transaction.oncomplete = doRetrieve;
};
}
var action = function() {
if (storeName in storeNames)
doRetrieve()
else
createStore();
}
if (db)
action();
else
postOpen.push(action);
return results;
};
openDB();
})(this);

View File

@@ -1,32 +0,0 @@
/*
* Copyright (c) 2014 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
*/
module.exports = function(grunt) {
grunt.initConfig({
karma: {
options: {
configFile: 'conf/karma.conf.js',
keepalive: true
},
buildbot: {
reporters: ['crbot'],
logLevel: 'OFF'
},
'observe-js': {
}
}
});
grunt.loadTasks('../tools/tasks');
grunt.loadNpmTasks('grunt-karma');
grunt.registerTask('default', 'test');
grunt.registerTask('test', ['override-chrome-launcher', 'karma:observe-js']);
grunt.registerTask('test-buildbot', ['override-chrome-launcher', 'karma:buildbot']);
};

View File

@@ -1,73 +0,0 @@
<!--
@license
Copyright (c) 2014 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
-->
<!doctype html>
<html>
<head>
<title>polymer api</title>
<style>
html, body {
font-family: Arial, sans-serif;
white-space: nowrap;
overflow: hidden;
}
[noviewer] [ifnoviewer] {
display: block;
}
[detector], [ifnoviewer], [noviewer] [ifviewer] {
display: none;
}
[ifviewer], [ifnoviewer] {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
iframe {
border: none;
margin: 0;
width: 100%;
height: 100%;
}
#remote {
position: absolute;
top: 0;
right: 0;
}
</style>
<script src="../webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="../polymer-home-page/polymer-home-page.html">
</head>
<body>
<img detector src="../polymer-home-page/bowager-logo.png" onerror="noviewer()">
<polymer-home-page ifviewer></polymer-home-page>
<div ifnoviewer>
<span id="remote">[remote]</span>
<iframe></iframe>
</div>
<!-- -->
<script>
var remoteDocs = 'http://turbogadgetry.com/bowertopia/components/';
// if no local info viewer, load it remotely
function noviewer() {
document.body.setAttribute('noviewer', '');
var path = location.pathname.split('/');
var module = path.pop() || path.pop();
document.querySelector('iframe').src = remoteDocs + module;
document.querySelector('title').textContent = module;
}
// for testing only
var opts = window.location.search;
if (opts.indexOf('noviewer') >= 0) {
noviewer();
}
</script>
</body>
</html>

View File

@@ -1,33 +0,0 @@
{
"name": "observe-js",
"version": "0.4.2",
"description": "observe-js is a library for observing changes on JavaScript objects/arrays",
"main": "src/observe.js",
"directories": {
"example": "examples",
"test": "tests"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/Polymer/observe-js.git"
},
"author": "The Polymer Authors",
"license": "BSD",
"readmeFilename": "README.md",
"devDependencies": {
"chai": "*",
"mocha": "*",
"grunt": "*",
"grunt-karma": "*",
"karma": "~0.12.0",
"karma-mocha": "*",
"karma-firefox-launcher": "*",
"karma-ie-launcher": "*",
"karma-safari-launcher": "*",
"karma-script-launcher": "*",
"karma-crbot-reporter": "*"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,134 +0,0 @@
/*
* Copyright (c) 2014 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
*/
(function(global) {
function ArrayFuzzer() {}
ArrayFuzzer.valMax = 16;
ArrayFuzzer.arrayLengthMax = 128;
ArrayFuzzer.operationCount = 64;
function randDouble(start, end) {
return Math.random()*(end-start) + start;
}
function randInt(start, end) {
return Math.round(randDouble(start, end));
}
function randASCIIChar() {
return String.fromCharCode(randInt(32, 126));
}
function randValue() {
switch(randInt(0, 5)) {
case 0:
return {};
case 1:
return undefined;
case 2:
return null;
case 3:
return randInt(0, ArrayFuzzer.valMax);
case 4:
return randDouble(0, ArrayFuzzer.valMax);
case 5:
return randASCIIChar();
}
}
function randArray() {
var args = [];
var count = randInt(0, ArrayFuzzer.arrayLengthMax);
while(count-- > 0)
args.push(randValue());
return args;
}
function randomArrayOperation(arr) {
function empty() {
return [];
}
var operations = {
push: randArray,
unshift: randArray,
pop: empty,
shift: empty,
splice: function() {
var args = [];
args.push(randInt(-arr.length*2, arr.length*2), randInt(0, arr.length*2));
args = args.concat(randArray());
return args;
}
};
// Do a splice once for each of the other operations.
var operationList = ['splice', 'update',
'splice', 'delete',
'splice', 'push',
'splice', 'pop',
'splice', 'shift',
'splice', 'unshift'];
var op = {
name: operationList[randInt(0, operationList.length - 1)]
};
switch(op.name) {
case 'delete':
op.index = randInt(0, arr.length - 1);
delete arr[op.index];
break;
case 'update':
op.index = randInt(0, arr.length);
op.value = randValue();
arr[op.index] = op.value;
break;
default:
op.args = operations[op.name]();
arr[op.name].apply(arr, op.args);
break;
}
return op;
}
function randomArrayOperations(arr, count) {
var ops = []
for (var i = 0; i < count; i++) {
ops.push(randomArrayOperation(arr));
}
return ops;
}
ArrayFuzzer.prototype.go = function() {
var orig = this.arr = randArray();
randomArrayOperations(this.arr, ArrayFuzzer.operationCount);
var copy = this.copy = this.arr.slice();
this.origCopy = this.copy.slice();
var observer = new ArrayObserver(this.arr);
observer.open(function(splices) {
ArrayObserver.applySplices(copy, orig, splices);
});
this.ops = randomArrayOperations(this.arr, ArrayFuzzer.operationCount);
observer.deliver();
observer.close();
}
global.ArrayFuzzer = ArrayFuzzer;
})(this);

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) 2014 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
*/
// Run ArrayFuzzer under d8, e.g.
// path/to/d8 change_summary.js tests/array_fuzzer.js tests/d8_array_fuzzer.js (--harmony)
function checkEqual(arr1, arr2) {
if (arr1.length != arr2.length)
throw 'Lengths not equal: ' + arr1.length + ', ' + arr2.length;
for (var i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i])
throw 'Value at i: ' + i + ' not equal: ' + arr1[i] + ', ' + arr2[i];
}
}
var t1 = new Date();
for (var i = 0; i < 2048 * 1000; i++) {
print('pass: ' + i);
var fuzzer = new ArrayFuzzer();
fuzzer.go();
try {
checkEqual(fuzzer.arr, fuzzer.copy);
} catch (ex) {
console.log('Fail: ' + ex);
console.log(JSON.stringify(fuzzer.origCopy));
console.log(JSON.stringify(fuzzer.ops));
throw ex;
}
}
var t2 = new Date();
print('Finished in: ' + (t2.getTime() - t1.getTime()) + 'ms');

View File

@@ -1,51 +0,0 @@
/*
* Copyright (c) 2014 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
*/
"use strict";
var planner;
function setup() {
planner = new Planner();
function addVariable(priority) {
return planner.addVariable(function() {
return priority;
});
}
function bind(prop1, prop2) {
var c = planner.addConstraint();
return {
constraint: c,
to: c.addMethod(prop2),
from: c.addMethod(prop1)
};
}
var count = 1000000;
var variable = addVariable(count);
while (count-- > 0) {
var newVar = addVariable(count);
bind(variable, newVar);
variable = newVar;
}
}
function run() {
var t1 = new Date();
planner.getPlan();
var t2 = new Date();
print('Finished in: ' + (t2.getTime() - t1.getTime()) + 'ms');
}
setup();
run();

View File

@@ -1,38 +0,0 @@
<!doctype html>
<html>
<!--
Copyright (c) 2014 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
-->
<head>
<title>observe-js tests</title>
<meta charset="utf-8">
<link rel="stylesheet" href="../node_modules/mocha/mocha.css">
<script src="../node_modules/chai/chai.js"></script>
<script src="../node_modules/mocha/mocha.js"></script>
<script>window.testingExposeCycleCount = true</script>
<script src="../src/observe.js"></script>
<script>
mocha.setup({
ui: 'tdd',
ignoreLeaks: true
});
var assert = chai.assert;
</script>
</head>
<body>
<script src="array_fuzzer.js"></script>
<script src="test.js"></script>
<div id="mocha"></div>
<script>
mocha.run();
</script>
</body>
</html>

View File

@@ -1,130 +0,0 @@
<!doctype html>
<html>
<!--
Copyright (c) 2014 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
-->
<head>
<title>Planner Tests</title>
<meta charset="utf-8">
<link rel="stylesheet" href="../node_modules/mocha/mocha.css">
<script src="../node_modules/chai/chai.js"></script>
<script src="../node_modules/mocha/mocha.js"></script>
<script src="../util/planner.js"></script>
<script>
mocha.setup({
ui: 'tdd',
ignoreLeaks: true
});
var assert = chai.assert;
</script>
</head>
<body>
<script>
"use strict";
suite('Planner Tests', function() {
var planner;
setup(function() {
planner = new Planner();
});
teardown(function() {
planner = undefined;
});
function addVariable(priority) {
return planner.addVariable(function() {
return priority;
});
}
function bind(prop1, prop2) {
var c = planner.addConstraint();
return {
constraint: c,
to: c.addMethod(prop2),
from: c.addMethod(prop1)
};
}
test('Linear', function() {
var a = addVariable(0);
var b = addVariable(1);
var c = addVariable(1);
var aToB = bind(a, b);
var bToC = bind(b, c);
assert.deepEqual(planner.getPlan(), [aToB.to, bToC.to]);
});
test('Linear Reverse Priority', function() {
var a = addVariable(1);
var b = addVariable(1);
var c = addVariable(0);
var aToB = bind(a, b);
var bToC = bind(b, c);
assert.deepEqual(planner.getPlan(), [bToC.from, aToB.from]);
});
test('Overconstrained', function() {
var a = addVariable(1);
var b = addVariable(1);
var c = addVariable(0);
var aToB = bind(a, b);
var bToC = bind(b, c);
var cToA = bind(c, a);
assert.isUndefined(planner.getPlan());
});
test('Remove Constraint', function() {
var a = addVariable(1);
var b = addVariable(1);
var c = addVariable(0);
var aToB = bind(a, b);
var bToC = bind(b, c);
var cToA = bind(c, a);
assert.isUndefined(planner.getPlan());
planner.removeConstraint(bToC.constraint);
assert.deepEqual(planner.getPlan(), [cToA.to, aToB.to]);
planner.removeConstraint(aToB.constraint);
assert.deepEqual(planner.getPlan(), [cToA.to]);
});
test('Stress', function() {
var count = 10000;
var variable = addVariable(count);
while (count-- > 0) {
var newVar = addVariable(count);
bind(variable, newVar);
variable = newVar;
}
console.time('Plan');
planner.getPlan();
console.timeEnd('Plan');
});
});
</script>
<div id="mocha"></div>
<script>
mocha.run();
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,309 +0,0 @@
// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
(function(global) {
"use strict";
function ArraySet() {
this.entries = [];
}
ArraySet.prototype = {
add: function(key) {
if (this.entries.indexOf(key) >= 0)
return;
this.entries.push(key);
},
delete: function(key) {
var i = this.entries.indexOf(key);
if (i < 0)
return;
this.entries.splice(i, 1);
},
first: function() {
return this.entries[0];
},
get size() {
return this.entries.length;
}
};
function UIDSet() {
this.entries = {};
this.size = 0;
}
UIDSet.prototype = {
add: function(key) {
if (this.entries[key.__UID__] !== undefined)
return;
this.entries[key.__UID__] = key;
this.size++;
},
delete: function(key) {
if (this.entries[key.__UID__] === undefined)
return;
this.entries[key.__UID__] = undefined;
this.size--;
}
};
function Heap(scoreFunction, populate) {
this.scoreFunction = scoreFunction;
this.content = populate || [];
if (this.content.length)
this.build();
}
Heap.prototype = {
get size() {
return this.content.length;
},
build: function() {
var lastNonLeaf = Math.floor(this.content.length / 2) - 1;
for (var i = lastNonLeaf; i >= 0; i--)
this.sinkDown(i);
},
push: function(element) {
this.content.push(element);
this.bubbleUp(this.content.length - 1);
},
pop: function() {
var result = this.content[0];
var end = this.content.pop();
if (this.content.length) {
this.content[0] = end;
this.sinkDown(0);
}
return result;
},
delete: function(element) {
var len = this.content.length;
for (var i = 0; i < len; i++) {
if (this.content[i] == element) {
var end = this.content.pop();
if (i != len - 1) {
this.content[i] = end;
if (this.scoreFunction(end) < this.scoreFunction(node)) this.bubbleUp(i);
else this.sinkDown(i);
}
return;
}
}
},
bubbleUp: function(n) {
var element = this.content[n];
while (n > 0) {
var parentN = Math.floor((n + 1) / 2) - 1,
parent = this.content[parentN];
if (this.scoreFunction(element) <= this.scoreFunction(parent))
break;
this.content[parentN] = element;
this.content[n] = parent;
n = parentN;
}
},
sinkDown: function(n) {
var length = this.content.length,
element = this.content[n],
elemScore = this.scoreFunction(element);
do {
var child2N = (n + 1) * 2
var child1N = child2N - 1;
var swap = null;
var swapScore = elemScore;
if (child1N < length) {
var child1 = this.content[child1N],
child1Score = this.scoreFunction(child1);
if (child1Score > elemScore) {
swap = child1N;
swapScore = child1Score;
}
}
if (child2N < length) {
var child2 = this.content[child2N],
child2Score = this.scoreFunction(child2);
if (child2Score > swapScore)
swap = child2N;
}
if (swap != null) {
this.content[n] = this.content[swap];
this.content[swap] = element;
n = swap;
}
} while (swap != null);
}
};
function Variable(stayFunc) {
this.stayFunc = stayFunc;
this.methods = new ArraySet;
};
Variable.prototype = {
freeMethod: function() {
return this.methods.first();
}
}
function Method(constraint, variable) {
this.constraint = constraint;
this.variable = variable;
};
function Constraint(planner) {
this.planner = planner;
this.methods = [];
};
Constraint.prototype = {
addMethod: function(variable) {
var method = new Method(this, variable);
this.methods.push(method);
method.__UID__ = this.planner.methodUIDCounter++;
return method;
},
reset: function() {
this.methods.forEach(function(method) {
method.variable.methods.add(method);
});
},
remove: function() {
this.methods.forEach(function(method) {
method.variable.methods.delete(method);
});
}
};
function Planner() {
this.variables = [];
this.constraints = [];
this.variableUIDCounter = 1;
this.methodUIDCounter = 1;
};
Planner.prototype = {
addVariable: function(stayFunc) {
var variable = new Variable(stayFunc);
variable.__UID__ = this.variableUIDCounter++;
this.variables.push(variable);
return variable;
},
addConstraint: function() {
var constraint = new Constraint(this);
this.constraints.push(constraint);
return constraint;
},
removeConstraint: function(constraint) {
var index = this.constraints.indexOf(constraint);
if (index < 0)
return;
constraint.remove();
this.constraints.splice(index, 1);
this.constraints.forEach(function(constraint) {
constraint.reset();
});
this.variables = this.variables.filter(function(variable) {
return variable.methods.size;
});
},
getPlan: function() {
this.variables.forEach(function(variable) {
variable.priority = variable.stayFunc();
});
this.constraints.forEach(function(constraint) {
constraint.reset();
});
var methods = [];
var free = [];
var overconstrained = new UIDSet;
this.variables.forEach(function(variable) {
var methodCount = variable.methods.size;
if (methodCount > 1)
overconstrained.add(variable);
else if (methodCount == 1)
free.push(variable);
});
free = new Heap(function(variable) {
return variable.priority;
}, free);
while (free.size) {
var lowest;
do {
lowest = free.pop();
} while (free.size && !lowest.methods.size);
if (!lowest.methods.size)
break;
var method = lowest.freeMethod();
var constraint = method.constraint;
constraint.remove();
constraint.methods.forEach(function(method) {
var variable = method.variable;
if (variable.methods.size == 1) {
overconstrained.delete(variable);
free.push(variable);
}
});
methods.push(method);
}
if (overconstrained.size)
return undefined;
return methods.reverse();
}
}
global.Planner = Planner;
})(this);

View File

@@ -1,252 +0,0 @@
<link rel="import" href="polymer/polymer.html">
<template>
<style>
:host {
display: block;
font-family: sans-serif;
font-size: 1.4em;
}
iframe {
position: absolute;
border: 0;
width: 1920px;
height: 1080px;
visibility: hidden;
xdisplay: none;
}
o, n {
display: inline-block;
xwidth: 24px;
margin: 2px;
text-align: right;
font-family: monospace;
}
o {
color: rgba(255, 0, 0, 0.5);
}
n {
display: inline-block;
color: green;
font-weight: bold;
}
</style>
<div></div>
<iframe id="frame"></iframe>
</template><script>
Polymer({
name: 'frame-tester',
base: '',
runs: 25,
published: [
'tests'
],
created: function() {
this.frame = this.$('#frame');
this.strategy = this.strategies.minimum;
this.attributeChangedCallback('runs');
this.attributeChangedCallback('base');
addEventListener('message', this.scoreMessage.bind(this));
},
attributeChangedCallback: function(name) {
var value = this.getAttribute(name);
switch(name) {
case 'runs':
this.runs = value || this.runs;
break;
case 'base':
this.base = value || this.base;
break;
case 'strategy':
this.strategy = this.strategies[strategy] || this.strategy;
break;
}
},
testsChanged: function() {
this.go();
},
shuffle: function(tests) {
var shuffled = [];
var ordered = tests.slice(0);
var count = ordered.length;
for (var i=0, j; i<count; i++) {
j = Math.floor(Math.random()*count);
// TODO(sjmiles): this is an easy but poorly randomized distribution
for (; !ordered[j]; j = (j + 1) % count);
shuffled.push(j);
ordered[j] = null;
}
return shuffled;
},
go: function() {
this.count = 0;
this.total = [];
this.times = [];
for (var i=0; i<this.tests.length; i++) {
this.total[i] = 0;
this.times[i] = [];
}
this.startRun();
},
startRun: function() {
this.shuffled = this.shuffle(this.tests);
this.index = -1;
//console.group('run', this.count);
this.nextTest();
},
nextTest: function() {
// last test in this run?
if (++this.index === this.tests.length) {
//console.groupEnd();
// report results
++this.count;
this.report();
// more runs?
if (this.count < this.runs) {
this.startRun();
} else {
// all done!
this.fire('done');
}
return;
}
// test order is randomized
this.test = this.shuffled[this.index];
this.frame.src = this.base + this.tests[this.test];
// it's possible for a test to end before the load event fires,
// so assume the frame loads immediately and start waiting
// for a result.
this.load();
},
load: function() {
// frame is loaded, measure the time, then proceed
this.measure(function(time) {
this.record(time);
this.nextTest();
});
},
measure: function(next) {
this.afterScore = next;
},
scoreMessage: function(e) {
if (this.afterScore) {
var time = e.data;
if (time.slice(-2) === 'ms') {
time = Number(time.slice(0, -2));
this.afterScore(time);
}
}
},
record: function(time) {
//console.log('index [%d], test [%d] time [%d]', this.index, this.test, time);
this.times[this.test].push(time);
this.total[this.test] += time;
},
report: function() {
var info = '<br>Runs: ' + this.count + '/' + this.runs
+ '<br><br>';
//
for (var i=0; i<this.tests.length; i++) {
var url = this.tests[i],
total = this.total[i],
times = this.times[i],
stats = this.stats(times);
//
var time = this.strategy.score(times, stats);
//
info += ''
+ ' <b>' + (time).toFixed(1) + 'ms' + '</b>'
//+ ' [stddev: ' + stats.deviation.toFixed(2) + ']'
+ ' &nbsp;&nbsp;&nbsp;<a href="' + this.base + url + '" target="_blank">' + url + '</a>'
+ '<br>'
;
//
info += '<span style="font-size: 8px">';
for (var j=0, v; v=times[j]; j++) {
var o = stats.outlier(v);
info += (o ? '<o>' : '<n>') + v.toFixed(0) + (o ? '</o>' : '</n>') + '|';
}
info += '</span>';
info += '<hr>';
}
//
this.$('div').innerHTML = info;
},
stats: function(a) {
var r = {mean: 0, variance: 0, deviation: 0}, t = a.length;
for (var m, s = 0, l = t; l--; s += a[l]);
for (m = r.mean = s / t, l = t, s = 0; l--; s += Math.pow(a[l] - m, 2));
r.outlier = this.strategy.outlier;
return r.deviation = Math.sqrt(r.variance = s / t), r;
},
//
// selectable statical strategies
//
strategies: {
// This strategy selects the minimum timing for score.
minimum: {
score: function(times, stats) {
var min = Number.MAX_VALUE;
for (var j=0, v; v=times[j]; j++) {
min = Math.min(v, min);
}
stats.score = min;
return min;
},
// called in stats context
outlier: function(value) {
return value > this.score;
}
},
// This strategy selects the mean of all times not more than one stddev
// away from the total sampling mean.
onedev: {
score: function(times, stats) {
var cleaned = [];
for (var j=0, v; v=times[j]; j++) {
if (!stats.outlier(v)) {
cleaned.push(v);
}
}
return this.stats(cleaned).mean;
},
// called in stats context
outlier: function(value) {
return Math.abs(value - this.mean) > (1 * this.deviation);
}
}
}
});
</script>

View File

@@ -1,40 +0,0 @@
// x-browser compat.
if (!window.performance) {
var start = Date.now();
// only at millisecond precision
window.performance = {now: function(){ return Date.now() - start }};
}
console.perf = function() {
if (console.timeline) {
console.timeline();
}
console.profile();
console.perf.time = performance.now();
};
console.perfEnd = function() {
if (window.WebComponents) {
// TODO(sjmiles): we need some kind of 'whenReady' or other signal
// that will work if this function is called after the event has fired
addEventListener('WebComponentsReady', function() {
console._perfEnd();
});
} else {
console._perfEnd();
}
};
console._perfEnd = function() {
// force layout
document.body.offsetWidth;
var time = performance.now() - console.perf.time;
console.profileEnd();
if (console.timeline) {
console.timelineEnd();
}
document.title = time.toFixed(1) + 'ms: ' + document.title;
if (window.top !== window) {
window.top.postMessage(time + 'ms', '*');
}
};

View File

@@ -1,126 +0,0 @@
<script>
/*
Scans a template to produce an annotation map that stores expression metadata
and information that can be used to associate that metadata with the
corresponding nodes in a template instance.
Supported annotations are:
* binding annotations in text nodes
* double-mustache expressions: {{expression}}
* double-bracket expressions: [[expression]]
* binding annotations in attributes
* attribute-bind expressions: name={{expression}} || [[expression]]
* property-bind expressions: name*={{expression}} || [[expression]]
* event annotations
* event delegation directives: on-<eventName>="expression"
Generated data-structure:
[
{
bindings: [
{
kind: ['event'|'text'|'attribute'|'property'],
mode: ['auto'|''],
name: '<name>'
value: '<expression>'
}
],
// TODO(sjmiles): confusingly, this is annotation-parent, not node-parent
parent: <reference to parent annotation>,
index: <integer index in parent's childNodes collection>
},
...
]
TODO(sjmiles): this module should produce either syntactic metadata
(e.g. double-mustache, double-bracket, star-attr), or semantic metadata
(e.g. manual-bind, auto-bind, property-bind). Right now it's half and half.
*/
Base.features.push({
findAnnotatedNode: function(root, annote) {
return !annote.parent ? root :
this.findAnnotatedNode(root, annote.parent).childNodes[annote.index];
},
parseTemplateAnnotations: function(template) {
// TODO(sjmiles): it's not a map, per se
var map = [];
this._parseTemplateNode(template.content, map);
if (map.length) {
template.map = map;
}
},
_parseTemplateNode: function(node, map) {
return node.nodeType === Node.TEXT_NODE ?
this._parseTemplateTextNode(node, map) :
this._parseTemplateElement(node, map);
},
_parseTemplateTextNode: function(node, map) {
var v = node.textContent, escape = v.slice(0, 2);
if (escape === '{{' || escape === '[[') {
var annotation = {
bindings: [{
kind: 'text',
mode: escape === '{{' ? 'auto' : '',
value: v.slice(2, -2)
}]
};
map.push(annotation);
return annotation;
}
},
_parseTemplateElement: function(node, map) {
var annotations = {
bindings: []
};
this._parseTemplateNodeAnnotations(node, annotations, map);
this._parseTemplateChildNodes(node, annotations, map);
if (annotations.bindings.length) {
map.push(annotations);
}
return annotations;
},
_parseTemplateNodeAnnotations: function(node, annotation) {
if (node.attributes) {
for (var i=0, a; (a=node.attributes[i]); i++) {
var n = a.name, v = a.value, escape = v.slice(0, 2);
if (escape === '{{' || escape === '[[') {
var kind = (n[n.length-1]) === '*' ? 'property' : 'attribute';
if (kind === 'property') {
n = n.slice(0, -1);
}
annotation.bindings.push({
kind: kind,
mode: escape === '{{' ? 'auto' : '',
name: n,
value: v.slice(2, -2)
});
} else if (n.slice(0, 3) === 'on-') {
annotation.bindings.push({
kind: 'event',
name: n.slice(3),
value: v
});
}
}
}
},
_parseTemplateChildNodes: function(root, annotations, map) {
if (root.firstChild) {
for (var i=0, node=root.firstChild; node; node=node.nextSibling, i++) {
var annotation = this._parseTemplateNode(node, map);
if (annotation) {
annotation.parent = annotations;
annotation.index = i;
}
}
}
}
});
</script>

View File

@@ -1,82 +0,0 @@
<script>
var attributes = function(node, attr$) {
attr$.split(' ').forEach(function(a) {
node.setAttribute(a, '');
});
};
Base = {
// (semi-)pluggable features for Base
features: [],
installFeatures: function() {
// simple engine to modularize features
Base.features.forEach(function(f) {
extend(Base, f);
});
delete Base.init;
delete Base.installFeatures;
},
registerCallback: function() {
// context is a prototype, not an instance
var prototype = this;
prototype._template = window.import.querySelector('template');
if (prototype._template) {
// requires annotations feature
prototype.parseTemplateAnnotations(prototype._template);
}
// make a list of names that have properties of the form <name>Changed.
// DataClient can use this list to efficiently associate *Changed
// methods with published properties.
// TODO(sjmiles): maybe remove this feature completely in favor of
// explicit annotations in the prototype.
//prototype.precomputeNotifierCandidates();
},
createdCallback: function() {
this.initFeatures();
this.createRoot();
//if (!this.deferStamp) {
this.stampTemplate();
//}
this.installAttributes();
this.created();
// requires bindings feature
this.updateBindings();
},
created: function() {
},
initFeatures: function() {
Base.features.forEach(function(f) {
f.init && f.init.call(this);
}, this);
},
//
// TODO(sjmiles): all the following should be 'features'?
//
createRoot: function(){
// TODO(sjmiles): ad hoc to switch on _template existence here
this.root = this._template ? this.createShadowRoot() : this;
},
stampTemplate: function() {
if (this._template && !this._stamped) {
this.root.appendChild(this.instanceTemplate(this._template));
this._stamped = true;
// requires bindings feature
this.marshalBindings();
// TODO(sjmiles): we don't necessarily want to do this here
//if (this.deferBindings) {
// this.updateBindings();
//}
}
},
installAttributes: function() {
if (this._attributes) {
attributes(this, this._attributes);
}
},
instanceTemplate: function(template) {
return document.importNode(template.content, true);
}
};
</script>

View File

@@ -1,147 +0,0 @@
<script>
//
// `marshalBindings` consumes template annotations to:
//
// 1. set up event delegation machinery
// 2. set up binding machinery and instance data
//
// `updateBindings` can be called to perform propagation of model data to DOM
// on demand
Base.features.push({
init: function() {
this._model = this;
this._bindings = [];
},
// instance binding data
marshalBindings: function() {
if (this._template.map) {
this._template.map.forEach(function(annotation) {
// locate instance node
var node = this.findAnnotatedNode(this.root, annotation);
// implement data-binding on the instance node
this.marshalNodeBindings(node, annotation);
}, this);
}
},
// TODO(sjmiles): most of these methods should probably be prefixed with _
marshalNodeBindings: function(node, annotation) {
for (var i=0, fn, b; b=annotation.bindings[i]; i++) {
if (b.kind === 'event') {
this.implementListener(node, b.name, b.value);
} else {
this._bindings.push({
node: node,
property: b.value,
fn: this.implementBinding(node, b.kind, b.name, b.value, b.mode)
});
}
}
},
implementListener: function(node, name, method) {
// TODO(sjmiles): perhaps implementListener should
// be factored even further (i.e. into a separate module/feature?)
// because it's conceptually separable from the details of template
// annotation processing.
var ctrlr = this;
node.addEventListener(name, function(e) {
if (ctrlr[method]) {
Polymer.log.events && console.log('[event-binding]: %s -> %s.%s', name, ctrlr.localName, method)
ctrlr[method](e, e.detail);
}
});
},
implementBinding: function(node, kind, name, property, mode) {
// TODO(sjmiles): perhaps implementBinding should
// be factored even further (i.e. into a separate module/feature?)
// because it's conceptually separable from the details of template
// annotation processing.
switch(kind) {
case 'text':
// TODO(sjmiles): baby-step toward path support
// - only text bindings
// - support exactly one dot (foo.bar)
// - generated fn binds to this, derefs path from model
// (ignores argument)
/*
if (property.indexOf('.') >= 0) {
var path = property.split('.');
var object = path[0];
var property = path[1];
// TODO(sjmiles): tortured attempt to avoid nerfing performance
// - binder does nothing until target object becomes available
// then memoizes it for all time
var work = function() {
var obj = this[object];
if (obj) {
object = obj;
work = postWork;
work();
}
}.bind(this);
var postWork = function() {
node.data = object[property];
};
var fn = function() {
work();
};
//console.log('[implementBinding]: path detected: [%s]', property);
break;
}
*/
var fn = function(value) {
node.data = value;
};
break;
case 'attribute':
var fn = function(value) {
if (typeof value === 'boolean') {
node[value ? 'setAttribute' : 'removeAttribute'](name, '');
} else {
node.setAttribute(name, value);
}
};
break;
case 'property':
// this is a fourth type of binding that utilizes shared storage to
// avoid the need to observe and propagate changes
// TODO(sjmiles): ad-hoc DataClient detection
if (node._data && (name in node._data)) {
this.publishProperty(property);
this.bindProperty(property, name, node);
return null;
}
// generic property binding
var fn = function(value) {
node[name] = value;
};
break;
}
if (mode === 'auto') {
// create an observable property
this.publishProperty(property);
// update the binding when changes are observed
this.watch(property, fn);
}
return fn;
},
updateBindings: function() {
var model = this._model;
this._bindings.forEach(function(b) {
// TODO(sjmiles): the `fn` are structured so as to be called directly
// from `watch` which supplies a `value` argument. We would instead
// compose the `fn` to include the model dereference instead of taking
// an argument.
// The conceptual propriety is unclear to me at the moment.
// Needing to encode `property` in `b` is a cost to the current method.
// Doing an extra lookup in `fn` when called from watch (or having a
// conditional to avoid doing that) would be a cost the other way.
if (b.fn) {
b.fn(model[b.property]);
}
});
}
});
</script>

View File

@@ -1,322 +0,0 @@
<script>
// TODO(sjmiles): when binding properties that are themselves bound,
// we need to do a merge, which increases the complexity considerably.
// Is there a different way to frame this problem?
// TODO(sjmiles): implement dispose
/*
* Datum wraps a concrete data value and provides:
*
* - persistent shareable reference
* - synchronous notifications on mutations (via method-traps)
*
* Multiple DataClients can refer to a single Datum instance. If any of the
* clients change the concrete value, the new value is immediately available
* to all the others (single source of truth).
*
* e.g. given
* foo.datum = datum1
* bar.datum = datum1
* then obviously:
* foo.datum.value == bar.datum.value
*
* But now foo and bar can construct accessors such that:
* foo.baz => get() { return this.datum.value };
* bar.zot => get() { return this.datum.value };
* now, less obviously:
* foo.baz === bar.zot
*
* This is the data-binding gambit.
*
* The `watch` method registers a callback function to be invoked
* synchronously on data mutations.
*
* Watch callbacks are triggered when:
* - data is changed via setValue
* - any of various Array methods are called value (when value is Array)
* - `notify` method is called directly
*
* `merge` method collapses a DataClient into this one, combining
* all watchers and referers.
*/
function Datum(value) {
this.value = value;
// we require back references so we can merge datums
// back references will require dispose pattern for GC,
// but then we already have this problem wrt watchers
// a 'referer' must be a DataClient
this.referers = [];
}
Datum.prototype = {
addReferer: function(client, name) {
// TODO(sjmiles): `client` has to be a DataClient right now, could be
// generalized.
// TODO(sjmiles): storing this data seems wrong, the Datum doesn't need
// to know these details except for merging. Perhaps we should take
// a function argument, and let the caller supply a closure with the
// necessary bookkeeping.
this.referers.push({client: client, name: name});
},
watch: function(notifier) {
if (!this.watchers) {
this.watchers = [];
}
this.watchers.push(notifier);
},
// TODO(sjmiles): use accessors?
// TODO(sjmiles): factor out Array decoration
setValue: function(value) {
var old = this.value;
if (old !== value) {
// TODO(sjmiles): experimental
if (value instanceof Array) {
//console.log('decorating Array');
// TODO(sjmiles): how costly is this?
extend(value, ArrayTrap);
// TODO(sjmiles): binding client this way is problematic
value.client = this;
}
this.value = value;
this.notify(old);
}
},
notify: function(old) {
if (this.watchers) {
var value = this.value;
this.watchers.forEach(function(w) {
w(value, old);
});
}
},
merge: function(other) {
// transfer all watchers of `other` to `this`
if (other.watchers) {
this.watchers = (this.watchers || []).concat(other.watchers);
other.watchers = null;
}
// redirect all referers of `other` to `this`
var referers = other.referers;
if (referers.length) {
referers.forEach(function(r) {
r.client._refer(r.name, this);
}, this);
other.referers = null;
}
// `other` should be free to GC at this point
}
};
ArrayTrap = Object.create(null);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(function(n) {
ArrayTrap[n] = function() {
console.log('Array.%s notify', n);
Array.prototype[n].apply(this, arguments);
this.client.notify(this);
};
});
/*
* DataClient implements a data-store whose properties can be:
*
* - shared among DataClients (aka _bound_)
* - observed for mutations
* - computed from dependent properties
*
* `Publishing` a property on a DataClient:
*
* - creates a Datum instance mapped to the property name
* - installs (as needed) get/set accessors (on the prototype) for the
* property name that reference the mapped Datum instance.
* - if a method called `<name>Changed` exists, use this
* method as a `watch` callback.
*
* A sugaring system is implemented to set up relationships at
* init-time from meta-data declarations on the instance.
*
* // `published` identifies property names to publish at init-time.
* // TODO(sjmiles): use a map to support initial values
* published: [
* 'foo',
* 'bar'
* ],
* // `watched` object maps properties to names of methods to use for `watch`
* // callbacks. Compound watches are supported.
* published: [
* foo: 'doUpdates',
* 'foo bar baz': 'otherUpdates'
* ],
* // `computed` object maps properties to faux method-invocations. The
* // right-side is parsed to construct a CompoundWatch whose notify callback
* // computes the value of the left-side.
* computed: [
* foo: 'computeFoo(bar)',
* baz: 'computeBaz(foo, zot, narg)'
* ]
*
*/
DataClient = {
published: [],
watched: {},
computed: {},
init: function() {
this._data = {};
this.publishProperties(this.published);
this.watchProperties(this.watched);
this.defineComputedProperties(this.computed);
},
publishProperties: function(properties) {
properties.forEach(this.publishProperty, this)
},
publishProperty: function(property) {
this._defineProperty(property);
// auto-watch feature
// TODO(sjmiles): consider eliminating this feature in favor
// of explicit annotation
var watchName = property + 'Changed';
/*
if (this._hasNotifier) {
if (!this._hasNotifier[property]) {
return;
}
} else {
*/
// TODO(sjmiles): either test is extremely slow
// TODO(sjmiles): slowness of this test was exaggerated by red-herring:
// some last-gen elements (x-repeater) binding *Changed methods manually
// causing double updates.
//if (!(watchName in this)) {
if (!this[watchName]) {
return;
}
//}
this.watch(property, this[watchName]);
},
precomputeNotifierCandidates: function() {
// TODO(sjmiles): implemented due to bogus results as described above
/*
this._hasNotifier = {};
// TODO(sjmiles): seems simple, fraught with performance danger
for (var n in this) {
if (n.slice(-7) === 'Changed') {
this._hasNotifier[n.slice(0, -7)] = true;
}
}
*/
},
notifyChange: function(name) {
var datum = this._data[name];
datum.notify(datum.value);
},
watch: function(name, notify) {
this._data[name].watch(notify.bind(this));
},
watchProperties: function(properties) {
for (var n in properties) {
this.compoundWatch(n.split(' '), this[properties[n]]);
}
},
defineComputedProperties: function(computed) {
for (var n in computed) {
this.defineComputedProperty(n, computed[n]);
}
},
defineComputedProperty: function(name, expression) {
this.publishProperty(name);
var parts = expression.match(/(.*)\((.*)\)/);
var method = this[parts[1]];
var args = parts[2].replace(/ /g, '').split(',');
this.compoundWatch(args, function() {
Polymer.log.watches && console.log('[defineComputedProperty]: computing [%s]', name, arguments);
this[name] = method.apply(this, arguments);
});
},
compoundWatch: function(names, notify) {
// TODO(sjmiles): needs factoring
//
// fallback to normal watch if we are not truly compound
if (names.length === 1) {
this.watch(names[0], notify);
return;
}
var debouncing = false,
data = this._data,
async = this.async.bind(this),
client = this
;
names.forEach(function(n) {
data[n].watch(function(value) {
Polymer.log.watches && console.log('[compoundWatch]: debounce [%s]', n);
if (!debouncing) {
debouncing = true;
// TODO(sjmiles): if a property in `name` is itself computed
// we fail to debounce properly.
// I don't see how we can debounce properly unless we study
// the dependency graph. :(
async(function() {
debouncing = false;
var args = [];
names.forEach(function(n) {
args.push(client[n])
});
Polymer.log.watches && console.log('[compoundWatch]: async-notify ', names, args);
notify.apply(client, args);
});
}
});
});
},
// cause this[name] and target[targetName] to refer to the same datum
// TODO(sjmiles): change call signature to (name, target[, targetName])
bindProperty: function(name, targetName, target) {
//
// TODO(sjmiles): which datum is 'old' and which is 'new' is arbitrary atm
// (one value is discarded)
//
// merge old into new
target._data[targetName].merge(this._data[name], name);
},
// TODO(sjmiles): general-purpose utility method should be implemented
// elsewhere?
async: function(method) {
var handled = false;
var handle = function() {
if (!handled) {
handled = true;
method.call(this);
}
}.bind(this);
// minimize latency by racing requests
setTimeout(handle);
requestAnimationFrame(handle);
},
_defineProperty: function(name) {
if (!(name in this._data)) {
this._refer(name, new Datum(null));
// install accessors on our prototype (if needed)
Object.getPrototypeOf(this)._defineAccessors(name);
}
},
_defineAccessors: function(name) {
if (!this.hasOwnProperty(name)) {
Object.defineProperty(this, name, {
get: function() {
return this._data[name].value;
},
set: function(value) {
this._data[name].setValue(value);
}
});
}
},
_refer: function(name, datum) {
this._data[name] = datum;
datum.addReferer(this, name);
}
};
Base.features.push(DataClient);
</script>

View File

@@ -1,38 +0,0 @@
<script>
Base.features.push({
listeners: {},
init: function() {
this.listenListeners();
},
listenListeners: function() {
for (var n in this.listeners) {
this.listen(n, this.listeners[n]);
}
},
listen: function(eventName, methodName) {
this.addEventListener(eventName, function(e) {
this[methodName](e, e.detail);
}.bind(this));
},
fire: function(type, detail, onNode, bubbles, cancelable) {
var node = onNode || this;
var detail = (detail === null || detail === undefined) ? {} : detail;
var event = new CustomEvent(type, {
bubbles: bubbles !== undefined ? bubbles : true,
cancelable: cancelable !== undefined ? cancelable : true,
detail: detail
});
node.dispatchEvent(event);
return event;
},
eventBind: function(eventName, node, targetValue, model, property) {
node.addEventListener(eventName, function(e) {
model[property] = e.target[targetValue];
Polymer.log.events && console.log('[eventBind]: %s.%s = %s',
e.target.localName, targetValue, e.target[targetValue]);
});
}
});
</script>

View File

@@ -1,4 +0,0 @@
<script>
</script>

View File

@@ -1,41 +0,0 @@
<script>
// a tiny bit of sugar for `document.currentScript.ownerDocument`
// sadly `import` is reserved, so we need another name or
// you have to refer to this value `window.import`
Object.defineProperty(window, 'import', {
enumerable: true,
configurable: true,
get: function() {
var script = document._currentScript || document.currentScript;
return script.ownerDocument;
}
});
// copy own properties from 'api' to 'prototype, with name hinting for 'super'
function extend(prototype, api) {
if (prototype && api) {
// use only own properties of 'api'
Object.getOwnPropertyNames(api).forEach(function(n) {
// acquire property descriptor
var pd = Object.getOwnPropertyDescriptor(api, n);
if (pd) {
// clone property via descriptor
Object.defineProperty(prototype, n, pd);
// cache name-of-method for 'super' engine
if (typeof pd.value == 'function') {
// hint the 'super' engine
pd.value.nom = n;
}
}
});
}
return prototype;
};
Event.prototype.keys = {
ESC_KEY: 27,
ENTER_KEY: 13
};
</script>

View File

@@ -1,278 +0,0 @@
<!--
Copyright (c) 2014 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
-->
<style shim-shadowdom>
/*******************************
Flex Layout
*******************************/
html /deep/ [layout][horizontal], html /deep/ [layout][vertical] {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
html /deep/ [layout][horizontal][inline], html /deep/ [layout][vertical][inline] {
display: -ms-inline-flexbox;
display: -webkit-inline-flex;
display: inline-flex;
}
html /deep/ [layout][horizontal] {
-ms-flex-direction: row;
-webkit-flex-direction: row;
flex-direction: row;
}
html /deep/ [layout][horizontal][reverse] {
-ms-flex-direction: row-reverse;
-webkit-flex-direction: row-reverse;
flex-direction: row-reverse;
}
html /deep/ [layout][vertical] {
-ms-flex-direction: column;
-webkit-flex-direction: column;
flex-direction: column;
}
html /deep/ [layout][vertical][reverse] {
-ms-flex-direction: column-reverse;
-webkit-flex-direction: column-reverse;
flex-direction: column-reverse;
}
html /deep/ [layout][wrap] {
-ms-flex-wrap: wrap;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
}
html /deep/ [layout][wrap-reverse] {
-ms-flex-wrap: wrap-reverse;
-webkit-flex-wrap: wrap-reverse;
flex-wrap: wrap-reverse;
}
html /deep/ [flex] {
-ms-flex: 1;
-webkit-flex: 1;
flex: 1;
}
html /deep/ [flex][auto] {
-ms-flex: 1 1 auto;
-webkit-flex: 1 1 auto;
flex: 1 1 auto;
}
html /deep/ [flex][none] {
-ms-flex: none;
-webkit-flex: none;
flex: none;
}
html /deep/ [flex][one] {
-ms-flex: 1;
-webkit-flex: 1;
flex: 1;
}
html /deep/ [flex][two] {
-ms-flex: 2;
-webkit-flex: 2;
flex: 2;
}
html /deep/ [flex][three] {
-ms-flex: 3;
-webkit-flex: 3;
flex: 3;
}
html /deep/ [flex][four] {
-ms-flex: 4;
-webkit-flex: 4;
flex: 4;
}
html /deep/ [flex][five] {
-ms-flex: 5;
-webkit-flex: 5;
flex: 5;
}
html /deep/ [flex][six] {
-ms-flex: 6;
-webkit-flex: 6;
flex: 6;
}
html /deep/ [flex][seven] {
-ms-flex: 7;
-webkit-flex: 7;
flex: 7;
}
html /deep/ [flex][eight] {
-ms-flex: 8;
-webkit-flex: 8;
flex: 8;
}
html /deep/ [flex][nine] {
-ms-flex: 9;
-webkit-flex: 9;
flex: 9;
}
html /deep/ [flex][ten] {
-ms-flex: 10;
-webkit-flex: 10;
flex: 10;
}
html /deep/ [flex][eleven] {
-ms-flex: 11;
-webkit-flex: 11;
flex: 11;
}
html /deep/ [flex][twelve] {
-ms-flex: 12;
-webkit-flex: 12;
flex: 12;
}
/* alignment in cross axis */
html /deep/ [layout][start] {
-ms-flex-align: start;
-webkit-align-items: flex-start;
align-items: flex-start;
}
html /deep/ [layout][center], html /deep/ [layout][center-center] {
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
}
html /deep/ [layout][end] {
-ms-flex-align: end;
-webkit-align-items: flex-end;
align-items: flex-end;
}
/* alignment in main axis */
html /deep/ [layout][start-justified] {
-ms-flex-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start;
}
html /deep/ [layout][center-justified], html /deep/ [layout][center-center] {
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
}
html /deep/ [layout][end-justified] {
-ms-flex-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
}
html /deep/ [layout][around-justified] {
-ms-flex-pack: around;
-webkit-justify-content: space-around;
justify-content: space-around;
}
html /deep/ [layout][justified] {
-ms-flex-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
}
/* self alignment */
html /deep/ [self-start] {
-ms-align-self: flex-start;
-webkit-align-self: flex-start;
align-self: flex-start;
}
html /deep/ [self-center] {
-ms-align-self: center;
-webkit-align-self: center;
align-self: center;
}
html /deep/ [self-end] {
-ms-align-self: flex-end;
-webkit-align-self: flex-end;
align-self: flex-end;
}
html /deep/ [self-stretch] {
-ms-align-self: stretch;
-webkit-align-self: stretch;
align-self: stretch;
}
/*******************************
Other Layout
*******************************/
html /deep/ [block] {
display: block;
}
/* ie support for hidden */
html /deep/ [hidden] {
display: none !important;
}
html /deep/ [relative] {
position: relative;
}
html /deep/ [fit] {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
body[fullbleed] {
margin: 0;
height: 100vh;
}
/*******************************
Other
*******************************/
html /deep/ [segment], html /deep/ segment {
display: block;
position: relative;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
margin: 1em 0.5em;
padding: 1em;
background-color: white;
-webkit-box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
border-radius: 5px 5px 5px 5px;
}
</style>

View File

@@ -1,26 +0,0 @@
<link rel="import" href="lang.html">
<link rel="import" href="layout.html">
<link rel="import" href="base.html">
<!-- pluggable features for Base-->
<link rel="import" href="utils.html">
<link rel="import" href="data.html">
<link rel="import" href="annotations.html">
<link rel="import" href="bindings.html">
<link rel="import" href="events.html">
<link rel="import" href="experimental.html">
<script>
Base.installFeatures();
Base.__proto__ = HTMLElement.prototype;
var Polymer = function(prototype) {
prototype.__proto__ = Base;
prototype.registerCallback();
document.registerElement(prototype.name, {prototype: prototype});
}
Polymer.log = {
};
</script>

View File

@@ -1,83 +0,0 @@
<script>
var instanceTemplate = function(template) {
return document.importNode(template.content, true);
};
var preprocessTemplate = function(template) {
var map = [];
var a = _preprocess(template.content, map);
if (a) {
a.map = map;
//console.log(a.map);
}
template.map = map;
};
var _preprocess = function(node, map) {
return node.nodeType === Node.TEXT_NODE ? preprocessTextNode(node, map) : preprocessNode(node, map);
};
var preprocessTextNode = function(node, map) {
var t = node.textContent;
if (t.slice(0, 2) === '{{' || t.slice(0, 2) === '[[') {
var annotations = Object.create(null);
annotations.name = 'text';
annotations.value = t;
map.push(annotations);
return annotations;
}
return null;
};
var preprocessNode = function(node, map) {
var annotations = Object.create(null);
parseAnnotations(node, annotations, map);
preprocessChildNodes(node, annotations, map);
return annotations;
};
var parseAnnotations = function(node, annotations, map) {
var bound = false;
if (node.attributes) {
var b$ = annotations.bindings = Object.create(null);
var e$ = annotations.events = Object.create(null);
for (var i=0, a; a=node.attributes[i]; i++) {
var n = a.name, v = a.value;
if (v.slice(0, 2) === '{{') {
b$[n] = {
raw: v,
prop: v.slice(2, -2)
};
bound = true;
}
if (n.slice(0, 3) === 'on-') {
e$[n.slice(3)] = v;
bound = true;
}
}
}
if (bound) {
map.push(annotations);
}
annotations.name = node.localName || 'template';
};
var preprocessChildNodes = function(root, annotations, map) {
if (root.firstChild) {
var c$ = annotations.children = [];
for (var i=0, node=root.firstChild; node; node=node.nextSibling, i++) {
var ann = _preprocess(node, map);
if (ann) {
ann.parent = annotations;
ann.index = i;
}
c$.push(ann);
}
}
};
var mapFind = function(root, n) {
return n.parent ? mapFind(root, n.parent).childNodes[n.index] : root;
};
</script>

View File

@@ -1,36 +0,0 @@
<script>
// a tiny bit of sugar for `document.currentScript.ownerDocument`
// sadly `import` is reserved, so we need another name or
// you have to refer to this value `window.import`
Object.defineProperty(window, 'import', {
enumerable: true,
configurable: true,
get: function() {
var script = document._currentScript || document.currentScript;
return script.ownerDocument;
}
});
// copy own properties from 'api' to 'prototype, with name hinting for 'super'
function extend(prototype, api) {
if (prototype && api) {
// use only own properties of 'api'
Object.getOwnPropertyNames(api).forEach(function(n) {
// acquire property descriptor
var pd = Object.getOwnPropertyDescriptor(api, n);
if (pd) {
// clone property via descriptor
Object.defineProperty(prototype, n, pd);
// cache name-of-method for 'super' engine
if (typeof pd.value == 'function') {
// hint the 'super' engine
pd.value.nom = n;
}
}
});
}
return prototype;
};
</script>

View File

@@ -1,14 +0,0 @@
<script>
Base.features.push({
$: function(slctr) {
return this.root.querySelector(slctr);
},
bindModel: function(model, properties) {
properties.forEach(function(p) {
this.bindProperty(p, p, model);
}, this);
}
});
</script>

View File

@@ -1 +0,0 @@
Mutation-2: 01: As with 00, but eschew normative ShadowDOM.

View File

@@ -1 +0,0 @@
node_modules

View File

@@ -1,111 +0,0 @@
#!/usr/bin/env node
/**
* @license
* Copyright (c) 2014 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 path = require('path');
var fs = require('fs');
var nopt = require('nopt');
var vulcan = require('../lib/vulcan.js');
var pkg = require('../package.json');
var help = [
'vulcanize: Concatenate a set of Web Components into one file',
'',
'Usage:',
' vulcanize [OPTIONS] <html file>*',
'',
'Options:',
' --output, -o: Output file name (defaults to vulcanized.html)',
' --verbose, -v: More verbose logging',
' --help, -h, -?: Print this message',
' --config: Read the given config file',
' --strip, -s: Remove comments and empty text nodes',
' --abspath, -p: Specify site root. Resolve paths to absolute paths based on site root',
' --csp: Extract inline scripts to a separate file (uses <output file name>.js)',
' --inline: The opposite of CSP mode, inline all assets (script and css) into the document',
' --csp --inline: Bundle all javascript (inline and external) into <output file name>.js',
' --version, -V: print version information',
' --no-strip-excludes: Keep imports excluded from inlining',
' --no-update-notifier: disable "update vulcanize" checks',
'',
'Config:',
' JSON file for additional options',
'',
' {',
' "excludes": {',
' "imports": [ "regex-to-exclude" ],',
' "styles": [ "regex-to-exclude" ],',
' "scripts": [ "regex-to-exclude" ],',
' }',
' }'
];
function printHelp() {
console.log(help.join('\n'));
process.exit(0);
}
var options = nopt(
{
'config': path,
'csp': Boolean,
'help': Boolean,
'inline': Boolean,
'output': path,
'abspath': path,
'strip': Boolean,
'verbose': Boolean,
'version': Boolean
},
{
'?': ['--help'],
'h': ['--help'],
'o': ['--output'],
'p': ['--abspath'],
's': ['--strip'],
'v': ['--verbose'],
'V': ['--version']
}
);
if (options.help || process.argv.length === 2) {
printHelp();
}
if (options.version) {
console.log('vulcanize %s', pkg.version);
process.exit(0);
}
if (options['update-notifier'] !== false) {
(function() {
try {
require('update-notifier')({
packageName: pkg.name,
packageVersion: pkg.version
}).notify();
} catch(_) {}
})();
}
var argv = options.argv.remain;
if (argv[0]) {
options.input = path.resolve(argv[0]);
}
vulcan.setOptions(options, function(err) {
if (err) {
console.error(err);
process.exit(1);
}
vulcan.processDocument();
});

View File

@@ -1,2 +0,0 @@
bower_components
vulcanized*

View File

@@ -1,12 +0,0 @@
<!--
@license
Copyright (c) 2014 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
-->
<link rel="import" href="http://example.com/foo/bar.html">
<link rel="import" href="http://example.com/foo/fizz/../bar.html">
<link rel="import" href="/foo/bar.html">

View File

@@ -1,5 +0,0 @@
{
"excludes": {
"imports": ["polymer.html$"]
}
}

View File

@@ -1,10 +0,0 @@
/*
* @license
* Copyright (c) 2014 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
*/

View File

@@ -1,15 +0,0 @@
/*
* @license
* Copyright (c) 2014 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
*/
:host([type="platform"]) { background-color: red; }
:host([type="core"]) { background-color: red; }
:host([type="elements"]) { background-color: red; }
polyfill-next-selector { content: ':host header'; }
polyfill-next-selector { content: 'I WIN'; }

View File

@@ -1,58 +0,0 @@
<!--
@license
Copyright (c) 2014 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
-->
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="sub-import/sub-import.html">
<polymer-element name="x-import">
<template>
<link rel="stylesheet" href="import-test.css" shim-shadowdom>
[Imported: <content></content>]
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 630 630" fill="#fff" width="630" height="630" flex?="{{mode !== 'cover'}}">
<rect x="0" y="0" width="630" height="630" fill="#3c790a"/>
<path d="m212 497c11 17 20 31 40 31 19 0 32-8 32-37v-201h59v202c0 61-36 89-88 89-47 0-75-25-89-54M423 492c13 21 29 36 58 36 25 0 40-12 40-29 0-20-16-27-43-39l-15-6c-43-18-71-41-71-89 0-44 34-78 87-78 38 0 65 13 84 47l-46 30c-10-18-21-25-38-25-17 0-28 11-28 25 0 18 11 25 36 36l15 6c50 22 79 44 79 93 0 53-42 82-98 82-55 0-91-26-108-60"/>
<polygon />
<path />
<polygon/>
<path />
</svg>
<ceci-definition>
{
"name": "Signal Transformer",
"thumbnail": "./thumbnail.png",
"description": "Transforms an incoming signal to a value you set and broadcasts it.",
"broadcasts": {
"transformedMessage": {
"label": "Transformed Message"
}
},
"listeners": {
"incomingMessage": {
"label": "Incoming Message",
"default" : true
}
},
"attributes": {
"message": {
"label": "Message",
"editable": "Text",
"default" : true
}
}
}
</ceci-definition>
&nbsp; &quot; entities! &quot; &lt; &gt;
<span>é</span>
</template>
<script>
Polymer('x-import');
</script>
<script type="application/fbs">
WHAT GOES HERE?
</script>
</polymer-element>

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html>
<!--
@license
Copyright (c) 2014 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
-->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vulcanizer Test</title>
<script src="bower_components/platform/platform.js"></script>
<link rel="import" href="absolutes.html">
<link rel="import" href="import-test.html" />
<link rel="stylesheet" href="empty.css">
</head>
<body>
<x-import>Hello Import!</x-import>
<y-import></y-import>
<polymer-element name="x-foo" attributes="">
<script>Polymer()</script>
</polymer-element>
<polymer-element name="x-bar" attributes="">
<script>Polymer({})</script>
</polymer-element>
<script>
console.log('&lt;hi&gt;');
</script>
</body>
</html>

View File

@@ -1,23 +0,0 @@
<!--
@license
Copyright (c) 2014 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
-->
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="y-import">
<template>
<style>
:host{
background: url(../foo.jpg);
}
</style>
<a href="mailto:azakus@users.noreply.github.com">REPORT A BUG</a>
</template>
<script>
Polymer('y-import');
</script>
</polymer-element>

View File

@@ -1,32 +0,0 @@
/**
* @license
* Copyright (c) 2014 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 JS = 'script:not([type]), script[type="text/javascript"]';
var URL_ATTR = ['href', 'src', 'action', 'style'];
module.exports = {
EOL: require('os').EOL,
ELEMENTS: 'polymer-element:not([assetpath])',
ELEMENTS_NOSCRIPT: 'polymer-element[noscript]',
ABS_URL: /(^data:)|(^http[s]?:)|(^\/)|(^mailto:)/,
REMOTE_ABS_URL: /(^http[s]?\:)|(^\/\/)/,
IMPORTS: 'link[rel="import"][href]',
URL: /url\([^)]*\)/g,
URL_ATTR: URL_ATTR,
URL_ATTR_SEL: '[' + URL_ATTR.join('],[') + ']',
URL_TEMPLATE: '{{.*}}',
JS: JS,
JS_SRC: JS.split(',').map(function(s){ return s + '[src]'; }).join(','),
JS_INLINE: JS.split(',').map(function(s) { return s + ':not([src])'; }).join(','),
CSS: 'style:not([type]), style[type="text/css"]',
// Output match is [ 'Polymer(', NAME_OF_ELEMENT OR undefined, ',', { or ) ]
POLYMER_INVOCATION: /Polymer\(([^,{]+)?(,\s*)?({|\))/,
NEOPRENE_INVOCATION: /name:\s*['"]([^'"]*)['"]/
};

View File

@@ -1,104 +0,0 @@
/**
* @license
* Copyright (c) 2014 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 fs = require('fs');
var path = require('path');
var CONSTANTS = require('./constants.js');
var ABS_URL = CONSTANTS.ABS_URL;
var REMOTE_ABS_URL = CONSTANTS.REMOTE_ABS_URL;
var DEFAULT = 'vulcanized.html';
// validate options with boolean return
function processOptions(options, callback) {
var config = {};
var excludes = {
imports: [],
scripts: [],
styles: []
};
options = options || Object.create(null);
if (options.config) {
var configBlob;
try {
// TODO(dfreedm): Make this async
configBlob = fs.readFileSync(options.config, 'utf8');
} catch(e) {
return callback('Config file not found!');
}
try {
config = JSON.parse(configBlob);
} catch(e) {
return callback('Malformed config JSON!');
}
}
options.input = options.input || config.input;
if (!options.input) {
return callback('No input file given!');
}
options.excludes = options.excludes || config.excludes;
if (options.excludes) {
var e = options.excludes;
try {
if (e.imports) {
e.imports.forEach(function(r) {
excludes.imports.push(new RegExp(r));
});
}
if (e.scripts) {
e.scripts.forEach(function(r) {
excludes.scripts.push(new RegExp(r));
});
}
if (e.styles) {
e.styles.forEach(function(r) {
excludes.styles.push(new RegExp(r));
});
}
} catch(_) {
return callback('Malformed import exclude config');
}
}
options.output = options.output || config.output;
if (!options.output) {
options.output = path.resolve(path.dirname(options.input), DEFAULT);
}
options.outputDir = path.dirname(options.output);
options.csp = options.csp || config.csp;
if (options.csp) {
options.csp = options.output.replace(/\.html$/, '.js');
}
options.abspath = options.abspath || config.abspath;
if (options.abspath) {
options.abspath = path.resolve(options.abspath);
excludes.imports.push(REMOTE_ABS_URL);
excludes.scripts.push(REMOTE_ABS_URL);
excludes.styles.push(REMOTE_ABS_URL);
} else {
excludes.imports.push(ABS_URL);
excludes.scripts.push(ABS_URL);
excludes.styles.push(ABS_URL);
}
options.excludes = excludes;
options.keepExcludes = options['strip-excludes'] === false || config['strip-excludes'] === false;
callback(null, options);
}
exports.processOptions = processOptions;

View File

@@ -1,84 +0,0 @@
/**
* @license
* Copyright (c) 2014 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 path = require('path');
var constants = require('./constants.js');
var utils = require('./utils.js');
var setTextContent = utils.setTextContent;
var getTextContent = utils.getTextContent;
function resolvePaths($, input, output, abspath) {
var assetPath;
if (abspath) {
assetPath = rebasePath(input, abspath);
} else {
assetPath = path.relative(output, input);
}
// make sure assetpath is a folder, but not root!
if (assetPath) {
assetPath = utils.unixPath(assetPath) + '/';
}
// resolve attributes
$(constants.URL_ATTR_SEL).each(function() {
var el = $(this);
constants.URL_ATTR.forEach(function(a) {
var val = el.attr(a);
if (val) {
if (val.search(constants.URL_TEMPLATE) < 0) {
if (a === 'style') {
el.attr(a, rewriteURL(input, output, val, abspath));
} else {
el.attr(a, rewriteRelPath(input, output, val, abspath));
}
}
}
});
});
$(constants.CSS).each(function() {
var el = $(this);
var text = rewriteURL(input, output, getTextContent(el), abspath);
setTextContent(el, text);
});
$(constants.ELEMENTS).each(function() {
$(this).attr('assetpath', assetPath);
});
}
function rebasePath(absolutePath, baselinePath) {
var absBase = new RegExp('^' + utils.escapeForRegExp(baselinePath));
return absolutePath.replace(absBase, '');
}
function rewriteRelPath(inputPath, outputPath, rel, abspath) {
if (constants.ABS_URL.test(rel)) {
return rel;
}
var abs = path.resolve(inputPath, rel);
if (abspath) {
return utils.unixPath(rebasePath(abs, abspath));
}
var relPath = path.relative(outputPath, abs);
return utils.unixPath(relPath);
}
function rewriteURL(inputPath, outputPath, cssText, abspath) {
return cssText.replace(constants.URL, function(match) {
var path = match.replace(/["']/g, "").slice(4, -1);
path = rewriteRelPath(inputPath, outputPath, path, abspath);
return 'url("' + path + '")';
});
}
exports.resolvePaths = resolvePaths;
exports.rewriteRelPath = rewriteRelPath;
exports.rewriteURL = rewriteURL;

View File

@@ -1,63 +0,0 @@
/**
* @license
* Copyright (c) 2014 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 path = require('path');
module.exports = {
// directly update the textnode child of <style>
// equivalent to <style>.textContent
setTextContent: function(node, text) {
var unwrapped = node.get(0);
var child = unwrapped.children[0];
if (child) {
child.data = text;
} else {
unwrapped.children[0] = {
data: text,
type: 'text',
next: null,
prev: null,
parent: unwrapped
};
}
},
getTextContent: function(node) {
var unwrapped = node.get(0);
var child = unwrapped.children[0];
return child ? child.data : '';
},
// escape a string to be used in new RegExp
escapeForRegExp: function(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
},
unixPath: function(inpath, optSep) {
var sep = optSep || path.sep;
if (sep !== '/') {
inpath = inpath.split(sep).join('/');
}
return inpath;
},
processPolymerInvocation: function(elementName, invocation) {
var name = invocation[1] || '';
var split = invocation[2] || '';
var trailing = invocation[3];
var nameIsString = /^['"]/.test(name);
if (!split) {
// assume "name" is actually the prototype if it is not a string literal
if (!name || (name && !nameIsString)) {
trailing = name + trailing;
name = '\'' + elementName + '\'';
}
if (trailing !== ')') {
split = ',';
}
}
return 'Polymer(' + name + split + trailing;
}
};

View File

@@ -1,308 +0,0 @@
/**
* @license
* Copyright (c) 2014 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
*/
// jshint node: true
var cleancss = require('clean-css');
var fs = require('fs');
var path = require('path');
var uglify = require('uglify-js');
var url = require('url');
var whacko = require('whacko');
var constants = require('./constants.js');
var optparser = require('./optparser.js');
var pathresolver = require('./pathresolver');
var utils = require('./utils');
var setTextContent = utils.setTextContent;
var getTextContent = utils.getTextContent;
var read = {};
var options = {};
// validate options with boolean return
function setOptions(optHash, callback) {
optparser.processOptions(optHash, function(err, o) {
if (err) {
return callback(err);
}
options = o;
callback();
});
}
function exclude(regexes, href) {
return regexes.some(function(r) {
return r.test(href);
});
}
function excludeImport(href) {
return exclude(options.excludes.imports, href);
}
function excludeScript(href) {
return exclude(options.excludes.scripts, href);
}
function excludeStyle(href) {
return exclude(options.excludes.styles, href);
}
function readFile(file) {
var content = fs.readFileSync(file, 'utf8');
return content.replace(/^\uFEFF/, '');
}
// inline relative linked stylesheets into <style> tags
function inlineSheets($, inputPath, outputPath) {
$('link[rel="stylesheet"]').each(function() {
var el = $(this);
var href = el.attr('href');
if (href && !excludeStyle(href)) {
var rel = href;
var inputPath = path.dirname(options.input);
if (constants.ABS_URL.test(rel)) {
var abs = path.resolve(inputPath, path.join(options.abspath, rel));
rel = path.relative(options.outputDir, abs);
}
var filepath = path.resolve(options.outputDir, rel);
// fix up paths in the stylesheet to be relative to the location of the style
var content = pathresolver.rewriteURL(path.dirname(filepath), outputPath, readFile(filepath));
var styleEl = whacko('<style>' + content + '</style>');
// clone attributes
styleEl.attr(el.attr());
// don't set href or rel on the <style>
styleEl.attr('href', null);
styleEl.attr('rel', null);
el.replaceWith(whacko.html(styleEl));
}
});
}
function inlineScripts($, dir) {
$(constants.JS_SRC).each(function() {
var el = $(this);
var src = el.attr('src');
if (src && !excludeScript(src)) {
var rel = src;
var inputPath = path.dirname(options.input);
if (constants.ABS_URL.test(rel)) {
var abs = path.resolve(inputPath, path.join(options.abspath, rel));
rel = path.relative(options.outputDir, abs);
}
var filepath = path.resolve(dir, rel);
var content = readFile(filepath);
// NOTE: reusing UglifyJS's inline script printer (not exported from OutputStream :/)
content = content.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
el.replaceWith('<script>' + content + '</script>');
}
});
}
function concat(filename) {
if (!read[filename]) {
read[filename] = true;
var $ = whacko.load(readFile(filename));
var dir = path.dirname(filename);
pathresolver.resolvePaths($, dir, options.outputDir, options.abspath);
processImports($);
inlineSheets($, dir, options.outputDir);
return $;
} else if (options.verbose) {
console.log('Dependency deduplicated');
}
}
function processImports($, mainDoc) {
var bodyContent = [];
$(constants.IMPORTS).each(function() {
var el = $(this);
var href = el.attr('href');
if (!excludeImport(href)) {
var rel = href;
var inputPath = path.dirname(options.input);
if (constants.ABS_URL.test(rel)) {
var abs = path.resolve(inputPath, path.join(options.abspath, rel));
rel = path.relative(options.outputDir, abs);
}
var $$ = concat(path.resolve(options.outputDir, rel));
if (!$$) {
// remove import link
el.remove();
return;
}
// append import document head to main document head
el.replaceWith($$('head').html());
var bodyHTML = $$('body').html();
// keep the ordering of the import body in main document, before main document's body
bodyContent.push(bodyHTML);
} else if (!options.keepExcludes) {
// if the path is excluded for being absolute, then the import link must remain
var absexclude = options.abspath ? constants.REMOTE_ABS_URL : constants.ABS_URL;
if (!absexclude.test(href)) {
el.remove();
}
}
});
// prepend the import document body contents to the main document, in order
var content = bodyContent.join('\n');
// hide import body content in the main document
if (mainDoc && content) {
content = '<div hidden>' + content + '</div>';
}
$('body').prepend(content);
}
function findScriptLocation($) {
var pos = $('body').last();
if (!pos.length) {
pos = $.root();
}
return pos;
}
// arguments are (index, node), where index is unnecessary
function isCommentOrEmptyTextNode(_, node) {
if (node.type === 'comment'){
return true;
} else if (node.type === 'text') {
// return true if the node is only whitespace
return !((/\S/).test(node.data));
}
}
function compressJS(content, inline) {
var ast = uglify.parse(content);
return ast.print_to_string({inline_script: inline});
}
function removeCommentsAndWhitespace($) {
$(constants.JS_INLINE).each(function() {
var el = $(this);
var content = getTextContent(el);
setTextContent(el, compressJS(content, true));
});
$(constants.CSS).each(function() {
var el = $(this);
var content = getTextContent(el);
setTextContent(el, new cleancss({noAdvanced: true}).minify(content));
});
$('*').contents().filter(isCommentOrEmptyTextNode).remove();
}
function writeFileSync(filename, data, eop) {
if (!options.outputSrc) {
fs.writeFileSync(filename, data, 'utf8');
} else {
options.outputSrc(filename, data, eop);
}
}
function handleMainDocument() {
// reset shared buffers
read = {};
var content = options.inputSrc ? options.inputSrc.toString() : readFile(options.input);
var $ = whacko.load(content);
var dir = path.dirname(options.input);
pathresolver.resolvePaths($, dir, options.outputDir, options.abspath);
processImports($, true);
if (options.inline) {
inlineSheets($, dir, options.outputDir);
}
if (options.inline) {
inlineScripts($, options.outputDir);
}
$(constants.JS_INLINE).each(function() {
var el = $(this);
var content = getTextContent(el);
// find ancestor polymer-element node
var templateElement = el.prev('template').get(0);
if (templateElement) {
var match = constants.NEOPRENE_INVOCATION.exec(content);
var elementName = $(templateElement).attr('id', match[1]);
}
});
// strip noscript from elements, and instead inject explicit Polymer() invocation
// script, so registration order is preserved
$(constants.ELEMENTS_NOSCRIPT).each(function() {
var el = $(this);
var name = el.attr('name');
if (options.verbose) {
console.log('Injecting explicit Polymer invocation for noscript element "' + name + '"');
}
el.append('<script>Polymer(\'' + name + '\');</script>');
el.attr('noscript', null);
});
// strip scripts into a separate file
if (options.csp) {
if (options.verbose) {
console.log('Separating scripts into separate file');
}
// CSPify main page by removing inline scripts
var scripts = [];
$(constants.JS_INLINE).each(function() {
var el = $(this);
var content = getTextContent(el);
scripts.push(content);
el.remove();
});
// join scripts with ';' to prevent breakages due to EOF semicolon insertion
var scriptName = path.basename(options.output, '.html') + '.js';
var scriptContent = scripts.join(';' + constants.EOL);
if (options.strip) {
scriptContent = compressJS(scriptContent, false);
}
writeFileSync(path.resolve(options.outputDir, scriptName), scriptContent);
// insert out-of-lined script into document
findScriptLocation($).append('<script src="' + scriptName + '"></script>');
}
deduplicateImports($);
if (options.strip) {
removeCommentsAndWhitespace($);
}
writeFileSync(options.output, $.html(), true);
}
function deduplicateImports($) {
var imports = {};
$(constants.IMPORTS).each(function() {
var el = $(this);
var href = el.attr('href');
// TODO(dfreedm): allow a user defined base url?
var abs = url.resolve('http://', href);
if (!imports[abs]) {
imports[abs] = true;
} else {
if(options.verbose) {
console.log('Import Dependency deduplicated');
}
el.remove();
}
});
}
exports.processDocument = handleMainDocument;
exports.setOptions = setOptions;

View File

@@ -1,41 +0,0 @@
{
"name": "vulcanize",
"version": "0.6.1",
"description": "Process Web Components into one output file",
"main": "lib/vulcan.js",
"bin": {
"vulcanize": "bin/vulcanize"
},
"dependencies": {
"clean-css": "^2.2.11",
"nopt": "^3.0.1",
"uglify-js": "^2.4.15",
"whacko": "^0.17.1"
},
"devDependencies": {
"jshint": "^2.5.6",
"mocha": "^2.0.1"
},
"scripts": {
"test": "node_modules/.bin/jshint --verbose lib/*.js bin/* test/*.js && node_modules/.bin/mocha"
},
"author": "Daniel Freedman",
"license": "BSD",
"directories": {
"test": "test"
},
"keywords": [
"web components",
"polymer"
],
"repository": {
"type": "git",
"url": "git://github.com/Polymer/vulcanize.git"
},
"bugs": {
"url": "https://github.com/Polymer/vulcanize/issues"
},
"optionalDependencies": {
"update-notifier": "^0.2.2"
}
}

View File

@@ -1,3 +0,0 @@
{
input: "index.html",
}

View File

@@ -1,6 +0,0 @@
{
"csp": true,
"excludes": {
"imports": [".*"]
}
}

View File

@@ -1,22 +0,0 @@
<!DOCTYPE html>
<!--
@license
Copyright (c) 2014 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
-->
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="import" href="imports/simple-import.html">
<link rel="import" href="imports/simple-import.html">
<link rel="import" href="http://example.com/foo/bar.html">
<title>Sample Build</title>
</head>
<body>
<my-element></my-element>
</body>
</html>

View File

@@ -1,22 +0,0 @@
<!--
@license
Copyright (c) 2014 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
-->
<polymer-element name="my-element" noscript>
<template>
<link rel="stylesheet" href="simple-style.css" shim-shadowdom>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 630 630">
<rect x="0" y="0" width="630" height="630" fill="#3c790a"/>
<path d="m212 497c11"/>
<polygon />
<path />
<polygon/>
<path />
</svg>
</template>
</polymer-element>

View File

@@ -1,14 +0,0 @@
/*
@license
Copyright (c) 2014 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
*/
:host([type="platform"]) { background-color: red; }
:host([type="core"]) { background-color: red; }
:host([type="elements"]) { background-color: red; }
polyfill-next-selector { content: ':host header'; }
polyfill-next-selector { content: 'I WIN'; }

View File

@@ -1,2 +0,0 @@
--ui tdd
--slow 300

View File

@@ -1,451 +0,0 @@
/**
* @license
* Copyright (c) 2014 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
*/
// jshint node: true
var assert = require('assert');
var path = require('path');
assert.AssertionError.prototype.showDiff = true;
suite('constants', function() {
var constants = require('../lib/constants.js');
suite('URLs', function() {
test('absolute urls', function() {
var abs = constants.ABS_URL;
assert(abs.test('data:charset=utf8,'), 'data urls');
assert(abs.test('http://foo.com'), 'http');
assert(abs.test('https://foo.com'), 'https');
assert(abs.test('mailto:foo@bar.com'), 'mailto');
assert(abs.test('//foo.com'), 'protocol-free');
assert(abs.test('/components/'), '/');
assert(!abs.test('../foo/bar.html'), '../');
assert(!abs.test('bar.html'), 'sibling dependency');
});
test('remote absolute urls', function() {
var rabs = constants.REMOTE_ABS_URL;
assert(rabs.test('http://foo.com'), 'http');
assert(rabs.test('https://foo.com'), 'https');
assert(rabs.test('//foo.com'), 'protocol-free');
assert(!rabs.test('../foo/bar.html'), '../');
assert(!rabs.test('bar.html'), 'sibling dependency');
assert(!rabs.test('/components/'), '/');
});
test('CSS URLs', function() {
var url = constants.URL;
assert('url(foo.html)'.match(url), 'naked');
assert('url(\'foo.html\')'.match(url), 'single quote');
assert('url("foo.html")'.match(url), 'double quote');
});
});
test('Polymer Invocation', function() {
var polymer = constants.POLYMER_INVOCATION;
function test(invocation, msg) {
var matches = polymer.exec(invocation);
assert(matches, 'polymer invocation found', msg);
}
test('Polymer(\'core-input\', {})', 'full');
test('Polymer(\'core-input\')', 'name-only');
test('Polymer()', 'none');
test('Polymer({})', 'object-only');
test('Polymer(p)', 'indirect');
});
});
suite('Path Resolver', function() {
var pathresolver = require('../lib/pathresolver.js');
var inputPath = '/foo/bar/my-element';
var outputPath = '/foo/bar';
test('Rewrite URLs', function() {
var css = [
'x-element {',
' background-image: url(foo.jpg);',
'}',
'x-bar {',
' background-image: url(data:xxxxx);',
'}',
'x-quuz {',
' background-image: url(\'https://foo.bar/baz.jpg\');',
'}',
].join('\n');
var expected = [
'x-element {',
' background-image: url("my-element/foo.jpg");',
'}',
'x-bar {',
' background-image: url("data:xxxxx");',
'}',
'x-quuz {',
' background-image: url("https://foo.bar/baz.jpg");',
'}',
].join('\n');
var actual = pathresolver.rewriteURL(inputPath, outputPath, css);
assert.equal(actual, expected);
});
test('Rewrite Paths', function() {
function testPath(val, expected, abs, msg) {
var actual = pathresolver.rewriteRelPath(inputPath, outputPath, val, abs);
assert.equal(actual, expected, msg);
}
testPath('biz.jpg', 'my-element/biz.jpg', null, 'local');
testPath('http://foo/biz.jpg', 'http://foo/biz.jpg', null, 'remote');
testPath('biz.jpg', 'bar/my-element/biz.jpg', '/foo/', 'build path');
});
test('Resolve Paths', function() {
var html = [
'<link rel="import" href="../polymer/polymer.html">',
'<link rel="stylesheet" href="my-element.css">',
'<polymer-element name="my-element">',
'<template>',
'<style>:host { background-image: url(background.svg); }</style>',
'<script>Polymer()</script>',
'</template>',
'</polymer-element>'
].join('\n');
var expected = [
'<html><head><link rel="import" href="polymer/polymer.html">',
'<link rel="stylesheet" href="my-element/my-element.css">',
'</head><body><polymer-element name="my-element" assetpath="my-element/">',
'<template>',
'<style>:host { background-image: url("my-element/background.svg"); }</style>',
'<script>Polymer()</script>',
'</template>',
'</polymer-element></body></html>'
].join('\n');
var expected2 = [
'<html><head><link rel="import" href="/bar/polymer/polymer.html">',
'<link rel="stylesheet" href="/bar/my-element/my-element.css">',
'</head><body><polymer-element name="my-element" assetpath="/bar/my-element/">',
'<template>',
'<style>:host { background-image: url("/bar/my-element/background.svg"); }</style>',
'<script>Polymer()</script>',
'</template>',
'</polymer-element></body></html>'
].join('\n');
var actual;
var whacko = require('whacko');
var $ = whacko.load(html);
pathresolver.resolvePaths($, inputPath, outputPath);
actual = $.html();
assert.equal(actual, expected, 'relative');
$ = whacko.load(html);
pathresolver.resolvePaths($, inputPath, outputPath, '/foo');
actual = $.html();
assert.equal(actual, expected2, 'absolute');
});
});
suite('Utils', function() {
var constants = require('../lib/constants.js');
var utils = require('../lib/utils.js');
test('getTextContent', function() {
var whacko = require('whacko');
var divEl = whacko('<div>some text!</div>');
assert.equal(utils.getTextContent(divEl), 'some text!', 'a textnode child');
var blankEl = whacko('<div></div>');
assert.equal(utils.getTextContent(blankEl), '', 'no textnode children');
});
test('setTextContent', function() {
var whacko = require('whacko');
var divEl = whacko('<div></div>');
utils.setTextContent(divEl, 'some text!');
assert.equal(utils.getTextContent(divEl), 'some text!', 'create text node');
utils.setTextContent(divEl, 'some text 2!');
assert.equal(utils.getTextContent(divEl), 'some text 2!', 'override text node');
});
test('unixPath', function() {
var pp = ['foo', 'bar', 'baz'];
var p = pp.join('/');
var actual = utils.unixPath(p);
assert.equal(actual, p, 'started unix');
var p2 = pp.join('\\');
actual = utils.unixPath(p2, '\\');
assert.equal(actual, p, 'windows path');
});
test('escapeForRegExp', function() {
var actual = utils.escapeForRegExp('foo-bar');
assert.equal(actual, 'foo\\-bar', 'element name');
actual = utils.escapeForRegExp('foo/bar/baz');
assert.equal(actual, 'foo\\/bar\\/baz', 'absolute path');
});
test('Polymer Invocation', function() {
var polymer = constants.POLYMER_INVOCATION;
function test(invocation, expected, msg) {
var matches = polymer.exec(invocation);
assert(matches, 'polymer invocation found');
var replacement = utils.processPolymerInvocation('core-input', matches);
var actual = invocation.replace(matches[0], replacement);
assert.strictEqual(actual, expected, msg);
}
test('Polymer(\'core-input\', {})', 'Polymer(\'core-input\', {})', 'full');
test('Polymer(\'core-input\')', 'Polymer(\'core-input\')', 'name-only');
test('Polymer()', 'Polymer(\'core-input\')', 'none');
test('Polymer({})', 'Polymer(\'core-input\',{})', 'object-only');
test('Polymer(p)', 'Polymer(\'core-input\',p)', 'indirect');
});
test('#82', function() {
var constants = require('../lib/constants.js');
var whacko = require('whacko');
var $ = whacko.load('<polymer-element name="paper-button-base"><script>(function(){ Polymer(p);}()</script></polymer-element>');
$(constants.JS_INLINE).each(function() {
var el = $(this);
var content = utils.getTextContent(el);
assert(content);
var parentElement = el.closest('polymer-element').get(0);
if (parentElement) {
var match = constants.POLYMER_INVOCATION.exec(content);
var elementName = $(parentElement).attr('name');
if (match) {
var invocation = utils.processPolymerInvocation(elementName, match);
content = content.replace(match[0], invocation);
utils.setTextContent(el, content);
}
}
assert.equal(utils.getTextContent(el), '(function(){ Polymer(\'paper-button-base\',p);}()');
});
});
});
suite('Optparser', function() {
var path = require('path');
var optParser = require('../lib/optparser.js');
var constants = require('../lib/constants.js');
var ABS_URL = constants.ABS_URL;
var REMOTE_ABS_URL = constants.REMOTE_ABS_URL;
function optParserTest(fn, opts, skipFail) {
if (typeof opts === 'undefined') {
opts = {input: path.resolve('index.html')};
}
optParser.processOptions(opts, function(err, options) {
if (!skipFail) {
assert.equal(err, null);
}
fn(err, options);
});
}
test('Error on no input', function(done) {
optParserTest(function(err, options) {
assert.equal(err, 'No input file given!');
done();
}, null, true);
});
test('Defaults', function(done) {
optParserTest(function(err, options) {
assert.equal(options.input, path.resolve('index.html'));
assert.equal(options.output, path.resolve('vulcanized.html'));
assert.equal(options.outputDir, path.dirname(path.resolve('vulcanized.html')));
assert(!options.csp);
assert(!options.abspath);
assert.deepEqual(options.excludes, {imports:[ABS_URL], scripts:[ABS_URL], styles:[ABS_URL]});
done();
});
});
test('CSP', function(done) {
optParserTest(function(err, options) {
assert.equal(options.csp, path.resolve('vulcanized.js'));
done();
}, {input: 'index.html', csp: true});
});
test('output', function(done) {
optParserTest(function(err, options) {
assert.equal(options.output, path.resolve('build.html'));
assert.equal(options.csp, path.resolve('build.js'));
done();
}, {input: path.resolve('index.html'), output: path.resolve('build.html'), csp: true});
});
test('abspath', function(done) {
optParserTest(function(err, options) {
assert.equal(options.abspath, path.resolve('../'));
assert.deepEqual(options.excludes, {imports:[REMOTE_ABS_URL], scripts:[REMOTE_ABS_URL], styles:[REMOTE_ABS_URL]});
done();
}, {input: path.resolve('index.html'), abspath: path.resolve('../')});
});
test('excludes', function(done) {
var excludes = {
imports: [
'.*'
]
};
var expected = [/.*/, ABS_URL];
optParserTest(function(err, options) {
assert.deepEqual(options.excludes.imports, expected);
done();
}, {input: path.resolve('index.html'), excludes: excludes});
});
test('config file', function(done) {
optParserTest(function(err, options) {
assert.equal(options.input, path.resolve('index.html'));
assert.equal(options.output, path.resolve('build.html'));
assert.equal(options.csp, path.resolve('build.js'));
assert(!options.abspath);
assert.deepEqual(options.excludes, {imports:[/.*/, ABS_URL], scripts:[ABS_URL], styles:[ABS_URL]});
done();
}, {config: path.resolve('test/config.json'), input: path.resolve('index.html'), output: path.resolve('build.html'), csp: true});
});
test('report broken config file', function(done) {
optParserTest(function(err, options) {
assert.equal(err, 'Malformed config JSON!');
done();
}, {config: path.resolve('test/broken_config.json')}, true);
});
});
suite('Vulcan', function() {
var vulcan = require('../lib/vulcan.js');
var outputPath = path.resolve('test/html/actual.html');
var inputPath = path.resolve('test/html/default.html');
test('set options', function(done) {
var options = {
input: 'index.html'
};
vulcan.setOptions(options, done);
});
function process(options, fn) {
var outputs = Object.create(null);
options.outputSrc = function(name, data, eop) {
if (!data) {
throw new Error("Writing empty data");
}
outputs[name] = data;
};
vulcan.setOptions(options, function(err) {
assert(!err);
vulcan.processDocument();
Object.keys(outputs).forEach(function(o) {
assert.equal(typeof outputs[o], 'string', 'all buffers are closed');
});
fn(outputs);
});
}
test('defaults', function(done) {
var getTextContent = require('../lib/utils.js').getTextContent;
process({input: inputPath, output: outputPath}, function(outputs) {
assert.equal(Object.keys(outputs).length, 1);
var vulcanized = outputs[outputPath];
assert(vulcanized);
var $ = require('whacko').load(vulcanized);
assert.equal($('body > div[hidden]').length, 1, 'only one div[hidden]');
assert.equal($('head > link[rel="import"]:not([href^="http://"])').length, 0, 'all relative imports removed');
assert.equal($('polymer-element').length, 1, 'imports were deduplicated');
assert.equal($('polymer-element').attr('noscript'), null, 'noscript removed');
assert.equal(getTextContent($('polymer-element > script')), 'Polymer(\'my-element\');', 'polymer script included');
assert.equal($('polymer-element > template > link').length, 0, 'external styles removed');
assert.equal($('polymer-element > template > style').length, 1, 'styles inlined');
assert.equal($('polymer-element > template > svg > *').length, 6, 'svg children propery nested');
assert.equal($('polymer-element').attr('assetpath'), 'imports/', 'assetpath set');
done();
});
});
test('CSP', function(done) {
process({input: inputPath, output: outputPath, csp: true}, function(outputs) {
assert.equal(Object.keys(outputs).length, 2);
var vulcanized = outputs[outputPath];
var vulcanizedJS = outputs[path.resolve(outputPath, '../actual.js')];
assert(vulcanized);
assert(vulcanizedJS);
var $ = require('whacko').load(vulcanized);
assert($('body > script[src="actual.js"]'), 'vulcanized script in body');
assert.equal($('body script:not([src])').length, 0, 'inline scripts removed');
assert.equal(vulcanizedJS, 'Polymer(\'my-element\');', 'csp element script');
done();
});
});
test('exclude', function(done) {
var i = 3;
function reallyDone() {
if (--i === 0) {
done();
}
}
process({input: inputPath, output: outputPath, excludes: {imports: ['simple-import']}}, function(outputs) {
var vulcanized = outputs[outputPath];
assert(vulcanized);
var $ = require('whacko').load(vulcanized);
assert.equal($('head > link[href="imports/simple-import.html"]').length, 0, 'import excluded');
assert.equal($('head > link[rel="stylesheet"][href="imports/simple-style.css"]').length, 0, 'import content excluded');
assert.equal($('head > link[href="http://example.com/foo/bar.html"]').length, 1, 'external import is not excluded');
reallyDone();
});
process({input: inputPath, output: outputPath, excludes: {styles: ['simple-style']}}, function(outputs) {
var vulcanized = outputs[outputPath];
assert(vulcanized);
var $ = require('whacko').load(vulcanized);
assert.equal($('polymer-element[name="my-element"] > template > link[href="imports/simple-style.css"]').length, 1, 'style excluded');
reallyDone();
});
process({input: inputPath, output: outputPath, excludes: {imports: ['simple-import']}, 'strip-excludes': false}, function(outputs) {
var vulcanized = outputs[outputPath];
assert(vulcanized);
var $ = require('whacko').load(vulcanized);
assert.equal($('link[href="imports/simple-import.html"]').length, 1, 'excluded import not stripped');
reallyDone();
});
});
});

View File

@@ -1,23 +0,0 @@
#!/bin/bash
#
# @license
# Copyright (c) 2014 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
#
# tags sorted semver style
TAGS=($(git tag -l | sort -k1,1r -k2,2r -k3,3r -t.))
TO=(${TAGS[@]})
FROM=(${TAGS[@]:1})
FROM+=(`git rev-list --max-parents=0 HEAD`)
for i in ${!FROM[@]}; do
echo "### ${TO[$i]}"
git log ${FROM[$i]}..${TO[$i]} --pretty="- %s"
done

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,928 +0,0 @@
/**
* @license
* Copyright (c) 2014 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
*/
// @version 0.5.0-b6cf8b1
if (typeof WeakMap === "undefined") {
(function() {
var defineProperty = Object.defineProperty;
var counter = Date.now() % 1e9;
var WeakMap = function() {
this.name = "__st" + (Math.random() * 1e9 >>> 0) + (counter++ + "__");
};
WeakMap.prototype = {
set: function(key, value) {
var entry = key[this.name];
if (entry && entry[0] === key) entry[1] = value; else defineProperty(key, this.name, {
value: [ key, value ],
writable: true
});
return this;
},
get: function(key) {
var entry;
return (entry = key[this.name]) && entry[0] === key ? entry[1] : undefined;
},
"delete": function(key) {
var entry = key[this.name];
if (!entry) return false;
var hasValue = entry[0] === key;
entry[0] = entry[1] = undefined;
return hasValue;
},
has: function(key) {
var entry = key[this.name];
if (!entry) return false;
return entry[0] === key;
}
};
window.WeakMap = WeakMap;
})();
}
(function(global) {
var registrationsTable = new WeakMap();
var setImmediate = window.msSetImmediate;
if (!setImmediate) {
var setImmediateQueue = [];
var sentinel = String(Math.random());
window.addEventListener("message", function(e) {
if (e.data === sentinel) {
var queue = setImmediateQueue;
setImmediateQueue = [];
queue.forEach(function(func) {
func();
});
}
});
setImmediate = function(func) {
setImmediateQueue.push(func);
window.postMessage(sentinel, "*");
};
}
var isScheduled = false;
var scheduledObservers = [];
function scheduleCallback(observer) {
scheduledObservers.push(observer);
if (!isScheduled) {
isScheduled = true;
setImmediate(dispatchCallbacks);
}
}
function wrapIfNeeded(node) {
return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(node) || node;
}
function dispatchCallbacks() {
isScheduled = false;
var observers = scheduledObservers;
scheduledObservers = [];
observers.sort(function(o1, o2) {
return o1.uid_ - o2.uid_;
});
var anyNonEmpty = false;
observers.forEach(function(observer) {
var queue = observer.takeRecords();
removeTransientObserversFor(observer);
if (queue.length) {
observer.callback_(queue, observer);
anyNonEmpty = true;
}
});
if (anyNonEmpty) dispatchCallbacks();
}
function removeTransientObserversFor(observer) {
observer.nodes_.forEach(function(node) {
var registrations = registrationsTable.get(node);
if (!registrations) return;
registrations.forEach(function(registration) {
if (registration.observer === observer) registration.removeTransientObservers();
});
});
}
function forEachAncestorAndObserverEnqueueRecord(target, callback) {
for (var node = target; node; node = node.parentNode) {
var registrations = registrationsTable.get(node);
if (registrations) {
for (var j = 0; j < registrations.length; j++) {
var registration = registrations[j];
var options = registration.options;
if (node !== target && !options.subtree) continue;
var record = callback(options);
if (record) registration.enqueue(record);
}
}
}
}
var uidCounter = 0;
function JsMutationObserver(callback) {
this.callback_ = callback;
this.nodes_ = [];
this.records_ = [];
this.uid_ = ++uidCounter;
}
JsMutationObserver.prototype = {
observe: function(target, options) {
target = wrapIfNeeded(target);
if (!options.childList && !options.attributes && !options.characterData || options.attributeOldValue && !options.attributes || options.attributeFilter && options.attributeFilter.length && !options.attributes || options.characterDataOldValue && !options.characterData) {
throw new SyntaxError();
}
var registrations = registrationsTable.get(target);
if (!registrations) registrationsTable.set(target, registrations = []);
var registration;
for (var i = 0; i < registrations.length; i++) {
if (registrations[i].observer === this) {
registration = registrations[i];
registration.removeListeners();
registration.options = options;
break;
}
}
if (!registration) {
registration = new Registration(this, target, options);
registrations.push(registration);
this.nodes_.push(target);
}
registration.addListeners();
},
disconnect: function() {
this.nodes_.forEach(function(node) {
var registrations = registrationsTable.get(node);
for (var i = 0; i < registrations.length; i++) {
var registration = registrations[i];
if (registration.observer === this) {
registration.removeListeners();
registrations.splice(i, 1);
break;
}
}
}, this);
this.records_ = [];
},
takeRecords: function() {
var copyOfRecords = this.records_;
this.records_ = [];
return copyOfRecords;
}
};
function MutationRecord(type, target) {
this.type = type;
this.target = target;
this.addedNodes = [];
this.removedNodes = [];
this.previousSibling = null;
this.nextSibling = null;
this.attributeName = null;
this.attributeNamespace = null;
this.oldValue = null;
}
function copyMutationRecord(original) {
var record = new MutationRecord(original.type, original.target);
record.addedNodes = original.addedNodes.slice();
record.removedNodes = original.removedNodes.slice();
record.previousSibling = original.previousSibling;
record.nextSibling = original.nextSibling;
record.attributeName = original.attributeName;
record.attributeNamespace = original.attributeNamespace;
record.oldValue = original.oldValue;
return record;
}
var currentRecord, recordWithOldValue;
function getRecord(type, target) {
return currentRecord = new MutationRecord(type, target);
}
function getRecordWithOldValue(oldValue) {
if (recordWithOldValue) return recordWithOldValue;
recordWithOldValue = copyMutationRecord(currentRecord);
recordWithOldValue.oldValue = oldValue;
return recordWithOldValue;
}
function clearRecords() {
currentRecord = recordWithOldValue = undefined;
}
function recordRepresentsCurrentMutation(record) {
return record === recordWithOldValue || record === currentRecord;
}
function selectRecord(lastRecord, newRecord) {
if (lastRecord === newRecord) return lastRecord;
if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue;
return null;
}
function Registration(observer, target, options) {
this.observer = observer;
this.target = target;
this.options = options;
this.transientObservedNodes = [];
}
Registration.prototype = {
enqueue: function(record) {
var records = this.observer.records_;
var length = records.length;
if (records.length > 0) {
var lastRecord = records[length - 1];
var recordToReplaceLast = selectRecord(lastRecord, record);
if (recordToReplaceLast) {
records[length - 1] = recordToReplaceLast;
return;
}
} else {
scheduleCallback(this.observer);
}
records[length] = record;
},
addListeners: function() {
this.addListeners_(this.target);
},
addListeners_: function(node) {
var options = this.options;
if (options.attributes) node.addEventListener("DOMAttrModified", this, true);
if (options.characterData) node.addEventListener("DOMCharacterDataModified", this, true);
if (options.childList) node.addEventListener("DOMNodeInserted", this, true);
if (options.childList || options.subtree) node.addEventListener("DOMNodeRemoved", this, true);
},
removeListeners: function() {
this.removeListeners_(this.target);
},
removeListeners_: function(node) {
var options = this.options;
if (options.attributes) node.removeEventListener("DOMAttrModified", this, true);
if (options.characterData) node.removeEventListener("DOMCharacterDataModified", this, true);
if (options.childList) node.removeEventListener("DOMNodeInserted", this, true);
if (options.childList || options.subtree) node.removeEventListener("DOMNodeRemoved", this, true);
},
addTransientObserver: function(node) {
if (node === this.target) return;
this.addListeners_(node);
this.transientObservedNodes.push(node);
var registrations = registrationsTable.get(node);
if (!registrations) registrationsTable.set(node, registrations = []);
registrations.push(this);
},
removeTransientObservers: function() {
var transientObservedNodes = this.transientObservedNodes;
this.transientObservedNodes = [];
transientObservedNodes.forEach(function(node) {
this.removeListeners_(node);
var registrations = registrationsTable.get(node);
for (var i = 0; i < registrations.length; i++) {
if (registrations[i] === this) {
registrations.splice(i, 1);
break;
}
}
}, this);
},
handleEvent: function(e) {
e.stopImmediatePropagation();
switch (e.type) {
case "DOMAttrModified":
var name = e.attrName;
var namespace = e.relatedNode.namespaceURI;
var target = e.target;
var record = new getRecord("attributes", target);
record.attributeName = name;
record.attributeNamespace = namespace;
var oldValue = e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
forEachAncestorAndObserverEnqueueRecord(target, function(options) {
if (!options.attributes) return;
if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) {
return;
}
if (options.attributeOldValue) return getRecordWithOldValue(oldValue);
return record;
});
break;
case "DOMCharacterDataModified":
var target = e.target;
var record = getRecord("characterData", target);
var oldValue = e.prevValue;
forEachAncestorAndObserverEnqueueRecord(target, function(options) {
if (!options.characterData) return;
if (options.characterDataOldValue) return getRecordWithOldValue(oldValue);
return record;
});
break;
case "DOMNodeRemoved":
this.addTransientObserver(e.target);
case "DOMNodeInserted":
var target = e.relatedNode;
var changedNode = e.target;
var addedNodes, removedNodes;
if (e.type === "DOMNodeInserted") {
addedNodes = [ changedNode ];
removedNodes = [];
} else {
addedNodes = [];
removedNodes = [ changedNode ];
}
var previousSibling = changedNode.previousSibling;
var nextSibling = changedNode.nextSibling;
var record = getRecord("childList", target);
record.addedNodes = addedNodes;
record.removedNodes = removedNodes;
record.previousSibling = previousSibling;
record.nextSibling = nextSibling;
forEachAncestorAndObserverEnqueueRecord(target, function(options) {
if (!options.childList) return;
return record;
});
}
clearRecords();
}
};
global.JsMutationObserver = JsMutationObserver;
if (!global.MutationObserver) global.MutationObserver = JsMutationObserver;
})(this);
window.CustomElements = window.CustomElements || {
flags: {}
};
(function(scope) {
var flags = scope.flags;
var modules = [];
var addModule = function(module) {
modules.push(module);
};
var initializeModules = function() {
modules.forEach(function(module) {
module(scope);
});
};
scope.addModule = addModule;
scope.initializeModules = initializeModules;
scope.hasNative = Boolean(document.registerElement);
scope.useNative = !flags.register && scope.hasNative && !window.ShadowDOMPolyfill && (!window.HTMLImports || HTMLImports.useNative);
})(CustomElements);
CustomElements.addModule(function(scope) {
var IMPORT_LINK_TYPE = window.HTMLImports ? HTMLImports.IMPORT_LINK_TYPE : "none";
function forSubtree(node, cb) {
findAllElements(node, function(e) {
if (cb(e)) {
return true;
}
forRoots(e, cb);
});
forRoots(node, cb);
}
function findAllElements(node, find, data) {
var e = node.firstElementChild;
if (!e) {
e = node.firstChild;
while (e && e.nodeType !== Node.ELEMENT_NODE) {
e = e.nextSibling;
}
}
while (e) {
if (find(e, data) !== true) {
findAllElements(e, find, data);
}
e = e.nextElementSibling;
}
return null;
}
function forRoots(node, cb) {
var root = node.shadowRoot;
while (root) {
forSubtree(root, cb);
root = root.olderShadowRoot;
}
}
var processingDocuments;
function forDocumentTree(doc, cb) {
processingDocuments = [];
_forDocumentTree(doc, cb);
processingDocuments = null;
}
function _forDocumentTree(doc, cb) {
doc = wrap(doc);
if (processingDocuments.indexOf(doc) >= 0) {
return;
}
processingDocuments.push(doc);
var imports = doc.querySelectorAll("link[rel=" + IMPORT_LINK_TYPE + "]");
for (var i = 0, l = imports.length, n; i < l && (n = imports[i]); i++) {
if (n.import) {
_forDocumentTree(n.import, cb);
}
}
cb(doc);
}
scope.forDocumentTree = forDocumentTree;
scope.forSubtree = forSubtree;
});
CustomElements.addModule(function(scope) {
var flags = scope.flags;
var forSubtree = scope.forSubtree;
var forDocumentTree = scope.forDocumentTree;
function addedNode(node) {
return added(node) || addedSubtree(node);
}
function added(node) {
if (scope.upgrade(node)) {
return true;
}
attached(node);
}
function addedSubtree(node) {
forSubtree(node, function(e) {
if (added(e)) {
return true;
}
});
}
function attachedNode(node) {
attached(node);
if (inDocument(node)) {
forSubtree(node, function(e) {
attached(e);
});
}
}
var hasPolyfillMutations = !window.MutationObserver || window.MutationObserver === window.JsMutationObserver;
scope.hasPolyfillMutations = hasPolyfillMutations;
var isPendingMutations = false;
var pendingMutations = [];
function deferMutation(fn) {
pendingMutations.push(fn);
if (!isPendingMutations) {
isPendingMutations = true;
setTimeout(takeMutations);
}
}
function takeMutations() {
isPendingMutations = false;
var $p = pendingMutations;
for (var i = 0, l = $p.length, p; i < l && (p = $p[i]); i++) {
p();
}
pendingMutations = [];
}
function attached(element) {
if (hasPolyfillMutations) {
deferMutation(function() {
_attached(element);
});
} else {
_attached(element);
}
}
function _attached(element) {
if (element.__upgraded__ && (element.attachedCallback || element.detachedCallback)) {
if (!element.__attached && inDocument(element)) {
element.__attached = true;
if (element.attachedCallback) {
element.attachedCallback();
}
}
}
}
function detachedNode(node) {
detached(node);
forSubtree(node, function(e) {
detached(e);
});
}
function detached(element) {
if (hasPolyfillMutations) {
deferMutation(function() {
_detached(element);
});
} else {
_detached(element);
}
}
function _detached(element) {
if (element.__upgraded__ && (element.attachedCallback || element.detachedCallback)) {
if (element.__attached && !inDocument(element)) {
element.__attached = false;
if (element.detachedCallback) {
element.detachedCallback();
}
}
}
}
function inDocument(element) {
var p = element;
var doc = wrap(document);
while (p) {
if (p == doc) {
return true;
}
p = p.parentNode || p.host;
}
}
function watchShadow(node) {
if (node.shadowRoot && !node.shadowRoot.__watched) {
flags.dom && console.log("watching shadow-root for: ", node.localName);
var root = node.shadowRoot;
while (root) {
observe(root);
root = root.olderShadowRoot;
}
}
}
function handler(mutations) {
if (flags.dom) {
var mx = mutations[0];
if (mx && mx.type === "childList" && mx.addedNodes) {
if (mx.addedNodes) {
var d = mx.addedNodes[0];
while (d && d !== document && !d.host) {
d = d.parentNode;
}
var u = d && (d.URL || d._URL || d.host && d.host.localName) || "";
u = u.split("/?").shift().split("/").pop();
}
}
console.group("mutations (%d) [%s]", mutations.length, u || "");
}
mutations.forEach(function(mx) {
if (mx.type === "childList") {
forEach(mx.addedNodes, function(n) {
if (!n.localName) {
return;
}
addedNode(n);
});
forEach(mx.removedNodes, function(n) {
if (!n.localName) {
return;
}
detachedNode(n);
});
}
});
flags.dom && console.groupEnd();
}
function takeRecords(node) {
node = wrap(node);
if (!node) {
node = wrap(document);
}
while (node.parentNode) {
node = node.parentNode;
}
var observer = node.__observer;
if (observer) {
handler(observer.takeRecords());
takeMutations();
}
}
var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
function observe(inRoot) {
if (inRoot.__observer) {
return;
}
var observer = new MutationObserver(handler);
observer.observe(inRoot, {
childList: true,
subtree: true
});
inRoot.__observer = observer;
}
function upgradeDocument(doc) {
doc = wrap(doc);
flags.dom && console.group("upgradeDocument: ", doc.baseURI.split("/").pop());
addedNode(doc);
observe(doc);
flags.dom && console.groupEnd();
}
function upgradeDocumentTree(doc) {
forDocumentTree(doc, upgradeDocument);
}
var originalCreateShadowRoot = Element.prototype.createShadowRoot;
Element.prototype.createShadowRoot = function() {
var root = originalCreateShadowRoot.call(this);
CustomElements.watchShadow(this);
return root;
};
scope.watchShadow = watchShadow;
scope.upgradeDocumentTree = upgradeDocumentTree;
scope.upgradeSubtree = addedSubtree;
scope.upgradeAll = addedNode;
scope.attachedNode = attachedNode;
scope.takeRecords = takeRecords;
});
CustomElements.addModule(function(scope) {
var flags = scope.flags;
function upgrade(node) {
if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {
var is = node.getAttribute("is");
var definition = scope.getRegisteredDefinition(is || node.localName);
if (definition) {
if (is && definition.tag == node.localName) {
return upgradeWithDefinition(node, definition);
} else if (!is && !definition.extends) {
return upgradeWithDefinition(node, definition);
}
}
}
}
function upgradeWithDefinition(element, definition) {
flags.upgrade && console.group("upgrade:", element.localName);
if (definition.is) {
element.setAttribute("is", definition.is);
}
implementPrototype(element, definition);
element.__upgraded__ = true;
created(element);
scope.attachedNode(element);
scope.upgradeSubtree(element);
flags.upgrade && console.groupEnd();
return element;
}
function implementPrototype(element, definition) {
if (Object.__proto__) {
element.__proto__ = definition.prototype;
} else {
customMixin(element, definition.prototype, definition.native);
element.__proto__ = definition.prototype;
}
}
function customMixin(inTarget, inSrc, inNative) {
var used = {};
var p = inSrc;
while (p !== inNative && p !== HTMLElement.prototype) {
var keys = Object.getOwnPropertyNames(p);
for (var i = 0, k; k = keys[i]; i++) {
if (!used[k]) {
Object.defineProperty(inTarget, k, Object.getOwnPropertyDescriptor(p, k));
used[k] = 1;
}
}
p = Object.getPrototypeOf(p);
}
}
function created(element) {
if (element.createdCallback) {
element.createdCallback();
}
}
scope.upgrade = upgrade;
scope.upgradeWithDefinition = upgradeWithDefinition;
scope.implementPrototype = implementPrototype;
});
CustomElements.addModule(function(scope) {
var upgradeDocumentTree = scope.upgradeDocumentTree;
var upgrade = scope.upgrade;
var upgradeWithDefinition = scope.upgradeWithDefinition;
var implementPrototype = scope.implementPrototype;
var useNative = scope.useNative;
function register(name, options) {
var definition = options || {};
if (!name) {
throw new Error("document.registerElement: first argument `name` must not be empty");
}
if (name.indexOf("-") < 0) {
throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '" + String(name) + "'.");
}
if (isReservedTag(name)) {
throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '" + String(name) + "'. The type name is invalid.");
}
if (getRegisteredDefinition(name)) {
throw new Error("DuplicateDefinitionError: a type with name '" + String(name) + "' is already registered");
}
if (!definition.prototype) {
definition.prototype = Object.create(HTMLElement.prototype);
}
definition.__name = name.toLowerCase();
definition.lifecycle = definition.lifecycle || {};
definition.ancestry = ancestry(definition.extends);
resolveTagName(definition);
resolvePrototypeChain(definition);
overrideAttributeApi(definition.prototype);
registerDefinition(definition.__name, definition);
definition.ctor = generateConstructor(definition);
definition.ctor.prototype = definition.prototype;
definition.prototype.constructor = definition.ctor;
if (scope.ready) {
upgradeDocumentTree(document);
}
return definition.ctor;
}
function overrideAttributeApi(prototype) {
if (prototype.setAttribute._polyfilled) {
return;
}
var setAttribute = prototype.setAttribute;
prototype.setAttribute = function(name, value) {
changeAttribute.call(this, name, value, setAttribute);
};
var removeAttribute = prototype.removeAttribute;
prototype.removeAttribute = function(name) {
changeAttribute.call(this, name, null, removeAttribute);
};
prototype.setAttribute._polyfilled = true;
}
function changeAttribute(name, value, operation) {
name = name.toLowerCase();
var oldValue = this.getAttribute(name);
operation.apply(this, arguments);
var newValue = this.getAttribute(name);
if (this.attributeChangedCallback && newValue !== oldValue) {
this.attributeChangedCallback(name, oldValue, newValue);
}
}
function isReservedTag(name) {
for (var i = 0; i < reservedTagList.length; i++) {
if (name === reservedTagList[i]) {
return true;
}
}
}
var reservedTagList = [ "annotation-xml", "color-profile", "font-face", "font-face-src", "font-face-uri", "font-face-format", "font-face-name", "missing-glyph" ];
function ancestry(extnds) {
var extendee = getRegisteredDefinition(extnds);
if (extendee) {
return ancestry(extendee.extends).concat([ extendee ]);
}
return [];
}
function resolveTagName(definition) {
var baseTag = definition.extends;
for (var i = 0, a; a = definition.ancestry[i]; i++) {
baseTag = a.is && a.tag;
}
definition.tag = baseTag || definition.__name;
if (baseTag) {
definition.is = definition.__name;
}
}
function resolvePrototypeChain(definition) {
if (!Object.__proto__) {
var nativePrototype = HTMLElement.prototype;
if (definition.is) {
var inst = document.createElement(definition.tag);
var expectedPrototype = Object.getPrototypeOf(inst);
if (expectedPrototype === definition.prototype) {
nativePrototype = expectedPrototype;
}
}
var proto = definition.prototype, ancestor;
while (proto && proto !== nativePrototype) {
ancestor = Object.getPrototypeOf(proto);
proto.__proto__ = ancestor;
proto = ancestor;
}
definition.native = nativePrototype;
}
}
function instantiate(definition) {
return upgradeWithDefinition(domCreateElement(definition.tag), definition);
}
var registry = {};
function getRegisteredDefinition(name) {
if (name) {
return registry[name.toLowerCase()];
}
}
function registerDefinition(name, definition) {
registry[name] = definition;
}
function generateConstructor(definition) {
return function() {
return instantiate(definition);
};
}
var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
function createElementNS(namespace, tag, typeExtension) {
if (namespace === HTML_NAMESPACE) {
return createElement(tag, typeExtension);
} else {
return domCreateElementNS(namespace, tag);
}
}
function createElement(tag, typeExtension) {
var definition = getRegisteredDefinition(typeExtension || tag);
if (definition) {
if (tag == definition.tag && typeExtension == definition.is) {
return new definition.ctor();
}
if (!typeExtension && !definition.is) {
return new definition.ctor();
}
}
var element;
if (typeExtension) {
element = createElement(tag);
element.setAttribute("is", typeExtension);
return element;
}
element = domCreateElement(tag);
if (tag.indexOf("-") >= 0) {
implementPrototype(element, HTMLElement);
}
return element;
}
function cloneNode(deep) {
var n = domCloneNode.call(this, deep);
upgrade(n);
return n;
}
var domCreateElement = document.createElement.bind(document);
var domCreateElementNS = document.createElementNS.bind(document);
var domCloneNode = Node.prototype.cloneNode;
var isInstance;
if (!Object.__proto__ && !useNative) {
isInstance = function(obj, ctor) {
var p = obj;
while (p) {
if (p === ctor.prototype) {
return true;
}
p = p.__proto__;
}
return false;
};
} else {
isInstance = function(obj, base) {
return obj instanceof base;
};
}
document.registerElement = register;
document.createElement = createElement;
document.createElementNS = createElementNS;
Node.prototype.cloneNode = cloneNode;
scope.registry = registry;
scope.instanceof = isInstance;
scope.reservedTagList = reservedTagList;
scope.getRegisteredDefinition = getRegisteredDefinition;
document.register = document.registerElement;
});
(function(scope) {
var useNative = scope.useNative;
var initializeModules = scope.initializeModules;
if (useNative) {
var nop = function() {};
scope.watchShadow = nop;
scope.upgrade = nop;
scope.upgradeAll = nop;
scope.upgradeDocumentTree = nop;
scope.upgradeSubtree = nop;
scope.takeRecords = nop;
scope.instanceof = function(obj, base) {
return obj instanceof base;
};
} else {
initializeModules();
}
var upgradeDocumentTree = scope.upgradeDocumentTree;
if (!window.wrap) {
if (window.ShadowDOMPolyfill) {
window.wrap = ShadowDOMPolyfill.wrapIfNeeded;
window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded;
} else {
window.wrap = window.unwrap = function(node) {
return node;
};
}
}
function bootstrap() {
upgradeDocumentTree(wrap(document));
if (window.HTMLImports) {
HTMLImports.__importsParsingHook = function(elt) {
upgradeDocumentTree(wrap(elt.import));
};
}
CustomElements.ready = true;
setTimeout(function() {
CustomElements.readyTime = Date.now();
if (window.HTMLImports) {
CustomElements.elapsed = CustomElements.readyTime - HTMLImports.readyTime;
}
document.dispatchEvent(new CustomEvent("WebComponentsReady", {
bubbles: true
}));
});
}
if (typeof window.CustomEvent !== "function") {
window.CustomEvent = function(inType, params) {
params = params || {};
var e = document.createEvent("CustomEvent");
e.initCustomEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable), params.detail);
return e;
};
window.CustomEvent.prototype = window.Event.prototype;
}
if (document.readyState === "complete" || scope.flags.eager) {
bootstrap();
} else if (document.readyState === "interactive" && !window.attachEvent && (!window.HTMLImports || window.HTMLImports.ready)) {
bootstrap();
} else {
var loadEvent = window.HTMLImports && !HTMLImports.ready ? "HTMLImportsLoaded" : "DOMContentLoaded";
window.addEventListener(loadEvent, bootstrap);
}
})(window.CustomElements);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2012 The Polymer Authors. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
// minimal template polyfill
if (typeof HTMLTemplateElement === 'undefined') {
(function() {
var TEMPLATE_TAG = 'template';
HTMLTemplateElement = function() {}
HTMLTemplateElement.prototype = Object.create(HTMLElement.prototype);
HTMLTemplateElement.decorate = function(template) {
if (template.content) {
return;
}
template.content = template.ownerDocument.createDocumentFragment();
var child;
while (child = template.firstChild) {
template.content.appendChild(child);
}
}
HTMLTemplateElement.bootstrap = function(doc) {
var templates = doc.querySelectorAll(TEMPLATE_TAG);
Array.prototype.forEach.call(templates, function(template) {
HTMLTemplateElement.decorate(template);
});
}
// auto-bootstrapping
// boot main document
addEventListener('DOMContentLoaded', function() {
HTMLTemplateElement.bootstrap(document);
});
})();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,20 +0,0 @@
<link rel="import" href="x-collapse.html">
<link rel="import" href="x-drawer-panel.html">
<link rel="import" href="x-drawer-panel2.html">
<link rel="import" href="x-drop-button.html">
<link rel="import" href="x-icon.html">
<link rel="import" href="x-icon-button.html">
<link rel="import" href="x-item.html">
<link rel="import" href="x-overlay.html">
<link rel="import" href="x-pages.html">
<link rel="import" href="x-repeater.html">
<link rel="import" href="x-search-input.html">
<link rel="import" href="x-selector.html">
<link rel="import" href="x-submenu.html">
<link rel="import" href="x-toolbar.html">
<link rel="import" href="x-ajax.html">
<link rel="import" href="x-route/x-route.html">
<link rel="import" href="paper-button.html">
<link rel="import" href="paper-ripple.html">
<link rel="import" href="paper-spinner.html">
<link rel="import" href="paper-tabs/paper-tabs.html">

View File

@@ -1,79 +0,0 @@
<link rel="import" href="paper-ripple.html">
<style>
paper-button, .paper-button {
/* layout */
display: inline-block;
position: relative;
/* box */
min-width: 5.14em;
margin: 0 0.29em;
border-radius: 3px;
/* text */
font: inherit;
text-transform: uppercase;
xtext-align: center;
/* decoration */
xbackground: #dfdfdf;
outline: none;
/* behavior */
-webkit-user-select: none;
user-select: none;
cursor: pointer;
}
paper-button.hover:hover {
background: #d6d6d6;
}
paper-button[disabled] {
background: #eaeaea !important;
color: #a8a8a8 !important;
cursor: auto;
}
paper-button paper-ripple {
padding: 0.7em 0.57em;
}
</style>
<template>
<paper-ripple id="ripple" horizontal center-center layout>
<content></content>
</paper-ripple>
</template>
<script>
Polymer({
name: 'paper-button',
listeners: {
'ripple.click': 'clickHandler'
},
/*
features: function() {
var frag = document.createDocumentFragment();
while (this.lastChild) {
frag.appendChild(this.lastChild);
}
Base.features.call(this);
var content = this.querySelector('content');
content.parentNode.replaceChild(frag, content);
},
*/
clickHandler: function(e) {
e.stopPropagation();
setTimeout(function() {
this.fire('click', null, this);
}.bind(this), 100);
}
});
</script>

View File

@@ -1,419 +0,0 @@
<style>
paper-ripple {
display: block;
position: relative;
border-radius: inherit;
/*overflow: hidden;*/
}
/*:host-context([noink]) {
pointer-events: none;
}*/
paper-ripple #bg, paper-ripple #waves,
paper-ripple .wave-container, paper-ripple .wave {
pointer-events: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
paper-ripple #bg, paper-ripple .wave {
opacity: 0;
}
paper-ripple #waves, paper-ripple .wave {
overflow: hidden;
}
paper-ripple .wave-container, paper-ripple .wave {
border-radius: 50%;
}
paper-ripple.circle #bg,
paper-ripple.circle #waves {
border-radius: 50%;
}
paper-ripple.circle .wave-container {
overflow: hidden;
}
</style>
<!--
<template>
<div id="bg"></div>
<div id="waves"></div>
<content></content>
</template>
-->
<script>
(function() {
var waveMaxRadius = 150;
//
// INK EQUATIONS
//
function waveRadiusFn(touchDownMs, touchUpMs, anim) {
// Convert from ms to s.
var touchDown = touchDownMs / 1000;
var touchUp = touchUpMs / 1000;
var totalElapsed = touchDown + touchUp;
var ww = anim.width, hh = anim.height;
// use diagonal size of container to avoid floating point math sadness
var waveRadius = Math.min(Math.sqrt(ww * ww + hh * hh), waveMaxRadius) * 1.1 + 5;
var duration = 1.1 - .2 * (waveRadius / waveMaxRadius);
var tt = (totalElapsed / duration);
var size = waveRadius * (1 - Math.pow(80, -tt));
return Math.abs(size);
}
function waveOpacityFn(td, tu, anim) {
// Convert from ms to s.
var touchDown = td / 1000;
var touchUp = tu / 1000;
var totalElapsed = touchDown + touchUp;
if (tu <= 0) { // before touch up
return anim.initialOpacity;
}
return Math.max(0, anim.initialOpacity - touchUp * anim.opacityDecayVelocity);
}
function waveOuterOpacityFn(td, tu, anim) {
// Convert from ms to s.
var touchDown = td / 1000;
var touchUp = tu / 1000;
// Linear increase in background opacity, capped at the opacity
// of the wavefront (waveOpacity).
var outerOpacity = touchDown * 0.3;
var waveOpacity = waveOpacityFn(td, tu, anim);
return Math.max(0, Math.min(outerOpacity, waveOpacity));
}
// Determines whether the wave should be completely removed.
function waveDidFinish(wave, radius, anim) {
var waveOpacity = waveOpacityFn(wave.tDown, wave.tUp, anim);
// If the wave opacity is 0 and the radius exceeds the bounds
// of the element, then this is finished.
return waveOpacity < 0.01 && radius >= Math.min(wave.maxRadius, waveMaxRadius);
};
function waveAtMaximum(wave, radius, anim) {
var waveOpacity = waveOpacityFn(wave.tDown, wave.tUp, anim);
return waveOpacity >= anim.initialOpacity && radius >= Math.min(wave.maxRadius, waveMaxRadius);
}
//
// DRAWING
//
function drawRipple(ctx, x, y, radius, innerAlpha, outerAlpha) {
// Only animate opacity and transform
if (outerAlpha !== undefined) {
ctx.bg.style.opacity = outerAlpha;
}
ctx.wave.style.opacity = innerAlpha;
var s = radius / (ctx.containerSize / 2);
var dx = x - (ctx.containerWidth / 2);
var dy = y - (ctx.containerHeight / 2);
ctx.wc.style.webkitTransform = 'translate3d(' + dx + 'px,' + dy + 'px,0)';
ctx.wc.style.transform = 'translate3d(' + dx + 'px,' + dy + 'px,0)';
// 2d transform for safari because of border-radius and overflow:hidden clipping bug.
// https://bugs.webkit.org/show_bug.cgi?id=98538
ctx.wave.style.webkitTransform = 'scale(' + s + ',' + s + ')';
ctx.wave.style.transform = 'scale3d(' + s + ',' + s + ',1)';
}
//
// SETUP
//
function createWave(elem) {
var elementStyle = window.getComputedStyle(elem);
var fgColor = elementStyle.color;
var inner = document.createElement('div');
inner.style.backgroundColor = fgColor;
inner.classList.add('wave');
var outer = document.createElement('div');
outer.classList.add('wave-container');
outer.appendChild(inner);
var container = elem.$.waves;
container.appendChild(outer);
elem.$.bg.style.backgroundColor = fgColor;
var wave = {
bg: elem.$.bg,
wc: outer,
wave: inner,
waveColor: fgColor,
maxRadius: 0,
isMouseDown: false,
mouseDownStart: 0.0,
mouseUpStart: 0.0,
tDown: 0,
tUp: 0
};
return wave;
}
function removeWaveFromScope(scope, wave) {
if (scope.waves) {
var pos = scope.waves.indexOf(wave);
scope.waves.splice(pos, 1);
// FIXME cache nodes
wave.wc.remove();
}
};
// Shortcuts.
var pow = Math.pow;
var now = Date.now;
if (window.performance && performance.now) {
now = performance.now.bind(performance);
}
function cssColorWithAlpha(cssColor, alpha) {
var parts = cssColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
if (typeof alpha == 'undefined') {
alpha = 1;
}
if (!parts) {
return 'rgba(255, 255, 255, ' + alpha + ')';
}
return 'rgba(' + parts[1] + ', ' + parts[2] + ', ' + parts[3] + ', ' + alpha + ')';
}
function dist(p1, p2) {
return Math.sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2));
}
function distanceFromPointToFurthestCorner(point, size) {
var tl_d = dist(point, {x: 0, y: 0});
var tr_d = dist(point, {x: size.w, y: 0});
var bl_d = dist(point, {x: 0, y: size.h});
var br_d = dist(point, {x: size.w, y: size.h});
return Math.max(tl_d, tr_d, bl_d, br_d);
}
Polymer({
name: 'paper-ripple',
/**
* The initial opacity set on the wave.
*
* @attribute initialOpacity
* @type number
* @default 0.25
*/
initialOpacity: 0.25,
/**
* How fast (opacity per second) the wave fades out.
*
* @attribute opacityDecayVelocity
* @type number
* @default 0.8
*/
opacityDecayVelocity: 0.8,
backgroundFill: true,
pixelDensity: 2,
listeners: {
mousedown: 'downAction',
mouseup: 'upAction'
},
created: function() {
this.waves = [];
this.$ = {};
this.$.bg = this.appendChild(document.createElement('div'));
this.$.bg.id = 'bg';
this.$.waves = this.appendChild(document.createElement('div'));
this.$.waves.id = 'waves';
},
downAction: function(e) {
if (e.button & 2) {
// squelch right-clicks
return;
}
this.cancelled = false;
var wave = createWave(this);
wave.isMouseDown = true;
wave.tDown = 0.0;
wave.tUp = 0.0;
wave.mouseUpStart = 0.0;
wave.mouseDownStart = now();
var rect = this.getBoundingClientRect();
var width = rect.width;
var height = rect.height;
var touchX = e.x - rect.left;
var touchY = e.y - rect.top;
wave.startPosition = {x:touchX, y:touchY};
if (this.classList.contains("recenteringTouch")) {
wave.endPosition = {x: width / 2, y: height / 2};
wave.slideDistance = dist(wave.startPosition, wave.endPosition);
}
wave.containerSize = Math.max(width, height);
wave.containerWidth = width;
wave.containerHeight = height;
wave.maxRadius = distanceFromPointToFurthestCorner(wave.startPosition, {w: width, h: height});
// The wave is circular so constrain its container to 1:1
wave.wc.style.top = (wave.containerHeight - wave.containerSize) / 2 + 'px';
wave.wc.style.left = (wave.containerWidth - wave.containerSize) / 2 + 'px';
wave.wc.style.width = wave.containerSize + 'px';
wave.wc.style.height = wave.containerSize + 'px';
this.waves.push(wave);
if (!this._loop) {
this._loop = this.animate.bind(this, {
width: width,
height: height
});
requestAnimationFrame(this._loop);
}
// else there is already a rAF
},
upAction: function() {
for (var i = 0; i < this.waves.length; i++) {
// Declare the next wave that has mouse down to be mouse'ed up.
var wave = this.waves[i];
if (wave.isMouseDown) {
wave.isMouseDown = false
wave.mouseUpStart = now();
wave.mouseDownStart = 0;
wave.tUp = 0.0;
break;
}
}
this._loop && requestAnimationFrame(this._loop);
},
cancel: function() {
this.cancelled = true;
},
animate: function(ctx) {
var shouldRenderNextFrame = false;
var deleteTheseWaves = [];
// The oldest wave's touch down duration
var longestTouchDownDuration = 0;
var longestTouchUpDuration = 0;
// Save the last known wave color
var lastWaveColor = null;
// wave animation values
var anim = {
initialOpacity: this.initialOpacity,
opacityDecayVelocity: this.opacityDecayVelocity,
height: ctx.height,
width: ctx.width
}
var t = now();
for (var i = 0; i < this.waves.length; i++) {
var wave = this.waves[i];
if (wave.mouseDownStart > 0) {
wave.tDown = t - wave.mouseDownStart;
}
if (wave.mouseUpStart > 0) {
wave.tUp = t - wave.mouseUpStart;
}
// Determine how long the touch has been up or down.
var tUp = wave.tUp;
var tDown = wave.tDown;
longestTouchDownDuration = Math.max(longestTouchDownDuration, tDown);
longestTouchUpDuration = Math.max(longestTouchUpDuration, tUp);
// Obtain the instantenous size and alpha of the ripple.
var radius = waveRadiusFn(tDown, tUp, anim);
var waveAlpha = waveOpacityFn(tDown, tUp, anim);
var waveColor = cssColorWithAlpha(wave.waveColor, waveAlpha);
lastWaveColor = wave.waveColor;
// Position of the ripple.
var x = wave.startPosition.x;
var y = wave.startPosition.y;
// Ripple gravitational pull to the center of the canvas.
if (wave.endPosition) {
// This translates from the origin to the center of the view based on the max dimension of
var translateFraction = Math.min(1, radius / wave.containerSize * 2 / Math.sqrt(2) );
x += translateFraction * (wave.endPosition.x - wave.startPosition.x);
y += translateFraction * (wave.endPosition.y - wave.startPosition.y);
}
// If we do a background fill fade too, work out the correct color.
var bgFillColor = null;
if (this.backgroundFill) {
var bgFillAlpha = waveOuterOpacityFn(tDown, tUp, anim);
bgFillColor = cssColorWithAlpha(wave.waveColor, bgFillAlpha);
}
// Draw the ripple.
drawRipple(wave, x, y, radius, waveAlpha, bgFillAlpha);
// Determine whether there is any more rendering to be done.
var maximumWave = waveAtMaximum(wave, radius, anim);
var waveDissipated = waveDidFinish(wave, radius, anim);
var shouldKeepWave = !waveDissipated || maximumWave;
// keep rendering dissipating wave when at maximum radius on upAction
var shouldRenderWaveAgain = wave.mouseUpStart ? !waveDissipated : !maximumWave;
shouldRenderNextFrame = shouldRenderNextFrame || shouldRenderWaveAgain;
if (!shouldKeepWave || this.cancelled) {
deleteTheseWaves.push(wave);
}
}
if (shouldRenderNextFrame) {
requestAnimationFrame(this._loop);
}
for (var i = 0; i < deleteTheseWaves.length; ++i) {
var wave = deleteTheseWaves[i];
removeWaveFromScope(this, wave);
}
if (!this.waves.length && this._loop) {
// clear the background color
this.$.bg.style.backgroundColor = null;
this._loop = null;
this.fire('core-transitionend');
}
}
});
})();
</script>

View File

@@ -1,542 +0,0 @@
<!--
@license
Copyright (c) 2014 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
-->
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../polymer/data.html">
<!--
Element providing material design circular spinner.
##### Example
<paper-spinner id="spinner" active></paper-spinner>
@element paper-spinner
@blurb Element providing material design circular spinner.
@status alpha
@homepage http://polymerlabs.github.io/paper-spinner
-->
<style>
/*
* Constants:
* STROKEWIDTH = 3px
* ARCSIZE = 270 degrees (amount of circle the arc takes up)
* ARCTIME = 1333ms (time it takes to expand and contract arc)
* ARCSTARTROT = 216 degrees (how much the start location of the arc
* should rotate each time, 216 gives us a
* 5 pointed star shape (it's 360/5 * 3).
* For a 7 pointed star, we might do
* 360/7 * 3 = 154.286)
* CONTAINERWIDTH = 28px
* SHRINK_TIME = 400ms
*/
paper-spinner {
display: inline-block;
position: relative;
width: 28px; /* CONTAINERWIDTH */
height: 28px; /* CONTAINERWIDTH */
}
paper-spinner #container {
width: 100%;
height: 100%;
}
paper-spinner #container.active {
/* duration: 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
-webkit-animation: container-rotate 1568ms linear infinite;
animation: container-rotate 1568ms linear infinite;
}
@-webkit-keyframes container-rotate {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@keyframes container-rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
paper-spinner .circle-container {
width: 100%;
height: 100%;
}
paper-spinner .active .circle-container {
/* duration: 4 * ARCTIME */
-webkit-animation: circle-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite;
animation: circle-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite;
}
@-webkit-keyframes circle-rotate {
from {
-webkit-transform: rotate(0deg); /* 0 * ARCSIZE */
}
12.5% {
-webkit-transform: rotate(135deg); /* 0.5 * ARCSIZE */
}
25% {
-webkit-transform: rotate(270deg); /* 1 * ARCSIZE */
}
37.5% {
-webkit-transform: rotate(405deg); /* 1.5 * ARCSIZE */
}
50% {
-webkit-transform: rotate(540deg); /* 2 * ARCSIZE */
}
62.5% {
-webkit-transform: rotate(675deg); /* 2.5 * ARCSIZE */
}
75% {
-webkit-transform: rotate(810deg); /* 3 * ARCSIZE */
}
87.5% {
-webkit-transform: rotate(945deg); /* 3.5 * ARCSIZE */
}
to {
-webkit-transform: rotate(1080deg); /* 4 * ARCSIZE */
}
}
@keyframes circle-rotate {
from {
transform: rotate(0deg); /* 0 * ARCSIZE */
}
12.5% {
transform: rotate(135deg); /* 0.5 * ARCSIZE */
}
25% {
transform: rotate(270deg); /* 1 * ARCSIZE */
}
37.5% {
transform: rotate(405deg); /* 1.5 * ARCSIZE */
}
50% {
transform: rotate(540deg); /* 2 * ARCSIZE */
}
62.5% {
transform: rotate(675deg); /* 2.5 * ARCSIZE */
}
75% {
transform: rotate(810deg); /* 3 * ARCSIZE */
}
87.5% {
transform: rotate(945deg); /* 3.5 * ARCSIZE */
}
to {
transform: rotate(1080deg); /* 4 * ARCSIZE */
}
}
paper-spinner .circle-clipper {
display: inline-block;
position: relative;
width: 50%;
height: 100%;
overflow: hidden;
}
paper-spinner .circle {
box-sizing: border-box;
width: 200%;
height: 100%;
border-bottom-color: transparent !important;
border-width: 3px; /* STROKEWIDTH */
border-style: solid;
border-radius: 50%;
opacity: 0;
-webkit-animation: none;
animation: none;
}
paper-spinner .circle.left {
border-right-color: transparent !important;
-webkit-transform: rotate(129deg);
transform: rotate(129deg);
}
paper-spinner .circle.right {
left: -100%;
border-left-color: transparent !important;
-webkit-transform: rotate(-129deg);
transform: rotate(-129deg);
}
paper-spinner .circle.blue {
border-color: #4285f4;
}
paper-spinner .circle.red {
border-color: #db4437;
}
paper-spinner .circle.yellow {
border-color: #f4b400;
}
paper-spinner .circle.green {
border-color: #0f9d58;
}
/**
* IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee):
*
* iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't
* guarantee that the animation will start _exactly_ after that value. So we avoid using
* animation-delay and instead set custom keyframes for each color (as redundant as it
* seems).
*
* We write out each animation in full below (instead of animation-name, animation-duration,
* etc.) because under the polyfill, Safari does not recognize those specific properties
* properly, treats them as -webkit-animation, and overrides the other animation rules.
* See https://github.com/Polymer/platform/issues/53.
*/
paper-spinner .active .circle.blue.left {
/* duration: ARCTIME, 4 * ARCTIME */
-webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
paper-spinner .active .circle.blue.right {
/* duration: ARCTIME, 4 * ARCTIME */
-webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
paper-spinner .active .circle.red.left {
/* duration: ARCTIME, 4 * ARCTIME */
-webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
paper-spinner .active .circle.red.right {
/* duration: ARCTIME, 4 * ARCTIME */
-webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
paper-spinner .active .circle.yellow.left {
/* duration: ARCTIME, 4 * ARCTIME */
-webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
paper-spinner .active .circle.yellow.right {
/* duration: ARCTIME, 4 * ARCTIME */
-webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
paper-spinner .active .circle.green.left {
/* duration: ARCTIME, 4 * ARCTIME */
-webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
paper-spinner .active .circle.green.right {
/* duration: ARCTIME, 4 * ARCTIME */
-webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
@-webkit-keyframes left-spin {
from {
-webkit-transform: rotate(130deg);
}
50% {
-webkit-transform: rotate(-5deg);
}
to {
-webkit-transform: rotate(130deg);
}
}
@keyframes left-spin {
from {
transform: rotate(130deg);
}
50% {
transform: rotate(-5deg);
}
to {
transform: rotate(130deg);
}
}
@-webkit-keyframes right-spin {
from {
-webkit-transform: rotate(-130deg);
}
50% {
-webkit-transform: rotate(5deg);
}
to {
-webkit-transform: rotate(-130deg);
}
}
@keyframes right-spin {
from {
transform: rotate(-130deg);
}
50% {
transform: rotate(5deg);
}
to {
transform: rotate(-130deg);
}
}
@-webkit-keyframes blue-fade-in-out {
from {
opacity: 1;
}
25% {
opacity: 1;
}
26% {
opacity: 0;
}
89% {
opacity: 0;
}
90% {
opacity: 1;
}
100% {
opacity: 1;
}
}
@keyframes blue-fade-in-out {
from {
opacity: 1;
}
25% {
opacity: 1;
}
26% {
opacity: 0;
}
89% {
opacity: 0;
}
90% {
opacity: 1;
}
100% {
opacity: 1;
}
}
@-webkit-keyframes red-fade-in-out {
from {
opacity: 0;
}
15% {
opacity: 0;
}
25% {
opacity: 1;
}
50% {
opacity: 1;
}
51% {
opacity: 0;
}
}
@keyframes red-fade-in-out {
from {
opacity: 0;
}
15% {
opacity: 0;
}
25% {
opacity: 1;
}
50% {
opacity: 1;
}
51% {
opacity: 0;
}
}
@-webkit-keyframes yellow-fade-in-out {
from {
opacity: 0;
}
40% {
opacity: 0;
}
50% {
opacity: 1;
}
75% {
opacity: 1;
}
76% {
opacity: 0;
}
}
@keyframes yellow-fade-in-out {
from {
opacity: 0;
}
40% {
opacity: 0;
}
50% {
opacity: 1;
}
75% {
opacity: 1;
}
76% {
opacity: 0;
}
}
@-webkit-keyframes green-fade-in-out {
from {
opacity: 0;
}
65% {
opacity: 0;
}
75% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes green-fade-in-out {
from {
opacity: 0;
}
65% {
opacity: 0;
}
75% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
opacity: 0;
}
}
paper-spinner .warmdown .circle-clipper {
/* duration: SHRINK_TIME */
-webkit-animation: fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
animation: fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
}
@-webkit-keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
</style>
<template>
<div id="container">
<div class="circle-container">
<div class="circle-clipper">
<div class="circle left blue" fit></div>
<div class="circle left red" fit></div>
<div class="circle left yellow" fit></div>
<div class="circle left green" fit></div>
<!-- No space between div.circle-clipper. -->
</div><div class="circle-clipper">
<div class="circle right blue" fit></div>
<div class="circle right red" fit></div>
<div class="circle right yellow" fit></div>
<div class="circle right green" fit></div>
</div>
</div>
</div>
</template>
<script>
Polymer({
name: 'paper-spinner',
listeners: {
'animationend': 'reset',
'webkitAnimationEnd': 'reset'
},
published: {
/**
* Displays the spinner.
*
* @attribute active
* @type boolean
* @default false
*/
active: Boolean
},
bind: {
active: 'activeChanged'
},
activeChanged: function() {
this.$.container.classList.add(this.active ? 'active' : 'warmdown');
},
reset: function() {
this.$.container.classList.remove('active', 'warmdown');
}
});
</script>

View File

@@ -1,229 +0,0 @@
<!--
@license
Copyright (c) 2014 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
-->
<!doctype html>
<html>
<head>
<title>paper-tabs</title>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
<script src="../webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="../core-icons/core-icons.html">
<link rel="import" href="../font-roboto/roboto.html">
<link rel="import" href="paper-tabs.html">
<link rel="import" href="../core-toolbar/core-toolbar.html">
<link rel="import" href="../core-media-query/core-media-query.html">
<link rel="import" href="../paper-icon-button/paper-icon-button.html">
<style shim-shadowdom>
body {
font-family: RobotoDraft, 'Helvetica Neue', Helvetica, Arial;
margin: 0;
padding: 24px;
color: #333;
}
body.core-narrow {
padding: 8px;
}
paper-tabs, core-toolbar {
background-color: #00bcd4;
color: #fff;
box-shadow: 0px 3px 2px rgba(0, 0, 0, 0.2);
}
core-toolbar paper-tabs {
box-shadow: none;
}
paper-tabs[noink][nobar] paper-tab.core-selected {
color: #ffff8d;
}
paper-tabs.transparent-teal {
background-color: transparent;
color: #00bcd4;
box-shadow: none;
}
paper-tabs.transparent-teal::shadow #selectionBar {
background-color: #00bcd4;
}
paper-tabs.transparent-teal paper-tab::shadow #ink {
color: #00bcd4;
}
h3 {
font-size: 16px;
font-weight: 400;
}
</style>
</head>
<body unresolved>
<h3>A. No ink effect and no sliding bar</h3>
<paper-tabs selected="0" noink nobar>
<paper-tab>ITEM ONE</paper-tab>
<paper-tab>ITEM TWO</paper-tab>
<paper-tab>ITEM THREE</paper-tab>
</paper-tabs>
<br>
<br>
<h3>B. The bottom bar appears to indicate the selected tab, but without sliding effect.</h3>
<paper-tabs selected="0" noink noslide>
<paper-tab>ITEM ONE</paper-tab>
<paper-tab>ITEM TWO</paper-tab>
<paper-tab>ITEM THREE</paper-tab>
</paper-tabs>
<br>
<br>
<h3>C. The bar slides to the selected tab</h3>
<paper-tabs selected="0" noink>
<paper-tab>ITEM ONE</paper-tab>
<paper-tab>ITEM TWO</paper-tab>
<paper-tab>ITEM THREE</paper-tab>
</paper-tabs>
<br>
<br>
<h3>D. Inky Tabs</h3>
<paper-tabs selected="0">
<paper-tab>ITEM ONE</paper-tab>
<paper-tab>ITEM TWO</paper-tab>
<paper-tab>ITEM THREE</paper-tab>
</paper-tabs>
<br>
<br>
<paper-tabs selected="0" class="transparent-teal">
<paper-tab>ITEM ONE</paper-tab>
<paper-tab>ITEM TWO</paper-tab>
<paper-tab>ITEM THREE</paper-tab>
</paper-tabs>
<br>
<br>
<h3>E. Scrollable Tabs</h3>
<paper-tabs id="scrollableTabs" selected="0" scrollable>
<paper-tab>NUMBER ONE ITEM</paper-tab>
<paper-tab>ITEM TWO</paper-tab>
<paper-tab>THE THIRD ITEM</paper-tab>
<paper-tab>THE ITEM FOUR</paper-tab>
<paper-tab>FIFTH</paper-tab>
<paper-tab>THE SIXTH TAB</paper-tab>
<paper-tab>NUMBER SEVEN</paper-tab>
<paper-tab>EIGHT</paper-tab>
<paper-tab>NUMBER NINE</paper-tab>
<paper-tab>THE TENTH</paper-tab>
<paper-tab>THE ITEM ELEVEN</paper-tab>
<paper-tab>TWELFTH ITEM</paper-tab>
</paper-tabs>
<br>
<br>
<h3>F. Link Tabs</h3>
<paper-tabs selected="0" link>
<paper-tab><a href="#item1" horizontal center-center layout>ITEM ONE</a></paper-tab>
<paper-tab><a href="#item2" horizontal center-center layout>ITEM TWO</a></paper-tab>
<paper-tab><a href="#item3" horizontal center-center layout>ITEM THREE</a></paper-tab>
</paper-tabs>
<br>
<br>
<h3>G. Tabs in Toolbar</h3>
<core-toolbar class="medium-tall">
<paper-icon-button icon="menu"></paper-icon-button>
<div flex>Title</div>
<paper-icon-button icon="search"></paper-icon-button>
<paper-icon-button icon="more-vert"></paper-icon-button>
<div class="bottom fit" horizontal layout>
<paper-tabs selected="0" flex style="max-width: 600px;">
<paper-tab>ITEM ONE</paper-tab>
<paper-tab>ITEM TWO</paper-tab>
<paper-tab>ITEM THREE</paper-tab>
</paper-tabs>
</div>
</core-toolbar>
<br>
<br>
<core-toolbar class="tall">
<paper-tabs selected="0" class="bottom" self-end style="width: 300px;">
<paper-tab>ITEM ONE</paper-tab>
<paper-tab>ITEM TWO</paper-tab>
</paper-tabs>
<div class="bottom" flex></div>
<paper-icon-button class="bottom" icon="search"></paper-icon-button>
</core-toolbar>
<!-- detect when window is narrow -->
<core-media-query id="mediaQuery" query="max-width: 640px"></core-media-query>
<script>
document.querySelector('#mediaQuery').addEventListener('core-media-change',
function(e) {
document.body.classList.toggle('core-narrow', e.detail.matches);
document.querySelector('#scrollableTabs').updateBar();
});
</script>
</body>
</html>

View File

@@ -1,32 +0,0 @@
<!doctype html>
<html>
<head>
<script src="../../../perf-lib/perf.js"></script>
<title>paper-tabs test</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="import" href="src/x-app.html">
<link rel="import" href="../../../assets/icons.html">
<style>
body {
font-family: sans-serif;
font-size: 15px;
}
</style>
</head>
<body fullbleed vertical layout>
<script>console.perf();</script>
<x-app flex></x-app>
<script>console.perfEnd();</script>
</body>
</html>

View File

@@ -1,61 +0,0 @@
<link rel="import" href="../../../../polymer/polymer.html">
<link rel="import" href="../../../../polymer/data.html">
<link rel="import" href="../../../paper-tabs/paper-tab.html">
<link rel="import" href="../../../paper-tabs/paper-tabs.html">
<style>
x-app {
display: block;
}
x-app > div {
background-color: blue;
color: white;
}
x-app paper-tabs {
background-color: blue;
color: white;
}
x-app div paper-tab {
padding: 8px 0;
}
x-app hr {
margin-left: 0;
margin-right: 0;
}
</style>
<template>
<br>
<div>
<paper-tab>I'm a Tab</paper-tab>
<paper-tab>I'm a Tab</paper-tab>
</div>
<hr>
<paper-tabs>
<paper-tab>I'm a Tab</paper-tab>
<paper-tab>I'm a Tab</paper-tab>
<paper-tab>I'm a Tab</paper-tab>
</paper-tabs>
</template>
<script>
Polymer({
name: 'x-app',
hostAttributes: 'vertical layout'
});
</script>

View File

@@ -1,59 +0,0 @@
/*
Copyright (c) 2014 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
*/
:host {
position: relative;
overflow: hidden;
cursor: default;
}
.tab-content {
transition: opacity .1s cubic-bezier(0.4, 0.0, 1, 1), color .1s cubic-bezier(0.4, 0.0, 1, 1);
height: 100%;
margin: 0 12px;
}
:host-context(#tabsContainer.scrollable) .tab-content {
margin: 0 24px;
}
:host-context(paper-tabs[link]) .tab-content {
margin: 0 !important;
}
polyfill-next-selector { content: '.core-narrow #tabsContainer.scrollable :host .tab-content'; }
:host-context(.core-narrow):host-context(#tabsContainer.scrollable) .tab-content {
margin: 0 12px;
}
:host(:not(.core-selected)) .tab-content {
opacity: 0.6;
}
#ink {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
color: #ffff8d;
pointer-events: none;
}
polyfill-next-selector { content: '.tab-content > a'; }
::content > a {
height: 100%;
padding: 0 12px;
/* flex */
-ms-flex: 1 1 0.000000001px;
-webkit-flex: 1;
flex: 1;
-webkit-flex-basis: 0.000000001px;
flex-basis: 0.000000001px;
}

View File

@@ -1,140 +0,0 @@
<!--
Copyright (c) 2014 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
-->
<!--
`paper-tab` is styled to look like a tab. It should be used in conjunction with
`paper-tabs`.
Example:
<paper-tabs selected="0">
<paper-tab>TAB 1</paper-tab>
<paper-tab>TAB 2</paper-tab>
<paper-tab>TAB 3</paper-tab>
</paper-tabs>
Styling tab:
To change the ink color:
.pink paper-tab::shadow #ink {
color: #ff4081;
}
@group Paper Elements
@element paper-tab
@homepage github.io
-->
<link rel="import" href="../paper-ripple.html">
<style>
paper-tab {
position: relative;
overflow: hidden;
cursor: default;
}
paper-tab .tab-content {
transition: opacity .1s cubic-bezier(0.4, 0.0, 1, 1), color .1s cubic-bezier(0.4, 0.0, 1, 1);
height: 100%;
margin: 0 12px;
}
.scrollable paper-tab .tab-content {
margin: 0 24px;
}
paper-tabs[link] paper-tab .tab-content {
margin: 0 !important;
}
.core-narrow #tabsContainer.scrollable paper-tab .tab-content {
margin: 0 12px;
}
paper-tab:not([selected]) .tab-content {
opacity: 0.6;
}
paper-tab #ink {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
color: #ffff8d;
pointer-events: none;
}
paper-tab .tab-content > a {
height: 100%;
padding: 0 12px;
/* flex */
-ms-flex: 1 1 0.000000001px;
-webkit-flex: 1;
flex: 1;
-webkit-flex-basis: 0.000000001px;
flex-basis: 0.000000001px;
}
</style>
<template>
<div class="tab-content" flex auto horizontal center-center layout>
<content></content>
</div>
<paper-ripple id="ink" initialOpacity="0.95" opacityDecayVelocity="0.98"></paper-ripple>
</template>
<script>
Polymer({
name: 'paper-tab',
hostAttributes: 'noink inline horizontal center-center layout',
role: 'tab',
/**
* If true, ink ripple effect is disabled.
*
* @attribute noink
* @type boolean
* @default false
*/
noink: false,
listeners: {
mousedown: 'downAction',
mouseup: 'upAction'
},
downAction: function(e) {
if (this.noink || (this.parentElement && this.parentElement.noink)) {
return;
}
this.$.ink.downAction(e);
},
upAction: function() {
this.$.ink.upAction();
},
cancelRipple: function() {
this.$.ink.upAction();
}
});
</script>

View File

@@ -1,75 +0,0 @@
/*
Copyright (c) 2014 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
*/
:host {
display: block;
font-size: 14px;
font-weight: 500;
height: 48px;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
#tabsContainer {
position: relative;
height: 100%;
white-space: nowrap;
overflow: hidden;
}
#tabsContent {
height: 100%;
}
#tabsContainer.scrollable > #tabsContent {
position: absolute;
white-space: nowrap;
}
.scroll-button {
width: 40px;
padding: 0 12px;
}
.scroll-button > paper-icon-button {
transition: opacity 0.18s;
}
.scroll-button > .hidden {
opacity: 0;
}
#selectionBar {
position: absolute;
height: 2px;
bottom: 0;
left: 0;
width: 0;
background-color: #ffff8d;
transition: width, left;
}
#selectionBar.expand {
transition-duration: 0.15s;
transition-timing-function: cubic-bezier(0.4, 0.0, 1, 1);
}
#selectionBar.contract {
transition-duration: 0.18s;
transition-timing-function: cubic-bezier(0.0, 0.0, 0.2, 1);
}
polyfill-next-selector { content: '#tabsContent > *:not(#selectionBar)'; }
::content > * {
height: 100%;
}

View File

@@ -1,320 +0,0 @@
<!--
Copyright (c) 2014 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
-->
<link rel="import" href="../x-selector.html">
<link rel="import" href="paper-tab.html">
<!--
`paper-tabs` is a `core-selector` styled to look like tabs. Tabs make it easy to
explore and switch between different views or functional aspects of an app, or
to browse categorized data sets.
Use `selected` property to get or set the selected tab.
Example:
<paper-tabs selected="0">
<paper-tab>TAB 1</paper-tab>
<paper-tab>TAB 2</paper-tab>
<paper-tab>TAB 3</paper-tab>
</paper-tabs>
See <a href="#paper-tab">paper-tab</a> for more information about
`paper-tab`.
A common usage for `paper-tabs` is to use it along with `core-pages` to switch
between different views.
<paper-tabs selected="{{selected}}">
<paper-tab>Tab 1</paper-tab>
<paper-tab>Tab 2</paper-tab>
<paper-tab>Tab 3</paper-tab>
</paper-tabs>
<core-pages selected="{{selected}}>
<div>Page 1</div>
<div>Page 2</div>
<div>Page 3</div>
</core-pages>
`paper-tabs` adapt to mobile/narrow layout when there is a `core-narrow` class set
on itself or any of its ancestors.
To use links in tabs, add `link` attribute to `paper-tabs` and put an `<a>`
element in `paper-tab`.
Example:
<paper-tabs selected="0" link>
<paper-tab>
<a href="#link1" horizontal center-center layout>TAB ONE</a>
</paper-tab>
<paper-tab>
<a href="#link2" horizontal center-center layout>TAB TWO</a>
</paper-tab>
<paper-tab>
<a href="#link3" horizontal center-center layout>TAB THREE</a>
</paper-tab>
</paper-tabs>
Styling tabs:
To change the sliding bar color:
paper-tabs.pink::shadow #selectionBar {
background-color: #ff4081;
}
To change the ink ripple color:
paper-tabs.pink paper-tab::shadow #ink {
color: #ff4081;
}
@group Paper Elements
@element paper-tabs
@extends core-selector
@homepage github.io
-->
<style>
paper-tabs {
display: block;
font-size: 14px;
font-weight: 500;
height: 48px;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
paper-tabs #tabsContainer {
position: relative;
height: 100%;
white-space: nowrap;
overflow: hidden;
}
paper-tabs #tabsContent {
height: 100%;
}
paper-tabs #tabsContainer.scrollable > #tabsContent {
position: absolute;
white-space: nowrap;
}
paper-tabs .scroll-button {
width: 40px;
padding: 0 12px;
}
paper-tabs .scroll-button > paper-icon-button {
transition: opacity 0.18s;
}
paper-tabs .scroll-button > .hidden {
opacity: 0;
}
paper-tabs #selectionBar {
position: absolute;
height: 2px;
bottom: 0;
left: 0;
width: 0;
background-color: #ffff8d;
transition: width, left;
}
paper-tabs #selectionBar.expand {
transition-duration: 0.15s;
transition-timing-function: cubic-bezier(0.4, 0.0, 1, 1);
}
paper-tabs #selectionBar.contract {
transition-duration: 0.18s;
transition-timing-function: cubic-bezier(0.0, 0.0, 0.2, 1);
}
paper-tabs #tabsContent > *:not(#selectionBar) {
height: 100%;
}
</style>
<template>
<x-selector id="tabsContainer" flex selected="{{selectedItem}}" index="{{index}}" selectable="paper-tab" class="scrollable" on-scroll="scroll">
<div id="tabsContent" horizontal layout>
<content></content>
<div id="selectionBar" hidden="{{nobar}}" on-transitionend="barTransitionEnd"></div>
</div>
</x-selector>
</template>
<script>
Polymer({
name: 'paper-tabs',
hostAttributes: 'vertical layout',
published: {
index: {
type: Number,
notify: true
}
},
/**
* If true, ink ripple effect is disabled.
*
* @attribute noink
* @type boolean
* @default false
*/
noink: false,
/**
* If true, the bottom bar to indicate the selected tab will not be shown.
*
* @attribute nobar
* @type boolean
* @default false
*/
nobar: false,
/**
* If true, the slide effect for the bottom bar is disabled.
*
* @attribute noslide
* @type boolean
* @default false
*/
noslide: false,
/**
* If true, tabs are scrollable and the tab width is based on the label width.
*
* @attribute scrollable
* @type boolean
* @default false
*/
scrollable: false,
bind: {
selectedItem: 'selectedItemChanged',
barColor: 'barColorChanged'
},
/**
* Invoke this to update the size and position of the bottom bar. Usually
* you only need to call this if the `paper-tabs` is initially hidden and
* later becomes visible.
*
* @method updateBar
*/
updateBar: function() {
this.async('selectedItemChanged');
},
selectedItemChanged: function(item, old) {
var s = this.$.selectionBar.style;
if (!item) {
s.width = 0;
s.left = 0;
return;
}
var r = this.$.tabsContent.getBoundingClientRect();
w = r.width;
l = r.left;
r = item.getBoundingClientRect();
sw = r.width;
sl = r.left;
sOffsetLeft = sl - l;
this._pos = {
width: this.calcPercent(sw, w) + '%',
left: this.calcPercent(sOffsetLeft, w) + '%'
};
if (this.noslide || old == null) {
this.positionBarForSelected();
return;
}
this.$.selectionBar.classList.add('expand');
var oldRect = old.getBoundingClientRect();
var oldIndex = this.$.tabsContainer.indexOfItem(old);
var newIndex = this.$.tabsContainer.index;
var m = 5;
if (oldIndex < newIndex) {
s.width = this.calcPercent(sl + sw - oldRect.left, w) - m + '%';
this._transitionCounter = 1;
} else {
s.width = this.calcPercent(oldRect.left + oldRect.width - sl, w) - m + '%';
s.left = this.calcPercent(sOffsetLeft, w) + m + '%';
this._transitionCounter = 2;
}
if (this.scrollable) {
this.scrollToSelectedIfNeeded();
}
},
calcPercent: function(w, w0) {
return 100 * w / w0;
},
positionBarForSelected: function() {
var s = this.$.selectionBar.style;
s.width = this._pos.width;
s.left = this._pos.left;
},
barTransitionEnd: function(e) {
var cl = this.$.selectionBar.classList;
if (cl.contains('expand')) {
if (--this._transitionCounter === 0) {
cl.remove('expand');
cl.add('contract');
this.positionBarForSelected();
}
} else if (cl.contains('contract')) {
cl.remove('contract');
}
},
barColorChanged: function(color) {
this.$.selectionBar.style.backgroundColor = color;
}
});
</script>
</polymer-element>

View File

@@ -1,31 +0,0 @@
<script>
Polymer({
name: 'x-ajax',
method: 'GET',
url: 'http://www.json-generator.com/api/json/get/cezCjjAaZK?indent=2',
send: function() {
var xhr = new XMLHttpRequest();
xhr.open(this.method, this.url);
xhr.send();
xhr.onreadystatechange = function() {
this.readyStateChange(xhr);
}.bind(this);
},
readyStateChange: function(xhr) {
if (xhr.readyState == 4) {
this.handleResponse(xhr)
}
},
handleResponse: function(xhr) {
this.fire('ajax-response', xhr)
}
});
</script>

View File

@@ -1,58 +0,0 @@
<style>
x-collapse {
display: block;
overflow: hidden;
}
x-collapse[animate] {
transition: height 200ms ease-in;
/*
transition-property: width, height;
transition-duration: 200ms;
transition-timing-function: ease-in;
*/
}
</style>
<script>
Polymer({
name: 'x-collapse',
listeners: {
click: 'clickAction'
},
created: function() {
this.async(this.setup);
},
setup: function() {
this.rect = this.getBoundingClientRect();
if (!this.open) {
this.style.height = 0;
}
this.setAttribute('animate', '');
console.log(this.rect);
},
toggle: function() {
this.open = !this.open;
},
clickAction: function() {
this.toggle();
},
set open(open) {
this._open = open;
this.style.height = open ? this.rect.height + 'px' : 0;
},
get open() {
return this._open;
}
})
</script>

View File

@@ -1,7 +0,0 @@
core-doc-viewer
================
See the [component page](http://polymer-project.org/docs/x-elements/core-x-elements.html#core-doc-viewer) for more information.
**Note** If you update x-elements in this repo, you'll need to rebuild `build.sh` in [core-component-page-dev](https://github.com/Polymer/core-component-page-dev) so they're used in the compiled version (core-component-page).

View File

@@ -1,45 +0,0 @@
<!doctype html>
<!--
@license
Copyright (c) 2014 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
-->
<html>
<head>
<title>x-doc-viewer</title>
<script src="../../perf-lib/perf.js"></script>
<link rel="import" href="x-doc-viewer.html">
<link rel="import" href="../../assets/icons.html">
<style>
html, body {
font-family: Arial, sans-serif;
margin: 0;
}
</style>
</head>
<body fullbleed vertical layout>
<script>console.perf();</script>
<x-doc-viewer flex sources='[
"../../polymer/src/features/bind.html",
"x-doc-viewer.html"
]'></x-doc-viewer>
<script>console.perfEnd();</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More