tvdeyen-handles_sortable_columns 0.1.5
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.
- checksums.yaml +15 -0
- data/.gitignore +9 -0
- data/MIT-LICENSE +20 -0
- data/README.html +140 -0
- data/README.md +137 -0
- data/Rakefile +25 -0
- data/VERSION.yml +5 -0
- data/dev/github.css +41 -0
- data/dev/head.html +4 -0
- data/init.rb +2 -0
- data/lib/action_controller/base/handles_sortable_columns.rb +5 -0
- data/lib/handles/sortable_columns.rb +307 -0
- data/lib/handles_sortable_columns.rb +5 -0
- data/tvdeyen-handles_sortable_columns.gemspec +18 -0
- metadata +60 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
!binary "U0hBMQ==":
|
|
3
|
+
metadata.gz: !binary |-
|
|
4
|
+
YzQzYWI5MjU4OTg2YTIwM2NjNmQ5YjJiNjU3NWYyMWIyMzJlMTRmNQ==
|
|
5
|
+
data.tar.gz: !binary |-
|
|
6
|
+
YTUwNzkyY2ExZjRlOWU1MDI3MjJhYWZmNzIwMGQzODNhZGIyM2NjOA==
|
|
7
|
+
!binary "U0hBNTEy":
|
|
8
|
+
metadata.gz: !binary |-
|
|
9
|
+
NTljZmQ1ZjdhYTY1Yzc1MzJkZmM4MTAxYmRhZWExMmMyODRlZmYyODZjZWM5
|
|
10
|
+
OTFjZDE1OWNhODMyNDk2MjVjOWI0NmY3YzhlMmE1OGFiZDI5NTAyZGNjMTk4
|
|
11
|
+
OTFmM2IwOTFlY2I2ZDg4NTNhZGQ1MDQ5YTcwNjVkNTBjOTY1NzA=
|
|
12
|
+
data.tar.gz: !binary |-
|
|
13
|
+
YjFiYzdjODQ4MDM2ZWY5MDcxYjQyMDIwOWIwNTVkYzAzN2ZiM2Y3OWUzYzY3
|
|
14
|
+
MjgzZGI3NjQ0ZTkzMDAzYWMwZDZhNTdmMTE5OWMxOTE5MDg2MjFlMGZjMjY1
|
|
15
|
+
ZDNmODE1OTM2Zjg3MDA5ZTRiYWI2M2M0YjgyNzQ1N2M0ZjMwZmI=
|
data/.gitignore
ADDED
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2010-2011 Alex Fortuna
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.html
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
|
3
|
+
<link href="dev/github.css" rel="stylesheet" type="text/css" />
|
|
4
|
+
</head>
|
|
5
|
+
|
|
6
|
+
<h1 id="sortable-table-columns">Sortable Table Columns</h1>
|
|
7
|
+
|
|
8
|
+
<h2 id="introduction">Introduction</h2>
|
|
9
|
+
|
|
10
|
+
<p>A simple yet flexible Rails gem/plugin to quickly add sortable table columns to your controller and views.</p>
|
|
11
|
+
|
|
12
|
+
<h2 id="setup-rails-3">Setup (Rails 3)</h2>
|
|
13
|
+
|
|
14
|
+
<p>In your app’s <code>Gemfile</code>, add:</p>
|
|
15
|
+
|
|
16
|
+
<pre><code>gem "handles_sortable_columns"
|
|
17
|
+
</code></pre>
|
|
18
|
+
|
|
19
|
+
<p>To install the gem with RDoc/ri documentation, do a:</p>
|
|
20
|
+
|
|
21
|
+
<pre><code>$ gem install handles_sortable_columns
|
|
22
|
+
</code></pre>
|
|
23
|
+
|
|
24
|
+
<p>Otherwise, do a <code>bundle install</code>.</p>
|
|
25
|
+
|
|
26
|
+
<h2 id="setup-rails-2">Setup (Rails 2)</h2>
|
|
27
|
+
|
|
28
|
+
<p>In your app’s <code>config/environment.rb</code> add:</p>
|
|
29
|
+
|
|
30
|
+
<pre><code>config.gem "handles_sortable_columns"
|
|
31
|
+
</code></pre>
|
|
32
|
+
|
|
33
|
+
<p>To install the gem, do a:</p>
|
|
34
|
+
|
|
35
|
+
<pre><code>$ gem sources --add http://rubygems.org
|
|
36
|
+
$ gem install handles_sortable_columns
|
|
37
|
+
</code></pre>
|
|
38
|
+
|
|
39
|
+
<p>, or use <code>rake gems:install</code>.</p>
|
|
40
|
+
|
|
41
|
+
<h2 id="basic-usage">Basic Usage</h2>
|
|
42
|
+
|
|
43
|
+
<p>Activate the feature in your controller class:</p>
|
|
44
|
+
|
|
45
|
+
<pre><code>class MyController < ApplicationController
|
|
46
|
+
handles_sortable_columns
|
|
47
|
+
...
|
|
48
|
+
</code></pre>
|
|
49
|
+
|
|
50
|
+
<p>In a view, mark up sortable columns by using the <tt>sortable_column</tt> helper:</p>
|
|
51
|
+
|
|
52
|
+
<pre><code><%= sortable_column "Product" %>
|
|
53
|
+
<%= sortable_column "Price" %>
|
|
54
|
+
</code></pre>
|
|
55
|
+
|
|
56
|
+
<p>In controller action, fetch and use the order clause according to current state of sortable columns:</p>
|
|
57
|
+
|
|
58
|
+
<pre><code>def index
|
|
59
|
+
order = sortable_column_order
|
|
60
|
+
@records = Article.order(order) # Rails 3.
|
|
61
|
+
@records = Article.all(:order => order) # Rails 2.
|
|
62
|
+
end
|
|
63
|
+
</code></pre>
|
|
64
|
+
|
|
65
|
+
<p>That’s it for basic usage. Production usage may require passing additional parameters to listed methods.</p>
|
|
66
|
+
|
|
67
|
+
<h2 id="production-usage">Production Usage</h2>
|
|
68
|
+
|
|
69
|
+
<p>Please take time to read the gem’s full <a href="http://rdoc.info/projects/dadooda/handles_sortable_columns">RDoc documentation</a>. This README has a limited coverage.</p>
|
|
70
|
+
|
|
71
|
+
<h3 id="configuration">Configuration</h3>
|
|
72
|
+
|
|
73
|
+
<p>Change names of GET parameters used for sorting and pagination:</p>
|
|
74
|
+
|
|
75
|
+
<pre><code>class MyController < ApplicationController
|
|
76
|
+
handles_sortable_columns do |conf|
|
|
77
|
+
conf.sort_param = "s"
|
|
78
|
+
conf.page_param = "p"
|
|
79
|
+
end
|
|
80
|
+
...
|
|
81
|
+
</code></pre>
|
|
82
|
+
|
|
83
|
+
<p>Change CSS class of all sortable column <code><a></code> tags:</p>
|
|
84
|
+
|
|
85
|
+
<pre><code>handles_sortable_columns do |conf|
|
|
86
|
+
conf.class = "SortableLink"
|
|
87
|
+
conf.indicator_class = {:asc => "AscSortableLink", :desc => "DescSortableLink"}
|
|
88
|
+
end
|
|
89
|
+
</code></pre>
|
|
90
|
+
|
|
91
|
+
<p>Change how text-based sort indicator looks like:</p>
|
|
92
|
+
|
|
93
|
+
<pre><code>handles_sortable_columns do |conf|
|
|
94
|
+
conf.indicator_text = {:asc => "[asc]", :desc => "[desc]"}
|
|
95
|
+
end
|
|
96
|
+
</code></pre>
|
|
97
|
+
|
|
98
|
+
<p>Disable text-based sort indicator completely:</p>
|
|
99
|
+
|
|
100
|
+
<pre><code>handles_sortable_columns do |conf|
|
|
101
|
+
conf.indicator_text = {}
|
|
102
|
+
end
|
|
103
|
+
</code></pre>
|
|
104
|
+
|
|
105
|
+
<h3 id="helper-options">Helper Options</h3>
|
|
106
|
+
|
|
107
|
+
<p>Explicitly specify column name:</p>
|
|
108
|
+
|
|
109
|
+
<pre><code><%= sortable_column "Highest Price", :column => "max_price" %>
|
|
110
|
+
</code></pre>
|
|
111
|
+
|
|
112
|
+
<p>Specify CSS class for this particular link:</p>
|
|
113
|
+
|
|
114
|
+
<pre><code><%= sortable_column "Name", :class => "SortableLink" %>
|
|
115
|
+
</code></pre>
|
|
116
|
+
|
|
117
|
+
<p>Specify sort direction on first click:</p>
|
|
118
|
+
|
|
119
|
+
<pre><code><%= sortable_column "Created At", :direction => :asc %>
|
|
120
|
+
</code></pre>
|
|
121
|
+
|
|
122
|
+
<h3 id="fetching-sort-order">Fetching Sort Order</h3>
|
|
123
|
+
|
|
124
|
+
<p>To fetch sort order <strong>securely</strong>, with <strong>column name validation</strong>, <strong>default values</strong> and <strong>multiple sort criteria</strong>, use the block form of <code>sortable_column_order</code>:</p>
|
|
125
|
+
|
|
126
|
+
<pre><code>order = sortable_column_order do |column, direction|
|
|
127
|
+
case column
|
|
128
|
+
when "name"
|
|
129
|
+
"#{column} #{direction}"
|
|
130
|
+
when "created_at", "updated_at"
|
|
131
|
+
"#{column} #{direction}, name ASC"
|
|
132
|
+
else
|
|
133
|
+
"name ASC"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
</code></pre>
|
|
137
|
+
|
|
138
|
+
<h2 id="feedback">Feedback</h2>
|
|
139
|
+
|
|
140
|
+
<p>Send bug reports, suggestions and criticisms through <a href="http://github.com/dadooda/handles_sortable_columns">project’s page on GitHub</a>.</p>
|
data/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
|
|
2
|
+
Sortable Table Columns
|
|
3
|
+
======================
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Introduction
|
|
7
|
+
------------
|
|
8
|
+
|
|
9
|
+
A simple yet flexible Rails gem/plugin to quickly add sortable table columns to your controller and views.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Setup (Rails 3)
|
|
13
|
+
---------------
|
|
14
|
+
|
|
15
|
+
In your app's `Gemfile`, add:
|
|
16
|
+
|
|
17
|
+
gem "handles_sortable_columns"
|
|
18
|
+
|
|
19
|
+
To install the gem with RDoc/ri documentation, do a:
|
|
20
|
+
|
|
21
|
+
$ gem install handles_sortable_columns
|
|
22
|
+
|
|
23
|
+
Otherwise, do a `bundle install`.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
Setup (Rails 2)
|
|
27
|
+
---------------
|
|
28
|
+
|
|
29
|
+
In your app's `config/environment.rb` add:
|
|
30
|
+
|
|
31
|
+
config.gem "handles_sortable_columns"
|
|
32
|
+
|
|
33
|
+
To install the gem, do a:
|
|
34
|
+
|
|
35
|
+
$ gem sources --add http://rubygems.org
|
|
36
|
+
$ gem install handles_sortable_columns
|
|
37
|
+
|
|
38
|
+
, or use `rake gems:install`.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
Basic Usage
|
|
42
|
+
-----------
|
|
43
|
+
|
|
44
|
+
Activate the feature in your controller class:
|
|
45
|
+
|
|
46
|
+
class MyController < ApplicationController
|
|
47
|
+
handles_sortable_columns
|
|
48
|
+
...
|
|
49
|
+
|
|
50
|
+
In a view, mark up sortable columns by using the <tt>sortable_column</tt> helper:
|
|
51
|
+
|
|
52
|
+
<%= sortable_column "Product" %>
|
|
53
|
+
<%= sortable_column "Price" %>
|
|
54
|
+
|
|
55
|
+
In controller action, fetch and use the order clause according to current state of sortable columns:
|
|
56
|
+
|
|
57
|
+
def index
|
|
58
|
+
order = sortable_column_order
|
|
59
|
+
@records = Article.order(order) # Rails 3.
|
|
60
|
+
@records = Article.all(:order => order) # Rails 2.
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
That's it for basic usage. Production usage may require passing additional parameters to listed methods.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
Production Usage
|
|
67
|
+
----------------
|
|
68
|
+
|
|
69
|
+
Please take time to read the gem's full [RDoc documentation](http://rdoc.info/projects/dadooda/handles_sortable_columns). This README has a limited coverage.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
### Configuration ###
|
|
73
|
+
|
|
74
|
+
Change names of GET parameters used for sorting and pagination:
|
|
75
|
+
|
|
76
|
+
class MyController < ApplicationController
|
|
77
|
+
handles_sortable_columns do |conf|
|
|
78
|
+
conf.sort_param = "s"
|
|
79
|
+
conf.page_param = "p"
|
|
80
|
+
end
|
|
81
|
+
...
|
|
82
|
+
|
|
83
|
+
Change CSS class of all sortable column `<a>` tags:
|
|
84
|
+
|
|
85
|
+
handles_sortable_columns do |conf|
|
|
86
|
+
conf.class = "SortableLink"
|
|
87
|
+
conf.indicator_class = {:asc => "AscSortableLink", :desc => "DescSortableLink"}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
Change how text-based sort indicator looks like:
|
|
91
|
+
|
|
92
|
+
handles_sortable_columns do |conf|
|
|
93
|
+
conf.indicator_text = {:asc => "[asc]", :desc => "[desc]"}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
Disable text-based sort indicator completely:
|
|
97
|
+
|
|
98
|
+
handles_sortable_columns do |conf|
|
|
99
|
+
conf.indicator_text = {}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
### Helper Options ###
|
|
104
|
+
|
|
105
|
+
Explicitly specify column name:
|
|
106
|
+
|
|
107
|
+
<%= sortable_column "Highest Price", :column => "max_price" %>
|
|
108
|
+
|
|
109
|
+
Specify CSS class for this particular link:
|
|
110
|
+
|
|
111
|
+
<%= sortable_column "Name", :class => "SortableLink" %>
|
|
112
|
+
|
|
113
|
+
Specify sort direction on first click:
|
|
114
|
+
|
|
115
|
+
<%= sortable_column "Created At", :direction => :asc %>
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
### Fetching Sort Order ###
|
|
119
|
+
|
|
120
|
+
To fetch sort order **securely**, with **column name validation**, **default values** and **multiple sort criteria**, use the block form of `sortable_column_order`:
|
|
121
|
+
|
|
122
|
+
order = sortable_column_order do |column, direction|
|
|
123
|
+
case column
|
|
124
|
+
when "name"
|
|
125
|
+
"#{column} #{direction}"
|
|
126
|
+
when "created_at", "updated_at"
|
|
127
|
+
"#{column} #{direction}, name ASC"
|
|
128
|
+
else
|
|
129
|
+
"name ASC"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
Feedback
|
|
135
|
+
--------
|
|
136
|
+
|
|
137
|
+
Send bug reports, suggestions and criticisms through [project's page on GitHub](http://github.com/dadooda/handles_sortable_columns).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
begin
|
|
3
|
+
require 'bundler/gem_helper'
|
|
4
|
+
rescue LoadError
|
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
Bundler::GemHelper.install_tasks
|
|
9
|
+
|
|
10
|
+
task :default => :build
|
|
11
|
+
|
|
12
|
+
begin
|
|
13
|
+
require 'rdoc/task'
|
|
14
|
+
rescue LoadError
|
|
15
|
+
require 'rdoc/rdoc'
|
|
16
|
+
require 'rake/rdoctask'
|
|
17
|
+
RDoc::Task = Rake::RDocTask
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
desc "Generate RDoc documentation"
|
|
21
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
22
|
+
rdoc.rdoc_dir = "doc"
|
|
23
|
+
rdoc.title = "Handles::SortableColumns"
|
|
24
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
|
25
|
+
end
|
data/VERSION.yml
ADDED
data/dev/github.css
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
body{font:13.34px helvetica,arial,freesans,clean,sans-serif;}
|
|
3
|
+
body{width:920px;margin:0 auto;padding:0 15px;text-align:left;}
|
|
4
|
+
|
|
5
|
+
/* Это неважно работает, с виду погано. */
|
|
6
|
+
xbody{background-color:#f8f8f8;padding:.7em;}
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
#readme div.plain,#readme div.wikistyle{background-color:#f8f8f8;padding:.7em;}
|
|
10
|
+
.site{width:920px;margin:0 auto;padding:0 15px;text-align:left;}
|
|
11
|
+
#readme{font:13.34px helvetica,arial,freesans,clean,sans-serif;}
|
|
12
|
+
#readme.announce{margin:1em 0;}
|
|
13
|
+
#readme span.name{font-size:140%;padding:.8em 0;}
|
|
14
|
+
#readme div.plain,#readme div.wikistyle{background-color:#f8f8f8;padding:.7em;}
|
|
15
|
+
#readme.announce div.plain,#readme.announce div.wikistyle{border:1px solid #e9e9e9;}
|
|
16
|
+
#readme.blob div.plain,#readme.blob div.wikistyle{border-top:none;}
|
|
17
|
+
#readme div.plain pre{font-family:'Bitstream Vera Sans Mono','Courier',monospace;font-size:85%;color:#444;}
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
h1,h2,h3,h4,h5,h6{border:0!important;}
|
|
21
|
+
h1{font-size:170%!important;border-top:4px solid #aaa!important;padding-top:.5em!important;margin-top:1.5em!important;}
|
|
22
|
+
h1:first-child{margin-top:0!important;padding-top:.25em!important;border-top:none!important;}
|
|
23
|
+
h2{font-size:150%!important;margin-top:1.5em!important;border-top:4px solid #e0e0e0!important;padding-top:.5em!important;}
|
|
24
|
+
h3{margin-top:1em!important;}
|
|
25
|
+
p{margin:1em 0!important;line-height:1.5em!important;}
|
|
26
|
+
ul{margin:1em 0 1em 2em!important;}
|
|
27
|
+
ol{margin:1em 0 1em 2em!important;}
|
|
28
|
+
ul ul,ul ol,ol ol,ol ul{margin-top:0!important;margin-bottom:0!important;}
|
|
29
|
+
blockquote{margin:1em 0!important;border-left:5px solid #ddd!important;padding-left:.6em!important;color:#555!important;}
|
|
30
|
+
dt{font-weight:bold!important;margin-left:1em!important;}
|
|
31
|
+
dd{margin-left:2em!important;margin-bottom:1em!important;}
|
|
32
|
+
table{margin:1em 0!important;}
|
|
33
|
+
table th{border-bottom:1px solid #bbb!important;padding:.2em 1em!important;}
|
|
34
|
+
table td{border-bottom:1px solid #ddd!important;padding:.2em 1em!important;}
|
|
35
|
+
pre{margin:1em 0!important;font-size:90%!important;background-color:#f8f8ff!important;border:1px solid #dedede!important;padding:.5em!important;line-height:1.5em!important;color:#444!important;overflow:auto!important;}
|
|
36
|
+
pre code{padding:0!important;font-size:100%!important;background-color:#f8f8ff!important;border:none!important;}
|
|
37
|
+
code{font-size:90%!important;background-color:#f8f8ff!important;color:#444!important;padding:0 .2em!important;border:1px solid #dedede!important;}
|
|
38
|
+
pre.console{margin:1em 0!important;font-size:90%!important;background-color:black!important;padding:.5em!important;line-height:1.5em!important;color:white!important;}
|
|
39
|
+
pre.console code{padding:0!important;font-size:100%!important;background-color:black!important;border:none!important;color:white!important;}
|
|
40
|
+
pre.console span{color:#888!important;}
|
|
41
|
+
pre.console span.command{color:yellow!important;}
|
data/dev/head.html
ADDED
data/init.rb
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
module Handles #:nodoc:
|
|
2
|
+
# == Overview
|
|
3
|
+
#
|
|
4
|
+
# A sortable columns feature for your controller and views.
|
|
5
|
+
#
|
|
6
|
+
# == Basic Usage
|
|
7
|
+
#
|
|
8
|
+
# Activate the feature in your controller class:
|
|
9
|
+
#
|
|
10
|
+
# class MyController < ApplicationController
|
|
11
|
+
# handles_sortable_columns
|
|
12
|
+
# ...
|
|
13
|
+
#
|
|
14
|
+
# In a view, mark up sortable columns by using the <tt>sortable_column</tt> helper:
|
|
15
|
+
#
|
|
16
|
+
# <%= sortable_column "Product" %>
|
|
17
|
+
# <%= sortable_column "Price" % >
|
|
18
|
+
#
|
|
19
|
+
# In controller action, fetch and use the order clause according to current state of sortable columns:
|
|
20
|
+
#
|
|
21
|
+
# def index
|
|
22
|
+
# order = sortable_column_order
|
|
23
|
+
# @records = Article.order(order) # Rails 3.
|
|
24
|
+
# @records = Article.all(:order => order) # Rails 2.
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# That's it for basic usage. Production usage may require passing additional parameters to listed methods.
|
|
28
|
+
#
|
|
29
|
+
# See also:
|
|
30
|
+
# * MetaClassMethods#handles_sortable_columns
|
|
31
|
+
# * InstanceMethods#sortable_column_order
|
|
32
|
+
module SortableColumns
|
|
33
|
+
def self.included(owner) #:nodoc:
|
|
34
|
+
owner.extend MetaClassMethods
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Sortable columns configuration object. Passed to the block when you do a:
|
|
38
|
+
#
|
|
39
|
+
# handles_sortable_columns do |conf|
|
|
40
|
+
# ...
|
|
41
|
+
# end
|
|
42
|
+
class Config
|
|
43
|
+
# CSS class for link (regardless of sorted state). Default:
|
|
44
|
+
#
|
|
45
|
+
# SortableColumnLink
|
|
46
|
+
attr_accessor :link_class
|
|
47
|
+
|
|
48
|
+
# GET parameter name for page number. Default:
|
|
49
|
+
#
|
|
50
|
+
# page
|
|
51
|
+
attr_accessor :page_param
|
|
52
|
+
|
|
53
|
+
# GET parameter name for sort column and direction. Default:
|
|
54
|
+
#
|
|
55
|
+
# sort
|
|
56
|
+
attr_accessor :sort_param
|
|
57
|
+
|
|
58
|
+
# Default sort direction, if params[sort_param] is not given.
|
|
59
|
+
#
|
|
60
|
+
# default_sort_value
|
|
61
|
+
attr_accessor :default_sort_value
|
|
62
|
+
|
|
63
|
+
# Sort indicator text. If any of values are empty, indicator is not displayed. Default:
|
|
64
|
+
#
|
|
65
|
+
# {:asc => " ↓ ", :desc => " ↑ "}
|
|
66
|
+
attr_accessor :indicator_text
|
|
67
|
+
|
|
68
|
+
# Sort indicator class. Default:
|
|
69
|
+
#
|
|
70
|
+
# {:asc => "SortedAsc", :desc => "SortedDesc"}
|
|
71
|
+
attr_accessor :indicator_class
|
|
72
|
+
|
|
73
|
+
def initialize(attrs = {})
|
|
74
|
+
defaults = {
|
|
75
|
+
:link_class => "SortableColumnLink",
|
|
76
|
+
:indicator_class => {:asc => "SortedAsc", :desc => "SortedDesc"},
|
|
77
|
+
:indicator_text => {:asc => " ↓ ", :desc => " ↑ "},
|
|
78
|
+
:page_param => "page",
|
|
79
|
+
:sort_param => "sort",
|
|
80
|
+
:default_sort_value => nil
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
defaults.merge(attrs).each {|k, v| send("#{k}=", v)}
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Bracket access for convenience.
|
|
87
|
+
def [](key)
|
|
88
|
+
send(key)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Bracket access for convenience.
|
|
92
|
+
def []=(key, value)
|
|
93
|
+
send("#{key}=", value)
|
|
94
|
+
end
|
|
95
|
+
end # Config
|
|
96
|
+
|
|
97
|
+
module MetaClassMethods
|
|
98
|
+
# Activate and optionally configure the sortable columns feature in your controller.
|
|
99
|
+
#
|
|
100
|
+
# class MyController < ApplicationController
|
|
101
|
+
# handles_sortable_columns
|
|
102
|
+
# ...
|
|
103
|
+
#
|
|
104
|
+
# With configuration:
|
|
105
|
+
#
|
|
106
|
+
# class MyController < ApplicationController
|
|
107
|
+
# handles_sortable_columns do |conf|
|
|
108
|
+
# conf.sort_param = "s"
|
|
109
|
+
# conf.page_param = "p"
|
|
110
|
+
# conf.indicator_text = {}
|
|
111
|
+
# ...
|
|
112
|
+
# end
|
|
113
|
+
# ...
|
|
114
|
+
#
|
|
115
|
+
# With filter options:
|
|
116
|
+
#
|
|
117
|
+
# class MyController < ApplicationController
|
|
118
|
+
# handles_sortable_columns(:only => [:index]) do |conf|
|
|
119
|
+
# ...
|
|
120
|
+
# end
|
|
121
|
+
# ...
|
|
122
|
+
#
|
|
123
|
+
# NOTE: <tt>conf</tt> is a Config object.
|
|
124
|
+
def handles_sortable_columns(fopts = {}, &block)
|
|
125
|
+
# Multiple activation protection.
|
|
126
|
+
if not self < InstanceMethods
|
|
127
|
+
include InstanceMethods
|
|
128
|
+
helper_method :sortable_column
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Process configuration at every activation.
|
|
132
|
+
before_filter(fopts) do |ac|
|
|
133
|
+
ac.instance_eval do
|
|
134
|
+
# NOTE: Can't `yield`, we're in a block already.
|
|
135
|
+
block.call(sortable_columns_config) if block
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end # MetaClassMethods
|
|
140
|
+
|
|
141
|
+
module InstanceMethods
|
|
142
|
+
private
|
|
143
|
+
|
|
144
|
+
# Internal/advanced use only. Parse sortable column sort param into a Hash with predefined keys.
|
|
145
|
+
#
|
|
146
|
+
# parse_sortable_column_sort_param("name") # => {:column => "name", :direction => :asc}
|
|
147
|
+
# parse_sortable_column_sort_param("-name") # => {:column => "name", :direction => :desc}
|
|
148
|
+
# parse_sortable_column_sort_param("") # => {:column => nil, :direction => nil}
|
|
149
|
+
def parse_sortable_column_sort_param(sort) #:nodoc:
|
|
150
|
+
out = {:column => nil, :direction => nil}
|
|
151
|
+
if sort.to_s.strip.match /\A((?:-|))([^-]+)\z/
|
|
152
|
+
out[:direction] = $1.empty?? :asc : :desc
|
|
153
|
+
out[:column] = $2.strip
|
|
154
|
+
end
|
|
155
|
+
out
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Render a sortable column link.
|
|
159
|
+
#
|
|
160
|
+
# Options:
|
|
161
|
+
#
|
|
162
|
+
# * <tt>:column</tt> -- Column name. E.g. <tt>created_at</tt>.
|
|
163
|
+
# * <tt>:direction</tt> -- Sort direction on first click. <tt>:asc</tt> or <tt>:desc</tt>. Default is <tt>:asc</tt>.
|
|
164
|
+
# * <tt>:link_class</tt> -- CSS class for link, regardless of sorted state.
|
|
165
|
+
# * <tt>:link_style</tt> -- CSS style for link, regardless of sorted state.
|
|
166
|
+
#
|
|
167
|
+
# Examples:
|
|
168
|
+
#
|
|
169
|
+
# <%= sortable_column "Product" %>
|
|
170
|
+
# <%= sortable_column "Highest Price", :column => "max_price" %>
|
|
171
|
+
# <%= sortable_column "Name", :link_class => "SortableLink" %>
|
|
172
|
+
# <%= sortable_column "Created At", :direction => :asc %>
|
|
173
|
+
def sortable_column(title, options = {}) #:doc:
|
|
174
|
+
options = options.dup
|
|
175
|
+
o = {}
|
|
176
|
+
conf = {}
|
|
177
|
+
conf[k = :sort_param] = sortable_columns_config[k]
|
|
178
|
+
conf[k = :default_sort_value] = sortable_columns_config[k]
|
|
179
|
+
conf[k = :page_param] = sortable_columns_config[k]
|
|
180
|
+
conf[k = :indicator_text] = sortable_columns_config[k]
|
|
181
|
+
conf[k = :indicator_class] = sortable_columns_config[k]
|
|
182
|
+
|
|
183
|
+
#HELP sortable_column
|
|
184
|
+
o[k = :column] = options.delete(k) || sortable_column_title_to_name(title)
|
|
185
|
+
o[k = :direction] = options.delete(k).to_s.downcase =~ /\Adesc\z/ ? :desc : :asc
|
|
186
|
+
o[k = :link_class] = options.delete(k) || sortable_columns_config[k]
|
|
187
|
+
o[k = :link_style] = options.delete(k)
|
|
188
|
+
o[k = :link_style] = options.delete(k)
|
|
189
|
+
o[k = :route_proxy] = options.delete(k)
|
|
190
|
+
#HELP /sortable_column
|
|
191
|
+
|
|
192
|
+
raise "Unknown option(s): #{options.inspect}" if not options.empty?
|
|
193
|
+
|
|
194
|
+
# Parse sort param.
|
|
195
|
+
sort = params[conf[:sort_param]] || conf[:default_sort_value]
|
|
196
|
+
pp = parse_sortable_column_sort_param(sort)
|
|
197
|
+
|
|
198
|
+
css_class = []
|
|
199
|
+
if (s = o[:link_class]).present?
|
|
200
|
+
css_class << s
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# If already sorted and indicator class defined, append it.
|
|
204
|
+
if pp[:column] == o[:column].to_s and (s = conf[:indicator_class][pp[:direction]]).present?
|
|
205
|
+
css_class << s
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Build link itself.
|
|
209
|
+
pcs = []
|
|
210
|
+
|
|
211
|
+
html_options = {}
|
|
212
|
+
html_options[:class] = css_class.join(" ") if css_class.present?
|
|
213
|
+
html_options[:style] = o[:link_style] if o[:link_style].present?
|
|
214
|
+
|
|
215
|
+
# Rails 3 / Rails 2 fork.
|
|
216
|
+
tpl = respond_to?(:view_context) ? view_context : @template
|
|
217
|
+
|
|
218
|
+
# Already sorted?
|
|
219
|
+
if pp[:column] == o[:column].to_s
|
|
220
|
+
if o[:route_proxy]
|
|
221
|
+
url = o[:route_proxy].send(:url_for, params.merge({conf[:sort_param] => [("-" if pp[:direction] == :asc), o[:column]].join, conf[:page_param] => 1}))
|
|
222
|
+
else
|
|
223
|
+
url = url_for(params.merge({conf[:sort_param] => [("-" if pp[:direction] == :asc), o[:column]].join, conf[:page_param] => 1}))
|
|
224
|
+
end
|
|
225
|
+
pcs << tpl.link_to(title, url, html_options) # Opposite sort order when clicked.
|
|
226
|
+
|
|
227
|
+
# Append indicator, if configured.
|
|
228
|
+
if (s = conf[:indicator_text][pp[:direction]]).present?
|
|
229
|
+
pcs << s
|
|
230
|
+
end
|
|
231
|
+
else
|
|
232
|
+
# Not sorted.
|
|
233
|
+
if o[:route_proxy]
|
|
234
|
+
url = o[:route_proxy].send(:url_for, params.merge({conf[:sort_param] => [("-" if o[:direction] != :asc), o[:column]].join, conf[:page_param] => 1}))
|
|
235
|
+
else
|
|
236
|
+
url = url_for(params.merge({conf[:sort_param] => [("-" if o[:direction] != :asc), o[:column]].join, conf[:page_param] => 1}))
|
|
237
|
+
end
|
|
238
|
+
pcs << tpl.link_to(title, url, html_options)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# For Rails 3 provide #html_safe.
|
|
242
|
+
(v = pcs.join).respond_to?(:html_safe) ? v.html_safe : v
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Compile SQL order clause according to current state of sortable columns.
|
|
246
|
+
#
|
|
247
|
+
# Basic (kickstart) usage:
|
|
248
|
+
#
|
|
249
|
+
# order = sortable_column_order
|
|
250
|
+
#
|
|
251
|
+
# <b>WARNING:</b> Basic usage is <b>not recommended</b> for production since it is potentially
|
|
252
|
+
# vulnerable to SQL injection!
|
|
253
|
+
#
|
|
254
|
+
# Production usage with multiple sort criteria, column name validation and defaults:
|
|
255
|
+
#
|
|
256
|
+
# order = sortable_column_order do |column, direction|
|
|
257
|
+
# case column
|
|
258
|
+
# when "name"
|
|
259
|
+
# "#{column} #{direction}"
|
|
260
|
+
# when "created_at", "updated_at"
|
|
261
|
+
# "#{column} #{direction}, name ASC"
|
|
262
|
+
# else
|
|
263
|
+
# "name ASC"
|
|
264
|
+
# end
|
|
265
|
+
# end
|
|
266
|
+
#
|
|
267
|
+
# Apply order:
|
|
268
|
+
#
|
|
269
|
+
# @records = Article.order(order) # Rails 3.
|
|
270
|
+
# @records = Article.all(:order => order) # Rails 2.
|
|
271
|
+
def sortable_column_order(&block)
|
|
272
|
+
conf = {}
|
|
273
|
+
conf[k = :sort_param] = sortable_columns_config[k]
|
|
274
|
+
conf[k = :default_sort_value] = sortable_columns_config[k]
|
|
275
|
+
|
|
276
|
+
# Parse sort param.
|
|
277
|
+
sort = params[conf[:sort_param]] || conf[:default_sort_value]
|
|
278
|
+
pp = parse_sortable_column_sort_param(sort)
|
|
279
|
+
|
|
280
|
+
order = if block
|
|
281
|
+
column, direction = pp[:column], pp[:direction]
|
|
282
|
+
yield(column, direction) # NOTE: Makes RDoc/ri look a little smarter.
|
|
283
|
+
else
|
|
284
|
+
# No block -- do a straight mapping.
|
|
285
|
+
if pp[:column]
|
|
286
|
+
[pp[:column], pp[:direction]].join(" ")
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Can be nil.
|
|
291
|
+
order
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Internal use only. Convert title to sortable column name.
|
|
295
|
+
#
|
|
296
|
+
# sortable_column_title_to_name("ProductName") # => "product_name"
|
|
297
|
+
def sortable_column_title_to_name(title) #:nodoc:
|
|
298
|
+
title.gsub(/(\s)(\S)/) {$2.upcase}.underscore
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Internal use only. Access/initialize feature's config.
|
|
302
|
+
def sortable_columns_config #:nodoc:
|
|
303
|
+
@sortable_columns_config ||= ::Handles::SortableColumns::Config.new
|
|
304
|
+
end
|
|
305
|
+
end # InstanceMethods
|
|
306
|
+
end # SortableColumns
|
|
307
|
+
end # Handles
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = "tvdeyen-handles_sortable_columns"
|
|
5
|
+
s.version = "0.1.5"
|
|
6
|
+
s.authors = ["Alex Fortuna", "Thomas von Deyen"]
|
|
7
|
+
s.summary = "Sortable Table Columns"
|
|
8
|
+
s.description = "Sortable Table Columns"
|
|
9
|
+
s.license = "MIT"
|
|
10
|
+
s.email = "tvdeyen@gmail.com"
|
|
11
|
+
s.extra_rdoc_files = [
|
|
12
|
+
"README.html",
|
|
13
|
+
"README.md"
|
|
14
|
+
]
|
|
15
|
+
s.files = `git ls-files`.split("\n")
|
|
16
|
+
s.homepage = "https://github.com/tvdeyen/handles_sortable_columns"
|
|
17
|
+
s.require_paths = ["lib"]
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tvdeyen-handles_sortable_columns
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.5
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Alex Fortuna
|
|
8
|
+
- Thomas von Deyen
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-03-27 00:00:00.000000000 Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: Sortable Table Columns
|
|
15
|
+
email: tvdeyen@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files:
|
|
19
|
+
- README.html
|
|
20
|
+
- README.md
|
|
21
|
+
files:
|
|
22
|
+
- .gitignore
|
|
23
|
+
- MIT-LICENSE
|
|
24
|
+
- README.html
|
|
25
|
+
- README.md
|
|
26
|
+
- Rakefile
|
|
27
|
+
- VERSION.yml
|
|
28
|
+
- dev/github.css
|
|
29
|
+
- dev/head.html
|
|
30
|
+
- init.rb
|
|
31
|
+
- lib/action_controller/base/handles_sortable_columns.rb
|
|
32
|
+
- lib/handles/sortable_columns.rb
|
|
33
|
+
- lib/handles_sortable_columns.rb
|
|
34
|
+
- tvdeyen-handles_sortable_columns.gemspec
|
|
35
|
+
homepage: https://github.com/tvdeyen/handles_sortable_columns
|
|
36
|
+
licenses:
|
|
37
|
+
- MIT
|
|
38
|
+
metadata: {}
|
|
39
|
+
post_install_message:
|
|
40
|
+
rdoc_options: []
|
|
41
|
+
require_paths:
|
|
42
|
+
- lib
|
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ! '>='
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ! '>='
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0'
|
|
53
|
+
requirements: []
|
|
54
|
+
rubyforge_project:
|
|
55
|
+
rubygems_version: 2.0.3
|
|
56
|
+
signing_key:
|
|
57
|
+
specification_version: 4
|
|
58
|
+
summary: Sortable Table Columns
|
|
59
|
+
test_files: []
|
|
60
|
+
has_rdoc:
|