pjax_rails 0.1.10 → 0.2.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,5 @@
1
+ // DEPRECATED: Require "jquery.pjax" instead.
2
+ //
3
+ //= require jquery.pjax
4
+ //= require ./pjax/page_triggers
5
+ //= require ./pjax/enable_pjax
@@ -0,0 +1,7 @@
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]');
@@ -0,0 +1,18 @@
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
+ });
@@ -1,30 +1,41 @@
1
1
  module Pjax
2
2
  extend ActiveSupport::Concern
3
-
3
+
4
4
  included do
5
- layout ->(c) { pjax_request? ? false : 'application' }
5
+ layout proc { |c| pjax_request? ? pjax_layout : 'application' }
6
6
  helper_method :pjax_request?
7
+
8
+ before_filter :strip_pjax_param, :if => :pjax_request?
9
+ before_filter :set_pjax_url, :if => :pjax_request?
7
10
  end
8
-
9
- private
10
- def redirect_pjax_to(action, url = nil)
11
- new_url = url_for(url ? url : { action: action })
12
-
13
- render js: <<-EJS
14
- if (!window.history || !window.history.pushState) {
15
- window.location.href = '#{new_url}';
16
- } else {
17
- $('[data-pjax-container]').html(#{render_to_string("#{action}.html.erb", layout: false).to_json});
18
- $(document).trigger('end.pjax');
19
-
20
- var title = $.trim($('[data-pjax-container]').find('title').remove().text());
21
- if (title) document.title = title;
22
- window.history.pushState({}, document.title, '#{new_url}');
23
- }
24
- EJS
25
- end
26
11
 
12
+ protected
27
13
  def pjax_request?
28
14
  env['HTTP_X_PJAX'].present?
29
15
  end
30
- end
16
+
17
+ def pjax_layout
18
+ false
19
+ end
20
+
21
+ def pjax_container
22
+ return unless pjax_request?
23
+ request.headers['X-PJAX-Container']
24
+ end
25
+
26
+ def strip_pjax_param
27
+ params.delete(:_pjax)
28
+ request.env['QUERY_STRING'].sub!(/_pjax=[^&]+&?/, '')
29
+
30
+ request.env.delete('rack.request.query_string')
31
+ request.env.delete('rack.request.query_hash')
32
+ request.env.delete('action_dispatch.request.query_parameters')
33
+
34
+ request.instance_variable_set('@original_fullpath', nil)
35
+ request.instance_variable_set('@fullpath', nil)
36
+ end
37
+
38
+ def set_pjax_url
39
+ response.headers['X-PJAX-URL'] = request.url
40
+ end
41
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'pjax_rails'
3
- s.version = '0.1.10'
3
+ s.version = '0.2.0'
4
4
  s.author = 'David Heinemeier Hansson (PJAX by Chris Wanstrath)'
5
5
  s.email = 'david@loudthinking.com'
6
6
  s.summary = 'PJAX integration for Rails 3.1+'
@@ -0,0 +1,470 @@
1
+ // jquery.pjax.js
2
+ // copyright chris wanstrath
3
+ // https://github.com/defunkt/jquery-pjax
4
+
5
+ (function($){
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.
10
+ //
11
+ // Tries to make sure the back button and ctrl+click work the way
12
+ // you'd expect.
13
+ //
14
+ // Accepts a jQuery ajax options object that may include these
15
+ // pjax specific options:
16
+ //
17
+ // container - Where to stick the response body. Usually a String selector.
18
+ // $(container).html(xhr.responseBody)
19
+ // push - Whether to pushState the URL. Defaults to true (of course).
20
+ // replace - Want to use replaceState instead? That's cool.
21
+ //
22
+ // For convenience the first parameter can be either the container or
23
+ // the options object.
24
+ //
25
+ // Returns the jQuery object
26
+ $.fn.pjax = function( container, options ) {
27
+ return this.live('click', function(event){
28
+ return handleClick(event, container, options)
29
+ })
30
+ }
31
+
32
+ // Public: pjax on click handler
33
+ //
34
+ // Exported as $.pjax.click.
35
+ //
36
+ // event - "click" jQuery.Event
37
+ // options - pjax options
38
+ //
39
+ // Examples
40
+ //
41
+ // $('a').live('click', $.pjax.click)
42
+ // // is the same as
43
+ // $('a').pjax()
44
+ //
45
+ // $(document).on('click', 'a', function(event) {
46
+ // var container = $(this).closest('[data-pjax-container]')
47
+ // return $.pjax.click(event, container)
48
+ // })
49
+ //
50
+ // Returns false if pjax runs, otherwise nothing.
51
+ function handleClick(event, container, options) {
52
+ options = optionsFor(container, options)
53
+
54
+ var link = event.currentTarget
55
+
56
+ if (link.tagName.toUpperCase() !== 'A')
57
+ throw "$.fn.pjax or $.pjax.click requires an anchor element"
58
+
59
+ // Middle click, cmd click, and ctrl click should open
60
+ // links in a new tab as normal.
61
+ if ( event.which > 1 || event.metaKey )
62
+ return
63
+
64
+ // Ignore cross origin links
65
+ if ( location.protocol !== link.protocol || location.host !== link.host )
66
+ return
67
+
68
+ // Ignore anchors on the same page
69
+ if ( link.hash && link.href.replace(link.hash, '') ===
70
+ location.href.replace(location.hash, '') )
71
+ return
72
+
73
+ var defaults = {
74
+ url: link.href,
75
+ container: $(link).attr('data-pjax'),
76
+ target: link,
77
+ clickedElement: $(link), // DEPRECATED: use target
78
+ fragment: null
79
+ }
80
+
81
+ $.pjax($.extend({}, defaults, options))
82
+
83
+ event.preventDefault()
84
+ return false
85
+ }
86
+
87
+ // Internal: Strips _pjax param from url
88
+ //
89
+ // url - String
90
+ //
91
+ // Returns String.
92
+ function stripPjaxParam(url) {
93
+ return url
94
+ .replace(/\?_pjax=[^&]+&?/, '?')
95
+ .replace(/_pjax=[^&]+&?/, '')
96
+ .replace(/[\?&]$/, '')
97
+ }
98
+
99
+ // Internal: Parse URL components and returns a Locationish object.
100
+ //
101
+ // url - String URL
102
+ //
103
+ // Returns HTMLAnchorElement that acts like Location.
104
+ function parseURL(url) {
105
+ var a = document.createElement('a')
106
+ a.href = url
107
+ return a
108
+ }
109
+
110
+
111
+ // Loads a URL with ajax, puts the response body inside a container,
112
+ // then pushState()'s the loaded URL.
113
+ //
114
+ // Works just like $.ajax in that it accepts a jQuery ajax
115
+ // settings object (with keys like url, type, data, etc).
116
+ //
117
+ // Accepts these extra keys:
118
+ //
119
+ // container - Where to stick the response body.
120
+ // $(container).html(xhr.responseBody)
121
+ // push - Whether to pushState the URL. Defaults to true (of course).
122
+ // replace - Want to use replaceState instead? That's cool.
123
+ //
124
+ // Use it just like $.ajax:
125
+ //
126
+ // var xhr = $.pjax({ url: this.href, container: '#main' })
127
+ // console.log( xhr.readyState )
128
+ //
129
+ // Returns whatever $.ajax returns.
130
+ var pjax = $.pjax = function( options ) {
131
+ options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options)
132
+
133
+ if ($.isFunction(options.url)) {
134
+ options.url = options.url()
135
+ }
136
+
137
+ var target = options.target
138
+
139
+ // DEPRECATED: use options.target
140
+ if (!target && options.clickedElement) target = options.clickedElement[0]
141
+
142
+ var url = options.url
143
+ var hash = parseURL(url).hash
144
+
145
+ // DEPRECATED: Save references to original event callbacks. However,
146
+ // listening for custom pjax:* events is prefered.
147
+ var oldBeforeSend = options.beforeSend,
148
+ oldComplete = options.complete,
149
+ oldSuccess = options.success,
150
+ oldError = options.error
151
+
152
+ var context = options.context = findContainerFor(options.container)
153
+
154
+ // We want the browser to maintain two separate internal caches: one
155
+ // for pjax'd partial page loads and one for normal page loads.
156
+ // Without adding this secret parameter, some browsers will often
157
+ // confuse the two.
158
+ if (!options.data) options.data = {}
159
+ options.data._pjax = context.selector
160
+
161
+ function fire(type, args) {
162
+ var event = $.Event(type, { relatedTarget: target })
163
+ context.trigger(event, args)
164
+ return !event.isDefaultPrevented()
165
+ }
166
+
167
+ var timeoutTimer
168
+
169
+ options.beforeSend = function(xhr, settings) {
170
+ url = stripPjaxParam(settings.url)
171
+
172
+ if (settings.timeout > 0) {
173
+ timeoutTimer = setTimeout(function() {
174
+ if (fire('pjax:timeout', [xhr, options]))
175
+ xhr.abort('timeout')
176
+ }, settings.timeout)
177
+
178
+ // Clear timeout setting so jquerys internal timeout isn't invoked
179
+ settings.timeout = 0
180
+ }
181
+
182
+ xhr.setRequestHeader('X-PJAX', 'true')
183
+ xhr.setRequestHeader('X-PJAX-Container', context.selector)
184
+
185
+ var result
186
+
187
+ // DEPRECATED: Invoke original `beforeSend` handler
188
+ if (oldBeforeSend) {
189
+ result = oldBeforeSend.apply(this, arguments)
190
+ if (result === false) return false
191
+ }
192
+
193
+ if (!fire('pjax:beforeSend', [xhr, settings])) return false
194
+
195
+ fire('pjax:start', [xhr, options])
196
+ // start.pjax is deprecated
197
+ fire('start.pjax', [xhr, options])
198
+ }
199
+
200
+ options.complete = function(xhr, textStatus) {
201
+ if (timeoutTimer)
202
+ clearTimeout(timeoutTimer)
203
+
204
+ // DEPRECATED: Invoke original `complete` handler
205
+ if (oldComplete) oldComplete.apply(this, arguments)
206
+
207
+ fire('pjax:complete', [xhr, textStatus, options])
208
+
209
+ fire('pjax:end', [xhr, options])
210
+ // end.pjax is deprecated
211
+ fire('end.pjax', [xhr, options])
212
+ }
213
+
214
+ options.error = function(xhr, textStatus, errorThrown) {
215
+ var respUrl = xhr.getResponseHeader('X-PJAX-URL')
216
+ if (respUrl) url = stripPjaxParam(respUrl)
217
+
218
+ // DEPRECATED: Invoke original `error` handler
219
+ if (oldError) oldError.apply(this, arguments)
220
+
221
+ var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options])
222
+ if (textStatus !== 'abort' && allowed)
223
+ window.location = url
224
+ }
225
+
226
+ options.success = function(data, status, xhr) {
227
+ var respUrl = xhr.getResponseHeader('X-PJAX-URL')
228
+ if (respUrl) url = stripPjaxParam(respUrl)
229
+
230
+ var title, oldTitle = document.title
231
+
232
+ if ( options.fragment ) {
233
+ // If they specified a fragment, look for it in the response
234
+ // and pull it out.
235
+ var html = $('<html>').html(data)
236
+ var $fragment = html.find(options.fragment)
237
+ if ( $fragment.length ) {
238
+ this.html($fragment.contents())
239
+
240
+ // If there's a <title> tag in the response, use it as
241
+ // the page's title. Otherwise, look for data-title and title attributes.
242
+ title = html.find('title').text() || $fragment.attr('title') || $fragment.data('title')
243
+ } else {
244
+ return window.location = url
245
+ }
246
+ } else {
247
+ // If we got no data or an entire web page, go directly
248
+ // to the page and let normal error handling happen.
249
+ if ( !$.trim(data) || /<html/i.test(data) )
250
+ return window.location = url
251
+
252
+ this.html(data)
253
+
254
+ // If there's a <title> tag in the response, use it as
255
+ // the page's title.
256
+ title = this.find('title').remove().text()
257
+ }
258
+
259
+ if ( title ) document.title = $.trim(title)
260
+
261
+ var state = {
262
+ url: url,
263
+ pjax: this.selector,
264
+ fragment: options.fragment,
265
+ timeout: options.timeout
266
+ }
267
+
268
+ if ( options.replace ) {
269
+ pjax.active = true
270
+ window.history.replaceState(state, document.title, url)
271
+ } else if ( options.push ) {
272
+ // this extra replaceState before first push ensures good back
273
+ // button behavior
274
+ if ( !pjax.active ) {
275
+ window.history.replaceState($.extend({}, state, {url:null}), oldTitle)
276
+ pjax.active = true
277
+ }
278
+
279
+ window.history.pushState(state, document.title, url)
280
+ }
281
+
282
+ // Google Analytics support
283
+ if ( (options.replace || options.push) && window._gaq )
284
+ _gaq.push(['_trackPageview'])
285
+
286
+ // If the URL has a hash in it, make sure the browser
287
+ // knows to navigate to the hash.
288
+ if ( hash !== '' ) {
289
+ window.location.href = hash
290
+ }
291
+
292
+ // DEPRECATED: Invoke original `success` handler
293
+ if (oldSuccess) oldSuccess.apply(this, arguments)
294
+
295
+ fire('pjax:success', [data, status, xhr, options])
296
+ }
297
+
298
+
299
+ // Cancel the current request if we're already pjaxing
300
+ var xhr = pjax.xhr
301
+ if ( xhr && xhr.readyState < 4) {
302
+ xhr.onreadystatechange = $.noop
303
+ xhr.abort()
304
+ }
305
+
306
+ pjax.options = options
307
+ pjax.xhr = $.ajax(options)
308
+ $(document).trigger('pjax', [pjax.xhr, options])
309
+
310
+ return pjax.xhr
311
+ }
312
+
313
+
314
+ // Internal: Build options Object for arguments.
315
+ //
316
+ // For convenience the first parameter can be either the container or
317
+ // the options object.
318
+ //
319
+ // Examples
320
+ //
321
+ // optionsFor('#container')
322
+ // // => {container: '#container'}
323
+ //
324
+ // optionsFor('#container', {push: true})
325
+ // // => {container: '#container', push: true}
326
+ //
327
+ // optionsFor({container: '#container', push: true})
328
+ // // => {container: '#container', push: true}
329
+ //
330
+ // Returns options Object.
331
+ function optionsFor(container, options) {
332
+ // Both container and options
333
+ if ( container && options )
334
+ options.container = container
335
+
336
+ // First argument is options Object
337
+ else if ( $.isPlainObject(container) )
338
+ options = container
339
+
340
+ // Only container
341
+ else
342
+ options = {container: container}
343
+
344
+ // Find and validate container
345
+ if (options.container)
346
+ options.container = findContainerFor(options.container)
347
+
348
+ return options
349
+ }
350
+
351
+ // Internal: Find container element for a variety of inputs.
352
+ //
353
+ // Because we can't persist elements using the history API, we must be
354
+ // able to find a String selector that will consistently find the Element.
355
+ //
356
+ // container - A selector String, jQuery object, or DOM Element.
357
+ //
358
+ // Returns a jQuery object whose context is `document` and has a selector.
359
+ function findContainerFor(container) {
360
+ container = $(container)
361
+
362
+ if ( !container.length ) {
363
+ throw "no pjax container for " + container.selector
364
+ } else if ( container.selector !== '' && container.context === document ) {
365
+ return container
366
+ } else if ( container.attr('id') ) {
367
+ return $('#' + container.attr('id'))
368
+ } else {
369
+ throw "cant get selector for pjax container!"
370
+ }
371
+ }
372
+
373
+
374
+ pjax.defaults = {
375
+ timeout: 650,
376
+ push: true,
377
+ replace: false,
378
+ type: 'GET',
379
+ dataType: 'html'
380
+ }
381
+
382
+ // Export $.pjax.click
383
+ pjax.click = handleClick
384
+
385
+
386
+ // Used to detect initial (useless) popstate.
387
+ // If history.state exists, assume browser isn't going to fire initial popstate.
388
+ var popped = ('state' in window.history), initialURL = location.href
389
+
390
+
391
+ // popstate handler takes care of the back and forward buttons
392
+ //
393
+ // You probably shouldn't use pjax on pages with other pushState
394
+ // stuff yet.
395
+ $(window).bind('popstate', function(event){
396
+ // Ignore inital popstate that some browsers fire on page load
397
+ var initialPop = !popped && location.href == initialURL
398
+ popped = true
399
+ if ( initialPop ) return
400
+
401
+ var state = event.state
402
+
403
+ if ( state && state.pjax ) {
404
+ var container = state.pjax
405
+ if ( $(container+'').length )
406
+ $.pjax({
407
+ url: state.url || location.href,
408
+ fragment: state.fragment,
409
+ container: container,
410
+ push: false,
411
+ timeout: state.timeout
412
+ })
413
+ else
414
+ window.location = location.href
415
+ }
416
+ })
417
+
418
+
419
+ // Add the state property to jQuery's event object so we can use it in
420
+ // $(window).bind('popstate')
421
+ if ( $.inArray('state', $.event.props) < 0 )
422
+ $.event.props.push('state')
423
+
424
+
425
+ // Is pjax supported by this browser?
426
+ $.support.pjax =
427
+ window.history && window.history.pushState && window.history.replaceState
428
+ // pushState isn't reliable on iOS until 5.
429
+ && !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)
430
+
431
+
432
+ // Fall back to normalcy for older browsers.
433
+ if ( !$.support.pjax ) {
434
+ $.pjax = function( options ) {
435
+ var url = $.isFunction(options.url) ? options.url() : options.url,
436
+ method = options.type ? options.type.toUpperCase() : 'GET'
437
+
438
+ var form = $('<form>', {
439
+ method: method === 'GET' ? 'GET' : 'POST',
440
+ action: url,
441
+ style: 'display:none'
442
+ })
443
+
444
+ if (method !== 'GET' && method !== 'POST') {
445
+ form.append($('<input>', {
446
+ type: 'hidden',
447
+ name: '_method',
448
+ value: method.toLowerCase()
449
+ }))
450
+ }
451
+
452
+ var data = options.data
453
+ if (typeof data === 'string') {
454
+ $.each(data.split('&'), function(index, value) {
455
+ var pair = value.split('=')
456
+ form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
457
+ })
458
+ } else if (typeof data === 'object') {
459
+ for (key in data)
460
+ form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
461
+ }
462
+
463
+ $(document.body).append(form)
464
+ form.submit()
465
+ }
466
+ $.pjax.click = $.noop
467
+ $.fn.pjax = function() { return this }
468
+ }
469
+
470
+ })(jQuery);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pjax_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-29 00:00:00.000000000 Z
12
+ date: 2012-04-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: jquery-rails
16
- requirement: &2164711580 !ruby/object:Gem::Requirement
16
+ requirement: &70172476533540 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,25 +21,21 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2164711580
24
+ version_requirements: *70172476533540
25
25
  description:
