Jquery
/*
*    Wikidot jsAPI (XML-RPC Library for Wikidot's XML-RPC) v3.2
*    jsAPI by Kenneth Tsang (http://www.ktsang.tk/)
*    
*    jsAPI is powered by Mimic (XML-RPC Client for JavaScript) v2.3
*    Mimic has been modified by Kenneth Tsang to allow for asynchronous requests.
*
 *    Mimic (XML-RPC Client for JavaScript) v2.3 
 *    Copyright (C) 2005-2013 Carlos Eduardo Goncalves (cadu.goncalves@gmail.com)
 *
 *    Mimic is dual licensed under the MIT (http://opensource.org/licenses/mit-license.php) 
 *     and GPLv3 (http://opensource.org/licenses/gpl-3.0.html) licenses.
 */
 
/**
 * XmlRpc helper.
 */
function XmlRpc() {
 
};
 
/**
 * <p>
 * XML-RPC document prolog.
 * </p>
 */
XmlRpc.PROLOG = "<?xml version=\"1.0\"?>\n";
 
/**
 * <p>
 * XML-RPC methodCall node template.
 * </p>
 */
XmlRpc.REQUEST = "<methodCall>\n<methodName>${METHOD}</methodName>\n<params>\n${DATA}</params>\n</methodCall>";
 
/**
 * <p>
 * XML-RPC param node template.
 * </p>
 */
XmlRpc.PARAM = "<param>\n<value>\n${DATA}</value>\n</param>\n";
 
/**
 * <p>
 * XML-RPC array node template.
 * </p>
 */
XmlRpc.ARRAY = "<array>\n<data>\n${DATA}</data>\n</array>\n";
 
/**
 * <p>
 * XML-RPC struct node template.
 * </p>
 */
XmlRpc.STRUCT = "<struct>\n${DATA}</struct>\n";
 
/**
 * <p>
 * XML-RPC member node template.
 * </p>
 */
XmlRpc.MEMBER = "<member>\n${DATA}</member>\n";
 
/**
 * <p>
 * XML-RPC name node template.
 * </p>
 */
XmlRpc.NAME = "<name>${DATA}</name>\n";
 
/**
 * <p>
 * XML-RPC value node template.
 * </p>
 */
XmlRpc.VALUE = "<value>\n${DATA}</value>\n";
 
/**
 * <p>
 * XML-RPC scalar node template (int, i4, double, string, boolean, base64,
 * dateTime.iso8601).
 * </p>
 */
XmlRpc.SCALAR = "<${TYPE}>${DATA}</${TYPE}>\n";
 
/**
 * <p>
 * Get the tag name used to represent a JavaScript object in the XMLRPC
 * protocol.
 * </p>
 * 
 * @param data
 *            A JavaScript object.
 * @return <code>String</code> with XMLRPC object type.
 */
XmlRpc.getDataTag = function(data) {
    try {
        // Vars
        var tag = typeof data;
 
        switch (tag.toLowerCase()) {
        case "number":
            tag = (Math.round(data) == data) ? "int" : "double";
            break;
        case "object":
            if (data.constructor == Base64) {
                tag = "base64";
            } else if (data.constructor == String) {
                tag = "string";
            } else if (data.constructor == Boolean) {
                tag = "boolean";
            } else if (data.constructor == Array) {
                tag = "array";
            } else if (data.constructor == Date) {
                tag = "dateTime.iso8601";
            } else if (data.constructor == Number) {
                tag = (Math.round(data) == data) ? "int" : "double";
            } else {
                tag = "struct";
            }
            break;
        }
        return tag;
    } catch (e) {
        return null;
    }
};
 
/**
 * <p>
 * Get JavaScript object type represented by XMLRPC protocol tag.
 * <p>
 * 
 * @param tag
 *            A XMLRPC tag name.
 * @return A JavaScript object.
 */
