pjax_rails 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 097fb0fd95fb00440599199ed502f5c2a25267e7
4
+ data.tar.gz: eb7d75f29172e733146484d404c436a692c5c8e8
5
+ SHA512:
6
+ metadata.gz: c4dde951c62dbff0cc9b0d9b7628a6a09e8d8c06ea8b1f0cdde2b8f1f01af7ff9dd619a1b29c7c737517441fefd4accab2e6f7d3478e1d41effa7799f00b0494
7
+ data.tar.gz: 0e810bd47708b355702028630a96c91a722548768fc9f9693d11088c2ae9ca80741981af24821cfa0c697dde7c29f912e7068e35eaf716f9019dd662d4dc2354
@@ -2,7 +2,7 @@ module Pjax
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- layout proc { |c| pjax_request? ? pjax_layout : 'application' }
5
+ layout proc { |c| pjax_request? ? pjax_layout : nil }
6
6
  helper_method :pjax_request?
7
7
 
8
8
  rescue_from Pjax::Unsupported, :with => :pjax_unsupported
@@ -16,7 +16,7 @@ module Pjax
16
16
 
17
17
  protected
18
18
  def pjax_request?
19
- env['HTTP_X_PJAX'].present?
19
+ request.env['HTTP_X_PJAX'].present?
20
20
  end
21
21
 
22
22
  def pjax_layout
@@ -2,8 +2,10 @@ require 'pjax'
2
2
 
3
3
  module PjaxRails
4
4
  class Engine < ::Rails::Engine
5
- initializer "pjax_rails.add_controller" do
6
- config.to_prepare { ApplicationController.send :include, Pjax }
5
+ initializer 'pjax_rails.add_controller' do
6
+ ActiveSupport.on_load :action_controller do
7
+ ActionController::Base.send :include, Pjax
8
+ end
7
9
  end
8
10
  end