26
26
  email: david@loudthinking.com
27
27
  executables: []
28
28
  extensions: []
29
29
  extra_rdoc_files: []
30
30
  files:
31
- - ./CHANGELOG
32
- - ./lib/assets/javascripts/pjax/enable_pjax.js.coffee
33
- - ./lib/assets/javascripts/pjax/index.js
34
- - ./lib/assets/javascripts/pjax/jquery_pjax.js
35
- - ./lib/assets/javascripts/pjax/page_triggers.js.coffee
31
+ - ./lib/assets/javascripts/pjax/enable_pjax.js
32
+ - ./lib/assets/javascripts/pjax/page_triggers.js
33
+ - ./lib/assets/javascripts/pjax.js
36
34
  - ./lib/pjax.rb
37
35
  - ./lib/pjax_rails.rb
38
- - ./pjax_rails-0.1.7.gem
39
- - ./pjax_rails-0.1.8.gem
40
- - ./pjax_rails-0.1.9.gem
41
36
  - ./pjax_rails.gemspec
42
37
  - ./README.md
38
+ - ./vendor/assets/javascripts/jquery.pjax.js
43
39
  homepage:
44
40
  licenses: []
45
41
  post_install_message:
@@ -60,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
56
  version: '0'
61
57
  requirements: []