XmlRpc.getTagData = function(tag) {
    // Vars
    var data = null;
 
    switch (tag) {
    case "struct":
        data = new Object();
        break;
    case "array":
        data = new Array();
        break;
    case "datetime.iso8601":
        data = new Date();
        break;
    case "boolean":
        data = new Boolean();
        break;
    case "int":
    case "i4":
    case "double":
        data = new Number();
        break;
    case "string":
        data = new String();
        break;
    case "base64":
        data = new Base64();
        break;
    }
    return data;
};
 
/**
 * XmlRpcRequest.
 * 
 * @param url
 *            Server url.
 * @param method
 *            Server side method do call.
 */
function XmlRpcRequest(url, method) {
    this.serviceUrl = url;
    this.methodName = method;
    this.crossDomain = false;
    this.withCredentials = false;    
    this.params = [];
    this.headers = {};
};
 
/**
 * <p>
 * Add a new request parameter.
 * </p>
 * 
 * @param data
 *            New parameter value.
 */
XmlRpcRequest.prototype.addParam = function(data) {
    // Vars
    var type = typeof data;
 
    this.params= data;
};
 
/**
 * <p>
 * Clear all request parameters.
 * </p>
 * 
 * @param data
 *            New parameter value.
 */
XmlRpcRequest.prototype.clearParams = function() {
    this.params.splice(0, this.params.length);
};
 
/**
 * <p>
 * Define HTTP header value.
 * </p>
 * 
 * @param name
 *            Header name.
 * @param data
 *            Header value. Use <null> to clear the header.
 */
XmlRpcRequest.prototype.setHeader = function(name, value) {
    if(value) {
      this.headers[name] = value;
    } else {
      delete this.headers[name];
    }
};
 
/**
 * <p>
 * Execute a synchronous XML-RPC request.
 * </p>
 *
 * @return XmlRpcResponse object.
 */
XmlRpcRequest.prototype.send = function(callback, username, password) {
 
    // Vars
    var xml_params = "", 
        i = 0, 
        xml_call, xhr;
    // XMLRPC
    xml_params = XmlRpc.PARAM.replace("${DATA}", this.marshal(this.params));
    xml_call = XmlRpc.REQUEST.replace("${METHOD}", this.methodName);
    xml_call = XmlRpc.PROLOG + xml_call.replace("${DATA}", xml_params);    
    // XHR
    xhr = Builder.buildXHR(this.crossDomain);
    if(typeof(callback)!="function"){
        var async=false;
    }else{
        var async=true;
    }
 
    xhr.open("POST", this.serviceUrl, async, username, password);
    if(async){
        xhr.onreadystatechange=function(){
            callback(new XmlRpcResponse(xhr.responseXML));
        }
    }
 
    // HTTP headers
    for(i in this.headers) {
        if (this.headers.hasOwnProperty(i)) {
          xhr.setRequestHeader(i, this.headers[i]);
        }
    }        
    // HTTP credentials 
    if(this.withCredentials && "withCredentials" in xhr) {
        xhr.withCredentials = true;
    }    
    xhr.send(xml_call);
 
    if(!async){ return new XmlRpcResponse(xhr.responseXML); }else{ return true; }
};
 
/**
 * <p>
 * Marshal request parameters.
 * </p>
 * 
 * @param data
 *            A request parameter.
 * @return String with XML-RPC element notation.
 */
XmlRpcRequest.prototype.marshal = function(data) {
    // Vars
    var type = XmlRpc.getDataTag(data), 
        scalar_type = XmlRpc.SCALAR.replace(/\$\{TYPE\}/g, type), 
        xml = "", 
        value, i, member;
 
    switch (type) {
    case "struct":
        member = "";
        for (i in data) {
            value = "";
            value += XmlRpc.NAME.replace("${DATA}", i);
            value += XmlRpc.VALUE.replace("${DATA}", this.marshal(data[i]));
            member += XmlRpc.MEMBER.replace("${DATA}", value);
        }
        xml = XmlRpc.STRUCT.replace("${DATA}", member);
        break;
    case "array":
        value = "";
        for (i = 0; i < data.length; i++) {
            value += XmlRpc.VALUE.replace("${DATA}", this.marshal(data[i]));
        }
        xml = XmlRpc.ARRAY.replace("${DATA}", value);
        break;
    case "dateTime.iso8601":
        xml = scalar_type.replace("${DATA}", data.toIso8601());
        break;
    case "boolean":
        xml = scalar_type.replace("${DATA}", (data == true) ? 1 : 0);
        break;
    case "base64":
        xml = scalar_type.replace("${DATA}", data.encode());
        break;
    default:
        xml = scalar_type.replace("${DATA}", data);
        break;
    }
    return xml;
};
 
