x-http-client
Version:
An http client to make it easier to send requests (including JSONP requests) to the server.
1,629 lines (1,403 loc) • 189 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.HttpClient = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
var isFunction = require(38);
/**
* Cancel controller is used to cancel actions. One controller can bind any number of actions.
*
* @class
*/
function CancelController() {
/**
* @type {boolean} Whether the controller is cancelled.
*/
this.cancelled = false;
/**
* @type {Function[]} The callbacks to call on cancel.
*/
this.callbacks = [];
}
/**
* Cancel the actions that bind with this cancel controller.
*/
CancelController.prototype.cancel = function () {
var callbacks = this.callbacks;
var i = 0;
var l = callbacks.length;
if (this.cancelled === false) {
this.cancelled = true;
for ( ; i < l; i += 1) {
try {
callbacks[i]();
} catch (e) {
// Throw the error later for debuging.
(function (e) {
setTimeout(function () {
throw e;
});
})(e);
}
}
}
};
/**
* Check whether the controller is cancelled.
*
* @returns {boolean} Returns `true` if the controller is cancelled, otherwise `false` is returned.
*/
CancelController.prototype.isCancelled = function () {
return this.cancelled;
};
/**
* Register a callback, which will be called when the `cancel()` method is called.
*
* @param {Function} callback The callback function to call on cancel.
*/
CancelController.prototype.registerCancelCallback = function (callback) {
if (isFunction(callback)) {
this.callbacks.push(callback);
}
};
module.exports = CancelController;
},{"38":38}],2:[function(require,module,exports){
var QS = require(43);
var merge = require(40);
var isFunction = require(38);
var isPlainObject = require(39);
var isAbsoluteURL = require(36);
var uuid = require(35);
var noop = require(33);
var template = require(34);
var inherits = require(32);
var constants = require(25);
var defineExports = require(28);
var createDefaultOptions = require(27);
var createCancelController = require(26);
var Request = require(9);
var HttpRequest = require(3);
var JSONPRequest = require(6);
var Response = require(10);
var HttpResponse = require(4);
var JSONPResponse = require(7);
var ResponseError = require(11);
var HttpResponseError = require(5);
var JSONPResponseError = require(8);
var CancelController = require(1);
var version = '0.0.1-alpha.5';
/**
* @class
*
* @param {RequestOptions} [defaults] The default options to use when sending requests with the created http client.
* This default options will be merged into the internal default options that `createDefaultOptions()` returns.
*
* @param {HandleOptionsFunction} [handleDefaults] The handler function to process the merged default options. The
* merged default options will be passed into the function as the first argument. You can make changes to it as you
* want. This function must return synchronously. The return value of this function is ignored.
*
* @param {HandleOptionsFunction} [handleRequestOptions] The handler function to process each merged request options.
* Every options that passed into `send`, `fetch`, `getJSONP`, `fetchJSONP` will be processed by this handler function.
*/
function HttpClient(defaults, handleDefaults, handleRequestOptions) {
var defaultOptions = createDefaultOptions();
if (isPlainObject(defaults)) {
merge(defaultOptions, defaults);
}
if (isFunction(handleDefaults)) {
handleDefaults(defaultOptions);
// Deep copy the chagned options
defaultOptions = merge({}, defaultOptions);
}
if (!isFunction(handleRequestOptions)) {
handleRequestOptions = noop;
}
/**
* Get a copy of the default request options. This function is NOT available on the prototype of `HttpClient`.
*
* @returns {RequestOptions}
*/
this.copyOptions = function () {
return merge({}, defaultOptions);
};
/**
* Merge the request options with the default request options. This function is NOT available on the prototype of
* `HttpClient` and will call `handleRequestOptions` to handle the merged request options.
*
* @param {RequestOptions} options The request options to merge.
* @returns {RequestOptions} Returns the merged request options.
*/
this.mergeOptions = function (options) {
var requestOptions = merge({}, defaultOptions, options);
handleRequestOptions(requestOptions);
return requestOptions;
};
}
/**
* Send an http request.
*
* @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options.
* @param {RequestSuccessCallback} onsuccess The callback to call on success.
* @param {RequestErrorCallback} onerror The callback to call on error.
* @returns {HttpRequest} Returns an instance of `HttpRequest`.
*/
HttpClient.prototype.send = function (options, onsuccess, onerror) {
var requestOptions = this.mergeOptions(options);
requestOptions.requestFunctionName = 'send';
requestOptions.controller = null;
return new HttpRequest(requestOptions, onsuccess, onerror);
};
/**
* Send an http request and return a promise.
*
* @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options.
* @returns {Promise} Returns an instance of `Promise`.
*/
HttpClient.prototype.fetch = function (options) {
var requestOptions = this.mergeOptions(options);
var controller = requestOptions.controller;
requestOptions.requestFunctionName = 'fetch';
return new Promise(function (resolve, reject) {
var request = new HttpRequest(requestOptions, function (response) {
if (controller) {
if (!controller.isCancelled()) {
resolve(response);
}
} else {
resolve(response);
}
}, reject);
if (controller) {
// Trigger the `ERR_CANCELLED` error.
if (controller.isCancelled()) {
request.cancel();
} else {
controller.registerCancelCallback(function () {
request.cancel();
});
}
}
});
};
/**
* Send a jsonp request.
*
* @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options.
* @param {RequestSuccessCallback} onsuccess The callback to call on success.
* @param {RequestErrorCallback} onerror The callback to call on error.
* @returns {JSONPRequest} Returns an instance of `JSONPRequest`.
*/
HttpClient.prototype.getJSONP = function (options, onsuccess, onerror) {
var requestOptions = this.mergeOptions(options);
requestOptions.requestFunctionName = 'getJSONP';
requestOptions.controller = null;
return new JSONPRequest(requestOptions, onsuccess, onerror);
};
/**
* Send a jsonp request and return a promise.
*
* @param {RequestOptions} options The request options to use, which will be merged into a copy of the default options.
* @returns {Promise} Returns an instance of `Promise`.
*/
HttpClient.prototype.fetchJSONP = function (options) {
var requestOptions = this.mergeOptions(options);
var controller = requestOptions.controller;
requestOptions.requestFunctionName = 'fetchJSONP';
return new Promise(function (resolve, reject) {
var request = new JSONPRequest(requestOptions, function (response) {
if (controller) {
if (!controller.isCancelled()) {
resolve(response);
}
} else {
resolve(response);
}
}, reject);
if (controller) {
// Trigger the `ERR_CANCELLED` error.
if (controller.isCancelled()) {
request.cancel();
} else {
controller.registerCancelCallback(function () {
request.cancel();
});
}
}
});
};
/**
* Create a new instance of `CancelController`.
*
* @returns {CancelController} Returns an new instance of `CancelController`.
*/
HttpClient.prototype.createCancelController = createCancelController;
/**
* Create a new instance of `CancelController`.
*
* @returns {CancelController} Returns an new instance of `CancelController`.
*/
HttpClient.createCancelController = createCancelController;
// The version.
HttpClient.version = version;
HttpClient.prototype.version = version;
defineExports(HttpClient, 'constants', merge({}, constants));
defineExports(HttpClient, 'libs', {
QS: QS
});
defineExports(HttpClient, 'classes', {
CancelController: CancelController,
HttpClient: HttpClient,
HttpRequest: HttpRequest,
HttpResponse: HttpResponse,
HttpResponseError: HttpResponseError,
JSONPRequest: JSONPRequest,
JSONPResponse: JSONPResponse,
JSONPResponseError: JSONPResponseError,
Request: Request,
Response: Response,
ResponseError: ResponseError
});
defineExports(HttpClient, 'functions', {
template: template,
merge: merge,
isAbsoluteURL: isAbsoluteURL,
isFunction: isFunction,
isPlainObject: isPlainObject,
uuid: uuid,
noop: noop,
inherits: inherits,
createDefaultOptions: createDefaultOptions
});
module.exports = HttpClient;
/**
* This callback is used to hanlde the merged request options. It must retrun the result synchronously.
*
* @callback HandleOptionsFunction
* @param {RequestOptions} options The merged request options.
* @returns {void}
*/
/**
* The callback to call on success.
*
* @callback RequestSuccessCallback
* @param {HttpResponse|any} response The http response or the return value of `options.transformResponse(response)`.
*/
/**
* The callback to call on error.
*
* @callback RequestErrorCallback
* @param {HttpResponseError|any} error The http response error or the return value of `options.transformError(error)`.
*/
/**
* The definiton of the request options.
*
* @typedef {Object.<string, *>} RequestOptions
*
* @property {string} [method] The http request method. The default method is `GET`.
*
* @property {string} [baseURL] The request base url. If the `url` is relative url, and the `baseURL` is not `null`, the
* `baseURL` will be prepend to the `url`.
*
* @property {string} url The request url that can contain any number of placeholders, and will be compiled with the
* data that passed in with `options.model`.
*
* @property {Object.<string, *>} [model] The data used to compile the request url.
*
* @property {Object.<string, *>} [query] The data that will be compiled to query string.
*
* @property {Object.<string, *>} [body] The object that contains the content which will be send to the server. This
* object has only one property. The name of the property is the content type of the content, which will be used to find
* a processor in `options.httpRequestBodyProcessor`. The processor is used to process the value of the property. The
* processed value which the processor returns will be send to the server as the request body.
*
* @property {number} [timeout] The number of milliseconds the request can take before it finished. If the timeout value
* is `0`, no timer will be set. If the request does not finsihed within the given time, a timeout error will be thrown.
* The default value is `0`.
*
* @property {boolean} [cors] Whether to set `withCredentials` property of the `XMLHttpRequest` to `true`. The default
* value is `false`.
*
* @property {boolean} [noCache] Whether to disable the cache. If the value is `true`, the headers in
* `options.noCacheHeaders` will be set. The default value is `false`.
*
* @property {Object.<string, *>} [noCacheHeaders] The headers to set when `options.noCache` is set to `true`.
*
* @property {string} [jsonp] The query string key to hold the value of the callback name when sending JSONP request.
* The default values is `callback`.
*
* @property {Object.<string, *>} [settings] The object to keep the settings information that the user passed in. The
* library itself will not touch this property. You can use this property to hold any information that you want, when
* you extend the functionality of your own instance of `HttpClient`. The default value of this property is an empty
* object.
*
* @property {Object.<string, *>} [headers] The object that contains the headers to set when sending the request. Only
* the non-undefined and non-null headers are set.
*
* @property {CancelController} [controller] The `CancelController` used to cancel the request. It only works when using
* `fetch` or `fetchJSONP` to send request. If the you send request using `send` or `getJSONP`, the `options.controller`
* will be set to `null`.
*
* @property {string} [requestFunctionName] The name of the function that send the request. Can be `send`, `fetch`,
* `getJSONP`, `fetchJSONP`. This value is set by the library, don't change it.
*
* @property {string} [requestType] The request type of this request. The value of it is set by the library itself, can
* be `HTTP_REQUEST` or `JSONP_REQUEST`. Any other value the user passed in is ignored. You can use this property to get
* the type of the current request.
*
* @property {Object.<string, *>} [xhrProps] The object that contains the properties to set on the instance of the
* `XMLHttpRequest`.
*
* @property {string} [username] The user name to use for authentication purposes. The defualt value is `null`.
*
* @property {string} [password] The password to use for authentication purposes. The defualt value is `null`.
*
* @property {Object.<string, httpRequestBodyProcessor>} [httpRequestBodyProcessor] The object that contains the
* http request body processors.
*
* @property {Object.<string, ResponseParseFunction>} [httpResponseParser] The object that contains the http response
* parsers.
*
* @property {Object.<string, ResponseParseFunction>} [jsonpResponseParser] The object that contains the jsonp response
* parsers.
*
* @property {Object.<string, ResponseErrorParseFunction>} [httpResponseErrorParser] The object that contains the http
* response error parsers.
*
* @property {Object.<string, ResponseErrorParseFunction>} [jsonpResponseErrorParser] The object that contains the jsonp
* response error parsers.
*
* @property {HanldeOptionsFunction} [handleOptions] The function to handle the options.
*
* @property {CreateXHRFunction} [createXHR] The function to create the `XMLHttpRequest` instance.
*
* @property {ScriptCreateFunction} [createScript] The function to create the `HTMLScriptElement` instance.
*
* @property {JSONPContainerFindFunction} [jsonpContainerNode] The function that returns the container node, which will
* be used to append the script element when sending jsonp request.
*
* @property {JSONPCallbackNameGenerateFunction} [jsonpCallbackName] The function to generate the unique callback name
* when sending jsonp request.
*
* @property {CompileURLFunction} [compileURL] The function to compile url.
*
* @property {EncodeQueryStringFunction} encodeQueryString The function to encode the query string.
*
* @property {XHRHookFunction} onXhrCreated The function to call on xhr created.
*
* @property {XHRHookFunction} onXhrOpened The functon to call on xhr opened.
*
* @property {XHRHookFunction} onXhrSent The function to call on xhr sent.
*
* @property {RequestCreatedFunction} onRequestCreated The function to call on request created.
*
* @property {CheckResponseOkFunction} isResponseOk The function to check whether the response is ok.
*
* @property {TransformErrorFunction} transformError The function to transfrom the response error. The return value of
* this function will be passed to the `onerror` callback.
*
* @property {TransformResponseFunction} transformResponse The function to transfrom the response. The return value of
* this function will be passed to the `onsuccess` callback.
*
* @property {CheckShouldCallErrorCallbackFunction} shouldCallErrorCallback The function to check whether to call the
* error callback.
*
* @property {CheckShouldCallSuccessCallbackFunction} shouldCallSuccessCallback The function to check whether to call
* the success callback.
*/
/**
* The definiton of http request data processor.
*
* @typedef {Object.<string, *>} httpRequestBodyProcessor
* @property {number} priority The priority of the processor.
* @property {Object.<string, *>} [headers] The headers to set when this processor is used.
* @property {HttpRequestContentProcessFunction} [processor] The function to process the request body.
*/
/**
* The function to handle the options.
*
* @callback HanldeOptionsFunction
* @param {RequestOptions} options The request options.
*/
/**
* The function to process the request data.
*
* @callback HttpRequestContentProcessFunction
* @param {Object.<string, *>} content The conent need to process.
* @param {RequestOptions} options The request options of the current request.
* @returns {any} Returns the value that will be send to the server.
*/
/**
* The function to parse the response. This function will be mounted on the response instance, which made it a method
* of the `Response` instance. The parameters and the return value is up on you.
*
* @callback ResponseParseFunction
*/
/**
* The function to parse the response error. This function will be mounted on the response error instance, which made it
* a method of the `ResponseError` instance. The parameters and the return value is up on you.
*
* @callback ResponseErrorParseFunction
*/
/**
* The function to create the `XMLHttpRequest` instance.
*
* @callback CreateXHRFunction
* @param {RequestOptions} options The request options.
* @returns {XMLHttpRequest} Returns an instance of `XMLHttpRequest`.
*/
/**
* The function to create the `HTMLScriptElement` instance.
*
* @callback ScriptCreateFunction
* @param {RequestOptions} options The request options.
* @returns {HTMLScriptElement} Returns an instance of `HTMLScriptElement`.
*/
/**
* The function that returns the node to append the script element.
*
* @callback JSONPContainerFindFunction
* @param {RequestOptions} options The request options.
* @returns {Node} Returns the node to append the script element.
*/
/**
* The function to generate the unique callback name.
*
* @callback JSONPCallbackNameGenerateFunction
* @param {RequestOptions} options The request options.
* @returns {string} Retruns a valid javascript identifier to hold the callbak.
*/
/**
* The function to compile the request url.
*
* @callback CompileURLFunction
* @param {string} url The url (with baseURL) to compile.
* @param {Object.<string, *>} param The param to compile the url.
* @param {RequestOptions} options The request options.
* @returns {string} Returns the compiled url.
*/
/**
* The function to encode the query string.
*
* @callback EncodeQueryStringFunction
* @param {Object.<string, *>} data The data to be encoded to query string.
* @param {RequestOptions} options The request options.
* @returns {string} Returns the encoded query string.
*/
/**
* The xhr hook function.
*
* @callback XHRHookFunction
* @param {XMLHttpRequest} xhr The instance of `XMLHttpRequest`.
* @param {RequestOptions} options The request options.
*/
/**
* @callback RequestCreatedFunction
* @param {HttpRequest|JSONPRequest} request The request instance, can be `HttpRequest` or `JSONPRequest`.
*/
/**
* The function to check whether the response is ok.
*
* @callback CheckResponseOkFunction
* @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
* @param {Response} response The response instance.
* @returns {boolean} Returns `true` if the response is ok, otherwise `false` is returned.
*/
/**
* The function to check whether to call the error callback.
*
* @callback CheckShouldCallErrorCallbackFunction
* @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
* @param {any} transformedError The data that `options.transformError(...)` returns.
* @param {HttpResponseError|JSONPResponseError} error The response error.
*/
/**
* The function to check whether to call the success callback.
*
* @callback CheckShouldCallSuccessCallbackFunction
* @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
* @param {any} transformedResponse The data that `options.transformResponse(...)` returns.
* @param {HttpResponse|JSONPResponse} response The response.
*/
/**
* The function to transfrom the response. The return value of this function will be passed to the `onsuccess` callback.
*
* @callback TransformResponseFunction
* @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
* @param {HttpResponse|JSONPResponse} response The response.
* @returns {any} Returns the transformed response.
*/
/**
* The function to transfrom the response error. The return value of this function will be passed to the `onerror`
* callback.
*
* @callback TransformErrorFunction
* @param {string} requestType The request type, `HTTP_REQUEST` or `JSONP_REQUEST`.
* @param {HttpResponseError|JSONPResponseError} error The response error.
* @returns {any} Returns the transformed response error.
*/
},{"1":1,"10":10,"11":11,"25":25,"26":26,"27":27,"28":28,"3":3,"32":32,"33":33,"34":34,"35":35,"36":36,"38":38,"39":39,"4":4,"40":40,"43":43,"5":5,"6":6,"7":7,"8":8,"9":9}],3:[function(require,module,exports){
var Request = require(9);
var constants = require(25);
var inherits = require(32);
var buildURL = require(23);
var handleOptions = require(30);
var callRequestCreatedCallback = require(24);
var addEventListeners = require(12);
var handleXhrProps = require(17);
var handleHeaders = require(15);
var handleRequestBody = require(16);
var callXhrHook = require(14);
/**
* http request.
*
* @class
* @extends {Request}
* @param {RequestOptions} options The request options.
* @param {RequestSuccessCallback} onsuccess The callback to call on success.
* @param {RequestErrorCallback} onerror The callback to call on error.
*/
function HttpRequest(options, onsuccess, onerror) {
var xhr;
var body;
var url;
// Call the super constructor.
Request.call(this, constants.HTTP_REQUEST, options, onsuccess, onerror);
// Call `options.handleOptions` to handle options.
handleOptions(options);
xhr = this.xhr = options.createXHR.call(null, options);
body = handleRequestBody(options);
url = buildURL(options);
// Set properties to the xhr.
handleXhrProps(xhr, options);
// Call onXhrCreated.
callXhrHook(options.onXhrCreated, xhr, options);
// Open the request.
xhr.open(options.method || 'GET', url, true, options.username, options.password);
// Add event listeners.
addEventListeners(this);
// Call onXhrOpened.
callXhrHook(options.onXhrOpened, xhr, options);
// Hanlde headers.
handleHeaders(xhr, options);
// Send the body to the server.
xhr.send(body);
// Call onXhrSent.
callXhrHook(options.onXhrSent, xhr, options);
// Call onRequestCreated
callRequestCreatedCallback(options, this);
}
inherits(HttpRequest, Request);
module.exports = HttpRequest;
},{"12":12,"14":14,"15":15,"16":16,"17":17,"23":23,"24":24,"25":25,"30":30,"32":32,"9":9}],4:[function(require,module,exports){
/**
* HttpResponse module.
*
* @module class/HttpResponse
*/
var Response = require(10);
var inherits = require(32);
var addCustomParser = require(22);
/**
* The HttpResponse class.
*
* @class
* @param {HttpRequest} request The http request.
*/
function HttpResponse(request) {
Response.call(this, request);
addCustomParser(this, request.options, 'httpResponseParser');
}
inherits(HttpResponse, Response);
module.exports = HttpResponse;
},{"10":10,"22":22,"32":32}],5:[function(require,module,exports){
var ResponseError = require(11);
var inherits = require(32);
var addCustomParser = require(22);
/**
* @class
* @param {string} code The error code.
* @param {HttpRequest} request The http request.
*/
function HttpResponseError(code, request) {
ResponseError.call(this, code, request);
addCustomParser(this, request.options, 'httpResponseErrorParser');
}
inherits(HttpResponseError, ResponseError);
module.exports = HttpResponseError;
},{"11":11,"22":22,"32":32}],6:[function(require,module,exports){
var Request = require(9);
var constants = require(25);
var inherits = require(32);
var handleOptions = require(30);
var callRequestCreatedCallback = require(24);
var addEventListeners = require(18);
var buildCallbackName = require(19);
var handleScriptCors = require(21);
var buildScriptSrc = require(20);
/**
* JSONP request.
*
* @class
* @extends {Request}
* @param {RequestOptions} options The request options.
* @param {RequestSuccessCallback} onsuccess The callback to call on success.
* @param {RequestErrorCallback} onerror The callback to call on error.
*/
function JSONPRequest(options, onsuccess, onerror) {
var src;
var script;
var callbackName;
var containerNode;
Request.call(this, constants.JSONP_REQUEST, options, onsuccess, onerror);
// Call `options.handleOptions` to handle options.
handleOptions(options);
script = this.script = options.createScript.call(null, options);
containerNode = options.jsonpContainerNode.call(null, options);
callbackName = buildCallbackName(options);
src = buildScriptSrc(options, callbackName);
// Set the src attribute.
script.setAttribute('src', src);
// Handle `options.cors`.
handleScriptCors(script, options);
// Add event listeners.
addEventListeners(this, callbackName);
// Inject the script node.
containerNode.appendChild(script);
// Call onRequestCreated.
callRequestCreatedCallback(options, this);
}
inherits(JSONPRequest, Request);
module.exports = JSONPRequest;
},{"18":18,"19":19,"20":20,"21":21,"24":24,"25":25,"30":30,"32":32,"9":9}],7:[function(require,module,exports){
/**
* JSONPResponse module.
*
* @module class/JSONPResponse
*/
var Response = require(10);
var inherits = require(32);
var addCustomParser = require(22);
/**
* The JSONPResponse class.
*
* @class
* @param {JSONRequest} request The http request.
*/
function JSONPResponse(request) {
Response.call(this, request);
addCustomParser(this, request.options, 'jsonpResponseParser');
}
inherits(JSONPResponse, Response);
module.exports = JSONPResponse;
},{"10":10,"22":22,"32":32}],8:[function(require,module,exports){
var ResponseError = require(11);
var inherits = require(32);
var addCustomParser = require(22);
/**
* @class
* @param {string} code The error code.
* @param {JSONPRequest} request The JSONP request.
*/
function JSONPResponseError(code, request) {
ResponseError.call(this, code, request);
addCustomParser(this, request.options, 'jsonpResponseErrorParser');
}
inherits(ResponseError, JSONPResponseError);
module.exports = JSONPResponseError;
},{"11":11,"22":22,"32":32}],9:[function(require,module,exports){
var uuid = require(35);
/**
* The base Reqeust class.
*
* @class
* @param {string} type The type of request, can be `HTTP_REQUEST` or `JSONP_REQUEST`.
* @param {RequestOptions} options The request options.
* @param {RequestSuccessCallback} onsuccess The callback to call on success.
* @param {RequestErrorCallback} onerror The callback to call on error.
*/
function Request(type, options, onsuccess, onerror) {
/**
* If there is an error happend, the `errorCode` is a string reprsengting the type of the error. If there is no
* error, the value of `errorCode` is `null`.
*/
this.errorCode = null;
/**
* The `XMLHttpRequest` we use when sending http request.
*/
this.xhr = null;
/**
* The `HTMLScriptElement` we use when sending JSONP request.
*/
this.script = null;
/**
* Whether the request is finished.
*/
this.finished = false;
/**
* The response JSON data of the JSONP request.
*/
this.responseJSON = null;
/**
* An unique id for this request.
*/
this.requestId = uuid();
/**
* The type of request, can be `HTTP_REQUEST` or `JSONP_REQUEST`.
*/
this.requestType = type;
/**
* The request options.
*/
this.options = options;
/**
* The name of the function that create this request. Can be `send`, `fetch`, `getJOSNP`, `fetchJSONP`. This value
* is set by the libray itself.
*/
this.requestFunctionName = options.requestFunctionName;
/**
* The `CancelController` that used to cancel this request. We never use this property internally, just holding the
* information in case that the user needs.
*/
this.controller = options.controller || null;
/**
* The callback to call on success.
*/
this.onsuccess = onsuccess || null;
/**
* The callback to call on error.
*/
this.onerror = onerror || null;
/**
* Set the request type back.
*/
options.requestType = type;
}
module.exports = Request;
},{"35":35}],10:[function(require,module,exports){
/**
* Represents a response.
*
* @param {Request} request The instance of `Request`.
*/
function Response(request) {
/**
* @type {Request}
*/
this.request = request;
}
module.exports = Response;
},{}],11:[function(require,module,exports){
var errorMessages = {
ERR_ABORTED: 'Request aborted',
ERR_CANCELLED: 'Request cancelled',
ERR_NETWORK: 'Network error',
ERR_RESPONSE: 'Response error',
ERR_TIMEOUT: 'Request timeout'
};
/**
* Represents response error.
*
* @constructor
* @param {string} code The error code.
* @param {Request} request The request.
*/
function ResponseError(code, request) {
var message;
code = code || 'ERR_UNKNOWN';
if (errorMessages[code]) {
message = errorMessages[code];
}
if (!message) {
message = 'Unknown error ' + code;
}
request.errorCode = code;
this.code = code;
this.request = request;
this.message = message;
}
module.exports = ResponseError;
},{}],12:[function(require,module,exports){
var isFunction = require(38);
var HttpResponse = require(4);
var addTimeoutListener = require(13);
var fireCallbacks = require(29);
var noop = require(33);
var constants = require(25);
var ERR_ABORTED = constants.ERR_ABORTED;
var ERR_CANCELLED = constants.ERR_CANCELLED;
var ERR_NETWORK = constants.ERR_NETWORK;
var ERR_RESPONSE = constants.ERR_RESPONSE;
var ERR_TIMEOUT = constants.ERR_TIMEOUT;
/**
* Add event listeners to the http request. This function will overwite the `cancel` method on the given `HttpReqest`
* instance.
*
* @param {HttpRequest} request The http request to add event listeners.
*/
function addEventListeners(request) {
var xhr = request.xhr;
var options = request.options;
var requestType = request.requestType;
var response = new HttpResponse(request);
var isResponseOk = options.isResponseOk;
var clearTimeoutEvent = null;
var timeout = parseInt(options.timeout || 0, 10);
/**
* Cancel the request.
*/
var cancel = function () {
clearEvents();
if (xhr.abort) {
try {
xhr.abort();
} catch (e) {
// empty
}
}
finish(ERR_CANCELLED);
};
/**
* The function to clear events.
*/
var clearEvents = function () {
// Set clearEvents to the noop function.
clearEvents = noop;
xhr.onabort = null;
xhr.onerror = null;
xhr.onreadystatechange = null;
xhr.ontimeout = null;
if (clearTimeoutEvent) {
clearTimeoutEvent();
clearTimeoutEvent = null;
}
};
/**
* The function finish the request.
*
* @param {string} code The error code on error. If no error occured, the code is `null`.
*/
var finish = function (code) {
// Set finish to the noop function.
finish = noop;
// Set cancel to the noop function.
cancel = noop;
// Mark this request as finished.
request.finished = true;
// Clear events.
clearEvents();
// Fire callbacks.
fireCallbacks(code, response);
};
xhr.onabort = function () {
finish(ERR_ABORTED);
};
xhr.onerror = function () {
finish(ERR_NETWORK);
};
xhr.onreadystatechange = function () {
if (+xhr.readyState === 4) {
if (isFunction(isResponseOk)) {
if (isResponseOk(requestType, response)) {
finish(null);
} else {
finish(ERR_RESPONSE);
}
} else {
finish(null);
}
}
};
/**
* Cancel the request.
*/
request.cancel = function () {
cancel();
};
// Add timeout listener
if (!isNaN(timeout) && timeout > 0) {
clearTimeoutEvent = addTimeoutListener(xhr, timeout, function () {
clearEvents();
if (xhr.abort) {
try {
xhr.abort();
} catch (e) {
// empty
}
}
finish(ERR_TIMEOUT);
});
}
}
module.exports = addEventListeners;
},{"13":13,"25":25,"29":29,"33":33,"38":38,"4":4}],13:[function(require,module,exports){
/**
* Add timeout event listener on the XHR object.
*
* @param {XMLHttpRequest} xhr The XHR to add timeout event listener.
* @param {number} timeout The time to wait in milliseconds.
* @param {() => void} listener The timeout callback.
* @returns {() => void)} Returns a function to remove the timeout event listener.
*/
function addTimeoutListener(xhr, timeout, listener) {
var timeoutId = null;
var supportTimeout = 'timeout' in xhr && 'ontimeout' in xhr;
if (supportTimeout) {
xhr.timeout = timeout;
xhr.ontimeout = listener;
} else {
timeoutId = setTimeout(listener, timeout);
}
// Call this function to remove timeout event listener
function clearTimeoutEvent() {
if (xhr) {
if (timeoutId === null) {
xhr.ontimeout = null;
} else {
clearTimeout(timeoutId);
}
xhr = null;
listener = null;
}
}
return clearTimeoutEvent;
}
module.exports = addTimeoutListener;
},{}],14:[function(require,module,exports){
var isFunction = require(38);
/**
* The function to call xhr hook function.
*
* @param {XHRHookFunction} func The hook function to call, if it is not function, this hook is skipped.
* @param {XMLHttpReqeust} xhr The instance of `XMLHttpReqeust`.
* @param {RequestOption} options The request options.
*/
function callXhrHook(func, xhr, options) {
if (isFunction(func)) {
func(xhr, options);
}
}
module.exports = callXhrHook;
},{"38":38}],15:[function(require,module,exports){
var merge = require(40);
var isPlainObject = require(39);
var hasOwn = require(31);
/**
* The function to set the request headers.
*
* 1. Merge the `options.noCacheHeaders` if needed.
* 2. Set the request headers if needed.
*
* @param {XMLHttpReqeust} xhr The instance of `XMLHttpReqeust`.
* @param {RequestOption} options The request options.
*/
function handleHeaders(xhr, options) {
var name;
var value;
var headers = isPlainObject(options.headers) ? options.headers : {};
if (options.noCache) {
if (isPlainObject(options.noCacheHeaders)) {
headers = merge(headers, options.noCacheHeaders);
}
}
for (name in headers) {
if (hasOwn.call(headers, name)) {
value = headers[name];
// Only the non-undefined and non-null headers are set
if (value !== undefined && value !== null) {
xhr.setRequestHeader(name, value);
}
}
}
// Set the headers back.
options.headers = headers;
}
module.exports = handleHeaders;
},{"31":31,"39":39,"40":40}],16:[function(require,module,exports){
var merge = require(40);
var isFunction = require(38);
var isPlainObject = require(39);
var hasOwn = require(31);
/**
* Find a processor from `options.httpRequestBodyProcessor` to process the request body.
*
* @param {RequestOptions} options The request options.
* @returns {any} Retruns the content that send to the server.
*/
function handleRequestBody(options) {
var i;
var l;
var key;
var content = null;
var processor;
var contentProcessor;
var contentProcessors = [];
var body = options.body;
var processors = options.httpRequestBodyProcessor;
var headers = isPlainObject(options.headers) ? options.headers : {};
if (isPlainObject(body) && isPlainObject(processors)) {
// Find all processors.
for (key in processors) {
if (hasOwn.call(processors, key)) {
processor = processors[key];
if (isPlainObject(processor)) {
contentProcessors.push({
key: key,
headers: processor.headers,
priority: processor.priority,
processor: processor.processor
});
}
}
}
// Sort the processors by its priority.
contentProcessors.sort(function (a, b) {
return b.priority - a.priority;
});
// Find the first non-undefined content.
for (i = 0, l = contentProcessors.length; i < l; i += 1) {
processor = contentProcessors[i];
if (body[processor.key] !== undefined) {
content = body[processor.key];
contentProcessor = processor;
break;
}
}
// Use the processor to process the content.
if (contentProcessor) {
if (isPlainObject(contentProcessor.headers)) {
headers = merge(headers, contentProcessor.headers);
}
processor = contentProcessor.processor;
if (isFunction(processor)) {
content = processor(content, options);
}
}
}
// Make sure that the headers is a plain object.
options.headers = headers;
return content;
}
module.exports = handleRequestBody;
},{"31":31,"38":38,"39":39,"40":40}],17:[function(require,module,exports){
var isPlainObject = require(39);
var hasOwn = require(31);
/**
* The function to hanlde XMLHttpRequest properties.
*
* @param {XMLHttpRequest} xhr The instance of `XMLHttpRequest`.
* @param {RequestOptions} options The request options.
*/
function handleXhrProps(xhr, options) {
var prop;
var xhrProps = options.xhrProps;
if (options.cors) {
xhr.withCredentials = true;
}
if (isPlainObject(xhrProps)) {
for (prop in xhrProps) {
if (hasOwn.call(xhrProps, prop)) {
xhr[prop] = xhrProps[prop];
}
}
}
}
module.exports = handleXhrProps;
},{"31":31,"39":39}],18:[function(require,module,exports){
var isFunction = require(38);
var JSONPResponse = require(7);
var fireCallbacks = require(29);
var noop = require(33);
var constants = require(25);
var ERR_CANCELLED = constants.ERR_CANCELLED;
var ERR_NETWORK = constants.ERR_NETWORK;
var ERR_RESPONSE = constants.ERR_RESPONSE;
var ERR_TIMEOUT = constants.ERR_TIMEOUT;
/**
* Add event listeners to JSONP request.
*
* @param {JSONPRequest} request The JSONP request.
* @param {string} callbackName The callback name used to define the global JSONP callback.
*/
function addEventListeners(request, callbackName) {
var script = request.script;
var options = request.options;
var requestType = request.requestType;
var isResponseOk = options.isResponseOk;
var response = new JSONPResponse(request);
var timeout = parseInt(options.timeout || 0, 10);
var timeoutId = null;
/**
* The function finish the request.
*
* @param {string} code The error code on error. If no error occured, the code is `null`.
*/
var finish = function (code) {
// Set finish to the no operation function.
finish = noop;
// Mark this request as finished.
request.finished = true;
// Clear listeners.
window[callbackName] = noop;
script.onerror = null;
// Clear timeout.
if (timeoutId !== null) {
clearTimeout(timeoutId);
timeoutId = null;
}
// Fire callbacks.
fireCallbacks(code, response);
};
// Define the callback function.
window[callbackName] = function (responseJSON) {
request.responseJSON = responseJSON;
if (isFunction(isResponseOk)) {
if (isResponseOk(requestType, response)) {
finish(null);
} else {
finish(ERR_RESPONSE);
}
} else {
finish(null);
}
};
// Catch the error.
script.onerror = function () {
finish(ERR_NETWORK);
};
/**
* Cancel the request.
*/
request.cancel = function () {
finish(ERR_CANCELLED);
};
// Add timeout listener
if (!isNaN(timeout) && timeout > 0) {
timeoutId = setTimeout(function () {
finish(ERR_TIMEOUT);
}, timeout);
}
}
module.exports = addEventListeners;
},{"25":25,"29":29,"33":33,"38":38,"7":7}],19:[function(require,module,exports){
/**
* The function to create JSONP callback name.
*
* @param {RequestOptions} options The request options.
* @returns {string} Returns the callback name.
*/
function buildCalllbackName(options) {
var callbackName;
do {
callbackName = options.jsonpCallbackName.call(null, options);
} while (callbackName in window);
window[callbackName] = null;
return callbackName;
}
module.exports = buildCalllbackName;
},{}],20:[function(require,module,exports){
var buildURL = require(23);
/**
* Build the JSONP script src.
*
* @param {RequestOptions} options The request opitons.
* @param {string} callbackName The callback name of the JSONP.
* @return {string} Returns the script src.
*/
function buildScriptSrc(options, callbackName) {
var query = options.query;
var key = options.jsonp;
var url;
if (!query) {
query = {};
options.query = query;
}
query[key] = callbackName;
url = buildURL(options);
return url;
}
module.exports = buildScriptSrc;
},{"23":23}],21:[function(require,module,exports){
/**
* The function to handle `options.cors` setting when sending JSONP requests. If `options.cors` is `true`, the
* `crossorigin` attribute of the `script` element we using is set to `use-credentials`.
*
* @param {HTMLScriptElement} script The script element.
* @param {RequestOptions} options The request options.
*/
function handleScriptCors(script, options) {
if (options.cors) {
script.setAttribute('crossorigin', 'use-credentials');
}
}
module.exports = handleScriptCors;
},{}],22:[function(require,module,exports){
var isPlainObject = require(39);
var isFunction = require(38);
var hasOwn = require(31);
/**
* The function to add custom parsers to the instance of `Response` or `ResponseError`.
*
* @param {Response|ResponseError} target The target to add the custome parsers.
* @param {RequestOptions} options The request options.
* @param {string} optionName The option name the parsers container.
*/
function addCustomParser(target, options, optionName) {
var parsers = options[optionName];
var name;
var parser;
if (isPlainObject(parsers)) {
for (name in parsers) {
if (hasOwn.call(parsers, name)) {
parser = parsers[name];
if (isFunction(parser)) {
if (name in target) {
throw new Error('"' + name + '" cannot be a name of parser');
}
target[name] = parser;
}
}
}
}
}
module.exports = addCustomParser;
},{"31":31,"38":38,"39":39}],23:[function(require,module,exports){
var isFunction = require(38);
var isAbsoluteURL = require(36);
var isPlainObject = require(39);
/**
* The function to build request url.
*
* 1. Add baseURL if needed.
* 2. Compile url if needed.
* 3. Compile query string if needed.
*
* @param {RequestOptions} options The request options.
* @returns {string} Returns the final url string.
*/
function buildURL(options) {
var url = options.url + '';
var baseURL = options.baseURL;
var model = options.model;
var query = options.query;
var compileURL = options.compileURL;
var encodeQueryString = options.encodeQueryString;
var array;
// If the url is not absolute url and the baseURL is defined,
// prepend the baseURL to the url.
if (!isAbsoluteURL(url)) {
if (typeof baseURL === 'string') {
url = baseURL + url;
}
}
// Compile the url if needed.
if (isPlainObject(model) && isFunction(compileURL)) {
url = compileURL(url, model, options);
}
// Compile the query string.
if (isPlainObject(query) && isFunction(encodeQueryString)) {
query = encodeQueryString(query, options);
array = url.split('#'); // There may be hash string in the url.
url = array[0];
if (url.indexOf('?') > -1) {
if (url.charAt(url.length - 1) === '&') {
url = url + query;
} else {
url = url + '&' + query;
}
} else {
url = url + '?' + query;
}
array[0] = url;
url = array.join('#');
}
return url;
}
module.exports = buildURL;
},{"36":36,"38":38,"39":39}],24:[function(require,module,exports){
var isFunction = require(38);
/**
* The function to call `options.onRequestCreated` callback.
*
* @param {RequestOptions} options The request options.
* @param {HttpRequest|JSONPRequest} request The request instance.
*/
function callRequestCreatedCallback(options, request) {
var onRequestCreated = options.onRequestCreated;
if (isFunction(onRequestCreated)) {
onRequestCreated(request);
}
}
module.exports = callRequestCreatedCallback;
},{"38":38}],25:[function(require,module,exports){
exports.ERR_ABORTED = 'ERR_ABORTED';
exports.ERR_RESPONSE = 'ERR_RESPONSE';
exports.ERR_CANCELLED = 'ERR_CANCELLED';
exports.ERR_NETWORK = 'ERR_NETWORK';
exports.ERR_TIMEOUT = 'ERR_TIMEOUT';
exports.HTTP_REQUEST = 'HTTP_REQUEST';
exports.JSONP_REQUEST = 'JSONP_REQUEST';
},{}],26:[function(require,module,exports){
var CancelController = require(1);
/**
* Create a new instance of `CancelController`.
*
* @returns {CancelController} Returns an new instance of `CancelController`.
*/
var createCancelController = function () {
return new CancelController();
};
module.exports = createCancelController;
},{"1":1}],27:[function(require,module,exports){
var QS = require(43);
var constants = require(25);
var template = require(34);
var uuid = require(35);
var HTTP_REQUEST = constants.HTTP_REQUEST;
/**
* Create a new default request options.
*
* @returns {RequestOptions} Returns a new default request opitons.
*/
function createDefaultOptions() {
/*eslint no-unused-vars: ["error", { "args": "none" }]*/
/**
* @type {RequestOptions}
*/
var options = {
method: 'GET',
baseURL: null,
url: null,
model: null,
query: null,
headers: null,
body: null,
timeout: 0,
cors: false,
noCache: false,
noCacheHeaders: {
'Pragma': 'no-cache',
'Cache-Control': 'no-cache, no-store, must-revalidate'
},
jsonp: 'callback',
settings: {},
controller: null,
requestFunctionName: null,
requestType: null,
xhrProps: null,
username: null,
password: null,
httpRequestBodyProcessor: {
raw: {
priority: 0,
headers: null,
processor: null,
},
form: {
priority: 1,
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
processor: function (data, options) {
return QS.encode(data);
}
},
json: {
priority: 2,
headers: {
'Content-Type': 'application/json; charset=UTF-8'