Skip to content

Instantly share code, notes, and snippets.

@tbranyen
Created June 3, 2011 02:29
Show Gist options
  • Save tbranyen/1005747 to your computer and use it in GitHub Desktop.
Save tbranyen/1005747 to your computer and use it in GitHub Desktop.
Synchronize yo HTML5 slides
(function(window, document) {
// The end user should be allowed to disable synchronization. This button
// is optional on the page
var syncAllow = true;
var syncButton = document.querySelector('.sync-button');
// If the sync button exists bind a click event and toggle the syncAllow
// boolean. Set the value of the button.
if(syncButton) {
syncButton.addEventListener('click', function() {
syncAllow = !syncAllow;
syncButton.setAttribute('value', syncAllow ? 'Turn Sync Off'
: 'Turn Sync On');
}, true);
}
// The socket.io client side library connects to your server, the node address
// can be a domain name or an ip address.
var socket = new io.Socket('tabdeveloper.com', { port: 1987 });
// Connect the websocket (or fallback)
socket.connect();
// When the server pushes a message handle it accordingly
socket.on('message', function(e) {
// Set the hash to match the state
if(syncAllow && e.state) {
location.hash = e.state;
}
// If the message is cornify and cornify_add is a function, trigger.
if(e.cornify && typeof cornify_add === 'function') {
cornify_add();
}
// Reload the page to clear all the cornification.
if(e.refresh) {
location.reload(true);
}
});
})(this, this.document);
var server = 'http://tabdeveloper.com:1987/';
// Luckily a response from the server is never required. So
// a basic XHR GET request to the server will trigger the
// action appropriately.
function xhr(url) {
var request = new window.XMLHttpRequest();
request.open('GET', url, true);
request.send(null);
}
// The values of the buttons correspond with the Node.js server
// routes.
var buttons = [].slice.call(document.getElementsByTagName('button'));
buttons.forEach(function(button) {
button.addEventListener('click', function() {
xhr(server + button.value);
}, true);
});
<button value="reset">RESET</button>
<button value="refresh">REFRESH</button>
<div class="swipe"> SWIPE </div>
<button value="cornify">CORNIFY</button>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>HTML5 Slides Controller</title>
<style>
/* These styles are ugly but functional on iOS and Android */
html, body {
height: 100%;
border: 0;
margin: 0;
padding: 0;
}
button {
height: 20%;
width: 100%;
display: block;
font-size: 24px;
}
.swipe {
width: 100%;
height: 40%;
color: #FFF;
font-size: 24px;
background-color: #333;
}
</style>
</head>
<body>
<!-- If you use this controller pattern, make sure the values
correspond correctly to your bound paths in the Node.js
server -->
<button value="reset">RESET</button>
<button value="refresh">REFRESH</button>
<div class="swipe"> SWIPE </div>
<button value="cornify">CORNIFY</button>
<script>
(function(window, document) {
// To assist with swipe calculation originalX holds the starting
// touch X position, and x holds the ending X position. Swipe
// is an area for moving between slides. You may want to increase
// the swipe threshold variable if you find its too sensitive.
var originalX, x;
var swipe = document.querySelector('.swipe');
var swipeThreshold = 50;
var server = 'http://tabdeveloper.com:1987/';
// Luckily a response from the server is never required. So
// a basic XHR GET request to the server will trigger the
// action appropriately.
function xhr(url) {
var request = new window.XMLHttpRequest();
request.open('GET', url, true);
request.send(null);
}
// The values of the buttons correspond with the Node.js server
// routes.
var buttons = [].slice.call(document.getElementsByTagName('button'));
buttons.forEach(function(button) {
button.addEventListener('click', function() {
xhr(server + button.value);
}, true);
});
// Swiping is relatively simple to implement and very effective to
// use. Three events are needed, touchstart, touchmove, and
// touchend. Touchstart sets the original position.
swipe.addEventListener('touchstart', function(e) {
originalX = e.touches[0].pageX;
}, true);
// Touchmove updates the end position.
swipe.addEventListener('touchmove', function(e) {
e.preventDefault();
x = e.touches[0].pageX;
}, true);
// Touchend determines if a swipe occurred.
swipe.addEventListener('touchend', function(e) {
// If swipe is forward, advance.
if ((originalX - x) > swipeThreshold) {
xhr(server + 'advance');
}
// If swipe is backward, recede.
if ((x - originalX) > swipeThreshold) {
xhr(server + 'recede');
}
}, true);
})(this, this.document);
</script>
</body>
</html>
...
<head>
...
<!-- HTML5 slides scripts, put these underneath -->
<script src="http://www.cornify.com/js/cornify.js"></script>
<script src="http://tabdeveloper.com:1987/socket.io/socket.io.js"></script>
<script src="client.js"></script>
...
</head>
...
<body>
...
<!-- Optionally slap in a sync button -->
<input type="button" class="sync-button" value="Turn Sync Off">
...
// For each connection made add the client to the
// list of clients.
socket.on('connection', function(client) {
clients.push(client);
});
// This is a simple wrapper for sending a message
// to all the connected users and pruning out the
// disconnected ones.
function send(message) {
// Iterate through all potential clients
clients.forEach(function(client) {
// User is still connected, send message
if(client._open) {
client.send(message);
}
// Prune out disconnected user
else {
delete client;
}
});
}
// Listen on some high level port to avoid dealing
// with authbind or root user privileges.
app.listen(1987);
// Required dependancies
var io = require('socket.io');
var app = require('express').createServer();
var fs = require('fs');
// State is the current slide position
var state = 1
// Clients is a list of users who have connected
var clients = [];
// Bind socket.io to express
var socket = io.listen(app);
// Advancing will... move the slides forward!
app.get('/advance', function(req, res) {
// Increment and send over socket
state++;
send({ state: state });
// Send the state as a response
res.send(state.toString());
});
// Receding will... move the slides backwards!
app.get('/recede', function(req, res) {
state--;
send({ state: state });
res.send(state.toString());
});
// This will allow the presenter to clear the
// slides of any cornification.
app.get('/refresh', function(req, res) {
client.send({ refresh: true });
res.send(state.toString());
});
// Reset will not refresh cornfication, but
// will send the slides back to the beginning.
app.get('/reset', function(req, res) {
state = 1;
send({ state: state });
res.send(state.toString());
});
// Give your viewers what they really want...
// an unrepentable amount of unicorns.
app.get('/cornify', function(req, res) {
send({ cornify: true });
res.send(state.toString());
});
// Send the controller for any other request to this
// Node.js server.
app.get('*', function(req, res) {
fs.readFile('controller.html', function(err, buffer) {
res.send(buffer.toString());
});
});
// Required dependancies
var io = require('socket.io');
var app = require('express').createServer();
var fs = require('fs');
// State is the current slide position
var state = 1
// Clients is a list of users who have connected
var clients = [];
// Bind socket.io to express
var socket = io.listen(app);
// For each connection made add the client to the
// list of clients.
socket.on('connection', function(client) {
clients.push(client);
});
// This is a simple wrapper for sending a message
// to all the connected users and pruning out the
// disconnected ones.
function send(message) {
// Iterate through all potential clients
clients.forEach(function(client) {
// User is still connected, send message
if(client._open) {
client.send(message);
}
// Prune out disconnected user
else {
delete client;
}
});
}
// Advancing will... move the slides forward!
app.get('/advance', function(req, res) {
// Increment and send over socket
state++;
send({ state: state });
// Send the state as a response
res.send(state.toString());
});
// Receding will... move the slides backwards!
app.get('/recede', function(req, res) {
state--;
send({ state: state });
res.send(state.toString());
});
// This will allow the presenter to clear the
// slides of any cornification.
app.get('/refresh', function(req, res) {
client.send({ refresh: true });
res.send(state.toString());
});
// Reset will not refresh cornfication, but
// will send the slides back to the beginning.
app.get('/reset', function(req, res) {
state = 1;
send({ state: state });
res.send(state.toString());
});
// Give your viewers what they really want...
// an unrepentable amount of unicorns.
app.get('/cornify', function(req, res) {
send({ cornify: true });
res.send(state.toString());
});
// Send the controller for any other request to this
// Node.js server.
app.get('*', function(req, res) {
fs.readFile('controller.html', function(err, buffer) {
res.send(buffer.toString());
});
});
// Listen on some high level port to avoid dealing
// with authbind or root user privileges.
app.listen(1987);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment