updated app

This commit is contained in:
2012-05-30 23:00:06 -04:00
parent 6a753904b7
commit da6ad88d48
5545 changed files with 1101709 additions and 60 deletions

2
node_modules/derby-examples/chat/Makefile generated vendored Normal file
View File

@@ -0,0 +1,2 @@
compile:
./node_modules/coffee-script/bin/coffee -bw -o ./lib -c ./src

99
node_modules/derby-examples/chat/lib/chat/index.js generated vendored Normal file
View File

@@ -0,0 +1,99 @@
// Generated by CoffeeScript 1.3.1
var NUM_USER_IMAGES, get, getRoom, ready, view, _ref;
_ref = require('derby').createApp(module), get = _ref.get, view = _ref.view, ready = _ref.ready;
NUM_USER_IMAGES = 10;
get('/:room?', function(page, model, _arg) {
var room, userId, _room;
room = _arg.room;
if (!(room && /^[-\w ]+$/.test(room))) {
return page.redirect('/lobby');
}
_room = room.toLowerCase().replace(/[_ ]/g, '-');
if (_room !== room) {
return page.redirect("/" + _room);
}
if (userId = model.get('_session.userId')) {
return getRoom(page, model, room, userId);
}
return model.async.incr('configs.1.nextUserId', function(err, userId) {
model.set('_session.userId', userId);
model.set("users." + userId, {
name: 'User ' + userId,
picClass: 'pic' + (userId % NUM_USER_IMAGES)
});
return getRoom(page, model, room, userId);
});
});
getRoom = function(page, model, roomName, userId) {
return model.subscribe("rooms." + roomName, 'users', function(err, room, users) {
model.ref('_room', room);
model.setNull('_room.messages', []);
model.set('_newComment', '');
model.ref('_user', "users." + userId);
model.fn('_numMessages', '_room.messages', function(messages) {
return messages.length;
});
return page.render();
});
};
ready(function(model) {
var atBottom, displayTime, i, message, messageList, messages, months, _i, _len, _ref1;
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
displayTime = function(time) {
var hours, minutes, period;
time = new Date(time);
hours = time.getHours();
period = hours < 12 ? ' am, ' : ' pm, ';
hours = (hours % 12) || 12;
minutes = time.getMinutes();
if (minutes < 10) {
minutes = '0' + minutes;
}
return hours + ':' + minutes + period + months[time.getMonth()] + ' ' + time.getDate() + ', ' + time.getFullYear();
};
_ref1 = model.get('_room.messages');
for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) {
message = _ref1[i];
model.set("_room.messages." + i + "._displayTime", displayTime(message.time));
}
model.set('_showReconnect', true);
exports.connect = function() {
model.set('_showReconnect', false);
setTimeout((function() {
return model.set('_showReconnect', true);
}), 1000);
return model.socket.socket.connect();
};
exports.reload = function() {
return window.location.reload();
};
messages = document.getElementById('messages');
messageList = document.getElementById('messageList');
atBottom = true;
model.on('pre:push', '_room.messages', function() {
var bottom, containerHeight, scrollBottom;
bottom = messageList.offsetHeight;
containerHeight = messages.offsetHeight;
scrollBottom = messages.scrollTop + containerHeight;
return atBottom = bottom < containerHeight || scrollBottom === bottom;
});
model.on('push', '_room.messages', function(message, len, isLocal) {
if (isLocal || atBottom) {
messages.scrollTop = messageList.offsetHeight;
}
return model.set("_room.messages." + (len - 1) + "._displayTime", displayTime(message.time));
});
return exports.postMessage = function() {
model.push('_room.messages', {
userId: model.get('_session.userId'),
comment: model.get('_newComment'),
time: +(new Date)
});
return model.set('_newComment', '');
};
});

16
node_modules/derby-examples/chat/lib/chat/inline.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
// Generated by CoffeeScript 1.3.1
var commentInput, messageList, messages;
messages = document.getElementById('messages');
messageList = document.getElementById('messageList');
commentInput = document.getElementById('commentInput');
(window.onresize = function() {
return messages.scrollTop = messageList.offsetHeight;
})();
if (!('autofocus' in commentInput)) {
commentInput.focus();
}

52
node_modules/derby-examples/chat/lib/server/index.js generated vendored Normal file
View File