/**
 * XmlRpcResponse.
 * 
 * @param xml
 *            Response XML document.
 */
function XmlRpcResponse(xml) {
    this.xmlData = xml;
};
 
/**
 * <p>
 * Indicate if response is a fault.
 * </p>
 * 
 * @return Boolean flag indicating fault status.
 */
XmlRpcResponse.prototype.isFault = function() {
    return this.faultValue;
};
 
/**
 * <p>
 * Parse XML response to JavaScript.
 * </p>
 * 
 * @return JavaScript object parsed from XML-RPC document.
 */
XmlRpcResponse.prototype.parseXML = function() {
    // Vars
    var i, nodesLength;
 
    nodesLength = this.xmlData.childNodes.length;
    this.faultValue = undefined;
    this.currentIsName = false;
    this.propertyName = "";
    this.params = [];
    for (i = 0; i < nodesLength; i++) {
        this.unmarshal(this.xmlData.childNodes[i], 0);
    }
    return this.params[0];
};
 
/**
 * <p>
 * Unmarshal response parameters.
 * </p>
 * 
 * @param node
 *            Current document node under processing.
 * @param parent
 *            Current node' parent node.
 */
XmlRpcResponse.prototype.unmarshal = function(node, parent) {
    // Vars
    var obj, tag, i, nodesLength;
 
    if (node.nodeType == 1) {
        obj = null;
        tag = node.tagName.toLowerCase();
        switch (tag) {
        case "fault":
            this.faultValue = true;
            break;
        case "name":
            this.currentIsName = true;
            break;
        default:
            obj = XmlRpc.getTagData(tag);
            break;
        }
        if (obj != null) {
            this.params.push(obj);
            if (tag == "struct" || tag == "array") {
                if (this.params.length > 1) {
                    switch (XmlRpc.getDataTag(this.params[parent])) {
                    case "struct":
                        this.params[parent][this.propertyName] = this.params[this.params.length - 1];
                        break;
                    case "array":
                        this.params[parent].push(this.params[this.params.length - 1]);
                        break;
                    }
                }
                parent = this.params.length - 1;
            }
        }
        nodesLength = node.childNodes.length;
        for (i = 0; i < nodesLength; i++) {
            this.unmarshal(node.childNodes[i], parent);
        }
    }
    if ((node.nodeType == 3) && (/[^\t\n\r ]/.test(node.nodeValue))) {
        if (this.currentIsName == true) {
            this.propertyName = node.nodeValue;
            this.currentIsName = false;
        } else {
            switch (XmlRpc.getDataTag(this.params[this.params.length - 1])) {
            case "dateTime.iso8601":
                this.params[this.params.length - 1] = Date.fromIso8601(node.nodeValue);
                break;
            case "boolean":
                this.params[this.params.length - 1] = (node.nodeValue == "1") ? true : false;
                break;
            case "int":
            case "double":
                this.params[this.params.length - 1] = new Number(node.nodeValue);
                break;
            case "string":
                this.params[this.params.length - 1] = new String(node.nodeValue);
                break;
            case "base64":
                this.params[this.params.length - 1] = new Base64(node.nodeValue);
                break;
            }
            if (this.params.length > 1) {
                switch (XmlRpc.getDataTag(this.params[parent])) {
                case "struct":
                    this.params[parent][this.propertyName] = this.params[this.params.length - 1];
                    break;
                case "array":
                    this.params[parent].push(this.params[this.params.length - 1]);
                    break;
                }
            }
        }
    }
};
 
