hoarder-js 0.0.1 → 0.0.2
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.
- data/CHANGELOG +2 -0
- data/Gemfile.lock +2 -2
- data/Manifest +14 -3
- data/assets/scripts/coffee/hoarder/form/form.coffee +47 -44
- data/assets/scripts/coffee/hoarder/form/form_serializer.coffee +23 -0
- data/assets/scripts/coffee/hoarder/form_manager.coffee +35 -19
- data/assets/scripts/coffee/hoarder/submitter/form_submitter.coffee +10 -15
- data/assets/scripts/coffee/hoarder/submitter/submitters/base_submitter.coffee +11 -0
- data/assets/scripts/coffee/hoarder/submitter/submitters/polling_submitter.coffee +30 -27
- data/assets/scripts/coffee/hoarder/submitter/submitters/simple_submitter.coffee +11 -21
- data/assets/scripts/coffee/hoarder/validator/constraints/alpha_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/alphanumeric_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/base_constraint.coffee +10 -0
- data/assets/scripts/coffee/hoarder/validator/constraints/credit_card_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/email_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/max_length_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/min_length_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/numeric_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/phone_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/constraints/required_constraint.coffee +8 -14
- data/assets/scripts/coffee/hoarder/validator/form_validator.coffee +30 -25
- data/assets/scripts/coffee/hoarder/validator/rules/validation_rule.coffee +10 -0
- data/assets/scripts/js/lib/bonzo.js +1151 -0
- data/assets/scripts/js/lib/qwery.js +369 -0
- data/assets/scripts/js/lib/reqwest.js +565 -0
- data/assets/scripts/js/patches/event_listeners.js +73 -0
- data/bin/hoarder.js +2807 -369
- data/hoarder-js.gemspec +3 -3
- data/spec/jasmine.yml +3 -0
- data/spec/runner.html +44 -34
- data/spec/support/fixtures.coffee +19 -0
- data/spec/support/lib/jasmine-fixture.js +506 -0
- data/spec/support/lib/jquery-1.7.1.min.js +4 -0
- data/spec/support/mocks.coffee +12 -37
- data/spec/support/requirements.coffee +0 -1
- data/spec/tests/form/form_serializer_spec.coffee +78 -0
- data/spec/tests/form/form_spec.coffee +127 -0
- data/spec/tests/form_manager_spec.coffee +128 -40
- data/spec/tests/submitter/form_submitter_spec.coffee +59 -42
- data/spec/tests/submitter/submitters/polling_submitter_spec.coffee +102 -57
- data/spec/tests/submitter/submitters/simple_submitter_spec.coffee +42 -16
- data/spec/tests/validator/constraints_spec.coffee +65 -57
- data/spec/tests/validator/form_validator_spec.coffee +39 -23
- data/spec/tests/validator/validation_rule_spec.coffee +14 -0
- metadata +16 -5
- data/assets/scripts/coffee/hoarder/form/form_element.coffee +0 -22
- data/assets/scripts/coffee/hoarder/validator/error/validation_error.coffee +0 -9
- data/assets/scripts/js/lib/jquery.js +0 -5
@@ -0,0 +1,369 @@
|
|
1
|
+
/*!
|
2
|
+
* @preserve Qwery - A Blazing Fast query selector engine
|
3
|
+
* https://github.com/ded/qwery
|
4
|
+
* copyright Dustin Diaz 2012
|
5
|
+
* MIT License
|
6
|
+
*/
|
7
|
+
|
8
|
+
(function (name, context, definition) {
|
9
|
+
if (typeof module != 'undefined' && module.exports) module.exports = definition()
|
10
|
+
else if (typeof define == 'function' && define.amd) define(definition)
|
11
|
+
else context[name] = definition()
|
12
|
+
})('qwery', this, function () {
|
13
|
+
var doc = document
|
14
|
+
, html = doc.documentElement
|
15
|
+
, byClass = 'getElementsByClassName'
|
16
|
+
, byTag = 'getElementsByTagName'
|
17
|
+
, qSA = 'querySelectorAll'
|
18
|
+
, useNativeQSA = 'useNativeQSA'
|
19
|
+
, tagName = 'tagName'
|
20
|
+
, nodeType = 'nodeType'
|
21
|
+
, select // main select() method, assign later
|
22
|
+
|
23
|
+
, id = /#([\w\-]+)/
|
24
|
+
, clas = /\.[\w\-]+/g
|
25
|
+
, idOnly = /^#([\w\-]+)$/
|
26
|
+
, classOnly = /^\.([\w\-]+)$/
|
27
|
+
, tagOnly = /^([\w\-]+)$/
|
28
|
+
, tagAndOrClass = /^([\w]+)?\.([\w\-]+)$/
|
29
|
+
, splittable = /(^|,)\s*[>~+]/
|
30
|
+
, normalizr = /^\s+|\s*([,\s\+\~>]|$)\s*/g
|
31
|
+
, splitters = /[\s\>\+\~]/
|
32
|
+
, splittersMore = /(?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\]|[\s\w\+\-]*\))/
|
33
|
+
, specialChars = /([.*+?\^=!:${}()|\[\]\/\\])/g
|
34
|
+
, simple = /^(\*|[a-z0-9]+)?(?:([\.\#]+[\w\-\.#]+)?)/
|
35
|
+
, attr = /\[([\w\-]+)(?:([\|\^\$\*\~]?\=)['"]?([ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+)["']?)?\]/
|
36
|
+
, pseudo = /:([\w\-]+)(\(['"]?([^()]+)['"]?\))?/
|
37
|
+
, easy = new RegExp(idOnly.source + '|' + tagOnly.source + '|' + classOnly.source)
|
38
|
+
, dividers = new RegExp('(' + splitters.source + ')' + splittersMore.source, 'g')
|
39
|
+
, tokenizr = new RegExp(splitters.source + splittersMore.source)
|
40
|
+
, chunker = new RegExp(simple.source + '(' + attr.source + ')?' + '(' + pseudo.source + ')?')
|
41
|
+
|
42
|
+
var walker = {
|
43
|
+
' ': function (node) {
|
44
|
+
return node && node !== html && node.parentNode
|
45
|
+
}
|
46
|
+
, '>': function (node, contestant) {
|
47
|
+
return node && node.parentNode == contestant.parentNode && node.parentNode
|
48
|
+
}
|
49
|
+
, '~': function (node) {
|
50
|
+
return node && node.previousSibling
|
51
|
+
}
|
52
|
+
, '+': function (node, contestant, p1, p2) {
|
53
|
+
if (!node) return false
|
54
|
+
return (p1 = previous(node)) && (p2 = previous(contestant)) && p1 == p2 && p1
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
function cache() {
|
59
|
+
this.c = {}
|
60
|
+
}
|
61
|
+
cache.prototype = {
|
62
|
+
g: function (k) {
|
63
|
+
return this.c[k] || undefined
|
64
|
+
}
|
65
|
+
, s: function (k, v, r) {
|
66
|
+
v = r ? new RegExp(v) : v
|
67
|
+
return (this.c[k] = v)
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
var classCache = new cache()
|
72
|
+
, cleanCache = new cache()
|
73
|
+
, attrCache = new cache()
|
74
|
+
, tokenCache = new cache()
|
75
|
+
|
76
|
+
function classRegex(c) {
|
77
|
+
return classCache.g(c) || classCache.s(c, '(^|\\s+)' + c + '(\\s+|$)', 1)
|
78
|
+
}
|
79
|
+
|
80
|
+
// not quite as fast as inline loops in older browsers so don't use liberally
|
81
|
+
function each(a, fn) {
|
82
|
+
var i = 0, l = a.length
|
83
|
+
for (; i < l; i++) fn(a[i])
|
84
|
+
}
|
85
|
+
|
86
|
+
function flatten(ar) {
|
87
|
+
for (var r = [], i = 0, l = ar.length; i < l; ++i) arrayLike(ar[i]) ? (r = r.concat(ar[i])) : (r[r.length] = ar[i])
|
88
|
+
return r
|
89
|
+
}
|
90
|
+
|
91
|
+
function arrayify(ar) {
|
92
|
+
var i = 0, l = ar.length, r = []
|
93
|
+
for (; i < l; i++) r[i] = ar[i]
|
94
|
+
return r
|
95
|
+
}
|
96
|
+
|
97
|
+
function previous(n) {
|
98
|
+
while (n = n.previousSibling) if (n[nodeType] == 1) break;
|
99
|
+
return n
|
100
|
+
}
|
101
|
+
|
102
|
+
function q(query) {
|
103
|
+
return query.match(chunker)
|
104
|
+
}
|
105
|
+
|
106
|
+
// called using `this` as element and arguments from regex group results.
|
107
|
+
// given => div.hello[title="world"]:foo('bar')
|
108
|
+
// div.hello[title="world"]:foo('bar'), div, .hello, [title="world"], title, =, world, :foo('bar'), foo, ('bar'), bar]
|
109
|
+
function interpret(whole, tag, idsAndClasses, wholeAttribute, attribute, qualifier, value, wholePseudo, pseudo, wholePseudoVal, pseudoVal) {
|
110
|
+
var i, m, k, o, classes
|
111
|
+
if (this[nodeType] !== 1) return false
|
112
|
+
if (tag && tag !== '*' && this[tagName] && this[tagName].toLowerCase() !== tag) return false
|
113
|
+
if (idsAndClasses && (m = idsAndClasses.match(id)) && m[1] !== this.id) return false
|
114
|
+
if (idsAndClasses && (classes = idsAndClasses.match(clas))) {
|
115
|
+
for (i = classes.length; i--;) if (!classRegex(classes[i].slice(1)).test(this.className)) return false
|
116
|
+
}
|
117
|
+
if (pseudo && qwery.pseudos[pseudo] && !qwery.pseudos[pseudo](this, pseudoVal)) return false
|
118
|
+
if (wholeAttribute && !value) { // select is just for existance of attrib
|
119
|
+
o = this.attributes
|
120
|
+
for (k in o) {
|
121
|
+
if (Object.prototype.hasOwnProperty.call(o, k) && (o[k].name || k) == attribute) {
|
122
|
+
return this
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
if (wholeAttribute && !checkAttr(qualifier, getAttr(this, attribute) || '', value)) {
|
127
|
+
// select is for attrib equality
|
128
|
+
return false
|
129
|
+
}
|
130
|
+
return this
|
131
|
+
}
|
132
|
+
|
133
|
+
function clean(s) {
|
134
|
+
return cleanCache.g(s) || cleanCache.s(s, s.replace(specialChars, '\\$1'))
|
135
|
+
}
|
136
|
+
|
137
|
+
function checkAttr(qualify, actual, val) {
|
138
|
+
switch (qualify) {
|
139
|
+
case '=':
|
140
|
+
return actual == val
|
141
|
+
case '^=':
|
142
|
+
return actual.match(attrCache.g('^=' + val) || attrCache.s('^=' + val, '^' + clean(val), 1))
|
143
|
+
case '$=':
|
144
|
+
return actual.match(attrCache.g('$=' + val) || attrCache.s('$=' + val, clean(val) + '$', 1))
|
145
|
+
case '*=':
|
146
|
+
return actual.match(attrCache.g(val) || attrCache.s(val, clean(val), 1))
|
147
|
+
case '~=':
|
148
|
+
return actual.match(attrCache.g('~=' + val) || attrCache.s('~=' + val, '(?:^|\\s+)' + clean(val) + '(?:\\s+|$)', 1))
|
149
|
+
case '|=':
|
150
|
+
return actual.match(attrCache.g('|=' + val) || attrCache.s('|=' + val, '^' + clean(val) + '(-|$)', 1))
|
151
|
+
}
|
152
|
+
return 0
|
153
|
+
}
|
154
|
+
|
155
|
+
// given a selector, first check for simple cases then collect all base candidate matches and filter
|
156
|
+
function _qwery(selector, _root) {
|
157
|
+
var r = [], ret = [], i, l, m, token, tag, els, intr, item, root = _root
|
158
|
+
, tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr))
|
159
|
+
, dividedTokens = selector.match(dividers)
|
160
|
+
|
161
|
+
if (!tokens.length) return r
|
162
|
+
|
163
|
+
token = (tokens = tokens.slice(0)).pop() // copy cached tokens, take the last one
|
164
|
+
if (tokens.length && (m = tokens[tokens.length - 1].match(idOnly))) root = byId(_root, m[1])
|
165
|
+
if (!root) return r
|
166
|
+
|
167
|
+
intr = q(token)
|
168
|
+
// collect base candidates to filter
|
169
|
+
els = root !== _root && root[nodeType] !== 9 && dividedTokens && /^[+~]$/.test(dividedTokens[dividedTokens.length - 1]) ?
|
170
|
+
function (r) {
|
171
|
+
while (root = root.nextSibling) {
|
172
|
+
root[nodeType] == 1 && (intr[1] ? intr[1] == root[tagName].toLowerCase() : 1) && (r[r.length] = root)
|
173
|
+
}
|
174
|
+
return r
|
175
|
+
}([]) :
|
176
|
+
root[byTag](intr[1] || '*')
|
177
|
+
// filter elements according to the right-most part of the selector
|
178
|
+
for (i = 0, l = els.length; i < l; i++) {
|
179
|
+
if (item = interpret.apply(els[i], intr)) r[r.length] = item
|
180
|
+
}
|
181
|
+
if (!tokens.length) return r
|
182
|
+
|
183
|
+
// filter further according to the rest of the selector (the left side)
|
184
|
+
each(r, function (e) { if (ancestorMatch(e, tokens, dividedTokens)) ret[ret.length] = e })
|
185
|
+
return ret
|
186
|
+
}
|
187
|
+
|
188
|
+
// compare element to a selector
|
189
|
+
function is(el, selector, root) {
|
190
|
+
if (isNode(selector)) return el == selector
|
191
|
+
if (arrayLike(selector)) return !!~flatten(selector).indexOf(el) // if selector is an array, is el a member?
|
192
|
+
|
193
|
+
var selectors = selector.split(','), tokens, dividedTokens
|
194
|
+
while (selector = selectors.pop()) {
|
195
|
+
tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr))
|
196
|
+
dividedTokens = selector.match(dividers)
|
197
|
+
tokens = tokens.slice(0) // copy array
|
198
|
+
if (interpret.apply(el, q(tokens.pop())) && (!tokens.length || ancestorMatch(el, tokens, dividedTokens, root))) {
|
199
|
+
return true
|
200
|
+
}
|
201
|
+
}
|
202
|
+
return false
|
203
|
+
}
|
204
|
+
|
205
|
+
// given elements matching the right-most part of a selector, filter out any that don't match the rest
|
206
|
+
function ancestorMatch(el, tokens, dividedTokens, root) {
|
207
|
+
var cand
|
208
|
+
// recursively work backwards through the tokens and up the dom, covering all options
|
209
|
+
function crawl(e, i, p) {
|
210
|
+
while (p = walker[dividedTokens[i]](p, e)) {
|
211
|
+
if (isNode(p) && (interpret.apply(p, q(tokens[i])))) {
|
212
|
+
if (i) {
|
213
|
+
if (cand = crawl(p, i - 1, p)) return cand
|
214
|
+
} else return p
|
215
|
+
}
|
216
|
+
}
|
217
|
+
}
|
218
|
+
return (cand = crawl(el, tokens.length - 1, el)) && (!root || isAncestor(cand, root))
|
219
|
+
}
|
220
|
+
|
221
|
+
function isNode(el, t) {
|
222
|
+
return el && typeof el === 'object' && (t = el[nodeType]) && (t == 1 || t == 9)
|
223
|
+
}
|
224
|
+
|
225
|
+
function uniq(ar) {
|
226
|
+
var a = [], i, j;
|
227
|
+
o:
|
228
|
+
for (i = 0; i < ar.length; ++i) {
|
229
|
+
for (j = 0; j < a.length; ++j) if (a[j] == ar[i]) continue o
|
230
|
+
a[a.length] = ar[i]
|
231
|
+
}
|
232
|
+
return a
|
233
|
+
}
|
234
|
+
|
235
|
+
function arrayLike(o) {
|
236
|
+
return (typeof o === 'object' && isFinite(o.length))
|
237
|
+
}
|
238
|
+
|
239
|
+
function normalizeRoot(root) {
|
240
|
+
if (!root) return doc
|
241
|
+
if (typeof root == 'string') return qwery(root)[0]
|
242
|
+
if (!root[nodeType] && arrayLike(root)) return root[0]
|
243
|
+
return root
|
244
|
+
}
|
245
|
+
|
246
|
+
function byId(root, id, el) {
|
247
|
+
// if doc, query on it, else query the parent doc or if a detached fragment rewrite the query and run on the fragment
|
248
|
+
return root[nodeType] === 9 ? root.getElementById(id) :
|
249
|
+
root.ownerDocument &&
|
250
|
+
(((el = root.ownerDocument.getElementById(id)) && isAncestor(el, root) && el) ||
|
251
|
+
(!isAncestor(root, root.ownerDocument) && select('[id="' + id + '"]', root)[0]))
|
252
|
+
}
|
253
|
+
|
254
|
+
function qwery(selector, _root) {
|
255
|
+
var m, el, root = normalizeRoot(_root)
|
256
|
+
|
257
|
+
// easy, fast cases that we can dispatch with simple DOM calls
|
258
|
+
if (!root || !selector) return []
|
259
|
+
if (selector === window || isNode(selector)) {
|
260
|
+
return !_root || (selector !== window && isNode(root) && isAncestor(selector, root)) ? [selector] : []
|
261
|
+
}
|
262
|
+
if (selector && arrayLike(selector)) return flatten(selector)
|
263
|
+
if (m = selector.match(easy)) {
|
264
|
+
if (m[1]) return (el = byId(root, m[1])) ? [el] : []
|
265
|
+
if (m[2]) return arrayify(root[byTag](m[2]))
|
266
|
+
if (hasByClass && m[3]) return arrayify(root[byClass](m[3]))
|
267
|
+
}
|
268
|
+
|
269
|
+
return select(selector, root)
|
270
|
+
}
|
271
|
+
|
272
|
+
// where the root is not document and a relationship selector is first we have to
|
273
|
+
// do some awkward adjustments to get it to work, even with qSA
|
274
|
+
function collectSelector(root, collector) {
|
275
|
+
return function (s) {
|
276
|
+
var oid, nid
|
277
|
+
if (splittable.test(s)) {
|
278
|
+
if (root[nodeType] !== 9) {
|
279
|
+
// make sure the el has an id, rewrite the query, set root to doc and run it
|
280
|
+
if (!(nid = oid = root.getAttribute('id'))) root.setAttribute('id', nid = '__qwerymeupscotty')
|
281
|
+
s = '[id="' + nid + '"]' + s // avoid byId and allow us to match context element
|
282
|
+
collector(root.parentNode || root, s, true)
|
283
|
+
oid || root.removeAttribute('id')
|
284
|
+
}
|
285
|
+
return;
|
286
|
+
}
|
287
|
+
s.length && collector(root, s, false)
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
291
|
+
var isAncestor = 'compareDocumentPosition' in html ?
|
292
|
+
function (element, container) {
|
293
|
+
return (container.compareDocumentPosition(element) & 16) == 16
|
294
|
+
} : 'contains' in html ?
|
295
|
+
function (element, container) {
|
296
|
+
container = container[nodeType] === 9 || container == window ? html : container
|
297
|
+
return container !== element && container.contains(element)
|
298
|
+
} :
|
299
|
+
function (element, container) {
|
300
|
+
while (element = element.parentNode) if (element === container) return 1
|
301
|
+
return 0
|
302
|
+
}
|
303
|
+
, getAttr = function () {
|
304
|
+
// detect buggy IE src/href getAttribute() call
|
305
|
+
var e = doc.createElement('p')
|
306
|
+
return ((e.innerHTML = '<a href="#x">x</a>') && e.firstChild.getAttribute('href') != '#x') ?
|
307
|
+
function (e, a) {
|
308
|
+
return a === 'class' ? e.className : (a === 'href' || a === 'src') ?
|
309
|
+
e.getAttribute(a, 2) : e.getAttribute(a)
|
310
|
+
} :
|
311
|
+
function (e, a) { return e.getAttribute(a) }
|
312
|
+
}()
|
313
|
+
, hasByClass = !!doc[byClass]
|
314
|
+
// has native qSA support
|
315
|
+
, hasQSA = doc.querySelector && doc[qSA]
|
316
|
+
// use native qSA
|
317
|
+
, selectQSA = function (selector, root) {
|
318
|
+
var result = [], ss, e
|
319
|
+
try {
|
320
|
+
if (root[nodeType] === 9 || !splittable.test(selector)) {
|
321
|
+
// most work is done right here, defer to qSA
|
322
|
+
return arrayify(root[qSA](selector))
|
323
|
+
}
|
324
|
+
// special case where we need the services of `collectSelector()`
|
325
|
+
each(ss = selector.split(','), collectSelector(root, function (ctx, s) {
|
326
|
+
e = ctx[qSA](s)
|
327
|
+
if (e.length == 1) result[result.length] = e.item(0)
|
328
|
+
else if (e.length) result = result.concat(arrayify(e))
|
329
|
+
}))
|
330
|
+
return ss.length > 1 && result.length > 1 ? uniq(result) : result
|
331
|
+
} catch (ex) { }
|
332
|
+
return selectNonNative(selector, root)
|
333
|
+
}
|
334
|
+
// no native selector support
|
335
|
+
, selectNonNative = function (selector, root) {
|
336
|
+
var result = [], items, m, i, l, r, ss
|
337
|
+
selector = selector.replace(normalizr, '$1')
|
338
|
+
if (m = selector.match(tagAndOrClass)) {
|
339
|
+
r = classRegex(m[2])
|
340
|
+
items = root[byTag](m[1] || '*')
|
341
|
+
for (i = 0, l = items.length; i < l; i++) {
|
342
|
+
if (r.test(items[i].className)) result[result.length] = items[i]
|
343
|
+
}
|
344
|
+
return result
|
345
|
+
}
|
346
|
+
// more complex selector, get `_qwery()` to do the work for us
|
347
|
+
each(ss = selector.split(','), collectSelector(root, function (ctx, s, rewrite) {
|
348
|
+
r = _qwery(s, ctx)
|
349
|
+
for (i = 0, l = r.length; i < l; i++) {
|
350
|
+
if (ctx[nodeType] === 9 || rewrite || isAncestor(r[i], root)) result[result.length] = r[i]
|
351
|
+
}
|
352
|
+
}))
|
353
|
+
return ss.length > 1 && result.length > 1 ? uniq(result) : result
|
354
|
+
}
|
355
|
+
, configure = function (options) {
|
356
|
+
// configNativeQSA: use fully-internal selector or native qSA where present
|
357
|
+
if (typeof options[useNativeQSA] !== 'undefined')
|
358
|
+
select = !options[useNativeQSA] ? selectNonNative : hasQSA ? selectQSA : selectNonNative
|
359
|
+
}
|
360
|
+
|
361
|
+
configure({ useNativeQSA: true })
|
362
|
+
|
363
|
+
qwery.configure = configure
|
364
|
+
qwery.uniq = uniq
|
365
|
+
qwery.is = is
|
366
|
+
qwery.pseudos = {}
|
367
|
+
|
368
|
+
return qwery
|
369
|
+
});
|
@@ -0,0 +1,565 @@
|
|
1
|
+
/*!
|
2
|
+
* Reqwest! A general purpose XHR connection manager
|
3
|
+
* (c) Dustin Diaz 2013
|
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
|
+
|
13
|
+
var win = window
|
14
|
+
, doc = document
|
15
|
+
, twoHundo = /^20\d$/
|
16
|
+
, byTag = 'getElementsByTagName'
|
17
|
+
, readyState = 'readyState'
|
18
|
+
, contentType = 'Content-Type'
|
19
|
+
, requestedWith = 'X-Requested-With'
|
20
|
+
, head = doc[byTag]('head')[0]
|
21
|
+
, uniqid = 0
|
22
|
+
, callbackPrefix = 'reqwest_' + (+new Date())
|
23
|
+
, lastValue // data stored by the most recent JSONP callback
|
24
|
+
, xmlHttpRequest = 'XMLHttpRequest'
|
25
|
+
, noop = function () {}
|
26
|
+
|
27
|
+
, isArray = typeof Array.isArray == 'function'
|
28
|
+
? Array.isArray
|
29
|
+
: function (a) {
|
30
|
+
return a instanceof Array
|
31
|
+
}
|
32
|
+
|
33
|
+
, defaultHeaders = {
|
34
|
+
contentType: 'application/x-www-form-urlencoded'
|
35
|
+
, requestedWith: xmlHttpRequest
|
36
|
+
, accept: {
|
37
|
+
'*': 'text/javascript, text/html, application/xml, text/xml, */*'
|
38
|
+
, xml: 'application/xml, text/xml'
|
39
|
+
, html: 'text/html'
|
40
|
+
, text: 'text/plain'
|
41
|
+
, json: 'application/json, text/javascript'
|
42
|
+
, js: 'application/javascript, text/javascript'
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
, xhr = win[xmlHttpRequest]
|
47
|
+
? function () {
|
48
|
+
return new XMLHttpRequest()
|
49
|
+
}
|
50
|
+
: function () {
|
51
|
+
return new ActiveXObject('Microsoft.XMLHTTP')
|
52
|
+
}
|
53
|
+
, globalSetupOptions = {
|
54
|
+
dataFilter: function (data) {
|
55
|
+
return data
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
function handleReadyState(r, success, error) {
|
60
|
+
return function () {
|
61
|
+
// use _aborted to mitigate against IE err c00c023f
|
62
|
+
// (can't read props on aborted request objects)
|
63
|
+
if (r._aborted) return error(r.request)
|
64
|
+
if (r.request && r.request[readyState] == 4) {
|
65
|
+
r.request.onreadystatechange = noop
|
66
|
+
if (twoHundo.test(r.request.status))
|
67
|
+
success(r.request)
|
68
|
+
else
|
69
|
+
error(r.request)
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
function setHeaders(http, o) {
|
75
|
+
var headers = o.headers || {}
|
76
|
+
, h
|
77
|
+
|
78
|
+
headers.Accept = headers.Accept
|
79
|
+
|| defaultHeaders.accept[o.type]
|
80
|
+
|| defaultHeaders.accept['*']
|
81
|
+
|
82
|
+
// breaks cross-origin requests with legacy browsers
|
83
|
+
if (!o.crossOrigin && !headers[requestedWith]) headers[requestedWith] = defaultHeaders.requestedWith
|
84
|
+
if (!headers[contentType]) headers[contentType] = o.contentType || defaultHeaders.contentType
|
85
|
+
for (h in headers)
|
86
|
+
headers.hasOwnProperty(h) && http.setRequestHeader(h, headers[h])
|
87
|
+
}
|
88
|
+
|
89
|
+
function setCredentials(http, o) {
|
90
|
+
if (typeof o.withCredentials !== 'undefined' && typeof http.withCredentials !== 'undefined') {
|
91
|
+
http.withCredentials = !!o.withCredentials
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
function generalCallback(data) {
|
96
|
+
lastValue = data
|
97
|
+
}
|
98
|
+
|
99
|
+
function urlappend (url, s) {
|
100
|
+
return url + (/\?/.test(url) ? '&' : '?') + s
|
101
|
+
}
|
102
|
+
|
103
|
+
function handleJsonp(o, fn, err, url) {
|
104
|
+
var reqId = uniqid++
|
105
|
+
, cbkey = o.jsonpCallback || 'callback' // the 'callback' key
|
106
|
+
, cbval = o.jsonpCallbackName || reqwest.getcallbackPrefix(reqId)
|
107
|
+
// , cbval = o.jsonpCallbackName || ('reqwest_' + reqId) // the 'callback' value
|
108
|
+
, cbreg = new RegExp('((^|\\?|&)' + cbkey + ')=([^&]+)')
|
109
|
+
, match = url.match(cbreg)
|
110
|
+
, script = doc.createElement('script')
|
111
|
+
, loaded = 0
|
112
|
+
, isIE10 = navigator.userAgent.indexOf('MSIE 10.0') !== -1
|
113
|
+
|
114
|
+
if (match) {
|
115
|
+
if (match[3] === '?') {
|
116
|
+
url = url.replace(cbreg, '$1=' + cbval) // wildcard callback func name
|
117
|
+
} else {
|
118
|
+
cbval = match[3] // provided callback func name
|
119
|
+
}
|
120
|
+
} else {
|
121
|
+
url = urlappend(url, cbkey + '=' + cbval) // no callback details, add 'em
|
122
|
+
}
|
123
|
+
|
124
|
+
win[cbval] = generalCallback
|
125
|
+
|
126
|
+
script.type = 'text/javascript'
|
127
|
+
script.src = url
|
128
|
+
script.async = true
|
129
|
+
if (typeof script.onreadystatechange !== 'undefined' && !isIE10) {
|
130
|
+
// need this for IE due to out-of-order onreadystatechange(), binding script
|
131
|
+
// execution to an event listener gives us control over when the script
|
132
|
+
// is executed. See http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
|
133
|
+
//
|
134
|
+
// if this hack is used in IE10 jsonp callback are never called
|
135
|
+
script.event = 'onclick'
|
136
|
+
script.htmlFor = script.id = '_reqwest_' + reqId
|
137
|
+
}
|
138
|
+
|
139
|
+
script.onload = script.onreadystatechange = function () {
|
140
|
+
if ((script[readyState] && script[readyState] !== 'complete' && script[readyState] !== 'loaded') || loaded) {
|
141
|
+
return false
|
142
|
+
}
|
143
|
+
script.onload = script.onreadystatechange = null
|
144
|
+
script.onclick && script.onclick()
|
145
|
+
// Call the user callback with the last value stored and clean up values and scripts.
|
146
|
+
fn(lastValue)
|
147
|
+
lastValue = undefined
|
148
|
+
head.removeChild(script)
|
149
|
+
loaded = 1
|
150
|
+
}
|
151
|
+
|
152
|
+
// Add the script to the DOM head
|
153
|
+
head.appendChild(script)
|
154
|
+
|
155
|
+
// Enable JSONP timeout
|
156
|
+
return {
|
157
|
+
abort: function () {
|
158
|
+
script.onload = script.onreadystatechange = null
|
159
|
+
err({}, 'Request is aborted: timeout', {})
|
160
|
+
lastValue = undefined
|
161
|
+
head.removeChild(script)
|
162
|
+
loaded = 1
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
function getRequest(fn, err) {
|
168
|
+
var o = this.o
|
169
|
+
, method = (o.method || 'GET').toUpperCase()
|
170
|
+
, url = typeof o === 'string' ? o : o.url
|
171
|
+
// convert non-string objects to query-string form unless o.processData is false
|
172
|
+
, data = (o.processData !== false && o.data && typeof o.data !== 'string')
|
173
|
+
? reqwest.toQueryString(o.data)
|
174
|
+
: (o.data || null)
|
175
|
+
, http
|
176
|
+
|
177
|
+
// if we're working on a GET request and we have data then we should append
|
178
|
+
// query string to end of URL and not post data
|
179
|
+
if ((o.type == 'jsonp' || method == 'GET') && data) {
|
180
|
+
url = urlappend(url, data)
|
181
|
+
data = null
|
182
|
+
}
|
183
|
+
|
184
|
+
if (o.type == 'jsonp') return handleJsonp(o, fn, err, url)
|
185
|
+
|
186
|
+
http = xhr()
|
187
|
+
http.open(method, url, o.async === false ? false : true)
|
188
|
+
setHeaders(http, o)
|
189
|
+
setCredentials(http, o)
|
190
|
+
http.onreadystatechange = handleReadyState(this, fn, err)
|
191
|
+
o.before && o.before(http)
|
192
|
+
http.send(data)
|
193
|
+
return http
|
194
|
+
}
|
195
|
+
|
196
|
+
function Reqwest(o, fn) {
|
197
|
+
this.o = o
|
198
|
+
this.fn = fn
|
199
|
+
|
200
|
+
init.apply(this, arguments)
|
201
|
+
}
|
202
|
+
|
203
|
+
function setType(url) {
|
204
|
+
var m = url.match(/\.(json|jsonp|html|xml)(\?|$)/)
|
205
|
+
return m ? m[1] : 'js'
|
206
|
+
}
|
207
|
+
|
208
|
+
function init(o, fn) {
|
209
|
+
|
210
|
+
this.url = typeof o == 'string' ? o : o.url
|
211
|
+
this.timeout = null
|
212
|
+
|
213
|
+
// whether request has been fulfilled for purpose
|
214
|
+
// of tracking the Promises
|
215
|
+
this._fulfilled = false
|
216
|
+
// success handlers
|
217
|
+
this._fulfillmentHandlers = []
|
218
|
+
// error handlers
|
219
|
+
this._errorHandlers = []
|
220
|
+
// complete (both success and fail) handlers
|
221
|
+
this._completeHandlers = []
|
222
|
+
this._erred = false
|
223
|
+
this._responseArgs = {}
|
224
|
+
|
225
|
+
var self = this
|
226
|
+
, type = o.type || setType(this.url)
|
227
|
+
|
228
|
+
fn = fn || function () {}
|
229
|
+
|
230
|
+
if (o.timeout) {
|
231
|
+
this.timeout = setTimeout(function () {
|
232
|
+
self.abort()
|
233
|
+
}, o.timeout)
|
234
|
+
}
|
235
|
+
|
236
|
+
if (o.success) {
|
237
|
+
this._fulfillmentHandlers.push(function () {
|
238
|
+
o.success.apply(o, arguments)
|
239
|
+
})
|
240
|
+
}
|
241
|
+
|
242
|
+
if (o.error) {
|
243
|
+
this._errorHandlers.push(function () {
|
244
|
+
o.error.apply(o, arguments)
|
245
|
+
})
|
246
|
+
}
|
247
|
+
|
248
|
+
if (o.complete) {
|
249
|
+
this._completeHandlers.push(function () {
|
250
|
+
o.complete.apply(o, arguments)
|
251
|
+
})
|
252
|
+
}
|
253
|
+
|
254
|
+
function complete (resp) {
|
255
|
+
o.timeout && clearTimeout(self.timeout)
|
256
|
+
self.timeout = null
|
257
|
+
while (self._completeHandlers.length > 0) {
|
258
|
+
self._completeHandlers.shift()(resp)
|
259
|
+
}
|
260
|
+
}
|
261
|
+
|
262
|
+
function success (resp) {
|
263
|
+
// use global data filter on response text
|
264
|
+
var filteredResponse = globalSetupOptions.dataFilter(resp.responseText, type)
|
265
|
+
, r = filteredResponse
|
266
|
+
try {
|
267
|
+
resp.responseText = r
|
268
|
+
} catch (e) {
|
269
|
+
// can't assign this in IE<=8, just ignore
|
270
|
+
}
|
271
|
+
if (r) {
|
272
|
+
switch (type) {
|
273
|
+
case 'json':
|
274
|
+
try {
|
275
|
+
resp = win.JSON ? win.JSON.parse(r) : eval('(' + r + ')')
|
276
|
+
} catch (err) {
|
277
|
+
return error(resp, 'Could not parse JSON in response', err)
|
278
|
+
}
|
279
|
+
break
|
280
|
+
case 'js':
|
281
|
+
resp = eval(r)
|
282
|
+
break
|
283
|
+
case 'html':
|
284
|
+
resp = r
|
285
|
+
break
|
286
|
+
case 'xml':
|
287
|
+
resp = resp.responseXML
|
288
|
+
&& resp.responseXML.parseError // IE trololo
|
289
|
+
&& resp.responseXML.parseError.errorCode
|
290
|
+
&& resp.responseXML.parseError.reason
|
291
|
+
? null
|
292
|
+
: resp.responseXML
|
293
|
+
break
|
294
|
+
}
|
295
|
+
}
|
296
|
+
|
297
|
+
self._responseArgs.resp = resp
|
298
|
+
self._fulfilled = true
|
299
|
+
fn(resp)
|
300
|
+
while (self._fulfillmentHandlers.length > 0) {
|
301
|
+
self._fulfillmentHandlers.shift()(resp)
|
302
|
+
}
|
303
|
+
|
304
|
+
complete(resp)
|
305
|
+
}
|
306
|
+
|
307
|
+
function error(resp, msg, t) {
|
308
|
+
self._responseArgs.resp = resp
|
309
|
+
self._responseArgs.msg = msg
|
310
|
+
self._responseArgs.t = t
|
311
|
+
self._erred = true
|
312
|
+
while (self._errorHandlers.length > 0) {
|
313
|
+
self._errorHandlers.shift()(resp, msg, t)
|
314
|
+
}
|
315
|
+
complete(resp)
|
316
|
+
}
|
317
|
+
|
318
|
+
this.request = getRequest.call(this, success, error)
|
319
|
+
}
|
320
|
+
|
321
|
+
Reqwest.prototype = {
|
322
|
+
abort: function () {
|
323
|
+
this._aborted = true
|
324
|
+
this.request.abort()
|
325
|
+
}
|
326
|
+
|
327
|
+
, retry: function () {
|
328
|
+
init.call(this, this.o, this.fn)
|
329
|
+
}
|
330
|
+
|
331
|
+
/**
|
332
|
+
* Small deviation from the Promises A CommonJs specification
|
333
|
+
* http://wiki.commonjs.org/wiki/Promises/A
|
334
|
+
*/
|
335
|
+
|
336
|
+
/**
|
337
|
+
* `then` will execute upon successful requests
|
338
|
+
*/
|
339
|
+
, then: function (success, fail) {
|
340
|
+
success = success || function () {}
|
341
|
+
fail = fail || function () {}
|
342
|
+
if (this._fulfilled) {
|
343
|
+
success(this._responseArgs.resp)
|
344
|
+
} else if (this._erred) {
|
345
|
+
fail(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
|
346
|
+
} else {
|
347
|
+
this._fulfillmentHandlers.push(success)
|
348
|
+
this._errorHandlers.push(fail)
|
349
|
+
}
|
350
|
+
return this
|
351
|
+
}
|
352
|
+
|
353
|
+
/**
|
354
|
+
* `always` will execute whether the request succeeds or fails
|
355
|
+
*/
|
356
|
+
, always: function (fn) {
|
357
|
+
if (this._fulfilled || this._erred) {
|
358
|
+
fn(this._responseArgs.resp)
|
359
|
+
} else {
|
360
|
+
this._completeHandlers.push(fn)
|
361
|
+
}
|
362
|
+
return this
|
363
|
+
}
|
364
|
+
|
365
|
+
/**
|
366
|
+
* `fail` will execute when the request fails
|
367
|
+
*/
|
368
|
+
, fail: function (fn) {
|
369
|
+
if (this._erred) {
|
370
|
+
fn(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
|
371
|
+
} else {
|
372
|
+
this._errorHandlers.push(fn)
|
373
|
+
}
|
374
|
+
return this
|
375
|
+
}
|
376
|
+
}
|
377
|
+
|
378
|
+
function reqwest(o, fn) {
|
379
|
+
return new Reqwest(o, fn)
|
380
|
+
}
|
381
|
+
|
382
|
+
// normalize newline variants according to spec -> CRLF
|
383
|
+
function normalize(s) {
|
384
|
+
return s ? s.replace(/\r?\n/g, '\r\n') : ''
|
385
|
+
}
|
386
|
+
|
387
|
+
function serial(el, cb) {
|
388
|
+
var n = el.name
|
389
|
+
, t = el.tagName.toLowerCase()
|
390
|
+
, optCb = function (o) {
|
391
|
+
// IE gives value="" even where there is no value attribute
|
392
|
+
// 'specified' ref: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-862529273
|
393
|
+
if (o && !o.disabled)
|
394
|
+
cb(n, normalize(o.attributes.value && o.attributes.value.specified ? o.value : o.text))
|
395
|
+
}
|
396
|
+
, ch, ra, val, i
|
397
|
+
|
398
|
+
// don't serialize elements that are disabled or without a name
|
399
|
+
if (el.disabled || !n) return
|
400
|
+
|
401
|
+
switch (t) {
|
402
|
+
case 'input':
|
403
|
+
if (!/reset|button|image|file/i.test(el.type)) {
|
404
|
+
ch = /checkbox/i.test(el.type)
|
405
|
+
ra = /radio/i.test(el.type)
|
406
|
+
val = el.value
|
407
|
+
// WebKit gives us "" instead of "on" if a checkbox has no value, so correct it here
|
408
|
+
;(!(ch || ra) || el.checked) && cb(n, normalize(ch && val === '' ? 'on' : val))
|
409
|
+
}
|
410
|
+
break
|
411
|
+
case 'textarea':
|
412
|
+
cb(n, normalize(el.value))
|
413
|
+
break
|
414
|
+
case 'select':
|
415
|
+
if (el.type.toLowerCase() === 'select-one') {
|
416
|
+
optCb(el.selectedIndex >= 0 ? el.options[el.selectedIndex] : null)
|
417
|
+
} else {
|
418
|
+
for (i = 0; el.length && i < el.length; i++) {
|
419
|
+
el.options[i].selected && optCb(el.options[i])
|
420
|
+
}
|
421
|
+
}
|
422
|
+
break
|
423
|
+
}
|
424
|
+
}
|
425
|
+
|
426
|
+
// collect up all form elements found from the passed argument elements all
|
427
|
+
// the way down to child elements; pass a '<form>' or form fields.
|
428
|
+
// called with 'this'=callback to use for serial() on each element
|
429
|
+
function eachFormElement() {
|
430
|
+
var cb = this
|
431
|
+
, e, i
|
432
|
+
, serializeSubtags = function (e, tags) {
|
433
|
+
var i, j, fa
|
434
|
+
for (i = 0; i < tags.length; i++) {
|
435
|
+
fa = e[byTag](tags[i])
|
436
|
+
for (j = 0; j < fa.length; j++) serial(fa[j], cb)
|
437
|
+
}
|
438
|
+
}
|
439
|
+
|
440
|
+
for (i = 0; i < arguments.length; i++) {
|
441
|
+
e = arguments[i]
|
442
|
+
if (/input|select|textarea/i.test(e.tagName)) serial(e, cb)
|
443
|
+
serializeSubtags(e, [ 'input', 'select', 'textarea' ])
|
444
|
+
}
|
445
|
+
}
|
446
|
+
|
447
|
+
// standard query string style serialization
|
448
|
+
function serializeQueryString() {
|
449
|
+
return reqwest.toQueryString(reqwest.serializeArray.apply(null, arguments))
|
450
|
+
}
|
451
|
+
|
452
|
+
// { 'name': 'value', ... } style serialization
|
453
|
+
function serializeHash() {
|
454
|
+
var hash = {}
|
455
|
+
eachFormElement.apply(function (name, value) {
|
456
|
+
if (name in hash) {
|
457
|
+
hash[name] && !isArray(hash[name]) && (hash[name] = [hash[name]])
|
458
|
+
hash[name].push(value)
|
459
|
+
} else hash[name] = value
|
460
|
+
}, arguments)
|
461
|
+
return hash
|
462
|
+
}
|
463
|
+
|
464
|
+
// [ { name: 'name', value: 'value' }, ... ] style serialization
|
465
|
+
reqwest.serializeArray = function () {
|
466
|
+
var arr = []
|
467
|
+
eachFormElement.apply(function (name, value) {
|
468
|
+
arr.push({name: name, value: value})
|
469
|
+
}, arguments)
|
470
|
+
return arr
|
471
|
+
}
|
472
|
+
|
473
|
+
reqwest.serialize = function () {
|
474
|
+
if (arguments.length === 0) return ''
|
475
|
+
var opt, fn
|
476
|
+
, args = Array.prototype.slice.call(arguments, 0)
|
477
|
+
|
478
|
+
opt = args.pop()
|
479
|
+
opt && opt.nodeType && args.push(opt) && (opt = null)
|
480
|
+
opt && (opt = opt.type)
|
481
|
+
|
482
|
+
if (opt == 'map') fn = serializeHash
|
483
|
+
else if (opt == 'array') fn = reqwest.serializeArray
|
484
|
+
else fn = serializeQueryString
|
485
|
+
|
486
|
+
return fn.apply(null, args)
|
487
|
+
}
|
488
|
+
|
489
|
+
reqwest.toQueryString = function (o, trad) {
|
490
|
+
var prefix, i
|
491
|
+
, traditional = trad || false
|
492
|
+
, s = []
|
493
|
+
, enc = encodeURIComponent
|
494
|
+
, add = function (key, value) {
|
495
|
+
// If value is a function, invoke it and return its value
|
496
|
+
value = ('function' === typeof value) ? value() : (value == null ? '' : value)
|
497
|
+
s[s.length] = enc(key) + '=' + enc(value)
|
498
|
+
}
|
499
|
+
// If an array was passed in, assume that it is an array of form elements.
|
500
|
+
if (isArray(o)) {
|
501
|
+
for (i = 0; o && i < o.length; i++) add(o[i].name, o[i].value)
|
502
|
+
} else {
|
503
|
+
// If traditional, encode the "old" way (the way 1.3.2 or older
|
504
|
+
// did it), otherwise encode params recursively.
|
505
|
+
for (prefix in o) {
|
506
|
+
buildParams(prefix, o[prefix], traditional, add)
|
507
|
+
}
|
508
|
+
}
|
509
|
+
|
510
|
+
// spaces should be + according to spec
|
511
|
+
return s.join('&').replace(/%20/g, '+')
|
512
|
+
}
|
513
|
+
|
514
|
+
function buildParams(prefix, obj, traditional, add) {
|
515
|
+
var name, i, v
|
516
|
+
, rbracket = /\[\]$/
|
517
|
+
|
518
|
+
if (isArray(obj)) {
|
519
|
+
// Serialize array item.
|
520
|
+
for (i = 0; obj && i < obj.length; i++) {
|
521
|
+
v = obj[i]
|
522
|
+
if (traditional || rbracket.test(prefix)) {
|
523
|
+
// Treat each array item as a scalar.
|
524
|
+
add(prefix, v)
|
525
|
+
} else {
|
526
|
+
buildParams(prefix + '[' + (typeof v === 'object' ? i : '') + ']', v, traditional, add)
|
527
|
+
}
|
528
|
+
}
|
529
|
+
} else if (obj && obj.toString() === '[object Object]') {
|
530
|
+
// Serialize object item.
|
531
|
+
for (name in obj) {
|
532
|
+
buildParams(prefix + '[' + name + ']', obj[name], traditional, add)
|
533
|
+
}
|
534
|
+
|
535
|
+
} else {
|
536
|
+
// Serialize scalar item.
|
537
|
+
add(prefix, obj)
|
538
|
+
}
|
539
|
+
}
|
540
|
+
|
541
|
+
reqwest.getcallbackPrefix = function () {
|
542
|
+
return callbackPrefix
|
543
|
+
}
|
544
|
+
|
545
|
+
// jQuery and Zepto compatibility, differences can be remapped here so you can call
|
546
|
+
// .ajax.compat(options, callback)
|
547
|
+
reqwest.compat = function (o, fn) {
|
548
|
+
if (o) {
|
549
|
+
o.type && (o.method = o.type) && delete o.type
|
550
|
+
o.dataType && (o.type = o.dataType)
|
551
|
+
o.jsonpCallback && (o.jsonpCallbackName = o.jsonpCallback) && delete o.jsonpCallback
|
552
|
+
o.jsonp && (o.jsonpCallback = o.jsonp)
|
553
|
+
}
|
554
|
+
return new Reqwest(o, fn)
|
555
|
+
}
|
556
|
+
|
557
|
+
reqwest.ajaxSetup = function (options) {
|
558
|
+
options = options || {}
|
559
|
+
for (var k in options) {
|
560
|
+
globalSetupOptions[k] = options[k]
|
561
|
+
}
|
562
|
+
}
|
563
|
+
|
564
|
+
return reqwest
|
565
|
+
});
|