@@ -0,0 +1,52 @@
// Generated by CoffeeScript 1.3.1
var MongoStore, ONE_YEAR, chat, derby, express, expressApp, gzippo, http, path, publicPath, root, server, serverError;
http = require('http');
path = require('path');
express = require('express');
gzippo = require('gzippo');
MongoStore = require('connect-mongo')(express);
derby = require('derby');
chat = require('../chat');
serverError = require('./serverError');
ONE_YEAR = 1000 * 60 * 60 * 24 * 365;
root = path.dirname(path.dirname(__dirname));
publicPath = path.join(root, 'public');
(expressApp = express()).use(express.favicon()).use(gzippo.staticGzip(publicPath, {
maxAge: ONE_YEAR
})).use(express.compress()).use(express.cookieParser('secret_sauce')).use(express.session({
cookie: {
maxAge: ONE_YEAR
},
store: new MongoStore({
db: 'derby-chat',
collection: 'express-sessions'
})
})).use(chat.session()).use(chat.router()).use(expressApp.router).use(serverError(root));
module.exports = server = http.createServer(expressApp);
expressApp.all('*', function(req) {
throw "404: " + req.url;
});
derby.use(require('racer-db-mongo'));
chat.createStore({
listen: server,
db: {
type: 'Mongo',
uri: 'mongodb://localhost/derby-chat'
}
});

View File

@@ -0,0 +1,27 @@
// Generated by CoffeeScript 1.3.1
var derby, isProduction;
derby = require('derby');
isProduction = derby.util.isProduction;
module.exports = function(root) {
var staticPages;
staticPages = derby.createStatic(root);
return function(err, req, res, next) {
var message, status;
if (err == null) {
return next();
}
console.log(err.stack ? err.stack : err);
message = err.message || err.toString();
status = parseInt(message);
if (status === 404) {
return staticPages.render('404', res, {
url: req.url
}, 404);
} else {
return res.send((400 <= status && status < 600) ? status : 500);
}
};
};

17
node_modules/derby-examples/chat/package.json generated vendored Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "derby-chat-example",
"description": "Demo chat application for Derby",
"version": "0.0.0",
"main": "./server.js",
"dependencies": {
"derby": "*",
"express": "3.x",
"gzippo": ">=0.1.4",
"racer-db-mongo": "*",
"connect-mongo": ">=0.1.9"
},
"private": true,
"devDependencies": {
"coffee-script": ">=1.3.1"
}
}

BIN
node_modules/derby-examples/chat/public/img/s.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

1
node_modules/derby-examples/chat/server.js generated vendored Normal file
View File

@@ -0,0 +1 @@
require('derby').run(__dirname + '/lib/server', 3002);

108
node_modules/derby-examples/chat/src/chat/index.coffee generated vendored Normal file
View File

@@ -0,0 +1,108 @@
# Derby exposes framework features on this module
{get, view, ready} = require('derby').createApp module
## ROUTES ##
NUM_USER_IMAGES = 10
get '/:room?', (page, model, {room}) ->
# Redirect users to URLs that only contain letters, numbers, and hyphens
return page.redirect '/lobby' unless room && /^[-\w ]+$/.test room
_room = room.toLowerCase().replace /[_ ]/g, '-'
return page.redirect "/#{_room}" if _room != room
# Render page if a userId is already stored in session data
if userId = model.get '_session.userId'
return getRoom page, model, room, userId
# Otherwise, select a new userId and initialize user
model.async.incr 'configs.1.nextUserId', (err, userId) ->
model.set '_session.userId', userId
model.set "users.#{userId}",
name: 'User ' + userId
picClass: 'pic' + (userId % NUM_USER_IMAGES)
getRoom page, model, room, userId
getRoom = (page, model, roomName, userId) ->
model.subscribe "rooms.#{roomName}", 'users', (err, room, users) ->
model.ref '_room', room
# setNull will set a value if the object is currently null or undefined
model.setNull '_room.messages', []
# Any path name that starts with an underscore is private to the current
# client. Nothing set under a private path is synced back to the server.
model.set '_newComment', ''
model.ref '_user', "users.#{userId}"
model.fn '_numMessages', '_room.messages', (messages) -> messages.length
page.render()
## CONTROLLER FUNCTIONS ##
ready (model) ->
months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
displayTime = (time) ->
time = new Date time
hours = time.getHours()
period = if hours < 12 then ' am, ' else ' pm, '
hours = (hours % 12) || 12
minutes = time.getMinutes()
minutes = '0' + minutes if minutes < 10
return hours + ':' + minutes + period + months[time.getMonth()] +
' ' + time.getDate() + ', ' + time.getFullYear()
# Display times are only set client-side, since the timezone is not known
# when performing server-side rendering
for message, i in model.get '_room.messages'
# _displayTime starts with an underscore so that its value is not
# stored or sent to other clients
model.set "_room.messages.#{i}._displayTime", displayTime message.time
# Exported functions are exposed as a global in the browser with the same
# name as the module that includes Derby. They can also be bound to DOM
# events using the "x-bind" attribute in a template.
model.set '_showReconnect', true
exports.connect = ->
# Hide the reconnect link for a second after clicking it
model.set '_showReconnect', false
setTimeout (-> model.set '_showReconnect', true), 1000
model.socket.socket.connect()
exports.reload = -> window.location.reload()
messages = document.getElementById 'messages'
messageList = document.getElementById 'messageList'
atBottom = true
# Derby emits pre mutator events after the model has been updated, but
# before the view bindings have been updated
model.on 'pre:push', '_room.messages', ->
# Check to see if the page is scrolled to the bottom before adding
# a new message
bottom = messageList.offsetHeight
containerHeight = messages.offsetHeight
scrollBottom = messages.scrollTop + containerHeight
atBottom = bottom < containerHeight || scrollBottom == bottom
# Regular model mutator events are emitted after both the model and view
# bindings have been updated
model.on 'push', '_room.messages', (message, len, isLocal) ->
# Scoll page when adding a message or when another user adds a message
# and the page is already at the bottom
if isLocal || atBottom
messages.scrollTop = messageList.offsetHeight
# Update display time using local timezone
model.set "_room.messages.#{len - 1}._displayTime", displayTime message.time
exports.postMessage = ->
model.push '_room.messages',
userId: model.get '_session.userId'
comment: model.get '_newComment'
time: +new Date
model.set '_newComment', ''

