paginated_table 0.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.
Files changed (63) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +132 -0
  3. data/Rakefile +38 -0
  4. data/lib/paginated_table.rb +7 -0
  5. data/lib/paginated_table/controller_helpers.rb +14 -0
  6. data/lib/paginated_table/engine.rb +7 -0
  7. data/lib/paginated_table/page.rb +87 -0
  8. data/lib/paginated_table/railtie.rb +12 -0
  9. data/lib/paginated_table/version.rb +3 -0
  10. data/lib/paginated_table/view_helpers.rb +168 -0
  11. data/lib/tasks/paginated_table_tasks.rake +4 -0
  12. data/test/dummy/README.rdoc +261 -0
  13. data/test/dummy/Rakefile +7 -0
  14. data/test/dummy/app/assets/javascripts/application.js +16 -0
  15. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  16. data/test/dummy/app/controllers/application_controller.rb +3 -0
  17. data/test/dummy/app/controllers/data_controller.rb +27 -0
  18. data/test/dummy/app/helpers/application_helper.rb +2 -0
  19. data/test/dummy/app/views/data/_data.html.erb +7 -0
  20. data/test/dummy/app/views/data/index.html.erb +3 -0
  21. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  22. data/test/dummy/config.ru +4 -0
  23. data/test/dummy/config/application.rb +59 -0
  24. data/test/dummy/config/boot.rb +10 -0
  25. data/test/dummy/config/database.yml +25 -0
  26. data/test/dummy/config/environment.rb +5 -0
  27. data/test/dummy/config/environments/development.rb +37 -0
  28. data/test/dummy/config/environments/production.rb +67 -0
  29. data/test/dummy/config/environments/test.rb +37 -0
  30. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  31. data/test/dummy/config/initializers/inflections.rb +15 -0
  32. data/test/dummy/config/initializers/mime_types.rb +5 -0
  33. data/test/dummy/config/initializers/secret_token.rb +7 -0
  34. data/test/dummy/config/initializers/session_store.rb +8 -0
  35. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  36. data/test/dummy/config/locales/en.yml +5 -0
  37. data/test/dummy/config/routes.rb +59 -0
  38. data/test/dummy/db/test.sqlite3 +0 -0
  39. data/test/dummy/log/test.log +56930 -0
  40. data/test/dummy/public/404.html +26 -0
  41. data/test/dummy/public/422.html +26 -0
  42. data/test/dummy/public/500.html +25 -0
  43. data/test/dummy/public/favicon.ico +0 -0
  44. data/test/dummy/script/rails +6 -0
  45. data/test/dummy/tmp/cache/assets/CB7/360/sprockets%2F8334f01490cb91467dfd76ad25b67780 +0 -0
  46. data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  47. data/test/dummy/tmp/cache/assets/D25/810/sprockets%2F4ff88255fbab9775241c5d8c8c6e2088 +0 -0
  48. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  49. data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  50. data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  51. data/test/dummy/tmp/cache/assets/D62/6D0/sprockets%2F9b8014b0c5371c3bf5dd4f018a5ec71e +0 -0
  52. data/test/dummy/tmp/cache/assets/D71/1A0/sprockets%2F32c631252aee35736d93e06f3edffd6d +0 -0
  53. data/test/dummy/tmp/cache/assets/DD3/F90/sprockets%2Fc24290dff33aff9c3d2f971f6d8ae04b +0 -0
  54. data/test/dummy/tmp/cache/assets/DD4/950/sprockets%2F09e7f24ef1ff59b4fc390bdf415c60af +0 -0
  55. data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +9809 -0
  56. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +9809 -0
  57. data/test/dummy/tmp/capybara/capybara-201204041545476374284085.html +12 -0
  58. data/test/integration/paginated_table_integration_test.rb +235 -0
  59. data/test/test_helper.rb +31 -0
  60. data/test/units/controller_helpers_test.rb +43 -0
  61. data/test/units/page_test.rb +192 -0
  62. data/test/units/view_helpers_test.rb +317 -0
  63. metadata +276 -0
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <link href="/assets/application.css" media="all" rel="stylesheet" type="text/css">
6
+ <script src="/assets/application.js" type="text/javascript"></script>
7
+ </head>
8
+ <body>
9
+
10
+ <table class="paginated"><tbody></tbody></table>
11
+ </body>
12
+ </html>
@@ -0,0 +1,235 @@
1
+ require 'test_helper'
2
+ require 'capybara/webkit'
3
+
4
+ describe "paginated_table integration" do
5
+
6
+ describe "rendering" do
7
+ before do
8
+ visit "/data"
9
+ end
10
+
11
+ it "displays a pagination area" do
12
+ page.has_xpath?(pagination_xpath).must_equal true
13
+ end
14
+
15
+ it "displays a paginated table" do
16
+ page.has_xpath?(table_xpath).must_equal true
17
+ end
18
+
19
+ it "displays Name in the first column header" do
20
+ page.has_xpath?("#{th_xpath(1)}[.='Name']").must_equal true
21
+ end
22
+
23
+ it "displays Raw in the third column header" do
24
+ page.has_xpath?("#{th_xpath(3)}[.='Raw']").must_equal true
25
+ end
26
+
27
+ it "displays the data names in the first column" do
28
+ (1..10).each do |row|
29
+ page.has_xpath?("#{tr_xpath(row)}/td[1][.='Name #{row}']").must_equal true
30
+ end
31
+ end
32
+
33
+ it "displays links to the data in the second column" do
34
+ (1..10).each do |row|
35
+ page.has_xpath?("#{tr_xpath(row)}/td[2]/a[@href='/data/#{row}'][.='#{row}']").must_equal true
36
+ end
37
+ end
38
+
39
+ describe "with javascript" do
40
+ before do
41
+ Capybara.current_driver = Capybara.javascript_driver
42
+ end
43
+
44
+ it "updates only the pagination table from pagination table links" do
45
+ visit "/data"
46
+ click_link "2"
47
+ wait_for_ajax_request
48
+ page.has_xpath?("//h1[2]").must_equal false
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "pagination" do
54
+ describe "without javascript" do
55
+ it "displays one page of results" do
56
+ visit "/data"
57
+ pagination_info_text.must_equal "Displaying data controller/data 1 - 10 of 100 in total"
58
+ end
59
+
60
+ it "follows the link to the second page of results" do
61
+ visit "/data"
62
+ click_link "2"
63
+ pagination_info_text.must_equal "Displaying data controller/data 11 - 20 of 100 in total"
64
+ end
65
+ end
66
+
67
+ describe "with javascript" do
68
+ before do
69
+ Capybara.current_driver = Capybara.javascript_driver
70
+ end
71
+
72
+ it "displays one page of results" do
73
+ visit "/data"
74
+ pagination_info_text.must_equal "Displaying data controller/data 1 - 10 of 100 in total"
75
+ end
76
+
77
+ it "follows the link to the second page of results" do
78
+ visit "/data"
79
+ click_link "2"
80
+ wait_for_ajax_request
81
+ pagination_info_text.must_equal "Displaying data controller/data 11 - 20 of 100 in total"
82
+ end
83
+
84
+ # Ensures the AJAX content is decorated with event handlers
85
+ it "follows the link to the fourth page, then back to the third page" do
86
+ visit "/data"
87
+ click_link "4"
88
+ wait_for_ajax_request
89
+ pagination_info_text.must_equal "Displaying data controller/data 31 - 40 of 100 in total"
90
+ click_link "3"
91
+ wait_for_ajax_request
92
+ pagination_info_text.must_equal "Displaying data controller/data 21 - 30 of 100 in total"
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "sorting" do
98
+ describe "decoration" do
99
+ it "marks the sortable columns" do
100
+ visit "/data"
101
+ page.has_xpath?("#{th_xpath(1)}[@class='sortable'][.='Name']").must_equal true
102
+ end
103
+
104
+ it "marks the sort column when sorted in ascending order" do
105
+ visit "/data"
106
+ click_link "Name"
107
+ page.has_xpath?("#{th_xpath(1)}[@class='sortable sorted_asc'][.='Name']").must_equal true
108
+ end
109
+
110
+ it "marks the sort column when sorted in descending order" do
111
+ visit "/data"
112
+ click_link "Name"
113
+ click_link "Name"
114
+ page.has_xpath?("#{th_xpath(1)}[@class='sortable sorted_desc'][.='Name']").must_equal true
115
+ end
116
+ end
117
+
118
+ describe "without javascript" do
119
+ it "follows the link to sort the first column in ascending order" do
120
+ visit "/data"
121
+ click_link "Name"
122
+ [1, 10, 100, 11, 12, 13, 14, 15, 16, 17].each_with_index do |row, i|
123
+ page.has_xpath?("#{tr_xpath(i + 1)}/td[1][.='Name #{row}']").must_equal true
124
+ end
125
+ end
126
+
127
+ it "follows the link to sort the first column twice in descending order" do
128
+ visit "/data"
129
+ click_link "Name"
130
+ click_link "Name"
131
+ [99, 98, 97, 96, 95, 94, 93, 92, 91, 90].each_with_index do |row, i|
132
+ page.has_xpath?("#{tr_xpath(i + 1)}/td[1][.='Name #{row}']").must_equal true
133
+ end
134
+ end
135
+
136
+ it "follows the link to sort the first column, then to the second page" do
137
+ visit "/data"
138
+ click_link "Name"
139
+ click_link "2"
140
+ [18, 19, 2, 20, 21, 22, 23, 24, 25, 26].each_with_index do |row, i|
141
+ page.has_xpath?("#{tr_xpath(i + 1)}/td[1][.='Name #{row}']").must_equal true
142
+ end
143
+ end
144
+
145
+ it "has no link to sort the second column" do
146
+ visit "/data"
147
+ page.has_xpath?("a[.='Link']").must_equal false
148
+ end
149
+ end
150
+
151
+ describe "with javascript" do
152
+ before do
153
+ Capybara.current_driver = Capybara.javascript_driver
154
+ end
155
+
156
+ it "follows the link to sort the first column in ascending order" do
157
+ visit "/data"
158
+ click_link "Name"
159
+ wait_for_ajax_request
160
+ [1, 10, 100, 11, 12, 13, 14, 15, 16, 17].each_with_index do |row, i|
161
+ page.has_xpath?("#{tr_xpath(i + 1)}/td[1][.='Name #{row}']").must_equal true
162
+ end
163
+ end
164
+
165
+ it "follows the link to sort the first column twice in descending order" do
166
+ visit "/data"
167
+ click_link "Name"
168
+ wait_for_ajax_request
169
+ click_link "Name"
170
+ wait_for_ajax_request
171
+ [99, 98, 97, 96, 95, 94, 93, 92, 91, 90].each_with_index do |row, i|
172
+ page.has_xpath?("#{tr_xpath(i + 1)}/td[1][.='Name #{row}']").must_equal true
173
+ end
174
+ end
175
+
176
+ it "follows the link to sort the first column, then to the second page" do
177
+ visit "/data"
178
+ click_link "Name"
179
+ wait_for_ajax_request
180
+ click_link "2"
181
+ wait_for_ajax_request
182
+ [18, 19, 2, 20, 21, 22, 23, 24, 25, 26].each_with_index do |row, i|
183
+ page.has_xpath?("#{tr_xpath(i + 1)}/td[1][.='Name #{row}']").must_equal true
184
+ end
185
+ end
186
+ end
187
+ end
188
+
189
+ def pagination_xpath
190
+ "//div[@class='paginated_table']"
191
+ end
192
+
193
+ def pagination_header_xpath
194
+ "#{pagination_xpath}/div[@class='header']"
195
+ end
196
+
197
+ def pagination_info_xpath
198
+ "#{pagination_header_xpath}/div[@class='info']"
199
+ end
200
+
201
+ def table_xpath
202
+ "#{pagination_xpath}/table[@class='paginated']"
203
+ end
204
+
205
+ def th_xpath(column)
206
+ "#{table_xpath}/thead/tr[1]/th[#{column}]"
207
+ end
208
+
209
+ def tbody_xpath
210
+ "#{table_xpath}/tbody[1]"
211
+ end
212
+
213
+ def tr_xpath(row)
214
+ "#{tbody_xpath}/tr[#{row}]"
215
+ end
216
+
217
+ def pagination_info_text
218
+ info = find(:xpath, pagination_info_xpath)
219
+ replace_nbsp(info.text)
220
+ end
221
+
222
+ def replace_nbsp(str)
223
+ if str.respond_to?(:valid_encoding?)
224
+ str.force_encoding('UTF-8').gsub(/\xc2\xa0/u, ' ')
225
+ else
226
+ str.gsub(/\xc2\xa0/u, ' ')
227
+ end
228
+ end
229
+
230
+ def wait_for_ajax_request
231
+ wait_until do
232
+ page.evaluate_script('jQuery.active') == 0
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,31 @@
1
+ # Configure Rails Environment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rails/test_help"
6
+ require 'minitest/autorun'
7
+ require 'capybara/rails'
8
+ require 'mocha/integration/mini_test'
9
+
10
+ Rails.backtrace_cleaner.remove_silencers!
11
+
12
+ # Load support files
13
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
14
+
15
+ # Load fixtures from the engine
16
+ if ActiveSupport::TestCase.method_defined?(:fixture_path=)
17
+ ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
18
+ end
19
+
20
+ Capybara.javascript_driver = :webkit
21
+
22
+ class IntegrationTest < MiniTest::Spec
23
+ include Capybara::DSL
24
+
25
+ after do
26
+ Capybara.reset_sessions!
27
+ Capybara.use_default_driver
28
+ end
29
+ end
30
+
31
+ MiniTest::Spec.register_spec_type(/integration$/, IntegrationTest)
@@ -0,0 +1,43 @@
1
+ module PaginatedTable
2
+ describe ControllerHelpers do
3
+ let(:params) { stub("params") }
4
+ let(:request) { stub("request", :xhr? => false) }
5
+ let(:controller) {
6
+ controller = Object.new
7
+ controller.extend(ControllerHelpers)
8
+ controller.stubs(:params => params, :request => request)
9
+ controller
10
+ }
11
+
12
+ describe "#paginated_table" do
13
+ let(:collection) { stub("collection") }
14
+ let(:tables) { { "collection_name" => collection } }
15
+ let(:page) { stub("page") }
16
+ let(:data) { stub("data") }
17
+ let(:data_page) { stub("data_page", :data => data, :page => page) }
18
+
19
+ before do
20
+ PageParams.stubs(:create_page_from_params).with(params).returns(page)
21
+ DataPage.stubs(:new).with(collection, page).returns(data_page)
22
+ end
23
+
24
+ it "sets an instance variable on the controller with the data page" do
25
+ controller.paginated_table(tables)
26
+ controller.instance_variable_get("@collection_name").must_equal data_page
27
+ end
28
+
29
+ it "renders the named partial without layout if request is xhr?" do
30
+ request.stubs(:xhr? => true)
31
+ controller.expects(:render).
32
+ with(:partial => "collection_name", :layout => false)
33
+ controller.paginated_table(tables)
34
+ end
35
+
36
+ it "does not render if request is not xhr?" do
37
+ request.stubs(:xhr? => false)
38
+ controller.expects(:render).never
39
+ controller.paginated_table(tables)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,192 @@
1
+ module PaginatedTable
2
+ describe Page do
3
+ let(:page) { Page.new(:number => 2, :rows => 5, :sort_column => 'name', :sort_direction => 'desc') }
4
+
5
+ it "has a page number" do
6
+ page.number.must_equal 2
7
+ end
8
+
9
+ it "does not accept a negative page number" do
10
+ lambda { Page.new(:number => -1) }.must_raise ArgumentError
11
+ end
12
+
13
+ it "does not accept a zero page number" do
14
+ lambda { Page.new(:number => 0) }.must_raise ArgumentError
15
+ end
16
+
17
+ it "does not accept an invalid page number" do
18
+ lambda { Page.new(:number => 'foo') }.must_raise ArgumentError
19
+ end
20
+
21
+ it "has a rows number" do
22
+ page.rows.must_equal 5
23
+ end
24
+
25
+ it "does not accept a negative number of rows" do
26
+ lambda { Page.new(:rows => -1) }.must_raise ArgumentError
27
+ end
28
+
29
+ it "does not accept a zero number of rows "do
30
+ lambda { Page.new(:rows => 0) }.must_raise ArgumentError
31
+ end
32
+
33
+ it "does not accept an invalid page number" do
34
+ lambda { Page.new(:rows => 'foo') }.must_raise ArgumentError
35
+ end
36
+
37
+ it "has a sort column" do
38
+ page.sort_column.must_equal 'name'
39
+ end
40
+
41
+ it "has a sort direction" do
42
+ page.sort_direction.must_equal 'desc'
43
+ end
44
+
45
+ it "does not accept an invalid sort direction" do
46
+ lambda { Page.new(:sort_direction => 'foo') }.must_raise ArgumentError
47
+ end
48
+
49
+ describe ".opposite_sort_direction" do
50
+ it "returns asc for desc" do
51
+ Page.opposite_sort_direction('asc').must_equal 'desc'
52
+ end
53
+
54
+ it "returns desc for asc" do
55
+ Page.opposite_sort_direction('desc').must_equal 'asc'
56
+ end
57
+ end
58
+
59
+ describe "#page_for_number" do
60
+ describe "with a new page number" do
61
+ let(:number_page) { page.page_for_number(3) }
62
+
63
+ it "returns a new page with the new page number" do
64
+ number_page.number.must_equal 3
65
+ end
66
+
67
+ it "returns a new page with the same number of rows" do
68
+ number_page.rows.must_equal 5
69
+ end
70
+
71
+ it "returns a new page with the same sort column" do
72
+ number_page.sort_column.must_equal 'name'
73
+ end
74
+
75
+ it "returns a new page with the same sort direction" do
76
+ number_page.sort_direction.must_equal 'desc'
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#page_for_sort_column" do
82
+ describe "on a new sort column" do
83
+ let(:sort_page) { page.page_for_sort_column('title') }
84
+
85
+ it "returns a new page with page number 1" do
86
+ sort_page.number.must_equal 1
87
+ end
88
+
89
+ it "returns a new page with the same number of rows" do
90
+ sort_page.rows.must_equal 5
91
+ end
92
+
93
+ it "returns a new page with the given sort column" do
94
+ sort_page.sort_column.must_equal 'title'
95
+ end
96
+
97
+ it "returns a new page with sort direction asc" do
98
+ sort_page.sort_direction.must_equal 'asc'
99
+ end
100
+ end
101
+
102
+ describe "on the same sort column" do
103
+ let(:sort_page) { page.page_for_sort_column('name') }
104
+
105
+ it "returns a new page with page number 1" do
106
+ sort_page.number.must_equal 1
107
+ end
108
+
109
+ it "returns a new page with the same number of rows" do
110
+ sort_page.rows.must_equal 5
111
+ end
112
+
113
+ it "returns a new page with the same sort column" do
114
+ sort_page.sort_column.must_equal 'name'
115
+ end
116
+
117
+ it "returns a new page with the opposite sort direction" do
118
+ sort_page.sort_direction.must_equal 'asc'
119
+ sort_page.page_for_sort_column('name').sort_direction.must_equal 'desc'
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ describe PageParams do
126
+ describe ".create_from_params" do
127
+ it "returns a new page created from the request params" do
128
+ page = PageParams.create_page_from_params(
129
+ :page => '2',
130
+ :per_page => '5',
131
+ :sort_column => 'name',
132
+ :sort_direction => 'desc'
133
+ )
134
+ page.number.must_equal 2
135
+ page.rows.must_equal 5
136
+ page.sort_column.must_equal 'name'
137
+ page.sort_direction.must_equal 'desc'
138
+ end
139
+ end
140
+
141
+ describe ".to_params" do
142
+ it "creates a params hash from the page" do
143
+ page = Page.new(
144
+ :number => 2,
145
+ :rows => 5,
146
+ :sort_column => 'name',
147
+ :sort_direction => 'desc'
148
+ )
149
+ PageParams.to_params(page).must_equal(
150
+ :page => '2',
151
+ :per_page => '5',
152
+ :sort_column => 'name',
153
+ :sort_direction => 'desc'
154
+ )
155
+ end
156
+ end
157
+ end
158
+
159
+ describe DataPage do
160
+ describe "#data" do
161
+ let(:page) {
162
+ Page.new(
163
+ :number => 2,
164
+ :rows => 5,
165
+ :sort_column => 'name',
166
+ :sort_direction => 'asc'
167
+ )
168
+ }
169
+ let(:collection) {
170
+ collection = (1..10).map { |i| "Name #{i}" }
171
+ def collection.order(clause)
172
+ raise unless clause == "name asc"
173
+ sort
174
+ end
175
+ collection
176
+ }
177
+
178
+ it "sorts the collection and pages to the given page number" do
179
+ DataPage.new(collection, page).data.must_equal(
180
+ ["Name 5", "Name 6", "Name 7", "Name 8", "Name 9"]
181
+ )
182
+ end
183
+
184
+ describe "#page" do
185
+ it "provides a reference to the given page" do
186
+ DataPage.new(collection, page).page.must_equal page
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ end