dhxmvp
Version:
A complete boilerplate for building online, offline and syncable MVP Single Page Applications using DHTMLX.
261 lines (214 loc) • 7.77 kB
JavaScript
/*jslint browser: true, devel: true, white: true */
/*global $dhx, dhtmlx */
/*
Copyright (c) 2010,2011,2012,2013,2014 Morgan Roderick http://roderick.dk
License: MIT - http://mrgnrdrck.mit-license.org
https://github.com/mroderick/PubSubJS
*/
(function(root, factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['exports'], factory);
} else if (typeof exports === 'object') {
// CommonJS
factory(exports);
} else {
// Browser globals
var PubSub = {};
root.PubSub = PubSub;
factory(PubSub);
}
}((typeof window === 'object' && window) || this, function(PubSub) {
'use strict';
var messages = {},
lastUid = -1;
function hasKeys(obj) {
var key;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
return true;
}
}
return false;
}
/**
* Returns a function that throws the passed exception, for use as argument for setTimeout
* @param { Object } ex An Error object
*/
function throwException(ex) {
return function reThrowException() {
throw ex;
};
}
function callSubscriberWithDelayedExceptions(subscriber, message, data) {
try {
subscriber(message, data);
} catch (ex) {
setTimeout(throwException(ex), 0);
}
}
function callSubscriberWithImmediateExceptions(subscriber, message, data) {
subscriber(message, data);
}
function deliverMessage(originalMessage, matchedMessage, data, immediateExceptions) {
var subscribers = messages[matchedMessage],
callSubscriber = immediateExceptions ? callSubscriberWithImmediateExceptions : callSubscriberWithDelayedExceptions,
s;
if (!messages.hasOwnProperty(matchedMessage)) {
return;
}
for (s in subscribers) {
if (subscribers.hasOwnProperty(s)) {
callSubscriber(subscribers[s], originalMessage, data);
}
}
}
function createDeliveryFunction(message, data, immediateExceptions) {
return function deliverNamespaced() {
var topic = String(message),
position = topic.lastIndexOf('.');
// deliver the message as it is now
deliverMessage(message, message, data, immediateExceptions);
// trim the hierarchy and deliver message to each level
while (position !== -1) {
topic = topic.substr(0, position);
position = topic.lastIndexOf('.');
deliverMessage(message, topic, data, immediateExceptions);
}
};
}
function messageHasSubscribers(message) {
var topic = String(message),
found = Boolean(messages.hasOwnProperty(topic) && hasKeys(messages[topic])),
position = topic.lastIndexOf('.');
while (!found && position !== -1) {
topic = topic.substr(0, position);
position = topic.lastIndexOf('.');
found = Boolean(messages.hasOwnProperty(topic) && hasKeys(messages[topic]));
}
return found;
}
function publish(message, data, sync, immediateExceptions) {
var deliver = createDeliveryFunction(message, data, immediateExceptions),
hasSubscribers = messageHasSubscribers(message);
if (!hasSubscribers) {
return false;
}
if (sync === true) {
deliver();
} else {
setTimeout(deliver, 0);
}
return true;
}
/**
* PubSub.publish( message[, data] ) -> Boolean
* - message (String): The message to publish
* - data: The data to pass to subscribers
* Publishes the the message, passing the data to it's subscribers
**/
PubSub.publish = function(message, data) {
return publish(message, data, false, PubSub.immediateExceptions);
};
/**
* PubSub.publishSync( message[, data] ) -> Boolean
* - message (String): The message to publish
* - data: The data to pass to subscribers
* Publishes the the message synchronously, passing the data to it's subscribers
**/
PubSub.publishSync = function(message, data) {
return publish(message, data, true, PubSub.immediateExceptions);
};
/**
* PubSub.subscribe( message, func ) -> String
* - message (String): The message to subscribe to
* - func (Function): The function to call when a new message is published
* Subscribes the passed function to the passed message. Every returned token is unique and should be stored if
* you need to unsubscribe
**/
PubSub.subscribe = function(message, func) {
if (typeof func !== 'function') {
return false;
}
// message is not registered yet
if (!messages.hasOwnProperty(message)) {
messages[message] = {};
}
// forcing token as String, to allow for future expansions without breaking usage
// and allow for easy use as key names for the 'messages' object
var token = 'uid_' + String(++lastUid);
messages[message][token] = func;
// return token for unsubscribing
return token;
};
/* Public: Clears all subscriptions
*/
PubSub.clearAllSubscriptions = function clearAllSubscriptions() {
messages = {};
};
/*Public: Clear subscriptions by the topic
*/
PubSub.clearSubscriptions = function clearSubscriptions(topic) {
var m;
for (m in messages) {
if (messages.hasOwnProperty(m) && m.indexOf(topic) === 0) {
delete messages[m];
}
}
};
/* Public: removes subscriptions.
* When passed a token, removes a specific subscription.
* When passed a function, removes all subscriptions for that function
* When passed a topic, removes all subscriptions for that topic (hierarchy)
*
* value - A token, function or topic to unsubscribe.
*
* Examples
*
* // Example 1 - unsubscribing with a token
* var token = PubSub.subscribe('mytopic', myFunc);
* PubSub.unsubscribe(token);
*
* // Example 2 - unsubscribing with a function
* PubSub.unsubscribe(myFunc);
*
* // Example 3 - unsubscribing a topic
* PubSub.unsubscribe('mytopic');
*/
PubSub.unsubscribe = function(value) {
var isTopic = typeof value === 'string' && messages.hasOwnProperty(value),
isToken = !isTopic && typeof value === 'string',
isFunction = typeof value === 'function',
result = false,
m, message, t;
if (isTopic) {
delete messages[value];
return;
}
for (m in messages) {
if (messages.hasOwnProperty(m)) {
message = messages[m];
if (isToken && message[value]) {
delete message[value];
result = value;
// tokens are unique, so we can just stop here
break;
}
if (isFunction) {
for (t in message) {
if (message.hasOwnProperty(t) && message[t] === value) {
delete message[t];
result = true;
}
}
}
}
}
return result;
};
}));
(function(namespace) {
'use strict';
})(window.$dhx = window.$dhx || {});
$dhx.MQ = PubSub;