View File

@@ -0,0 +1,12 @@
# Scripts required to properly render the page can be put in a file called
# "inline.js". This file will be automatically inserted before the external
# scripts are included.
messages = document.getElementById 'messages'
messageList = document.getElementById 'messageList'
commentInput = document.getElementById 'commentInput'
do window.onresize = ->
# Scroll the message list to the bottom
messages.scrollTop = messageList.offsetHeight
# Use HTML5 autofocus if supported. Otherwise, focus manually
commentInput.focus() unless 'autofocus' of commentInput

View File

@@ -0,0 +1,57 @@
http = require 'http'
path = require 'path'
express = require 'express'
gzippo = require 'gzippo'
MongoStore = require('connect-mongo')(express)
derby = require 'derby'
chat = require '../chat'
serverError = require './serverError'
## SERVER CONFIGURATION ##
ONE_YEAR = 1000 * 60 * 60 * 24 * 365
root = path.dirname path.dirname __dirname
publicPath = path.join root, 'public'
(expressApp = express())
.use(express.favicon())
# Gzip static files and serve from memory
.use(gzippo.staticGzip publicPath, maxAge: ONE_YEAR)
# Gzip dynamically rendered content
.use(express.compress())
# Uncomment to add form data parsing support
# .use(express.bodyParser())
# .use(express.methodOverride())
# Derby session middleware creates req.model and subscribes to _session
.use(express.cookieParser 'secret_sauce')
.use(express.session
cookie: {maxAge: ONE_YEAR}
store: new MongoStore(db: 'derby-chat', collection: 'express-sessions')
)
.use(chat.session())
# The router method creates an express middleware from the app's routes
.use(chat.router())
.use(expressApp.router)
.use(serverError root)
module.exports = server = http.createServer expressApp
## SERVER ONLY ROUTES ##
expressApp.all '*', (req) ->
throw "404: #{req.url}"
## STORE SETUP ##
derby.use(require 'racer-db-mongo')
chat.createStore
listen: server
db: {type: 'Mongo', uri: 'mongodb://localhost/derby-chat'}

View File

@@ -0,0 +1,18 @@
derby = require 'derby'
{isProduction} = derby.util
module.exports = (root) ->
staticPages = derby.createStatic root
return (err, req, res, next) ->
return next() unless err?
console.log(if err.stack then err.stack else err)
## Customize error handling here ##
message = err.message || err.toString()
status = parseInt message
if status is 404
staticPages.render '404', res, {url: req.url}, 404
else
res.send if 400 <= status < 600 then status else 500

12
node_modules/derby-examples/chat/styles/404.styl generated vendored Normal file
View File

@@ -0,0 +1,12 @@
@import "./reset";
body {
padding: 2em;
}
h1 {
font-size: 2em;
margin-bottom: .5em;
}
p {
line-height: 2em;
}

113
node_modules/derby-examples/chat/styles/chat/index.styl generated vendored Normal file
View File

