1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | `
|
9 |
|
10 | * Reqwest! A x-browser general purpose XHR connection manager
|
11 | * copyright Dustin Diaz 2011
|
12 | * https:
|
13 | * license MIT
|
14 | */
|
15 | !
|
16 | function(context, win) {
|
17 |
|
18 | var twoHundo = /^20\d$/,
|
19 | doc = document,
|
20 | byTag = 'getElementsByTagName',
|
21 | contentType = 'Content-Type',
|
22 | head = doc[byTag]('head')[0],
|
23 | uniqid = 0,
|
24 | lastValue
|
25 | , xhr = ('XMLHttpRequest' in win) ?
|
26 | function() {
|
27 | return new XMLHttpRequest()
|
28 | } : function() {
|
29 | return new ActiveXObject('Microsoft.XMLHTTP')
|
30 | }
|
31 |
|
32 | function readyState(o, success, error) {
|
33 | return function() {
|
34 | if (o && o.readyState == 4) {
|
35 | if (twoHundo.test(o.status)) {
|
36 | success(o)
|
37 | } else {
|
38 | error(o)
|
39 | }
|
40 | }
|
41 | }
|
42 | }
|
43 |
|
44 | function setHeaders(http, o) {
|
45 | var headers = o.headers || {}
|
46 | headers.Accept = headers.Accept || 'text/javascript, text/html, application/xml, text/xml, */*'
|
47 |
|
48 |
|
49 | if (!o.crossOrigin) {
|
50 | headers['X-Requested-With'] = headers['X-Requested-With'] || 'XMLHttpRequest'
|
51 | }
|
52 |
|
53 | if (o.data) {
|
54 | headers[contentType] = headers[contentType] || 'application/x-www-form-urlencoded'
|
55 | }
|
56 | for (var h in headers) {
|
57 | headers.hasOwnProperty(h) && http.setRequestHeader(h, headers[h], false)
|
58 | }
|
59 | }
|
60 |
|
61 | function getCallbackName(o) {
|
62 | var callbackVar = o.jsonpCallback || "callback"
|
63 | if (o.url.slice(-(callbackVar.length + 2)) == (callbackVar + "=?")) {
|
64 |
|
65 | var callbackName = "reqwest_" + uniqid++
|
66 |
|
67 |
|
68 | o.url = o.url.substr(0, o.url.length - 1) + callbackName
|
69 | return callbackName
|
70 | } else {
|
71 |
|
72 | var regex = new RegExp(callbackVar + "=([\\w]+)")
|
73 | return o.url.match(regex)[1]
|
74 | }
|
75 | }
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | function generalCallback(data) {
|
81 | lastValue = data
|
82 | }
|
83 |
|
84 | function getRequest(o, fn, err) {
|
85 | function onload() {
|
86 |
|
87 |
|
88 | o.success && o.success(lastValue)
|
89 | lastValue = undefined
|
90 | head.removeChild(script);
|
91 | }
|
92 | if (o.type == 'jsonp') {
|
93 | var script = doc.createElement('script')
|
94 |
|
95 |
|
96 | win[getCallbackName(o)] = generalCallback;
|
97 |
|
98 |
|
99 | script.type = 'text/javascript'
|
100 | script.src = o.url
|
101 | script.async = true
|
102 |
|
103 | script.onload = onload
|
104 |
|
105 | script.onreadystatechange = function() {
|
106 | /^loaded|complete$/.test(script.readyState) && onload()
|
107 | }
|
108 |
|
109 |
|
110 | head.appendChild(script)
|
111 | } else {
|
112 | var http = xhr()
|
113 | http.open(o.method || 'GET', typeof o == 'string' ? o : o.url, true)
|
114 | setHeaders(http, o)
|
115 | http.onreadystatechange = readyState(http, fn, err)
|
116 | o.before && o.before(http)
|
117 | http.send(o.data || null)
|
118 | return http
|
119 | }
|
120 | }
|
121 |
|
122 | function Reqwest(o, fn) {
|
123 | this.o = o
|
124 | this.fn = fn
|
125 | init.apply(this, arguments)
|
126 | }
|
127 |
|
128 | function setType(url) {
|
129 | if (/\.json$/.test(url)) {
|
130 | return 'json'
|
131 | }
|
132 | if (/\.jsonp$/.test(url)) {
|
133 | return 'jsonp'
|
134 | }
|
135 | if (/\.js$/.test(url)) {
|
136 | return 'js'
|
137 | }
|
138 | if (/\.html?$/.test(url)) {
|
139 | return 'html'
|
140 | }
|
141 | if (/\.xml$/.test(url)) {
|
142 | return 'xml'
|
143 | }
|
144 | return 'js'
|
145 | }
|
146 |
|
147 | function init(o, fn) {
|
148 | this.url = typeof o == 'string' ? o : o.url
|
149 | this.timeout = null
|
150 | var type = o.type || setType(this.url),
|
151 | self = this
|
152 | fn = fn ||
|
153 | function() {}
|
154 |
|
155 | if (o.timeout) {
|
156 | this.timeout = setTimeout(function() {
|
157 | self.abort()
|
158 | error()
|
159 | }, o.timeout)
|
160 | }
|
161 |
|
162 | function complete(resp) {
|
163 | o.complete && o.complete(resp)
|
164 | }
|
165 |
|
166 | function success(resp) {
|
167 | o.timeout && clearTimeout(self.timeout) && (self.timeout = null)
|
168 | var r = resp.responseText
|
169 |
|
170 | if (r) {
|
171 | switch (type) {
|
172 | case 'json':
|
173 | resp = win.JSON ? win.JSON.parse(r) : eval('(' + r + ')')
|
174 | break;
|
175 | case 'js':
|
176 | resp = eval(r)
|
177 | break;
|
178 | case 'html':
|
179 | resp = r
|
180 | break;
|
181 | }
|
182 | }
|
183 |
|
184 | fn(resp)
|
185 | o.success && o.success(resp)
|
186 | complete(resp)
|
187 | }
|
188 |
|
189 | function error(resp) {
|
190 | o.error && o.error(resp)
|
191 | complete(resp)
|
192 | }
|
193 |
|
194 | this.request = getRequest(o, success, error)
|
195 | }
|
196 |
|
197 | Reqwest.prototype = {
|
198 | abort: function() {
|
199 | this.request.abort()
|
200 | }
|
201 |
|
202 | ,
|
203 | retry: function() {
|
204 | init.call(this, this.o, this.fn)
|
205 | }
|
206 | }
|
207 |
|
208 | function reqwest(o, fn) {
|
209 | return new Reqwest(o, fn)
|
210 | }
|
211 |
|
212 | function enc(v) {
|
213 | return encodeURIComponent(v)
|
214 | }
|
215 |
|
216 | function serial(el) {
|
217 | var n = el.name
|
218 |
|
219 | if (el.disabled || !n) {
|
220 | return ''
|
221 | }
|
222 | n = enc(n)
|
223 | switch (el.tagName.toLowerCase()) {
|
224 | case 'input':
|
225 | switch (el.type) {
|
226 |
|
227 | case 'reset':
|
228 | case 'button':
|
229 | case 'image':
|
230 | case 'file':
|
231 | return ''
|
232 | case 'checkbox':
|
233 | case 'radio':
|
234 | return el.checked ? n + '=' + (el.value ? enc(el.value) : true) + '&' : ''
|
235 | default:
|
236 |
|
237 | return n + '=' + (el.value ? enc(el.value) : '') + '&'
|
238 | }
|
239 | break;
|
240 | case 'textarea':
|
241 | return n + '=' + enc(el.value) + '&'
|
242 | case 'select':
|
243 |
|
244 | return n + '=' + enc(el.options[el.selectedIndex].value) + '&'
|
245 | }
|
246 | return ''
|
247 | }
|
248 |
|
249 | reqwest.serialize = function(form) {
|
250 | var fields = [form[byTag]('input'), form[byTag]('select'), form[byTag]('textarea')],
|
251 | serialized = []
|
252 |
|
253 | for (var i = 0, l = fields.length; i < l; ++i) {
|
254 | for (var j = 0, l2 = fields[i].length; j < l2; ++j) {
|
255 | serialized.push(serial(fields[i][j]))
|
256 | }
|
257 | }
|
258 | return serialized.join('').replace(/&$/, '')
|
259 | }
|
260 |
|
261 | reqwest.serializeArray = function(f) {
|
262 | for (var pairs = this.serialize(f).split('&'), i = 0, l = pairs.length, r = [], o; i < l; i++) {
|
263 | pairs[i] && (o = pairs[i].split('=')) && r.push({
|
264 | name: o[0],
|
265 | value: o[1]
|
266 | })
|
267 | }
|
268 | return r
|
269 | }
|
270 |
|
271 | var old = context.reqwest
|
272 | reqwest.noConflict = function() {
|
273 | context.reqwest = old
|
274 | return this
|
275 | }
|
276 |
|
277 |
|
278 | if (typeof module !== 'undefined') module.exports = reqwest
|
279 | context['reqwest'] = reqwest
|
280 |
|
281 | }(this, window)
|
282 |
|
283 | `
|
284 | (exports ? this).reqwest = if window? then window.reqwest else reqwest
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 | rbracket = /\[\]$/
|
295 | r20 = /%20/g
|
296 | param = (a) ->
|
297 | s = []
|
298 | add = (key, value) ->
|
299 | value = (if Batman.typeOf(value) is 'function' then value() else value)
|
300 | s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value)
|
301 |
|
302 | if Batman.typeOf(a) is 'Array'
|
303 | for value, name of a
|
304 | add name, value
|
305 | else
|
306 | for k, v of a
|
307 | buildParams k, v, add
|
308 | s.join("&").replace r20, "+"
|
309 |
|
310 | buildParams = (prefix, obj, add) ->
|
311 | if Batman.typeOf(obj) is 'Array'
|
312 | for v, i in obj
|
313 | if rbracket.test(prefix)
|
314 | add prefix, v
|
315 | else
|
316 | buildParams prefix + "[" + (if typeof v == "object" or Batman.typeOf(v) is 'Array' then i else "") + "]", v, add
|
317 | else if obj? and typeof obj == "object"
|
318 | for name of obj
|
319 | buildParams prefix + "[" + name + "]", obj[name], add
|
320 | else
|
321 | add prefix, obj
|
322 |
|
323 | Batman.Request::send = (data) ->
|
324 | @fire 'loading'
|
325 |
|
326 | options =
|
327 | url: @get 'url'
|
328 | method: @get 'method'
|
329 | type: @get 'type'
|
330 | headers: {}
|
331 |
|
332 | success: (response) =>
|
333 | @set 'response', response
|
334 | @set 'status', xhr.status
|
335 | @fire 'success', response
|
336 |
|
337 | error: (xhr) =>
|
338 | @set 'response', xhr.responseText || xhr.content
|
339 | @set 'status', xhr.status
|
340 | xhr.request = @
|
341 | @fire 'error', xhr
|
342 |
|
343 | complete: =>
|
344 | @fire 'loaded'
|
345 |
|
346 | if options.method in ['PUT', 'POST']
|
347 | unless @get('formData')
|
348 | options.headers['Content-type'] = @get 'contentType'
|
349 | data = data || @get('data')
|
350 | if options.method is 'GET'
|
351 | options.url += param(data)
|
352 | else
|
353 | options.data = param(data)
|
354 | else
|
355 | options.data = @constructor.objectToFormData(options.data)
|
356 |
|
357 |
|
358 | xhr = (reqwest options).request
|
359 |
|
360 | prefixes = ['Webkit', 'Moz', 'O', 'ms', '']
|
361 | Batman.mixins.animation =
|
362 | initialize: ->
|
363 | for prefix in prefixes
|
364 | @style["#{prefix}Transform"] = 'scale(0, 0)'
|
365 | @style.opacity = 0
|
366 |
|
367 | @style["#{prefix}TransitionProperty"] = "#{if prefix then '-' + prefix.toLowerCase() + '-' else ''}transform, opacity"
|
368 | @style["#{prefix}TransitionDuration"] = "0.8s, 0.55s"
|
369 | @style["#{prefix}TransformOrigin"] = "left top"
|
370 | @
|
371 | show: (addToParent) ->
|
372 | show = =>
|
373 | @style.opacity = 1
|
374 | for prefix in prefixes
|
375 | @style["#{prefix}Transform"] = 'scale(1, 1)'
|
376 | @
|
377 |
|
378 | if addToParent
|
379 | addToParent.append?.appendChild @
|
380 | addToParent.before?.parentNode.insertBefore @, addToParent.before
|
381 |
|
382 | setTimeout show, 0
|
383 | else
|
384 | show()
|
385 | @
|
386 | hide: (shouldRemove) ->
|
387 | @style.opacity = 0
|
388 | for prefix in prefixes
|
389 | @style["#{prefix}Transform"] = 'scale(0, 0)'
|
390 |
|
391 | setTimeout((=> @parentNode?.removeChild @), 600) if shouldRemove
|
392 | @
|