9
- end
11
+ end
@@ -70,7 +70,7 @@ function handleClick(event, container, options) {
70
70
  return
71
71
 
72
72
  // Ignore cross origin links
73
- if ( location.protocol !== link.protocol || location.host !== link.host )
73
+ if ( location.protocol !== link.protocol || location.hostname !== link.hostname )
74
74
  return
75
75
 
76
76
  // Ignore anchors on the same page
@@ -85,13 +85,17 @@ function handleClick(event, container, options) {
85
85
  var defaults = {
86
86
  url: link.href,
87
87
  container: $(link).attr('data-pjax'),
88
- target: link,
89
- fragment: null
88
+ target: link
90
89
  }
91
90
 
92
- pjax($.extend({}, defaults, options))
91
+ var opts = $.extend({}, defaults, options)
92
+ var clickEvent = $.Event('pjax:click')
93
+ $(link).trigger(clickEvent, [opts])
93
94
 
94
- event.preventDefault()
95
+ if (!clickEvent.isDefaultPrevented()) {
96
+ pjax(opts)
97
+ event.preventDefault()
98
+ }
95
99
  }
96
100
 
97
101
  // Public: pjax on form submit handler
@@ -118,13 +122,11 @@ function handleSubmit(event, container, options) {
118
122
  throw "$.pjax.submit requires a form element"
119
123
 
120
124
  var defaults = {
121
- type: form.method,
125
+ type: form.method.toUpperCase(),
122
126
  url: form.action,
123
127
  data: $(form).serializeArray(),
124
128
  container: $(form).attr('data-pjax'),
125
- target: form,
126
- fragment: null,
127
- timeout: 0
129
+ target: form
128
130
  }
129
131
 
130
132
  pjax($.extend({}, defaults, options))
@@ -186,6 +188,12 @@ function pjax(options) {
186
188
  settings.timeout = 0
187
189
  }
188
190
 
191
+ xhr.setRequestHeader('X-PJAX', 'true')
192
+ xhr.setRequestHeader('X-PJAX-Container', context.selector)
193
+
194
+ if (!fire('pjax:beforeSend', [xhr, settings]))
195
+ return false
196
+
189
197
  if (settings.timeout > 0) {
190
198
  timeoutTimer = setTimeout(function() {
191
199
  if (fire('pjax:timeout', [xhr, options]))
@@ -196,14 +204,6 @@ function pjax(options) {
196
204
  settings.timeout = 0
197
205
  }
198
206
 
199
- xhr.setRequestHeader('X-PJAX', 'true')
200
- xhr.setRequestHeader('X-PJAX-Container', context.selector)
201
-
202
- var result
203
-
204
- if (!fire('pjax:beforeSend', [xhr, settings]))
205
- return false
206
-
207
207
  options.requestUrl = parseURL(settings.url).href
208
208
  }
209
209
 
@@ -226,8 +226,23 @@ function pjax(options) {
226
226
  }
227
227
 
228
228
  options.success = function(data, status, xhr) {
229
+ // If $.pjax.defaults.version is a function, invoke it first.
230
+ // Otherwise it can be a static string.
231
+ var currentVersion = (typeof $.pjax.defaults.version === 'function') ?
232
+ $.pjax.defaults.version() :
233
+ $.pjax.defaults.version
234
+
235
+ var latestVersion = xhr.getResponseHeader('X-PJAX-Version')
236
+
229
237
  var container = extractContainer(data, xhr, options)
230
238
 
239
+ // If there is a layout version mismatch, hard load the new url
240
+ if (currentVersion && latestVersion && currentVersion !== latestVersion) {
241
+ locationReplace(container.url)
242
+ return
243
+ }
244
+
245
+ // If the new response is missing a body, hard load the page
231
246
  if (!container.contents) {
232
247
  locationReplace(container.url)
233
248
  return
@@ -246,17 +261,28 @@ function pjax(options) {
246
261
  window.history.replaceState(pjax.state, container.title, container.url)
247
262
  }
248
263
 
264
+ // Clear out any focused controls before inserting new page contents.
265
+ document.activeElement.blur()
266
+
249
267
  if (container.title) document.title = container.title
250
268
  context.html(container.contents)
251
269
 
270
+ // FF bug: Won't autofocus fields that are inserted via JS.
271
+ // This behavior is incorrect. So if theres no current focus, autofocus
272
+ // the last field.
273
+ //
274
+ // http://www.w3.org/html/wg/drafts/html/master/forms.html
275
+ var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0]
276
+ if (autofocusEl && document.activeElement !== autofocusEl) {
277
+ autofocusEl.focus();
278
+ }
279
+
280
+ executeScriptTags(container.scripts)
281
+
252
282
  // Scroll to top by default
253
283
  if (typeof options.scrollTo === 'number')
254
284
  $(window).scrollTop(options.scrollTo)
255
285
 
256
- // Google Analytics support
257
- if ( (options.replace || options.push) && window._gaq )
258
- _gaq.push(['_trackPageview'])
259
-
260
286
  // If the URL has a hash in it, make sure the browser
261
287
  // knows to navigate to the hash.
262
288
  if ( hash !== '' ) {
@@ -345,6 +371,23 @@ function locationReplace(url) {
345
371
  window.location.replace(url)
346
372
  }
347
373
 
374
+
375
+ var initialPop = true
376
+ var initialURL = window.location.href
377
+ var initialState = window.history.state
378
+
379
+ // Initialize $.pjax.state if possible
380
+ // Happens when reloading a page and coming forward from a different
381
+ // session history.
382
+ if (initialState && initialState.container) {
383
+ pjax.state = initialState
384
+ }
385
+
386
+ // Non-webkit browsers don't fire an initial popstate event
387
+ if ('state' in window.history) {
388
+ initialPop = false
389
+ }
390
+
348
391
  // popstate handler takes care of the back and forward buttons
349
392
  //
350
393
  // You probably shouldn't use pjax on pages with other pushState
@@ -353,14 +396,23 @@ function onPjaxPopstate(event) {
353
396
  var state = event.state
354
397
 
355
398
  if (state && state.container) {
399
+ // When coming forward from a separate history session, will get an
400
+ // initial pop with a state we are already at. Skip reloading the current
401
+ // page.
402
+ if (initialPop && initialURL == state.url) return
403
+
404
+ // If popping back to the same state, just skip.
405
+ // Could be clicking back from hashchange rather than a pushState.
406
+ if (pjax.state.id === state.id) return
407
+
356
408
  var container = $(state.container)
357
409
  if (container.length) {
358
- var contents = cacheMapping[state.id]
410
+ var direction, contents = cacheMapping[state.id]
359
411
 
360
412
  if (pjax.state) {
361
413
  // Since state ids always increase, we can deduce the history
362
414
  // direction from the previous state.
363
- var direction = pjax.state.id < state.id ? 'forward' : 'back'
415
+ direction = pjax.state.id < state.id ? 'forward' : 'back'
364
416
 
365
417
  // Cache current container before replacement and inform the
366
418
  // cache which direction the history shifted.
@@ -402,6 +454,7 @@ function onPjaxPopstate(event) {
402
454
  locationReplace(location.href)
403
455
  }
404
456
  }
457
+ initialPop = false
405
458
  }
406
459
 
407
460
  // Fallback version of main pjax function for browsers that don't
@@ -546,6 +599,10 @@ function findAll(elems, selector) {
546
599
  return elems.filter(selector).add(elems.find(selector));
547
600
  }
548
601
 
602
+ function parseHTML(html) {
603
+ return $.parseHTML(html, document, true)
604
+ }
605
+
549
606
  // Internal: Extracts container and metadata from response.
550
607
  //
551
608
  // 1. Extracts X-PJAX-URL header if set
@@ -566,10 +623,10 @@ function extractContainer(data, xhr, options) {
566
623
 
567
624
  // Attempt to parse response html into elements
568
625
  if (/<html/i.test(data)) {
569
- var $head = $(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0])
570
- var $body = $(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0])
626
+ var $head = $(parseHTML(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0]))
627
+ var $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]))
571
628
  } else {
572
- var $head = $body = $(data)
629
+ var $head = $body = $(parseHTML(data))
573
630
  }
574
631
 
575
632
  // If response data is empty, return fast
@@ -605,10 +662,14 @@ function extractContainer(data, xhr, options) {
605
662
  // Clean up any <title> tags
606
663
  if (obj.contents) {
607
664
  // Remove any parent title elements
608
- obj.contents = obj.contents.not('title')
665
+ obj.contents = obj.contents.not(function() { return $(this).is('title') })
609
666
 
610
- // Then scrub any titles from their descendents
667
+ // Then scrub any titles from their descendants
611
668
  obj.contents.find('title').remove()
669
+
670
+ // Gather all script[src] elements
671
+ obj.scripts = findAll(obj.contents, 'script[src]').remove()
672
+ obj.contents = obj.contents.not(obj.scripts)
612
673
  }
613
674
 
614
675
  // Trim any whitespace off the title
@@ -617,6 +678,33 @@ function extractContainer(data, xhr, options) {
617
678
  return obj
618
679
  }
619
680
 
681
+ // Load an execute scripts using standard script request.
682
+ //
683
+ // Avoids jQuery's traditional $.getScript which does a XHR request and
684
+ // globalEval.
685
+ //
686
+ // scripts - jQuery object of script Elements
687
+ //
688
+ // Returns nothing.
689
+ function executeScriptTags(scripts) {
690
+ if (!scripts) return
691
+
692
+ var existingScripts = $('script[src]')
693
+
694
+ scripts.each(function() {
695
+ var src = this.src
696
+ var matchedScripts = existingScripts.filter(function() {
697
+ return this.src === src
698
+ })
699
+ if (matchedScripts.length) return
700
+
701
+ var script = document.createElement('script')
702
+ script.type = $(this).attr('type')
703
+ script.src = $(this).attr('src')
704
+ document.head.appendChild(script)
705
+ })
706
+ }
707
+
620
708
  // Internal: History DOM caching class.
621
709
  var cacheMapping = {}
622
710
  var cacheForwardStack = []
@@ -670,6 +758,16 @@ function cachePop(direction, id, value) {
670
758
  delete cacheMapping[id]
671
759
  }
672
760
 
761
+ // Public: Find version identifier for the initial page load.
762
+ //
763
+ // Returns String version or undefined.
764
+ function findVersion() {
765
+ return $('meta').filter(function() {
766
+ var name = $(this).attr('http-equiv')
767
+ return name && name.toUpperCase() === 'X-PJAX-VERSION'
768
+ }).attr('content')
769
+ }
770
+
673
771
  // Install pjax functions on $.pjax to enable pushState behavior.
674
772
  //
675
773
  // Does nothing if already enabled.
@@ -694,9 +792,10 @@ function enable() {
694
792
  type: 'GET',
695
793
  dataType: 'html',
696
794
  scrollTo: 0,
697
- maxCacheLength: 20
795
+ maxCacheLength: 20,
796
+ version: findVersion
698
797
  }
699
- $(window).bind('popstate.pjax', onPjaxPopstate)
798
+ $(window).on('popstate.pjax', onPjaxPopstate)
700
799
  }
701
800
 
702
801
  // Disable pushState behavior.
@@ -719,7 +818,7 @@ function disable() {
719
818
  $.pjax.submit = $.noop
720
819
  $.pjax.reload = function() { window.location.reload() }
721
820
 
722
- $(window).unbind('popstate.pjax', onPjaxPopstate)
821
+ $(window).off('popstate.pjax', onPjaxPopstate)
723
822
  }
724
823
 
725
824
 
@@ -728,7 +827,7 @@ function disable() {
728
827
  if ( $.inArray('state', $.event.props) < 0 )
729
828
  $.event.props.push('state')
730
829
 
731
- // Is pjax supported by this browser?
830
+ // Is pjax supported by this browser?
732
831
  $.support.pjax =
733
832
  window.history && window.history.pushState && window.history.replaceState &&
734
833
  // pushState isn't reliable on iOS until 5.
metadata CHANGED
@@ -1,30 +1,103 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pjax_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
5
- prerelease:
4
+ version: 0.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - David Heinemeier Hansson (PJAX by Chris Wanstrath)
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-10-22 00:00:00.000000000 Z
11
+ date: 2013-12-12 00:00:00.000000000 Z
13
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '3.2'
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
14
33
  - !ruby/object:Gem::Dependency
15
34
  name: jquery-rails
16
35
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
36
  requirements:
19
- - - ! '>='
37
+ - - '>='
20
38
  - !ruby/object:Gem::Version
21
39
  version: '0'
22
40
  type: :runtime
23
41
  prerelease: false
24
42
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
43
  requirements:
27
- - - ! '>='
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rails
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: capybara
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: poltergeist
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '>='
28
101
  - !ruby/object:Gem::Version
29
102
  version: '0'
30
103
  description:
@@ -35,32 +108,29 @@ extra_rdoc_files: []
35
108
  files:
36
109
  - lib/pjax.rb
37
110
  - lib/pjax_rails.rb
38
- - lib/assets/javascripts/pjax/enable_pjax.js
39
- - lib/assets/javascripts/pjax/page_triggers.js
40
- - lib/assets/javascripts/pjax.js
41
111
  - vendor/assets/javascripts/jquery.pjax.js
42
112
  homepage:
43
113
  licenses: []
114
+ metadata: {}
44
115
  post_install_message:
45
116
  rdoc_options: []
46
117
  require_paths:
47
118
  - lib
48
119
  required_ruby_version: !ruby/object:Gem::Requirement
49
- none: false
50
120
  requirements:
51
- - - ! '>='
121
+ - - '>='
52
122
  - !ruby/object:Gem::Version
53
123
  version: '0'
54
124
  required_rubygems_version: !ruby/object:Gem::Requirement
55
- none: false
56
125
  requirements:
57
- - - ! '>='
126
+ - - '>='
58
127
  - !ruby/object:Gem::Version
59
128
  version: '0'
60
129
  requirements: []
61
130
  rubyforge_project:
62
- rubygems_version: 1.8.24
131
+ rubygems_version: 2.1.11
63
132
  signing_key:
64
- specification_version: 3
133
+ specification_version: 4
65
134
  summary: PJAX integration for Rails 3.1+
66
135
  test_files: []
136
+ has_rdoc:
@@ -1,5 +0,0 @@
1
- // DEPRECATED: Require "jquery.pjax" instead.
2
- //
3
- //= require jquery.pjax
4
- //= require ./pjax/page_triggers
5
- //= require ./pjax/enable_pjax
@@ -1,7 +0,0 @@
1
- // DEPRECATED: This default activation selector is too domain specific
2
- // and can not be easily customized.
3
- //
4
- // This file will be removed in 0.3.
5
-
6
- $('a:not([data-remote]):not([data-behavior]):not([data-skip-pjax])')
7
- .pjax('[data-pjax-container]');
@@ -1,18 +0,0 @@
1
- // DEPRECATED: Move these events into your application if you want to
2
- // continue using them.
3
- //
4
- // This file will be removed in 0.3.
5
-
6
- $(document).ready(function() {
7
- $(document).trigger('pageChanged');
8
- $(document).trigger('pageUpdated');
9
- });
10
-
11
- $(document).bind('pjax:end', function() {
12
- $(document).trigger('pageChanged');
13
- $(document).trigger('pageUpdated');
14
- });
15
-
16
- $(document).bind('ajaxComplete', function() {
17
- $(document).trigger('pageUpdated');
18
- });