0) {
309 | self._completeHandlers.shift()(resp)
310 | }
311 | }
312 |
313 | function success (resp) {
314 | var type = o['type'] || resp && setType(resp.getResponseHeader('Content-Type')) // resp can be undefined in IE
315 | resp = (type !== 'jsonp') ? self.request : resp
316 | // use global data filter on response text
317 | var filteredResponse = globalSetupOptions.dataFilter(resp.responseText, type)
318 | , r = filteredResponse
319 | try {
320 | resp.responseText = r
321 | } catch (e) {
322 | // can't assign this in IE<=8, just ignore
323 | }
324 | if (r) {
325 | switch (type) {
326 | case 'json':
327 | try {
328 | resp = context.JSON ? context.JSON.parse(r) : eval('(' + r + ')')
329 | } catch (err) {
330 | return error(resp, 'Could not parse JSON in response', err)
331 | }
332 | break
333 | case 'js':
334 | resp = eval(r)
335 | break
336 | case 'html':
337 | resp = r
338 | break
339 | case 'xml':
340 | resp = resp.responseXML
341 | && resp.responseXML.parseError // IE trololo
342 | && resp.responseXML.parseError.errorCode
343 | && resp.responseXML.parseError.reason
344 | ? null
345 | : resp.responseXML
346 | break
347 | }
348 | }
349 |
350 | self._responseArgs.resp = resp
351 | self._fulfilled = true
352 | fn(resp)
353 | self._successHandler(resp)
354 | while (self._fulfillmentHandlers.length > 0) {
355 | resp = self._fulfillmentHandlers.shift()(resp)
356 | }
357 |
358 | complete(resp)
359 | }
360 |
361 | function timedOut() {
362 | self._timedOut = true
363 | self.request.abort()
364 | }
365 |
366 | function error(resp, msg, t) {
367 | resp = self.request
368 | self._responseArgs.resp = resp
369 | self._responseArgs.msg = msg
370 | self._responseArgs.t = t
371 | self._erred = true
372 | while (self._errorHandlers.length > 0) {
373 | self._errorHandlers.shift()(resp, msg, t)
374 | }
375 | complete(resp)
376 | }
377 |
378 | this.request = getRequest.call(this, success, error)
379 | }
380 |
381 | Reqwest.prototype = {
382 | abort: function () {
383 | this._aborted = true
384 | this.request.abort()
385 | }
386 |
387 | , retry: function () {
388 | init.call(this, this.o, this.fn)
389 | }
390 |
391 | /**
392 | * Small deviation from the Promises A CommonJs specification
393 | * http://wiki.commonjs.org/wiki/Promises/A
394 | */
395 |
396 | /**
397 | * `then` will execute upon successful requests
398 | */
399 | , then: function (success, fail) {
400 | success = success || function () {}
401 | fail = fail || function () {}
402 | if (this._fulfilled) {
403 | this._responseArgs.resp = success(this._responseArgs.resp)
404 | } else if (this._erred) {
405 | fail(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
406 | } else {
407 | this._fulfillmentHandlers.push(success)
408 | this._errorHandlers.push(fail)
409 | }
410 | return this
411 | }
412 |
413 | /**
414 | * `always` will execute whether the request succeeds or fails
415 | */
416 | , always: function (fn) {
417 | if (this._fulfilled || this._erred) {
418 | fn(this._responseArgs.resp)
419 | } else {
420 | this._completeHandlers.push(fn)
421 | }
422 | return this
423 | }
424 |
425 | /**
426 | * `fail` will execute when the request fails
427 | */
428 | , fail: function (fn) {
429 | if (this._erred) {
430 | fn(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
431 | } else {
432 | this._errorHandlers.push(fn)
433 | }
434 | return this
435 | }
436 | , 'catch': function (fn) {
437 | return this.fail(fn)
438 | }
439 | }
440 |
441 | function reqwest(o, fn) {
442 | return new Reqwest(o, fn)
443 | }
444 |
445 | // normalize newline variants according to spec -> CRLF
446 | function normalize(s) {
447 | return s ? s.replace(/\r?\n/g, '\r\n') : ''
448 | }
449 |
450 | function serial(el, cb) {
451 | var n = el.name
452 | , t = el.tagName.toLowerCase()
453 | , optCb = function (o) {
454 | // IE gives value="" even where there is no value attribute
455 | // 'specified' ref: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-862529273
456 | if (o && !o['disabled'])
457 | cb(n, normalize(o['attributes']['value'] && o['attributes']['value']['specified'] ? o['value'] : o['text']))
458 | }
459 | , ch, ra, val, i
460 |
461 | // don't serialize elements that are disabled or without a name
462 | if (el.disabled || !n) return
463 |
464 | switch (t) {
465 | case 'input':
466 | if (!/reset|button|image|file/i.test(el.type)) {
467 | ch = /checkbox/i.test(el.type)
468 | ra = /radio/i.test(el.type)
469 | val = el.value
470 | // WebKit gives us "" instead of "on" if a checkbox has no value, so correct it here
471 | ;(!(ch || ra) || el.checked) && cb(n, normalize(ch && val === '' ? 'on' : val))
472 | }
473 | break
474 | case 'textarea':
475 | cb(n, normalize(el.value))
476 | break
477 | case 'select':
478 | if (el.type.toLowerCase() === 'select-one') {
479 | optCb(el.selectedIndex >= 0 ? el.options[el.selectedIndex] : null)
480 | } else {
481 | for (i = 0; el.length && i < el.length; i++) {
482 | el.options[i].selected && optCb(el.options[i])
483 | }
484 | }
485 | break
486 | }
487 | }
488 |
489 | // collect up all form elements found from the passed argument elements all
490 | // the way down to child elements; pass a '