pjax_rails 0.1.10 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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