aboutsummaryrefslogtreecommitdiffstats
path: root/jquery.rpc.js
diff options
context:
space:
mode:
Diffstat (limited to 'jquery.rpc.js')
-rw-r--r--jquery.rpc.js236
1 files changed, 236 insertions, 0 deletions
diff --git a/jquery.rpc.js b/jquery.rpc.js
new file mode 100644
index 0000000..892eb48
--- /dev/null
+++ b/jquery.rpc.js
@@ -0,0 +1,236 @@
+window.jQuery = window.jQuery || {};
+
+jQuery.rpc = function(url, dataType, onLoadCallback, version, methods) {
+ return new (function(url, dataType, onLoadCallback, version) {
+ version = version || "1.0";
+ dataType = dataType || "json";
+ if(dataType != "json" && dataType != "xml") {
+ new Error("IllegalArgument: Unsupported data type");
+ }
+
+ var _self = this;
+
+ function pad2(f) {
+ if(f<=9) {
+ return "0"+f;
+ } else {
+ return ""+f;
+ }
+ }
+
+ var serializeToXml = function(data) {
+ switch (typeof data) {
+ case 'boolean':
+ return '<boolean>'+ ((data) ? '1' : '0') +'</boolean>';
+ case 'number':
+ var parsed = parseInt(data);
+ if(parsed == data) {
+ return '<int>'+ data +'</int>';
+ }
+ return '<double>'+ data +'</double>';
+ case 'string':
+ return '<string>'+ data +'</string>';
+ case 'object':
+ if(data instanceof Date) {
+ return '<dateTime.iso8601>'+ data.getFullYear() + pad2(data.getMonth()) + pad2(data.getDate()) +'T'+ pad2(data.getHours()) +':'+ pad2(data.getMinutes()) +':'+ pad2(data.getSeconds()) +'</dateTime.iso8601>';
+ } else if(data instanceof Array) {
+ var ret = '<array><data>'+"\n";
+ for (var i=0; i < data.length; i++) {
+ ret += ' <value>'+ serializeToXml(data[i]) +"</value>\n";
+ }
+ ret += '</data></array>';
+ return ret;
+ } else {
+ var ret = '<struct>'+"\n";
+ jQuery.each(data, function(key, value) {
+ ret += " <member><name>"+ key +"</name><value>";
+ ret += serializeToXml(value) +"</value></member>\n";
+ });
+ ret += '</struct>';
+ return ret;
+ }
+ }
+ }
+ var xmlRpc = function(method, params) {
+ var ret = '<?xml version="'+version+'"?><methodCall><methodName>'+method+'</methodName><params>';
+ for(var i=0; i<params.length; i++) {
+ ret += "<param><value>"+serializeToXml(params[i])+"</value></param>";
+ }
+ ret += "</params></methodCall>";
+ return ret;
+ }
+ var parseXmlValue = function(node) {
+ var jnode = jQuery(node);
+ childs = jnode.children();
+
+ // String not enclosed in a <string> tag
+ if(childs.length==0) {
+ var s="";
+ for(var j=0; j<jnode[0].childNodes.length;j++) {
+ s+=new String(jnode[0].childNodes[j].nodeValue);
+ }
+ return s;
+ }
+
+ for(var i=0; i < childs.length; i++) {
+ switch(childs[i].tagName) {
+ case 'boolean':
+ return (jQuery(childs[i]).text() == 1);
+ case 'int':
+ case 'i4':
+ return parseInt(jQuery(childs[i]).text());
+ case 'double':
+ return parseFloat(jQuery(childs[i]).text());
+ case "string":
+ return jQuery(childs[i]).text();
+ case "array":
+ var ret = [];
+ jQuery("> data > value", childs[i]).each(
+ function() {
+ ret.push(parseXmlValue(this));
+ }
+ );
+ return ret;
+ case "struct":
+ var ret = {};
+ jQuery("> member", childs[i]).each(
+ function() {
+ ret[jQuery( "> name", this).text()] = parseXmlValue(jQuery("value", this));
+ }
+ );
+ return ret;
+ case "dateTime.iso8601":
+ /* TODO: fill me :( */
+ return 0;
+ }
+ }
+ }
+ var parseXmlResponse = function(data) {
+ var ret = {};
+ ret.version = version;
+ jQuery("methodResponse params param > value", data).each(
+ function(index) {
+ ret.result = parseXmlValue(this);
+ }
+ );
+ jQuery("methodResponse fault > value", data).each(
+ function(index) {
+ ret.error = parseXmlValue(this);
+ }
+ );
+ return ret;
+ }
+ var rpc_contents = {
+ 'xml':'text/xml'
+ ,'json':'application/json'
+ };
+ var _rpc = function(method) {
+ var params = [];
+ var async; // whether we're async or not
+ var callback;
+ var nargs=arguments.length;
+
+ if(nargs > 1 && typeof(arguments[nargs-1])=="function") {
+ callback = arguments[nargs-1];
+ nargs=nargs-1;
+ async=true;
+ } else {
+ async=false;
+ }
+
+ for (var i=1; i<nargs; i++) {
+ params.push(arguments[i]);
+ }
+
+ var data;
+ if(dataType == 'json') {
+ data = {"version":version, "method":method, "params":params};
+ } else {
+ data = xmlRpc(method, params);
+ }
+
+ if(async) {
+ jQuery.ajax({
+ url: url,
+ dataType: dataType,
+ type: "POST",
+ data: data,
+ success: function(inp) {
+ var json = inp;
+ if(dataType == "xml") {
+ json = parseXmlResponse(inp);
+ }
+ // console.log("json response:", json);
+ callback(json);
+ },
+ processData: false,
+ contentType: rpc_contents[dataType]});
+ } else {
+ var result = jQuery.ajax({
+ url: url,
+ dataType: dataType,
+ type: "POST",
+ data: data,
+ async: false,
+ contentType: rpc_contents[dataType]});
+ if(dataType=="json") {
+ return eval("("+result.responseText+")");
+ } else {
+ var myresult=parseXmlResponse(result.responseXML);
+ return myresult;
+ }
+ }
+
+ };
+ function populate(methods) {
+ // console.log(json);
+ /* get the functions */
+ var proc = null;
+ for(var i = 0; i<methods.length; i++) {
+ proc = methods[i];
+ var obj = _self;
+ var objStack = proc.split(/\./);
+ for(var j = 0; j < (objStack.length - 1); j++){
+ obj[objStack[j]] = obj[objStack[j]] || {};
+ obj = obj[objStack[j]];
+ }
+ /* add the new procedure */
+ obj[objStack[j]] = (
+ function(method, obj) {
+ var _outer = {"method":method,"rpc":_rpc};
+ return function() {
+ var params = [];
+ params.push(_outer.method);
+ for (var i=0; i<arguments.length; i++) {
+ params.push(arguments[i]);
+ }
+ return _rpc.apply(_self, params);
+ }
+ }
+ )(proc, _rpc);
+ }
+ // console.log('Load was performed.');
+ }
+
+ function asyncCallback(json) {
+ populate(json.result);
+ if(onLoadCallback) {
+ onLoadCallback(_self);
+ }
+ }
+
+ if(!methods) {
+ _rpc("system.listMethods", asyncCallback);
+ } else {
+ populate(methods);
+ if(onLoadCallback) {
+ // not sure this works - the intention is to call the callback as soon as this
+ // javascript function returns control back to the browser, to emulate the behaviour
+ // that the system.listMethods approach
+ setTimeout(function(){onLoadCallback(_self);},0);
+ }
+ }
+
+ })(url, dataType, onLoadCallback, version);
+};
+