diff --git a/README.md b/README.md
index 0ce36e6..ea5306f 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,6 @@ column.
* nodejs
* npm
-* Static web server
##Install
@@ -24,17 +23,20 @@ $ cp config/database.coffee.sample database.coffee
```
* Edit settings in application.coffee and database.coffee as necessary
-* Setup your web server to serve the public directory
##Usage
-Go to URL setup in your static web server!
+```
+$ coffee dbmonitor.coffee
+```
+
+Access the application in your browser using the port you have configured.
##License
The MIT License
-Copyright (c) 2012 Andrew Tomaka
+Copyright (c) 2013 Andrew Tomaka
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/dbmonitor.coffee b/dbmonitor.coffee
index 1517663..902e3a1 100644
--- a/dbmonitor.coffee
+++ b/dbmonitor.coffee
@@ -2,10 +2,9 @@ database = require './config/database.coffee'
application = require './config/application.coffee'
moment = require 'moment'
-io = require('socket.io').listen(application.port)
+fs = require 'fs'
sockets = []
-io.set('log level', 1);
db = require('mysql-native').createTCPClient(database.host, database.port)
db.auth database.database, database.username, database.password
@@ -24,6 +23,26 @@ updateClient = (job) ->
for client in sockets
client.emit 'update', job
+http = require('http').createServer((req, res) ->
+ if req.url == '/'
+ res.writeHead 200, {'Content-Type': 'text/html'}
+ res.end fs.readFileSync('public/index.html')
+ else if req.url == '/css/style.css'
+ res.writeHead 200, {'Content-Type': 'text/css'}
+ res.end fs.readFileSync('public/css/style.css')
+ else if req.url == '/js/jquery.mustache.js'
+ res.writeHead 200, {'Content-Type': 'text/javascript'}
+ res.end fs.readFileSync('public/js/jquery.mustache.js')
+ else if req.url == '/templates/views.html'
+ res.writeHead 200, {'Content-Type': 'text/html'}
+ res.end fs.readFileSync('public/templates/views.html')
+ else
+ res.writeHead 404, {"Content-Type": "text/plain"}
+ res.end "404 Not Found\n"
+).listen application.port
+
+io = require('socket.io').listen(http)
+io.set('log level', 1);
io.sockets.on 'connection', (socket) ->
sockets.push socket
diff --git a/public/index.html b/public/index.html
index 6c93305..7efa263 100644
--- a/public/index.html
+++ b/public/index.html
@@ -10,13 +10,12 @@
-
+
`
+ domTemplateType: 'text/html',
+
+ // Specifies the `dataType` attribute used when external templates are loaded.
+ externalTemplateDataType: 'text'
+ };
+
+ function getMustache() {
+ // Lazily retrieve Mustache from the window global if it hasn't been defined by
+ // the User.
+ if (instance === null) {
+ instance = window.Mustache;
+ if (instance === void 0) {
+ $.error("Failed to locate Mustache instance, are you sure it has been loaded?");
+ }
+ }
+ return instance;
+ }
+
+ /**
+ * Returns true if the supplied templateName has been added.
+ */
+ function has(templateName) {
+ return templateMap[templateName] !== void 0;
+ }
+
+ /**
+ * Registers a template so that it can be used by $.Mustache.
+ *
+ * @param templateName A name which uniquely identifies this template.
+ * @param templateHtml The HTML which makes us the template; this will be rendered by Mustache when render()
+ * is invoked.
+ * @throws If options.allowOverwrite is false and the templateName has already been registered.
+ */
+ function add(templateName, templateHtml) {
+ if (!options.allowOverwrite && has(templateName)) {
+ $.error('TemplateName: ' + templateName + ' is already mapped.');
+ return;
+ }
+ templateMap[templateName] = $.trim(templateHtml);
+ }
+
+ /**
+ * Adds one or more tempaltes from the DOM using either the supplied templateElementIds or by retrieving all script
+ * tags of the 'domTemplateType'. Templates added in this fashion will be registered with their elementId value.
+ *
+ * @param [...templateElementIds] List of element id's present on the DOM which contain templates to be added;
+ * if none are supplied all script tags that are of the same type as the
+ * `options.domTemplateType` configuration value will be added.
+ */
+ function addFromDom() {
+ var templateElementIds;
+
+ // If no args are supplied, all script blocks will be read from the document.
+ if (arguments.length === 0) {
+ templateElementIds = $('script[type="' + options.domTemplateType + '"]').map(function () {
+ return this.id;
+ });
+ }
+ else {
+ templateElementIds = $.makeArray(arguments);
+ }
+
+ $.each(templateElementIds, function() {
+ var templateElement = document.getElementById(this);
+
+ if (templateElement === null) {
+ $.error('No such elementId: #' + this);
+ }
+ else {
+ add(this, $(templateElement).html());
+ }
+ });
+ }
+
+ /**
+ * Removes a template, the contents of the removed Template will be returned.
+ *
+ * @param templateName The name of the previously registered Mustache template that you wish to remove.
+ * @returns String which represents the raw content of the template.
+ */
+ function remove(templateName) {
+ var result = templateMap[templateName];
+ delete templateMap[templateName];
+ return result;
+ }
+
+ /**
+ * Removes all templates and tells Mustache to flush its cache.
+ */
+ function clear() {
+ templateMap = {};
+ getMustache().clearCache();
+ }
+
+ /**
+ * Renders a previously added Mustache template using the supplied templateData object. Note if the supplied
+ * templateName doesn't exist an empty String will be returned.
+ */
+ function render(templateName, templateData) {
+ if (!has(templateName)) {
+ if (options.warnOnMissingTemplates) {
+ $.error('No template registered for: ' + templateName);
+ }
+ return '';
+ }
+ return getMustache().to_html(templateMap[templateName], templateData, templateMap);
+ }
+
+ /**
+ * Loads the external Mustache templates located at the supplied URL and registers them for later use. This method
+ * returns a jQuery Promise and also support an `onComplete` callback.
+ *
+ * @param url URL of the external Mustache template file to load.
+ * @param onComplete Optional callback function which will be invoked when the templates from the supplied URL
+ * have been loaded and are ready for use.
+ * @returns jQuery deferred promise which will complete when the templates have been loaded and are
+ * ready for use.
+ */
+ function load(url, onComplete) {
+ return $.ajax({
+ url: url,
+ dataType: options.externalTemplateDataType
+ }).done(function (templates) {
+ $(templates).filter('script').each(function (i, el) {
+ add(el.id, $(el).html());
+ });
+
+ if ($.isFunction(onComplete)) {
+ onComplete();
+ }
+ });
+ }
+
+ /**
+ * Returns an Array of templateNames which have been registered and can be retrieved via
+ * $.Mustache.render() or $(element).mustache().
+ */
+ function templates() {
+ return $.map(templateMap, function (value, key) {
+ return key;
+ });
+ }
+
+ // Expose the public methods on jQuery.Mustache
+ $.Mustache = {
+ options: options,
+ load: load,
+ add: add,
+ addFromDom: addFromDom,
+ remove: remove,
+ clear: clear,
+ render: render,
+ templates: templates,
+ instance: instance
+ };
+
+ /**
+ * Renders one or more viewModels into the current jQuery element.
+ *
+ * @param templateName The name of the Mustache template you wish to render, Note that the
+ * template must have been previously loaded and / or added.
+ * @param templateData One or more JavaScript objects which will be used to render the Mustache
+ * template.
+ * @param options.method jQuery method to use when rendering, defaults to 'append'.
+ */
+ $.fn.mustache = function (templateName, templateData, options) {
+ var settings = $.extend({
+ method: 'append'
+ }, options);
+
+ var renderTemplate = function (obj, viewModel) {
+ $(obj)[settings.method](render(templateName, viewModel));
+ };
+
+ return this.each(function () {
+ var element = this;
+
+ // Render a collection of viewModels.
+ if ($.isArray(templateData)) {
+ $.each(templateData, function () {
+ renderTemplate(element, this);
+ });
+ }
+
+ // Render a single viewModel.
+ else {
+ renderTemplate(element, templateData);
+ }
+ });
+ };
+
+}(jQuery, window));
\ No newline at end of file