193 lines
6.5 KiB
JavaScript
193 lines
6.5 KiB
JavaScript
(function(context,$) {
|
|
|
|
"use strict";
|
|
|
|
context.JK = context.JK || {};
|
|
|
|
var JamKazam = context.JK.JamKazam = function() {
|
|
var app;
|
|
var logger = context.JK.logger;
|
|
var heartbeatInterval = null;
|
|
var subscribers = {}; // Keys are MessageType.MESSAGE values Values are lists of functions to call
|
|
|
|
var opts = {
|
|
layoutOpts: {}
|
|
};
|
|
|
|
/**
|
|
* Dynamically build routes from markup. Any layout="screen" will get a route corresponding to
|
|
* his layout-id attribute. If a layout-arg attribute is present, that will be named as a data
|
|
* section of the route.
|
|
*/
|
|
function routing() {
|
|
var routes = context.RouteMap,
|
|
rules = {},
|
|
rule,
|
|
routingContext = {};
|
|
$('div[layout="screen"]').each(function() {
|
|
var target = $(this).attr('layout-id'),
|
|
targetUrl = target,
|
|
targetArg = $(this).attr('layout-arg'),
|
|
fn = function(data) {
|
|
app.layout.changeToScreen(target, data);
|
|
};
|
|
if (targetArg) {
|
|
targetUrl += "/:" + targetArg;
|
|
}
|
|
rules[target] = {route: '/' + targetUrl + '/d:?', method: target};
|
|
routingContext[target] = fn;
|
|
});
|
|
routes.context(routingContext);
|
|
for (rule in rules) if (rules.hasOwnProperty(rule)) routes.add(rules[rule]);
|
|
$(context).bind('hashchange', routes.handler);
|
|
$(routes.handler);
|
|
}
|
|
|
|
/**
|
|
* Handle a websocket message
|
|
*/
|
|
function handleMessage(header, payload) {
|
|
logger.debug(header.type + ": " + JSON.stringify(payload));
|
|
if (header.type in subscribers) {
|
|
$.each(subscribers[header.type], function() {
|
|
try {
|
|
this.call(context.JK, header, payload);
|
|
} catch (ex) {
|
|
logger.warn(ex);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function _handleLoginAck(header, payload) {
|
|
var heartbeatMS = payload.heartbeat_interval * 1000;
|
|
logger.debug("Login ACK. Setting up heartbeat every " + heartbeatMS + " MS");
|
|
heartbeatInterval = context.setInterval(_heartbeat, heartbeatMS);
|
|
}
|
|
|
|
function _heartbeat() {
|
|
var message = context.JK.MessageFactory.heartbeat();
|
|
context.JK.JamServer.send(message);
|
|
}
|
|
|
|
function loggedIn(header, payload) {
|
|
app.clientId = payload.client_id;
|
|
}
|
|
|
|
function registerLoginAck() {
|
|
logger.debug("register for loggedIn to set clientId");
|
|
context.JK.JamServer.registerMessageCallback(
|
|
context.JK.MessageType.LOGIN_ACK, loggedIn);
|
|
}
|
|
|
|
/**
|
|
* Generic error handler for Ajax calls.
|
|
*/
|
|
function ajaxError(jqXHR, textStatus, errorMessage) {
|
|
app.notify({title: textStatus, text: errorMessage, detail: jqXHR.responseText});
|
|
}
|
|
|
|
/**
|
|
* Register for all known types, logging events as they happen, and
|
|
* notifying subscribers (see this.subscribe) as they occur.
|
|
*/
|
|
function registerMessages() {
|
|
for (var message in context.JK.MessageType) {
|
|
logger.debug("registering " + message);
|
|
context.JK.JamServer.registerMessageCallback(message, handleMessage);
|
|
}
|
|
// Setup the heartbeat calls:
|
|
context.JK.JamServer.registerMessageCallback(context.JK.MessageType.LOGIN_ACK, _handleLoginAck);
|
|
}
|
|
|
|
/**
|
|
* Provide a function to call when a certain event type happens.
|
|
* No checks for dupes here, so take care to not add the same handler
|
|
* for the same event type repeatedly.
|
|
* Event Types should be one of the values in JK.MessageType
|
|
*/
|
|
this.subscribe = function(eventType, handler) {
|
|
if (!(eventType in subscribers)) {
|
|
subscribers[eventType] = [];
|
|
}
|
|
subscribers[eventType].push(handler);
|
|
};
|
|
|
|
/**
|
|
* Expose event firing. Generally not to be used except by tests.
|
|
*/
|
|
this.fireEvent = handleMessage;
|
|
|
|
/**
|
|
* Expose ajaxError.
|
|
*/
|
|
this.ajaxError = ajaxError;
|
|
|
|
/**
|
|
* Provide a handler object for events related to a particular screen
|
|
* being shown or hidden.
|
|
* @screen is a string corresponding to the screen's layout-id attribute
|
|
* @handler is an object with up to four optional keys:
|
|
* beforeHide, afterHide, beforeShow, afterShow, which should all have
|
|
* functions as values. If there is data provided by the screen's route
|
|
* it will be provided to these functions.
|
|
*/
|
|
this.bindScreen = function(screen, handler) {
|
|
this.layout.bindScreen(screen, handler);
|
|
};
|
|
|
|
/**
|
|
* Show a notification. Expects an object with a
|
|
* title property and a text property.
|
|
*/
|
|
this.notify = function(message) {
|
|
this.layout.notify(message);
|
|
};
|
|
|
|
/**
|
|
* Initialize any common events.
|
|
*/
|
|
function events() {
|
|
// Hook up the screen navigation controls.
|
|
$(".content-nav .arrow-left").click(function(evt) {
|
|
evt.preventDefault();
|
|
context.history.back();
|
|
return false;
|
|
});
|
|
$(".content-nav .arrow-right").click(function(evt) {
|
|
evt.preventDefault();
|
|
context.history.forward();
|
|
return false;
|
|
});
|
|
}
|
|
|
|
this.initialize = function(inOpts) {
|
|
var url, hash;
|
|
app = this;
|
|
this.opts = $.extend(opts, inOpts);
|
|
this.layout = new context.JK.Layout();
|
|
this.layout.initialize(this.opts.layoutOpts);
|
|
routing();
|
|
registerMessages();
|
|
registerLoginAck();
|
|
|
|
events();
|
|
|
|
hash = context.location.hash;
|
|
url = '#/ftue1';
|
|
if (hash) {
|
|
url = hash;
|
|
}
|
|
context.location = url;
|
|
};
|
|
|
|
/**
|
|
* Expose clientId as a public variable.
|
|
* Will be set upon LOGIN_ACK
|
|
*/
|
|
this.clientId = null;
|
|
|
|
return this;
|
|
};
|
|
|
|
}(window,jQuery)); |