js.rt.js Maven / Gradle / Ivy
/**
* RT Javascript client
* for RT Servlet
* Version ${project.version}
*/
(function(global){
/**
* Extender function
*/
var extend = function(base, defaults){
for (var name in defaults){
if (typeof(base[name]) === "undefined")
//no default value in base, use from defaults
base[name] = defaults[name];
}
//No recursion (yet)
};
/**
* JSONP requester
*/
var JSONP = function(opts){
extend(opts, {
url: "",
timeout: 35000,
success: function(data){},
error: function(){}
});
//http://stackoverflow.com/questions/5907777/help-on-making-and-handling-jsonp-request-usin-javascript
var cbName = "jsonp" + Math.floor( Math.random() * 1000000 ),
script = document.createElement('SCRIPT'),
//Cleanup job
cleanup = function(){
delete window[cbName];
document.body.removeChild(script);
},
//Start timeout job
timeoutJob = setTimeout(function(){
cleanup();
//error state
opts.error();
}, opts.timeout);
//Source attribute with callback
script.src = opts.url.replace("callback=?", "callback=" + cbName);
//Global callback
window[cbName] = function(data){
//cancel timeout
clearTimeout(timeoutJob);
//callback
opts.success(data);
//cleanup
cleanup();
};
//Start "request"
document.body.appendChild(script);
};
/**
* RT with long poll implementation
*/
/*
var RTLongPollImpl = function(url){
var id = Math.floor( Math.random() * 10000 );
//enhance url
url = url + "?id=" + id + "&mode=longpoll&callback=?";
var listeners = {};
var doRequest = function(){
JSONP({
url: url,
success: handler,
error: doRequest //start request again after timeout
});
};
var handler = function(list){
if (list instanceof Array)
list.forEach(function(e){
var l = listeners[e.type];
if (typeof l !== "undefined")
l.forEach(function(l){
l(e.data);
});
});
doRequest();
};
//Start polling
doRequest();
this.on = function(name, fn){
if (typeof listeners[name] === "undefined")
listeners[name] = [];
listeners[name].push(fn);
};
};
*/
/**
* RT with EventSource implementation
*/
/*
var RTEventSourceImpl = function(url, error){
var id = Math.floor( Math.random() * 10000 ),
source = new EventSource(url + "?id=" + id + "&mode=sse"),
initReceived = false;
this.on = function(name, fn){
source.addEventListener(name, function(e){
fn(JSON.parse(e.data));
});
};
//Watch for init event
source.addEventListener("__init__", function(e){
initReceived = true;
});
setTimeout(function(){
//Check connection, fail over to longpoll
if (initReceived)
return;
//Close source
source.close();
error();
}, 2000);
};
*/
/**
* RT function
*/
var RT = function(url, cfg){
cfg = cfg || {};
/**
* Default config
*/
extend(cfg, {
jsonp: true
});
var self = this;
/**
* Client id
*/
this.id = Math.floor( Math.random() * 10000 );
/**
* Map to listeners id -> [l,l]
*/
this.listenerMap = {};
/**
* Run flag
*/
this.run = true;
/**
* Create url
*/
url += "?mode=longpoll";
//Check jsonp flag
if (cfg.jsonp)
url += "&callback=?";
/**
* Handles a response
*/
var handler = function(list){
if (list instanceof Array)
list.forEach(function(e){
self.fire(e.type, e.data)
});
self.doRequest();
};
/**
* Starts a request
*/
this.doRequest = function(){
if (self.run)
JSONP({
url: url,
success: handler,
error: self.doRequest //start request again after timeout
});
};
//Initial request (deferred)
setTimeout(this.doRequest, 0);
};
/**
* Stops all further requests
*/
RT.prototype.stop = function(){
this.run = false;
};
/**
* Restarts after stop
*/
RT.prototype.start = function(){
if (!this.run){
this.run = true;
this.doRequest();
}
};
/**
* Fires an event
*/
RT.prototype.fire = function(changeId, event){
var listeners = this.listenerMap[changeId];
if (listeners !== undefined)
listeners.forEach(function(listener){
listener(event);
});
}
/**
* Registers a listener
*/
RT.prototype.on = function(changeId, listener){
if (this.listenerMap[changeId] === undefined)
//No listeners by that changeId, create new array
this.listenerMap[changeId] = [];
//append
this.listenerMap[changeId].push(listener);
};
/**
* Generate linked observable
*/
RT.prototype.observable = function(changeId, cfg){
if (typeof(ko) === "undefined")
throw "knockoutjs required for Observable feature";
var o = ko.observable();
//Register observable listener
this.on(changeId, function(e){
var value = e;
//Filter event
if (cfg && typeof cfg.filter === "function" && !cfg.filter(value))
return;
//Dereference event
if (cfg && typeof cfg.accessor === "function")
value = cfg.accessor(value);
//Set new value
o(value);
});
return o;
};
/**
* Generate linked observable array
*/
RT.prototype.observableArray = function(changeId, cfg){
if (typeof(ko) === "undefined")
throw "knockoutjs required for ObservableArray feature";
var o = ko.observableArray();
//Register observable listener
this.on(changeId, function(e){
switch(e.op){
case "INIT":
e.item.forEach(function(item){
o.push(item);
});
break;
case "APPEND":
o.push(e.item);
break;
case "ADD":
//TODO
break;
case "REMOVE":
o.remove( o()[e.index] );
break;
case "REPLACE":
//TODO
break;
case "CLEAR":
o.removeAll();
break;
}
});
return o;
};
//Export RT function
if (typeof define === 'function' && define.amd)
//requirejs
define(function(require){
ko = require("knockout");
return RT;
});
else
//script
global.RT = RT;
})(this);
© 2015 - 2024 Weber Informatics LLC | Privacy Policy