// NanoStateManager handles data from the server and uses it to render templates
NanoStateManager = function ()
{
// _isInitialised is set to true when all of this ui's templates have been processed/rendered
var _isInitialised = false;
// the data for this ui
var _data = 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 = {};
// this is an array of state objects, these can be used to provide custom javascript logic
var _states = {};
var _currentState = null;
// the init function is called when the ui has loaded
// this function sets up the templates and base functionality
var init = function ()
{
// We store initialData and templateData in the body tag, it's as good a place as any
_data = $('body').data('initialData');
if (_data == null || !_data.hasOwnProperty('config') || !_data.hasOwnProperty('data'))
{
alert('Error: Initial data did not load correctly.');
}
var stateKey = 'default';
if (_data['config'].hasOwnProperty('stateKey') && _data['config']['stateKey'])
{
stateKey = _data['config']['stateKey'].toLowerCase();
}
NanoStateManager.setCurrentState(stateKey);
$(document).on('templatesLoaded', function () {
doUpdate(_data);
_isInitialised = true;
});
};
// Receive update data from the server
var receiveUpdateData = function (jsonString)
{
var updateData;
//alert("recieveUpdateData called." + "
Type: " + typeof jsonString); //debug hook
try
{
// parse the JSON string from the server into a JSON object
updateData = jQuery.parseJSON(jsonString);
}
catch (error)
{
alert("recieveUpdateData failed. " + "
Error name: " + error.name + "
Error Message: " + error.message);
return;
}
//alert("recieveUpdateData passed trycatch block."); //debug hook
if (!updateData.hasOwnProperty('data'))
{
if (_data && _data.hasOwnProperty('data'))
{
updateData['data'] = _data['data'];
}
else
{
updateData['data'] = {};
}
}
if (_isInitialised) // all templates have been registered, so render them
{
doUpdate(updateData);
}
else
{
_data = updateData; // all templates have not been registered. We set _data directly here which will be applied after the template is loaded with the initial data
}
};
// This function does the update by calling the methods on the current state
var doUpdate = function (data)
{
if (_currentState == null)
{
return;
}
data = _currentState.onBeforeUpdate(data);
if (data === false)
{
alert('data is false, return');
return; // A beforeUpdateCallback returned a false value, this prevents the render from occuring
}
_data = data;
_currentState.onUpdate(_data);
_currentState.onAfterUpdate(_data);
};
// Execute all callbacks in the callbacks array/object provided, updateData is passed to them for processing and potential modification
var executeCallbacks = function (callbacks, data)
{
for (var key in callbacks)
{
if (callbacks.hasOwnProperty(key) && jQuery.isFunction(callbacks[key]))
{
data = callbacks[key].call(this, data);
}
}
return data;
};
return {
init: function ()
{
init();
},
receiveUpdateData: function (jsonString)
{
receiveUpdateData(jsonString);
},
addBeforeUpdateCallback: function (key, callbackFunction)
{
_beforeUpdateCallbacks[key] = callbackFunction;
},
addBeforeUpdateCallbacks: function (callbacks) {
for (var callbackKey in callbacks) {
if (!callbacks.hasOwnProperty(callbackKey))
{
continue;
}
NanoStateManager.addBeforeUpdateCallback(callbackKey, callbacks[callbackKey]);
}
},
removeBeforeUpdateCallback: function (key)
{
if (_beforeUpdateCallbacks.hasOwnProperty(key))
{
delete _beforeUpdateCallbacks[key];
}
},
executeBeforeUpdateCallbacks: function (data) {
return executeCallbacks(_beforeUpdateCallbacks, data);
},
addAfterUpdateCallback: function (key, callbackFunction)
{
_afterUpdateCallbacks[key] = callbackFunction;
},
addAfterUpdateCallbacks: function (callbacks) {
for (var callbackKey in callbacks) {
if (!callbacks.hasOwnProperty(callbackKey))
{
continue;
}
NanoStateManager.addAfterUpdateCallback(callbackKey, callbacks[callbackKey]);
}
},
removeAfterUpdateCallback: function (key)
{
if (_afterUpdateCallbacks.hasOwnProperty(key))
{
delete _afterUpdateCallbacks[key];
}
},
executeAfterUpdateCallbacks: function (data) {
return executeCallbacks(_afterUpdateCallbacks, data);
},
addState: function (state)
{
if (!(state instanceof NanoStateClass))
{
alert('ERROR: Attempted to add a state which is not instanceof NanoStateClass');
return;
}
if (!state.key)
{
alert('ERROR: Attempted to add a state with an invalid stateKey');
return;
}
_states[state.key] = state;
},
setCurrentState: function (stateKey)
{
if (typeof stateKey == 'undefined' || !stateKey) {
alert('ERROR: No state key was passed!');
return false;
}
if (!_states.hasOwnProperty(stateKey))
{
alert('ERROR: Attempted to set a current state which does not exist: ' + stateKey);
return false;
}
var previousState = _currentState;
_currentState = _states[stateKey];
if (previousState != null) {
previousState.onRemove(_currentState);
}
_currentState.onAdd(previousState);
return true;
},
getCurrentState: function ()
{
return _currentState;
}
};
} ();