From e01e4842593d7093c6b1d9d1bc43359e20899c57 Mon Sep 17 00:00:00 2001 From: djmaze Date: Tue, 21 Jul 2020 22:22:58 +0200 Subject: [PATCH] Ajax use window.fetch() instead of $.ajax (not perfect yet). This allows us to use jquery.slim (and cash-dom in the future) --- dev/Common/Enums.js | 2 + dev/Promises/AbstractAjax.js | 150 ++++++++++++++++------------------ dev/Remote/AbstractAjax.js | 154 +++++++++++++++++++---------------- 3 files changed, 154 insertions(+), 152 deletions(-) diff --git a/dev/Common/Enums.js b/dev/Common/Enums.js index e0d146366..e009a0fe0 100644 --- a/dev/Common/Enums.js +++ b/dev/Common/Enums.js @@ -545,4 +545,6 @@ export const Notification = { 'UnknownNotification': 999, 'UnknownError': 999 + + ,getKeyByValue: function(v) { return Object.keys(this).find(key => this[key] === v); } }; diff --git a/dev/Promises/AbstractAjax.js b/dev/Promises/AbstractAjax.js index ed92a6fbd..9d858308e 100644 --- a/dev/Promises/AbstractAjax.js +++ b/dev/Promises/AbstractAjax.js @@ -1,12 +1,11 @@ import window from 'window'; -import $ from '$'; import { ajax } from 'Common/Links'; -import { microtime, isUnd, isNormal, pString, pInt } from 'Common/Utils'; +import { isUnd, isNormal, pString } from 'Common/Utils'; import { DEFAULT_AJAX_TIMEOUT, TOKEN_ERROR_LIMIT, AJAX_ERROR_LIMIT } from 'Common/Consts'; -import { StorageResultType, Notification } from 'Common/Enums'; +import { Notification } from 'Common/Enums'; import { data as GlobalsData } from 'Common/Globals'; -import * as Plugins from 'Common/Plugins'; +import { runHook } from 'Common/Plugins'; import * as Settings from 'Storage/Settings'; import { AbstractBasicPromises } from 'Promises/AbstractBasic'; @@ -27,7 +26,7 @@ class AbstractAjaxPromises extends AbstractBasicPromises { abort(sAction, bClearOnly) { if (this.oRequests[sAction]) { if (!bClearOnly && this.oRequests[sAction].abort) { - this.oRequests[sAction].__aborted__ = true; +// this.oRequests[sAction].__aborted__ = true; this.oRequests[sAction].abort(); } @@ -39,44 +38,62 @@ class AbstractAjaxPromises extends AbstractBasicPromises { } ajaxRequest(action, isPost, timeOut, params, additionalGetString, fTrigger) { - return new window.Promise((resolve, reject) => { - const start = microtime(); - timeOut = isNormal(timeOut) ? timeOut : DEFAULT_AJAX_TIMEOUT; - additionalGetString = isUnd(additionalGetString) ? '' : pString(additionalGetString); + additionalGetString = isUnd(additionalGetString) ? '' : pString(additionalGetString); - if (isPost) { - params.XToken = Settings.appSettingsGet('token'); - } + let init = { + mode: 'same-origin', + cache: 'no-cache', + redirect: 'error', + referrerPolicy: 'no-referrer', + credentials: 'same-origin' + }; + if (isPost) { + init.method = 'POST'; + init.headers = { +// 'Content-Type': 'application/json' + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }; + params.XToken = Settings.appSettingsGet('token'); +// init.body = JSON.stringify(params); + const formData = new window.FormData(); + Object.keys(params).forEach(key => { + formData.append(key, params[key]) + }); + init.body = (new URLSearchParams(formData)).toString(); + } - Plugins.runHook('ajax-default-request', [action, params, additionalGetString]); + runHook('ajax-default-request', [action, params, additionalGetString]); - this.setTrigger(fTrigger, true); + this.setTrigger(fTrigger, true); - const oH = $.ajax({ - type: isPost ? 'POST' : 'GET', - url: ajax(additionalGetString), - async: true, - dataType: 'json', - data: isPost ? params || {} : {}, - timeout: timeOut, - global: true - }).always((data, textStatus) => { - let isCached = false, - errorData = null; + if (window.AbortController) { + this.abort(action); + const controller = new window.AbortController(); + setTimeout(() => controller.abort(), isNormal(timeOut) ? timeOut : DEFAULT_AJAX_TIMEOUT); + init.signal = controller.signal; + this.oRequests[action] = controller; + } + return window.fetch(ajax(additionalGetString), init) + .then(response => response.json()) + .then(data => { + this.abort(action, true); + + if (!data) { + return Promise.reject(Notification.AjaxParse); + } + + if (data.UpdateToken && GlobalsData.__APP__ && GlobalsData.__APP__.setClientSideToken) { + GlobalsData.__APP__.setClientSideToken(data.UpdateToken); + } + +/* + let isCached = false, type = ''; if (data && data.Time) { isCached = pInt(data.Time) > microtime() - start; } - - if (data && data.UpdateToken) { - if (GlobalsData.__APP__ && GlobalsData.__APP__.setClientSideToken) { - GlobalsData.__APP__.setClientSideToken(data.UpdateToken); - } - } - // backward capability - let type = ''; switch (true) { case 'success' === textStatus && data && data.Result && action === data.Action: type = StorageResultType.Success; @@ -88,46 +105,17 @@ class AbstractAjaxPromises extends AbstractBasicPromises { type = StorageResultType.Error; break; } - - Plugins.runHook('ajax-default-response', [ + runHook('ajax-default-response', [ action, StorageResultType.Success === type ? data : null, type, isCached, params ]); - - if ('success' === textStatus) { - if (data && data.Result && action === data.Action) { - data.__cached__ = isCached; - resolve(data); - } else if (data && data.Action) { - errorData = data; - reject(data.ErrorCode ? data.ErrorCode : Notification.AjaxFalse); - } else { - errorData = data; - reject(Notification.AjaxParse); - } - } else if ('timeout' === textStatus) { - errorData = data; - reject(Notification.AjaxTimeout); - } else if ('abort' === textStatus) { - if (!data || !data.__aborted__) { - reject(Notification.AjaxAbort); - } - } else { - errorData = data; - reject(Notification.AjaxParse); - } - - if (this.oRequests[action]) { - this.oRequests[action] = null; - delete this.oRequests[action]; - } - +*/ this.setTrigger(fTrigger, false); - if (errorData) { + if (!data.Result || action !== data.Action) { if ([ Notification.AuthError, Notification.AccessError, @@ -137,13 +125,13 @@ class AbstractAjaxPromises extends AbstractBasicPromises { Notification.MailServerError, Notification.UnknownNotification, Notification.UnknownError - ].includes(errorData.ErrorCode) + ].includes(data.ErrorCode) ) { - GlobalsData.iAjaxErrorCount += 1; + ++GlobalsData.iAjaxErrorCount; } - if (Notification.InvalidToken === errorData.ErrorCode) { - GlobalsData.iTokenErrorCount += 1; + if (Notification.InvalidToken === data.ErrorCode) { + ++GlobalsData.iTokenErrorCount; } if (TOKEN_ERROR_LIMIT < GlobalsData.iTokenErrorCount) { @@ -152,27 +140,27 @@ class AbstractAjaxPromises extends AbstractBasicPromises { } } - if (errorData.ClearAuth || errorData.Logout || AJAX_ERROR_LIMIT < GlobalsData.iAjaxErrorCount) { + if (data.ClearAuth || data.Logout || AJAX_ERROR_LIMIT < GlobalsData.iAjaxErrorCount) { if (GlobalsData.__APP__ && GlobalsData.__APP__.clearClientSideToken) { GlobalsData.__APP__.clearClientSideToken(); } - if (GlobalsData.__APP__ && !errorData.ClearAuth && GlobalsData.__APP__.loginAndLogoutReload) { + if (GlobalsData.__APP__ && !data.ClearAuth && GlobalsData.__APP__.loginAndLogoutReload) { GlobalsData.__APP__.loginAndLogoutReload(false, true); } } + + return Promise.reject(data.ErrorCode ? data.ErrorCode : Notification.AjaxFalse); } + + return data; + }).catch(err => { +window.console.log('AbstractAjaxPromises ' + action + ' request failed:', err, Notification.getKeyByValue(err)); + if (err.name == 'AbortError') { // handle abort() + return Promise.reject(Notification.AjaxAbort); + } + return Promise.reject(err); }); - - if (oH) { - if (this.oRequests[action]) { - this.oRequests[action] = null; - delete this.oRequests[action]; - } - - this.oRequests[action] = oH; - } - }); } getRequest(sAction, fTrigger, sAdditionalGetString, iTimeOut) { diff --git a/dev/Remote/AbstractAjax.js b/dev/Remote/AbstractAjax.js index f7316544d..5c95ba2a7 100644 --- a/dev/Remote/AbstractAjax.js +++ b/dev/Remote/AbstractAjax.js @@ -1,6 +1,4 @@ import window from 'window'; -import _ from '_'; -import $ from '$'; import { TOKEN_ERROR_LIMIT, AJAX_ERROR_LIMIT, DEFAULT_AJAX_TIMEOUT } from 'Common/Consts'; import { StorageResultType, Notification } from 'Common/Enums'; @@ -16,6 +14,20 @@ class AbstractAjaxRemote { this.oRequests = {}; } + abort(sAction, bClearOnly) { + if (this.oRequests[sAction]) { + if (!bClearOnly && this.oRequests[sAction].abort) { +// this.oRequests[sAction].__aborted = true; + this.oRequests[sAction].abort(); + } + + this.oRequests[sAction] = null; + delete this.oRequests[sAction]; + } + + return this; + } + /** * @param {?Function} fCallback * @param {string} sRequestAction @@ -31,6 +43,10 @@ class AbstractAjaxRemote { } if (StorageResultType.Success === sType && oData && !oData.Result) { + const err = oData ? oData.ErrorCode : null; +if (err) { + window.console.log('AbstractAjaxRemote ' + sRequestAction + ' request failed:', err, Notification.getKeyByValue(err)); +} if ( oData && [ Notification.AuthError, @@ -41,13 +57,13 @@ class AbstractAjaxRemote { Notification.MailServerError, Notification.UnknownNotification, Notification.UnknownError - ].includes(oData.ErrorCode) + ].includes(err) ) { - GlobalsData.iAjaxErrorCount += 1; + ++GlobalsData.iAjaxErrorCount; } - if (oData && Notification.InvalidToken === oData.ErrorCode) { - GlobalsData.iTokenErrorCount += 1; + if (oData && Notification.InvalidToken === err) { + ++GlobalsData.iTokenErrorCount; } if (TOKEN_ERROR_LIMIT < GlobalsData.iTokenErrorCount) { @@ -102,7 +118,7 @@ class AbstractAjaxRemote { } if (StorageResultType.Error === sType) { - _.delay(fCall, 300); + setTimeout(fCall, 300); } else { fCall(); } @@ -117,80 +133,76 @@ class AbstractAjaxRemote { * @returns {jQuery.jqXHR} */ ajaxRequest(fResultCallback, params, iTimeOut = 20000, sGetAdd = '', abortActions = []) { - const isPost = '' === sGetAdd, - headers = {}, - start = new window.Date().getTime(); - - let action = ''; - params = params || {}; - action = params.Action || ''; + const isPost = '' === sGetAdd, + start = new window.Date().getTime(), + action = params.Action || ''; - if (action && 0 < abortActions.length) { - _.each(abortActions, (actionToAbort) => { - if (this.oRequests[actionToAbort]) { - this.oRequests[actionToAbort].__aborted = true; - if (this.oRequests[actionToAbort].abort) { - this.oRequests[actionToAbort].abort(); - } - this.oRequests[actionToAbort] = null; - } - }); + if (action && abortActions) { + abortActions.forEach(actionToAbort => this.abort(actionToAbort)); } + let init = { + mode: 'same-origin', + cache: 'no-cache', + redirect: 'error', + referrerPolicy: 'no-referrer', + credentials: 'same-origin' + }; if (isPost) { + init.method = 'POST'; + init.headers = { +// 'Content-Type': 'application/json' + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }; params.XToken = Settings.appSettingsGet('token'); +// init.body = JSON.stringify(params); + const formData = new window.FormData(); + Object.keys(params).forEach(key => { + formData.append(key, params[key]) + }); + init.body = (new URLSearchParams(formData)).toString(); } - const oDefAjax = $.ajax({ - type: isPost ? 'POST' : 'GET', - url: ajax(sGetAdd), - async: true, - dataType: 'json', - data: isPost ? params : {}, - headers: headers, - timeout: iTimeOut, - global: true - }); - - oDefAjax.always((oData, sType) => { - let cached = false; - if (oData && oData.Time) { - cached = pInt(oData.Time) > new window.Date().getTime() - start; - } - - if (oData && oData.UpdateToken) { - if (GlobalsData.__APP__ && GlobalsData.__APP__.setClientSideToken) { - GlobalsData.__APP__.setClientSideToken(oData.UpdateToken); - } - } - - if (action && this.oRequests[action]) { - if (this.oRequests[action].__aborted) { - sType = 'abort'; - } - - this.oRequests[action] = null; - } - - this.defaultResponse(fResultCallback, action, sType, oData, cached, params); - }); - - if (action && 0 < abortActions.length && abortActions.includes(action)) { - if (this.oRequests[action]) { - this.oRequests[action].__aborted = true; - if (this.oRequests[action].abort) { - this.oRequests[action].abort(); - } - this.oRequests[action] = null; - } - - this.oRequests[action] = oDefAjax; + if (window.AbortController) { + this.abort(action); + const controller = new window.AbortController(); + setTimeout(() => controller.abort(), iTimeOut); + init.signal = controller.signal; + this.oRequests[action] = controller; } - // eslint-disable-next-line no-console - oDefAjax.catch(console.log); - return oDefAjax; + window.fetch(ajax(sGetAdd), init) + .then(response => response.json()) + .then(oData => { + let cached = false; + if (oData && oData.Time) { + cached = pInt(oData.Time) > new window.Date().getTime() - start; + } + + if (oData && oData.UpdateToken) { + if (GlobalsData.__APP__ && GlobalsData.__APP__.setClientSideToken) { + GlobalsData.__APP__.setClientSideToken(oData.UpdateToken); + } + } + + let sType = 'success'; + if (action && this.oRequests[action]) { + if (this.oRequests[action].__aborted) { + sType = 'abort'; + } + + this.oRequests[action] = null; + } + + this.defaultResponse(fResultCallback, action, sType, oData, cached, params); + }).catch(err => { +window.console.log('AbstractAjaxRemote ' + action + ' request failed:', err, Notification.getKeyByValue(err)); + if (err.name == 'AbortError') { // handle abort() + return Promise.reject(Notification.AjaxAbort); + } + return Promise.reject(err); + }); } /**