1 /** 2 * @file AJAX requests 3 * 4 * @author Dominik Kocuj 5 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License v2 or later 6 * @copyright Copyright (c) 2016-2018 kocuj.pl 7 */ 8 9 (function() {})(); // empty function for correct minify with comments 10 //'use strict'; // for jshint uncomment this and comment line above 11 12 /* jshint strict: true */ 13 /* jshint -W034 */ 14 15 /* global document */ 16 /* global jQuery */ 17 /* global window */ 18 19 /* global ajaxurl */ 20 21 /* global kocujILV12aHelper */ 22 23 /* global kocujILV12aAllJsAjaxVals */ 24 25 /** 26 * AJAX prototype constructor 27 * 28 * @constructs 29 * @namespace kocujILV12aCAllJsAjax 30 * @public 31 * @return {void} 32 */ 33 function kocujILV12aCAllJsAjax() { 34 'use strict'; 35 /* jshint validthis: true */ 36 // get this object 37 var self = this; 38 // initialize objects 39 self._objHelper = kocujILV12aHelper; 40 // get current script filename 41 self._thisFilename = document.scripts[document.scripts.length-1].src; 42 // get settings 43 var vals = kocujILV12aAllJsAjaxVals; 44 if (vals.throwErrors === '1') { 45 self._valsThrowErrors = true; 46 } else { 47 self._valsThrowErrors = false; 48 } 49 self._valsPrefix = vals.prefix; 50 self._valsSecurity = vals.security; 51 if (vals.canUseProxy === '1') { 52 self._valsCanUseProxy = true; 53 } else { 54 self._valsCanUseProxy = false; 55 } 56 self._valsAjaxUrl = vals.ajaxUrl; 57 } 58 59 /** 60 * AJAX prototype 61 * 62 * @namespace kocujILV12aCAllJsAjax 63 * @public 64 */ 65 kocujILV12aCAllJsAjax.prototype = { 66 /** 67 * Object kocujILV12aHelper 68 * 69 * @private 70 * @type {Object} 71 */ 72 _objHelper : null, 73 74 /** 75 * Current script filename 76 * 77 * @private 78 * @type {string} 79 */ 80 _thisFilename : '', 81 82 /** 83 * Projects list 84 * 85 * @private 86 * @type {Array} 87 */ 88 _prj : [], 89 90 /** 91 * Script settings - throw errors (true) or not (false) 92 * 93 * @private 94 * @type {string} 95 */ 96 _valsThrowErrors : false, 97 98 /** 99 * Script settings - prefix 100 * 101 * @private 102 * @type {string} 103 */ 104 _valsPrefix : '', 105 106 /** 107 * Script settings - security string 108 * 109 * @private 110 * @type {string} 111 */ 112 _valsSecurity : '', 113 114 /** 115 * Script settings - proxy can be used (true) or not (false) 116 * 117 * @private 118 * @type {boolean} 119 */ 120 _valsCanUseProxy : true, 121 122 /** 123 * Script settings - AJAX URL 124 * 125 * @private 126 * @type {string} 127 */ 128 _valsAjaxUrl : '', 129 130 /** 131 * Add project 132 * 133 * @public 134 * @param {string} projectId Project identifier 135 * @return {void} 136 * @throws {kocujILV12aCException} kocujILV12aExceptionCode.PROJECT_ALREADY_EXISTS if project identifier entered in projectId already exists 137 */ 138 addProject : function(projectId) { 139 'use strict'; 140 // parse arguments 141 var args = this._checkAddProject(projectId); 142 // add project 143 if (this._prj['prj_' + args.projectId] === undefined) { 144 this.addProjectIfNotExists(args.projectId); 145 } else { 146 this._throwError('PROJECT_ALREADY_EXISTS', args.projectId); 147 return; 148 } 149 }, 150 151 /** 152 * Add project if not exists 153 * 154 * @public 155 * @param {string} projectId Project identifier 156 * @return {void} 157 */ 158 addProjectIfNotExists : function(projectId) { 159 'use strict'; 160 // parse arguments 161 var args = this._checkAddProject(projectId); 162 // add project 163 if (this._prj['prj_' + args.projectId] === undefined) { 164 this._prj['prj_' + args.projectId] = []; 165 } 166 }, 167 168 /** 169 * Send AJAX request with GET method 170 * 171 * @public 172 * @param {string} projectId Project identifier 173 * @param {string} connectionId Connection identifier 174 * @param {string} url URL 175 * @param {string} dataType Data type 176 * @param {Object} [data] Data to send 177 * @param {Object} [callbacks] Callback functions for AJAX request; there are the following callbacks available: error (when there was an error with request), retryWait (when there will be a retring of connection after a few seconds), retryNow (when there will be a retring of connection now), success (when there was a success) 178 * @return {void} 179 */ 180 sendGet : function(projectId, connectionId, url, dataType, data, callbacks) { 181 'use strict'; 182 // send AJAX 183 this.send(projectId, connectionId, url, 'GET', dataType, data, callbacks); 184 }, 185 186 /** 187 * Send AJAX request with POST method 188 * 189 * @public 190 * @param {string} projectId Project identifier 191 * @param {string} connectionId Connection identifier 192 * @param {string} url URL 193 * @param {string} dataType Data type 194 * @param {Object} [data] Data to send 195 * @param {Object} [callbacks] Callback functions for AJAX request; there are the following callbacks available: error (when there was an error with request), retryWait (when there will be a retring of connection after a few seconds), retryNow (when there will be a retring of connection now), success (when there was a success) 196 * @return {void} 197 */ 198 sendPost : function(projectId, connectionId, url, dataType, data, callbacks) { 199 'use strict'; 200 // send AJAX 201 this.send(projectId, connectionId, url, 'POST', dataType, data, callbacks); 202 }, 203 204 /** 205 * Send AJAX request with JSON data 206 * 207 * @public 208 * @param {string} projectId Project identifier 209 * @param {string} connectionId Connection identifier 210 * @param {string} url URL 211 * @param {Object} [data] Data to send 212 * @param {Object} [callbacks] Callback functions for AJAX request; there are the following callbacks available: error (when there was an error with request), retryWait (when there will be a retring of connection after a few seconds), retryNow (when there will be a retring of connection now), success (when there was a success) 213 * @return {void} 214 */ 215 sendJson : function(projectId, connectionId, url, data, callbacks) { 216 'use strict'; 217 // send AJAX 218 this.send(projectId, connectionId, url, 'GET', 'jsonp', data, callbacks); 219 }, 220 221 /** 222 * Send AJAX request 223 * 224 * @public 225 * @param {string} projectId Project identifier 226 * @param {string} connectionId Connection identifier 227 * @param {string} url URL 228 * @param {string} method Request method 229 * @param {string} dataType Data type 230 * @param {Object} [data] Data to send 231 * @param {Object} [callbacks] Callback functions for AJAX request; there are the following callbacks available: error (when there was an error with request), retryWait (when there will be a retring of connection after a few seconds), retryNow (when there will be a retring of connection now), success (when there was a success) 232 * @return {void} 233 */ 234 send : function(projectId, connectionId, url, method, dataType, data, callbacks) { 235 'use strict'; 236 // get this object 237 var self = this; 238 (function($) { 239 // parse arguments 240 projectId = self._parseProjectId(projectId); 241 connectionId = self._objHelper.initString(connectionId); 242 url = self._objHelper.initString(url); 243 if (url === '') { 244 self._throwError('JS_AJAX_EMPTY_URL'); 245 return; 246 } 247 method = self._objHelper.initString(method); 248 if (method === '') { 249 self._throwError('JS_AJAX_EMPTY_METHOD'); 250 return; 251 } 252 dataType = self._objHelper.initString(dataType); 253 if (dataType === '') { 254 self._throwError('JS_AJAX_EMPTY_DATA_TYPE'); 255 return; 256 } 257 data = self._objHelper.initObject(data); 258 if (data === '') { 259 data = {}; 260 } 261 callbacks = self._objHelper.initObject(callbacks); 262 if (callbacks === '') { 263 callbacks = {}; 264 } 265 if (callbacks.error === undefined) { 266 callbacks.error = false; 267 } 268 if (callbacks.retryWait === undefined) { 269 callbacks.retryWait = false; 270 } 271 if (callbacks.retryNow === undefined) { 272 callbacks.retryNow = false; 273 } 274 if (callbacks.success === undefined) { 275 callbacks.success = false; 276 } 277 // optionally clear retries timer 278 if ((typeof self._prj['prj_' + projectId]['con_' + connectionId] !== 'undefined') && (self._prj['prj_' + projectId]['con_' + connectionId].retries > 0)) { 279 self._deactivateTimer(projectId, connectionId); 280 } 281 // initialize connection data 282 if (typeof self._prj['prj_' + projectId]['con_' + connectionId] === 'undefined') { 283 self._prj['prj_' + projectId]['con_' + connectionId] = { 284 timer : null, 285 retries : 0 286 }; 287 } 288 // optionally change AJAX URL from relative to absolute 289 if ((typeof ajaxurl !== 'undefined') && (url === ajaxurl)) { 290 url = self._valsAjaxUrl; 291 } 292 // optionally set proxy 293 var isProxy = false; 294 if ((self._valsCanUseProxy) && (url !== self._valsAjaxUrl)) { 295 // add proxy settings to data 296 data._kocuj_internal_lib_proxy_url = url; 297 data._kocuj_internal_lib_proxy_security = self._valsSecurity; 298 if (typeof data.action !== 'undefined') { 299 data._kocuj_internal_lib_proxy_old_action = data.action; 300 } else { 301 data._kocuj_internal_lib_proxy_old_action = ''; 302 } 303 data.action = self._valsPrefix + '_' + projectId + '__js_ajax'; 304 // change url 305 url = self._valsAjaxUrl; 306 // set proxy flag 307 isProxy = true; 308 } 309 // optionally set timeout if this request is to different server 310 if (url !== self._valsAjaxUrl) { 311 // deactivate timer 312 self._deactivateTimer(projectId, connectionId); 313 // set timer 314 self._prj['prj_' + projectId]['con_' + connectionId].timer = window.setTimeout(function() { 315 self._error(projectId, connectionId, isProxy, callbacks.error, callbacks.retryWait, callbacks.retryNow, null, 'timeout', ''); 316 }, 30000); 317 } 318 // send AJAX request 319 $.ajax({ 320 url : url, 321 async : true, 322 cache : false, 323 data : data, 324 dataType : dataType, 325 error : function(obj, status, err) { 326 self._error(projectId, connectionId, isProxy, callbacks.error, callbacks.retryWait, callbacks.retryNow, new Array( 327 projectId, 328 connectionId, 329 url, 330 method, 331 dataType, 332 data, 333 callbacks 334 ), obj, status, err); 335 }, 336 success : function(data, status, obj) { 337 self._success(projectId, connectionId, isProxy, callbacks.success, data, status, obj); 338 }, 339 timeout : 30000, 340 type : method 341 }); 342 }(jQuery)); 343 }, 344 345 /** 346 * Deactivate timer 347 * 348 * @private 349 * @param {string} projectId Project identifier 350 * @param {string} connectionId Connection identifier 351 * @return {void} 352 */ 353 _deactivateTimer : function(projectId, connectionId) { 354 'use strict'; 355 // clear timer 356 if (this._prj['prj_' + projectId]['con_' + connectionId].timer !== null) { 357 window.clearTimeout(this._prj['prj_' + projectId]['con_' + connectionId].timer); 358 this._prj['prj_' + projectId]['con_' + connectionId].timer = null; 359 } 360 }, 361 362 /** 363 * AJAX loading success 364 * 365 * @private 366 * @param {string} projectId Project identifier 367 * @param {string} connectionId Connection identifier 368 * @param {boolean} isProxy AJAX has been sent through proxy (true) or directly (false) 369 * @param {function} callbackSuccess Callback function for AJAX success 370 * @param {anything} data Data 371 * @param {string} status Text status 372 * @param {Object} obj Request object 373 * @return {void} 374 */ 375 _success : function(projectId, connectionId, isProxy, callbackSuccess, data, status, obj) { 376 'use strict'; 377 // get this object 378 var self = this; 379 (function($) { 380 // parse arguments 381 status = self._objHelper.initString(status); 382 obj = self._objHelper.initObject(obj); 383 if (obj === '') { 384 obj = null; 385 } 386 // clear retries 387 self._prj['prj_' + projectId]['con_' + connectionId].retries = 0; 388 // optionally deactivate AJAX timeout 389 if (isProxy) { 390 self._deactivateTimer(projectId, connectionId); 391 } 392 // optionally execute callback function 393 if (callbackSuccess !== false) { 394 callbackSuccess(projectId, connectionId, data, status, obj); 395 } 396 }(jQuery)); 397 }, 398 399 /** 400 * AJAX loading error 401 * 402 * @private 403 * @param {string} projectId Project identifier 404 * @param {string} connectionId Connection identifier 405 * @param {boolean} isProxy AJAX has been sent through proxy (true) or directly (false) 406 * @param {function} callbackError Callback function for AJAX error 407 * @param {function} callbackRetryWait Callback function for doing something before waiting for AJAX request retry 408 * @param {function} callbackRetryNow Callback function for doing something at the beginning of AJAX request retry 409 * @param {Array} sendMethodArguments Argument for method send() which are used when there is trying to connect again 410 * @param {Object} obj Request object 411 * @param {string} status Text status 412 * @param {string} err Error 413 * @return {void} 414 */ 415 _error : function(projectId, connectionId, isProxy, callbackError, callbackRetryWait, callbackRetryNow, sendMethodArguments, obj, status, err) { 416 'use strict'; 417 // get this object 418 var self = this; 419 (function($) { 420 // parse arguments 421 obj = self._objHelper.initObject(obj); 422 if (obj === '') { 423 obj = null; 424 } 425 status = self._objHelper.initString(status); 426 err = self._objHelper.initString(err); 427 // optionally deactivate AJAX timeout 428 if (isProxy) { 429 self._deactivateTimer(projectId, connectionId); 430 } 431 // optionally retry connection 432 ++self._prj['prj_' + projectId]['con_' + connectionId].retries; 433 if (self._prj['prj_' + projectId]['con_' + connectionId].retries < 3) { 434 if (callbackRetryWait !== false) { 435 callbackRetryWait(projectId, connectionId, self._prj['prj_' + projectId]['con_' + connectionId].retries, obj, status, err); 436 } 437 self._prj['prj_' + projectId]['con_' + connectionId].timer = window.setTimeout(function() { 438 if (callbackRetryNow !== false) { 439 callbackRetryNow(projectId, connectionId, self._prj['prj_' + projectId]['con_' + connectionId].retries, obj, status, err); 440 } 441 self.send(sendMethodArguments[0], sendMethodArguments[1], sendMethodArguments[2], sendMethodArguments[3], sendMethodArguments[4], sendMethodArguments[5], sendMethodArguments[6]); 442 }, 5000); 443 return; 444 } 445 // clear retries 446 self._prj['prj_' + projectId]['con_' + connectionId].retries = 0; 447 // optionally execute callback function 448 if (callbackError !== false) { 449 callbackError(projectId, connectionId, obj, status, err); 450 } 451 }(jQuery)); 452 }, 453 454 /** 455 * Parse project identifier 456 * 457 * @private 458 * @param {string} projectId Project identifier 459 * @return {string} Parsed project identifier 460 * @throws {kocujILV12aCException} kocujILV12aExceptionCode.EMPTY_PROJECT_ID if project identifier entered in projectId is empty 461 * @throws {kocujILV12aCException} kocujILV12aExceptionCode.PROJECT_DOES_NOT_EXIST if project identifier entered in projectId does not exist 462 */ 463 _parseProjectId : function(projectId) { 464 'use strict'; 465 // parse project identifier 466 projectId = this._objHelper.initString(projectId); 467 if (projectId === '') { 468 this._throwError('EMPTY_PROJECT_ID'); 469 return; 470 } 471 // check if project exists 472 if (this._prj['prj_' + projectId] === undefined) { 473 this._throwError('PROJECT_DOES_NOT_EXIST', projectId); 474 return; 475 } 476 // exit 477 return projectId; 478 }, 479 480 /** 481 * Check arguments for adding project 482 * 483 * @private 484 * @param {string} projectId Project identifier 485 * @return {Object} Parsed arguments for adding project 486 * @throws {kocujILV12aCException} kocujILV12aExceptionCode.EMPTY_PROJECT_ID if project identifier entered in projectId is empty 487 */ 488 _checkAddProject : function(projectId) { 489 'use strict'; 490 // parse arguments 491 projectId = this._objHelper.initString(projectId); 492 if (projectId === '') { 493 this._throwError('EMPTY_PROJECT_ID'); 494 return; 495 } 496 // exit 497 return { 498 projectId : projectId 499 }; 500 }, 501 502 /** 503 * Throw an error if debugging is enabled 504 * 505 * @private 506 * @param {string} codeString Error code in string format 507 * @param {string} [param] Parameter for error information 508 * @return {void} 509 */ 510 _throwError : function(codeString, param) { 511 'use strict'; 512 // parse arguments 513 codeString = this._objHelper.initString(codeString); 514 if (codeString === '') { 515 return; 516 } 517 param = this._objHelper.initString(param); 518 // throw an error 519 if (this._valsThrowErrors) { 520 /* jshint evil: true */ 521 eval('throw new kocujILV12aCException(kocujILV12aExceptionCode.' + codeString + ', this._thisFilename, param);'); 522 } 523 } 524 }; 525 526 // initialize 527 var kocujILV12aAllJsAjax = new kocujILV12aCAllJsAjax(); 528