@@ -0,0 +1,113 @@
@import "../reset";
body {
background: #bbb;
color: #000;
}
a {
color: #01c;
}
li {
margin: 8px 0;
clear: both;
}
input {
box-sizing: border-box;
margin: 0;
padding: 1px;
height: 22px;
}
#page {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
}
#alert {
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
height: 0;
z-index: 99;
}
#alert > p {
background: #fff1a8;
border: 1px solid #999;
border-top: 0;
border-radius: 0 0 3px 3px;
display: inline-block;
line-height: 21px;
padding: 0 12px;
}
#messages {
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
left: 0;
right: 0;
top: 0;
bottom: 65px;
position: absolute;
}
#messageList {
list-style: none;
position: relative;
overflow: hidden;
}
.message,#inputs {
margin: 0 8px 0 64px;
}
.message {
background: #fff;
border-radius: 8px;
min-height: 32px;
padding: 8px 12px;
white-space: pre;
}
.time {
float: right;
color: #888;
}
.pic {
width: 48px;
height: 48px;
position: absolute;
left: 0;
margin: 0 8px;
}
.pic0,.pic1,.pic2,.pic3,.pic4,.pic5,.pic6,.pic7,.pic8,.pic9 {
height: 480px;
}
picClip(num) {
clip: rect(48px * num, 48px, 48px * (num + 1), 0);
margin-top: -48px * num;
}
.pic0 { picClip: 0 }
.pic1 { picClip: 1 }
.pic2 { picClip: 2 }
.pic3 { picClip: 3 }
.pic4 { picClip: 4 }
.pic5 { picClip: 5 }
.pic6 { picClip: 6 }
.pic7 { picClip: 7 }
.pic8 { picClip: 8 }
.pic9 { picClip: 9 }
#foot {
background: #ddd;
width: 100%;
height: 48px;
border-top: 1px solid #eee;
position: absolute;
bottom: 0;
padding: 8px 0;
}
#inputForm {
margin-top: 4px;
}
#commentInput {
width: 100%;
}

18
node_modules/derby-examples/chat/styles/reset.styl generated vendored Normal file
View File

@@ -0,0 +1,18 @@
@import "nib/vendor";
body,h1,h2,h3,h4,input,pre,select,textarea,th {
font: 13px/normal arial,sans-serif;
}
body,fieldset,form,h1,h2,h3,h4,input,ul,li,ol,p,td,textarea,th {
margin: 0;
padding: 0;
}
ul {
margin: 0 normal;
}
table {
border-collapse: collapse;
}
fieldset,img {
border: 0;
}

16
node_modules/derby-examples/chat/views/404.html generated vendored Normal file
View File

@@ -0,0 +1,16 @@
<!--
This is a static page, so it has views and styles, but no associated scripts
-->
<Title:>
Chat
<!--
Static pages don't include the Derby client library, so they can't have bound
variables that automatically update. However, they do support Handlebars-style
templating with a model and/or context object
-->
<Body:>
<h1>404</h1>
<p>Sorry, we can't find anything at <b>{{url}}</b>.
<p>Try heading back to the <a href=/lobby>lobby</a>.

80
node_modules/derby-examples/chat/views/chat/index.html generated vendored Normal file
View File

@@ -0,0 +1,80 @@
<!--
Derby templates are similar to Handlebars, except that they are first
parsed as HTML, and there are a few extensions to make them work directly
with models. A single HTML template defines the HTML output, the event
handlers that update the model after user interaction, and the event handlers
that update the DOM when the model changes.
As in Handlebars, double curly braces output a value literally. Derby templates
add single curly braces, which output a value and set up model <- -> view
bindings for that object.
Elements that end in colon define the names of views. Pre-defined views are
capitalized by convention, but view names are case-insensitive. Pre-defined views
are automatically included when the page is rendered.
-->
<Title:>
Chat ({_numMessages}) - {_user.name}
<Head:>
<meta name=viewport content="width=device-width">
<Header:>
<!-- Other templates are referenced like custom HTML elements -->
<app:alert>
<Body:>
<div id=page>
<div id=messages>
<ul id=messageList>
{#each _room.messages}
<app:message>
{/}
</ul>
</div>
<div id=foot>
<img id=inputPic src=/img/s.png class="pic {_user.picClass}" alt="">
<div id=inputs>
<input id=inputName value={_user.name}>
<form id=inputForm x-bind=submit:postMessage>
<input id=commentInput value={_newComment} autofocus>
</form>
</div>
</div>
</div>
<!--
connected and canConnect are built-in properties of model. If a variable
is not defined in the current context, it will be looked up in the model
data and the model properties
-->
<alert:>
<div id=alert>
<!--
Handlebars syntax is used for conditional blocks, except that the
name need not be repeated in the closing tag or if-else blocks
-->
{#unless connected}
<p>
{#if canConnect}
<!-- Leading space is removed, and trailing space is maintained -->
Offline
{#if _showReconnect}&ndash; <a x-bind=click:connect>Reconnect</a>{/}
{else}
Unable to reconnect &ndash; <a x-bind=click:reload>Reload</a>
{/}
</p>
{/}
</div>
<message:>
<li>
<!-- Square brackets perform interpolation within a model name -->
<img src=img/s.png class="pic {{users.[userId].picClass}}" alt="">
<div class=message>
<p class=time>{._displayTime}</p>
<p><b>{users.[userId].name}</b></p>
<p>{{comment}}</p>
</div>
</li>