updated app
2
node_modules/derby-examples/chat/Makefile
generated
vendored
Normal 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
@@ -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
@@ -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
@@ -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'
|
||||
}
|
||||
});
|
||||
27
node_modules/derby-examples/chat/lib/server/serverError.js
generated
vendored
Normal 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
@@ -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
|
After Width: | Height: | Size: 16 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_blue.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_cyan.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_dark_gray.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_green.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_light_gray.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_magenta.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_orange.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_purple.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_red.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_red_orig.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
node_modules/derby-examples/chat/public/img/user_yellow.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
1
node_modules/derby-examples/chat/server.js
generated
vendored
Normal 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
@@ -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', ''
|
||||
12
node_modules/derby-examples/chat/src/chat/inline.coffee
generated
vendored
Normal 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
|
||||
57
node_modules/derby-examples/chat/src/server/index.coffee
generated
vendored
Normal 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'}
|
||||
18
node_modules/derby-examples/chat/src/server/serverError.coffee
generated
vendored
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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}– <a x-bind=click:connect>Reconnect</a>{/}
|
||||
{else}
|
||||
Unable to reconnect – <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>
|
||||