rasputin 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- })({});