| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved. | 
					
						
							|  |  |  |  * Microsoft Open Technologies would like to thank its contributors, a list | 
					
						
							|  |  |  |  * of whom are at http://rx.codeplex.com/wikipage?title=Contributors.
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); you | 
					
						
							|  |  |  |  * may not use this file except in compliance with the License. You may | 
					
						
							|  |  |  |  * obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | 
					
						
							|  |  |  |  * implied. See the License for the specific language governing permissions | 
					
						
							|  |  |  |  * and limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-23 13:40:26 -07:00
										 |  |  | import debugFactory from 'debug'; | 
					
						
							| 
									
										
										
										
											2015-12-29 17:35:50 -08:00
										 |  |  | import { Observable, AnonymousObservable, helpers } from 'rx'; | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-27 11:34:44 -08:00
										 |  |  | const debug = debugFactory('fcc:ajax$'); | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | const root = typeof window !== 'undefined' ? window : {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Gets the proper XMLHttpRequest for support for older IE
 | 
					
						
							|  |  |  | function getXMLHttpRequest() { | 
					
						
							|  |  |  |   if (root.XMLHttpRequest) { | 
					
						
							|  |  |  |     return new root.XMLHttpRequest(); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     var progId; | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       var progIds = [ | 
					
						
							|  |  |  |         'Msxml2.XMLHTTP', | 
					
						
							|  |  |  |         'Microsoft.XMLHTTP', | 
					
						
							|  |  |  |         'Msxml2.XMLHTTP.4.0' | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  |       for (var i = 0; i < 3; i++) { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           progId = progIds[i]; | 
					
						
							|  |  |  |           if (new root.ActiveXObject(progId)) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           // purposely do nothing
 | 
					
						
							|  |  |  |           helpers.noop(e); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return new root.ActiveXObject(progId); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       throw new Error('XMLHttpRequest is not supported by your browser'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Get CORS support even for older IE
 | 
					
						
							|  |  |  | function getCORSRequest() { | 
					
						
							|  |  |  |   var xhr = new root.XMLHttpRequest(); | 
					
						
							|  |  |  |   if ('withCredentials' in xhr) { | 
					
						
							|  |  |  |     return xhr; | 
					
						
							|  |  |  |   } else if (root.XDomainRequest) { | 
					
						
							|  |  |  |     return new XDomainRequest(); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     throw new Error('CORS is not supported by your browser'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 11:22:39 -08:00
										 |  |  | function parseXhrResponse(responseType, xhr) { | 
					
						
							|  |  |  |   switch (responseType) { | 
					
						
							|  |  |  |     case 'json': | 
					
						
							|  |  |  |       if ('response' in xhr) { | 
					
						
							|  |  |  |         return xhr.responseType ? | 
					
						
							|  |  |  |           xhr.response : | 
					
						
							|  |  |  |           JSON.parse(xhr.response || xhr.responseText || 'null'); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         return JSON.parse(xhr.responseText || 'null'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     case 'xml': | 
					
						
							|  |  |  |       return xhr.responseXML; | 
					
						
							|  |  |  |     case 'text': | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return ('response' in xhr) ? xhr.response : xhr.responseText; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | function normalizeAjaxSuccessEvent(e, xhr, settings) { | 
					
						
							|  |  |  |   return { | 
					
						
							| 
									
										
										
										
											2018-01-29 11:22:39 -08:00
										 |  |  |     response: parseXhrResponse(settings.responseType || xhr.responseType, xhr), | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  |     status: xhr.status, | 
					
						
							|  |  |  |     responseType: xhr.responseType, | 
					
						
							|  |  |  |     xhr: xhr, | 
					
						
							|  |  |  |     originalEvent: e | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function normalizeAjaxErrorEvent(e, xhr, type) { | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     type: type, | 
					
						
							|  |  |  |     status: xhr.status, | 
					
						
							|  |  |  |     xhr: xhr, | 
					
						
							|  |  |  |     originalEvent: e | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Creates an observable for an Ajax request with either a settings object | 
					
						
							|  |  |  |  * with url, headers, etc or a string for a URL. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @example | 
					
						
							|  |  |  |  *   source = Rx.DOM.ajax('/products'); | 
					
						
							|  |  |  |  *   source = Rx.DOM.ajax( url: 'products', method: 'GET' }); | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-05-17 10:25:20 -07:00
										 |  |  |  * interface Options { | 
					
						
							|  |  |  |  *   url: String, // URL of the request
 | 
					
						
							|  |  |  |  *   body?: Object, // The body of the request
 | 
					
						
							|  |  |  |  *   method? = 'GET' : 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', | 
					
						
							|  |  |  |  *   async? = true: Boolean, // Whether the request is async
 | 
					
						
							|  |  |  |  *   headers?: Object, // optional headers
 | 
					
						
							|  |  |  |  *   crossDomain?: true // if a cross domain request, else false
 | 
					
						
							|  |  |  |  * } | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-05-17 10:25:20 -07:00
										 |  |  |  * ajax$(url?: String, options: Options) => Observable[XMLHttpRequest] | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | export function ajax$(options) { | 
					
						
							|  |  |  |   var settings = { | 
					
						
							|  |  |  |     method: 'GET', | 
					
						
							|  |  |  |     crossDomain: false, | 
					
						
							|  |  |  |     async: true, | 
					
						
							|  |  |  |     headers: {}, | 
					
						
							|  |  |  |     responseType: 'text', | 
					
						
							|  |  |  |     createXHR: function() { | 
					
						
							|  |  |  |       return this.crossDomain ? getCORSRequest() : getXMLHttpRequest(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     normalizeError: normalizeAjaxErrorEvent, | 
					
						
							|  |  |  |     normalizeSuccess: normalizeAjaxSuccessEvent | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (typeof options === 'string') { | 
					
						
							|  |  |  |     settings.url = options; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     for (var prop in options) { | 
					
						
							|  |  |  |       if (hasOwnProperty.call(options, prop)) { | 
					
						
							|  |  |  |         settings[prop] = options[prop]; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var normalizeError = settings.normalizeError; | 
					
						
							|  |  |  |   var normalizeSuccess = settings.normalizeSuccess; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!settings.crossDomain && !settings.headers['X-Requested-With']) { | 
					
						
							|  |  |  |     settings.headers['X-Requested-With'] = 'XMLHttpRequest'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   settings.hasContent = typeof settings.body !== 'undefined'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return new AnonymousObservable(function(observer) { | 
					
						
							|  |  |  |     var isDone = false; | 
					
						
							|  |  |  |     var xhr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var processResponse = function(xhr, e) { | 
					
						
							|  |  |  |       var status = xhr.status === 1223 ? 204 : xhr.status; | 
					
						
							|  |  |  |       if ((status >= 200 && status <= 300) || status === 0 || status === '') { | 
					
						
							| 
									
										
										
										
											2015-12-29 17:35:50 -08:00
										 |  |  |         try { | 
					
						
							|  |  |  |           observer.onNext(normalizeSuccess(e, xhr, settings)); | 
					
						
							|  |  |  |           observer.onCompleted(); | 
					
						
							|  |  |  |         } catch (err) { | 
					
						
							|  |  |  |           observer.onError(err); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         observer.onError(normalizeError(e, xhr, 'error')); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       isDone = true; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       xhr = settings.createXHR(); | 
					
						
							|  |  |  |     } catch (err) { | 
					
						
							|  |  |  |       observer.onError(err); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       if (settings.user) { | 
					
						
							|  |  |  |         xhr.open( | 
					
						
							|  |  |  |           settings.method, | 
					
						
							|  |  |  |           settings.url, | 
					
						
							|  |  |  |           settings.async, | 
					
						
							|  |  |  |           settings.user, | 
					
						
							|  |  |  |           settings.password | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         xhr.open(settings.method, settings.url, settings.async); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       var headers = settings.headers; | 
					
						
							|  |  |  |       for (var header in headers) { | 
					
						
							|  |  |  |         if (hasOwnProperty.call(headers, header)) { | 
					
						
							|  |  |  |           xhr.setRequestHeader(header, headers[header]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if ( | 
					
						
							|  |  |  |         !xhr.upload || | 
					
						
							|  |  |  |         (!('withCredentials' in xhr) && root.XDomainRequest) | 
					
						
							|  |  |  |       ) { | 
					
						
							|  |  |  |         xhr.onload = function(e) { | 
					
						
							|  |  |  |           if (settings.progressObserver) { | 
					
						
							|  |  |  |             settings.progressObserver.onNext(e); | 
					
						
							|  |  |  |             settings.progressObserver.onCompleted(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           processResponse(xhr, e); | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (settings.progressObserver) { | 
					
						
							|  |  |  |           xhr.onprogress = function(e) { | 
					
						
							|  |  |  |             settings.progressObserver.onNext(e); | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         xhr.onerror = function(e) { | 
					
						
							|  |  |  |           if (settings.progressObserver) { | 
					
						
							|  |  |  |             settings.progressObserver.onError(e); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           observer.onError(normalizeError(e, xhr, 'error')); | 
					
						
							|  |  |  |           isDone = true; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         xhr.onabort = function(e) { | 
					
						
							|  |  |  |           if (settings.progressObserver) { | 
					
						
							|  |  |  |             settings.progressObserver.onError(e); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           observer.onError(normalizeError(e, xhr, 'abort')); | 
					
						
							|  |  |  |           isDone = true; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         xhr.onreadystatechange = function(e) { | 
					
						
							|  |  |  |           if (xhr.readyState === 4) { | 
					
						
							|  |  |  |             processResponse(xhr, e); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-23 13:40:26 -07:00
										 |  |  |       debug( | 
					
						
							|  |  |  |         'ajax$ sending content', | 
					
						
							|  |  |  |         settings.hasContent && settings.body | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  |       xhr.send(settings.hasContent && settings.body || null); | 
					
						
							| 
									
										
										
										
											2015-12-29 17:35:50 -08:00
										 |  |  |     } catch (err) { | 
					
						
							|  |  |  |       observer.onError(err); | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return function() { | 
					
						
							|  |  |  |       if (!isDone && xhr.readyState !== 4) { xhr.abort(); } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-17 10:25:20 -07:00
										 |  |  | // Creates an observable sequence from an Ajax POST Request with the body.
 | 
					
						
							|  |  |  | // post$(url: String, body: Object) => Observable[Any]
 | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | export function post$(url, body) { | 
					
						
							| 
									
										
										
										
											2015-12-29 17:35:50 -08:00
										 |  |  |   try { | 
					
						
							|  |  |  |     body = JSON.stringify(body); | 
					
						
							|  |  |  |   } catch (e) { | 
					
						
							|  |  |  |     return Observable.throw(e); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-23 13:40:26 -07:00
										 |  |  |   return ajax$({ url, body, method: 'POST' }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-17 10:25:20 -07:00
										 |  |  | // postJSON$(url: String, body: Object) => Observable[Object]
 | 
					
						
							| 
									
										
										
										
											2015-07-23 13:40:26 -07:00
										 |  |  | export function postJSON$(url, body) { | 
					
						
							| 
									
										
										
										
											2015-12-29 17:35:50 -08:00
										 |  |  |   try { | 
					
						
							|  |  |  |     body = JSON.stringify(body); | 
					
						
							|  |  |  |   } catch (e) { | 
					
						
							|  |  |  |     return Observable.throw(e); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-23 13:40:26 -07:00
										 |  |  |   return ajax$({ | 
					
						
							|  |  |  |     url, | 
					
						
							| 
									
										
										
										
											2015-12-29 17:35:50 -08:00
										 |  |  |     body, | 
					
						
							| 
									
										
										
										
											2015-07-23 13:40:26 -07:00
										 |  |  |     method: 'POST', | 
					
						
							| 
									
										
										
										
											2015-10-26 17:39:38 -07:00
										 |  |  |     responseType: 'json', | 
					
						
							| 
									
										
										
										
											2016-01-09 19:59:17 -08:00
										 |  |  |     headers: { | 
					
						
							|  |  |  |       'Content-Type': 'application/json', | 
					
						
							| 
									
										
										
										
											2016-04-15 23:48:02 +08:00
										 |  |  |       Accept: 'application/json' | 
					
						
							| 
									
										
										
										
											2018-01-29 11:22:39 -08:00
										 |  |  |     }, | 
					
						
							|  |  |  |     normalizeError: (e, xhr) => parseXhrResponse('json', xhr) | 
					
						
							| 
									
										
										
										
											2016-01-09 23:05:53 -08:00
										 |  |  |   }) | 
					
						
							|  |  |  |     .map(({ response }) => response); | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-17 10:25:20 -07:00
										 |  |  | // Creates an observable sequence from an Ajax GET Request with the body.
 | 
					
						
							|  |  |  | // get$(url: String) => Obserable[Any]
 | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | export function get$(url) { | 
					
						
							|  |  |  |   return ajax$({ url: url }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |   * Creates an observable sequence from JSON from an Ajax request | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   * @param {String} url The URL to GET | 
					
						
							|  |  |  |   * @returns {Observable} The observable sequence which contains the parsed JSON | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-05-17 10:25:20 -07:00
										 |  |  | // getJSON$(url: String) => Observable[Object];
 | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | export function getJSON$(url) { | 
					
						
							| 
									
										
										
										
											2016-01-09 19:59:17 -08:00
										 |  |  |   return ajax$({ | 
					
						
							|  |  |  |     url: url, | 
					
						
							|  |  |  |     responseType: 'json', | 
					
						
							|  |  |  |     headers: { | 
					
						
							|  |  |  |       'Content-Type': 'application/json', | 
					
						
							| 
									
										
										
										
											2016-04-15 23:48:02 +08:00
										 |  |  |       Accept: 'application/json' | 
					
						
							| 
									
										
										
										
											2018-01-29 11:22:39 -08:00
										 |  |  |     }, | 
					
						
							|  |  |  |     normalizeError: (e, xhr) => parseXhrResponse('json', xhr) | 
					
						
							| 
									
										
										
										
											2016-01-09 23:05:53 -08:00
										 |  |  |   }).map(({ response }) => response); | 
					
						
							| 
									
										
										
										
											2015-07-22 23:10:57 -07:00
										 |  |  | } |