clean up the demo

This commit is contained in:
Geoff Schmidt
2012-08-15 20:42:50 -07:00
parent 5d8038cae1
commit 0241f84b56
10 changed files with 276 additions and 141 deletions

View File

@@ -152,7 +152,7 @@ Commands.push({
var example_dir = path.join(__dirname, '../../examples');
var examples = _.reject(fs.readdirSync(example_dir), function (e) {
return (e === 'unfinished');
return (e === 'unfinished' || e === 'other');
});
if (argv._.length === 1) {

View File

@@ -1,20 +0,0 @@
/* CSS declarations go here */
@-webkit-keyframes spinForward {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-webkit-keyframes spinBackward {
from {-webkit-transform: rotate(360deg);}
to {-webkit-transform: rotate(0deg);}
}
.spinner {
width: 100px;
border: 2px solid black;
font-weight: bold;
text-align: center;
background: white;
}

View File

@@ -1,87 +0,0 @@
<head>
<title>landmark-demo</title>
</head>
<body>
<h1>Spark demo</h1>
{{> redrawButtons }}
{{> preserveDemo }}
{{> constantDemo }}
{{> stateDemo }}
{{> d3Demo }}
</body>
<template name="redrawButtons">
<input type="button" value="X++" class="x">
<input type="button" value="Y++" class="y">
<input type="button" value="Z++" class="z">
<br>
</template>
<template name="preserveDemo">
<h2>Simple element preservation</h2>
X={{x}}<br>
<div class="spinner" style="-webkit-animation: {{spinAnim}} 2s infinite linear">
X={{x}}
</div>
<div>
<input type="checkbox" class="spinforward" {{spinForwardChecked}}>
Spin Forward
</div>
X={{x}}
</template>
<template name="constantDemo">
<h2>Constant regions</h2>
X={{x}}<br>
{{#constant}}
<div style="float: left; padding-right: 20px;">
<iframe width="200" height="200" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=140+10th+Street,+San+Francisco,+CA&amp;aq=0&amp;oq=140+10th+s&amp;sll=37.7577,-122.4376&amp;sspn=0.166931,0.329247&amp;ie=UTF8&amp;hq=&amp;hnear=140+10th+St,+San+Francisco,+California+94103&amp;t=m&amp;ll=37.774921,-122.415419&amp;spn=0.013569,0.017252&amp;z=14&amp;iwloc=A&amp;output=embed"></iframe><br /><small><a href="https://maps.google.com/maps?f=q&amp;source=embed&amp;hl=en&amp;geocode=&amp;q=140+10th+Street,+San+Francisco,+CA&amp;aq=0&amp;oq=140+10th+s&amp;sll=37.7577,-122.4376&amp;sspn=0.166931,0.329247&amp;ie=UTF8&amp;hq=&amp;hnear=140+10th+St,+San+Francisco,+California+94103&amp;t=m&amp;ll=37.774921,-122.415419&amp;spn=0.013569,0.017252&amp;z=14&amp;iwloc=A" style="color:#0000FF;text-align:left">View Larger Map</a></small>
</div>
{{/constant}}
{{#constant}}
<div>
<iframe width="200" height="200" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=880+Harrison+Street,+San+Francisco,+CA&amp;aq=0&amp;oq=880+harrison&amp;sll=37.7577,-122.4376&amp;sspn=0.166931,0.329247&amp;ie=UTF8&amp;hq=&amp;hnear=880+Harrison+St,+San+Francisco,+California+94107&amp;t=m&amp;ll=37.779534,-122.411213&amp;spn=0.013568,0.01708&amp;z=14&amp;iwloc=A&amp;output=embed"></iframe><br /><small><a href="https://maps.google.com/maps?f=q&amp;source=embed&amp;hl=en&amp;geocode=&amp;q=880+Harrison+Street,+San+Francisco,+CA&amp;aq=0&amp;oq=880+harrison&amp;sll=37.7577,-122.4376&amp;sspn=0.166931,0.329247&amp;ie=UTF8&amp;hq=&amp;hnear=880+Harrison+St,+San+Francisco,+California+94107&amp;t=m&amp;ll=37.779534,-122.411213&amp;spn=0.013568,0.01708&amp;z=14&amp;iwloc=A" style="color:#0000FF;text-align:left">View Larger Map</a></small>
</div>
{{/constant}}
X={{x}}
</template>
<template name="stateDemo">
<h2>Template callbacks</h2>
X={{x}}<br>
<input type="button" value="Create a timer" class="create"><br>
{{#each timers}}
<div>
{{> timer}}
Y={{y}}
</div>
{{/each}}
X={{x}}
</template>
<template name="timer">
<span class="elapsed"></span>
<input type="button" value="Reset" class="reset">
<input type="button" value="Delete" class="delete">
Z={{z}}
</template>
<template name="d3Demo">
<h2>Simple d3.js integration</h2>
{{> circles left}}
{{> circles right}}
</template>
<template name="circles">
<div style="float: left; padding-right: 20px;">
{{#constant}}
<svg width="200" height="200" class="xyzzy"></svg>
{{/constant}}
<br>
{{count}} circles<br>
<input type="button" value="Add" class="add">
<input type="button" value="Remove" class="remove" {{{disabled}}}>
<input type="button" value="Scram" class="scram">
</div>
</template>

View File

@@ -0,0 +1,44 @@
body {
font-family: 'Helvetica Neue', Helvetica, Arial, san-serif;
width: 600px;
margin: auto;
padding: 25px 50px;
border: 5px dashed #ccc;
border-style: none dashed;
}
h2 {
margin-top: 50px;
text-decoration: underline;
}
.clearboth {
clear: both;
}
@-webkit-keyframes spinForward {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-webkit-keyframes spinBackward {
from {-webkit-transform: rotate(360deg);}
to {-webkit-transform: rotate(0deg);}
}
.spinner {
width: 100px;
border: 2px solid black;
font-weight: bold;
text-align: center;
background: white;
}
.circles {
float: left;
padding-right: 20px;
}
.circles svg {
border: 2px solid #333;
}

View File

@@ -0,0 +1,182 @@
<head>
<title>Advanced Template Demo</title>
</head>
<body>
{{> page}}
</body>
<template name="page">
<h1>Advanced Template Demo</h1>
<p>
This demo shows off the advanced features of Meteor's optional
Spark-based templating system, including constant regions, node
preservation, per-template state, and template lifecycle
callbacks.
</p>
{{> preserveDemo }}
{{> constantDemo }}
{{> stateDemo }}
{{> d3Demo }}
</template>
<template name="preserveDemo">
<h2>Element preservation</h2>
<input type="button" value="X++" class="x">
<p>
Elements can be <em>preserved</em>, meaning that they will not be
disturbed even as their attributes, children, or siblings
change. In this example, when you press the X++ button, the CSS
animation continues uninterrupted.
</p>
X={{x}}<br>
<div class="spinner" style="-webkit-animation: {{spinAnim}} 2s infinite linear">
X={{x}}
</div>
<div>
<input type="checkbox" class="spinforward" {{spinForwardChecked}}>
Spin Forward
</div>
X={{x}}
</template>
<template name="constantDemo">
<h2>Constant regions</h2>
<div>
<input type="button" value="X++" class="x"> <br>
<input type="checkbox" class="remove" which="1" {{checked 1}}>
Remove map 1<br>
<input type="checkbox" class="remove" which="2" {{checked 2}}>
Remove map 2
</div>
<br>
<p>
Parts of a template can be marked as <em>constant</em>, meaning
that Meteor will leave the entire region alone (even as its
siblings change.) This is great for embedding non-Meteor
widgets. Try scrolling the two Google Maps embeds below. When you
press X++, the maps stay where they are.
</p>
<p>
Try using the checkboxes to remove either or both of the
maps. When you remove a map, Spark tracks the <em>identity</em> of
the constant regions so that it knows which DOM nodes to keep and
which DOM nodes to throw away. In the case of the Handlebars
package, the identity is based on the actual template call stack
that rendered the constant region.
</p>
X={{x}}<br>
{{#if show 1}}
{{#constant}}
<div style="float: left; padding-right: 20px;">
<iframe width="290" height="290" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=140+10th+Street,+San+Francisco,+CA&amp;aq=0&amp;oq=140+10th+s&amp;sll=37.7577,-122.4376&amp;sspn=0.166931,0.329247&amp;ie=UTF8&amp;hq=&amp;hnear=140+10th+St,+San+Francisco,+California+94103&amp;t=m&amp;ll=37.774921,-122.415419&amp;spn=0.013569,0.017252&amp;z=14&amp;iwloc=A&amp;output=embed"></iframe><br /><small><a href="https://maps.google.com/maps?f=q&amp;source=embed&amp;hl=en&amp;geocode=&amp;q=140+10th+Street,+San+Francisco,+CA&amp;aq=0&amp;oq=140+10th+s&amp;sll=37.7577,-122.4376&amp;sspn=0.166931,0.329247&amp;ie=UTF8&amp;hq=&amp;hnear=140+10th+St,+San+Francisco,+California+94103&amp;t=m&amp;ll=37.774921,-122.415419&amp;spn=0.013569,0.017252&amp;z=14&amp;iwloc=A" style="color:#0000FF;text-align:left">View Larger Map</a></small>
</div>
{{/constant}}
{{/if}}
{{#if show 2}}
{{#constant}}
<div>
<iframe width="290" height="290" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=880+Harrison+Street,+San+Francisco,+CA&amp;aq=0&amp;oq=880+harrison&amp;sll=37.7577,-122.4376&amp;sspn=0.166931,0.329247&amp;ie=UTF8&amp;hq=&amp;hnear=880+Harrison+St,+San+Francisco,+California+94107&amp;t=m&amp;ll=37.779534,-122.411213&amp;spn=0.013568,0.01708&amp;z=14&amp;iwloc=A&amp;output=embed"></iframe><br /><small><a href="https://maps.google.com/maps?f=q&amp;source=embed&amp;hl=en&amp;geocode=&amp;q=880+Harrison+Street,+San+Francisco,+CA&amp;aq=0&amp;oq=880+harrison&amp;sll=37.7577,-122.4376&amp;sspn=0.166931,0.329247&amp;ie=UTF8&amp;hq=&amp;hnear=880+Harrison+St,+San+Francisco,+California+94107&amp;t=m&amp;ll=37.779534,-122.411213&amp;spn=0.013568,0.01708&amp;z=14&amp;iwloc=A" style="color:#0000FF;text-align:left">View Larger Map</a></small>
</div>
{{/constant}}
{{/if}}
<div class="clearboth"> </div>
X={{x}}
</template>
<template name="stateDemo">
<h2>Template callbacks</h2>
<p>
<input type="button" value="X++" class="x">
<input type="button" value="Y++" class="y">
<input type="button" value="Z++" class="z">
</p>
<p>
You can get a <em>create</em> callback when a template is
initially rendered; a <em>render</em> when a template is placed on
the screen and when any part of the template is redrawn; and
a <em>destroy</em> callback when a template is taken across the
screen. All of these callbacks receive a common <em>template state
object</em> in 'this' which allows you to attach data to each
particular instance of a template.
</p>
<p>
In this case, <em>create</em> is used to create a new JavaScript
timer that updates the text of a &lt;span&gt; element every
second. <em>render</em> is used to find the &lt;span&gt; when it
appears on the screen, and update the pointer when the
&lt;span&gt; is redraw (say, when you press Y++ &mdash; since it
is not marked to be preserved.) <em>destroy</em> is used to cancel
the timer when the template goes off the screen.
</p>
<p>
The template state is used to hold the current time count and a
reference to the &lt;span&gt; object to update. That's why there
can be multiple copies of the same template, each with a different
value for the counter.
</p>
X={{x}}<br>
<input type="button" value="Create a timer" class="create"><br>
{{#each timers}}
<div>
{{> timer}}
Z={{z}}
</div>
{{/each}}
X={{x}}
</template>
<template name="timer">
<span class="elapsed"></span>
<input type="button" value="Reset" class="reset">
<input type="button" value="Delete" class="delete">
Y={{y}}
</template>
<template name="d3Demo">
<h2>Simple d3.js integration</h2>
<p>
Meteor fits naturally with the popular d3.js data visualization
library by Michael Bostock. Just set up d3 from your
template's <em>render</em> callback. With Meteor, you can pass
data directly out of a Mongo query into d3, and your d3
visualization will update in realtime, with no extra code! Try
opening this page in two browser windows.
</p>
{{> circles left}}
{{> circles right}}
<div class="clearboth"> </div>
</template>
<template name="circles">
<div class="circles">
{{#constant}}
<svg width="200" height="200" class="xyzzy"></svg>
{{/constant}}
<br>
{{count}} circles<br>
<input type="button" value="Add" class="add">
<input type="button" value="Remove" class="remove" {{{disabled}}}>
<input type="button" value="Scram" class="scram">
</div>
</template>

View File

@@ -1,5 +1,7 @@
Timers = new Meteor.Collection(null);
///////////////////////////////////////////////////////////////////////////////
if (! Session.get("x")) {
Session.set("x", 1);
}
@@ -12,11 +14,23 @@ if (! Session.get("z")) {
Session.set("z", 1);
}
if (typeof Session.get("spinForward") !== 'boolean') {
Session.set("spinForward", true);
}
Template.preserveDemo.x =
Template.constantDemo.x =
Template.stateDemo.x =
function () {
return Session.get("x");
};
Template.redrawButtons.events = {
Template.timer.y = function () {
return Session.get("y");
};
Template.stateDemo.z =
function () {
return Session.get("z");
};
Template.page.events = {
'click input.x': function () {
Session.set("x", Session.get("x") + 1);
},
@@ -30,6 +44,12 @@ Template.redrawButtons.events = {
}
};
///////////////////////////////////////////////////////////////////////////////
if (typeof Session.get("spinForward") !== 'boolean') {
Session.set("spinForward", true);
}
Template.preserveDemo.preserve([ '.spinner', '.spinforward' ]);
Template.preserveDemo.spinForwardChecked = function () {
@@ -46,18 +66,24 @@ Template.preserveDemo.events = {
}
};
Template.preserveDemo.x =
Template.constantDemo.x =
Template.stateDemo.x =
function () {
return Session.get("x");
///////////////////////////////////////////////////////////////////////////////
Template.constantDemo.checked = function (which) {
return Session.get('mapchecked' + which) ? 'checked="checked"' : '';
};
Template.stateDemo.y =
function () {
return Session.get("y");
Template.constantDemo.show = function (which) {
return ! Session.get('mapchecked' + which);
};
Template.constantDemo.events = {
'change .remove' : function (event) {
var tgt = event.currentTarget;
Session.set('mapchecked' + tgt.getAttribute("which"), tgt.checked);
}
};
///////////////////////////////////////////////////////////////////////////////
Template.stateDemo.events = {
'click .create': function () {
@@ -79,10 +105,6 @@ Template.timer.events = {
}
};
Template.timer.z = function () {
return Session.get("z");
};
var updateTimer = function (timer) {
timer.node.innerHTML = timer.elapsed + " second" +
((timer.elapsed === 1) ? "" : "s");
@@ -90,14 +112,12 @@ var updateTimer = function (timer) {
Template.timer.create = function () {
var self = this;
console.log("timer create");
self.elapsed = 0;
self.node = null;
};
Template.timer.render = function () {
var self = this;
console.log("timer render");
self.node = this.find(".elapsed");
updateTimer(self);
@@ -111,16 +131,19 @@ Template.timer.render = function () {
}
};
Template.timer.destroy = function () {
console.log("timer destroy");
clearInterval(this.timer);
};
///////////////////////////////////////////////////////////////////////////////
// XXX move to Meteor.autorun?
// (what else does it need to replace Meteor.autosubscribe?)
// Run f(). Record its dependencies. Rerun it whenever the
// dependencies change.
//
// Returns an object with a stop() method. Call stop() to stop the
// rerunning.
//
// XXX this should go into Meteor core as Meteor.autorun
var autorun = function (f) {
var ctx;
var slain = false;
@@ -149,10 +172,7 @@ Template.d3Demo.right = function () {
};
Template.circles.events = {
'click circle': function (evt, template) {
// XXX actually want to create a ReactiveVar on the template!
// (but how will it be preserved across migration?)
// (maybe template.get, template.set?? rather than form??)
'mousedown circle': function (evt, template) {
Session.set("selectedCircle:" + this.group, evt.currentTarget.id);
},
'click .add': function () {
@@ -184,9 +204,6 @@ Template.circles.events = {
}
};
Template.circles.create = function () {
};
var colorToString = function (color) {
var f = function (x) { return Math.floor(x * 256); };
return "rgb(" + f(color.r) + "," +
@@ -202,6 +219,9 @@ Template.circles.disabled = function () {
'' : 'disabled="disabled"';
};
Template.circles.create = function () {
};
Template.circles.render = function () {
var self = this;
self.node = self.find("svg");
@@ -209,9 +229,6 @@ Template.circles.render = function () {
var data = self.data;
if (! self.handle) {
// XXX template.firstRender would be handy here
// (except that node's inside a constant region, so it's unnecessary)
d3.select(self.node).append("rect");
self.handle = autorun(function () {
var circle = d3.select(self.node).selectAll("circle")
@@ -256,7 +273,6 @@ Template.circles.render = function () {
.attr("r", 0)
.remove();
// XXX this doesn't animate as I'd hoped when you press Scram
var selectionId = Session.get("selectedCircle:" + data.group);
var s = selectionId && Circles.findOne(selectionId);
var rect = d3.select(self.node).select("rect");