var sys = require('sys'),
http = require('http'),
fs = require('fs'),
json = require('./json'),
faye = require('./faye');
var comet = new faye.NodeAdapter({mount: '/fayeclient', timeout: 45}),
client = comet.getClient();
// setup sync client; TODO move into a separate module
var state = {};
client.subscribe('/general', function(message) {
// TODO discard malformed messages
if (!message.client || !message.type) return;
sys.puts('sync noticed message from client ' + message.client);
sys.puts('message type == ' + message.type);
switch (message.type) {
case 'place' :
state[message.el] || (state[message.el] = {});
process.mixin(state[message.el], {
x: message.x,
y: message.y
});
break;
case 'text' :
process.mixin(state[message.el], {
text: message.text,
});
break;
case 'delete' :
delete state[message.el];
break;
}
sys.puts("state: ");
sys.puts(json.stringify(state));
});
var port = 80;
sys.puts('Listening on ' + port);
http.createServer(function(req, resp) {
sys.puts(req.method + ' ' + req.url);
if (comet.call(req, resp)) {
sys.puts('** Handled by faye');
return;
}
var path = (req.url === '/') ? '/index.html' : req.url;
if (path === '/sync') {
sys.puts('** Handled by syncserver');
resp.sendHeader(200, {'Content-Type': 'text/html'});
resp.write(json.stringify(state));
resp.close();
return;
}
sys.puts('** Handled by file server');
fs.readFile('./static/' + path).addCallback(function(content) {
resp.sendHeader(200, {'Content-Type': 'text/html'});
resp.write(content);
resp.close();
}).addErrback(function(){
resp.sendHeader(404, {'Content-Type': 'text/html'});
resp.write('<html><head><title>404 not found</title></head><body>404 Not Found</body></html>');
resp.close();
});
}).listen(port);
if (typeof console == "undefined") { console = {log: function(m){}} };
var Remote = function(fayeclient, clientId) {
var fayepath = '/general';
this.publish = function(message){
return fayeclient.publish(fayepath, message);
};
this.clientId = clientId;
fayeclient.subscribe(fayepath, function(message) {
console.log('message recieved');
console.log(message);
if (message.client == clientId) {
console.log('loopback; ignore');
return;
}
$('body').trigger('dg-message', message);
});
$('body').bind('dg-message', function(e, args) {
args.type && $('body').trigger('dg-' + args.type, args);
});
}
Remote.prototype = {
fire: function(eventType, parameters) {
console.log('starting fayesend');
var data = { client: this.clientId, type: eventType };
$.extend(data, parameters);
console.log('sending data');
console.log(data);
this.publish(data);
}
};
$(function(){
var getNewId = function() {
// TODO overwrite with a hashing algorithm?
return 'xxxxxxxx-xxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
};
$('body').bind('dg-place', function(e, message) {
console.log('place handler');
console.log(message);
if ($('#'+message.el)[0]) {
$('#'+message.el).css({
left: message.x,
top: message.y
});
} else {
newBox(message.el, {left: message.x, top: message.y});
}
console.log(message.el);
});
$('body').bind('dg-text', function(e, message) {
console.log('text handler');
console.log(message);
$('#'+message.el).html('<span class="dg-letter">'+message.text+'</span>');
});
$('body').bind('dg-delete', function(e, message) {
console.log('deletion handler');
console.log(message);
$('#'+message.el).remove();
});
var clientId = getNewId(),
fayeclient = new Faye.Client('/fayeclient'),
remote = new Remote(fayeclient, clientId),
selected = null,
select = function(el) {
$(selected).removeClass('dg-selected');
selected = el == null ? null : $(el).addClass('dg-selected');
},
newBox = function(id, data) {
var boxHtml = data.text
? '<div class="dg-box"><span class="dg-letter">'+data.text+'</div>'
: '<div class="dg-box"></div>';
return $(boxHtml).appendTo($('#dg-boxstart'))
.draggable({
containment: 'window',
distance: 30,
grid: [51, 51],
stop: function(event, ui){
if (ui.helper.hasClass('dg-dead')) return;
select(ui.helper);
remote.fire('place', {
el: ui.helper.attr('id'),
x: ui.position.left,
y: ui.position.top
});
}
}).css({
top: data.top || data.y,
left: data.left || data.x
}).attr('id', id)
.click(function(e) {
console.log('box click fired');
console.log(e.currentTarget);
select(e.currentTarget);
});
};
$(".dg-spawn").draggable({
containment: 'window',
grid: [51, 51],
helper: 'clone',
stop: function(event, ui){
var newId = 'dg-box-' + getNewId();
var box = newBox(newId, ui.position);
select(box);
remote.fire('place', {
el: newId,
x: ui.position.left,
y: ui.position.top,
});
}
});
$(".dg-trash").droppable({
drop: function(event, ui){
if (ui.draggable.hasClass('dg-target')) return;
remote.fire('delete', { el: ui.draggable.attr('id')});
ui.draggable.addClass('dg-dead').remove();
}
});
// listen for deselect-click
$('html').add('.dg-banner').click(function(e){
e.preventDefault();
// deselect any selected items
if (e.target == this) {
console.log('click deselect');
select(null);
}
});
// listen for ESC (deselect)
// TODO get this shit working
/*$(document).keypress(function(e){
console.log('keypress');
console.log(e);
e.charCode == 27 && console.log('ESC triggered');
});*/
$(document).keydown(function(e){
console.log('keydown');
console.log(e.keyCode);
var key = e.which || e.keyCode;
if (32 <= key && key <= 126) {
//set selected state to keyCode
var text = String.fromCharCode(key);
$(selected).html('<span class="dg-letter">' + text + '</div>');
remote.fire('text', { el: $(selected).attr('id'), text: text });
}
});
$.getJSON('/sync', function(data) {
console.log('sync data recieved: ');
console.log(data);
$.each(data, function(id, data) {
newBox(id, data);
});
});
});
<html>
<head>
<title>draggies</title>
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/combo?3.0.0/build/cssreset/reset-min.css&3.0.0/build/cssfonts/fonts-min.css">
<link rel="stylesheet" href="draggies.css"/>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"></script>
<script type="text/javascript" src="fayeclient.js"></script>
<script type="text/javascript" src="draggies.js"></script>
</head>
<body>
<div class="dg-banner">
<div class="dg-target dg-spawn">
Drag me
</div>
<div class="dg-target dg-trash">
Trash
</div>
</div>
<div id="dg-boxstart">
</div>
</body>
</html>
html, body {
background-color: #888;
}
.dg-banner {
border: 1px solid black;
border-left-width: 0;
border-right-width: 0;
background-color: white;
height: 120px;
position: relative;
}
.dg-target {
border: 2px solid black;
height: 100px;
width: 100px;
background-color: white;
}
.dg-spawn {
position: absolute;
top: 8px;
left: 8px;
}
.dg-trash {
position: absolute;
top: 8px;
right: 8px;
border-color: red;
color: red;
}
.dg-box {
height: 100px;
width: 100px;
background-color: white;
border: 1px solid black;
position: absolute;
top: 0;
left: 0;
text-align: center;
}
.dg-box .dg-letter {
font-size: 764%;
}
.dg-selected {
background-color: orange;
}
Users browsing this forum: No registered users and 1 guest