/**
 * Builder helper for W3C / ActiveX objects
 */
function Builder() {
 
};
 
/**
 * <p>
 * Build a valid XMLHttpRequest object
 * </p>
 * 
 * @param cors
 *            Define if returned implementation must provide CORS (Cross-Origin Resource Sharing) support.
 * @return XMLHttpRequest object.
 */
Builder.buildXHR = function(cors) {
    if(cors) {
        return (typeof XDomainRequest != "undefined") ? new XDomainRequest() : new XMLHttpRequest();
    } else {
        return (typeof XMLHttpRequest != "undefined") ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
    }
};
 
/**
 * <p>
 * Build a valid XML document from string markup.
 * </p>
 * 
 * @param xml
 *            Document markup.
 * @return XMLDocument object.
 */
Builder.buildDOM = function(xml) {
    // Vars
    var parser, names, i;
 
    if (typeof DOMParser != "undefined") {
        parser = new DOMParser();
        return parser.parseFromString(xml, "text/xml");
    } else {
        names = [ "Microsoft.XMLDOM", "MSXML2.DOMDocument", "MSXML.DOMDocument" ];
        for (i = 0; i < names.length; i++) {
            try {
                parser = new ActiveXObject(names[i]);
                parser.loadXML(xml);
                return parser;
            } catch (e) {
                /* Ignore */
            }
        }
    }
    return null;
};
 
/**
 * Date extensions.
 */
 
/**
 * <p>
 * Convert a GMT date to ISO8601.
 * </p>
 * 
 * @return <code>String</code> with an ISO8601 date.
 */
Date.prototype.toIso8601 = function() {
    // Vars    
    var year = this.getYear(),
        month = this.getMonth() + 1,
        day = this.getDate(),
        time = this.toTimeString().substr(0, 8);
 
    // Normalization
    if (year < 1900) {
        year += 1900;
    }
    if (month < 10) {
        month = "0" + month;
    }
    if (day < 10) {
        day = "0" + day;
    }
 
    return year + month + day + "T" + time;
};
 
/**
 * <p>
 * Convert ISO8601 date to GMT.
 * </p>
 * 
 * @param value
 *            ISO8601 date.
 * @return GMT date.
 */
Date.fromIso8601 = function(value) {
    // Vars    
    var year = value.substr(0, 4),
        month = value.substr(4, 2),
        day = value.substr(6, 2),
        hour = value.substr(9, 2),
        minute = value.substr(12, 2),
        sec = value.substr(15, 2);
 
    return new Date(year, month - 1, day, hour, minute, sec, 0);
};
 
/**
 * Base64 implementation.
 */
function Base64(value) {
    this.bytes = value;
};
 
/**
 * <p>
 * Base64 characters map.
 * </p>
 */
Base64.CHAR_MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
 
/**
 * <p>
 * Encode the object bytes using base64 algorithm.
 * </p>
 * 
 * @return Encoded string.
 */
Base64.prototype.encode = function() {
    if (typeof btoa == "function") {
        return btoa(this.bytes);
    } else {
        // Vars
        var _byte = [], 
        _char = [], 
        _result = [],
        j = 0, i = 0;
 
        for (i = 0; i < this.bytes.length; i += 3) {
            _byte[0] = this.bytes.charCodeAt(i);
            _byte[1] = this.bytes.charCodeAt(i + 1);
            _byte[2] = this.bytes.charCodeAt(i + 2);
            _char[0] = _byte[0] >> 2;
            _char[1] = ((_byte[0] & 3) << 4) | (_byte[1] >> 4);
            _char[2] = ((_byte[1] & 15) << 2) | (_byte[2] >> 6);
            _char[3] = _byte[2] & 63;
            if (isNaN(_byte[1])) {
                _char[2] = _char[3] = 64;
            } else if (isNaN(_byte[2])) {
                _char[3] = 64;
            }
            _result[j++] = Base64.CHAR_MAP.charAt(_char[0])
                         + Base64.CHAR_MAP.charAt(_char[1])
                         + Base64.CHAR_MAP.charAt(_char[2])
                         + Base64.CHAR_MAP.charAt(_char[3]);
        }
        return _result.join("");
    }
};
 
