# HG changeset patch # User Thierry Florac # Date 1429022184 -7200 # Node ID 1ea9e5a677a3b4bc0fd2ef11aaf66ea861ccb2f0 # Parent d366c88a0f8895b2ebf8f1c9dd08c4ce3835597e Added XML-RPC plug-in diff -r d366c88a0f88 -r 1ea9e5a677a3 src/pyams_skin/resources/js/ext/jquery-xmlrpc.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_skin/resources/js/ext/jquery-xmlrpc.js Tue Apr 14 16:36:24 2015 +0200 @@ -0,0 +1,415 @@ +/*jshint browser:true */ +/*global jQuery */ +(function($) { + "use strict"; + + var XmlRpcFault = function() { + Error.apply(this, arguments); + }; + XmlRpcFault.prototype = new Error(); + XmlRpcFault.prototype.type = 'XML-RPC fault'; + + var xmlrpc = $.xmlrpc = function(url, settings) { + + if (arguments.length === 2) { + settings.url = url; + } else { + settings = url; + url = settings.url; + } + + settings.dataType = 'xml json'; + settings.type = 'POST'; + settings.contentType = 'text/xml'; + settings.converters = {'xml json': xmlrpc.parseDocument}; + + var xmlDoc = xmlrpc.document(settings.methodName, settings.params || []); + + if ("XMLSerializer" in window) { + settings.data = new window.XMLSerializer().serializeToString(xmlDoc); + } else { + // IE does not have XMLSerializer + settings.data = xmlDoc.xml; + } + + return $.ajax(settings); + }; + + /** + * Make an XML document node. + */ + xmlrpc.createXMLDocument = function () { + + if (document.implementation && "createDocument" in document.implementation) { + // Most browsers support createDocument + return document.implementation.createDocument(null, null, null); + + } else { + // IE uses ActiveXObject instead of the above. + var i, length, activeX = [ + "MSXML6.DomDocument", "MSXML3.DomDocument", + "MSXML2.DomDocument", "MSXML.DomDocument", "Microsoft.XmlDom" + ]; + for (i = 0, length = activeX.length; i < length; i++) { + try { + return new ActiveXObject(activeX[i]); + } catch(_) {} + } + } + }; + + /** + * Make an XML-RPC document from a method name and a set of parameters + */ + xmlrpc.document = function(name, params) { + var doc = xmlrpc.createXMLDocument(); + + + var $xml = function(name) { + return $(doc.createElement(name)); + }; + + var $methodName = $xml('methodName').text(name); + var $params = $xml('params').append($.map(params, function(param) { + var $value = $xml('value').append(xmlrpc.toXmlRpc(param, $xml)); + return $xml('param').append($value); + })); + var $methodCall = $xml('methodCall').append($methodName, $params); + doc.appendChild($methodCall.get(0)); + return doc; + }; + + var _isInt = function(x) { + return (x === parseInt(x, 10)) && !isNaN(x); + }; + + /** + * Take a JavaScript value, and return an XML node representing the value + * in XML-RPC style. If the value is one of the `XmlRpcType`s, that type is + * used. Otherwise, a best guess is made as to its type. The best guess is + * good enough in the vast majority of cases. + */ + xmlrpc.toXmlRpc = function(item, $xml) { + + if (item instanceof XmlRpcType) { + return item.toXmlRpc($xml); + } + + var types = $.xmlrpc.types; + var type = $.type(item); + + switch (type) { + case "undefined": + case "null": + return types.nil.encode(item, $xml); + + case "date": + return types['datetime.iso8601'].encode(item, $xml); + + case "object": + if (item instanceof ArrayBuffer) { + return types.base64.encode(item, $xml); + } else { + return types.struct.encode(item, $xml); + } + break; + + + case "number": + // Ints and Floats encode differently + if (_isInt(item)) { + return types['int'].encode(item, $xml); + } else { + return types['double'].encode(item, $xml); + } + break; + + case "array": + case "boolean": + case "string": + return types[type].encode(item, $xml); + + default: + throw new Error("Unknown type", item); + } + }; + + /** + * Take an XML-RPC document and decode it to an equivalent JavaScript + * representation. + * + * If the XML-RPC document represents a fault, then an equivalent + * XmlRpcFault will be thrown instead + */ + xmlrpc.parseDocument = function(doc) { + var $doc = $(doc); + var $response = $doc.children('methodresponse'); + + var $fault = $response.find('> fault'); + if ($fault.length === 0) { + var $params = $response.find('> params > param > value > *'); + var json = $params.toArray().map(xmlrpc.parseNode); + return json; + } else { + var fault = xmlrpc.parseNode($fault.find('> value > *').get(0)); + var err = new XmlRpcFault(fault.faultString); + err.msg = err.message = fault.faultString; + err.type = err.code = fault.faultCode; + throw err; + } + }; + + /* + * Take an XML-RPC node, and return the JavaScript equivalent + */ + xmlrpc.parseNode = function(node) { + + // Some XML-RPC services return empty elements. This is not + // legal XML-RPC, but we may as well handle it. + if (node === undefined) { + return null; + } + var nodename = node.nodeName.toLowerCase(); + if (nodename in xmlrpc.types) { + return xmlrpc.types[nodename].decode(node); + } else { + throw new Error('Unknown type ' + nodename); + } + }; + + /* + * Take a node, and return the JavaScript equivalent. + */ + xmlrpc.parseValue = function(value) { + var child = $(value).children()[0]; + if (child) { + // Child nodes should be decoded. + return xmlrpc.parseNode(child); + } else { + // If no child nodes, the value is a plain text node. + return $(value).text(); + } + }; + + var XmlRpcType = function() { }; + + $.xmlrpc.types = {}; + + /** + * Make a XML-RPC type. We use these to encode and decode values. You can + * also force a values type using this. See `$.xmlrpc.force()` + */ + xmlrpc.makeType = function(tagName, simple, encode, decode) { + var Type; + + Type = function(value) { + this.value = value; + }; + Type.prototype = new XmlRpcType(); + Type.prototype.tagName = tagName; + + if (simple) { + var simpleEncode = encode, simpleDecode = decode; + encode = function(value, $xml) { + var text = simpleEncode(value); + return $xml(Type.tagName).text(text); + }; + decode = function(node) { + return simpleDecode($(node).text(), node); + }; + } + Type.prototype.toXmlRpc = function($xml) { + return Type.encode(this.value, $xml); + }; + + Type.tagName = tagName; + Type.encode = encode; + Type.decode = decode; + + xmlrpc.types[tagName.toLowerCase()] = Type; + }; + + + // Number types + var _fromInt = function(value) { return '' + Math.floor(value); }; + var _toInt = function(text, _) { return parseInt(text, 10); }; + + xmlrpc.makeType('int', true, _fromInt, _toInt); + xmlrpc.makeType('i4', true, _fromInt, _toInt); + xmlrpc.makeType('i8', true, _fromInt, _toInt); + xmlrpc.makeType('i16', true, _fromInt, _toInt); + xmlrpc.makeType('i32', true, _fromInt, _toInt); + + xmlrpc.makeType('double', true, String, function(text) { + return parseFloat(text, 10); + }); + + // String type. Fairly simple + xmlrpc.makeType('string', true, String, String); + + // Boolean type. True == '1', False == '0' + xmlrpc.makeType('boolean', true, function(value) { + return value ? '1' : '0'; + }, function(text) { + return text === '1'; + }); + + // Dates are a little trickier + var _pad = function(n) { return n<10 ? '0'+n : n; }; + + xmlrpc.makeType('dateTime.iso8601', true, function(d) { + return [ + d.getUTCFullYear(), '-', _pad(d.getUTCMonth()+1), '-', + _pad(d.getUTCDate()), 'T', _pad(d.getUTCHours()), ':', + _pad(d.getUTCMinutes()), ':', _pad(d.getUTCSeconds()), 'Z' + ].join(''); + }, function(text) { + return new Date(text); + }); + + // Go between a base64 string and an ArrayBuffer + xmlrpc.binary = (function() { + var pad = '='; + var toChars = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' + + 'abcdefghijklmnopqrstuvwxyz0123456789+/').split(""); + var fromChars = toChars.reduce(function(acc, chr, i) { + acc[chr] = i; + return acc; + }, {}); + + /* + * In the following, three bytes are added together into a 24-bit + * number, which is then split up in to 4 6-bit numbers - or vice versa. + * That is why there is lots of shifting by multiples of 6 and 8, and + * the magic numbers 3 and 4. + * + * The modulo 64 is for converting to base 64, and the modulo 256 is for + * converting to 8-bit numbers. + */ + return { + toBase64: function(ab) { + var acc = []; + + var int8View = new Uint8Array(ab); + var int8Index = 0, int24; + for (; int8Index < int8View.length; int8Index += 3) { + + // Grab three bytes + int24 = + (int8View[int8Index + 0] << 16) + + (int8View[int8Index + 1] << 8) + + (int8View[int8Index + 2] << 0); + + // Push four chars + acc.push(toChars[(int24 >> 18) % 64]); + acc.push(toChars[(int24 >> 12) % 64]); + acc.push(toChars[(int24 >> 6) % 64]); + acc.push(toChars[(int24 >> 0)% 64]); + } + + // Set the last few characters to the padding character + var padChars = 3 - ((ab.byteLength % 3) || 3); + while (padChars--) { + acc[acc.length - padChars - 1] = pad; + } + + return acc.join(''); + }, + + fromBase64: function(base64) { + var base64Len = base64.length; + + // Work out the length of the data, accommodating for padding + var abLen = (base64Len / 4) * 3; + if (base64.charAt(base64Len - 1) === pad) { abLen--; } + if (base64.charAt(base64Len - 2) === pad) { abLen--; } + + // Make the ArrayBuffer, and an Int8Array to work with it + var ab = new ArrayBuffer(abLen); + var int8View = new Uint8Array(ab); + + var base64Index = 0, int8Index = 0, int24; + for (; base64Index < base64Len; base64Index += 4, int8Index += 3) { + + // Grab four chars + int24 = + (fromChars[base64[base64Index + 0]] << 18) + + (fromChars[base64[base64Index + 1]] << 12) + + (fromChars[base64[base64Index + 2]] << 6) + + (fromChars[base64[base64Index + 3]] << 0); + + // Push three bytes + int8View[int8Index + 0] = (int24 >> 16) % 256; + int8View[int8Index + 1] = (int24 >> 8) % 256; + int8View[int8Index + 2] = (int24 >> 0) % 256; + + } + + return ab; + } + }; + })(); + + xmlrpc.makeType('base64', true, function(ab) { + return xmlrpc.binary.toBase64(ab); + }, function(text) { + return xmlrpc.binary.fromBase64(text); + }); + + // Nil/null + xmlrpc.makeType('nil', false, + function(val, $xml) { return $xml('nil'); }, + function(_) { return null; } + ); + + // Structs/Objects + xmlrpc.makeType('struct', false, function(value, $xml) { + var $struct = $xml('struct'); + + $.each(value, function(name, value) { + var $name = $xml('name').text(name); + var $value = $xml('value').append(xmlrpc.toXmlRpc(value, $xml)); + $struct.append($xml('member').append($name, $value)); + }); + + return $struct; + + }, function(node) { + return $(node) + .find('> member') + .toArray() + .reduce(function(struct, el) { + var $el = $(el); + var key = $el.find('> name').text(); + var value = xmlrpc.parseValue($el.find('> value')); + + struct[key] = value; + return struct; + }, {}); + + }); + + // Arrays + xmlrpc.makeType('array', false, function(value, $xml) { + var $array = $xml('array'); + var $data = $xml('data'); + $.each(value, function(i, val) { + $data.append($xml('value').append(xmlrpc.toXmlRpc(val, $xml))); + }); + $array.append($data); + return $array; + }, function(node) { + return $(node).find('> data > value').toArray() + .map(xmlrpc.parseValue); + }); + + + /** + * Force a value to an XML-RPC type. All the usual XML-RPC types are + * supported + */ + xmlrpc.force = function(type, value) { + return new xmlrpc.types[type](value); + }; + +})(jQuery); diff -r d366c88a0f88 -r 1ea9e5a677a3 src/pyams_skin/resources/js/ext/jquery-xmlrpc.min.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_skin/resources/js/ext/jquery-xmlrpc.min.js Tue Apr 14 16:36:24 2015 +0200 @@ -0,0 +1,1 @@ +(function(g){var c=function(){Error.apply(this,arguments)};c.prototype=new Error();c.prototype.type="XML-RPC fault";var a=g.xmlrpc=function(i,j){if(arguments.length===2){j.url=i}else{j=i;i=j.url}j.dataType="xml json";j.type="POST";j.contentType="text/xml";j.converters={"xml json":a.parseDocument};var k=a.document(j.methodName,j.params||[]);if("XMLSerializer" in window){j.data=new window.XMLSerializer().serializeToString(k)}else{j.data=k.xml}return g.ajax(j)};a.createXMLDocument=function(){if(document.implementation&&"createDocument" in document.implementation){return document.implementation.createDocument(null,null,null)}else{var l,m,j=["MSXML6.DomDocument","MSXML3.DomDocument","MSXML2.DomDocument","MSXML.DomDocument","Microsoft.XmlDom"];for(l=0,m=j.length;l fault");if(l.length===0){var j=i.find("> params > param > value > *");var k=j.toArray().map(a.parseNode);return k}else{var n=a.parseNode(l.find("> value > *").get(0));var m=new c(n.faultString);m.msg=m.message=n.faultString;m.type=m.code=n.faultCode;throw m}};a.parseNode=function(j){if(j===undefined){return null}var i=j.nodeName.toLowerCase();if(i in a.types){return a.types[i].decode(j)}else{throw new Error("Unknown type "+i)}};a.parseValue=function(i){var j=g(i).children()[0];if(j){return a.parseNode(j)}else{return g(i).text()}};var f=function(){};g.xmlrpc.types={};a.makeType=function(j,o,k,m){var i;i=function(p){this.value=p};i.prototype=new f();i.prototype.tagName=j;if(o){var l=k,n=m;k=function(q,p){var r=l(q);return p(i.tagName).text(r)};m=function(p){return n(g(p).text(),p)}}i.prototype.toXmlRpc=function(p){return i.encode(this.value,p)};i.tagName=j;i.encode=k;i.decode=m;a.types[j.toLowerCase()]=i};var e=function(i){return""+Math.floor(i)};var d=function(j,i){return parseInt(j,10)};a.makeType("int",true,e,d);a.makeType("i4",true,e,d);a.makeType("i8",true,e,d);a.makeType("i16",true,e,d);a.makeType("i32",true,e,d);a.makeType("double",true,String,function(i){return parseFloat(i,10)});a.makeType("string",true,String,String);a.makeType("boolean",true,function(i){return i?"1":"0"},function(i){return i==="1"});var h=function(i){return i<10?"0"+i:i};a.makeType("dateTime.iso8601",true,function(i){return[i.getUTCFullYear(),"-",h(i.getUTCMonth()+1),"-",h(i.getUTCDate()),"T",h(i.getUTCHours()),":",h(i.getUTCMinutes()),":",h(i.getUTCSeconds()),"Z"].join("")},function(i){return new Date(i)});a.binary=(function(){var k="=";var i=("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").split("");var j=i.reduce(function(n,m,l){n[m]=l;return n},{});return{toBase64:function(p){var o=[];var q=new Uint8Array(p);var m=0,n;for(;m>18)%64]);o.push(i[(n>>12)%64]);o.push(i[(n>>6)%64]);o.push(i[(n>>0)%64])}var l=3-((p.byteLength%3)||3);while(l--){o[o.length-l-1]=k}return o.join("")},fromBase64:function(m){var l=m.length;var s=(l/4)*3;if(m.charAt(l-1)===k){s--}if(m.charAt(l-2)===k){s--}var q=new ArrayBuffer(s);var r=new Uint8Array(q);var o=0,n=0,p;for(;o>16)%256;r[n+1]=(p>>8)%256;r[n+2]=(p>>0)%256}return q}}})();a.makeType("base64",true,function(i){return a.binary.toBase64(i)},function(i){return a.binary.fromBase64(i)});a.makeType("nil",false,function(j,i){return i("nil")},function(i){return null});a.makeType("struct",false,function(k,j){var i=j("struct");g.each(k,function(l,n){var o=j("name").text(l);var m=j("value").append(a.toXmlRpc(n,j));i.append(j("member").append(o,m))});return i},function(i){return g(i).find("> member").toArray().reduce(function(n,l){var k=g(l);var j=k.find("> name").text();var m=a.parseValue(k.find("> value"));n[j]=m;return n},{})});a.makeType("array",false,function(l,j){var k=j("array");var i=j("data");g.each(l,function(m,n){i.append(j("value").append(a.toXmlRpc(n,j)))});k.append(i);return k},function(i){return g(i).find("> data > value").toArray().map(a.parseValue)});a.force=function(i,j){return new a.types[i](j)}})(jQuery); \ No newline at end of file