rasputin 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1072 +0,0 @@
1
-
2
- (function(exports) {
3
- // ==========================================================================
4
- // Project: SproutCore - JavaScript Application Framework
5
- // Copyright: ©2006-2011 Strobe Inc. and contributors.
6
- // Portions ©2008-2011 Apple Inc. All rights reserved.
7
- // License: Licensed under MIT license (see license.js)
8
- // ==========================================================================
9
-
10
- var get = SC.get, set = SC.set, getPath = SC.getPath;
11
-
12
- /**
13
- @class
14
-
15
- A response represents a single response from a server request. An instance
16
- of this class is returned whenever you call SC.Request.send().
17
-
18
- @extend SC.Object
19
- @since SproutCore 1.0
20
- */
21
- SC.Response = SC.Object.extend(
22
- /** @scope SC.Response.prototype */ {
23
-
24
- /**
25
- Walk like a duck
26
-
27
- @type Boolean
28
- */
29
- isResponse: true,
30
-
31
- /**
32
- Becomes true if there was a failure. Makes this into an error object.
33
-
34
- @type Boolean
35
- @default false
36
- */
37
- isError: false,
38
-
39
- /**
40
- Always the current response
41
-
42
- @field
43
- @type SC.Response
44
- @default `this`
45
- */
46
- errorValue: function() {
47
- return this;
48
- }.property().cacheable(),
49
-
50
- /**
51
- The error object generated when this becomes an error
52
-
53
- @type SC.Error
54
- @default null
55
- */
56
- errorObject: null,
57
-
58
- /**
59
- Request used to generate this response. This is a copy of the original
60
- request object as you may have modified the original request object since
61
- then.
62
-
63
- To retrieve the original request object use originalRequest.
64
-
65
- @type SC.Request
66
- @default null
67
- */
68
- request: null,
69
-
70
- /**
71
- The request object that originated this request series. Mostly this is
72
- useful if you are looking for a reference to the original request. To
73
- inspect actual properties you should use request instead.
74
-
75
- @field
76
- @type SC.Request
77
- @observes request
78
- */
79
- originalRequest: function() {
80
- var ret = get(this, 'request');
81
- while (get(ret, 'source')) { ret = get(ret, 'source'); }
82
- return ret ;
83
- }.property('request').cacheable(),
84
-
85
- /**
86
- Type of request. Must be an HTTP method. Based on the request.
87
-
88
- @field
89
- @type String
90
- @observes request
91
- */
92
- type: function() {
93
- return getPath(this, 'request.type');
94
- }.property('request').cacheable(),
95
-
96
- /**
97
- URL of request.
98
-
99
- @field
100
- @type String
101
- @observes request
102
- */
103
- url: function() {
104
- return getPath(this, 'request.url');
105
- }.property('request').cacheable(),
106
-
107
- /**
108
- Returns the hash of listeners set on the request.
109
-
110
- @field
111
- @type Hash
112
- @observes request
113
- */
114
- listeners: function() {
115
- return getPath(this, 'request.listeners');
116
- }.property('request').cacheable(),
117
-
118
- /**
119
- The response status code.
120
-
121
- @type Number
122
- @default -100
123
- */
124
- status: -100, // READY
125
-
126
- /**
127
- Headers from the response. Computed on-demand
128
-
129
- @type Hash
130
- @default null
131
- */
132
- headers: null,
133
-
134
- /**
135
- The response body or the parsed JSON.
136
- */
137
- body: null,
138
-
139
- /**
140
- Set to true if response is cancelled
141
-
142
- @type Boolean
143
- @default false
144
- */
145
- isCancelled: false,
146
-
147
- /**
148
- Set to true if the request timed out. Set to false if the request has
149
- completed before the timeout value. Set to null if the timeout timer is
150
- still ticking.
151
-
152
- @type Boolean
153
- @default null
154
- */
155
- timedOut: null,
156
-
157
- // ..........................................................
158
- // METHODS
159
- //
160
-
161
- /**
162
- Called by the request manager when its time to actually run. This will
163
- invoke any callbacks on the source request then invoke transport() to
164
- begin the actual request.
165
- */
166
- fire: function() {
167
- var req = get(this, 'request'),
168
- source = req ? get(req, 'source') : null;
169
-
170
- // first give the source a chance to fixup the request and response
171
- // then freeze req so no more changes can happen.
172
- if (source && source.willSend) { source.willSend(req, this); }
173
- req.freeze();
174
-
175
- // if the source did not cancel the request, then invoke the transport
176
- // to actually trigger the request. This might receive a response
177
- // immediately if it is synchronous.
178
- if (!get(this, 'isCancelled')) { this.invokeTransport(); }
179
-
180
- // if the transport did not cancel the request for some reason, let the
181
- // source know that the request was sent
182
- if (!this.get('isCancelled') && source && source.didSend) {
183
- source.didSend(req, this);
184
- }
185
- },
186
-
187
- /**
188
- Called by `SC.Response#fire()`. Starts the transport by invoking the
189
- `SC.Response#receive()` function.
190
- */
191
- invokeTransport: function() {
192
- this.receive(function(proceed) { set(this, 'status', 200); }, this);
193
- },
194
-
195
- /**
196
- Invoked by the transport when it receives a response. The passed-in
197
- callback will be invoked to actually process the response. If cancelled
198
- we will pass false. You should clean up instead.
199
-
200
- Invokes callbacks on the source request also.
201
-
202
- @param {Function} callback the function to receive
203
- @param {Object} context context to execute the callback in
204
- @returns {SC.Response} receiver
205
- */
206
- receive: function(callback, context) {
207
- var req = get(this, 'request');
208
- var source = req ? get(req, 'source') : null;
209
-
210
- SC.run(this, function() {
211
- // invoke the source, giving a chance to fixup the response or (more
212
- // likely) cancel the request.
213
- if (source && source.willReceive) { source.willReceive(req, this); }
214
-
215
- // invoke the callback. note if the response was cancelled or not
216
- callback.call(context, !get(this, 'isCancelled'));
217
-
218
- // if we weren't cancelled, then give the source first crack at handling
219
- // the response. if the source doesn't want listeners to be notified,
220
- // it will cancel the response.
221
- if (!get(this, 'isCancelled') && source && source.didReceive) {
222
- source.didReceive(req, this);
223
- }
224
-
225
- // notify listeners if we weren't cancelled.
226
- if (!get(this, 'isCancelled')) { this.notify(); }
227
- });
228
-
229
- // no matter what, remove from inflight queue
230
- SC.Request.manager.transportDidClose(this);
231
- return this;
232
- },
233
-
234
- /**
235
- Default method just closes the connection. It will also mark the request
236
- as cancelled, which will not call any listeners.
237
- */
238
- cancel: function() {
239
- if (!get(this, 'isCancelled')) {
240
- set(this, 'isCancelled', true) ;
241
- this.cancelTransport() ;
242
- SC.Request.manager.transportDidClose(this) ;
243
- }
244
- },
245
-
246
- /**
247
- Override with concrete implementation to actually cancel the transport.
248
- */
249
- cancelTransport: function() {},
250
-
251
- /**
252
- Notifies any saved target/action. Call whenever you cancel, or end.
253
-
254
- @returns {SC.Response} receiver
255
- */
256
- notify: function() {
257
- var listeners = this.get('listeners'),
258
- status = this.get('status'),
259
- baseStat = Math.floor(status / 100) * 100,
260
- handled = false;
261
-
262
- if (!listeners) { return this; }
263
-
264
- handled = this._notifyListeners(listeners, status);
265
- if (!handled && baseStat !== status) { handled = this._notifyListeners(listeners, baseStat); }
266
- if (!handled && status !== 0) { handled = this._notifyListeners(listeners, 0); }
267
-
268
- return this ;
269
- },
270
-
271
- /**
272
- String representation of the response object
273
-
274
- @returns {String}
275
- */
276
- toString: function() {
277
- var ret = this._super();
278
- return "%@<%@ %@, status=%@".fmt(ret, this.get('type'), this.get('url'), this.get('status'));
279
- },
280
-
281
- /**
282
- @private
283
-
284
- Will notify each listener. Returns true if any of the listeners handle.
285
- */
286
- _notifyListeners: function(listeners, status) {
287
- var notifiers = listeners[status], params, target, action;
288
- if (!notifiers) { return false; }
289
-
290
- var handled = false;
291
- var len = notifiers.length;
292
-
293
- for (var i = 0; i < len; i++) {
294
- var notifier = notifiers[i];
295
- params = (notifier.params || []).copy();
296
- params.unshift(this);
297
-
298
- target = notifier.target;
299
- action = notifier.action;
300
- if (SC.typeOf(action) === 'string') { action = target[action]; }
301
-
302
- handled = action.apply(target, params);
303
- }
304
-
305
- return handled;
306
- }
307
- });
308
-
309
- /**
310
- Concrete implementation of SC.Response that implements support for using
311
- jqXHR requests.
312
-
313
- @extends SC.Response
314
- */
315
- SC.XHRResponse = SC.Response.extend({
316
-
317
- /**
318
- Implement transport-specific support for fetching all headers
319
- */
320
- headers: function() {
321
- var rawRequest = get(this, 'rawRequest'),
322
- str = rawRequest ? rawRequest.getAllResponseHeaders() : null,
323
- ret = {};
324
-
325
- if (!str) return ret;
326
-
327
- str.split("\n").forEach(function(header) {
328
- var idx = header.indexOf(':'),
329
- key, value;
330
- if (idx>=0) {
331
- key = header.slice(0,idx);
332
- value = header.slice(idx+1).trim();
333
- ret[key] = value ;
334
- }
335
- }, this);
336
-
337
- return ret ;
338
- }.property('status').cacheable(),
339
-
340
- /**
341
- Implement transport-specific support for fetching named header
342
- */
343
- header: function(key) {
344
- var rawRequest = get(this, 'rawRequest');
345
- return rawRequest ? rawRequest.getResponseHeader(key) : null;
346
- },
347
-
348
- /**
349
- */
350
- cancelTransport: function() {
351
- var rawRequest = get(this, 'rawRequest');
352
- if (rawRequest) rawRequest.abort();
353
- set(this, 'rawRequest', null);
354
- },
355
-
356
- /**
357
- */
358
- invokeTransport: function() {
359
- var async = !!getPath(this, 'request.isAsynchronous');
360
- var rawRequest = this.createRequest();
361
-
362
- // save it
363
- set(this, 'rawRequest', rawRequest);
364
-
365
- // not async
366
- if (!async) this.finishRequest();
367
-
368
- return rawRequest;
369
- },
370
-
371
- /**
372
- Creates the jqXHR object.
373
-
374
- @returns {jqXHR}
375
- */
376
- createRequest: function() {
377
- var request = get(this, 'request');
378
- return SC.$.ajax({
379
- url: get(this, 'url'),
380
- type: get(this, 'type'),
381
- dataType: get(request, 'dataType'),
382
- async: get(request, 'isAsynchronous'),
383
- headers: get(request, 'headers'),
384
- data: get(request, 'body'),
385
- timeout: get(request, 'timeout'),
386
- ifModified: get(request, 'ifModified'),
387
- complete: this.finishRequest,
388
- success: this._didLoadContent,
389
- context: this
390
- });
391
- },
392
-
393
- /**
394
- @private
395
-
396
- Called by the jqXHR when it responds with some final results.
397
-
398
- @param {jqXHR} rawRequest the actual request
399
- @returns {Boolean} request success
400
- */
401
- finishRequest: function(rawRequest) {
402
- this.set('rawRequest', rawRequest);
403
- if (rawRequest.readyState === 4 && !get(this, 'timedOut')) {
404
- this.receive(function(proceed) {
405
- if (!proceed) return; // skip receiving...
406
- var statusText = rawRequest.statusText,
407
- status = rawRequest.status;
408
- set(this, 'status', status);
409
- if (statusText === 'success' || statusText === 'notmodified') {
410
- set(this, 'isError', false);
411
- set(this, 'errorObject', null);
412
- } else {
413
- if (statusText === 'timeout') {
414
- set(this, 'timedOut', true);
415
- this.cancelTransport();
416
- }
417
- var error = new SC.Error('%@ Request %@'.fmt(statusText, status));
418
- set(error, 'errorValue', this);
419
- set(this, 'isError', true);
420
- set(this, 'errorObject', error);
421
- }
422
- }, this);
423
-
424
- return true;
425
- }
426
- return false;
427
- },
428
-
429
- /**
430
- @private
431
- */
432
- _didLoadContent: function(data) {
433
- set(this, 'body', data);
434
- }
435
-
436
- });
437
-
438
- SC.HTTPError = SC.Object.extend({
439
-
440
- });
441
-
442
- SC.ok = function(ret) {
443
- return (ret !== false) && !(ret && ret.isError);
444
- };
445
-
446
- })({});
447
-
448
-
449
- (function(exports) {
450
- // ==========================================================================
451
- // Project: SproutCore - JavaScript Application Framework
452
- // Copyright: ©2006-2011 Strobe Inc. and contributors.
453
- // Portions ©2008-2011 Apple Inc. All rights reserved.
454
- // License: Licensed under MIT license (see license.js)
455
- // ==========================================================================
456
-
457
- var get = SC.get, set = SC.set;
458
-
459
- /**
460
- @class
461
-
462
- Implements support for Ajax requests using XHR and other prototcols.
463
-
464
- SC.Request is much like an inverted version of the request/response objects
465
- you receive when implementing HTTP servers.
466
-
467
- To send a request, you just need to create your request object, configure
468
- your options, and call send() to initiate the request.
469
-
470
- @extends SC.Object
471
- @extends SC.Copyable
472
- @extends SC.Freezable
473
- */
474
- SC.Request = SC.Object.extend(SC.Copyable, SC.Freezable, {
475
-
476
- // ..........................................................
477
- // PROPERTIES
478
- //
479
-
480
- /**
481
- Sends the request asynchronously instead of blocking the browser. You
482
- should almost always make requests asynchronous. You can change this
483
- options with the async() helper option (or simply set it directly).
484
-
485
- @type Boolean
486
- @default YES
487
- */
488
- isAsynchronous: true,
489
-
490
- /**
491
- Current set of headers for the request
492
-
493
- @field
494
- @type Hash
495
- @default {}
496
- */
497
- headers: function() {
498
- var ret = this._headers;
499
- if (!ret) { ret = this._headers = {}; }
500
- return ret;
501
- }.property().cacheable(),
502
-
503
- /**
504
- Underlying response class to actually handle this request. Currently the
505
- only supported option is SC.XHRResponse which uses a traditional
506
- XHR transport.
507
-
508
- @type SC.Response
509
- @default SC.XHRResponse
510
- */
511
- responseClass: SC.XHRResponse,
512
-
513
- /**
514
- The original request for copied requests.
515
-
516
- @property SC.Request
517
- @default null
518
- */
519
- source: null,
520
-
521
- /**
522
- The URL this request to go to.
523
-
524
- @type String
525
- @default null
526
- */
527
- url: null,
528
-
529
- /**
530
- The HTTP method to use.
531
-
532
- @type String
533
- @default 'GET'
534
- */
535
- type: 'GET',
536
-
537
- /**
538
- The body of the request. May be an object is isJSON or isXML is set,
539
- otherwise should be a string.
540
-
541
- @type Object|String
542
- @default null
543
- */
544
- body: null,
545
-
546
- /**
547
- @type String
548
- @default 'json'
549
- */
550
- dataType: 'json',
551
-
552
- /**
553
- An optional timeout value of the request, in milliseconds. The timer
554
- begins when SC.Response#fire is actually invoked by the request manager
555
- and not necessarily when SC.Request#send is invoked. If this timeout is
556
- reached before a response is received, the equivalent of
557
- SC.Request.manager#cancel() will be invoked on the SC.Response instance
558
- and the didReceive() callback will be called.
559
-
560
- An exception will be thrown if you try to invoke send() on a request that
561
- has both a timeout and isAsyncronous set to NO.
562
-
563
- @type Number
564
- @default null
565
- */
566
- timeout: null,
567
-
568
- /**
569
-
570
- */
571
- ifModified: false,
572
-
573
- // ..........................................................
574
- // CALLBACKS
575
- //
576
-
577
- /**
578
- Invoked on the original request object just before a copied request is
579
- frozen and then sent to the server. This gives you one last change to
580
- fixup the request; possibly adding headers and other options.
581
-
582
- If you do not want the request to actually send, call cancel().
583
-
584
- @param {SC.Request} request A copy of the request object, not frozen
585
- @param {SC.Response} response The object that will wrap the response
586
- */
587
- willSend: function(request, response) {},
588
-
589
- /**
590
- Invoked on the original request object just after the request is sent to
591
- the server. You might use this callback to update some state in your
592
- application.
593
-
594
- The passed request is a frozen copy of the request, indicating the
595
- options set at the time of the request.
596
-
597
- @param {SC.Request} request A copy of the request object, frozen
598
- @param {SC.Response} response The object that will wrap the response
599
- @returns {Boolean} YES on success, NO on failure
600
- */
601
- didSend: function(request, response) {},
602
-
603
- /**
604
- Invoked when a response has been received but not yet processed. This is
605
- your chance to fix up the response based on the results. If you don't
606
- want to continue processing the response call response.cancel().
607
-
608
- @param {SC.Request} request A copy of the request object, frozen
609
- @param {SC.Response} response The object that will wrap the response
610
- */
611
- willReceive: function(request, response) {},
612
-
613
- /**
614
- Invoked after a response has been processed but before any listeners are
615
- notified. You can do any standard processing on the request at this
616
- point. If you don't want to allow notifications to continue, call
617
- response.cancel()
618
-
619
- @param {SC.Request} request A copy of the request object, frozen
620
- @param {SC.Response} response The object that will wrap the response
621
- */
622
- didReceive: function(request, response) {},
623
-
624
-
625
- // ..........................................................
626
- // HELPER METHODS
627
- //
628
-
629
- /** @private */
630
- concatenatedProperties: 'COPY_KEYS',
631
-
632
- /** @private */
633
- COPY_KEYS: ['isAsynchronous', 'dataType', 'url', 'type', 'timeout', 'body', 'responseClass', 'willSend', 'didSend', 'willReceive', 'didReceive'],
634
-
635
- /**
636
- Returns a copy of the current request. This will only copy certain
637
- properties so if you want to add additional properties to the copy you
638
- will need to override copy() in a subclass.
639
-
640
- @returns {SC.Request} new request
641
- */
642
- copy: function() {
643
- var ret = {},
644
- keys = this.COPY_KEYS,
645
- loc = keys.length,
646
- key, listeners, headers;
647
-
648
- while(--loc >= 0) {
649
- key = keys[loc];
650
- if (this.hasOwnProperty(key)) {
651
- ret[key] = this.get(key);
652
- }
653
- }
654
-
655
- if (this.hasOwnProperty('listeners')) {
656
- ret.listeners = SC.copy(this.get('listeners'));
657
- }
658
-
659
- if (this.hasOwnProperty('_headers')) {
660
- ret._headers = SC.copy(this._headers);
661
- }
662
-
663
- ret.source = get(this, 'source') || this;
664
-
665
- return this.constructor.create(ret);
666
- },
667
-
668
- /**
669
- To set headers on the request object. Pass either a single key/value
670
- pair or a hash of key/value pairs. If you pass only a header name, this
671
- will return the current value of the header.
672
-
673
- @param {String|Hash} key
674
- @param {String} value
675
- @returns {SC.Request|Object} receiver
676
- */
677
- header: function(key, value) {
678
- var headers;
679
-
680
- if (SC.typeOf(key) === 'string') {
681
- headers = this._headers;
682
- if (arguments.length === 1) {
683
- return headers ? headers[key] : null;
684
- } else {
685
- this.propertyWillChange('headers');
686
- if (!headers) { headers = this._headers = {}; }
687
- headers[key] = value;
688
- this.propertyDidChange('headers');
689
- return this;
690
- }
691
-
692
- // handle parsing hash of parameters
693
- } else if (value === undefined) {
694
- headers = key;
695
- this.beginPropertyChanges();
696
- for(key in headers) {
697
- if (!headers.hasOwnProperty(key)) { continue; }
698
- this.header(key, headers[key]);
699
- }
700
- this.endPropertyChanges();
701
- return this;
702
- }
703
-
704
- return this;
705
- },
706
-
707
- /**
708
- Clears the list of headers that were set on this request.
709
- This could be used by a subclass to blow-away any custom
710
- headers that were added by the super class.
711
- */
712
- clearHeaders: function() {
713
- this.propertyWillChange('headers');
714
- this._headers = {};
715
- this.propertyDidChange('headers');
716
- },
717
-
718
- /**
719
- Converts the current request to be asynchronous.
720
-
721
- @param {Boolean} flag YES to make asynchronous, NO or undefined. Default YES.
722
- @returns {SC.Request} receiver
723
- */
724
- async: function(flag) {
725
- if (flag === undefined) { flag = true; }
726
- set(this, 'isAsynchronous', flag);
727
- return this;
728
- },
729
-
730
- /**
731
- Sets the maximum amount of time the request will wait for a response.
732
-
733
- @param {Number} timeout The timeout in milliseconds.
734
- @returns {SC.Request} receiver
735
- */
736
- timeoutAfter: function(timeout) {
737
- set(this, 'timeout', timeout);
738
- return this;
739
- },
740
-
741
- /**
742
- Converts the current request to use JSON.
743
-
744
- @returns {SC.Request} receiver
745
- */
746
- json: function() {
747
- set(this, 'dataType', 'json');
748
- return this;
749
- },
750
-
751
- /**
752
- Converts the current request to use XML.
753
-
754
- @returns {SC.Request} recevier
755
- */
756
- xml: function() {
757
- set(this, 'dataType', 'xml');
758
- return this;
759
- },
760
-
761
- /**
762
-
763
- */
764
- isJSON: function() {
765
- return get(this, 'dataType') === 'json';
766
- }.property('dataType').cacheable(),
767
-
768
- /**
769
-
770
- */
771
- isXML: function() {
772
- return get(this, 'dataType') === 'xml';
773
- }.property('dataType').cacheable(),
774
-
775
- /**
776
- Will fire the actual request. If you have set the request to use JSON
777
- mode then you can pass any object that can be converted to JSON as the
778
- body. Otherwise you should pass a string body.
779
-
780
- @param {String|Object} [body]
781
- @returns {SC.Response} New response object
782
- */
783
- send: function(body) {
784
- // Sanity-check: Be sure a timeout value was not specified if the request
785
- // is synchronous (because it wouldn't work).
786
- var timeout = get(this, 'timeout');
787
- if (timeout && !get(this, 'isAsynchronous')) {
788
- throw "Timeout values cannot be used with synchronous requests";
789
- } else if (timeout === 0) {
790
- throw "The timeout value must either not be specified or must be greater than 0";
791
- }
792
-
793
- if (body) { set(this, 'body', body); }
794
- return SC.Request.manager.sendRequest(this.copy());
795
- },
796
-
797
- /**
798
- Resends the current request. This is more efficient than calling send()
799
- for requests that have already been used in a send. Otherwise acts just
800
- like send(). Does not take a body argument.
801
-
802
- @returns {SC.Response} new response object
803
- */
804
- resend: function() {
805
- var req = get(this, 'source') ? this : this.copy();
806
- return SC.Request.manager.sendRequest(req);
807
- },
808
-
809
- /**
810
- Configures a callback to execute when a request completes. You must pass
811
- at least a target and action/method to this and optionally a status code.
812
- You may also pass additional parameters which will be passed along to your
813
- callback. If your callback handled the notification, it should return YES.
814
-
815
- ## Scoping With Status Codes
816
-
817
- If you pass a status code as the first option to this method, then your
818
- notification callback will only be called if the response status matches
819
- the code. For example, if you pass 201 (or SC.Request.CREATED) then
820
- your method will only be called if the response status from the server
821
- is 201.
822
-
823
- You can also pass "generic" status codes such as 200, 300, or 400, which
824
- will be invoked anytime the status code is the range if a more specific
825
- notifier was not registered first and returned YES.
826
-
827
- Finally, passing a status code of 0 or no status at all will cause your
828
- method to be executed no matter what the resulting status is unless a
829
- more specific notifier was registered and returned YES.
830
-
831
- ## Callback Format
832
-
833
- Your notification callback should expect to receive the Response object
834
- as the first parameter plus any additional parameters that you pass.
835
-
836
- @param {Number} status
837
- @param {Object} target
838
- @param {String|Function} action
839
- @param {Hash} params
840
- @returns {SC.Request} receiver
841
- */
842
- notify: function(status, target, action, params) {
843
- // normalize status
844
- var hasStatus = true;
845
- if (SC.typeOf(status) !== 'number') {
846
- params = $.makeArray(arguments).slice(2);
847
- action = target;
848
- target = status;
849
- status = 0;
850
- hasStatus = false;
851
- } else {
852
- params = $.makeArray(arguments).slice(3);
853
- }
854
-
855
- var listeners = get(this, 'listeners');
856
- if (!listeners) { set(this, 'listeners', listeners = {}); }
857
- if(!listeners[status]) { listeners[status] = []; }
858
-
859
- listeners[status].push({target: target, action: action, params: params});
860
-
861
- return this;
862
- }
863
-
864
- });
865
-
866
- SC.Request.reopenClass({
867
-
868
- /**
869
- Helper method for quickly setting up a GET request.
870
-
871
- @param {String} url of request
872
- @returns {SC.Request} receiver
873
- */
874
- getUrl: function(url) {
875
- return this.create().set('url', url).set('type', 'GET');
876
- },
877
-
878
- /**
879
- Helper method for quickly setting up a HEAD request.
880
-
881
- @param {String} url of request
882
- @returns {SC.Request} receiver
883
- */
884
- headUrl: function(url) {
885
- return this.create().set('url', url).set('type', 'HEAD');
886
- },
887
-
888
- /**
889
- Helper method for quickly setting up a DELETE request.
890
-
891
- @param {String} url of request
892
- @returns {SC.Request} receiver
893
- */
894
- deleteUrl: function(url) {
895
- return this.create().set('url', url).set('type', 'DELETE');
896
- },
897
-
898
- /**
899
- Helper method for quickly setting up a POST request.
900
-
901
- @param {String} url of request
902
- @param {String} body
903
- @returns {SC.Request} receiver
904
- */
905
- postUrl: function(url, body) {
906
- var req = this.create().set('url', url).set('type', 'POST');
907
- if (body) { set(req, 'body', body); }
908
- return req;
909
- },
910
-
911
- /**
912
- Helper method for quickly setting up a PUT request.
913
-
914
- @param {String} url of request
915
- @param {String} body
916
- @returns {SC.Request} receiver
917
- */
918
- putUrl: function(url, body) {
919
- var req = this.create().set('url', url).set('type', 'PUT');
920
- if (body) { set(req, 'body', body); }
921
- return req;
922
- }
923
-
924
- });
925
-
926
- /**
927
- @class
928
-
929
- The request manager coordinates all of the active XHR requests. It will
930
- only allow a certain number of requests to be active at a time; queuing
931
- any others. This allows you more precise control over which requests load
932
- in which order.
933
- */
934
- SC.Request.manager = SC.Object.create({
935
-
936
- /**
937
- Maximum number of concurrent requests allowed. 6 for all browsers.
938
-
939
- @type Number
940
- @default 6
941
- */
942
- maxRequests: 6,
943
-
944
- /**
945
- Current requests that are inflight.
946
-
947
- @type Array
948
- @default []
949
- */
950
- inflight: [],
951
-
952
- /**
953
- Requests that are pending and have not been started yet.
954
-
955
- @type Array
956
- @default []
957
- */
958
- pending: [],
959
-
960
-
961
- // ..........................................................
962
- // METHODS
963
- //
964
-
965
- /**
966
- Invoked by the send() method on a request. This will create a new low-
967
- level transport object and queue it if needed.
968
-
969
- @param {SC.Request} request the request to send
970
- @returns {SC.Object} response object
971
- */
972
- sendRequest: function(request) {
973
- if (!request) { return null; }
974
-
975
- // create low-level transport. copy all critical data for request over
976
- // so that if the request has been reconfigured the transport will still
977
- // work.
978
- var response = get(request, 'responseClass').create({request: request});
979
-
980
- // add to pending queue
981
- get(this, 'pending').pushObject(response);
982
- this.fireRequestIfNeeded();
983
-
984
- return response;
985
- },
986
-
987
- /**
988
- Cancels a specific request. If the request is pending it will simply
989
- be removed. Otherwise it will actually be cancelled.
990
-
991
- @param {Object} response a response object
992
- @returns {Boolean} YES if cancelled
993
- */
994
- cancel: function(response) {
995
- var pending = get(this, 'pending'),
996
- inflight = get(this, 'inflight'),
997
- idx;
998
-
999
- if (pending.indexOf(response) >= 0) {
1000
- this.propertyWillChange('pending');
1001
- pending.removeObject(response);
1002
- this.propertyDidChange('pending');
1003
- return true;
1004
- } else if (inflight.indexOf(response) >= 0) {
1005
- response.cancel();
1006
-
1007
- inflight.removeObject(response);
1008
- this.fireRequestIfNeeded();
1009
- return true;
1010
- }
1011
-
1012
- return false;
1013
- },
1014
-
1015
- /**
1016
- Cancels all inflight and pending requests.
1017
-
1018
- @returns {Boolean} YES if any items were cancelled.
1019
- */
1020
- cancelAll: function() {
1021
- if (get(this, 'pending').length || get(this, 'inflight').length) {
1022
- set(this, 'pending', []);
1023
- get(this, 'inflight').forEach(function(r) { r.cancel(); });
1024
- set(this, 'inflight', []);
1025
- return true;
1026
- }
1027
-
1028
- return false;
1029
- },
1030
-
1031
- /**
1032
- Checks the inflight queue. If there is an open slot, this will move a
1033
- request from pending to inflight.
1034
-
1035
- @returns {Object} receiver
1036
- */
1037
- fireRequestIfNeeded: function() {
1038
- var pending = get(this, 'pending'),
1039
- inflight = get(this, 'inflight'),
1040
- max = get(this, 'maxRequests'),
1041
- next;
1042
-
1043
- if ((pending.length>0) && (inflight.length<max)) {
1044
- next = pending.shiftObject();
1045
- inflight.pushObject(next);
1046
- next.fire();
1047
- }
1048
- },
1049
-
1050
- /**
1051
- Called by a response/transport object when finishes running. Removes
1052
- the transport from the queue and kicks off the next one.
1053
- */
1054
- transportDidClose: function(response) {
1055
- get(this, 'inflight').removeObject(response);
1056
- this.fireRequestIfNeeded();
1057
- }
1058
-
1059
- });
1060
-
1061
- })({});
1062
-
1063
-
1064
- (function(exports) {
1065
- // ==========================================================================
1066
- // Project: SproutCore AJAX
1067
- // Copyright: ©2011 Paul Chavard
1068
- // License: Licensed under MIT license (see license.js)
1069
- // ==========================================================================
1070
-
1071
-
1072
- })({});