(function (root, factory) { // Browser globals root.Fetch = factory(); }(typeof self !== 'undefined' ? self : this, function () { function post(options) { let url = options.url; let method = options.method.toUpperCase(); if (!['POST'].includes(method)) { throw new Error('HTTP method is not supported.'); } let responseType = options.responseType || 'text'; if (!['text', 'json'].includes(responseType)) { throw new Error('Response type is not supported.'); } let xhr = new XMLHttpRequest(); xhr.responseType = responseType; xhr.open(method, url, true); // xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.onabort = function () { options.complete && options.complete(); options.error && options.error('ABORT'); }; xhr.ontimeout = function () { options.complete && options.complete(); options.error && options.error('TIMEOUT'); }; xhr.onerror = function () { options.complete && options.complete(); options.error && options.error('ERROR'); }; xhr.onload = function () { options.complete && options.complete(); let status = xhr.status; if (status >= 200 && status < 400) { if (xhr.responseType == 'json' || xhr.responseType == 'text') { try { options.success && options.success(this.response); } catch (e) { options.error && options.error(e.name, e.message); } } } else { options.error && options.error('ERROR', xhr.status + ' ' + xhr.statusText); } }; let formData = null; if (options.data instanceof FormData) { formData = options.data; } else if (options.data instanceof HTMLFormElement) { formData = new FormData(options.data); } else { formData = new FormData(); for (let k in options.data) { formData.append(k, options.data[k]); } formData.append('csrfToken', __DATA__.csrfToken); } options.before && options.before(); xhr.send(formData); } function postProgress(form, options) { let url = form.action; let method = form.method.toUpperCase(); let responseType = options.responseType || 'text'; if (!['text', 'json'].includes(responseType)) { throw new Error('Response type is not supported.'); } let xhr = new XMLHttpRequest(); xhr.responseType = responseType; xhr.open(method, url, true); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); if (typeof options.uploadProgress !== 'undefined') { xhr.upload.addEventListener('progress', options.uploadProgress); } xhr.onabort = function () { options.complete && options.complete(); options.error && options.error('ABORT'); }; xhr.ontimeout = function () { options.complete && options.complete(); options.error && options.error('TIMEOUT'); }; xhr.onerror = function () { options.complete && options.complete(); options.error && options.error('ERROR'); }; xhr.onload = function () { options.complete && options.complete(); let status = this.status; if (status >= 200 && status < 400) { if (xhr.responseType == 'json' || xhr.responseType == 'text') { try { options.success && options.success(xhr.response); } catch (e) { options.error && options.error(e.name, e.message); } } } else { options.error && options.error('HTTP_ERROR'); } }; xhr.send(new FormData(form)); } function successCallback(response) { let status = response.status; let message = response.message; if (status == 1) { window.location = message; } else if (status == 2) { Modal.show({ title: 'An error encountered', message: message, closeText: 'Dismiss', focus: true, hideConfirmButton: true }); } else if (status === 'modal_info') { let data = response.data; Modal.show({ hideCloseButton: true, title: data.title, message: data.message, confirmText: data.confirmText, focus: true, onConfirm: function () { if (data.onConfirm.action == 'redirect') { window.location = data.onConfirm.url; } else { alert('Unknow actions'); } }, }); } else if (status == 4) { alert(message); } else if (status === 'toast') { MyToast.show(message, { delay: 4000 }); } } function errorCallback(name, message) { console.error(name, message); Modal.show({ title: 'An error encountered', message: message, closeText: 'Dismiss', focus: true, hideConfirmButton: true }); } MyEvent.addEventListener('submit', '.met-js-form', function (e) { e.preventDefault(); let form = e.target; let successCb = form.getAttribute('data-onsuccess'); let errorCb = form.getAttribute('data-onerror'); let beforeCb = form.getAttribute('data-onbefore'); let completeCb = form.getAttribute('data-oncomplete'); let loadingIndicator = new FormUtils.LoadingIndicator(form); post({ url: form.getAttribute('action'), method: form.method, responseType: 'json', data: form, success: function (response) { if (successCb) { window[successCb](response); } else { successCallback(response); } }, error: function (code, message) { if (errorCb) { window[errorCb](code, message); } else { errorCallback(code, message); } }, before: function () { loadingIndicator.onBefore(); if (beforeCb) { window[beforeCb](); } }, complete: function () { loadingIndicator.onComplete(); if (completeCb) { window[completeCb](); } } }); }); MyEvent.addEventListener('submit', '.met-js-form-with-recaptcha-v2', function (e) { e.preventDefault(); let form = e.target; const resetRecaptcha = function () { grecaptcha.reset(); console.log('Recaptcha input has been reset.'); }; post({ url: form.action, method: form.method, responseType: 'json', data: form, success: function (res) { successCallback(res); if (res.status != 1) { grecaptcha.reset(); resetRecaptcha(); } }, error: function (name, message) { errorCallback(name, message); resetRecaptcha(); } }); }); MyEvent.addEventListener('submit', '.met-js-form-with-recaptcha-v3', function (e) { e.preventDefault(); let form = e.target; grecaptcha.ready(function () { grecaptcha.execute(__DATA__.recaptchaV3SiteKey, { action: 'submit' }).then(function (token) { let formData = new FormData(form); formData.append('g-recaptcha-response', token); post({ url: form.action, method: form.method, responseType: 'json', data: formData, success: successCallback, error: errorCallback }); }); }); }); MyEvent.addEventListener('click', '.met-js-link', function (e) { e.preventDefault(); let link = e.target; post({ url: link.dataset.url, method: 'post', responseType: 'json', data: { ts: Date.now() }, success: successCallback, error: errorCallback }); }); return { post: post, postProgress: postProgress, errorCallback: errorCallback, successCallback: successCallback } }));