Files
vgstation13/nano/js/nano_update.js
2014-01-07 21:01:00 -08:00

236 lines
6.0 KiB
JavaScript

// NanoUpdate handles data from the server and uses it to render templates
NanoUpdate = function ()
{
// _isInitialised is set to true when all of this ui's templates have been processed/rendered
var _isInitialised = false;
// the array of template names to use for this ui
var _templates = null;
// the data for this ui
var _data = null;
// new data which arrives before _isInitialised is true is stored here for processing later
var _earlyUpdateData = null;
// this is an array of callbacks which are called when new data arrives, before it is processed
var _beforeUpdateCallbacks = [];
// this is an array of callbacks which are called when new data arrives, before it is processed
var _afterUpdateCallbacks = [];
// _canClick is used to disable clicks for a short period after each click (to avoid mis-clicks)
var _canClick = true;
// the init function is called when the ui has loaded
// this function sets up the templates and base functionality
var init = function ()
{
$('#uiNoJavaScript').html('Loading...');
// this callback is triggered after new data is processed
// it updates the status/visibility icon and adds click event handling to buttons/links
NanoUpdate.addAfterUpdateCallback(function (updateData) {
var uiStatusClass;
if (updateData['ui']['status'] == 2)
{
uiStatusClass = 'icon24 uiStatusGood';
$('.linkActive').removeClass('inactive');
}
else if (updateData['ui']['status'] == 1)
{
uiStatusClass = 'icon24 uiStatusAverage';
$('.linkActive').addClass('inactive');
}
else
{
uiStatusClass = 'icon24 uiStatusBad'
$('.linkActive').addClass('inactive');
}
$('#uiStatusIcon').attr('class', uiStatusClass);
$('.linkActive').stopTime('linkPending');
$('.linkActive').removeClass('linkPending');
$('.linkActive').off('click');
$('.linkActive').on('click', function (event) {
event.preventDefault();
var href = $(this).data('href');
if (href != null && _canClick)
{
_canClick = false;
$('body').oneTime(300, 'enableClick', function () {
_canClick = true;
});
if (updateData['ui']['status'] == 2)
{
$(this).oneTime(300, 'linkPending', function () {
$(this).addClass('linkPending');
});
}
window.location.href = href;
}
});
});
// We store initialData and templateData in the body tag, it's as good a place as any
var body = $('body');
var templateData = body.data('templateData');
var initialData = body.data('initialData');
if (templateData == null || !initialData == null)
{
alert('Error: Initial data did not load correctly.');
}
// we count the number of templates for this ui so that we know when they've all been rendered
var templateCount = 0;
for (var key in templateData)
{
if (templateData.hasOwnProperty(key))
{
templateCount++;
}
}
if (!templateCount)
{
alert('ERROR: No templates listed!');
}
// load markup for each template and register it
for (var key in templateData)
{
if (templateData.hasOwnProperty(key))
{
$.when($.get(templateData[key]))
.done(function(templateMarkup) {
if (_templates == null)
{
_templates = {};
}
templateMarkup = templateMarkup.replace(/ +\) *\}\}/g, ')}}');
templateMarkup += '<div class="clearBoth"></div>'
try
{
_templates[key] = $.templates(key, templateMarkup);
templateCount--;
if (templateCount <= 0)
{
if (_earlyUpdateData !== null) // Newer data has already arrived, so update
{
renderTemplates(_earlyUpdateData);
}
else
{
renderTemplates(initialData);
}
_isInitialised = true;
$('#uiNoJavaScript').hide();
}
executeCallbacks(_afterUpdateCallbacks, _data);
}
catch(error)
{
alert('ERROR: An error occurred while loading the UI: ' + error.message);
return;
}
});
}
}
};
// Receive update data from the server
var receiveUpdateData = function (jsonString)
{
var updateData;
try
{
// parse the JSON string from the server into a JSON object
updateData = jQuery.parseJSON(jsonString);
}
catch (error)
{
alert(error.Message);
return;
}
if (_isInitialised) // all templates have been registered, so render them
{
executeCallbacks(_beforeUpdateCallbacks, updateData);
renderTemplates(updateData);
executeCallbacks(_afterUpdateCallbacks, updateData);
}
else
{
_earlyUpdateData = updateData; // all templates have not been registered. We set _earlyUpdateData which will be applied after the template is loaded with the initial data
}
};
// This function renders the template with the latest data
// It has to be done recursively as each piece of data is observed individually and needs to be updated individually
var renderTemplates = function (data)
{
if (!_templates.hasOwnProperty("main"))
{
alert('Error: Main template not found.');
}
_data = data;
try
{
$("#mainTemplate").html(_templates["main"].render(_data));
}
catch(error)
{
alert('ERROR: An error occurred while rendering the UI: ' + error.message);
return;
}
};
// Execute all callbacks in the callbacks array/object provided, updateData is passed to them for processing
var executeCallbacks = function (callbacks, updateData)
{
for (var index in callbacks)
{
callbacks[index].call(this, updateData);
}
return updateData;
};
return {
init: function ()
{
init();
},
isInitialised: function ()
{
return _isInitialised;
},
receiveUpdateData: function (jsonString)
{
receiveUpdateData(jsonString);
},
addBeforeUpdateCallback: function (callbackFunction)
{
_beforeUpdateCallbacks.push(callbackFunction);
},
addAfterUpdateCallback: function (callbackFunction)
{
_afterUpdateCallbacks.push(callbackFunction);
}
};
} ();
$(document).ready(function()
{
NanoUpdate.init();
});