PHP Classes

File: MultiAjax.js

Recommend this page to a friend!
  Classes of V   MultiAjax   MultiAjax.js   Download  
File: MultiAjax.js
Role: Auxiliary data
Content type: text/plain
Description: MultiAjax JavaScript
Class: MultiAjax
Using AJAX in batch mode
Author: By
Last change: changed
Date: 6 years ago
Size: 11,380 bytes
 

Contents

Class file image Download
/** * MultiAjax class provides a convenient way to smart work with AJAX. * It supports timeout, queue, session limits and batch mode. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. */ /** * Serialize object. */ Object.prototype.serialize = function() { var s = '', i = 0; for (var key in this) { if (typeof this[key] != 'function') { s += ':' + key.serialize() + ':' + (this[key] ? this[key].serialize() : 'n'); i++; } } return 'o:' + i + s; } /** * Serialize array. */ Array.prototype.serialize = function() { while (this.length > 0 && typeof this[this.length - 1] == 'undefined') { this.length--; } var s = '', i = 0; for (; i < this.length; i++) { s += ':' + (this[i] ? this[i].serialize() : 'n'); } return 'a:' + i + s; } /** * Serialize number. */ Number.prototype.serialize = function() { return 's:' + this; } /** * String serialization separator. */ String.prototype.SERIALIZATION_SEPARATOR = "__\t__"; /** * Serialize string */ String.prototype.serialize = function() { return String(this) ? 's:' + encodeURIComponent(this.replace(/:/g, String.prototype.SERIALIZATION_SEPARATOR)).replace(/%20/g, '+'):'n'; } /** * Replace all occurrences of the search string with the replacement string. * * @param fromstr Searched string. * @param tostr Replaced string. * * @return Result string */ String.prototype.replaceAll = function(fromstr, tostr) { var s = String(this), i; while ((i = s.indexOf(fromstr)) >= 0) { s = s.replace(fromstr, tostr); } return s; } /** * Unserialize data. * * @param value Serialized string. * * @return Unserialized data. */ String.prototype.unserialize = function() { // Internal function for unserialization. function _unserialize_internal() { switch (arr[idx++]) { case 's': // String return decodeURIComponent(arr[idx++].replace(/\+/g, ' ')).replaceAll(String.prototype.SERIALIZATION_SEPARATOR, ':'); case 'a': // Array var a = []; for (var i = arr[idx++]; i > 0; i--) { a.push(_unserialize_internal()); } return a; case 'o': // Object var obj = new Object(); for (var i = arr[idx++]; i > 0; i--) { obj[_unserialize_internal()] = _unserialize_internal(); } return obj; default: return ''; } } // Divide lexemes of input serialized string. var arr = this.split(':'), idx = 0; return _unserialize_internal(); } /** * ============================================================================= * XMLHttpRequest pool class * ============================================================================= * * @param maxSize Maximal pool size. */ function RequestPool(maxSize) { this.maxSize = maxSize; this.pool = []; } /** * Get XMLHttpRequest from pool. * * @return Return XMLHttpRequest object or null. */ RequestPool.prototype.getRequest = function() { if (this.pool.length >= this.maxSize) { return null; } var rec = null; if (typeof XMLHttpRequest != 'undefined') { rec = new XMLHttpRequest(); } else { var ms = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.4.0', 'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP']; for (var i in ms) { try { rec = ActiveXObject(ms[i]); break; } catch(e) { } } } if (rec) { this.pool.push(rec); } return rec; } /** * Close XMLHttpRequest from pool. * * @param request XMLHttpRequest object. */ RequestPool.prototype.closeRequest = function(request) { for (var i in this.pool) { if (this.pool[i] === request) { this.pool.splice(i, 1); delete request.ontimeout; delete request.onreadystatechange; break; } } } /** * ============================================================================= * Queue class * ============================================================================= * * @param maxSize Maximal queue size. */ function Queue(maxSize) { this.maxSize = maxSize; this.queue = []; } /** * Push new element into the queue. * * @param value New element. * * @return Result 0 if the queue is overflowed, other number if the value * is added. */ Queue.prototype.push = function(value) { if (this.queue.length >= this.maxSize) { return 0; } return this.queue.push(value); } /** * Get element from the queue without deletion. * * @param i Number of element, this parameter is not required, 0 (first element) * by default. * * @return Result first element from the queue or undefined value if queue * is empty. */ Queue.prototype.get = function(i) { if (typeof i != 'number') { i = 0; } if (i < 0 || i >= this.queue.length) { return null; } return this.queue[i]; } /** * Shift element from the queue. * * @param i Number of element, this parameter is not required, 0 (first element) * by default. * * @return Result first element from the queue or undefined value if queue * is empty. */ Queue.prototype.shift = function(i) { if (typeof i != 'number') { i = 0; } if (i < 0 || i >= this.queue.length) { return null; } value = this.queue[i]; this.queue.splice(i, 1); return value; } /** * ============================================================================= * MultiAjax object * ============================================================================= */ var multiajax = { /** * Default request data. It is possible methods: 'GET', 'POST' and 'AUTO' */ _request: { url: '/multiajax', method: 'AUTO', request_parameter: 'q', timeout: 20, method_get_maxsize: 200 }, /** * AJAX sessions */ _sessions: new RequestPool(5), /** * Queue of AJAX queries */ _queue: new Queue(100), /** * Activity flag for _checkQueue method */ _isActive: 0, /** * Check queue of AJAX requests */ _checkQueue: function() { this._isActive = 1; // Get request from query var maxi = this._queue.queue.length; if (maxi == 0) { this._isActive = 0; return; } // Get HTTP request from pool var req = this._sessions.getRequest(); if (req != null) { // Prepare request var sessions = this._sessions; var r = this._queue.shift(); // Build batch package var batch = [[r.data, r.handler]]; var callbacks = [r.callback]; for (var i = 0; i < maxi - 1; i++) { var x = this._queue.get(i); if (r.url == x.url && r.timeout == x.timeout && r.method == x.method) { this._queue.shift(i); maxi--; i--; batch.push([x.data, x.handler]); callbacks.push(x.callback); } } // Prepare request parameters if (!r.url) { r.url = this._request.url; } if (!r.timeout) { r.timeout = this._request.timeout; } if (!r.method) { r.method = this._request.method; } // Build query string var reqstr = this._request.request_parameter + '=' + batch.serialize(); var geturl = r.url + (r.url.indexOf('?') < 0 ? '?' : '&') + reqstr; if (r.method == 'AUTO') { r.method = geturl.length > this._request.method_get_maxsize ? 'POST' : 'GET'; } // Set timeout req.ontimeout = function() { req.abort(); for (var i in callbacks) { callbacks[i]({error: 'TIMEOUT'}); } sessions.closeRequest(req); } var timeoutid = setTimeout(req.ontimeout, r.timeout * 1000); // Prepare callback method for result req.onreadystatechange = function() { if (req.readyState == 4) { if (req.status) { clearTimeout(timeoutid); var data = req.responseText.unserialize(); for (var i in callbacks) { callbacks[i](req.status == 200 && data instanceof Array ? {data: data[i]} : {error: 'REQUEST_ERROR'}); } } sessions.closeRequest(req); } } // Send Request if (r.method == 'POST') { req.open('POST', r.url, true); req.setRequestHeader( 'Content-type', 'application/x-www-form-urlencoded; charset=UTF-8'); req.send(reqstr); } else { req.open('GET', geturl, true); req.send(null); } } setTimeout(function() { multiajax._checkQueue(); }, 1000); }, /** * Send AJAX request. * The structure of request: * - url - URL of server-side resource * - handler - request function name ("/multiajax" by default) * - data - request data * - callback - JavaScript callback function name * - timeout - request timeout, seconds (30 seconds by default) * - method - HTTP request method, POST, GET or AUTO (AUTO by default) * * The structure of response: * - data - response data * - error - response error code * * @param r AJAX request. */ send: function(r) { if (!this._queue.push(r)) { r.callback({error: 'QUEUE_OVERFLOW'}); return; } if (!this._isActive) { this._checkQueue(); } } }