source: trunk/themes/default/js/plugins/jquery.ajaxmanager.js @ 19281

Last change on this file since 19281 was 9933, checked in by patdenice, 14 years ago

Add ajaxmanager plugin.

File size: 8.8 KB
Line 
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);
Note: See TracBrowser for help on using the repository browser.