62
58
  rubyforge_project:
63
- rubygems_version: 1.8.7
59
+ rubygems_version: 1.8.11
64
60
  signing_key:
65
61
  specification_version: 3
66
62
  summary: PJAX integration for Rails 3.1+
data/CHANGELOG DELETED
@@ -1,11 +0,0 @@
1
- *0.1.10*
2
-
3
- * Overwrite the jquery-pjax timeout default to null (from 650, which not even Github uses themselves)
4
-
5
- *0.1.9*
6
-
7
- * Use latest jquery-pjax JavaScript code [2011-08-29 version, see https://github.com/defunkt/jquery-pjax/commits/master]
8
-
9
- *0.1.8*
10
-
11
- * Expand the selector to allow data-skip-pjax to be applied to a container and have that affect all its children [Sam Stephenson]
@@ -1 +0,0 @@
1
- $ -> $('a[href]:not([data-remote]):not([data-behavior]):not([data-skip-pjax]):not([href^=#])').pjax('[data-pjax-container]')
@@ -1,3 +0,0 @@
1
- //= require ./jquery_pjax
2
- //= require ./page_triggers
3
- //= require ./enable_pjax
@@ -1,255 +0,0 @@
1
- // jquery.pjax.js
2
- // copyright chris wanstrath
3
- // https://github.com/defunkt/jquery-pjax
4
-
5
- (function($){
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.
10
- //
11
- // Tries to make sure the back button and ctrl+click work the way
12
- // you'd expect.
13
- //
14
- // Accepts a jQuery ajax options object that may include these
15
- // pjax specific options:
16
- //
17
- // container - Where to stick the response body. Usually a String selector.
18
- // $(container).html(xhr.responseBody)
19
- // push - Whether to pushState the URL. Defaults to true (of course).
20
- // replace - Want to use replaceState instead? That's cool.
21
- //
22
- // For convenience the first parameter can be either the container or
23
- // the options object.
24
- //
25
- // Returns the jQuery object
26
- $.fn.pjax = function( container, options ) {
27
- if ( options )
28
- options.container = container
29
- else
30
- options = $.isPlainObject(container) ? container : {container:container}
31
-
32
- // We can't persist $objects using the history API so we must use
33
- // a String selector. Bail if we got anything else.
34
- if ( options.container && typeof options.container !== 'string' ) {
35
- throw "pjax container must be a string selector!"
36
- return false
37
- }
38
-
39
- return this.live('click', function(event){
40
- // Middle click, cmd click, and ctrl click should open
41
- // links in a new tab as normal.
42
- if ( event.which > 1 || event.metaKey )
43
- return true
44
-
45
- var defaults = {
46
- url: this.href,
47
- container: $(this).attr('data-pjax'),
48
- clickedElement: $(this),
49
- fragment: null
50
- }
51
-
52
- $.pjax($.extend({}, defaults, options))
53
-
54
- event.preventDefault()
55
- })
56
- }
57
-
58
-
59
- // Loads a URL with ajax, puts the response body inside a container,
60
- // then pushState()'s the loaded URL.
61
- //
62
- // Works just like $.ajax in that it accepts a jQuery ajax
63
- // settings object (with keys like url, type, data, etc).
64
- //
65
- // Accepts these extra keys:
66
- //
67
- // container - Where to stick the response body. Must be a String.
68
- // $(container).html(xhr.responseBody)
69
- // push - Whether to pushState the URL. Defaults to true (of course).
70
- // replace - Want to use replaceState instead? That's cool.
71
- //
72
- // Use it just like $.ajax:
73
- //
74
- // var xhr = $.pjax({ url: this.href, container: '#main' })
75
- // console.log( xhr.readyState )
76
- //
77
- // Returns whatever $.ajax returns.
78
- var pjax = $.pjax = function( options ) {
79
- var $container = $(options.container),
80
- success = options.success || $.noop
81
-
82
- // We don't want to let anyone override our success handler.
83
- delete options.success
84
-
85
- // We can't persist $objects using the history API so we must use
86
- // a String selector. Bail if we got anything else.
87
- if ( typeof options.container !== 'string' )
88
- throw "pjax container must be a string selector!"
89
-
90
- options = $.extend(true, {}, pjax.defaults, options)
91
-
92
- if ( $.isFunction(options.url) ) {
93
- options.url = options.url()
94
- }
95
-
96
- options.context = $container
97
-
98
- options.success = function(data){
99
- if ( options.fragment ) {
100
- // If they specified a fragment, look for it in the response
101
- // and pull it out.
102
- var $fragment = $(data).find(options.fragment)
103
- if ( $fragment.length )
104
- data = $fragment.children()
105
- else
106
- return window.location = options.url
107
- } else {
108
- // If we got no data or an entire web page, go directly
109
- // to the page and let normal error handling happen.
110
- if ( !$.trim(data) || /<html/i.test(data) )
111
- return window.location = options.url
112
- }
113
-
114
- // Make it happen.
115
- this.html(data)
116
-
117
- // If there's a <title> tag in the response, use it as
118
- // the page's title.
119
- var oldTitle = document.title,
120
- title = $.trim( this.find('title').remove().text() )
121
- if ( title ) document.title = title
122
-
123
- var state = {
124
- pjax: options.container,
125
- fragment: options.fragment,
126
- timeout: options.timeout
127
- }
128
-
129
- // If there are extra params, save the complete URL in the state object
130
- var query = $.param(options.data)
131
- if ( query != "_pjax=true" )
132
- state.url = options.url + (/\?/.test(options.url) ? "&" : "?") + query
133
-
134
- if ( options.replace ) {
135
- window.history.replaceState(state, document.title, options.url)
136
- } else if ( options.push ) {
137
- // this extra replaceState before first push ensures good back
138
- // button behavior
139
- if ( !pjax.active ) {
140
- window.history.replaceState($.extend({}, state, {url:null}), oldTitle)
141
- pjax.active = true
142
- }
143
-
144
- window.history.pushState(state, document.title, options.url)
145
- }
146
-
147
- // Google Analytics support
148
- if ( (options.replace || options.push) && window._gaq )
149
- _gaq.push(['_trackPageview'])
150
-
151
- // If the URL has a hash in it, make sure the browser
152
- // knows to navigate to the hash.
153
- var hash = window.location.hash.toString()
154
- if ( hash !== '' ) {
155
- window.location.href = hash
156
- }
157
-
158
- // Invoke their success handler if they gave us one.
159
- success.apply(this, arguments)
160
- }
161
-
162
- // Cancel the current request if we're already pjaxing
163
- var xhr = pjax.xhr
164
- if ( xhr && xhr.readyState < 4) {
165
- xhr.onreadystatechange = $.noop
166
- xhr.abort()
167
- }
168
-
169
- pjax.options = options
170
- pjax.xhr = $.ajax(options)
171
- $(document).trigger('pjax', [pjax.xhr, options])
172
-
173
- return pjax.xhr
174
- }
175
-
176
-
177
- pjax.defaults = {
178
- timeout: null,
179
- push: true,
180
- replace: false,
181
- // We want the browser to maintain two separate internal caches: one for
182
- // pjax'd partial page loads and one for normal page loads. Without
183
- // adding this secret parameter, some browsers will often confuse the two.
184
- data: { _pjax: true },
185
- type: 'GET',
186
- dataType: 'html',
187
- beforeSend: function(xhr){
188
- this.trigger('start.pjax', [xhr, pjax.options])
189
- xhr.setRequestHeader('X-PJAX', 'true')
190
- },
191
- error: function(xhr, textStatus, errorThrown){
192
- if ( textStatus !== 'abort' )
193
- window.location = pjax.options.url
194
- },
195
- complete: function(xhr){
196
- this.trigger('end.pjax', [xhr, pjax.options])
197
- }
198
- }
199
-
200
-
201
- // Used to detect initial (useless) popstate.
202
- // If history.state exists, assume browser isn't going to fire initial popstate.
203
- var popped = ('state' in window.history), initialURL = location.href
204
-
205
-
206
- // popstate handler takes care of the back and forward buttons
207
- //
208
- // You probably shouldn't use pjax on pages with other pushState
209
- // stuff yet.
210
- $(window).bind('popstate', function(event){
211
- // Ignore inital popstate that some browsers fire on page load
212
- var initialPop = !popped && location.href == initialURL
213
- popped = true
214
- if ( initialPop ) return
215
-
216
- var state = event.state
217
-
218
- if ( state && state.pjax ) {
219
- var container = state.pjax
220
- if ( $(container+'').length )
221
- $.pjax({
222
- url: state.url || location.href,
223
- fragment: state.fragment,
224
- container: container,
225
- push: false,
226
- timeout: state.timeout
227
- })
228
- else
229
- window.location = location.href
230
- }
231
- })
232
-
233
-
234
- // Add the state property to jQuery's event object so we can use it in
235
- // $(window).bind('popstate')
236
- if ( $.inArray('state', $.event.props) < 0 )
237
- $.event.props.push('state')
238
-
239
-
240
- // Is pjax supported by this browser?
241
- $.support.pjax =
242
- window.history && window.history.pushState && window.history.replaceState
243
- // pushState isn't reliable on iOS yet.
244
- && !navigator.userAgent.match(/(iPod|iPhone|iPad|WebApps\/.+CFNetwork)/)
245
-
246
-
247
- // Fall back to normalcy for older browsers.
248
- if ( !$.support.pjax ) {
249
- $.pjax = function( options ) {
250
- window.location = $.isFunction(options.url) ? options.url() : options.url
251
- }
252
- $.fn.pjax = function() { return this }
253
- }
254
-
255
- })(jQuery);
@@ -1,10 +0,0 @@
1
- $(document).ready ->
2
- $(document).trigger 'pageChanged'
3
- $(document).trigger 'pageUpdated'
4
-
5
- $(document).bind 'end.pjax', ->
6
- $(document).trigger 'pageChanged'
7
- $(document).trigger 'pageUpdated'
8
-
9
- $(document).bind 'ajaxComplete', ->
10
- $(document).trigger 'pageUpdated'
Binary file
Binary file
Binary file