table_me 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.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +40 -0
- data/app/assets/images/table_me/orderable.png +0 -0
- data/app/assets/stylesheets/table_me/table_me.sass +171 -0
- data/config/routes.rb +2 -0
- data/lib/table_me/builder.rb +36 -0
- data/lib/table_me/column.rb +19 -0
- data/lib/table_me/engine.rb +28 -0
- data/lib/table_me/filter.rb +81 -0
- data/lib/table_me/table_for_helper/table_for_helper.rb +112 -0
- data/lib/table_me/table_for_presenter.rb +229 -0
- data/lib/table_me/table_me_helper/table_me_helper.rb +28 -0
- data/lib/table_me/table_me_presenter.rb +105 -0
- data/lib/table_me/table_pagination.rb +110 -0
- data/lib/table_me/table_vo.rb +48 -0
- data/lib/table_me/url_builder.rb +33 -0
- data/lib/table_me/url_parser.rb +38 -0
- data/lib/table_me/version.rb +3 -0
- data/lib/table_me.rb +15 -0
- data/lib/tasks/table_me_tasks.rake +4 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/users.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config/application.rb +56 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +46 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20120223225814_create_users.rb +9 -0
- data/test/dummy/db/schema.rb +23 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +52 -0
- data/test/dummy/log/test.log +6 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/fixtures/users.yml +9 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/integration/table_for_spec.rb +97 -0
- data/test/table_me_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- data/test/unit/table_me_presenter_test.rb +7 -0
- metadata +225 -0
@@ -0,0 +1,229 @@
|
|
1
|
+
require_relative 'table_me_presenter'
|
2
|
+
require_relative 'table_pagination'
|
3
|
+
require_relative 'builder'
|
4
|
+
require_relative 'url_builder'
|
5
|
+
|
6
|
+
module TableMe
|
7
|
+
|
8
|
+
# the first parameter of table_for is the name set in table_me. By default the class
|
9
|
+
# name is used if a name isn't set.
|
10
|
+
|
11
|
+
# table_for :user
|
12
|
+
# Now, this will list all columns from the database in your table, which you
|
13
|
+
# may not always want to do. You can pass a block of columns to be more specific:
|
14
|
+
|
15
|
+
# table_for :user do |t|
|
16
|
+
# t.column :id
|
17
|
+
# t.column :email
|
18
|
+
# t.column :created_at
|
19
|
+
# end
|
20
|
+
|
21
|
+
# This will give you a user table with the columns id, email, and created_at.
|
22
|
+
|
23
|
+
# What if you want to customize the output of the column? Each column can also
|
24
|
+
# take a block of content:
|
25
|
+
|
26
|
+
# table_for :user do |t|
|
27
|
+
# t.column :id
|
28
|
+
# t.column :email do |c|
|
29
|
+
# "<h1>c.email</h1>"
|
30
|
+
# end
|
31
|
+
# t.column :created_at
|
32
|
+
# end
|
33
|
+
|
34
|
+
# Now, when a block is used to alter the content of a column, the sorting is lost,
|
35
|
+
# since the table can no longer assume what is in the column. You need to set a sort_on
|
36
|
+
# param to tell the column what to sort by. For example:
|
37
|
+
|
38
|
+
# table_for :user do |t|
|
39
|
+
# t.column :id
|
40
|
+
# t.column :email, sort_on: :email do |c|
|
41
|
+
# "<h1>c.email</h1>"
|
42
|
+
# end
|
43
|
+
# t.column :created_at
|
44
|
+
# end
|
45
|
+
|
46
|
+
# Filters
|
47
|
+
# You can add basic filter fields to the table by using the filter method. Right now,
|
48
|
+
# only one filter can be applied and the filters are search fields. I would like to
|
49
|
+
# eventually add different types for different types of data. I would like to eventually
|
50
|
+
# add in the ability for multiple filter types with a single search button, but the basic
|
51
|
+
# form is all I need at the moment. Ajax enabled filtering would be freaking great as well.
|
52
|
+
|
53
|
+
# Filter usage:
|
54
|
+
|
55
|
+
# table_for :user do |t|
|
56
|
+
# t.filter :email
|
57
|
+
# t.filter :name
|
58
|
+
# t.column :id
|
59
|
+
# t.column :email
|
60
|
+
# t.column :name
|
61
|
+
# end
|
62
|
+
|
63
|
+
# The build_table method will use the other public methods to build a full table. It's
|
64
|
+
# possible to construct your own build table method if you want a custom layout.
|
65
|
+
|
66
|
+
|
67
|
+
class TableForPresenter < ActionView::Base
|
68
|
+
include ActionView::Helpers::CaptureHelper
|
69
|
+
include Haml::Helpers if defined?(Haml)
|
70
|
+
|
71
|
+
attr_accessor :name, :options
|
72
|
+
attr_reader :data
|
73
|
+
|
74
|
+
def initialize table_name, options = {}, &block
|
75
|
+
# self.parent = parent
|
76
|
+
self.options = options
|
77
|
+
self.name = table_name
|
78
|
+
@block = block
|
79
|
+
|
80
|
+
# required to get capture to work with haml
|
81
|
+
init_haml_helpers if defined?(Haml)
|
82
|
+
|
83
|
+
process_data_attributes
|
84
|
+
end
|
85
|
+
|
86
|
+
# build the complete table with pagination and filters if set.
|
87
|
+
|
88
|
+
def build_table
|
89
|
+
<<-HTML.strip_heredoc.html_safe
|
90
|
+
<div class='table-me'>
|
91
|
+
#{table_filters}
|
92
|
+
<div class="table-me-table #{'with-filters' if table_builder.filters}">
|
93
|
+
#{table_pagination.pagination_info}
|
94
|
+
<table>
|
95
|
+
<thead>
|
96
|
+
<tr>#{create_header}</tr>
|
97
|
+
</thead>
|
98
|
+
<tbody>
|
99
|
+
#{table_rows}
|
100
|
+
</tbody>
|
101
|
+
</table>
|
102
|
+
#{table_pagination.pagination_controls}
|
103
|
+
</div>
|
104
|
+
</div>
|
105
|
+
HTML
|
106
|
+
end
|
107
|
+
|
108
|
+
# get data from the table_me_presenter in the controller. This breaks encapsulation and makes
|
109
|
+
# this class too tightly coupled to the TableMePresenter, I wanted to keep the table data out
|
110
|
+
# of the class variables in the controller and view, but there has to be a better way to do it.
|
111
|
+
# TODO decouple this and options below
|
112
|
+
def data
|
113
|
+
TableMePresenter.data[name.to_s]
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
# same as data above, only with table options. Ideally this needs to be a value object instead
|
118
|
+
# of just a hash. TODO use a value object instead of a hash, see table_vo.rb
|
119
|
+
def options
|
120
|
+
TableMePresenter.options[name.to_s]
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
|
127
|
+
# create table filters if they exist
|
128
|
+
def table_filters
|
129
|
+
<<-HTML if table_builder.filters
|
130
|
+
<div class='table-filters'>
|
131
|
+
<h3>Filters</h3>
|
132
|
+
#{table_builder.filters.map do |filter|
|
133
|
+
filter.display
|
134
|
+
end.join("\n")}
|
135
|
+
#{table_builder.clear_filter}
|
136
|
+
</div>
|
137
|
+
HTML
|
138
|
+
end
|
139
|
+
|
140
|
+
# create a table pagination object
|
141
|
+
def table_pagination
|
142
|
+
@table_pagination ||= TablePagination.new(options)
|
143
|
+
end
|
144
|
+
|
145
|
+
# find the class of the data passed in
|
146
|
+
def data_class
|
147
|
+
data.first.class
|
148
|
+
end
|
149
|
+
|
150
|
+
# create the sortable headers from columns given
|
151
|
+
def create_header
|
152
|
+
order = options[:order].split(' ')
|
153
|
+
table_columns.map do |column|
|
154
|
+
if column.sortable
|
155
|
+
if order[0] == column.sortable.to_s
|
156
|
+
url = TableMe::UrlBuilder.url_for(options, order: "#{column.sortable.to_s} #{order[1].downcase == 'asc' ? 'desc' : 'asc'}")
|
157
|
+
klass = order[1]
|
158
|
+
else
|
159
|
+
url = TableMe::UrlBuilder.url_for(options, order: "#{column.sortable.to_s} asc")
|
160
|
+
klass = nil
|
161
|
+
end
|
162
|
+
"<th><a #{"class='#{klass}'" if klass} href='#{url}'>#{column.name.to_s.split('_').join(' ').titleize}</a></th>"
|
163
|
+
else
|
164
|
+
"<th>#{column.name.to_s.split('_').join(' ').titleize}</th>"
|
165
|
+
end
|
166
|
+
end.join.html_safe
|
167
|
+
end
|
168
|
+
|
169
|
+
# create table rows based on data for each row using columns as a template
|
170
|
+
def table_rows
|
171
|
+
data.map do |d|
|
172
|
+
<<-HTML
|
173
|
+
<tr>
|
174
|
+
#{table_column_for(d)}
|
175
|
+
</tr>
|
176
|
+
HTML
|
177
|
+
end.join.html_safe
|
178
|
+
end
|
179
|
+
|
180
|
+
# it would ne nicer to encapsulate this into the column class, but then we have
|
181
|
+
# to set it up like a view so capture works. For now, I'll leave this here, I'm not
|
182
|
+
# sure if the encapsulation is worth the overhead
|
183
|
+
def table_column_for data
|
184
|
+
table_columns.map do |column|
|
185
|
+
if column.content
|
186
|
+
"<td>#{capture(data, &column.content)}</td>"
|
187
|
+
else
|
188
|
+
"<td>#{data[column.name]}</td>"
|
189
|
+
end
|
190
|
+
end.join
|
191
|
+
end
|
192
|
+
|
193
|
+
# create a table builder instance
|
194
|
+
def table_builder
|
195
|
+
@builder ||= TableMe::Builder.new(options)
|
196
|
+
end
|
197
|
+
|
198
|
+
# get column names from the table_builder
|
199
|
+
def col_names
|
200
|
+
table_builder.names
|
201
|
+
end
|
202
|
+
|
203
|
+
# get table columns from the table_builder
|
204
|
+
def table_columns
|
205
|
+
table_builder.columns
|
206
|
+
end
|
207
|
+
|
208
|
+
# pass in the block given to the table_for_presenter if it exists
|
209
|
+
# else just create a column for every column in the data object
|
210
|
+
def process_data_attributes
|
211
|
+
if @block
|
212
|
+
capture(table_builder, &@block)
|
213
|
+
if table_builder.columns.empty?
|
214
|
+
build_all_columns
|
215
|
+
end
|
216
|
+
else
|
217
|
+
build_all_columns
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# create a column for every column in the data object
|
222
|
+
def build_all_columns
|
223
|
+
data.first.attribute_names.each do |attribute|
|
224
|
+
table_builder.column(attribute)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative '../../../table_me/table_me_presenter'
|
2
|
+
module TableMe
|
3
|
+
|
4
|
+
# Controller
|
5
|
+
# A table must first be created in your controller using the table_me method.
|
6
|
+
|
7
|
+
# table_me(collection, options)
|
8
|
+
# The collection can be two things, first an ActiveRecord::Relation, which
|
9
|
+
# is the result of some sort of active record query ex:
|
10
|
+
|
11
|
+
# table_me( User.where(subscribed: true) )
|
12
|
+
# Keep in mind that doing User.all just returns an array of objects, not the a relation.
|
13
|
+
|
14
|
+
# In order to do the equivalent of the .all just pass in the ActiveRecord class:
|
15
|
+
|
16
|
+
# table_me( User )
|
17
|
+
# Possible options available for this method are:
|
18
|
+
|
19
|
+
# name - Label for the the table
|
20
|
+
# per_page - The amount of items per page of the table
|
21
|
+
|
22
|
+
module TableMeHelper
|
23
|
+
def table_me(model, options = {})
|
24
|
+
table_presenter = TableMePresenter.new(model, options,params)
|
25
|
+
table_presenter.name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require_relative 'url_parser'
|
2
|
+
module TableMe
|
3
|
+
|
4
|
+
# table_me(collection, options)
|
5
|
+
# The collection can be two things, first an ActiveRecord::Relation, which
|
6
|
+
# is the result of some sort of active record query ex:
|
7
|
+
|
8
|
+
# table_me( User.where(subscribed: true) )
|
9
|
+
# Keep in mind that doing User.all just returns an array of objects, not the a relation.
|
10
|
+
|
11
|
+
# In order to do the equivalent of the .all just pass in the ActiveRecord class:
|
12
|
+
|
13
|
+
# table_me( User )
|
14
|
+
# Possible options available for this method are:
|
15
|
+
|
16
|
+
# name - Label for the the table
|
17
|
+
# per_page - The amount of items per page of the table
|
18
|
+
class TableMePresenter
|
19
|
+
attr_accessor :params, :name
|
20
|
+
attr_reader :data, :options
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def data
|
24
|
+
@@data
|
25
|
+
end
|
26
|
+
|
27
|
+
def options
|
28
|
+
@@options
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@@data = {}
|
33
|
+
@@options = {}
|
34
|
+
|
35
|
+
def initialize model, options = {}, params = {}
|
36
|
+
# this was more of a patch for the code. I need to go back through and normalize all
|
37
|
+
# the hash access so a normal has can be used with confidence
|
38
|
+
# TODO normalize hash access to strings or symbols
|
39
|
+
@options = ActiveSupport::HashWithIndifferentAccess.new(options)
|
40
|
+
|
41
|
+
set_defaults_for model
|
42
|
+
parse_params_for params
|
43
|
+
get_data_for model
|
44
|
+
@@options[self.name] = @options
|
45
|
+
end
|
46
|
+
|
47
|
+
# parse the params into an options hash that we can use
|
48
|
+
def parse_params_for params
|
49
|
+
options.merge! URLParser.parse_params_for(params, self.name)
|
50
|
+
end
|
51
|
+
|
52
|
+
# set defaults for options
|
53
|
+
def set_defaults_for model
|
54
|
+
options[:page] = 1
|
55
|
+
options[:per_page] ||= 10
|
56
|
+
options[:name] ||= model.to_s.downcase
|
57
|
+
options[:order] ||= 'created_at ASC'
|
58
|
+
self.name = options[:name]
|
59
|
+
end
|
60
|
+
|
61
|
+
# make the model queries to pull back the data based on pagination and search results if given
|
62
|
+
def get_data_for model
|
63
|
+
model = apply_search_to(model)
|
64
|
+
|
65
|
+
@@data[self.name] = @data = model.limit(options[:per_page])
|
66
|
+
.offset(start_item)
|
67
|
+
.order(options[:order])
|
68
|
+
|
69
|
+
options[:total_count] = model.count
|
70
|
+
options[:page_total] = (options[:total_count] / options[:per_page].to_f).ceil
|
71
|
+
end
|
72
|
+
|
73
|
+
# Apply the search query to the appropriate table columns. This is sort of ugly at the moment
|
74
|
+
# and not as reliable as it could be. It needs to be refactored to account for different column
|
75
|
+
# types and use appropriate search methods. Ex. LIKE doesn't work for integers
|
76
|
+
# TODO refactor this to be more reliable for all column types
|
77
|
+
def apply_search_to model
|
78
|
+
if options[:search]
|
79
|
+
if options[:new_search]
|
80
|
+
options[:page] = 1
|
81
|
+
options.delete(:new_search)
|
82
|
+
end
|
83
|
+
|
84
|
+
column_hash = model.columns_hash || model.class.columns_hash
|
85
|
+
|
86
|
+
if column_hash[options[:search][:column].to_s].sql_type.include?('char')
|
87
|
+
model.where(model.arel_table[options[:search][:column]].matches("%#{options[:search][:query]}%"))
|
88
|
+
else
|
89
|
+
model.where(options[:search][:column].to_sym => options[:search][:query])
|
90
|
+
end
|
91
|
+
else
|
92
|
+
model
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# beginning item for the offset relation call
|
97
|
+
def start_item
|
98
|
+
(options[:page].to_i - 1) * options[:per_page].to_i
|
99
|
+
end
|
100
|
+
|
101
|
+
def name= value
|
102
|
+
self.options[:name] = @name = value
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require_relative 'url_builder'
|
3
|
+
module TableMe
|
4
|
+
|
5
|
+
# This handles the pagination elements of the table
|
6
|
+
class TablePagination
|
7
|
+
attr_accessor :options
|
8
|
+
|
9
|
+
def initialize table_options
|
10
|
+
self.options = table_options
|
11
|
+
end
|
12
|
+
|
13
|
+
# Information at the top of the table displaying the table name and
|
14
|
+
# position page/item wise out of a total.
|
15
|
+
def pagination_info
|
16
|
+
<<-HTML.strip_heredoc
|
17
|
+
<div class='table-me-pagination-info'>
|
18
|
+
<h3>#{options[:name].split('_').join(' ').titleize}</h3> <p><b>#{options[:page]}</b> of <b>#{options[:page_total]}</b> out of a total <b>#{options[:total_count]}</b></p>
|
19
|
+
</div>
|
20
|
+
HTML
|
21
|
+
end
|
22
|
+
|
23
|
+
# Adds controls at the bottom of the table for previous and next and a 5 number range
|
24
|
+
# TODO Refactor so controllers are hidden when pages on unavailable. IE, if your on page 1
|
25
|
+
# you shouldn't be able to see a previous button, or if your on the last page you shouldn't
|
26
|
+
# be able to see the next button
|
27
|
+
def pagination_controls
|
28
|
+
<<-HTML.strip_heredoc
|
29
|
+
<div class='table-me-pagination-controls'>
|
30
|
+
<a href="#{prev_page_url}" class='previous'>« Prev</a> #{pagination_number_list} <a href="#{next_page_url}" class='next'>Next »</a>
|
31
|
+
</div>
|
32
|
+
HTML
|
33
|
+
end
|
34
|
+
|
35
|
+
def next_page_url
|
36
|
+
page = if current_page == total_pages
|
37
|
+
total_pages
|
38
|
+
else
|
39
|
+
current_page + 1
|
40
|
+
end
|
41
|
+
|
42
|
+
link_for_page page
|
43
|
+
end
|
44
|
+
|
45
|
+
def prev_page_url
|
46
|
+
page = if current_page == 0
|
47
|
+
0
|
48
|
+
else
|
49
|
+
current_page - 1
|
50
|
+
end
|
51
|
+
|
52
|
+
link_for_page page
|
53
|
+
end
|
54
|
+
|
55
|
+
# List of number links for the number range between next and previous
|
56
|
+
def pagination_number_list
|
57
|
+
(0...page_button_count).to_a.map do |n|
|
58
|
+
link_number = n + page_number_offset
|
59
|
+
number_span(link_number)
|
60
|
+
end.join(' ')
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def number_span link_number
|
66
|
+
if current_page.to_s == link_number.to_s
|
67
|
+
<<-HTML.strip_heredoc
|
68
|
+
<span class='page current'>#{link_number}</span>
|
69
|
+
HTML
|
70
|
+
else
|
71
|
+
<<-HTML.strip_heredoc
|
72
|
+
<span class='page'><a href='#{link_for_page(link_number)}'>#{link_number}</a></span>
|
73
|
+
HTML
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def link_for_page page
|
78
|
+
TableMe::UrlBuilder.url_for options, page: page
|
79
|
+
end
|
80
|
+
|
81
|
+
def current_page
|
82
|
+
options[:page].to_i
|
83
|
+
end
|
84
|
+
|
85
|
+
def total_pages
|
86
|
+
options[:page_total]
|
87
|
+
end
|
88
|
+
|
89
|
+
def page_number_offset
|
90
|
+
if current_page >= total_pages - 2
|
91
|
+
current_page - 4 + (total_pages - current_page)
|
92
|
+
elsif current_page <= 2
|
93
|
+
1
|
94
|
+
else
|
95
|
+
current_page - 2
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def page_button_count
|
100
|
+
if total_pages > 5
|
101
|
+
5
|
102
|
+
elsif total_pages > 1
|
103
|
+
total_pages
|
104
|
+
else
|
105
|
+
0
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# I was going to use this instead of a hash which is passed around, but it started getting too complex
|
2
|
+
# for a generic value object, so I might do something else later, not worth it at this time.
|
3
|
+
module TableMe
|
4
|
+
class TableVO
|
5
|
+
def self.vo_attr_accessor *args
|
6
|
+
@@set_methods = *args
|
7
|
+
attr_accessor *args
|
8
|
+
end
|
9
|
+
|
10
|
+
vo_attr_accessor :page, :page_total, :search,
|
11
|
+
:order, :name, :per_page,
|
12
|
+
:total_count, :other_tables
|
13
|
+
|
14
|
+
def initialize params = {}
|
15
|
+
self.merge! params
|
16
|
+
end
|
17
|
+
|
18
|
+
def []= key, value
|
19
|
+
self.method("#{key}=").call(value)
|
20
|
+
end
|
21
|
+
|
22
|
+
def [] key
|
23
|
+
self.method(key).call
|
24
|
+
end
|
25
|
+
|
26
|
+
def merge! object
|
27
|
+
object.each do |k,v|
|
28
|
+
self.method("#{k}=").call(v) unless v.nil?
|
29
|
+
end
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def each
|
34
|
+
@@set_methods.each do |method|
|
35
|
+
yield(method,self.method(method).call)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_hash
|
40
|
+
hash = {}
|
41
|
+
@@set_methods.each do |method|
|
42
|
+
hash[method] = method(method).call
|
43
|
+
end
|
44
|
+
hash
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
module TableMe
|
3
|
+
|
4
|
+
# This class builds the url needed for the tables based on the table options.
|
5
|
+
# Some options are filtered out to make the url as short as possible.
|
6
|
+
class UrlBuilder
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def url_for options, additional_options = {}
|
10
|
+
table_options = options.merge additional_options
|
11
|
+
|
12
|
+
url = []
|
13
|
+
filter_options(table_options).each do |option|
|
14
|
+
url << {"tm_#{option[:name]}".to_sym => option }.to_param
|
15
|
+
end
|
16
|
+
"?#{url.join('&')}"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Filter out all options except name page search and order
|
20
|
+
# We need to dup the objects so we don't alter the options
|
21
|
+
# object through out the table_me module
|
22
|
+
def filter_options options
|
23
|
+
other_tables = options[:other_tables].dup || []
|
24
|
+
temp_options = options.dup
|
25
|
+
temp_options.keep_if do |k,v|
|
26
|
+
['name','page','search','order'].include? k.to_s
|
27
|
+
end
|
28
|
+
other_tables << temp_options
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require_relative 'url_builder'
|
3
|
+
module TableMe
|
4
|
+
# Parse the url params into the hash needed for table_me to work. Take the tables
|
5
|
+
# which aren't the current one and save them as other_tables so we can persist
|
6
|
+
# their states in links.
|
7
|
+
class URLParser
|
8
|
+
def self.parse_params_for params, name
|
9
|
+
@@name = name
|
10
|
+
parse_table_me(params)
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
|
17
|
+
def self.parse_table_me params
|
18
|
+
table_options = {}
|
19
|
+
other_tables = []
|
20
|
+
params.each do |k,v|
|
21
|
+
if k.to_s.include? 'tm_'
|
22
|
+
if v[:name] == @@name.to_s
|
23
|
+
table_options = v
|
24
|
+
else
|
25
|
+
other_tables << v
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
table_options[:other_tables] = other_tables
|
30
|
+
table_options
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.name
|
34
|
+
@@name
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/table_me.rb
ADDED