Commit ce69c3b2 authored by Pascal Hartig's avatar Pascal Hartig

Merge pull request #523 from stephenplusplus/socketstream

socketstream updated to use bower.
parents 46df302c 31a4b78a
{
"directory" : "client/code/libs"
}
var http = require('http'),
ss = require('socketstream');
var http = require('http');
var ss = require('socketstream');
// Define a single-page client
ss.client.define('main', {
view: 'app.html',
css: ['base.css'],
code: [ 'libs', 'app' ],
code: [
'libs/jquery/jquery.js',
'libs/todomvc-common/base.js',
'app'
],
tmpl: '*'
});
// Serve this client on the root URL
ss.http.route( '/', function( req, res ) {
ss.http.route('/', function (req, res) {
res.serveClient('main');
});
// Use server-side compiled Hogan (Mustache) templates. Others engines available
ss.client.templateEngine.use( require('ss-hogan') );
ss.client.templateEngine.use(require('ss-hogan'));
// Minimize and pack assets if you type: SS_ENV=production node app.js
if ( ss.env === 'production' ) {
if (ss.env === 'production') {
ss.client.packAssets();
}
// Start web server
var server = http.Server( ss.http.middleware );
var server = http.Server(ss.http.middleware);
server.listen(3000);
// Start SocketStream
ss.start( server );
ss.start(server);
/*global $, ss */
'use strict';
/*global $, ss*/
(function () {
'use strict';
var Utils = {
var Utils = {
// https://gist.github.com/1308368
uuid: function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b},
pluralize: function( count, word ) {
pluralize: function (count, word) {
return count === 1 ? word : word + 's';
}
};
};
var App = {
init: function() {
var App = {
init: function () {
var self = this;
this.ENTER_KEY = 13;
ss.rpc('todos.getAll', function( todos ) {
ss.rpc('todos.getAll', function (todos) {
self.todos = todos;
self.cacheElements();
self.bindEvents();
self.render();
});
},
cacheElements: function() {
cacheElements: function () {
this.$todoApp = $('#todoapp');
this.$newTodo = $('#new-todo');
this.$toggleAll = $('#toggle-all');
......@@ -30,130 +33,167 @@ var App = {
this.$count = $('#todo-count');
this.$clearBtn = $('#clear-completed');
},
bindEvents: function() {
bindEvents: function () {
var list = this.$todoList;
this.$newTodo.on( 'keyup', this.create );
this.$toggleAll.on( 'change', this.toggleAll );
this.$footer.on( 'click', '#clear-completed', this.destroyCompleted );
list.on( 'change', '.toggle', this.toggle );
list.on( 'dblclick', 'label', this.edit );
list.on( 'keypress', '.edit', this.blurOnEnter );
list.on( 'blur', '.edit', this.update );
list.on( 'click', '.destroy', this.destroy );
ss.event.on( 'updateTodos', this.updateTodos );
this.$newTodo.on('keyup', this.create);
this.$toggleAll.on('change', this.toggleAll);
this.$footer.on('click', '#clear-completed', this.destroyCompleted);
list.on('change', '.toggle', this.toggle);
list.on('dblclick', 'label', this.edit);
list.on('keypress', '.edit', this.blurOnEnter);
list.on('blur', '.edit', this.update);
list.on('click', '.destroy', this.destroy);
ss.event.on('updateTodos', this.updateTodos);
},
updateTodos: function( todos ) {
updateTodos: function (todos) {
App.todos = todos;
App.render( true );
App.render(true);
},
render: function( preventRpc ) {
var html = this.todos.map(function( el ) {
return ss.tmpl.todo.render( el );
render: function (preventRpc) {
var html = this.todos.map(function (el) {
return ss.tmpl.todo.render(el);
}).join('');
this.$todoList.html( html );
this.$main.toggle( !!this.todos.length );
this.$toggleAll.prop( 'checked', !this.activeTodoCount() );
this.$todoList.html(html);
this.$main.toggle(!!this.todos.length);
this.$toggleAll.prop('checked', !this.activeTodoCount());
this.renderFooter();
if ( !preventRpc ) {
ss.rpc( 'todos.update', this.todos );
if (!preventRpc) {
ss.rpc('todos.update', this.todos);
}
},
renderFooter: function() {
var todoCount = this.todos.length,
activeTodoCount = this.activeTodoCount(),
footer = {
renderFooter: function () {
var todoCount = this.todos.length;
var activeTodoCount = this.activeTodoCount();
var footer = {
activeTodoCount: activeTodoCount,
activeTodoWord: Utils.pluralize( activeTodoCount, 'item' ),
activeTodoWord: Utils.pluralize(activeTodoCount, 'item'),
completedTodos: todoCount - activeTodoCount
};
this.$footer.toggle( !!todoCount );
this.$footer.html( ss.tmpl.footer.render( footer ) );
this.$footer.toggle(!!todoCount);
this.$footer.html( ss.tmpl.footer.render(footer) );
},
toggleAll: function() {
var isChecked = $( this ).prop('checked');
$.each( App.todos, function( i, val ) {
toggleAll: function () {
var isChecked = $(this).prop('checked');
$.each(App.todos, function (i, val) {
val.completed = isChecked;
});
App.render();
},
activeTodoCount: function() {
activeTodoCount: function () {
var count = 0;
$.each( this.todos, function( i, val ) {
if ( !val.completed ) {
$.each(this.todos, function (i, val) {
if (!val.completed) {
count++;
}
});
return count;
},
destroyCompleted: function() {
var todos = App.todos,
l = todos.length;
while ( l-- ) {
if ( todos[l].completed ) {
todos.splice( l, 1 );
destroyCompleted: function () {
var todos = App.todos;
var l = todos.length;
while (l--) {
if (todos[l].completed) {
todos.splice(l, 1);
}
}
App.render();
},
// Accepts an element from inside the ".item" div and
// returns the corresponding todo in the todos array
getTodo: function( elem, callback ) {
var id = $( elem ).closest('li').data('id');
$.each( this.todos, function( i, val ) {
if ( val.id === id ) {
callback.apply( App, arguments );
getTodo: function (elem, callback) {
var id = $(elem).closest('li').data('id');
$.each(this.todos, function (i, val) {
if (val.id === id) {
callback.apply(App, arguments);
return false;
}
});
},
create: function(e) {
var $input = $(this),
val = $.trim( $input.val() );
if ( e.which !== App.ENTER_KEY || !val ) {
create: function (e) {
var $input = $(this);
var val = $.trim($input.val());
if (e.which !== App.ENTER_KEY || !val) {
return;
}
App.todos.push({
id: Utils.uuid(),
title: val,
completed: false
});
$input.val('');
App.render();
},
toggle: function() {
App.getTodo( this, function( i, val ) {
toggle: function () {
App.getTodo(this, function (i, val) {
val.completed = !val.completed;
});
App.render();
},
edit: function() {
edit: function () {
$(this).closest('li').addClass('editing').find('.edit').focus();
},
blurOnEnter: function( e ) {
if ( e.keyCode === App.ENTER_KEY ) {
blurOnEnter: function (e) {
if (e.keyCode === App.ENTER_KEY) {
e.target.blur();
}
},
update: function() {
var val = $.trim( $(this).removeClass('editing').val() );
App.getTodo( this, function( i ) {
if ( val ) {
this.todos[ i ].title = val;
update: function () {
var val = $.trim($(this).removeClass('editing').val());
App.getTodo(this, function (i) {
if (val) {
this.todos[i].title = val;
} else {
this.todos.splice( i, 1 );
this.todos.splice(i, 1);
}
this.render();
});
},
destroy: function() {
App.getTodo( this, function( i ) {
this.todos.splice( i, 1 );
destroy: function () {
App.getTodo(this, function (i) {
this.todos.splice(i, 1);
this.render();
});
}
};
};
App.init();
App.init();
})();
// This file automatically gets called first by SocketStream and must always exist
/*global $, ss*/
(function () {
'use strict';
// This file automatically gets called first by SocketStream and must always exist
// Make 'ss' available to all modules and the browser console
window.ss = require('socketstream');
// Make 'ss' available to all modules and the browser console
window.ss = require('socketstream');
ss.server.on('disconnect', function() {
ss.server.on('disconnect', function () {
console.log('Connection down :-(');
});
});
ss.server.on('reconnect', function() {
ss.server.on('reconnect', function () {
console.log('Connection back up :-)');
});
ss.server.on('ready', function() {
});
ss.server.on('ready', function () {
// Wait for the DOM to finish loading
$(function() {
$(function () {
// Load app
require('/app');
});
});
});
})();
(function( window ) {
'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'));
}
})( window );
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();
})();
......@@ -155,22 +155,11 @@ label[for='toggle-all'] {
#toggle-all {
position: absolute;
top: -56px;
left: -15px;
width: 65px;
height: 41px;
top: -42px;
left: -4px;
width: 40px;
text-align: center;
border: none; /* Mobile Safari */
-webkit-appearance: none;
/*-moz-appearance: none;*/
-ms-appearance: none;
-o-appearance: none;
appearance: none;
-webkit-transform: rotate(90deg);
/*-moz-transform: rotate(90deg);*/
-ms-transform: rotate(90deg);
/*-o-transform: rotate(90deg);*/
transform: rotate(90deg);
}
#toggle-all:before {
......@@ -219,7 +208,8 @@ label[for='toggle-all'] {
#todo-list li .toggle {
text-align: center;
width: 40px;
height: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
......@@ -233,7 +223,6 @@ label[for='toggle-all'] {
}
#todo-list li .toggle:after {
font-size: 18px;
content: '✔';
line-height: 43px; /* 40 + a couple of pixels visual adjustment */
font-size: 20px;
......@@ -250,8 +239,9 @@ label[for='toggle-all'] {
#todo-list li label {
word-break: break-word;
margin: 15px 15px 15px 60px;
display: inline-block;
padding: 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
-webkit-transition: color 0.4s;
-moz-transition: color 0.4s;
......@@ -402,4 +392,23 @@ label[for='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;
}
<span id="todo-count"><strong>{{activeTodoCount}}</strong> {{activeTodoWord}} left</span>
{{#completedTodos}}<button id="clear-completed">Clear completed ({{completedTodos}})</button>{{/completedTodos}}
\ No newline at end of file
<span id="todo-count">
<strong>{{activeTodoCount}}</strong> {{activeTodoWord}} left
</span>
{{#completedTodos}}
<button id="clear-completed">Clear completed ({{completedTodos}})</button>
{{/completedTodos}}
{
"name": "todomvc-socketstream",
"version": "0.0.0",
"dependencies": {
"jquery": "~1.9.1",
"todomvc-common": "~0.1.3"
}
}
......@@ -6,14 +6,14 @@ var todos = [];
// Define actions which can be called from the client using
// ss.rpc('demo.ACTIONNAME', param1, param2...)
exports.actions = function( req, res, ss ) {
exports.actions = function(req, res, ss) {
return {
getAll: function() {
res( todos );
getAll: function () {
res(todos);
},
update: function( clientTodos ) {
update: function (clientTodos) {
todos = clientTodos;
ss.publish.all( 'updateTodos', todos );
ss.publish.all('updateTodos', todos);
}
};
};
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