goog.provide('M.remote');
goog.provide('M.remote.method');
goog.provide('M.remote.Response');
goog.require('M.utils');
goog.require('M.exception');
goog.require('goog.dom');
goog.require('goog.dom.xml');
/**
* @namespace M.remote
*/
(function(window) {
/**
* This function gets a resource throw a
* HTTP GET method and checks if the request
* is ajax or jsonp based
*
* @function
* @param {string} url
* @param {Object} options
* @returns {Promise}
* @api stable
*/
M.remote.get = function(url, data, options) {
var req;
var useProxy = ((M.utils.isNullOrEmpty(options) || (options.jsonp !== false)) && M.proxy_ !== false);
if (useProxy === true) {
req = M.remote.jsonp_(url, data, options);
}
else {
req = M.remote.ajax_(url, data, M.remote.method.GET, false);
}
return req;
};
/**
* This function gets a resource throw a
* HTTP POST method using ajax
*
* @function
* @param {string} url
* @param {Object} data
* @returns {Promise}
* @api stable
*/
M.remote.post = function(url, data, options) {
return M.remote.ajax_(url, data, M.remote.method.POST);
};
M.remote.jsonp_ = function(url, data, options) {
if (!M.utils.isNullOrEmpty(data)) {
url = M.utils.addParameters(url, data);
}
if (M.proxy_) {
url = M.remote.manageProxy_(url, M.remote.method.GET);
}
// creates a random name to avoid clonflicts
var jsonpHandlerName = M.utils.generateRandom('mapea_jsonp_handler_');
url = M.utils.addParameters(url, {
'callback': jsonpHandlerName
});
var req = new Promise(function(success, fail) {
var userCallback = success;
// get the promise of the script tag
var scriptTagPromise = new Promise(function(scriptTagSuccess) {
window[jsonpHandlerName] = scriptTagSuccess;
});
/* when the script tag was executed remove
* the handler and execute the callback
*/
scriptTagPromise.then(function(proxyResponse) {
// remove the jsonp handler from global window
delete window[jsonpHandlerName];
// remove the script tag from the html
M.remote.removeScriptTag_(jsonpHandlerName);
var response = new M.remote.Response();
response.parseProxy(proxyResponse);
userCallback(response);
});
});
// creates the script tag
M.remote.createScriptTag_(url, jsonpHandlerName);
return req;
};
M.remote.ajax_ = function(url, data, method, useProxy) {
if ((useProxy !== false) && (M.proxy_ === true)) {
url = M.remote.manageProxy_(url, method);
}
// parses parameters to string
if (M.utils.isObject(data)) {
data = JSON.stringify(data);
}
return new Promise(function(success, fail) {
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var response = new M.remote.Response();
response.parseXmlHttp(xhr);
success(response);
}
};
xhr.open(method, url, true);
xhr.send(data);
});
};
M.remote.manageProxy_ = function(url, method) {
// deafult GET
var proxyUrl = M.config.PROXY_URL;
if (method === M.remote.method.POST) {
proxyUrl = M.config.PROXY_POST_URL;
}
proxyUrl = M.utils.addParameters(proxyUrl, {
'url': url
});
return proxyUrl;
};
M.remote.createScriptTag_ = function(proxyUrl, jsonpHandlerName) {
var scriptTag = document.createElement("script");
scriptTag.type = "text/javascript";
scriptTag.id = jsonpHandlerName;
scriptTag.src = proxyUrl;
scriptTag.setAttribute("async", "");
goog.dom.appendChild(window.document.body, scriptTag);
};
M.remote.removeScriptTag_ = function(jsonpHandlerName) {
var scriptTag = document.getElementById(jsonpHandlerName);
goog.dom.removeNode(scriptTag);
};
/**
* @classdesc
* Response for proxy requests
*
* @constructor
* @extends {M.Object}
* @param {Object} response from proxy requests
* @api stable
*/
M.remote.Response = function(xmlHttpResponse) {
/**
* @public
* @type {string}
* @api stable
*/
this.text = null;
/**
* @public
* @type {XML}
* @api stable
*/
this.xml = null;
/**
* @public
* @type {Object}
* @api stable
*/
this.headers = {};
/**
* @public
* @type {boolean}
* @api stable
*/
this.error = false;
/**
* @public
* @type {int}
* @api stable
*/
this.code = 0;
};
/**
* This function parses a XmlHttp response
* from an ajax request
*
* @function
* @param {Object} url
* @api stable
*/
M.remote.Response.prototype.parseXmlHttp = function(xmlHttpResponse) {
this.text = xmlHttpResponse['responseText'];
this.xml = xmlHttpResponse['responseXML'];
this.code = xmlHttpResponse['status'];
this.error = (xmlHttpResponse['statusText'] !== 'OK');
var headers = xmlHttpResponse.getAllResponseHeaders();
headers = headers.split('\n');
headers.forEach(function(head) {
head = head.trim();
var headName = head.replace(/^([^\:]+)\:(.+)$/, '$1').trim();
var headValue = head.replace(/^([^\:]+)\:(.+)$/, '$2').trim();
if (headName !== '') {
this.headers[headName] = headValue;
}
}, this);
};
/**
* This function parses a XmlHttp response
* from an ajax request
*
* @function
* @param {Object} url
* @api stable
*/
M.remote.Response.prototype.parseProxy = function(proxyResponse) {
this.code = proxyResponse.code;
this.error = proxyResponse.error;
// adds content
if ((this.code === 200) && (this.error !== true)) {
this.text = proxyResponse.content.trim();
try {
// it uses DOMParser for html responses
// google XML parser in other case
let contentType = proxyResponse.headers['Content-Type'];
if ((typeof DOMParser !== 'undefined') && /text\/html/i.test(contentType)) {
this.xml = (new DOMParser()).parseFromString(this.text, 'text/html');
}
// it avoids responses that aren't xml format
else if (/xml/i.test(contentType)) {
this.xml = goog.dom.xml.loadXml(this.text);
}
}
catch (err) {
this.xml = null;
this.error = true;
}
}
// adds headers
Object.keys(proxyResponse.headers).forEach(function(head) {
this.headers[head] = proxyResponse.headers[head];
}, this);
};
/**
* HTTP method GET
* @const
* @type {string}
* @public
* @api stable
*/
M.remote.method.GET = 'GET';
/**
* HTTP method POST
* @const
* @type {string}
* @public
* @api stable
*/
M.remote.method.POST = 'POST';
})(window || {});