rails_admin 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rails_admin might be problematic. Click here for more details.

data/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # RailsAdmin
2
+ [![Gem Version](https://badge.fury.io/rb/rails_admin.png)][gem]
2
3
  [![Build Status](https://secure.travis-ci.org/sferik/rails_admin.png?branch=master)][travis]
3
4
  [![Dependency Status](https://gemnasium.com/sferik/rails_admin.png?travis)][gemnasium]
4
5
  [![Code Climate](https://codeclimate.com/badge.png)][codeclimate]
5
- [![Pledgie](https://www.pledgie.com/campaigns/15917.png)][pledgie]
6
+ [![Pledgie](http://www.pledgie.com/campaigns/15917.png)][pledgie]
6
7
  [![Flattr](http://api.flattr.com/button/flattr-badge-large.png)][flattr]
7
8
 
8
9
  RailsAdmin is a Rails engine that provides an easy-to-use interface for managing your data.
9
10
 
11
+ [gem]: https://rubygems.org/gems/rails_admin
10
12
  [travis]: http://travis-ci.org/sferik/rails_admin
11
13
  [gemnasium]: https://gemnasium.com/sferik/rails_admin
12
14
  [codeclimate]: https://codeclimate.com/github/sferik/rails_admin
@@ -4,28 +4,36 @@
4
4
 
5
5
  (function($){
6
6
 
7
- // When called on a link, fetches the href with ajax into the
8
- // container specified as the first parameter or with the data-pjax
9
- // attribute on the link itself.
7
+ // When called on a container with a selector, fetches the href with
8
+ // ajax into the container or with the data-pjax attribute on the link
9
+ // itself.
10
10
  //
11
11
  // Tries to make sure the back button and ctrl+click work the way
12
12
  // you'd expect.
13
13
  //
14
+ // Exported as $.fn.pjax
15
+ //
14
16
  // Accepts a jQuery ajax options object that may include these
15
17
  // pjax specific options:
16
18
  //
19
+ //
17
20
  // container - Where to stick the response body. Usually a String selector.
18
21
  // $(container).html(xhr.responseBody)
22
+ // (default: current jquery context)
19
23
  // push - Whether to pushState the URL. Defaults to true (of course).
20
24
  // replace - Want to use replaceState instead? That's cool.
21
25
  //
22
- // For convenience the first parameter can be either the container or
26
+ // For convenience the second parameter can be either the container or
23
27
  // the options object.
24
28
  //
25
29
  // Returns the jQuery object
26
- $.fn.pjax = function( container, options ) {
27
- return this.live('click.pjax', function(event){
28
- return handleClick(event, container, options)
30
+ function fnPjax(selector, container, options) {
31
+ var context = this
32
+ return this.on('click.pjax', selector, function(event) {
33
+ var opts = $.extend({}, optionsFor(container, options))
34
+ if (!opts.container)
35
+ opts.container = $(this).attr('data-pjax') || context
36
+ handleClick(event, opts)
29
37
  })
30
38
  }
31
39
 
@@ -38,16 +46,16 @@ $.fn.pjax = function( container, options ) {
38
46
  //
39
47
  // Examples
40
48
  //
41
- // $('a').live('click', $.pjax.click)
49
+ // $(document).on('click', 'a', $.pjax.click)
42
50
  // // is the same as
43
- // $('a').pjax()
51
+ // $(document).pjax('a')
44
52
  //
45
53
  // $(document).on('click', 'a', function(event) {
46
54
  // var container = $(this).closest('[data-pjax-container]')
47
- // return $.pjax.click(event, container)
55
+ // $.pjax.click(event, container)
48
56
  // })
49
57
  //
50
- // Returns false if pjax runs, otherwise nothing.
58
+ // Returns nothing.
51
59
  function handleClick(event, container, options) {
52
60
  options = optionsFor(container, options)
53
61
 
@@ -58,7 +66,7 @@ function handleClick(event, container, options) {
58
66
 
59
67
  // Middle click, cmd click, and ctrl click should open
60
68
  // links in a new tab as normal.
61
- if ( event.which > 1 || event.metaKey )
69
+ if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey )
62
70
  return
63
71
 
64
72
  // Ignore cross origin links
@@ -66,24 +74,62 @@ function handleClick(event, container, options) {
66
74
  return
67
75
 
68
76
  // Ignore anchors on the same page
69
- if ( link.hash && link.href.replace(link.hash, '') ===
70
- location.href.replace(location.hash, '') )
77
+ if (link.hash && link.href.replace(link.hash, '') ===
78
+ location.href.replace(location.hash, ''))
79
+ return
80
+
81
+ // Ignore empty anchor "foo.html#"
82
+ if (link.href === location.href + '#')
71
83
  return
72
84
 
73
85
  var defaults = {
74
86
  url: link.href,
75
87
  container: $(link).attr('data-pjax'),
76
88
  target: link,
77
- clickedElement: $(link), // DEPRECATED: use target
78
89
  fragment: null
79
90
  }
80
91
 
81
- $.pjax($.extend({}, defaults, options))
92
+ pjax($.extend({}, defaults, options))
82
93
 
83
94
  event.preventDefault()
84
- return false
85
95
  }
86
96
 
97
+ // Public: pjax on form submit handler
98
+ //
99
+ // Exported as $.pjax.submit
100
+ //
101
+ // event - "click" jQuery.Event
102
+ // options - pjax options
103
+ //
104
+ // Examples
105
+ //
106
+ // $(document).on('submit', 'form', function(event) {
107
+ // var container = $(this).closest('[data-pjax-container]')
108
+ // $.pjax.submit(event, container)
109
+ // })
110
+ //
111
+ // Returns nothing.
112
+ function handleSubmit(event, container, options) {
113
+ options = optionsFor(container, options)
114
+
115
+ var form = event.currentTarget
116
+
117
+ if (form.tagName.toUpperCase() !== 'FORM')
118
+ throw "$.pjax.submit requires a form element"
119
+
120
+ var defaults = {
121
+ type: form.method,
122
+ url: form.action,
123
+ data: $(form).serializeArray(),
124
+ container: $(form).attr('data-pjax'),
125
+ target: form,
126
+ fragment: null
127
+ }
128
+
129
+ pjax($.extend({}, defaults, options))
130
+
131
+ event.preventDefault()
132
+ }
87
133
 
88
134
  // Loads a URL with ajax, puts the response body inside a container,
89
135
  // then pushState()'s the loaded URL.
@@ -104,7 +150,7 @@ function handleClick(event, container, options) {
104
150
  // console.log( xhr.readyState )
105
151
  //
106
152
  // Returns whatever $.ajax returns.
107
- var pjax = $.pjax = function( options ) {
153
+ function pjax(options) {
108
154
  options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options)
109
155
 
110
156
  if ($.isFunction(options.url)) {
@@ -113,18 +159,8 @@ var pjax = $.pjax = function( options ) {
113
159
 
114
160
  var target = options.target
115
161
 
116
- // DEPRECATED: use options.target
117
- if (!target && options.clickedElement) target = options.clickedElement[0]
118
-
119
162
  var hash = parseURL(options.url).hash
120
163
 
121
- // DEPRECATED: Save references to original event callbacks. However,
122
- // listening for custom pjax:* events is prefered.
123
- var oldBeforeSend = options.beforeSend,
124
- oldComplete = options.complete,
125
- oldSuccess = options.success,
126
- oldError = options.error
127
-
128
164
  var context = options.context = findContainerFor(options.container)
129
165
 
130
166
  // We want the browser to maintain two separate internal caches: one
@@ -143,13 +179,9 @@ var pjax = $.pjax = function( options ) {
143
179
  var timeoutTimer
144
180
 
145
181
  options.beforeSend = function(xhr, settings) {
146
- if (settings.timeout > 0) {
147
- timeoutTimer = setTimeout(function() {
148
- if (fire('pjax:timeout', [xhr, options]))
149
- xhr.abort('timeout')
150
- }, settings.timeout)
151
-
152
- // Clear timeout setting so jquerys internal timeout isn't invoked
182
+ // No timeout for non-GET requests
183
+ // Its not safe to request the resource again with a fallback method.
184
+ if (settings.type !== 'GET') {
153
185
  settings.timeout = 0
154
186
  }
155
187
 
@@ -158,68 +190,67 @@ var pjax = $.pjax = function( options ) {
158
190
 
159
191
  var result
160
192
 
161
- // DEPRECATED: Invoke original `beforeSend` handler
162
- if (oldBeforeSend) {
163
- result = oldBeforeSend.apply(this, arguments)
164
- if (result === false) return false
165
- }
193
+ if (!fire('pjax:beforeSend', [xhr, settings]))
194
+ return false
195
+
196
+ if (settings.timeout > 0) {
197
+ timeoutTimer = setTimeout(function() {
198
+ if (fire('pjax:timeout', [xhr, options]))
199
+ xhr.abort('timeout')
200
+ }, settings.timeout)
166
201
 
167
- if (!fire('pjax:beforeSend', [xhr, settings])) return false
202
+ // Clear timeout setting so jquerys internal timeout isn't invoked
203
+ settings.timeout = 0
204
+ }
168
205
 
169
- fire('pjax:start', [xhr, options])
170
- // start.pjax is deprecated
171
- fire('start.pjax', [xhr, options])
206
+ options.requestUrl = parseURL(settings.url).href
172
207
  }
173
208
 
174
209
  options.complete = function(xhr, textStatus) {
175
210
  if (timeoutTimer)
176
211
  clearTimeout(timeoutTimer)
177
212
 
178
- // DEPRECATED: Invoke original `complete` handler
179
- if (oldComplete) oldComplete.apply(this, arguments)
180
-
181
213
  fire('pjax:complete', [xhr, textStatus, options])
182
214
 
183
215
  fire('pjax:end', [xhr, options])
184
- // end.pjax is deprecated
185
- fire('end.pjax', [xhr, options])
186
216
  }
187
217
 
188
218
  options.error = function(xhr, textStatus, errorThrown) {
189
219
  var container = extractContainer("", xhr, options)
190
220
 
191
- // DEPRECATED: Invoke original `error` handler
192
- if (oldError) oldError.apply(this, arguments)
193
-
194
221
  var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options])
195
- if (textStatus !== 'abort' && allowed)
196
- window.location = container.url
222
+ if (options.type == 'GET' && textStatus !== 'abort' && allowed) {
223
+ locationReplace(container.url)
224
+ }
197
225
  }
198
226
 
199
227
  options.success = function(data, status, xhr) {
200
228
  var container = extractContainer(data, xhr, options)
201
229
 
202
230
  if (!container.contents) {
203
- window.location = container.url
231
+ locationReplace(container.url)
204
232
  return
205
233
  }
206
234
 
207
235
  pjax.state = {
208
236
  id: options.id || uniqueId(),
209
237
  url: container.url,
238
+ title: container.title,
210
239
  container: context.selector,
211
240
  fragment: options.fragment,
212
241
  timeout: options.timeout
213
242
  }
214
243
 
244
+ if (options.push || options.replace) {
245
+ window.history.replaceState(pjax.state, container.title, container.url)
246
+ }
247
+
215
248
  if (container.title) document.title = container.title
216
249
  context.html(container.contents)
217
250
 
218
- if ( options.replace ) {
219
- window.history.replaceState(pjax.state, container.title, container.url)
220
- } else if ( options.push ) {
221
- window.history.pushState(pjax.state, container.title, container.url)
222
- }
251
+ // Scroll to top by default
252
+ if (typeof options.scrollTo === 'number')
253
+ $(window).scrollTop(options.scrollTo)
223
254
 
224
255
  // Google Analytics support
225
256
  if ( (options.replace || options.push) && window._gaq )
@@ -228,12 +259,21 @@ var pjax = $.pjax = function( options ) {
228
259
  // If the URL has a hash in it, make sure the browser
229
260
  // knows to navigate to the hash.
230
261
  if ( hash !== '' ) {
231
- window.location.href = hash
262
+ // Avoid using simple hash set here. Will add another history
263
+ // entry. Replace the url with replaceState and scroll to target
264
+ // by hand.
265
+ //
266
+ // window.location.hash = hash
267
+ var url = parseURL(container.url)
268
+ url.hash = hash
269
+
270
+ pjax.state.url = url.href
271
+ window.history.replaceState(pjax.state, container.title, url.href)
272
+
273
+ var target = $(url.hash)
274
+ if (target.length) $(window).scrollTop(target.offset().top)
232
275
  }
233
276
 
234
- // DEPRECATED: Invoke original `success` handler
235
- if (oldSuccess) oldSuccess.apply(this, arguments)
236
-
237
277
  fire('pjax:success', [data, status, xhr, options])
238
278
  }
239
279
 
@@ -246,6 +286,7 @@ var pjax = $.pjax = function( options ) {
246
286
  pjax.state = {
247
287
  id: uniqueId(),
248
288
  url: window.location.href,
289
+ title: document.title,
249
290
  container: context.selector,
250
291
  fragment: options.fragment,
251
292
  timeout: options.timeout
@@ -261,12 +302,148 @@ var pjax = $.pjax = function( options ) {
261
302
  }
262
303
 
263
304
  pjax.options = options
264
- pjax.xhr = $.ajax(options)
265
- $(document).trigger('pjax', [pjax.xhr, options])
305
+ var xhr = pjax.xhr = $.ajax(options)
306
+
307
+ if (xhr.readyState > 0) {
308
+ if (options.push && !options.replace) {
309
+ // Cache current container element before replacing it
310
+ cachePush(pjax.state.id, context.clone().contents())
311
+
312
+ window.history.pushState(null, "", stripPjaxParam(options.requestUrl))
313
+ }
314
+
315
+ fire('pjax:start', [xhr, options])
316
+ fire('pjax:send', [xhr, options])
317
+ }
266
318
 
267
319
  return pjax.xhr
268
320
  }
269
321
 
322
+ // Public: Reload current page with pjax.
323
+ //
324
+ // Returns whatever $.pjax returns.
325
+ function pjaxReload(container, options) {
326
+ var defaults = {
327
+ url: window.location.href,
328
+ push: false,
329
+ replace: true,
330
+ scrollTo: false
331
+ }
332
+
333
+ return pjax($.extend(defaults, optionsFor(container, options)))
334
+ }
335
+
336
+ // Internal: Hard replace current state with url.
337
+ //
338
+ // Work for around WebKit
339
+ // https://bugs.webkit.org/show_bug.cgi?id=93506
340
+ //
341
+ // Returns nothing.
342
+ function locationReplace(url) {
343
+ window.history.replaceState(null, "", "#")
344
+ window.location.replace(url)
345
+ }
346
+
347
+ // popstate handler takes care of the back and forward buttons
348
+ //
349
+ // You probably shouldn't use pjax on pages with other pushState
350
+ // stuff yet.
351
+ function onPjaxPopstate(event) {
352
+ var state = event.state
353
+
354
+ if (state && state.container) {
355
+ var container = $(state.container)
356
+ if (container.length) {
357
+ var contents = cacheMapping[state.id]
358
+
359
+ if (pjax.state) {
360
+ // Since state ids always increase, we can deduce the history
361
+ // direction from the previous state.
362
+ var direction = pjax.state.id < state.id ? 'forward' : 'back'
363
+
364
+ // Cache current container before replacement and inform the
365
+ // cache which direction the history shifted.
366
+ cachePop(direction, pjax.state.id, container.clone().contents())
367
+ } else {
368
+ // Page was reloaded but we have an existing history entry.
369
+ // Set it to our initial state.
370
+ pjax.state = state;
371
+ return;
372
+ }
373
+
374
+ var popstateEvent = $.Event('pjax:popstate', {
375
+ state: state,
376
+ direction: direction
377
+ })
378
+ container.trigger(popstateEvent)
379
+
380
+ var options = {
381
+ id: state.id,
382
+ url: state.url,
383
+ container: container,
384
+ push: false,
385
+ fragment: state.fragment,
386
+ timeout: state.timeout,
387
+ scrollTo: false
388
+ }
389
+
390
+ if (contents) {
391
+ container.trigger('pjax:start', [null, options])
392
+
393
+ if (state.title) document.title = state.title
394
+ container.html(contents)
395
+ pjax.state = state
396
+
397
+ container.trigger('pjax:end', [null, options])
398
+ } else {
399
+ pjax(options)
400
+ }
401
+
402
+ // Force reflow/relayout before the browser tries to restore the
403
+ // scroll position.
404
+ container[0].offsetHeight
405
+ } else {
406
+ locationReplace(location.href)
407
+ }
408
+ }
409
+ }
410
+
411
+ // Fallback version of main pjax function for browsers that don't
412
+ // support pushState.
413
+ //
414
+ // Returns nothing since it retriggers a hard form submission.
415
+ function fallbackPjax(options) {
416
+ var url = $.isFunction(options.url) ? options.url() : options.url,
417
+ method = options.type ? options.type.toUpperCase() : 'GET'
418
+
419
+ var form = $('<form>', {
420
+ method: method === 'GET' ? 'GET' : 'POST',
421
+ action: url,
422
+ style: 'display:none'
423
+ })
424
+
425
+ if (method !== 'GET' && method !== 'POST') {
426
+ form.append($('<input>', {
427
+ type: 'hidden',
428
+ name: '_method',
429
+ value: method.toLowerCase()
430
+ }))
431
+ }
432
+
433
+ var data = options.data
434
+ if (typeof data === 'string') {
435
+ $.each(data.split('&'), function(index, value) {
436
+ var pair = value.split('=')
437
+ form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
438
+ })
439
+ } else if (typeof data === 'object') {
440
+ for (key in data)
441
+ form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
442
+ }
443
+
444
+ $(document.body).append(form)
445
+ form.submit()
446
+ }
270
447
 
271
448
  // Internal: Generate unique id for state object.
272
449
  //
@@ -370,13 +547,7 @@ function findContainerFor(container) {
370
547
  //
371
548
  // Returns a jQuery object.
372
549
  function findAll(elems, selector) {
373
- var results = $()
374
- elems.each(function() {
375
- if ($(this).is(selector))
376
- results = results.add(this)
377
- results = results.add(selector, this)
378
- })
379
- return results
550
+ return elems.filter(selector).add(elems.find(selector));
380
551
  }
381
552
 
382
553
  // Internal: Extracts container and metadata from response.
@@ -395,23 +566,32 @@ function extractContainer(data, xhr, options) {
395
566
 
396
567
  // Prefer X-PJAX-URL header if it was set, otherwise fallback to
397
568
  // using the original requested url.
398
- obj.url = stripPjaxParam(xhr.getResponseHeader('X-PJAX-URL') || options.url)
569
+ obj.url = stripPjaxParam(xhr.getResponseHeader('X-PJAX-URL') || options.requestUrl)
399
570
 
400
571
  // Attempt to parse response html into elements
401
- var $data = $(data)
572
+ if (/<html/i.test(data)) {
573
+ var $head = $(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0])
574
+ var $body = $(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0])
575
+ } else {
576
+ var $head = $body = $(data)
577
+ }
402
578
 
403
579
  // If response data is empty, return fast
404
- if ($data.length === 0)
580
+ if ($body.length === 0)
405
581
  return obj
406
582
 
407
- // If there's a <title> tag in the response, use it as
583
+ // If there's a <title> tag in the header, use it as
408
584
  // the page's title.
409
- obj.title = findAll($data, 'title').last().text()
585
+ obj.title = findAll($head, 'title').last().text()
410
586
 
411
587
  if (options.fragment) {
412
588
  // If they specified a fragment, look for it in the response
413
589
  // and pull it out.
414
- var $fragment = findAll($data, options.fragment).first()
590
+ if (options.fragment === 'body') {
591
+ var $fragment = $body
592
+ } else {
593
+ var $fragment = findAll($body, options.fragment).first()
594
+ }
415
595
 
416
596
  if ($fragment.length) {
417
597
  obj.contents = $fragment.contents()
@@ -423,7 +603,7 @@ function extractContainer(data, xhr, options) {
423
603
  }
424
604
 
425
605
  } else if (!/<html/i.test(data)) {
426
- obj.contents = $data
606
+ obj.contents = $body
427
607
  }
428
608
 
429
609
  // Clean up any <title> tags
@@ -441,52 +621,110 @@ function extractContainer(data, xhr, options) {
441
621
  return obj
442
622
  }
443
623
 
624
+ // Internal: History DOM caching class.
625
+ var cacheMapping = {}
626
+ var cacheForwardStack = []
627
+ var cacheBackStack = []
444
628
 
445
- pjax.defaults = {
446
- timeout: 650,
447
- push: true,
448
- replace: false,
449
- type: 'GET',
450
- dataType: 'html'
451
- }
629
+ // Push previous state id and container contents into the history
630
+ // cache. Should be called in conjunction with `pushState` to save the
631
+ // previous container contents.
632
+ //
633
+ // id - State ID Number
634
+ // value - DOM Element to cache
635
+ //
636
+ // Returns nothing.
637
+ function cachePush(id, value) {
638
+ cacheMapping[id] = value
639
+ cacheBackStack.push(id)
640
+
641
+ // Remove all entires in forward history stack after pushing
642
+ // a new page.
643
+ while (cacheForwardStack.length)
644
+ delete cacheMapping[cacheForwardStack.shift()]
452
645
 
453
- // Export $.pjax.click
454
- pjax.click = handleClick
646
+ // Trim back history stack to max cache length.
647
+ while (cacheBackStack.length > pjax.defaults.maxCacheLength)
648
+ delete cacheMapping[cacheBackStack.shift()]
649
+ }
455
650
 
651
+ // Shifts cache from directional history cache. Should be
652
+ // called on `popstate` with the previous state id and container
653
+ // contents.
654
+ //
655
+ // direction - "forward" or "back" String
656
+ // id - State ID Number
657
+ // value - DOM Element to cache
658
+ //
659
+ // Returns nothing.
660
+ function cachePop(direction, id, value) {
661
+ var pushStack, popStack
662
+ cacheMapping[id] = value
456
663
 
457
- // Used to detect initial (useless) popstate.
458
- // If history.state exists, assume browser isn't going to fire initial popstate.
459
- var popped = ('state' in window.history), initialURL = location.href
664
+ if (direction === 'forward') {
665
+ pushStack = cacheBackStack
666
+ popStack = cacheForwardStack
667
+ } else {
668
+ pushStack = cacheForwardStack
669
+ popStack = cacheBackStack
670
+ }
460
671
 
672
+ pushStack.push(id)
673
+ if (id = popStack.pop())
674
+ delete cacheMapping[id]
675
+ }
461
676
 
462
- // popstate handler takes care of the back and forward buttons
677
+ // Install pjax functions on $.pjax to enable pushState behavior.
463
678
  //
464
- // You probably shouldn't use pjax on pages with other pushState
465
- // stuff yet.
466
- $(window).bind('popstate', function(event){
467
- // Ignore inital popstate that some browsers fire on page load
468
- var initialPop = !popped && location.href == initialURL
469
- popped = true
470
- if ( initialPop ) return
679
+ // Does nothing if already enabled.
680
+ //
681
+ // Examples
682
+ //
683
+ // $.pjax.enable()
684
+ //
685
+ // Returns nothing.
686
+ function enable() {
687
+ $.fn.pjax = fnPjax
688
+ $.pjax = pjax
689
+ $.pjax.enable = $.noop
690
+ $.pjax.disable = disable
691
+ $.pjax.click = handleClick
692
+ $.pjax.submit = handleSubmit
693
+ $.pjax.reload = pjaxReload
694
+ $.pjax.defaults = {
695
+ timeout: 650,
696
+ push: true,
697
+ replace: false,
698
+ type: 'GET',
699
+ dataType: 'html',
700
+ scrollTo: 0,
701
+ maxCacheLength: 20
702
+ }
703
+ $(window).bind('popstate.pjax', onPjaxPopstate)
704
+ }
471
705
 
472
- var state = event.state
706
+ // Disable pushState behavior.
707
+ //
708
+ // This is the case when a browser doesn't support pushState. It is
709
+ // sometimes useful to disable pushState for debugging on a modern
710
+ // browser.
711
+ //
712
+ // Examples
713
+ //
714
+ // $.pjax.disable()
715
+ //
716
+ // Returns nothing.
717
+ function disable() {
718
+ $.fn.pjax = function() { return this }
719
+ $.pjax = fallbackPjax
720
+ $.pjax.enable = enable
721
+ $.pjax.disable = $.noop
722
+ $.pjax.click = $.noop
723
+ $.pjax.submit = $.noop
724
+ $.pjax.reload = function() { window.location.reload() }
473
725
 
474
- if (state && state.container) {
475
- var container = $(state.container)
476
- if (container.length) {
477
- $.pjax({
478
- id: state.id,
479
- url: state.url,
480
- container: container,
481
- push: false,
482
- fragment: state.fragment,
483
- timeout: state.timeout
484
- })
485
- } else {
486
- window.location = location.href
487
- }
488
- }
489
- })
726
+ $(window).unbind('popstate.pjax', onPjaxPopstate)
727
+ }
490
728
 
491
729
 
492
730
  // Add the state property to jQuery's event object so we can use it in
@@ -494,50 +732,12 @@ $(window).bind('popstate', function(event){
494
732
  if ( $.inArray('state', $.event.props) < 0 )
495
733
  $.event.props.push('state')
496
734
 
497
-
498
- // Is pjax supported by this browser?
735
+ // Is pjax supported by this browser?
499
736
  $.support.pjax =
500
- window.history && window.history.pushState && window.history.replaceState
737
+ window.history && window.history.pushState && window.history.replaceState &&
501
738
  // pushState isn't reliable on iOS until 5.
502
- && !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)
503
-
504
-
505
- // Fall back to normalcy for older browsers.
506
- if ( !$.support.pjax ) {
507
- $.pjax = function( options ) {
508
- var url = $.isFunction(options.url) ? options.url() : options.url,
509
- method = options.type ? options.type.toUpperCase() : 'GET'
510
-
511
- var form = $('<form>', {
512
- method: method === 'GET' ? 'GET' : 'POST',
513
- action: url,
514
- style: 'display:none'
515
- })
516
-
517
- if (method !== 'GET' && method !== 'POST') {
518
- form.append($('<input>', {
519
- type: 'hidden',
520
- name: '_method',
521
- value: method.toLowerCase()
522
- }))
523
- }
524
-
525
- var data = options.data
526
- if (typeof data === 'string') {
527
- $.each(data.split('&'), function(index, value) {
528
- var pair = value.split('=')
529
- form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
530
- })
531
- } else if (typeof data === 'object') {
532
- for (key in data)
533
- form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
534
- }
739
+ !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)
535
740
 
536
- $(document.body).append(form)
537
- form.submit()
538
- }
539
- $.pjax.click = $.noop
540
- $.fn.pjax = function() { return this }
541
- }
741
+ $.support.pjax ? enable() : disable()
542
742
 
543
- })(jQuery);
743
+ })(jQuery);