/**
 * <p>
 * Decode the object bytes using base64 algorithm.
 * </p>
 * 
 * @return Decoded string.
 */
Base64.prototype.decode = function() {
    if (typeof atob == "function") {
        return atob(this.bytes);
    } else {
        // Vars
        var _byte = [], 
        _char = [], 
        _result = [], 
        j = 0, i = 0;
 
        while ((this.bytes.length % 4) != 0) {
            this.bytes += "=";
        }
        for (i = 0; i < this.bytes.length; i += 4) {
            _char[0] = Base64.CHAR_MAP.indexOf(this.bytes.charAt(i));
            _char[1] = Base64.CHAR_MAP.indexOf(this.bytes.charAt(i + 1));
            _char[2] = Base64.CHAR_MAP.indexOf(this.bytes.charAt(i + 2));
            _char[3] = Base64.CHAR_MAP.indexOf(this.bytes.charAt(i + 3));
            _byte[0] = (_char[0] << 2) | (_char[1] >> 4);
            _byte[1] = ((_char[1] & 15) << 4) | (_char[2] >> 2);
            _byte[2] = ((_char[2] & 3) << 6) | _char[3];
            _result[j++] = String.fromCharCode(_byte[0]);
            if (_char[2] != 64) {
                _result[j++] = String.fromCharCode(_byte[1]);
            }
            if (_char[3] != 64) {
                _result[j++] = String.fromCharCode(_byte[2]);
            }
        }
        return _result.join("");
    }
};
 
/*
*    Below is the code for Wikidot jsAPI.
*    (c) Kenneth Tsang 2011
*/
 
function WikidotAPI(username, key, sync){
 
    var api_key = key;
 
    var call = function(method,param,recallback){
 
        /* Check if protocol is HTTPS */
        if(window.location.protocol!="https:")
        {
            alert("Error: You must be in the HTTPS protocol to make request the API!");
        }
 
        /* Using Mimic */
        var request = new XmlRpcRequest("/xml-rpc-api.php", method);
 
        if(param["content"]!=null){
            param["content"]="<![CDATA["+param["content"].replace(/\]\]\>/g,"]]]]><![CDATA[>")+"]]>";
        }
        request.addParam(param); //Put entire struct into "addParam" class.
 
        if(typeof(recallback)!="function"){
            /* Synchronous request (data returned by the jsAPI function) */
            console.log("use synchronous");
            var response = request.send(null,"jsapi-v3-2",api_key);
            var responseData = response.parseXML();
 
            if(responseData.faultString){
                responseData = false;
            }
 
            return responseData;
        }else{
            /* Asynchronous request (data returned in the first parameter of the defined callback function */
            console.log("use async!");
            var response = request.send(callback,"jsapi-v3-2",api_key);
            function callback(data){
                var responseData = data.parseXML();
 
                if(responseData.faultString){
                    responseData = false;
                }
 
                recallback(responseData);
            }
        }
    }
 
    var api = {};
 
    var namespaces = ['categories', 'files', 'tags', 'pages', 'posts', 'users'];
    var methods = ['select', 'get_meta', 'get_one', 'save_one', 'get', 'get_me'];
 
    var register_method = function(namespace, method) {
        if (typeof(api[namespace]) == 'undefined') {
            api[namespace] = {};
        }
        api[namespace][method] = function(params, callback) {
            call(namespace + '.' + method, params, callback);
        };
    };
 
    for (var i = 0; i < namespaces.length; i++) {
        for (var j = 0; j < methods.length; j++) {
            register_method(namespaces[i], methods[j]);
        }
    }
 
    return api;
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License