PageRenderTime 79ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/reqwest/0.6.4/reqwest.js

https://gitlab.com/Mirros/cdnjs
JavaScript | 485 lines | 171 code | 25 blank | 289 comment | 69 complexity | ce5c193a7c7e5b2ef9dfe59d36b538a3 MD5 | raw file
  1. /*!
  2. * Reqwest! A general purpose XHR connection manager
  3. * (c) Dustin Diaz 2012
  4. * https://github.com/ded/reqwest
  5. * license MIT
  6. */
  7. (function (name, context, definition) {
  8. if (typeof module != 'undefined' && module.exports) module.exports = definition()
  9. else if (typeof define == 'function' && define.amd) define(definition)
  10. else context[name] = definition()
  11. })('reqwest', this, function () {
  12. var win = window
  13. , doc = document
  14. , twoHundo = /^20\d$/
  15. , byTag = 'getElementsByTagName'
  16. , readyState = 'readyState'
  17. , contentType = 'Content-Type'
  18. , requestedWith = 'X-Requested-With'
  19. , head = doc[byTag]('head')[0]
  20. , uniqid = 0
  21. , callbackPrefix = 'reqwest_' + (+new Date())
  22. , lastValue // data stored by the most recent JSONP callback
  23. , xmlHttpRequest = 'XMLHttpRequest'
  24. , noop = function () {}
  25. var isArray = typeof Array.isArray == 'function' ? Array.isArray : function (a) {
  26. return a instanceof Array
  27. }
  28. var defaultHeaders = {
  29. contentType: 'application/x-www-form-urlencoded'
  30. , requestedWith: xmlHttpRequest
  31. , accept: {
  32. '*': 'text/javascript, text/html, application/xml, text/xml, */*'
  33. , xml: 'application/xml, text/xml'
  34. , html: 'text/html'
  35. , text: 'text/plain'
  36. , json: 'application/json, text/javascript'
  37. , js: 'application/javascript, text/javascript'
  38. }
  39. }
  40. var xhr = win[xmlHttpRequest] ?
  41. function () {
  42. return new XMLHttpRequest()
  43. } :
  44. function () {
  45. return new ActiveXObject('Microsoft.XMLHTTP')
  46. }
  47. function handleReadyState(o, success, error) {
  48. return function () {
  49. if (o && o[readyState] == 4) {
  50. o.onreadystatechange = noop;
  51. if (twoHundo.test(o.status)) {
  52. success(o)
  53. } else {
  54. error(o)
  55. }
  56. }
  57. }
  58. }
  59. function setHeaders(http, o) {
  60. var headers = o.headers || {}, h
  61. headers.Accept = headers.Accept || defaultHeaders.accept[o.type] || defaultHeaders.accept['*']
  62. // breaks cross-origin requests with legacy browsers
  63. if (!o.crossOrigin && !headers[requestedWith]) headers[requestedWith] = defaultHeaders.requestedWith
  64. if (!headers[contentType]) headers[contentType] = o.contentType || defaultHeaders.contentType
  65. for (h in headers) {
  66. headers.hasOwnProperty(h) && http.setRequestHeader(h, headers[h])
  67. }
  68. }
  69. function setCredentials(http, o) {
  70. if (typeof o.withCredentials !== "undefined" && typeof http.withCredentials !== "undefined") {
  71. http.withCredentials = !!o.withCredentials
  72. }
  73. }
  74. function generalCallback(data) {
  75. lastValue = data
  76. }
  77. function urlappend(url, s) {
  78. return url + (/\?/.test(url) ? '&' : '?') + s
  79. }
  80. function handleJsonp(o, fn, err, url) {
  81. var reqId = uniqid++
  82. , cbkey = o.jsonpCallback || 'callback' // the 'callback' key
  83. , cbval = o.jsonpCallbackName || reqwest.getcallbackPrefix(reqId)
  84. // , cbval = o.jsonpCallbackName || ('reqwest_' + reqId) // the 'callback' value
  85. , cbreg = new RegExp('((^|\\?|&)' + cbkey + ')=([^&]+)')
  86. , match = url.match(cbreg)
  87. , script = doc.createElement('script')
  88. , loaded = 0
  89. , isIE10 = navigator.userAgent.indexOf('MSIE 10.0') !== -1
  90. if (match) {
  91. if (match[3] === '?') {
  92. url = url.replace(cbreg, '$1=' + cbval) // wildcard callback func name
  93. } else {
  94. cbval = match[3] // provided callback func name
  95. }
  96. } else {
  97. url = urlappend(url, cbkey + '=' + cbval) // no callback details, add 'em
  98. }
  99. win[cbval] = generalCallback
  100. script.type = 'text/javascript'
  101. script.src = url
  102. script.async = true
  103. if (typeof script.onreadystatechange !== 'undefined' && !isIE10) {
  104. // need this for IE due to out-of-order onreadystatechange(), binding script
  105. // execution to an event listener gives us control over when the script
  106. // is executed. See http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
  107. //
  108. // if this hack is used in IE10 jsonp callback are never called
  109. script.event = 'onclick'
  110. script.htmlFor = script.id = '_reqwest_' + reqId
  111. }
  112. script.onload = script.onreadystatechange = function () {
  113. if ((script[readyState] && script[readyState] !== 'complete' && script[readyState] !== 'loaded') || loaded) {
  114. return false
  115. }
  116. script.onload = script.onreadystatechange = null
  117. script.onclick && script.onclick()
  118. // Call the user callback with the last value stored and clean up values and scripts.
  119. o.success && o.success(lastValue)
  120. lastValue = undefined
  121. head.removeChild(script)
  122. loaded = 1
  123. }
  124. // Add the script to the DOM head
  125. head.appendChild(script)
  126. }
  127. function getRequest(o, fn, err) {
  128. var method = (o.method || 'GET').toUpperCase()
  129. , url = typeof o === 'string' ? o : o.url
  130. // convert non-string objects to query-string form unless o.processData is false
  131. , data = (o.processData !== false && o.data && typeof o.data !== 'string')
  132. ? reqwest.toQueryString(o.data)
  133. : (o.data || null)
  134. , http
  135. // if we're working on a GET request and we have data then we should append
  136. // query string to end of URL and not post data
  137. if ((o.type == 'jsonp' || method == 'GET') && data) {
  138. url = urlappend(url, data)
  139. data = null
  140. }
  141. if (o.type == 'jsonp') return handleJsonp(o, fn, err, url)
  142. http = xhr()
  143. http.open(method, url, true)
  144. setHeaders(http, o)
  145. setCredentials(http, o)
  146. http.onreadystatechange = handleReadyState(http, fn, err)
  147. o.before && o.before(http)
  148. http.send(data)
  149. return http
  150. }
  151. function Reqwest(o, fn) {
  152. this.o = o
  153. this.fn = fn
  154. init.apply(this, arguments)
  155. }
  156. function setType(url) {
  157. var m = url.match(/\.(json|jsonp|html|xml)(\?|$)/)
  158. return m ? m[1] : 'js'
  159. }
  160. function init(o, fn) {
  161. this.url = typeof o == 'string' ? o : o.url
  162. this.timeout = null
  163. // whether request has been fulfilled for purpose
  164. // of tracking the Promises
  165. this._fulfilled = false
  166. // success handlers
  167. this._fulfillmentHandlers = []
  168. // error handlers
  169. this._errorHandlers = []
  170. // complete (both success and fail) handlers
  171. this._completeHandlers = []
  172. this._erred = false
  173. this._responseArgs = {}
  174. var self = this
  175. , type = o.type || setType(this.url)
  176. fn = fn || function () {}
  177. if (o.timeout) {
  178. this.timeout = setTimeout(function () {
  179. self.abort()
  180. }, o.timeout)
  181. }
  182. if (o.success) {
  183. this._fulfillmentHandlers.push(function () {
  184. o.success.apply(o, arguments)
  185. })
  186. }
  187. if (o.error) {
  188. this._errorHandlers.push(function () {
  189. o.error.apply(o, arguments)
  190. })
  191. }
  192. if (o.complete) {
  193. this._completeHandlers.push(function () {
  194. o.complete.apply(o, arguments)
  195. })
  196. }
  197. function complete(resp) {
  198. o.timeout && clearTimeout(self.timeout)
  199. self.timeout = null
  200. while (self._completeHandlers.length > 0) {
  201. self._completeHandlers.shift()(resp)
  202. }
  203. }
  204. function success(resp) {
  205. var r = resp.responseText
  206. if (r) {
  207. switch (type) {
  208. case 'json':
  209. try {
  210. resp = win.JSON ? win.JSON.parse(r) : eval('(' + r + ')')
  211. } catch (err) {
  212. return error(resp, 'Could not parse JSON in response', err)
  213. }
  214. break;
  215. case 'js':
  216. resp = eval(r)
  217. break;
  218. case 'html':
  219. resp = r
  220. break;
  221. case 'xml':
  222. resp = resp.responseXML;
  223. break;
  224. }
  225. }
  226. self._responseArgs.resp = resp
  227. self._fulfilled = true
  228. fn(resp)
  229. while (self._fulfillmentHandlers.length > 0) {
  230. self._fulfillmentHandlers.shift()(resp)
  231. }
  232. complete(resp)
  233. }
  234. function error(resp, msg, t) {
  235. self._responseArgs.resp = resp
  236. self._responseArgs.msg = msg
  237. self._responseArgs.t = t
  238. self._erred = true
  239. while (self._errorHandlers.length > 0) {
  240. self._errorHandlers.shift()(resp, msg, t)
  241. }
  242. complete(resp)
  243. }
  244. this.request = getRequest(o, success, error)
  245. }
  246. Reqwest.prototype = {
  247. abort: function () {
  248. this.request.abort()
  249. }
  250. , retry: function () {
  251. init.call(this, this.o, this.fn)
  252. }
  253. /**
  254. * Small deviation from the Promises A CommonJs specification
  255. * http://wiki.commonjs.org/wiki/Promises/A
  256. */
  257. /**
  258. * `then` will execute upon successful requests
  259. */
  260. , then: function (success, fail) {
  261. if (this._fulfilled) {
  262. success(this._responseArgs.resp)
  263. } else if (this._erred) {
  264. fail(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
  265. } else {
  266. this._fulfillmentHandlers.push(success)
  267. this._errorHandlers.push(fail)
  268. }
  269. return this
  270. }
  271. /**
  272. * `always` will execute whether the request succeeds or fails
  273. */
  274. , always: function (fn) {
  275. if (this._fulfilled || this._erred) {
  276. fn(this._responseArgs.resp)
  277. } else {
  278. this._completeHandlers.push(fn)
  279. }
  280. return this
  281. }
  282. /**
  283. * `fail` will execute when the request fails
  284. */
  285. , fail: function (fn) {
  286. if (this._erred) {
  287. fn(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
  288. } else {
  289. this._errorHandlers.push(fn)
  290. }
  291. return this
  292. }
  293. }
  294. function reqwest(o, fn) {
  295. return new Reqwest(o, fn)
  296. }
  297. // normalize newline variants according to spec -> CRLF
  298. function normalize(s) {
  299. return s ? s.replace(/\r?\n/g, '\r\n') : ''
  300. }
  301. function serial(el, cb) {
  302. var n = el.name
  303. , t = el.tagName.toLowerCase()
  304. , optCb = function (o) {
  305. // IE gives value="" even where there is no value attribute
  306. // 'specified' ref: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-862529273
  307. if (o && !o.disabled)
  308. cb(n, normalize(o.attributes.value && o.attributes.value.specified ? o.value : o.text))
  309. }
  310. // don't serialize elements that are disabled or without a name
  311. if (el.disabled || !n) return;
  312. switch (t) {
  313. case 'input':
  314. if (!/reset|button|image|file/i.test(el.type)) {
  315. var ch = /checkbox/i.test(el.type)
  316. , ra = /radio/i.test(el.type)
  317. , val = el.value;
  318. // WebKit gives us "" instead of "on" if a checkbox has no value, so correct it here
  319. (!(ch || ra) || el.checked) && cb(n, normalize(ch && val === '' ? 'on' : val))
  320. }
  321. break;
  322. case 'textarea':
  323. cb(n, normalize(el.value))
  324. break;
  325. case 'select':
  326. if (el.type.toLowerCase() === 'select-one') {
  327. optCb(el.selectedIndex >= 0 ? el.options[el.selectedIndex] : null)
  328. } else {
  329. for (var i = 0; el.length && i < el.length; i++) {
  330. el.options[i].selected && optCb(el.options[i])
  331. }
  332. }
  333. break;
  334. }
  335. }
  336. // collect up all form elements found from the passed argument elements all
  337. // the way down to child elements; pass a '<form>' or form fields.
  338. // called with 'this'=callback to use for serial() on each element
  339. function eachFormElement() {
  340. var cb = this
  341. , e, i, j
  342. , serializeSubtags = function (e, tags) {
  343. for (var i = 0; i < tags.length; i++) {
  344. var fa = e[byTag](tags[i])
  345. for (j = 0; j < fa.length; j++) serial(fa[j], cb)
  346. }
  347. }
  348. for (i = 0; i < arguments.length; i++) {
  349. e = arguments[i]
  350. if (/input|select|textarea/i.test(e.tagName)) serial(e, cb)
  351. serializeSubtags(e, [ 'input', 'select', 'textarea' ])
  352. }
  353. }
  354. // standard query string style serialization
  355. function serializeQueryString() {
  356. return reqwest.toQueryString(reqwest.serializeArray.apply(null, arguments))
  357. }
  358. // { 'name': 'value', ... } style serialization
  359. function serializeHash() {
  360. var hash = {}
  361. eachFormElement.apply(function (name, value) {
  362. if (name in hash) {
  363. hash[name] && !isArray(hash[name]) && (hash[name] = [hash[name]])
  364. hash[name].push(value)
  365. } else hash[name] = value
  366. }, arguments)
  367. return hash
  368. }
  369. // [ { name: 'name', value: 'value' }, ... ] style serialization
  370. reqwest.serializeArray = function () {
  371. var arr = []
  372. eachFormElement.apply(function (name, value) {
  373. arr.push({name: name, value: value})
  374. }, arguments)
  375. return arr
  376. }
  377. reqwest.serialize = function () {
  378. if (arguments.length === 0) return ''
  379. var opt, fn
  380. , args = Array.prototype.slice.call(arguments, 0)
  381. opt = args.pop()
  382. opt && opt.nodeType && args.push(opt) && (opt = null)
  383. opt && (opt = opt.type)
  384. if (opt == 'map') fn = serializeHash
  385. else if (opt == 'array') fn = reqwest.serializeArray
  386. else fn = serializeQueryString
  387. return fn.apply(null, args)
  388. }
  389. reqwest.toQueryString = function (o) {
  390. var qs = '', i
  391. , enc = encodeURIComponent
  392. , push = function (k, v) {
  393. qs += enc(k) + '=' + enc(v) + '&'
  394. }
  395. if (isArray(o)) {
  396. for (i = 0; o && i < o.length; i++) push(o[i].name, o[i].value)
  397. } else {
  398. for (var k in o) {
  399. if (!Object.hasOwnProperty.call(o, k)) continue;
  400. var v = o[k]
  401. if (isArray(v)) {
  402. for (i = 0; i < v.length; i++) push(k, v[i])
  403. } else push(k, o[k])
  404. }
  405. }
  406. // spaces should be + according to spec
  407. return qs.replace(/&$/, '').replace(/%20/g, '+')
  408. }
  409. reqwest.getcallbackPrefix = function (reqId) {
  410. return callbackPrefix
  411. }
  412. // jQuery and Zepto compatibility, differences can be remapped here so you can call
  413. // .ajax.compat(options, callback)
  414. reqwest.compat = function (o, fn) {
  415. if (o) {
  416. o.type && (o.method = o.type) && delete o.type
  417. o.dataType && (o.type = o.dataType)
  418. o.jsonpCallback && (o.jsonpCallbackName = o.jsonpCallback) && delete o.jsonpCallback
  419. o.jsonp && (o.jsonpCallback = o.jsonp)
  420. }
  421. return new Reqwest(o, fn)
  422. }
  423. return reqwest
  424. });