hazdev-webutils
Version:
Utilities commonly used in web applications developed by the EHP HazDev team.
274 lines (235 loc) • 6.37 kB
JavaScript
;
var Util = require('./Util');
var _CALLBACK_SEQUENCE = 0;
// defaults for jsonp method
var _DEFAULT_JSONP_OPTIONS = {
url: null,
success: null,
error: null,
done: null,
data: null,
callbackName: null,
callbackParameter: 'callback'
};
// defaults for ajax method
var _DEFAULT_AJAX_OPTIONS = {
url: null,
success: null,
error: null,
done: null,
method: 'GET',
headers: null,
data: null,
rawdata: null,
timeout: 5000,
ontimeout: null
};
// API Method Declarations
var ajax,
getCallbackName,
jsonp,
restrictOrigin,
urlEncode;
// API Method Definitions
/**
* Make an AJAX request.
*
* @param options.url {String}
* the url to request.
* @param options.success {Function}
* called with data loaded by script
* @param options.error {Function} optional
* called when script fails to load
* @param options.done {Function}
* called when ajax is complete, after success or error.
* @param options.method {String}
* request method, default is 'GET'
* @param options.headers {Object}
* request header name as key, value as value.
* @param options.data {Object}
* request data, sent using content type
* 'application/x-www-form-urlencoded'.
* @param options.rawdata {?}
* passed directly to send method, when options.data is null.
* Content-type header must also be specified. Default is null.
* @param options.timeout {Number}
* time in milliseconds a request can take, default is 5000.
* @param options.ontimeout {Function} optional
* called when script fails to load due to network timeout.
*/
ajax = function (options) {
var h,
postdata,
queryString,
url,
xhr;
options = Util.extend({}, _DEFAULT_AJAX_OPTIONS, options);
url = options.url;
if (options.restrictOrigin) {
url = restrictOrigin(url);
}
postdata = options.rawdata;
if (options.data !== null) {
queryString = urlEncode(options.data);
if (options.method === 'GET') {
// append to url
url = url + '?' + queryString;
} else {
// otherwise send as request body
postdata = queryString;
if (options.headers === null) {
options.headers = {};
}
// set request content type
options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
}
xhr = new XMLHttpRequest();
// setup callback
xhr.onreadystatechange = function () {
var data, contentType;
if (xhr.readyState === 4) {
if (xhr.status === 200) {
if (options.success !== null) {
try {
data = xhr.response;
contentType = xhr.getResponseHeader('Content-Type');
if (contentType && contentType.indexOf('json') !== -1) {
data = JSON.parse(data);
}
options.success(data, xhr);
} catch (e) {
if (options.error !== null) {
options.error(e, xhr);
}
}
}
} else {
if (options.error) {
options.error(xhr.status, xhr);
}
}
if (options.done !== null) {
options.done(xhr);
}
}
};
// open request
xhr.open(options.method, url, true);
// handle timeout
if (options.ontimeout !== null) {
xhr.timeout = options.timeout;
xhr.ontimeout = function () {
options.ontimeout(xhr);
}
};
// send headers
if (options.headers !== null) {
for (h in options.headers) {
xhr.setRequestHeader(h, options.headers[h]);
}
}
// send data
xhr.send(postdata);
return xhr;
};
/**
* Generate a unique callback name.
*
* @return a unique callback name.
*/
getCallbackName = function () {
return '_xhr_callback_' + new Date().getTime() +
'_' + (++_CALLBACK_SEQUENCE);
};
/**
* Make a JSONP request.
*
* @param options.url {String}
* url to load
* @param options.success {Function}
* called with data loaded by script
* @param options.error {Function} optional
* called when script fails to load
* @param options.done {Function} optional
* called when jsonp is complete, after success or error.
* @param options.data {Object} optional
* request parameters to add to url
*
* @param options.callbackName {String} optional
* @param options.callbackParameter {String} optional
* default is 'callback'
*/
jsonp = function (options) {
var data,
callback,
url;
options = Util.extend({}, _DEFAULT_JSONP_OPTIONS, options);
url = options.url;
data = Util.extend({}, options.data);
callback = options.callbackName || getCallbackName();
// add data and callback to url
data[options.callbackParameter] = callback;
url += (url.indexOf('?') === -1 ? '?' : '&') + urlEncode(data);
// setup global callback called by script
window[callback] = function () {
options.success.apply(null, arguments);
};
Util.loadScript(url, {
error: options.error,
done: function () {
window[callback] = null;
delete window[callback];
if (options.done !== null) {
options.done();
}
}
});
};
restrictOrigin = function (url) {
var a,
restrictedUrl;
a = document.createElement('a'); // Hack to parse only the pathname
a.setAttribute('href', url);
restrictedUrl = a.pathname;
// Needed for IE, which omits leading slash.
if ((url.indexOf('http') === 0 || url.indexOf('/') === 0) &&
restrictedUrl.indexOf('/') !== 0) {
restrictedUrl = '/' + restrictedUrl;
}
return restrictedUrl;
};
/**
* URL encode an object.
*
* @param obj {Object}
* object to encode
*
* @return {String}
* url encoded object
*/
urlEncode = function (obj) {
var data, key, encodedKey, value, i, len;
data = [];
for (key in obj) {
encodedKey = encodeURIComponent(key);
value = obj[key];
if (value instanceof Array) {
// Add each value in array seperately
for (i = 0, len = value.length; i < len; i++) {
data.push(encodedKey + '=' + encodeURIComponent(value[i]));
}
} else {
data.push(encodedKey + '=' + encodeURIComponent(value));
}
}
return data.join('&');
};
// expose the API
module.exports = {
ajax: ajax,
getCallbackName: getCallbackName,
jsonp: jsonp,
restrictOrigin: restrictOrigin,
urlEncode: urlEncode,
};