Craig Austgen, Brian Capouch, Nathan Samano
Saint Joseph's College
http://slides.com/capouch/deck-1/live
Instead of a steady flow of page request/response interaction, there is a one-time transfer of a control program (and its data) from the server to the browser.
The program then takes over the browser window and directs all communication with both the enduser and the backend server.
-- Michael Mikowski
<!-- Let's get started -->
<script>
// Calling the toplevel initModule starts up the SPA
$(function () { spa.initModule( $('#spa') ); });
</script>
</head>
<body>
<main id="spa"></main>
</body>
</html>
index.html
The SPA takes full ownership of routing requests within its namespace, i.e. it owns all of the URL past the hostname
The shell is a command and control interpreter, named to suggest its analogy to the well-known OS shell
// Watch a file and let clients know if/when one changes
setWatch = function ( url_path, file_type ) {
console.log( 'setWatch called on ' + url_path );
//
if ( ! watchMap[ url_path ] ) {
console.log( 'setting watch on ' + url_path );
// Part of Node's native 'fs' package
fsHandle.watchFile(
url_path.slice(1),
function ( current, previous ) {
console.log( 'file accessed' );
// Send notice
if ( current.mtime !== previous.mtime ) {
console.log( 'file changed: ' + url_path);
io.sockets.emit( file_type, url_path );
}
}
);
watchMap[ url_path ] = true;
}
};
// Process all traffic looking for "magic names"
app.use( function ( request, response, next ) {
// Watch for changes to /js/data.js or /css/sockstyle.css file
if ( request.url.indexOf( '/js/data.js' ) >= 0 ) {
setWatch( request.url, 'script' );
}
else if ( request.url.indexOf( '/css/sockstyle.css' ) >= 0 ) {
setWatch( request.url, 'stylesheet' );
}
next();
app.use( express.static( __dirname + '/' ) );
});
var dummyPage = '<b>Name: </b>Javier Flores'
+ '<br><b> Address: </b>101 Calle Mayor'
+ '<br><b> Age: </b>52';
+ '<script id="sock_js" src="/js/data.js"></script>'
// Display the value of var "dummyPage" from the data.js file
$(function () {
jqueryMap.$socketIO.html( dummyPage );
});
// Set event handler to react to "script" message
io.connect(serverURL).on('script', function (path) {
$( '#sock_js' ).remove();
// Replace contents of element with freshly-loaded value
jqueryMap.$container.append(
'<script id="sock_js" src="'
+ path +
'"></script>'
);
// Redisplay HTML with new JavaScript
jqueryMap.$socketIO.html( dummyPage );
});
// Set event handler to react to "stylesheet" message
io.connect(serverURL).on('stylesheet', function (path) {
// Get rid of current style
$( '#sock_css' ).remove();
// Replace contents of stylesheet with file from websocket
// Note which container you append to here is crucial
jqueryMap.$container.append(
'<link id="sock_css" rel="stylesheet" href="'
+ path +
'"/>'
);
// Redisplay HTML with new styling
jqueryMap.$socketIO.html( dummyPage );
});
#!/bin/bash
cp js/intl/data.js-es js/data.js
cp css/intl/sockstyle.css-es css/sockstyle.css
// Spanish "version" of our SPA view
var dummyPage = '<b>Nombre: </b>Javier Flores'
+ '<br><b> Dirección: </b>101 Calle Mayor'
+ '<br><b> Edad: </b>52<br><b> Estado: </b> D.F.';
curl http://localhost:8000
Traditional crawlers' view
of index.html
curl http://localhost:8000/?_escaped_fragment_=