├── 0.html
├── 1.php
├── 2.php
├── 3.php
├── README
├── index.html
└── jquery.ajaxmanager.js
/0.html:
--------------------------------------------------------------------------------
1 | 0 seconds
--------------------------------------------------------------------------------
/1.php:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/2.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/3.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aFarkas/Ajaxmanager/7aba194323cbc4bf6c0b71fdfb5e28dd030c54e5/README
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
155 |
AJAX Queue/Cache/Abort/Block Manager v. 3.0
156 |
Helps you to manage AJAX requests and responses (i.e. abort requests, block requests, order requests). It is inspired by the AJAX Queue Plugin and the AjaxQueue document in the jQuery-Wiki.
157 |
$.manageAjax.create (uniqueName, options)
158 |
Creates a new ajaxmanager and returns it. Takes a list of options:
159 |
160 | - normal jQuery-Ajax-Options
161 | - queue: (true|false|'clear') the queue-type specifies the queue-behaviour. The clear option clears the queue, before it adds a new ajax-task to the queue (similiar to: last in first out)
162 |
- abortOld (true|false): aborts all "older" requests, if there is a response to a newer request
163 | - abortIsNoSuccess: (true|false): jQuery 1.4 calls the success-callback, if an XHR was aborted. If this option is set to true. Only the complete - callback will be called with status 'abort'.
164 | - abort: (function): callback, that will be called, if a XHR is aborted.
165 | - beforeCreate ([function]): a function that will be called, before the XHR-object is created. If you return false, the XHR won´t be created.
166 | - maxRequests: (number (1)) limits the number of simultaneous request in the queue. queue-option must be true or 'clear'.
167 | - preventDoubleRequests (true|false): prevents multiple equal requests (compares url, data and type)
168 | - cacheResponse (true|false): caches the response data of succesfull responses (not the xhr-object!)
169 | - domCompleteTrigger (false| DOM-Element, DOMNodelist, Selector or jQuery-List). Triggers the events uniqueName + "DOMComplete" and "DOMComplete" on the specified element.
170 | - domSuccessTrigger (false | DOM-Element, DOMNodelist, Selector or jQuery-List). Triggers the events uniqueName + "DOMSuccess" and "DOMSuccess" on the specified element.
171 |
172 |
Your constructed ajaxmanager knows the following methods:
173 |
174 |
175 | - add: ([uniqueName], options) returns an id of your XHR object and takes the following options:
176 |
180 |
181 | - clear: ([uniqueName], [shouldAbort: true|false]) Clears the ajax queue of waiting requests. If the second parameter is true, all requests in proccess will be aborted, too.
182 | - abort: ([uniqueName], [id]) Aborts all managed XHR-requests. If you pass the optional index number of your XHR object only this XHR will be aborted.
183 | - getXHR: ([uniqueName], id) Returns the XHR-Object, if it is already constructed or the queue-function
184 |
185 |
Note:
186 |
First you have to construct/configure a new Ajaxmanager
187 | //create an ajaxmanager named someAjaxProfileName
188 | var someManagedAjax = $.manageAjax.create('someAjaxProfileName', {
189 | queue: true,
190 | cacheResponse: true
191 | });
192 |
193 |
194 |
You have two different ways to call your methods (don´t mix them).
195 |
196 |
Calling Ajaxmanager with uniqueName
197 |
//and add an ajaxrequest
198 | $.manageAjax.add('someAjaxProfileName', {
199 | success: function(html) {
200 | $('ul').append('<li>'+html+'</li>');
201 | },
202 | url: 'test.html'
203 | });
204 |
205 |
Calling Ajaxmanager with the returned ajaxmanger-Object
206 |
//and add an ajaxrequest with the returned object
207 | $.manageAjax.add({
208 | success: function(html) {
209 | $('ul').append('<li>'+html+'</li>');
210 | },
211 | url: 'test.html'
212 | });
213 |
214 |
Example:
215 |
216 | //create an ajaxmanager named cacheQueue
217 | var ajaxManager = $.manageAjax.create('cacheQueue', {
218 | queue: true,
219 | cacheResponse: true
220 | });
221 | //and add an ajaxrequest with the returned object
222 | ajaxManager.add({
223 | success: function(html) {
224 | $('ul').append('<li>'+html+'</li>');
225 | },
226 | url: 'test.html'
227 | });
228 |
or only with the uniqueName parameter
229 |
230 | //generate an ajaxmanger named clearQueue
231 | $.manageAjax.create('clearQueue', {queue: 'clear', maxRequests: 2});
232 | //and add an ajaxrequest with the name parameter
233 | $.manageAjax.add('clearQueue', {
234 | success: function(html) {
235 | $('ul').append('<li>'+html+'</li>');
236 | },
237 | url: 'test.html'
238 | });
239 |
$.manageAjax.destroy (uniqueName)
240 |
Destroys an existing Ajaxmanager. Any requests in progress are aborted and waiting requests are cleared.
241 |
Events/Callbacks:
242 |
The ajaxmanager adds some new events or enhances some existing callbacks.
243 |
244 |
245 |
246 | name |
247 | arguments |
248 | new/enhanced |
249 |
250 |
251 |
252 |
253 |
254 | beforeCreate (local) |
255 | XHR-ID, options |
256 | new |
257 |
258 |
259 | beforeSend (local) |
260 | XMLHttpRequest, options |
261 | enhanced: options arguments is passed |
262 |
263 |
264 | managerName + 'AjaxStart' (global) |
265 | event |
266 | new |
267 |
268 |
269 | complete (local) |
270 |
271 | xhr*, status, options
272 | |
273 | enhanced: the options arguments is additionally passed. |
274 |
275 |
276 | managerName + 'AjaxComplete' (global) |
277 |
278 | event, xhr*, status, options
279 | |
280 | new |
281 |
282 |
283 | managerName + 'DOMComplete' (DOM-Event**) |
284 |
285 | event, xhr*, status, options
286 | |
287 | new |
288 |
289 |
290 | 'DOMComplete' (DOM-Event**) |
291 |
292 | event, xhr*, status, options
293 | |
294 | new |
295 |
296 |
297 | success (local) |
298 |
299 | data, textStatus, xhr*, options
300 | |
301 | enhanced: the options arguments is additionally passed. |
302 |
303 |
304 | managerName + 'AjaxSuccess' (global) |
305 |
306 | event, xhr, options, data
307 | |
308 | new |
309 |
310 |
311 | managerName + 'DOMSuccess' (DOM-Event**) |
312 |
313 | event, data, options
314 | |
315 | new |
316 |
317 |
318 | 'DOMSuccess' (DOM-Event**) |
319 |
320 | event, data, options
321 | |
322 | new |
323 |
324 |
325 | managerName + 'AjaxStop' (global) |
326 |
327 | event
328 | |
329 | new |
330 |
331 |
332 |
333 |
*Note: If the cacheResponse - option is true, the xhr-argument can be an empty object.
334 |
**Note: You need to configure 'domCompleteTrigger' / 'domSuccessTrigger' to trigger these events.
335 |
Demo:
336 |
Tip: Open your Firebug-Console, log the XHR´s and click around.
337 |
343 |
349 |
355 |
361 |
If you find bugs please report them!!!
362 |
Project Site & Bugtracker
363 |
367 |
Download
368 |
371 |
Licenses
372 |
376 |
Back to protofunc
377 |
378 |
379 |
380 |
--------------------------------------------------------------------------------
/jquery.ajaxmanager.js:
--------------------------------------------------------------------------------
1 | /**!
2 | * project-site: http://plugins.jquery.com/project/AjaxManager
3 | * repository: http://github.com/aFarkas/Ajaxmanager
4 | * @author Alexander Farkas
5 | * @version 3.12
6 | * Copyright 2010, Alexander Farkas
7 | * Dual licensed under the MIT or GPL Version 2 licenses.
8 | */
9 |
10 | (function($){
11 | "use strict";
12 | var managed = {},
13 | cache = {}
14 | ;
15 | $.manageAjax = (function(){
16 | function create(name, opts){
17 | managed[name] = new $.manageAjax._manager(name, opts);
18 | return managed[name];
19 | }
20 |
21 | function destroy(name){
22 | if(managed[name]){
23 | managed[name].clear(true);
24 | delete managed[name];
25 | }
26 | }
27 |
28 |
29 | var publicFns = {
30 | create: create,
31 | destroy: destroy
32 | };
33 |
34 | return publicFns;
35 | })();
36 |
37 | $.manageAjax._manager = function(name, opts){
38 | this.requests = {};
39 | this.inProgress = 0;
40 | this.name = name;
41 | this.qName = name;
42 |
43 | this.opts = $.extend({}, $.manageAjax.defaults, opts);
44 | if(opts && opts.queue && opts.queue !== true && typeof opts.queue === 'string' && opts.queue !== 'clear'){
45 | this.qName = opts.queue;
46 | }
47 | };
48 |
49 | $.manageAjax._manager.prototype = {
50 | add: function(url, o){
51 | if(typeof url == 'object'){
52 | o = url;
53 | } else if(typeof url == 'string'){
54 | o = $.extend(o || {}, {url: url});
55 | }
56 | o = $.extend({}, this.opts, o);
57 |
58 | var origCom = o.complete || $.noop,
59 | origSuc = o.success || $.noop,
60 | beforeSend = o.beforeSend || $.noop,
61 | origError = o.error || $.noop,
62 | strData = (typeof o.data == 'string') ? o.data : $.param(o.data || {}),
63 | xhrID = o.type + o.url + strData,
64 | that = this,
65 | ajaxFn = this._createAjax(xhrID, o, origSuc, origCom)
66 | ;
67 | if(o.preventDoubleRequests && o.queueDuplicateRequests){
68 | if(o.preventDoubleRequests){
69 | o.queueDuplicateRequests = false;
70 | }
71 | setTimeout(function(){
72 | throw("preventDoubleRequests and queueDuplicateRequests can't be both true");
73 | }, 0);
74 | }
75 | if(this.requests[xhrID] && o.preventDoubleRequests){
76 | return;
77 | }
78 | ajaxFn.xhrID = xhrID;
79 | o.xhrID = xhrID;
80 |
81 | o.beforeSend = function(xhr, opts){
82 | var ret = beforeSend.call(this, xhr, opts);
83 | if(ret === false){
84 | that._removeXHR(xhrID);
85 | }
86 | xhr = null;
87 | return ret;
88 | };
89 | o.complete = function(xhr, status){
90 | that._complete.call(that, this, origCom, xhr, status, xhrID, o);
91 | xhr = null;
92 | };
93 |
94 | o.success = function(data, status, xhr){
95 | that._success.call(that, this, origSuc, data, status, xhr, o);
96 | xhr = null;
97 | };
98 |
99 | //always add some error callback
100 | o.error = function(ahr, status, errorStr){
101 | var httpStatus = '',
102 | content = ''
103 | ;
104 | if(status !== 'timeout' && ahr){
105 | httpStatus = ahr.status;
106 | content = ahr.responseXML || ahr.responseText;
107 | }
108 | if(origError) {
109 | origError.call(this, ahr, status, errorStr, o);
110 | } else {
111 | setTimeout(function(){
112 | throw status + '| status: ' + httpStatus + ' | URL: ' + o.url + ' | data: '+ strData + ' | thrown: '+ errorStr + ' | response: '+ content;
113 | }, 0);
114 | }
115 | ahr = null;
116 | };
117 |
118 | if(o.queue === 'clear'){
119 | $(document).clearQueue(this.qName);
120 | }
121 |
122 | if(o.queue || (o.queueDuplicateRequests && this.requests[xhrID])){
123 | $.queue(document, this.qName, ajaxFn);
124 | if(this.inProgress < o.maxRequests && (!this.requests[xhrID] || !o.queueDuplicateRequests)){
125 | $.dequeue(document, this.qName);
126 | }
127 | return xhrID;
128 | }
129 | return ajaxFn();
130 | },
131 | _createAjax: function(id, o, origSuc, origCom){
132 | var that = this;
133 | return function(){
134 | if(o.beforeCreate.call(o.context || that, id, o) === false){return;}
135 | that.inProgress++;
136 | if(that.inProgress === 1){
137 | $.event.trigger(that.name +'AjaxStart');
138 | }
139 | if(o.cacheResponse && cache[id]){
140 | if(!cache[id].cacheTTL || cache[id].cacheTTL < 0 || ((new Date().getTime() - cache[id].timestamp) < cache[id].cacheTTL)){
141 | that.requests[id] = {};
142 | setTimeout(function(){
143 | that._success.call(that, o.context || o, origSuc, cache[id]._successData, 'success', cache[id], o);
144 | that._complete.call(that, o.context || o, origCom, cache[id], 'success', id, o);
145 | }, 0);
146 | } else {
147 | delete cache[id];
148 | }
149 | }
150 | if(!o.cacheResponse || !cache[id]) {
151 | if (o.async) {
152 | that.requests[id] = $.ajax(o);
153 | } else {
154 | $.ajax(o);
155 | }
156 | }
157 | return id;
158 | };
159 | },
160 | _removeXHR: function(xhrID){
161 | if(this.opts.queue || this.opts.queueDuplicateRequests){
162 | $.dequeue(document, this.qName);
163 | }
164 | this.inProgress--;
165 | this.requests[xhrID] = null;
166 | delete this.requests[xhrID];
167 | },
168 | clearCache: function () {
169 | cache = {};
170 | },
171 | _isAbort: function(xhr, status, o){
172 | if(!o.abortIsNoSuccess || (!xhr && !status)){
173 | return false;
174 | }
175 | var ret = !!( ( !xhr || xhr.readyState === 0 || this.lastAbort === o.xhrID ) );
176 | xhr = null;
177 | return ret;
178 | },
179 | _complete: function(context, origFn, xhr, status, xhrID, o){
180 | if(this._isAbort(xhr, status, o)){
181 | status = 'abort';
182 | o.abort.call(context, xhr, status, o);
183 | }
184 | origFn.call(context, xhr, status, o);
185 |
186 | $.event.trigger(this.name +'AjaxComplete', [xhr, status, o]);
187 |
188 | if(o.domCompleteTrigger){
189 | $(o.domCompleteTrigger)
190 | .trigger(this.name +'DOMComplete', [xhr, status, o])
191 | .trigger('DOMComplete', [xhr, status, o])
192 | ;
193 | }
194 |
195 | this._removeXHR(xhrID);
196 | if(!this.inProgress){
197 | $.event.trigger(this.name +'AjaxStop');
198 | }
199 | xhr = null;
200 | },
201 | _success: function(context, origFn, data, status, xhr, o){
202 | var that = this;
203 | if(this._isAbort(xhr, status, o)){
204 | xhr = null;
205 | return;
206 | }
207 | if(o.abortOld){
208 | $.each(this.requests, function(name){
209 | if(name === o.xhrID){
210 | return false;
211 | }
212 | that.abort(name);
213 | });
214 | }
215 | if(o.cacheResponse && !cache[o.xhrID]){
216 | if(!xhr){
217 | xhr = {};
218 | }
219 | cache[o.xhrID] = {
220 | status: xhr.status,
221 | statusText: xhr.statusText,
222 | responseText: xhr.responseText,
223 | responseXML: xhr.responseXML,
224 | _successData: data,
225 | cacheTTL: o.cacheTTL,
226 | timestamp: new Date().getTime()
227 | };
228 | if('getAllResponseHeaders' in xhr){
229 | var responseHeaders = xhr.getAllResponseHeaders();
230 | var parsedHeaders;
231 | var parseHeaders = function(){
232 | if(parsedHeaders){return;}
233 | parsedHeaders = {};
234 | $.each(responseHeaders.split("\n"), function(i, headerLine){
235 | var delimiter = headerLine.indexOf(":");
236 | parsedHeaders[headerLine.substr(0, delimiter)] = headerLine.substr(delimiter + 2);
237 | });
238 | };
239 | $.extend(cache[o.xhrID], {
240 | getAllResponseHeaders: function() {return responseHeaders;},
241 | getResponseHeader: function(name) {
242 | parseHeaders();
243 | return (name in parsedHeaders) ? parsedHeaders[name] : null;
244 | }
245 | });
246 | }
247 | }
248 | origFn.call(context, data, status, xhr, o);
249 | $.event.trigger(this.name +'AjaxSuccess', [xhr, o, data]);
250 | if(o.domSuccessTrigger){
251 | $(o.domSuccessTrigger)
252 | .trigger(this.name +'DOMSuccess', [data, o])
253 | .trigger('DOMSuccess', [data, o])
254 | ;
255 | }
256 | xhr = null;
257 | },
258 | getData: function(id){
259 | if( id ){
260 | var ret = this.requests[id];
261 | if(!ret && this.opts.queue) {
262 | ret = $.grep($(document).queue(this.qName), function(fn, i){
263 | return (fn.xhrID === id);
264 | })[0];
265 | }
266 | return ret;
267 | }
268 | return {
269 | requests: this.requests,
270 | queue: (this.opts.queue) ? $(document).queue(this.qName) : [],
271 | inProgress: this.inProgress
272 | };
273 | },
274 | abort: function(id){
275 | var xhr;
276 | if(id){
277 | xhr = this.getData(id);
278 |
279 | if(xhr && xhr.abort){
280 | this.lastAbort = id;
281 | xhr.abort();
282 | this.lastAbort = false;
283 | } else {
284 | $(document).queue(
285 | this.qName, $.grep($(document).queue(this.qName), function(fn, i){
286 | return (fn !== xhr);
287 | })
288 | );
289 | }
290 | xhr = null;
291 | return;
292 | }
293 |
294 | var that = this,
295 | ids = []
296 | ;
297 | $.each(this.requests, function(id){
298 | ids.push(id);
299 | });
300 | $.each(ids, function(i, id){
301 | that.abort(id);
302 | });
303 | },
304 | clear: function(shouldAbort){
305 | $(document).clearQueue(this.qName);
306 | if(shouldAbort){
307 | this.abort();
308 | }
309 | }
310 | };
311 | $.manageAjax._manager.prototype.getXHR = $.manageAjax._manager.prototype.getData;
312 | $.manageAjax.defaults = {
313 | beforeCreate: $.noop,
314 | abort: $.noop,
315 | abortIsNoSuccess: true,
316 | maxRequests: 1,
317 | cacheResponse: false,
318 | async: true,
319 | domCompleteTrigger: false,
320 | domSuccessTrigger: false,
321 | preventDoubleRequests: true,
322 | queueDuplicateRequests: false,
323 | cacheTTL: -1,
324 | queue: false // true, false, clear
325 | };
326 |
327 | $.each($.manageAjax._manager.prototype, function(n, fn){
328 | if(n.indexOf('_') === 0 || !$.isFunction(fn)){return;}
329 | $.manageAjax[n] = function(name, o){
330 | if(!managed[name]){
331 | if(n === 'add'){
332 | $.manageAjax.create(name, o);
333 | } else {
334 | return;
335 | }
336 | }
337 | var args = Array.prototype.slice.call(arguments, 1);
338 | managed[name][n].apply(managed[name], args);
339 | };
340 | });
341 |
342 | })(jQuery);
--------------------------------------------------------------------------------