Commit 249b69ac authored by Sindre Sorhus's avatar Sindre Sorhus

Merge pull request #520 from stephenplusplus/serenadejs

serenade updated to use bower.
parents dd83a536 637ff54e
{
"name": "todomvc-serenadejs",
"version": "0.0.0",
"dependencies": {
"director": "~1.2.0",
"todomvc-common": "~0.1.2"
}
}
html,
body {
margin: 0;
padding: 0;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
color: inherit;
-webkit-appearance: none;
/*-moz-appearance: none;*/
-ms-appearance: none;
-o-appearance: none;
appearance: none;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #eaeaea url('bg.png');
color: #4d4d4d;
width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
}
#todoapp {
background: #fff;
background: rgba(255, 255, 255, 0.9);
margin: 130px 0 40px 0;
border: 1px solid #ccc;
position: relative;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.15);
}
#todoapp:before {
content: '';
border-left: 1px solid #f5d6d6;
border-right: 1px solid #f5d6d6;
width: 2px;
position: absolute;
top: 0;
left: 40px;
height: 100%;
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
}
#todoapp input:-moz-placeholder {
font-style: italic;
color: #a9a9a9;
}
#todoapp h1 {
position: absolute;
top: -120px;
width: 100%;
font-size: 70px;
font-weight: bold;
text-align: center;
color: #b3b3b3;
color: rgba(255, 255, 255, 0.3);
text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
-ms-text-rendering: optimizeLegibility;
-o-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
#header {
padding-top: 15px;
border-radius: inherit;
}
#header:before {
content: '';
position: absolute;
top: 0;
right: 0;
left: 0;
height: 15px;
z-index: 2;
border-bottom: 1px solid #6c615c;
background: #8d7d77;
background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: -moz-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: -o-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: -ms-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
border-top-left-radius: 1px;
border-top-right-radius: 1px;
}
#new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
}
#new-todo {
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.02);
z-index: 2;
box-shadow: none;
}
#main {
position: relative;
z-index: 2;
border-top: 1px dotted #adadad;
}
label[for='toggle-all'] {
display: none;
}
#toggle-all {
position: absolute;
top: -42px;
left: -4px;
width: 40px;
text-align: center;
border: none; /* Mobile Safari */
}
#toggle-all:before {
content: '»';
font-size: 28px;
color: #d9d9d9;
padding: 0 25px 7px;
}
#toggle-all:checked:before {
color: #737373;
}
#todo-list {
margin: 0;
padding: 0;
list-style: none;
}
#todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px dotted #ccc;
}
#todo-list li:last-child {
border-bottom: none;
}
#todo-list li.editing {
border-bottom: none;
padding: 0;
}
#todo-list li.editing .edit {
display: block;
width: 506px;
padding: 13px 17px 12px 17px;
margin: 0 0 0 43px;
}
#todo-list li.editing .view {
display: none;
}
#todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
-webkit-appearance: none;
/*-moz-appearance: none;*/
-ms-appearance: none;
-o-appearance: none;
appearance: none;
}
#todo-list li .toggle:after {
content: '✔';
line-height: 43px; /* 40 + a couple of pixels visual adjustment */
font-size: 20px;
color: #d9d9d9;
text-shadow: 0 -1px 0 #bfbfbf;
}
#todo-list li .toggle:checked:after {
color: #85ada7;
text-shadow: 0 1px 0 #669991;
bottom: 1px;
position: relative;
}
#todo-list li label {
word-break: break-word;
padding: 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
-webkit-transition: color 0.4s;
-moz-transition: color 0.4s;
-ms-transition: color 0.4s;
-o-transition: color 0.4s;
transition: color 0.4s;
}
#todo-list li.completed label {
color: #a9a9a9;
text-decoration: line-through;
}
#todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 22px;
color: #a88a8a;
-webkit-transition: all 0.2s;
-moz-transition: all 0.2s;
-ms-transition: all 0.2s;
-o-transition: all 0.2s;
transition: all 0.2s;
}
#todo-list li .destroy:hover {
text-shadow: 0 0 1px #000,
0 0 10px rgba(199, 107, 107, 0.8);
-webkit-transform: scale(1.3);
-moz-transform: scale(1.3);
-ms-transform: scale(1.3);
-o-transform: scale(1.3);
transform: scale(1.3);
}
#todo-list li .destroy:after {
content: '✖';
}
#todo-list li:hover .destroy {
display: block;
}
#todo-list li .edit {
display: none;
}
#todo-list li.editing:last-child {
margin-bottom: -1px;
}
#footer {
color: #777;
padding: 0 15px;
position: absolute;
right: 0;
bottom: -31px;
left: 0;
height: 20px;
z-index: 1;
text-align: center;
}
#footer:before {
content: '';
position: absolute;
right: 0;
bottom: 31px;
left: 0;
height: 50px;
z-index: -1;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
0 6px 0 -3px rgba(255, 255, 255, 0.8),
0 7px 1px -3px rgba(0, 0, 0, 0.3),
0 43px 0 -6px rgba(255, 255, 255, 0.8),
0 44px 2px -6px rgba(0, 0, 0, 0.2);
}
#todo-count {
float: left;
text-align: left;
}
#filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
#filters li {
display: inline;
}
#filters li a {
color: #83756f;
margin: 2px;
text-decoration: none;
}
#filters li a.selected {
font-weight: bold;
}
#clear-completed {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
background: rgba(0, 0, 0, 0.1);
font-size: 11px;
padding: 0 10px;
border-radius: 3px;
box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
}
#clear-completed:hover {
background: rgba(0, 0, 0, 0.15);
box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
}
#info {
margin: 65px auto 0;
color: #a6a6a6;
font-size: 12px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
text-align: center;
}
#info a {
color: inherit;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox and Opera
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
#toggle-all,
#todo-list li .toggle {
background: none;
}
#todo-list li .toggle {
height: 40px;
}
#toggle-all {
top: -56px;
left: -15px;
width: 65px;
height: 41px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-appearance: none;
appearance: none;
}
}
.hidden{
display:none;
}
(function () {
'use strict';
if (location.hostname === 'todomvc.com') {
window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));
}
function getSourcePath() {
// If accessed via addyosmani.github.com/todomvc/, strip the project
// path.
if (location.hostname.indexOf('github.com') > 0) {
return location.pathname.replace(/todomvc\//, '');
}
return location.pathname;
}
function appendSourceLink() {
var sourceLink = document.createElement('a');
var paragraph = document.createElement('p');
var footer = document.getElementById('info');
var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages';
if (footer) {
sourceLink.href = urlBase + getSourcePath();
sourceLink.appendChild(document.createTextNode('Check out the source'));
paragraph.appendChild(sourceLink);
footer.appendChild(paragraph);
}
}
function redirect() {
if (location.hostname === 'addyosmani.github.com') {
location.href = location.href.replace('addyosmani.github.com/todomvc',
'todomvc.com');
}
}
appendSourceLink();
redirect();
})();
......@@ -4,65 +4,64 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Serenade.js • TodoMVC</title>
<link href="../../../assets/base.css" rel="stylesheet">
<!--[if IE]>
<script src="../../../assets/ie.js"></script>
<![endif]-->
<script id="app" type="text/serenade">
section#todoapp
header#header
form[event:submit=newTodo!]
h1 "todos"
<link href="components/todomvc-common/base.css" rel="stylesheet">
</head>
<body>
<script id="app" type="text/serenade">
section#todoapp
header#header
form[event:submit=newTodo!]
h1 "todos"
input#new-todo[binding:change=@newTitle placeholder="What needs to be done?" autofocus="autofocus"]
input#new-todo[binding:change=@newTitle placeholder="What needs to be done?" autofocus="autofocus"]
- if @allCount
section#main
input#toggle-all[type="checkbox" binding:change=@allCompleted]
- if @allCount
section#main
input#toggle-all[type="checkbox" binding:change=@allCompleted]
label[for="toggle-all"] "Mark all as complete"
label[for="toggle-all"] "Mark all as complete"
ul#todo-list
- collection @filtered
- view "todo"
ul#todo-list
- collection @filtered
- view "todo"
footer#footer
span#todo-count
strong @activeCount
" "
@label
footer#footer
span#todo-count
strong @activeCount
" "
@label
ul#filters
li
a.all[class:selected=@filterAll href="#/"] "All"
li
a.active[class:selected=@filterActive href="#/active"] "Active"
li
a.completed[class:selected=@filterCompleted href="#/completed"] "Completed"
- if @completedCount
button#clear-completed[event:click=clearCompleted]
"Clear completed (" @completedCount ")"
</script>
ul#filters
li
a.all[class:selected=@filterAll href="#/"] "All"
li
a.active[class:selected=@filterActive href="#/active"] "Active"
li
a.completed[class:selected=@filterCompleted href="#/completed"] "Completed"
- if @completedCount
button#clear-completed[event:click=clearCompleted]
"Clear completed (" @completedCount ")"
</script>
<script id="todo" type="text/serenade">
li[class:editing=@edit class:completed=@completed]
form[event:submit=edited!]
input.edit[on:load=loadField event:blur=edited! binding:change=@title]
<script id="todo" type="text/serenade">
li[class:editing=@edit class:completed=@completed]
form[event:submit=edited!]
input.edit[on:load=loadField event:blur=edited! binding:change=@title]
- unless @edit
input.toggle[type="checkbox" binding:change=@completed]
label[event:dblclick=edit] @title
button.destroy[event:click=removeTodo]
</script>
- unless @edit
input.toggle[type="checkbox" binding:change=@completed]
label[event:dblclick=edit] @title
button.destroy[event:click=removeTodo]
</script>
</head>
<body>
<footer id="info">
<p>Double-click to edit a todo</p>
<p>Created by <a href="http://elabs.se">Elabs</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<script src="../../../assets/base.js"></script>
<script src="../../../assets/director.min.js"></script>
<script src="components/todomvc-common/base.js"></script>
<script src="components/director/build/director.js"></script>
<script src="js/lib/serenade.js"></script>
<script src="js/app.js"></script>
</body>
......
class Todo extends Serenade.Model
@belongsTo 'app', inverseOf: 'all', as: -> App
@property 'title', serialize: true
@belongsTo 'app', inverseOf: 'all', as: -> App
@property 'title', serialize: true
@property 'completed', serialize: true
@property 'incomplete',
get: -> not @completed
@property 'completed', serialize: true
@property 'incomplete',
get: -> not @completed
@property 'edit'
@property 'edit'
remove: ->
@app.all.delete(this)
remove: ->
@app.all.delete(this)
class App extends Serenade.Model
@hasMany 'all', inverseOf: 'app', serialize: true, as: -> Todo
@hasMany 'all', inverseOf: 'app', serialize: true, as: -> Todo
@selection 'active', from: 'all', filter: 'incomplete'
@selection 'completed', from: 'all', filter: 'completed'
@selection 'active', from: 'all', filter: 'incomplete'
@selection 'completed', from: 'all', filter: 'completed'
@property 'label',
get: -> if @activeCount is 1 then 'item left' else 'items left'
@property 'label',
get: -> if @activeCount is 1 then 'item left' else 'items left'
@property 'allCompleted',
get: -> @activeCount is 0
set: (value) -> todo.completed = value for todo in @all
@property 'allCompleted',
get: -> @activeCount is 0
set: (value) -> todo.completed = value for todo in @all
@property 'newTitle'
@property 'newTitle'
@property 'filter', value: 'all'
@property 'filtered', get: -> @[@filter]
@property 'filter', value: 'all'
@property 'filtered', get: -> @[@filter]
@property 'filterAll', get: -> @filter is 'all'
@property 'filterActive', get: -> @filter is 'active'
@property 'filterCompleted', get: -> @filter is 'completed'
@property 'filterAll', get: -> @filter is 'all'
@property 'filterActive', get: -> @filter is 'active'
@property 'filterCompleted', get: -> @filter is 'completed'
class AppController
constructor: (@app) ->
constructor: (@app) ->
newTodo: ->
title = @app.newTitle.trim()
@app.all.push(title: title) if title
@app.newTitle = ''
newTodo: ->
title = @app.newTitle.trim()
@app.all.push(title: title) if title
@app.newTitle = ''
clearCompleted: ->
@app.all = @app.active
clearCompleted: ->
@app.all = @app.active
class TodoController
constructor: (@todo) ->
constructor: (@todo) ->
removeTodo: ->
@todo.remove()
removeTodo: ->
@todo.remove()
edit: ->
@todo.edit = true
@field.select()
edit: ->
@todo.edit = true
@field.select()
edited: ->
if @todo.title.trim()
@todo.edit = false if @todo.edit
else
@todo.remove()
@todo.app.changed.trigger()
edited: ->
if @todo.title.trim()
@todo.edit = false if @todo.edit
else
@todo.remove()
@todo.app.changed.trigger()
loadField: (@field) ->
loadField: (@field) ->
app = new App(JSON.parse(localStorage.getItem('todos-serenade')))
app.changed.bind -> localStorage.setItem('todos-serenade', app)
router = Router
'/': -> app.filter = 'all'
'/active': -> app.filter = 'active'
'/completed': -> app.filter = 'completed'
'/': -> app.filter = 'all'
'/active': -> app.filter = 'active'
'/completed': -> app.filter = 'completed'
router.init()
......
// Generated by CoffeeScript 1.4.0
// Generated by CoffeeScript 1.6.2
(function() {
var App, AppController, Todo, TodoController, app, router,
var App, AppController, Todo, TodoController, app, router, _ref, _ref1,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
Todo = (function(_super) {
__extends(Todo, _super);
function Todo() {
return Todo.__super__.constructor.apply(this, arguments);
_ref = Todo.__super__.constructor.apply(this, arguments);
return _ref;
}
Todo.belongsTo('app', {
......@@ -44,11 +44,11 @@
})(Serenade.Model);
App = (function(_super) {
__extends(App, _super);
function App() {
return App.__super__.constructor.apply(this, arguments);
_ref1 = App.__super__.constructor.apply(this, arguments);
return _ref1;
}
App.hasMany('all', {
......@@ -84,11 +84,12 @@
return this.activeCount === 0;
},
set: function(value) {
var todo, _i, _len, _ref, _results;
_ref = this.all;
var todo, _i, _len, _ref2, _results;
_ref2 = this.all;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
todo = _ref[_i];
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
todo = _ref2[_i];
_results.push(todo.completed = value);
}
return _results;
......@@ -130,13 +131,13 @@
})(Serenade.Model);
AppController = (function() {
function AppController(app) {
this.app = app;
}
AppController.prototype.newTodo = function() {
var title;
title = this.app.newTitle.trim();
if (title) {
this.app.all.push({
......@@ -155,7 +156,6 @@
})();
TodoController = (function() {
function TodoController(todo) {
this.todo = todo;
}
......@@ -188,10 +188,10 @@
})();
app = new App(JSON.parse(localStorage.getItem('todomvc-serenade')));
app = new App(JSON.parse(localStorage.getItem('todos-serenade')));
app.changed.bind(function() {
return localStorage.setItem('todomvc-serenade', app);
return localStorage.setItem('todos-serenade', app);
});
router = Router({
......
{
"name": "todomvc-serenadejs",
"description": "TodoMVC todo app using Serenade.js",
"version": "0.0.0",
"dependencies": {
},
"devDependencies": {
"serenade": "~0.4.0",
"coffee-script": "~1.6.2"
},
"scripts": {
"compile": "coffee -co js/ js/"
},
"private": true
}
# Serenade.js TodoMVC app
The Serenade.js app has a couple of dependencies which will be necessary if you wish to re-compile the source files.
Running `npm install` from this directory will give you [Serenade.js](http://serenadejs.org/) and [CoffeeScript](http://coffeescript.org/).
### Serenade.js
The latest release of Serenade.js is included in the `js/lib/` folder. The only way to upgrade is either by downloading the source from [their website](http://serenadejs.org/), or by compiling it yourself.
If you wish to compile it yourself, instructions are be available at [Serenade's website](http://serenadejs.org/development.html).
### CoffeeScript
The source code for the TodoMVC app was written in CoffeeScript. If you would like to re-compile the code, follow these instructions.
If you already have CoffeeScript globally installed, just run:
coffee -co js/ js/
If you don't have CoffeeScript globally installed, you may either install it globally...
npm install -g coffee-script
coffee -co js/ js/
...or if you wish to install it just for the purposes of this app...
cd to todomvc/labs/architecture-examples/serenadejs
npm install
npm run-script compile
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment