ajax_pagination 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +1 -1
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +30 -3
  4. data/Rakefile +10 -0
  5. data/ajax_pagination.gemspec +1 -1
  6. data/lib/ajax_pagination/version.rb +1 -1
  7. data/lib/generators/ajax_pagination/assets_generator.rb +37 -0
  8. data/spec/R30PORT +1 -0
  9. data/spec/ajax_pagination/integration/ajaxpaginate_spec.rb +85 -75
  10. data/spec/ajax_pagination/integration/rails30_spec.rb +35 -0
  11. data/spec/rails30_app/.gitignore +8 -0
  12. data/spec/rails30_app/Gemfile +28 -0
  13. data/spec/rails30_app/Gemfile.lock +96 -0
  14. data/spec/rails30_app/Rakefile +7 -0
  15. data/spec/rails30_app/app/controllers/application_controller.rb +13 -0
  16. data/spec/rails30_app/app/controllers/changelog_controller.rb +12 -0
  17. data/spec/rails30_app/app/controllers/pages_controller.rb +28 -0
  18. data/spec/rails30_app/app/controllers/sessions_controller.rb +9 -0
  19. data/spec/rails30_app/app/helpers/application_helper.rb +2 -0
  20. data/spec/rails30_app/app/helpers/posts_helper.rb +2 -0
  21. data/spec/rails30_app/app/mailers/.gitkeep +0 -0
  22. data/spec/rails30_app/app/models/.gitkeep +0 -0
  23. data/spec/rails30_app/app/models/changelog.rb +19 -0
  24. data/spec/rails30_app/app/views/changelog/_page.html.erb +10 -0
  25. data/spec/rails30_app/app/views/changelog/index.html.erb +3 -0
  26. data/spec/rails30_app/app/views/layouts/ajax.html.erb +8 -0
  27. data/spec/rails30_app/app/views/layouts/application.html.erb +49 -0
  28. data/spec/rails30_app/app/views/layouts/flash.html.erb +7 -0
  29. data/spec/rails30_app/app/views/pages/about.html.erb +4 -0
  30. data/spec/rails30_app/app/views/pages/readme.html.erb +4 -0
  31. data/spec/rails30_app/app/views/pages/warnings.html.erb +43 -0
  32. data/spec/rails30_app/app/views/pages/welcome.html.erb +6 -0
  33. data/spec/rails30_app/app/views/sessions/count.html.erb +7 -0
  34. data/spec/rails30_app/config.ru +4 -0
  35. data/spec/rails30_app/config/application.rb +53 -0
  36. data/spec/rails30_app/config/boot.rb +10 -0
  37. data/spec/rails30_app/config/database.yml +25 -0
  38. data/spec/rails30_app/config/environment.rb +6 -0
  39. data/spec/rails30_app/config/environments/development.rb +25 -0
  40. data/spec/rails30_app/config/environments/production.rb +43 -0
  41. data/spec/rails30_app/config/environments/test.rb +30 -0
  42. data/spec/rails30_app/config/initializers/ajax_pagination.rb +12 -0
  43. data/spec/rails30_app/config/initializers/backtrace_silencers.rb +7 -0
  44. data/spec/rails30_app/config/initializers/inflections.rb +15 -0
  45. data/spec/rails30_app/config/initializers/mime_types.rb +5 -0
  46. data/spec/rails30_app/config/initializers/secret_token.rb +7 -0
  47. data/spec/rails30_app/config/initializers/session_store.rb +8 -0
  48. data/spec/rails30_app/config/locales/en.yml +5 -0
  49. data/spec/rails30_app/config/routes.rb +71 -0
  50. data/spec/rails30_app/log/.gitkeep +0 -0
  51. data/spec/rails30_app/public/404.html +26 -0
  52. data/spec/rails30_app/public/422.html +26 -0
  53. data/spec/rails30_app/public/500.html +25 -0
  54. data/spec/rails30_app/public/favicon.ico +0 -0
  55. data/spec/rails30_app/public/images/ajax-loader.gif +0 -0
  56. data/spec/rails30_app/public/javascripts/ajax_pagination.js +380 -0
  57. data/spec/rails30_app/public/javascripts/history.js +4 -0
  58. data/spec/rails30_app/public/javascripts/history_adapter_jquery.js +77 -0
  59. data/spec/rails30_app/public/javascripts/history_core.js +1943 -0
  60. data/spec/rails30_app/public/javascripts/history_html4.js +621 -0
  61. data/spec/rails30_app/public/javascripts/jquery-ui.js +11767 -0
  62. data/spec/rails30_app/public/javascripts/jquery-ui.min.js +791 -0
  63. data/spec/rails30_app/public/javascripts/jquery.ba-bbq.js +18 -0
  64. data/spec/rails30_app/public/javascripts/jquery.js +9266 -0
  65. data/spec/rails30_app/public/javascripts/jquery.min.js +4 -0
  66. data/spec/rails30_app/public/javascripts/jquery.url.js +160 -0
  67. data/spec/rails30_app/public/javascripts/jquery_ujs.js +373 -0
  68. data/spec/rails30_app/public/javascripts/json2.js +487 -0
  69. data/spec/rails30_app/public/stylesheets/ajax_pagination.css +24 -0
  70. data/spec/rails30_app/public/stylesheets/application.css +12 -0
  71. data/spec/rails30_app/public/stylesheets/scaffold.css +56 -0
  72. data/spec/rails30_app/script/rails +6 -0
  73. data/spec/rails_app/Gemfile.lock +107 -0
  74. data/spec/spec_helper.rb +16 -1
  75. metadata +72 -10
  76. data/spec/rails_app/test/fixtures/posts.yml +0 -9
  77. data/spec/rails_app/test/functional/posts_controller_test.rb +0 -49
  78. data/spec/rails_app/test/unit/helpers/posts_helper_test.rb +0 -4
  79. data/spec/rails_app/test/unit/post_test.rb +0 -7
@@ -0,0 +1,30 @@
1
+ RailsApp::Application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb
3
+
4
+ # The test environment is used exclusively to run your application's
5
+ # test suite. You never need to work with it otherwise. Remember that
6
+ # your test database is "scratch space" for the test suite and is wiped
7
+ # and recreated between test runs. Don't rely on the data there!
8
+ config.cache_classes = true
9
+
10
+ # Log error messages when you accidentally call methods on nil
11
+ config.whiny_nils = true
12
+
13
+ # Show full error reports and disable caching
14
+ config.consider_all_requests_local = true
15
+ config.action_controller.perform_caching = false
16
+
17
+ # Raise exceptions instead of rendering exception templates
18
+ config.action_dispatch.show_exceptions = false
19
+
20
+ # Disable request forgery protection in test environment
21
+ config.action_controller.allow_forgery_protection = false
22
+
23
+ # Tell Action Mailer not to deliver emails to the real world.
24
+ # The :test delivery method accumulates sent emails in the
25
+ # ActionMailer::Base.deliveries array.
26
+ config.action_mailer.delivery_method = :test
27
+
28
+ # Print deprecation notices to the stderr
29
+ config.active_support.deprecation = :stderr
30
+ end
@@ -0,0 +1,12 @@
1
+ AjaxPagination.config do |config|
2
+ # uncomment to change default loading image file, located in assets/images.
3
+ # config.loading_image = "ajax-loader.gif"
4
+
5
+ # whether javascript warnings are on, these present themselves as alerts
6
+ # by default, warnings are active only if the environment is development
7
+ # to configure by environment otherwise, this configuration needs to be added to the environment specific files
8
+ # uncomment to turn warnings on in all environments
9
+ config.warnings = true
10
+ # or to turn off in all environments
11
+ # config.warnings = false
12
+ end
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4
+ # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5
+
6
+ # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7
+ # Rails.backtrace_cleaner.remove_silencers!
@@ -0,0 +1,15 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new inflection rules using the following format
4
+ # (all these examples are active by default):
5
+ # ActiveSupport::Inflector.inflections do |inflect|
6
+ # inflect.plural /^(ox)$/i, '\1en'
7
+ # inflect.singular /^(ox)en/i, '\1'
8
+ # inflect.irregular 'person', 'people'
9
+ # inflect.uncountable %w( fish sheep )
10
+ # end
11
+ #
12
+ # These inflection rules are supported but not enabled by default:
13
+ # ActiveSupport::Inflector.inflections do |inflect|
14
+ # inflect.acronym 'RESTful'
15
+ # end
@@ -0,0 +1,5 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new mime types for use in respond_to blocks:
4
+ # Mime::Type.register "text/richtext", :rtf
5
+ # Mime::Type.register_alias "text/html", :iphone
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+ # Make sure the secret is at least 30 characters and all random,
6
+ # no regular words or you'll be exposed to dictionary attacks.
7
+ RailsApp::Application.config.secret_token = 'a706a86b3637055b5983373afe5113e107ef65d626a4c1763ec9017948fb7d640b5bcb7c541bab0bc52761e0c8aa78fcc43e24182440cd21b866330739e97169'
@@ -0,0 +1,8 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ RailsApp::Application.config.session_store :cookie_store, :key => '_rails_app_session'
4
+
5
+ # Use the database for sessions instead of the cookie-based default,
6
+ # which shouldn't be used to store highly confidential information
7
+ # (create the session table with "rails generate session_migration")
8
+ # RailsApp::Application.config.session_store :active_record_store
@@ -0,0 +1,5 @@
1
+ # Sample localization file for English. Add more files in this directory for other locales.
2
+ # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3
+
4
+ en:
5
+ hello: "Hello world"
@@ -0,0 +1,71 @@
1
+ RailsApp::Application.routes.draw do
2
+
3
+ namespace :pages do
4
+ get 'about'
5
+ get 'readme'
6
+ end
7
+
8
+ get 'changelog' => 'changelog#index'
9
+
10
+ namespace :sessions do
11
+ get 'count'
12
+ post 'count'
13
+ end
14
+
15
+ # The priority is based upon order of creation:
16
+ # first created -> highest priority.
17
+
18
+ # Sample of regular route:
19
+ # match 'products/:id' => 'catalog#view'
20
+ # Keep in mind you can assign values other than :controller and :action
21
+
22
+ # Sample of named route:
23
+ # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
24
+ # This route can be invoked with purchase_url(:id => product.id)
25
+
26
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
27
+ # resources :products
28
+
29
+ # Sample resource route with options:
30
+ # resources :products do
31
+ # member do
32
+ # get 'short'
33
+ # post 'toggle'
34
+ # end
35
+ #
36
+ # collection do
37
+ # get 'sold'
38
+ # end
39
+ # end
40
+
41
+ # Sample resource route with sub-resources:
42
+ # resources :products do
43
+ # resources :comments, :sales
44
+ # resource :seller
45
+ # end
46
+
47
+ # Sample resource route with more complex sub-resources
48
+ # resources :products do
49
+ # resources :comments
50
+ # resources :sales do
51
+ # get 'recent', :on => :collection
52
+ # end
53
+ # end
54
+
55
+ # Sample resource route within a namespace:
56
+ # namespace :admin do
57
+ # # Directs /admin/products/* to Admin::ProductsController
58
+ # # (app/controllers/admin/products_controller.rb)
59
+ # resources :products
60
+ # end
61
+
62
+ # You can have the root of your site routed with "root"
63
+ # just remember to delete public/index.html.
64
+ root :to => 'pages#welcome'
65
+
66
+ # See how all your routes lay out with "rake routes"
67
+
68
+ # This is a legacy wild controller route that's not recommended for RESTful applications.
69
+ # Note: This route will make all actions in every controller accessible via GET requests.
70
+ # match ':controller(/:action(/:id))(.:format)'
71
+ end
File without changes
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/404.html -->
21
+ <div class="dialog">
22
+ <h1>The page you were looking for doesn't exist.</h1>
23
+ <p>You may have mistyped the address or the page may have moved.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ </div>
24
+ </body>
25
+ </html>
File without changes
@@ -0,0 +1,380 @@
1
+ //= require jquery.ba-bbq
2
+ //= require jquery.url
3
+
4
+ /*
5
+ * AJAX Pagination: Ajaxifying your pagination links
6
+ * https://github.com/ronalchn/ajax_pagination
7
+ *
8
+ * Copyright (c) 2012 Ronald Ping Man Chan
9
+ * Distributed under the LGPL license
10
+ *
11
+ * Although the ajax_pagination gem as a whole is distributed under LGPL, I am expressly permitting users to minify and concatenate this javascript file
12
+ * with other javascript files, as long as it is through an automatic asset management process (eg. Sprockets), and the automatic asset
13
+ * management process obtains this javascript file as a separate file via dynamically linked means (ie. with this file left in the separately
14
+ * installed ajax_pagination gem).
15
+ * ~ Ronald Chan
16
+ */
17
+ jQuery(document).ready(function () {
18
+ function minVersion(version) {
19
+ var $vrs = window.jQuery.fn.jquery.split('.'),
20
+ min = version.split('.');
21
+ for (var i=0, len=min.length; i<len; i++) {
22
+ if ($vrs[i]) {
23
+ min[i] = parseInt(min[i],10);
24
+ $vrs[i] = parseInt($vrs[i],10);
25
+ if ($vrs[i] < min[i]) return false;
26
+ else if ($vrs[i] > min[i]) return true;
27
+ }
28
+ else return false;
29
+ }
30
+ return true;
31
+ }
32
+
33
+
34
+ if (!(History && minVersion('1.7'))) { // dependencies missing
35
+ var missing = "";
36
+ if (!History) missing += "\nHistory.js not installed";
37
+ if (!minVersion('1.7')) missing += "\njQuery version 1.7+ not installed. Currently installed: jQuery " + window.jQuery.fn.jquery;
38
+ alert("AJAX Pagination MISSING_DEPENDENCIES:" + missing);
39
+ }
40
+
41
+ (function( $ ) { // on document ready
42
+ if (History && History.enabled && minVersion('1.7')) {
43
+ ///////////////////////////////////
44
+ ////// $.ajax_pagination API //////
45
+ ///////////////////////////////////
46
+ // selector function for pagination object
47
+ $.ajax_pagination = function (pagination_name) {
48
+ return new pagination_object(pagination_name);
49
+ };
50
+ $.ajax_pagination.version = '0.5.1';
51
+ $.ajax_pagination.enabled = true;
52
+ function pagination_object(pagination_name) {
53
+ this.get = function(url,options) {
54
+ if (options === undefined) options = {};
55
+ if (options.history === undefined) options.history = true;
56
+ swapPage(pagination_name,url,options.history);
57
+ }
58
+ this.exists = function() {
59
+ return $('#' + pagination_name + '_paginated_section').length == 1;
60
+ }
61
+ }
62
+ /////////////////////////////
63
+ ////// Basic Internals //////
64
+ /////////////////////////////
65
+ var pagination_loader_state = new Array(); // the page we are waiting for
66
+ var pagination_url = location.href; // url we came from, so we can see transitions of the url
67
+ var history_state = {ajax_pagination_set:true}; // current history state
68
+
69
+ function display_pagination_loader(pagination_name) {
70
+ var paginated_section = getSection(pagination_name);
71
+ if (pagination_loader_state[pagination_name] === undefined) { // show loader if not already shown
72
+ if ($.rails.fire(getSection(pagination_name),"ajaxp:loading")) {
73
+ var paginated_content;
74
+ if (paginated_section.hasClass("paginated_content")) paginated_content = paginated_section; // if the whole section is a loading zone
75
+ else paginated_content = paginated_section.children(".paginated_content").first(); // don't want to support multiple loader images
76
+ var height = paginated_content.height();
77
+ // setup loading look
78
+ var img = document.createElement("IMG");
79
+ if (paginated_section.data("pagination") !== undefined && paginated_section.data("pagination").image !== undefined) img.src = paginated_section.data("pagination").image;
80
+ else img.src = "/images/ajax-loader.gif";
81
+ var margin = Math.round(height>400?50:(height/8));
82
+ $(img).addClass('ajaxpagination-loader');
83
+ var div = document.createElement("DIV");
84
+ $(div).addClass('ajaxpagination-loadzone');
85
+ $(div).append("<div class=\"margin-top\" />").append(img);
86
+ paginated_content.wrapInner("<div class=\"ajaxpagination-oldcontent\" />");
87
+ paginated_content.append(div);
88
+ }
89
+ }
90
+ if ($.rails.fire(getSection(pagination_name),"ajaxp:focus")) {
91
+ // scroll to top of paginated_section if it is not visible
92
+ if ($(document).scrollTop() > paginated_section.offset().top - 20) {
93
+ $(document).scrollTop(paginated_section.offset().top - 20);
94
+ }
95
+ }
96
+ }
97
+ function getSection(pagination_name) {
98
+ var id = "#" + pagination_name + "_paginated_section"; // element id we are looking for
99
+ return $(id);
100
+ }
101
+ function getSectionName(section) {
102
+ var id = section.attr("id");
103
+ if (id === undefined) return undefined; // no name
104
+ var pagination_name = /^(.*)_paginated_section$/.exec(id)[1];
105
+ if (pagination_name == null || pagination_name === undefined) return undefined; // pagination not set up properly
106
+ return pagination_name;
107
+ }
108
+ function getSectionNames(sections) {
109
+ var names = new Array();
110
+ sections.each(function () {
111
+ names.push(getSectionName($(this)));
112
+ });
113
+ return names;
114
+ }
115
+ function intersects(a,b) { // do the arrays a and b intersect?
116
+ var i=0, j=0;
117
+ while (i < a.length && j < b.length) {
118
+ if (a[i]<b[j]) i++;
119
+ else if (a[i]>b[j]) j++;
120
+ else return true; // intersects
121
+ }
122
+ return false; // doesn't intersect
123
+ }
124
+ // whether change of state is a reload
125
+ function isReload(pagination_name,from,to) {
126
+ if (from == to) return true; // same url - always a reload
127
+ var section = getSection(pagination_name);
128
+ if (section.length == 0) return false;
129
+
130
+ // if data-pagination is not defined, then no reload can be detected
131
+ if (section.data('pagination') === undefined || section.data('pagination').reload === undefined) return false;
132
+
133
+ var reload = section.data('pagination').reload;
134
+ if (!(reload instanceof Array)) reload = new Array(reload);
135
+ for (i=0;i<reload.length;i++) {
136
+ if (reload[i].query !== undefined) {
137
+ if ($.deparam.querystring(from)[reload[i].query] !== $.deparam.querystring(to)[reload[i].query]) return false;
138
+ }
139
+ if (reload[i].urlregex !== undefined) {
140
+ var fstr = from, tstr = to;
141
+ if (reload[i].urlpart !== undefined) {
142
+ fstr = $.url(from,true).attr(reload[i].urlpart);
143
+ tstr = $.url(to,true).attr(reload[i].urlpart);
144
+ if (typeof(fstr)!="string" || typeof(tstr)!="string") continue; // skip
145
+ }
146
+ var index = 0;
147
+ if (reload[i].regexindex !== undefined) index = reload[i].regexindex;
148
+ var regex = new RegExp(reload[i].urlregex);
149
+ var frommatch = regex.exec(fstr), tomatch = regex.exec(tstr);
150
+ if (frommatch != null && frommatch.length>=index) frommatch = frommatch[index];
151
+ if (tomatch != null && tomatch.length>=index) tomatch = tomatch[index];
152
+ if (frommatch !== tomatch) return false;
153
+ }
154
+ }
155
+ return true;
156
+ }
157
+ // when this function is used beforeSend of an AJAX request, will use the resulting content in a section of the page
158
+ // this event handler has the same arguments as for jquery and jquery-ujs, except it also takes the name of the section to put the content into as first argument
159
+ // adapter functions will be used to reconcile the differences in arguments, this is required because jquery and jquery-ujs has different ways to get the pagination_name argument
160
+ function beforeSendHandler(pagination_name,jqXHR,settings) {
161
+ var id = "#" + pagination_name + "_paginated_section"; // element id we are looking for
162
+ var requesturl = settings.url;
163
+ var countid = $('[id="' + pagination_name + '_paginated_section"]').length;
164
+ if (countid != 1) { // something wrong, cannot find unique section to load page into
165
+
166
+ alert("AJAX Pagination UNIQUE_SECTION_NOT_FOUND:\nExpected one pagination section called " + pagination_name + ", found " + countid);
167
+
168
+ return false; // continue AJAX normally
169
+ }
170
+ if (!$.rails.fire(getSection(pagination_name),"ajaxp:beforeSend",[jqXHR,settings])) return false;
171
+ display_pagination_loader(pagination_name);
172
+ // register callbacks for other events
173
+ jqXHR.done(function(data, textStatus, jqXHR) {
174
+ if (requesturl != pagination_loader_state[pagination_name]) return; // ignore stale content
175
+ if (jqXHR.status == 200 && jqXHR.getResponseHeader('Location') !== null) { // special AJAX redirect
176
+ var redirecturl = jqXHR.getResponseHeader('Location');
177
+ swapPage(pagination_name,redirecturl);
178
+ pagination_url = redirecturl;
179
+ History.replaceState(history_state,document.title,redirecturl); // state not changed
180
+ return;
181
+ }
182
+ // find matching element id in data, after removing script tags
183
+ var page = $("<div />");
184
+ page[0].innerHTML = data; // put response in DOM without executing scripts
185
+
186
+ // if page contains a title, use it
187
+ var title = page.find("title");
188
+ if (title.length>0) History.replaceState(history_state,title.html(),location.href);
189
+
190
+ // get page contents
191
+ var content = page.find(id);
192
+ if (content.length>0) {
193
+ content = content.html();
194
+
195
+ alert("AJAX Pagination EXTRA_CONTENT_DISCARDED:\nExtra content returned by AJAX request ignored. Only a portion of the page content returned by the server was required. To fix this, explicitly call ajax_respond :pagination => \"" + pagination_name + "\" to render only the partial view required. This warning can be turned off in the ajax_pagination initializer file.");
196
+
197
+ }
198
+ else { // otherwise use all the content, including any scripts - we consider scripts specifically returned in the partial probably should be re-run
199
+ content = page.find("body"); // does not tend to work since browsers strip out the html, head, body tags
200
+ if (content.length>0) content = content.html(); // if it has a body tag, only include its contents (for full html structure), leaving out <head> etc sections.
201
+ else content = page.html(); // otherwise include the whole html snippet
202
+ }
203
+
204
+ if ($.rails.fire(getSection(pagination_name),"ajaxp:done",[content])) $(id).html(content);
205
+
206
+ delete pagination_loader_state[pagination_name]; // not waiting for page anymore
207
+
208
+ $.rails.fire(getSection(pagination_name),"ajaxp:loaded");
209
+ });
210
+ jqXHR.fail(function(jqXHR, textStatus, errorThrown) {
211
+ if (requesturl != pagination_loader_state[pagination_name]) return; // ignore stale content
212
+ if ($.rails.fire(getSection(pagination_name),"ajaxp:fail",[jqXHR.responseText])) $(id).html(jqXHR.responseText);
213
+
214
+ delete pagination_loader_state[pagination_name]; // not waiting for page anymore
215
+
216
+ $.rails.fire(getSection(pagination_name),"ajaxp:loaded");
217
+ });
218
+ return true;
219
+ }
220
+ function swapPage(pagination_name, requesturl, history) { // swaps the page at pagination_name to that from requesturl (used by History.popState, therefore no remote link has been clicked)
221
+ if (history === undefined) history = false;
222
+ // send our own ajax request, and tie it into the beforeSendHandler used for jquery-ujs as well
223
+ if (!$.rails.fire(getSection(pagination_name),"ajaxp:before",[requesturl,undefined])) return false;
224
+ $.ajax({url: requesturl, data: {pagination:pagination_name},
225
+ dataType: 'html',
226
+ beforeSend: function (jqXHR,settings) {
227
+ var result = beforeSendHandler(pagination_name,jqXHR,settings);
228
+ if (result) {
229
+ if (history) pushHistory(pagination_name,settings.url);
230
+ pagination_loader_state[pagination_name] = settings.url; // remember which page number we are waiting for
231
+ }
232
+ return result;
233
+ }
234
+ });
235
+ }
236
+ function pushHistory(pagination_name,url) {
237
+ var data = $("#" + pagination_name + "_paginated_section").data("pagination");
238
+ if (data === undefined || data.history === undefined || data.history) { // check that history is not disabled
239
+ // construct visible url
240
+ var data = $.deparam.querystring($.url(url).attr('query'));
241
+ delete data['pagination'];
242
+ pagination_url = $.param.querystring(url,data,2);
243
+ if (isReload(pagination_name,url,location.href)) History.replaceState(history_state,document.title,pagination_url);
244
+ else { // not just a reload of current page, so do actual pushState
245
+ // change current history state, and push it on
246
+ if (history_state.ajax_pagination === undefined) history_state.ajax_pagination = new Array();
247
+ var fieldname = "_" + pagination_name;
248
+ if (history_state.ajax_pagination[fieldname] === undefined) history_state.ajax_pagination[fieldname]=1;
249
+ else history_state.ajax_pagination[fieldname]++;
250
+ History.pushState(history_state,document.title,pagination_url); // push state
251
+ }
252
+ }
253
+ }
254
+ // these special containers are for convenience only, to apply the required data-remote, data-pagination attributes to all links inside
255
+ $(document).on("click", ".pagination a, .ajaxpagination a, a.ajaxpagination", function(e) {
256
+ // ignore if already selected by jquery-ujs
257
+ if ($(this).filter($.rails.linkClickSelector).length>0) return true; // continue with jquery-ujs - this behaviour is necessary because we do not know if the jquery-ujs handler executes before or after this handler
258
+ // find out what data-pagination should be set to
259
+ var pagination_container = $(this).closest(".pagination, .ajaxpagination"); // container of links (use to check for data-pagination first)
260
+ var pagination_name = pagination_container.data('pagination');
261
+ if (pagination_name === undefined) {
262
+ pagination_name = /^(.*)_paginated_section$/.exec($(this).closest(".paginated_section").attr("id")); // if data-pagination not present, search up the tree for a suitable section
263
+ if (pagination_name == null) {
264
+
265
+ alert("AJAX Pagination MISSING_REFERENCE:\nNo pagination section name given for link, and none could be implicitly assigned, AJAX cancelled for this request");
266
+
267
+ return true; // pagination not set up properly
268
+ }
269
+ pagination_name = pagination_name[1];
270
+ }
271
+
272
+ // set data-remote, data-pagination
273
+ $(this).attr({'data-remote':'true'}); // needs to be set so that the jquery-ujs selectors work
274
+ $(this).data({'remote':'true','pagination':pagination_name}); // needs to be set because attributes only read into jquery's data memory once
275
+ if ($(this).data('type') === undefined) { // to be moved to ajax:before filter when https://github.com/rails/jquery-ujs/pull/241 is successful, and jquery-rails minimum version updated
276
+ $(this).data('type','html'); // AJAX Pagination requests return html be default
277
+ }
278
+ // stop this event from having further effect (because we do not know if jquery-ujs's event handler executed before or after us)
279
+ e.preventDefault();
280
+ e.stopImmediatePropagation();
281
+ // pass it on the jquery-ujs
282
+ $.rails.handleRemote($(this));
283
+ return false;
284
+ });
285
+ $(document).on("ajax:before","a, " + $.rails.inputChangeSelector, function() {
286
+ var pagination_name = $(this).data('pagination');
287
+ if (pagination_name === undefined) return true; // this is not an AJAX Pagination AJAX request
288
+ $(this).data('params',$.extend($(this).data('params'),{'pagination':pagination_name})); // add data-pagination to the params data
289
+ return $.rails.fire(getSection(pagination_name),"ajaxp:before",[this.href,$(this).data('method')]);
290
+ });
291
+ $(document).on("ajax:before","form", function() {
292
+ var pagination_name = $(this).data('pagination');
293
+ if (pagination_name === undefined) return true; // this is not an AJAX Pagination AJAX request
294
+ // alter action to include pagination parameter in the GET part of the action url
295
+ $(this).attr('action',$.param.querystring($(this).attr('action'),{pagination:pagination_name}));
296
+ return $.rails.fire(getSection(pagination_name),"ajaxp:before",[$(this).attr('action'),$(this).data('method')]);
297
+ });
298
+ $(document).on("ajax:beforeSend","a, form, " + $.rails.inputChangeSelector, function (e,jqXHR,settings) {
299
+ var pagination_name = $(this).data('pagination');
300
+ if (pagination_name === undefined) return true; // this is not an AJAX Pagination AJAX request
301
+ if (beforeSendHandler(pagination_name,jqXHR,settings)) {
302
+ pushHistory(pagination_name,settings.url);
303
+ pagination_loader_state[pagination_name] = settings.url;
304
+ }
305
+ return true;
306
+ });
307
+ History.Adapter.bind(window,'popstate',function(e){ // popstate, but can work with hash changes as well
308
+ //var from = pagination_url, to = location.href; // from what state to what other state
309
+ var state = History.getState().data || {};
310
+ state.ajax_pagination = state.ajax_pagination || {};
311
+ history_state.ajax_pagination = history_state.ajax_pagination || {};
312
+ if (!state.ajax_pagination_set) { // page first visited (if refresh, state remains)
313
+ state.ajax_pagination = history_state.ajax_pagination; // put current known state in
314
+ state.ajax_pagination_set = true; // special flag so that we know its touched
315
+ History.replaceState(state,document.title,location.href);
316
+ return;
317
+ }
318
+ var allsections = {};
319
+ for (var field in state.ajax_pagination) {
320
+ //if (getSection(field.substr(1)).length == 0) delete state.ajax_pagination[field]; // section no longer exists in current page, so can be deleted
321
+ // edit it cannot be deleted anymore, because if history changes, section tree node not necessarily reloaded
322
+ allsections[field] = true;
323
+ }
324
+ for (var field in history_state.ajax_pagination) allsections[field] = true;
325
+
326
+ var changedsections = new Array();
327
+ for (var section in allsections) {
328
+ var from = history_state.ajax_pagination[section] || 0;
329
+ var to = state.ajax_pagination[section] || 0;
330
+ if (from != to) {
331
+ // schedule for loading only if not a refresh (changing browser history does not cause a refresh unless it is explicitly requested)
332
+ //alert('testing ' + section);
333
+ if (!isReload(section.substr(1),location.href,pagination_url)) changedsections.push(section.substr(1)); // this section changed
334
+ }
335
+ }
336
+ history_state = state; // we can update our view of the state now
337
+
338
+ changedsections.sort(); // sort the pagination_names stored in array
339
+ for (var i = 0; i < changedsections.length; i++) {
340
+ var section = getSection(changedsections[i]);
341
+ if (section.length == 0) continue; // no longer exists on page (meaning it does not need reloading)
342
+ var parentsections = getSectionNames(section.parents(".paginated_section"));
343
+ parentsections.sort();
344
+ // check for intersection
345
+ if (!intersects(changedsections,parentsections)) { // no intersection, load new content in this section
346
+ swapPage(changedsections[i],location.href);
347
+ }
348
+ }
349
+
350
+ pagination_url = location.href; // update url (new url recognised)
351
+ });
352
+
353
+ History.Adapter.trigger(window,"popstate"); // update stuff on page load
354
+
355
+ // trigger a loaded event on each section on initial page load
356
+ $.rails.fire($(".paginated_section"),"ajaxp:loaded");
357
+ }
358
+ else {
359
+ // AJAX Pagination is disabled, we need to tidy up a few things to keep things working
360
+
361
+ // remove remote attribute globally
362
+ $("a[data-pagination]").removeData('remote');
363
+ $("a[data-pagination]").removeAttr('data-remote');
364
+ $("form[data-pagination]").removeData('remote');
365
+ $("form[data-pagination]").removeAttr('data-remote');
366
+
367
+ // set an event handler to remove the remote attribute if new content is loaded with AJAX Pagination
368
+ $(document).children().add(".paginated_section").delegate("a, input, form","click.rails change.rails submit.rails", function(event) {
369
+ var element = $(event.target);
370
+ if (element.data('pagination') === undefined) return true;
371
+ else {
372
+ element.removeData('remote');
373
+ element.removeAttr('data-remote');
374
+ }
375
+ }); // note using delegate for this instance for backwards compatibility, since might be disabled due to old jQuery version
376
+
377
+ }
378
+ })( jQuery );
379
+ });
380
+