listalicious 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +0 -0
- data/.gitignore +0 -0
- data/LICENSE +0 -0
- data/README.textile +38 -54
- data/Rakefile +0 -0
- data/VERSION +1 -1
- data/lib/builders/generic_builder.rb +18 -13
- data/lib/builders/table_builder.rb +11 -13
- data/lib/listalicious.rb +102 -32
- data/listalicious.gemspec +2 -2
- data/test/helper.rb +0 -0
- data/test/test_listalicious.rb +0 -0
- metadata +2 -2
data/.document
CHANGED
File without changes
|
data/.gitignore
CHANGED
File without changes
|
data/LICENSE
CHANGED
File without changes
|
data/README.textile
CHANGED
@@ -4,9 +4,7 @@ Semantic listing; a semantic way to build datagrid structures in Rails.
|
|
4
4
|
|
5
5
|
h2. The Story
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
So I started this project to do just that. I quickly learned that datagrids aren't especially easy to make amazing, and there's a lot of things that one might want to do with them... grouping (with a row that creates a separator), sorting, ordering, additional informational rows, footers, ajax pagination, etc. etc. etc.. The list is actually pretty long, and I wrote a lot of those things, but it's nowhere near perfect. I sort of don't think it's possible with how I've approached it this time around. Anyhow, I thought I could get something to a point that simplified the datagrid process, and I believe I've succeeded in providing a good start. I opted out of adding several features for the time being until I need them -- at which point I might have a better understanding of how I could approach it better. I cover some of my thoughts below in this document.
|
7
|
+
I started this project to create a pretty simple and clean way to create datagrids. I quickly learned that datagrids aren't especially easy to make amazing, and there's a lot of things that one might want to do with them... grouping (with a row that creates a separator), sorting, ordering, additional informational rows, footers, ajax pagination, etc. etc. etc.. The list is actually pretty long, but I've only written a few of those things. This is a good start, and if it doesn't contain the features you're looking for feel free to fork and add them.
|
10
8
|
|
11
9
|
So, as always, I set up some requirements for what the project should do, and here's what I came up with (a lot of these are standard):
|
12
10
|
|
@@ -22,13 +20,13 @@ So, as always, I set up some requirements for what the project should do, and he
|
|
22
20
|
I wrote a DSL that met those requirements:
|
23
21
|
|
24
22
|
<pre>
|
25
|
-
<% semantic_list_for @users do |l| %>
|
23
|
+
<% semantic_list_for @users, :as => :user do |l| %>
|
26
24
|
<%= l.head do %>
|
27
|
-
<%= l.column '
|
28
|
-
<%= l.column 'Email
|
25
|
+
<%= l.column 'User Login' %>
|
26
|
+
<%= l.column 'Email' %>
|
29
27
|
<% end %>
|
30
28
|
<%= l.columns do |user, index| %>
|
31
|
-
<%= l.column
|
29
|
+
<%= l.column :login %>
|
32
30
|
<%= l.column link_to(user.email, "mailto:#{user.email}") %>
|
33
31
|
<%= l.controls link_to('edit', edit_user_path(user)) %>
|
34
32
|
<% end %>
|
@@ -38,22 +36,22 @@ I wrote a DSL that met those requirements:
|
|
38
36
|
<% end %>
|
39
37
|
</pre>
|
40
38
|
|
41
|
-
I liked this, but could it be reduced further if the use case allowed? I came up with the following
|
39
|
+
I liked this, but could it be reduced further if the use case allowed? I came up with the following (which outlines the different ways you can pass args)
|
42
40
|
|
43
41
|
<pre>
|
44
|
-
<% semantic_list_for @users do |l| %>
|
42
|
+
<% semantic_list_for @users, :as => :user do |l| %>
|
45
43
|
<%= l.columns [:head, :body] do |user, index| %>
|
46
|
-
|
47
|
-
<%= l.column user.
|
48
|
-
<%= l.column
|
44
|
+
<%= l.column :login, :title => 'User Login' %>
|
45
|
+
<%= l.column "#{user.first_name} #{user.last_name}", :title => 'Name' %>
|
46
|
+
<%= l.column :email, { link_to user.email, "mailto:#{user.email}" } %>
|
49
47
|
<%= l.controls link_to('edit', edit_user_path(user)) %>
|
50
48
|
<% end %>
|
51
49
|
<% end %>
|
52
50
|
</pre>
|
53
51
|
|
54
|
-
|
52
|
+
I implemented both DSLs and leave it to your discretion on which one is best to use in your case.
|
55
53
|
|
56
|
-
Since using builders on previous projects has worked out fairly well, I
|
54
|
+
Since using builders on previous projects has worked out fairly well, I tried the same thing here. There's a single builder provided for now, TableBuilder (which inherits from GenericBuilder). GenericBuilder provides some basic functionality (ordering links for example), and isn't intended to be used as a builder by itself. And as always, the builders can be extended or replaced if you need more custom markup.
|
57
55
|
|
58
56
|
h2. Installation
|
59
57
|
|
@@ -69,33 +67,26 @@ Then install the listalicious gem:
|
|
69
67
|
sudo gem install listalicious
|
70
68
|
</pre>
|
71
69
|
|
72
|
-
If you would like to get the default JS and CSS files you can use the generator after installing:
|
73
|
-
|
74
|
-
<pre>
|
75
|
-
[no javascript or css provided yet]
|
76
|
-
</pre>
|
77
|
-
|
78
70
|
h2. Usage
|
79
71
|
|
80
|
-
Listalicious works fine
|
72
|
+
Listalicious works fine as a simple view helper, but it also handles ordering of the lists as well. To add ordering to any list just use the order_from named scope with your find method. You can also specify fields that are allowed to be ordered in your model by using the orderable_fields method.
|
81
73
|
|
82
|
-
h3.
|
74
|
+
h3. Controllers
|
83
75
|
|
84
76
|
<pre>
|
85
|
-
|
86
|
-
|
87
|
-
|
77
|
+
def index
|
78
|
+
@user = User.ordered_from(params).paginate :page => params[:page], :per_page => 20
|
79
|
+
# respond ...
|
88
80
|
end
|
89
81
|
</pre>
|
90
82
|
|
91
|
-
h3.
|
83
|
+
h3. Models
|
92
84
|
|
93
85
|
<pre>
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
format.xml { render :xml => @users }
|
86
|
+
class User < ActiveRecord::Base
|
87
|
+
orderable_fields do
|
88
|
+
only :first_name, :last_name, :login, :email
|
89
|
+
default :login, :desc, :stable => true
|
99
90
|
end
|
100
91
|
end
|
101
92
|
</pre>
|
@@ -104,16 +95,13 @@ h3. Views (I prefer HAML, so no ERB examples, but it should work with ERB fine a
|
|
104
95
|
|
105
96
|
It's important to note that all the methods take blocks or content strings. For instance, look at the extra and controls methods in the simple usage example.
|
106
97
|
|
107
|
-
It's also important to notice that the controls cell is not being counted in the columns. This is because I position these absolutely and do a hover event on them.. I'll likely take this out shortly so it doesn't effect anyone else.
|
108
|
-
|
109
98
|
*Simple Usage*
|
110
99
|
|
111
100
|
<pre>
|
112
|
-
- semantic_list_for @users, :html => {:class => 'list'} do |l|
|
101
|
+
- semantic_list_for @users, :as => :user, :html => {:class => 'list'} do |l|
|
113
102
|
= l.columns [:head, :body] do |user, index|
|
114
|
-
|
115
|
-
= l.column
|
116
|
-
= l.column user.email, :title => 'Email Address', :sort => 'email'
|
103
|
+
= l.column :login, :width => '20%'
|
104
|
+
= l.column :email, :title => 'Email Address'
|
117
105
|
= l.extra do
|
118
106
|
= "You can add more information about #{user.first_name} here."
|
119
107
|
= l.controls link_to('edit', edit_user_path(user))
|
@@ -134,7 +122,7 @@ It's also important to notice that the controls cell is not being counted in the
|
|
134
122
|
<td class="controls"><a href="/users/1/edit">edit</a></td>
|
135
123
|
</tr>
|
136
124
|
<tr class="even">
|
137
|
-
<td colspan="
|
125
|
+
<td colspan="3">You can add more information about Jeremy here.</td>
|
138
126
|
</tr>
|
139
127
|
<tr class="odd">
|
140
128
|
<td>user1</td>
|
@@ -142,7 +130,7 @@ It's also important to notice that the controls cell is not being counted in the
|
|
142
130
|
<td class="controls"><a href="/users/2/edit">edit</a></td>
|
143
131
|
</tr>
|
144
132
|
<tr class="odd">
|
145
|
-
<td colspan="
|
133
|
+
<td colspan="3">You can add more information about User here.</td>
|
146
134
|
</tr>
|
147
135
|
</tbody>
|
148
136
|
</table>
|
@@ -168,7 +156,7 @@ It's also important to notice that the controls cell is not being counted in the
|
|
168
156
|
<table class="semantic-list" id="user_list">
|
169
157
|
<thead>
|
170
158
|
<tr class="header">
|
171
|
-
<th width="20%"><a class="sort-ascending" href="?
|
159
|
+
<th width="20%"><a class="sort-ascending" href="?user_sort_desc=last_name">Name</a></th>
|
172
160
|
<th>Email Address</th>
|
173
161
|
</tr>
|
174
162
|
</thead>
|
@@ -186,7 +174,7 @@ It's also important to notice that the controls cell is not being counted in the
|
|
186
174
|
</tbody>
|
187
175
|
<tfoot>
|
188
176
|
<tr>
|
189
|
-
<th colspan="
|
177
|
+
<th colspan="3">
|
190
178
|
<div class="pagination">[removed for your sanity]</div>
|
191
179
|
</th>
|
192
180
|
</tr>
|
@@ -197,39 +185,39 @@ It's also important to notice that the controls cell is not being counted in the
|
|
197
185
|
*Grouping* -- You can group lists, and this will add extra header rows as separators. This will include sort links if those were provided as well.
|
198
186
|
|
199
187
|
<pre>
|
200
|
-
- semantic_list_for @users, :group_by => :login do |l|
|
188
|
+
- semantic_list_for @users, :as => :user, :group_by => :login do |l|
|
201
189
|
</pre>
|
202
190
|
|
203
191
|
*Sorting* -- Sorting requires javascript. It's part of the javascript code that comes with Listalicious and requires Prototype.js. If you want to add sorting to the list, just provide a url for a sort action and it will put that into the HTML5 data-sorturl attribute. You can use your own javascript if you would like.
|
204
192
|
|
205
193
|
<pre>
|
206
|
-
- semantic_list_for @users, :sort_url => { :action => 'sort' } do |l|
|
194
|
+
- semantic_list_for @users, :as => :user, :sort_url => { :action => 'sort' } do |l|
|
207
195
|
</pre>
|
208
196
|
|
209
|
-
*Additional JS Functionality* -- There a few functions that are javascript specific. You can add any additional functionality this way as well
|
197
|
+
*Additional JS Functionality* -- There a few functions that are javascript specific. You can add any additional functionality this way as well since we're using unobtrusive JS to get the following features accomplished.
|
210
198
|
|
211
199
|
You can make the list multi-selectable. There isn't any pre-bundled functionality to do actions on the selected items, but you can fetch the list of selected items by using JS.
|
212
200
|
|
201
|
+
TODO: Document usage here
|
202
|
+
|
213
203
|
<pre>
|
214
|
-
- semantic_list_for @users, :selectable => true do |l|
|
204
|
+
- semantic_list_for @users, :as => :user, :selectable => true do |l|
|
215
205
|
</pre>
|
216
206
|
|
217
207
|
You can make the "extra" information rows expandable. If you add this, the extra rows won't show unless the row they belong to is highlighted.
|
218
208
|
|
219
209
|
<pre>
|
220
|
-
- semantic_list_for @users, :expandable => true do |l|
|
210
|
+
- semantic_list_for @users, :as => :user, :expandable => true do |l|
|
221
211
|
</pre>
|
222
212
|
|
223
213
|
h3. UL / OL Datagrids
|
224
214
|
|
225
|
-
The nature of doing a UL / OL based datagrid requires a certain level of CSS, and I haven't had time or reason to provide that level yet. When I finish up this project and include the JS and CSS needed for it (in a generator) I may add a builder for this, but there isn't one currently.
|
215
|
+
The nature of doing a UL / OL based datagrid requires a certain level of CSS, and I haven't had time or reason to provide that level yet. When I finish up this project and include the JS and CSS needed for it (in a generator) I may add a builder for this, but there isn't plans for one currently.
|
226
216
|
|
227
217
|
h3. Other
|
228
218
|
|
229
219
|
It's important to note that a lot of the functionality of these lists do not play nicely with one another -- I don't believe this is a shortcoming, and consider it more an effort to avoid overkill. A good example of this is the sortable features. For example, if you need the extra information and sorting together, you should consider using the :expandable => true option. Grouping and sorting don't play together nicely for obvious reasons as well. The javascript handles moving the extra container, in sorting, but doesn't attempt to do it gracefully. If I do the ListBuilder (UL/OL) to compliment the TableBuilder, it would likely handle these things somewhat better, but I haven't had a need for it yet.
|
230
220
|
|
231
|
-
I'm kicking around plans for how to make it more featureful without the annoying conflicts mentioned above. If you have any thoughts let me know, but I expect my solution will come by breaking up the builders by features.. So, instead of having a single TableBuilder, there would be a SortableTableBuilder, and an InformationalTableBuilder, and a MultiSelectTableBuilder, etc.. not sure how that would play out, but that's what I'm thinking might resolve some of the annoyances mentioned above.
|
232
|
-
|
233
221
|
And, as always, you can create your own builder by extending one of the existing ones, or by creating one from scratch.
|
234
222
|
|
235
223
|
Then just specify your builder, or do it as a configuration.
|
@@ -246,11 +234,7 @@ h2. Documentation
|
|
246
234
|
|
247
235
|
RDoc documentation _should_ be automatically generated after each commit and made available on the "rdoc.info website":http://rdoc.info/projects/jejacks0n/listalicious.
|
248
236
|
|
249
|
-
Documentation is pretty sparse right now.
|
250
|
-
|
251
|
-
h2. Compatibility
|
252
|
-
|
253
|
-
I'm only testing with the latest Rails 2.4.x stable release, and it should work under Rails 2.3.x as well. Feel free to add backwards compatibility if you need it.
|
237
|
+
Documentation is pretty sparse right now, and I'm working to resolve it.
|
254
238
|
|
255
239
|
h2. Project Info
|
256
240
|
|
data/Rakefile
CHANGED
File without changes
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
@@ -5,28 +5,33 @@ module Listalicious
|
|
5
5
|
|
6
6
|
def initialize(template, collection, options = {}, &proc)
|
7
7
|
@template, @collection, @options = template, collection, options
|
8
|
-
@object_name = collection.first.class.name.underscore
|
8
|
+
@object_name = "#{options[:as] || collection.first ? collection.first.class.name.underscore : ''}"
|
9
|
+
@table_name = (options[:table_name] || @object_name.pluralize).to_s
|
9
10
|
|
10
11
|
render(options.delete(:html), &proc)
|
11
12
|
end
|
12
13
|
|
13
14
|
def render(options, &proc); end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
# Creates the anchor tag for the orderable links.
|
17
|
+
# It looks in the params for specificly styled query params:
|
18
|
+
#
|
19
|
+
# eg. order[users][]=login:asc&order[users][]=first_name:asc
|
20
|
+
def orderable_link(contents, field)
|
21
|
+
return contents if @object_name.empty?
|
19
22
|
|
20
|
-
|
21
|
-
|
23
|
+
order_params = (template.params['order'] || {})[@table_name]
|
24
|
+
fields = Hash[*order_params.to_a.collect { |field_and_dir| field_and_dir.split(':') }.flatten]
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
method = direction == 'descending' ? "#{object_name}sort_desc" : "#{object_name}sort_asc"
|
26
|
-
params[method] = field
|
26
|
+
order_params = (template.params['order'] || {}).clone.
|
27
|
+
merge({@table_name => ["#{field}:#{"#{fields[field] == 'asc' ? 'desc' : 'asc'}"}"]})
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
query = template.params.reject{ |param, value| ['action', 'controller'].include?(param) }
|
30
|
+
query.merge!('order' => order_params)
|
30
31
|
|
32
|
+
template.content_tag(:a, contents,
|
33
|
+
:href => "?#{query.to_query}",
|
34
|
+
:class => "#{fields[field] ? fields[field] == 'asc' ? 'ascending' : 'descending' : ''}")
|
35
|
+
end
|
31
36
|
end
|
32
37
|
end
|
@@ -40,7 +40,7 @@ module Listalicious
|
|
40
40
|
|
41
41
|
def column_group_head(options = {}, &proc)
|
42
42
|
@column_count = 0
|
43
|
-
|
43
|
+
|
44
44
|
@head_wrapper = template.content_tag(:tr, template.capture(collection.first, 0, &proc),
|
45
45
|
options[:html].merge({:class => template.add_class(options[:html][:class], 'header')}))
|
46
46
|
template.content_tag(:thead, @head_wrapper, options.delete(:wrapper_html))
|
@@ -51,7 +51,8 @@ module Listalicious
|
|
51
51
|
return unless collection.first.present?
|
52
52
|
collection.each_with_index do |record, index|
|
53
53
|
@column_count = 0
|
54
|
-
|
54
|
+
@object = record
|
55
|
+
|
55
56
|
if @options[:grouped_by]
|
56
57
|
buffer << @head_wrapper if record[@options[:grouped_by]] != @last_row_grouping
|
57
58
|
@last_row_grouping = record[@options[:grouped_by]]
|
@@ -61,7 +62,7 @@ module Listalicious
|
|
61
62
|
buffer << template.content_tag(:tr, template.capture(record, index, &proc),
|
62
63
|
options[:html].merge({:class => template.add_class(options[:html][:class], @cycle)}))
|
63
64
|
buffer << template.content_tag(:tr, @extra,
|
64
|
-
options[:html].merge({:class => template.add_class(options[:html][:class], @cycle)})) if @extra.present?
|
65
|
+
options[:html].merge({:class => template.add_class(options[:html][:class], [@cycle, 'extra'])})) if @extra.present?
|
65
66
|
@extra = nil
|
66
67
|
end
|
67
68
|
template.content_tag(:tbody, buffer, options.delete(:wrapper_html))
|
@@ -93,9 +94,6 @@ module Listalicious
|
|
93
94
|
options[:html] ||= {}
|
94
95
|
options[:html][:colspan] ||= @column_count
|
95
96
|
|
96
|
-
options[:wrapper_html] ||= {}
|
97
|
-
options[:wrapper_html][:class] = template.add_class(options[:wrapper_html][:class], 'full-column')
|
98
|
-
|
99
97
|
@extra = self.send("#{@current_scope}_column", contents, options)
|
100
98
|
end
|
101
99
|
|
@@ -118,9 +116,6 @@ module Listalicious
|
|
118
116
|
options[:html] ||= {}
|
119
117
|
options[:html][:colspan] ||= @column_count
|
120
118
|
|
121
|
-
options[:wrapper_html] ||= {}
|
122
|
-
options[:wrapper_html][:class] = template.add_class(options[:wrapper_html][:class], 'extra')
|
123
|
-
|
124
119
|
@extra = self.send("#{@current_scope}_column", contents, options)
|
125
120
|
''
|
126
121
|
end
|
@@ -128,21 +123,24 @@ module Listalicious
|
|
128
123
|
def head_column(contents, options = {})
|
129
124
|
options[:html] ||= {}
|
130
125
|
options[:html][:width] ||= options[:width]
|
131
|
-
|
132
|
-
contents =
|
126
|
+
|
127
|
+
contents = contents.to_s.humanize.titleize if contents.is_a? Symbol
|
128
|
+
contents = orderable_link(contents, options[:sort]) if options[:sort]
|
133
129
|
|
134
130
|
template.content_tag(:th, contents, options.delete(:html))
|
135
131
|
end
|
136
132
|
|
137
133
|
def body_column(contents, options = {})
|
134
|
+
contents = @object.send(contents) if @object && contents.is_a?(Symbol)
|
135
|
+
|
138
136
|
template.content_tag(:td, contents, options.delete(:html))
|
139
137
|
end
|
140
138
|
|
141
139
|
def foot_column(contents, options = {})
|
142
|
-
contents =
|
140
|
+
contents = orderable_link(contents, options[:sort]) if options[:sort]
|
143
141
|
|
144
142
|
template.content_tag(:th, contents, options.delete(:html))
|
145
143
|
end
|
146
|
-
|
144
|
+
|
147
145
|
end
|
148
146
|
end
|
data/lib/listalicious.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
require
|
3
|
-
require
|
2
|
+
require 'builders/generic_builder'
|
3
|
+
require 'builders/table_builder'
|
4
4
|
|
5
5
|
module Listalicious #:nodoc:
|
6
6
|
|
@@ -13,23 +13,23 @@ module Listalicious #:nodoc:
|
|
13
13
|
@@builder = ::Listalicious::TableBuilder
|
14
14
|
mattr_accessor :builder
|
15
15
|
|
16
|
-
def semantic_list_for(collection,
|
16
|
+
def semantic_list_for(collection, options, &proc)
|
17
17
|
raise ArgumentError, "Missing block" unless block_given?
|
18
18
|
|
19
|
-
|
19
|
+
# TODO: should :as be required?
|
20
20
|
|
21
21
|
options[:html] ||= {}
|
22
22
|
options[:html][:class] = add_class(options[:html][:class], 'semantic-list')
|
23
|
-
options[:html][:id] ||= collection.first ?
|
24
|
-
|
25
|
-
options[:html][:class] = add_class(options[:html][:class], 'actionable') if options[:actionable]
|
26
|
-
options[:html][:class] = add_class(options[:html][:class], 'selectable') if options[:selectable]
|
23
|
+
options[:html][:id] ||= "#{options[:as] || collection.first ? collection.first.class.name.underscore : 'semantic'}_list"
|
27
24
|
|
28
25
|
if options[:sort_url]
|
29
26
|
options[:html][:class] = add_class(options[:html][:class], 'sortable')
|
30
27
|
options[:html]['data-sorturl'] = url_for(options[:sort_url])
|
31
28
|
end
|
32
29
|
|
30
|
+
options[:html][:class] = add_class(options[:html][:class], 'selectable') if options[:selectable]
|
31
|
+
options[:html][:class] = add_class(options[:html][:class], 'expandable') if options[:expandable]
|
32
|
+
|
33
33
|
builder = options[:builder] || TableBuilder
|
34
34
|
builder.new(@template, collection, options, &proc)
|
35
35
|
end
|
@@ -43,35 +43,105 @@ module Listalicious #:nodoc:
|
|
43
43
|
|
44
44
|
module ActiveRecordExtensions # :nodoc:
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
# Makes a given model orderable for lists
|
47
|
+
#
|
48
|
+
# To specify that a model behaves according to the Listalicious order style call orderable_fields. The
|
49
|
+
# orderable_fields method takes a configuration block.
|
50
|
+
#
|
51
|
+
# === Example
|
52
|
+
# orderable_fields do
|
53
|
+
# only :first_name, :last_name
|
54
|
+
# default :last_name
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# === Configuration Methods
|
58
|
+
# [only]
|
59
|
+
# Provide fields that are orderable.
|
60
|
+
# [except]
|
61
|
+
# Provide fields that are not orderable, with the default list being all fields.
|
62
|
+
# [default]
|
63
|
+
# Provide the default sort field, optionally a direction, and additional options.
|
64
|
+
#
|
65
|
+
# *Notes*:
|
66
|
+
# * If +only+ or +except+ are not called within the block, all fields on the model will be orderable, this includes
|
67
|
+
# things like id, and password/password salt columns.
|
68
|
+
# * If +default+ isn't called, the first field will be considered the default, asc being the default direction.
|
69
|
+
#
|
70
|
+
def orderable_fields(&config_block)
|
71
|
+
cattr_accessor :orderable_fields, :default_order
|
72
|
+
|
73
|
+
# make all columns orderable, incase only or except aren't called in the configuration block
|
74
|
+
self.orderable_fields = column_names.map { |column_name| column_name.to_s }
|
75
|
+
|
76
|
+
instance_eval(&config_block)
|
77
|
+
self.orderable_fields.collect!{ |field| field.to_s }
|
78
|
+
|
79
|
+
self.default_order ||= {:field => self.orderable_fields.first, :direction => :desc}
|
80
|
+
|
81
|
+
attach_orderable_scopes
|
51
82
|
end
|
52
83
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
84
|
+
# Provide fields that are orderable in the configuration block.
|
85
|
+
#
|
86
|
+
# *Note*: If +only+ or +except+ aren't called from within the configuration block, all fields will be orderable.
|
87
|
+
#
|
88
|
+
# === Example
|
89
|
+
# only :last_name, :email_address
|
90
|
+
def only(*args)
|
91
|
+
self.orderable_fields = args
|
92
|
+
end
|
62
93
|
|
63
|
-
|
64
|
-
|
65
|
-
|
94
|
+
# Provide fields that are not to be orderable, with the default list being all fields.
|
95
|
+
#
|
96
|
+
# *Note*: If +only+ or +except+ aren't called from within the configuration block, all fields will be orderable.
|
97
|
+
#
|
98
|
+
# === Example
|
99
|
+
# * except :id, :password
|
100
|
+
def except(*args)
|
101
|
+
self.orderable_fields - args
|
102
|
+
end
|
66
103
|
|
67
|
-
|
68
|
-
|
69
|
-
|
104
|
+
# Provide the default sort field, optionally a direction, and additional options.
|
105
|
+
#
|
106
|
+
# === Supported options
|
107
|
+
# [:stable]
|
108
|
+
# Will force appending the default sort to the end of all sort requests. Default is false.
|
109
|
+
#
|
110
|
+
# === Example
|
111
|
+
# default :first_name (direction defaults to :asc)
|
112
|
+
# default :first_name, :stable => true
|
113
|
+
# default :first_name, :desc, :stable => true
|
114
|
+
def default(*args)
|
115
|
+
options = args.extract_options!
|
116
|
+
field = args.shift
|
117
|
+
direction = args.shift || :asc
|
70
118
|
|
71
|
-
|
72
|
-
|
73
|
-
end
|
119
|
+
self.default_order = {:field => field, :direction => direction, :options => options}
|
120
|
+
end
|
74
121
|
|
122
|
+
# Attaches the ordered_from named scope to the model requesting it. The named scope can be chained in the
|
123
|
+
# controller by using:
|
124
|
+
#
|
125
|
+
# +Users.ordered_by(params).paginate :page => params[:page], :per_page => 2+
|
126
|
+
#
|
127
|
+
# The params are expected to be in a specific style:
|
128
|
+
#
|
129
|
+
# eg. order[table_name][]=last_name:desc&order[table_name][]=first_name:asc
|
130
|
+
#
|
131
|
+
# Which will generate the order clause +"last_name DESC, first_name ASC"+.
|
132
|
+
def attach_orderable_scopes
|
133
|
+
self.named_scope :ordered_from, lambda { |params|
|
134
|
+
return unless params.include?(:order) and params[:order][self.table_name.to_sym]
|
135
|
+
|
136
|
+
fields = params[:order][self.table_name.to_sym].collect do |field_and_dir|
|
137
|
+
field, dir = field_and_dir.split(':')
|
138
|
+
self.orderable_fields.include?(field) ? [field, dir.to_s.downcase] : nil
|
139
|
+
end.compact
|
140
|
+
|
141
|
+
fields.empty? ?
|
142
|
+
nil :
|
143
|
+
{:order => fields.map{ |field, dir| "#{field} #{dir.downcase == 'desc' ? 'DESC' : 'ASC'}" }.join(', ')}
|
144
|
+
}
|
75
145
|
end
|
76
146
|
|
77
147
|
end
|
@@ -79,4 +149,4 @@ module Listalicious #:nodoc:
|
|
79
149
|
end
|
80
150
|
|
81
151
|
ActionController::Base.helper Listalicious::SemanticListHelper
|
82
|
-
ActiveRecord::Base.
|
152
|
+
ActiveRecord::Base.extend Listalicious::ActiveRecordExtensions
|
data/listalicious.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{listalicious}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jeremy Jackson"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-03-02}
|
13
13
|
s.description = %q{Semantic listing; a semantic way to build datagrid structures in Rails.}
|
14
14
|
s.email = %q{jejacks0n@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/test/helper.rb
CHANGED
File without changes
|
data/test/test_listalicious.rb
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: listalicious
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Jackson
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-03-02 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|