/* exported AjaxSender */
/*eslint-disable */
if (typeof window === 'undefined') {
/**
* NodeJS dependencies
*/
XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
}
/*eslint-enable */
/**
* Callback function used for the XHR events
*
* @callback eventCallback
* @param {Object} response The XHR response
*/
/**
* AjaxSender Class used to handle ajax calls
*/
class AjaxSender {
/**
* Creates an instance of AjaxSender
* @param {String} url URL to send the call to
* @param {Object} [parameters] Request parameters
* @param {String} [parameters.method=GET] Request method
* @param {Object|FormData} [parameters.data] Request data
* @param {String} [parameters.responseType=json] Request response type
* @param {Object.<String, String>} [parameters.headers] Request headers
* @param {eventCallback} [parameters.progress] Callback for the progress event
* @param {eventCallback} [parameters.load] Callback for the load event
* @param {eventCallback} [parameters.error] Callback for the error event
* @param {eventCallback} [parameters.uploadProgress] Callback for the upload progress event
* @param {eventCallback} [parameters.uploadLoad] Callback for the upload progress event
* @param {Boolean} [parameters.wait] Don't send the request right away (enables the use of asPromise)
*/
constructor(url, parameters) {
this.url = url;
/**
* The request corresponding XMLHttpRequest
* @type {XMLHttpRequest}
*/
this.xhr = new XMLHttpRequest();
// Default values
this._parameters = {
method: parameters.method || 'GET',
data: parameters.data || {},
responseType: parameters.responseType || 'json',
headers: parameters.headers || {},
progress: parameters.progress,
load: parameters.load,
error: parameters.error,
uploadProgress: parameters.uploadProgress,
uploadLoad: parameters.uploadLoad
};
if(!this._parameters.wait){
this.send();
}
}
/**
* Handle callback attachment
* @return {Promise} Resolved when data is loaded
* @private
*/
_handleCallbacks() {
/**
* DOWNLOAD CALLBACKS
*/
if (this._parameters.progress) {
this.xhr.addEventListener('progress', () => {
Reflect.apply(this._parameters.progress, null, [this.xhr.response]);
});
}
const promise = new Promise((resolve, reject) => {
if (this._parameters.load || this._returnPromise) {
this.xhr.addEventListener('load', () => {
if (this.xhr.status == 200) {
resolve(this.xhr.response);
if(this._parameters.load) Reflect.apply(this._parameters.load, null, [this.xhr.response]);
} else {
if (this._parameters.error) {
Reflect.apply(this._parameters.error, null, [this.xhr]);
} else {
console.log(this.xhr);
}
reject(this.xhr);
}
});
}
});
this.xhr.addEventListener('error', this._parameters.error ? () => {
Reflect.apply(this._parameters.error, null, [this.xhr]);
} : () => {
console.log(this.xhr);
});
/**
* UPLOAD CALLBACKS
*/
if (this._parameters.uploadProgress) {
if(this.xhr.upload){
this.xhr.upload.addEventListener('progress', () => {
Reflect.apply(this._parameters.uploadProgress, null, [this.xhr.response]);
});
}else{
console.log('Upload callbacks are unavailable in a NodeJS environment.');
}
}
if (this._parameters.uploadLoad) {
if(this.xhr.upload){
this.xhr.upload.addEventListener('load', () => {
Reflect.apply(this._parameters.uploadLoad, null, [this.xhr.response]);
});
}else{
console.log('Upload callbacks are unavailable in a NodeJS environment.');
}
}
if(this.xhr.upload){
this.xhr.upload.addEventListener('error', this._parameters.error ? () => {
Reflect.apply(this._parameters.error, null, [this.xhr]);
} : () => {
console.log(this.xhr);
});
}
return promise;
}
/**
* Encode an object for an URL use
* @param {Object} object Object to transform
* @param {String} prefix Parameter needed for the recursion
* @private
*/
_objectToURL(object, prefix) {
const str = [];
for (const p in object) {
if (Reflect.ownKeys(object).includes(p)) {
const k = prefix ? prefix + '[' + p + ']' : p,
v = object[p];
str.push(v !== null && typeof v === 'object' ? this._objectToURL(v, k) : encodeURIComponent(k) + '=' + encodeURIComponent(v));
}
}
return str.join('&');
}
/**
* Sets the .send() return type to a Promise
* @returns {AjaxSender} The current AjaxSender
*/
asPromise() {
this._returnPromise = true;
return this;
}
/**
* Stops any outgoing request
* @returns {AjaxSender} The current AjaxSender
*/
stop() {
this.xhr.abort();
return this;
}
/**
* Send the request (if wait == true in init)
* @returns {AjaxSender|Promise} The current AjaxSender OR a Promise
*/
send() {
const loadPromise = this._handleCallbacks();
/**
* Response type
*/
this.xhr.responseType = this._parameters.responseType;
/**
* Request method
*/
if (this._parameters.method == 'GET') {
const urlObject = new URL(this.url);
urlObject.search += (urlObject.search.length && Object.keys(this._parameters.data).length ? '&' : '') + this._objectToURL(this._parameters.data);
this.xhr.open('GET', urlObject.href);
} else {
this.xhr.open(this._parameters.method, this.url);
}
/**
* Request headers
*/
Object.entries(this._parameters.headers).forEach(([header, value]) => this.xhr.setRequestHeader(header, value));
/**
* Data handling
*/
if (this._parameters.method == 'GET') {
this.xhr.send();
} else {
if (typeof window !== 'undefined' && this._parameters.data instanceof FormData) {
if(![...this._parameters.data.values()].find(e => e instanceof File)){
this._parameters.data.processData = false;
this._parameters.data.contentType = false;
}
this.xhr.send(this._parameters.data);
} else {
this.xhr.send(JSON.stringify(this._parameters.data));
}
}
return this._returnPromise ? loadPromise : this;
}
}
// eslint-disable-next-line no-undef
if (typeof window === 'undefined') module.exports = AjaxSender;