pjax_rails 0.3.4 → 0.4.0

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.
@@ -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
- });