pjax-rails 0.1

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,48 @@
1
+ PJAX for Rails 3.1+
2
+ ===================
3
+
4
+ Integrate Chris Wanstrath's PJAX into Rails 3.1+ via the asset pipeline.
5
+
6
+ To activate, add this to your app/assets/javascripts/application.js (or whatever bundle you use):
7
+
8
+ //=require pjax
9
+
10
+ All links that matches $('a:not([data-remote]):not([data-behavior])') will then use PJAX.
11
+
12
+ FIXME: Currently the layout is hardcoded to "application". Need to delegate that to the specific layout of the controller.
13
+
14
+ Examples for redirect_pjax_to
15
+ -----------------------------
16
+
17
+ class ProjectsController < ApplicationController
18
+ before_filter :set_project, except: [ :index, :create ]
19
+
20
+ def index
21
+ @projects = current_user.projects
22
+ end
23
+
24
+ def show
25
+ end
26
+
27
+ def create
28
+ @project = Project.create params[:project]
29
+ redirect_pjax_to :show, @project
30
+ end
31
+
32
+ def update
33
+ @project.update_attributes params[:project]
34
+ redirect_pjax_to :show, @project
35
+ end
36
+
37
+ def destroy
38
+ @project.destroy
39
+
40
+ index # set the objects needed for rendering index
41
+ redirect_pjax_to :index
42
+ end
43
+
44
+ private
45
+ def set_project
46
+ @project = current_user.projects.find params[:id].to_i
47
+ end
48
+ end
@@ -0,0 +1 @@
1
+ $ -> $('a:not([data-remote]):not([data-behavior])').pjax('div#main')
@@ -0,0 +1,3 @@
1
+ //= require ./jquery_pjax
2
+ //= require ./page_triggers
3
+ //= require ./enable_pjax
@@ -0,0 +1,208 @@
1
+ // jquery_pjax.js
2
+ // copyright chris wanstrath
3
+ // https://github.com/defunkt/pjax
4
+
5
+ // When called on a link, fetches the href with ajax into the
6
+ // container specified as the first parameter or with the data-pjax
7
+ // attribute on the link itself.
8
+ //
9
+ // Tries to make sure the back button and ctrl+click work the way
10
+ // you'd expect.
11
+ //
12
+ // Accepts a jQuery ajax options object that may include these
13
+ // pjax specific options:
14
+ //
15
+ // container - Where to stick the response body. Usually a String selector.
16
+ // $(container).html(xhr.responseBody)
17
+ // push - Whether to pushState the URL. Defaults to true (of course).
18
+ // replace - Want to use replaceState instead? That's cool.
19
+ //
20
+ // For convenience the first parameter can be either the container or
21
+ // the options object.
22
+ //
23
+ // Returns the jQuery object
24
+ $.fn.pjax = function( container, options ) {
25
+ if ( options )
26
+ options.container = container
27
+ else
28
+ options = $.isPlainObject(container) ? container : {container:container}
29
+
30
+ return this.live('click', function(event){
31
+ // Middle click, cmd click, and ctrl click should open
32
+ // links in a new tab as normal.
33
+ if ( event.which > 1 || event.metaKey )
34
+ return true
35
+
36
+ var defaults = {
37
+ url: this.href,
38
+ container: $(this).attr('data-pjax')
39
+ }
40
+
41
+ $.pjax($.extend({}, defaults, options))
42
+
43
+ event.preventDefault()
44
+ })
45
+ }
46
+
47
+
48
+ // Loads a URL with ajax, puts the response body inside a container,
49
+ // then pushState()'s the loaded URL.
50
+ //
51
+ // Works just like $.ajax in that it accepts a jQuery ajax
52
+ // settings object (with keys like url, type, data, etc).
53
+ //
54
+ // Accepts these extra keys:
55
+ //
56
+ // container - Where to stick the response body.
57
+ // $(container).html(xhr.responseBody)
58
+ // push - Whether to pushState the URL. Defaults to true (of course).
59
+ // replace - Want to use replaceState instead? That's cool.
60
+ //
61
+ // Use it just like $.ajax:
62
+ //
63
+ // var xhr = $.pjax({ url: this.href, container: '#main' })
64
+ // console.log( xhr.readyState )
65
+ //
66
+ // Returns whatever $.ajax returns.
67
+ $.pjax = function( options ) {
68
+ var $container = $(options.container),
69
+ success = options.success || $.noop
70
+
71
+ // We don't want to let anyone override our success handler.
72
+ delete options.success
73
+
74
+ var defaults = {
75
+ timeout: 650,
76
+ push: true,
77
+ replace: false,
78
+ // We want the browser to maintain two separate internal caches: one for
79
+ // pjax'd partial page loads and one for normal page loads. Without
80
+ // adding this secret parameter, some browsers will often confuse the two.
81
+ data: { _pjax: true },
82
+ type: 'GET',
83
+ dataType: 'html',
84
+ beforeSend: function(xhr){
85
+ $(document).trigger('start.pjax')
86
+ xhr.setRequestHeader('X-PJAX', 'true')
87
+ },
88
+ error: function(){
89
+ window.location = options.url
90
+ },
91
+ complete: function(){
92
+ $(document).trigger('end.pjax')
93
+ },
94
+ success: function(data){
95
+ // If we got no data or an entire web page, go directly
96
+ // to the page and let normal error handling happen.
97
+ if ( !$.trim(data) || /<html/i.test(data) )
98
+ return window.location = options.url
99
+
100
+ // Make it happen.
101
+ $container.html(data)
102
+
103
+ // If there's a <title> tag in the response, use it as
104
+ // the page's title.
105
+ var oldTitle = document.title,
106
+ title = $.trim( $container.find('title').remove().text() )
107
+ if ( title ) document.title = title
108
+
109
+ var state = {
110
+ pjax: options.container,
111
+ timeout: options.timeout
112
+ }
113
+
114
+ // We can't persist $objects using the history API so we need to store
115
+ // the string selector.
116
+ if ( $.isPlainObject(state.pjax) )
117
+ state.pjax = state.pjax.selector
118
+
119
+ // If there are extra params, save the complete URL in the state object
120
+ var query = $.param(options.data)
121
+ if ( query != "_pjax=true" )
122
+ state.url = options.url + (/\?/.test(options.url) ? "&" : "?") + query
123
+
124
+ if ( options.replace ) {
125
+ window.history.replaceState(state, document.title, options.url)
126
+ } else if ( options.push ) {
127
+ // this extra replaceState before first push ensures good back
128
+ // button behavior
129
+ if ( !$.pjax.active ) {
130
+ window.history.replaceState($.extend({}, state, {url:null}), oldTitle)
131
+ $.pjax.active = true
132
+ }
133
+
134
+ window.history.pushState(state, document.title, options.url)
135
+ }
136
+
137
+ // Google Analytics support
138
+ if ( (options.replace || options.push) && window._gaq )
139
+ _gaq.push(['_trackPageview'])
140
+
141
+ // Invoke their success handler if they gave us one.
142
+ success.apply(this, arguments)
143
+ }
144
+ }
145
+
146
+ options = $.extend(true, {}, defaults, options)
147
+
148
+ if ( $.isFunction(options.url) ) {
149
+ options.url = options.url()
150
+ }
151
+
152
+ // Cancel the current request if we're already pjaxing
153
+ var xhr = $.pjax.xhr
154
+ if ( xhr && xhr.readyState < 4) {
155
+ xhr.onreadystatechange = $.noop
156
+ xhr.abort()
157
+ }
158
+
159
+ $.pjax.xhr = $.ajax(options)
160
+ $(document).trigger('pjax', $.pjax.xhr, options)
161
+
162
+ return $.pjax.xhr
163
+ }
164
+
165
+
166
+ // Used to detect initial (useless) popstate.
167
+ // If history.state exists, assume browser isn't going to fire initial popstate.
168
+ var popped = ('state' in window.history), initialURL = location.href
169
+
170
+
171
+ // popstate handler takes care of the back and forward buttons
172
+ //
173
+ // You probably shouldn't use pjax on pages with other pushState
174
+ // stuff yet.
175
+ $(window).bind('popstate', function(event) {
176
+ // Ignore inital popstate that some browsers fire on page load
177
+ var initialPop = !popped && location.href == initialURL
178
+ popped = true
179
+ if ( initialPop ) return
180
+
181
+ var state = event.state
182
+
183
+ if ( state && state.pjax ) {
184
+ var $container = $(state.pjax+'')
185
+ if ( $container.length )
186
+ $.pjax({
187
+ url: state.url || location.href,
188
+ container: $container,
189
+ push: false,
190
+ timeout: state.timeout
191
+ })
192
+ else
193
+ window.location = location.href
194
+ }
195
+ })
196
+
197
+
198
+ // Add the state property to jQuery's event object so we can use it in
199
+ // $(window).bind('popstate')
200
+ if ( $.event.props.indexOf('state') < 0 )
201
+ $.event.props.push('state')
202
+
203
+
204
+ // Fall back to normalcy for older browsers.
205
+ if ( !window.history || !window.history.pushState ) {
206
+ $.pjax = $.noop
207
+ $.fn.pjax = function() { return this }
208
+ }
@@ -0,0 +1,10 @@
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'
@@ -0,0 +1,11 @@
1
+ require 'pjax'
2
+
3
+ module PjaxRails
4
+ class Engine < ::Rails::Engine
5
+ initializer "pjax_rails.add_controller" do
6
+ ActiveSupport.on_load(:action_controller) do
7
+ ::ApplicationController.send :include, Pjax
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ module Pjax
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ layout ->(c) { pjax_request? ? false : 'application' }
6
+ end
7
+
8
+ private
9
+ def redirect_pjax_to(action, url = nil)
10
+ new_url = url_for(url ? url : { action: action })
11
+
12
+ render js: <<-EJS
13
+ if (!window.history || !window.history.pushState) {
14
+ window.location.href = '#{new_url}';
15
+ } else {
16
+ $('div.pages').html(#{render_to_string("#{action}.html.erb").to_json});
17
+ $(document).trigger('end.pjax');
18
+
19
+ var title = $.trim($('div.pages').find('title').remove().text());
20
+ if (title) document.title = title;
21
+ window.history.pushState({}, document.title, '#{new_url}');
22
+ }
23
+ EJS
24
+ end
25
+
26
+ def pjax_request?
27
+ env['HTTP_X_PJAX'].present?
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'pjax-rails'
3
+ s.version = '0.1'
4
+ s.author = 'David Heinemeier Hansson (PJAX by Chris Wanstrath)'
5
+ s.email = 'david@loudthinking.com'
6
+ s.summary = 'PJAX integration for Rails 3.1+'
7
+
8
+ s.add_dependency 'jquery-rails'
9
+
10
+ s.files = Dir["#{File.dirname(__FILE__)}/**/*"]
11
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pjax-rails
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: "0.1"
6
+ platform: ruby
7
+ authors:
8
+ - David Heinemeier Hansson (PJAX by Chris Wanstrath)
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-17 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: jquery-rails
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ description:
28
+ email: david@loudthinking.com
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files: []
34
+
35
+ files:
36
+ - ./lib/assets/javascripts/pjax/enable_pjax.js.coffee
37
+ - ./lib/assets/javascripts/pjax/index.js
38
+ - ./lib/assets/javascripts/pjax/jquery_pjax.js
39
+ - ./lib/assets/javascripts/pjax/page_triggers.js.coffee
40
+ - ./lib/pjax-rails.rb
41
+ - ./lib/pjax.rb
42
+ - ./pjax-rails.gemspec
43
+ - ./README.md
44
+ has_rdoc: true
45
+ homepage:
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.6.2
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: PJAX integration for Rails 3.1+
72
+ test_files: []
73
+