handles_sortable_columns 0.1.2 → 0.1.3
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 +1 -1
- data/README.html +140 -0
- data/README.md +26 -7
- data/Rakefile +17 -8
- data/VERSION.yml +2 -1
- data/handles_sortable_columns.gemspec +16 -18
- data/lib/action_controller/base/handles_sortable_columns.rb +4 -2
- data/lib/handles/sortable_columns.rb +123 -108
- metadata +10 -20
- data/spec/handles_sortable_columns_spec.rb +0 -42
data/MIT-LICENSE
CHANGED
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
CHANGED
@@ -9,16 +9,34 @@ Introduction
|
|
9
9
|
A simple yet flexible Rails gem/plugin to quickly add sortable table columns to your controller and views.
|
10
10
|
|
11
11
|
|
12
|
-
Setup
|
13
|
-
|
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:
|
14
20
|
|
15
|
-
$ gem sources --add http://rubygems.org
|
16
21
|
$ gem install handles_sortable_columns
|
17
22
|
|
18
|
-
|
23
|
+
Otherwise, do a `bundle install`.
|
24
|
+
|
25
|
+
|
26
|
+
Setup (Rails 2)
|
27
|
+
---------------
|
28
|
+
|
29
|
+
In your app's `config/environment.rb` add:
|
19
30
|
|
20
31
|
config.gem "handles_sortable_columns"
|
21
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
|
+
|
22
40
|
|
23
41
|
Basic Usage
|
24
42
|
-----------
|
@@ -27,7 +45,7 @@ Activate the feature in your controller class:
|
|
27
45
|
|
28
46
|
class MyController < ApplicationController
|
29
47
|
handles_sortable_columns
|
30
|
-
|
48
|
+
...
|
31
49
|
|
32
50
|
In a view, mark up sortable columns by using the <tt>sortable_column</tt> helper:
|
33
51
|
|
@@ -38,7 +56,8 @@ In controller action, fetch and use the order clause according to current state
|
|
38
56
|
|
39
57
|
def index
|
40
58
|
order = sortable_column_order
|
41
|
-
@records = Article.
|
59
|
+
@records = Article.order(order) # Rails 3.
|
60
|
+
@records = Article.all(:order => order) # Rails 2.
|
42
61
|
end
|
43
62
|
|
44
63
|
That's it for basic usage. Production usage may require passing additional parameters to listed methods.
|
@@ -59,7 +78,7 @@ Change names of GET parameters used for sorting and pagination:
|
|
59
78
|
conf.sort_param = "s"
|
60
79
|
conf.page_param = "p"
|
61
80
|
end
|
62
|
-
|
81
|
+
...
|
63
82
|
|
64
83
|
Change CSS class of all sortable column `<a>` tags:
|
65
84
|
|
data/Rakefile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "rake/rdoctask"
|
2
|
+
require "yaml"
|
2
3
|
|
3
4
|
GEM_NAME = "handles_sortable_columns"
|
4
5
|
|
@@ -14,10 +15,9 @@ begin
|
|
14
15
|
gem.files = FileList[
|
15
16
|
"[A-Z]*",
|
16
17
|
"*.gemspec",
|
17
|
-
"lib/**/*.rb",
|
18
18
|
"init.rb",
|
19
|
-
|
20
|
-
|
19
|
+
"lib/**/*.rb",
|
20
|
+
]
|
21
21
|
end
|
22
22
|
rescue LoadError
|
23
23
|
STDERR.puts "This gem requires Jeweler to be built"
|
@@ -28,11 +28,20 @@ task :rebuild => [:gemspec, :build]
|
|
28
28
|
|
29
29
|
desc "Push (publish) gem to RubyGems (aka Gemcutter)"
|
30
30
|
task :push => :rebuild do
|
31
|
-
# Yet found no way to ask Jeweler forge a complete version string for us.
|
32
|
-
|
33
|
-
version = [
|
34
|
-
pkgfile = File.join("pkg",
|
35
|
-
system("gem", "push", pkgfile)
|
31
|
+
# NOTE: Yet found no way to ask Jeweler forge a complete version string for us.
|
32
|
+
h = YAML.load_file("VERSION.yml")
|
33
|
+
version = [h[:major], h[:minor], h[:patch], h[:build]].compact.join(".")
|
34
|
+
pkgfile = File.join("pkg", "#{GEM_NAME}-#{version}.gem")
|
35
|
+
Kernel.system("gem", "push", pkgfile)
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Generate RDoc documentation"
|
39
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
40
|
+
rdoc.rdoc_dir = "doc"
|
41
|
+
rdoc.title = "Handles::SortableColumns"
|
42
|
+
#rdoc.options << "--line-numbers"
|
43
|
+
#rdoc.options << "--inline-source"
|
44
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
36
45
|
end
|
37
46
|
|
38
47
|
desc "Compile README preview"
|
data/VERSION.yml
CHANGED
@@ -1,42 +1,39 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{handles_sortable_columns}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Alex Fortuna"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-07-29}
|
13
13
|
s.description = %q{Sortable Table Columns}
|
14
14
|
s.email = %q{alex.r@askit.org}
|
15
15
|
s.extra_rdoc_files = [
|
16
|
+
"README.html",
|
16
17
|
"README.md"
|
17
18
|
]
|
18
19
|
s.files = [
|
19
20
|
"MIT-LICENSE",
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
"README.html",
|
22
|
+
"README.md",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION.yml",
|
25
|
+
"handles_sortable_columns.gemspec",
|
26
|
+
"init.rb",
|
27
|
+
"lib/action_controller/base/handles_sortable_columns.rb",
|
28
|
+
"lib/handles/sortable_columns.rb",
|
29
|
+
"lib/handles_sortable_columns.rb"
|
28
30
|
]
|
29
31
|
s.homepage = %q{http://github.com/dadooda/handles_sortable_columns}
|
30
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
31
32
|
s.require_paths = ["lib"]
|
32
|
-
s.rubygems_version = %q{1.
|
33
|
+
s.rubygems_version = %q{1.6.2}
|
33
34
|
s.summary = %q{Sortable Table Columns}
|
34
|
-
s.test_files = [
|
35
|
-
"spec/handles_sortable_columns_spec.rb"
|
36
|
-
]
|
37
35
|
|
38
36
|
if s.respond_to? :specification_version then
|
39
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
40
37
|
s.specification_version = 3
|
41
38
|
|
42
39
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
@@ -45,3 +42,4 @@ Gem::Specification.new do |s|
|
|
45
42
|
else
|
46
43
|
end
|
47
44
|
end
|
45
|
+
|
@@ -9,7 +9,7 @@ module Handles #:nodoc:
|
|
9
9
|
#
|
10
10
|
# class MyController < ApplicationController
|
11
11
|
# handles_sortable_columns
|
12
|
-
#
|
12
|
+
# ...
|
13
13
|
#
|
14
14
|
# In a view, mark up sortable columns by using the <tt>sortable_column</tt> helper:
|
15
15
|
#
|
@@ -20,30 +20,30 @@ module Handles #:nodoc:
|
|
20
20
|
#
|
21
21
|
# def index
|
22
22
|
# order = sortable_column_order
|
23
|
-
# @records = Article.
|
23
|
+
# @records = Article.order(order) # Rails 3.
|
24
|
+
# @records = Article.all(:order => order) # Rails 2.
|
24
25
|
# end
|
25
26
|
#
|
26
27
|
# That's it for basic usage. Production usage may require passing additional parameters to listed methods.
|
27
28
|
#
|
28
29
|
# See also:
|
29
|
-
# *
|
30
|
-
# *
|
31
|
-
# * <tt>InstanceMethods#sortable_column_order</tt>
|
30
|
+
# * MetaClassMethods#handles_sortable_columns
|
31
|
+
# * InstanceMethods#sortable_column_order
|
32
32
|
module SortableColumns
|
33
|
-
def self.included(owner)
|
33
|
+
def self.included(owner) #:nodoc:
|
34
34
|
owner.extend MetaClassMethods
|
35
35
|
end
|
36
36
|
|
37
|
-
# Sortable columns configuration object. Passed to block when you do a:
|
37
|
+
# Sortable columns configuration object. Passed to the block when you do a:
|
38
38
|
#
|
39
|
-
#
|
39
|
+
# handles_sortable_columns do |conf|
|
40
40
|
# ...
|
41
41
|
# end
|
42
42
|
class Config
|
43
43
|
# CSS class for link (regardless of sorted state). Default:
|
44
44
|
#
|
45
|
-
#
|
46
|
-
attr_accessor :
|
45
|
+
# SortableColumnLink
|
46
|
+
attr_accessor :link_class
|
47
47
|
|
48
48
|
# GET parameter name for page number. Default:
|
49
49
|
#
|
@@ -67,30 +67,33 @@ module Handles #:nodoc:
|
|
67
67
|
|
68
68
|
def initialize(attrs = {})
|
69
69
|
defaults = {
|
70
|
-
:
|
71
|
-
:
|
72
|
-
:indicator_text
|
73
|
-
:
|
70
|
+
:link_class => "SortableColumnLink",
|
71
|
+
:indicator_class => {:asc => "SortedAsc", :desc => "SortedDesc"},
|
72
|
+
:indicator_text => {:asc => " ↓ ", :desc => " ↑ "},
|
73
|
+
:page_param => "page",
|
74
|
+
:sort_param => "sort",
|
74
75
|
}
|
75
76
|
|
76
77
|
defaults.merge(attrs).each {|k, v| send("#{k}=", v)}
|
77
78
|
end
|
78
79
|
|
80
|
+
# Bracket access for convenience.
|
79
81
|
def [](key)
|
80
82
|
send(key)
|
81
83
|
end
|
82
84
|
|
85
|
+
# Bracket access for convenience.
|
83
86
|
def []=(key, value)
|
84
87
|
send("#{key}=", value)
|
85
88
|
end
|
86
89
|
end # Config
|
87
90
|
|
88
91
|
module MetaClassMethods
|
89
|
-
# Activate and optionally configure the sortable columns.
|
92
|
+
# Activate and optionally configure the sortable columns feature in your controller.
|
90
93
|
#
|
91
94
|
# class MyController < ApplicationController
|
92
95
|
# handles_sortable_columns
|
93
|
-
#
|
96
|
+
# ...
|
94
97
|
#
|
95
98
|
# With configuration:
|
96
99
|
#
|
@@ -101,42 +104,43 @@ module Handles #:nodoc:
|
|
101
104
|
# conf.indicator_text = {}
|
102
105
|
# ...
|
103
106
|
# end
|
104
|
-
#
|
107
|
+
# ...
|
108
|
+
#
|
109
|
+
# With filter options:
|
110
|
+
#
|
111
|
+
# class MyController < ApplicationController
|
112
|
+
# handles_sortable_columns(:only => [:index]) do |conf|
|
113
|
+
# ...
|
114
|
+
# end
|
115
|
+
# ...
|
105
116
|
#
|
106
|
-
# <tt>conf</tt> is a
|
107
|
-
def handles_sortable_columns(&block)
|
117
|
+
# NOTE: <tt>conf</tt> is a Config object.
|
118
|
+
def handles_sortable_columns(fopts = {}, &block)
|
108
119
|
# Multiple activation protection.
|
109
120
|
if not self < InstanceMethods
|
110
|
-
extend ClassMethods
|
111
121
|
include InstanceMethods
|
112
|
-
|
122
|
+
helper_method :sortable_column
|
113
123
|
end
|
114
124
|
|
115
|
-
#
|
116
|
-
|
125
|
+
# Process configuration at every activation.
|
126
|
+
before_filter(fopts) do |ac|
|
127
|
+
ac.instance_eval do
|
128
|
+
# NOTE: Can't `yield`, we're in a block already.
|
129
|
+
block.call(sortable_columns_config) if block
|
130
|
+
end
|
131
|
+
end
|
117
132
|
end
|
118
133
|
end # MetaClassMethods
|
119
134
|
|
120
|
-
module
|
121
|
-
|
122
|
-
def sortable_columns_config
|
123
|
-
# NOTE: This is controller's class instance variable.
|
124
|
-
@sortable_columns_config ||= ::Handles::SortableColumns::Config.new
|
125
|
-
end
|
126
|
-
|
127
|
-
# Internal/advanced use only. Convert title to sortable column name.
|
128
|
-
#
|
129
|
-
# sortable_column_name_from_title("ProductName") # => "product_name"
|
130
|
-
def sortable_column_name_from_title(title)
|
131
|
-
title.gsub(/(\s)(\S)/) {$2.upcase}.underscore
|
132
|
-
end
|
135
|
+
module InstanceMethods
|
136
|
+
private
|
133
137
|
|
134
138
|
# Internal/advanced use only. Parse sortable column sort param into a Hash with predefined keys.
|
135
139
|
#
|
136
140
|
# parse_sortable_column_sort_param("name") # => {:column => "name", :direction => :asc}
|
137
141
|
# parse_sortable_column_sort_param("-name") # => {:column => "name", :direction => :desc}
|
138
142
|
# parse_sortable_column_sort_param("") # => {:column => nil, :direction => nil}
|
139
|
-
def parse_sortable_column_sort_param(sort)
|
143
|
+
def parse_sortable_column_sort_param(sort) #:nodoc:
|
140
144
|
out = {:column => nil, :direction => nil}
|
141
145
|
if sort.to_s.strip.match /\A((?:-|))([^-]+)\z/
|
142
146
|
out[:direction] = $1.empty?? :asc : :desc
|
@@ -144,96 +148,45 @@ module Handles #:nodoc:
|
|
144
148
|
end
|
145
149
|
out
|
146
150
|
end
|
147
|
-
end # ClassMethods
|
148
|
-
|
149
|
-
module InstanceMethods
|
150
|
-
protected
|
151
|
-
|
152
|
-
# Compile SQL order clause according to current state of sortable columns.
|
153
|
-
#
|
154
|
-
# Basic (kickstart) usage:
|
155
|
-
#
|
156
|
-
# order = sortable_column_order
|
157
|
-
#
|
158
|
-
# <b>WARNING!</b> Basic usage is <b>not recommended</b> for production since it is potentially
|
159
|
-
# vulnerable to SQL injection!
|
160
|
-
#
|
161
|
-
# Production usage with multiple sort criteria, column name validation and defaults:
|
162
|
-
#
|
163
|
-
# order = sortable_column_order do |column, direction|
|
164
|
-
# case column
|
165
|
-
# when "name"
|
166
|
-
# "#{column} #{direction}"
|
167
|
-
# when "created_at", "updated_at"
|
168
|
-
# "#{column} #{direction}, name ASC"
|
169
|
-
# else
|
170
|
-
# "name ASC"
|
171
|
-
# end
|
172
|
-
# end
|
173
|
-
#
|
174
|
-
# Apply order:
|
175
|
-
#
|
176
|
-
# @records = Article.all(:order => order) # Rails 2.x.
|
177
|
-
# @records = Article.order(order) # Rails 3.
|
178
|
-
def sortable_column_order(&block)
|
179
|
-
conf = {}
|
180
|
-
conf[k = :sort_param] = self.class.sortable_columns_config[k]
|
181
|
-
|
182
|
-
# Parse sort param.
|
183
|
-
pp = self.class.parse_sortable_column_sort_param(params[conf[:sort_param]])
|
184
|
-
|
185
|
-
order = if block
|
186
|
-
yield(pp[:column], pp[:direction])
|
187
|
-
else
|
188
|
-
# No block -- do a straight mapping.
|
189
|
-
if pp[:column]
|
190
|
-
[pp[:column], pp[:direction]].join(" ")
|
191
|
-
end
|
192
|
-
end
|
193
151
|
|
194
|
-
# Can be nil.
|
195
|
-
order
|
196
|
-
end
|
197
|
-
end # InstanceMethods
|
198
|
-
|
199
|
-
module HelperMethods
|
200
152
|
# Render a sortable column link.
|
201
153
|
#
|
202
154
|
# Options:
|
203
|
-
#
|
155
|
+
#
|
156
|
+
# * <tt>:column</tt> -- Column name. E.g. <tt>created_at</tt>.
|
204
157
|
# * <tt>:direction</tt> -- Sort direction on first click. <tt>:asc</tt> or <tt>:desc</tt>. Default is <tt>:asc</tt>.
|
205
|
-
# * <tt>:
|
206
|
-
# * <tt>:
|
158
|
+
# * <tt>:link_class</tt> -- CSS class for link, regardless of sorted state.
|
159
|
+
# * <tt>:link_style</tt> -- CSS style for link, regardless of sorted state.
|
207
160
|
#
|
208
161
|
# Examples:
|
209
162
|
#
|
210
163
|
# <%= sortable_column "Product" %>
|
211
|
-
# <%= sortable_column "Highest Price", :
|
212
|
-
# <%= sortable_column "Name", :
|
164
|
+
# <%= sortable_column "Highest Price", :column => "max_price" %>
|
165
|
+
# <%= sortable_column "Name", :link_class => "SortableLink" %>
|
213
166
|
# <%= sortable_column "Created At", :direction => :asc %>
|
214
|
-
def sortable_column(title, options = {})
|
167
|
+
def sortable_column(title, options = {}) #:doc:
|
215
168
|
options = options.dup
|
216
169
|
o = {}
|
217
170
|
conf = {}
|
218
|
-
conf[k = :sort_param] =
|
219
|
-
conf[k = :page_param] =
|
220
|
-
conf[k = :indicator_text] =
|
221
|
-
conf[k = :indicator_class] =
|
171
|
+
conf[k = :sort_param] = sortable_columns_config[k]
|
172
|
+
conf[k = :page_param] = sortable_columns_config[k]
|
173
|
+
conf[k = :indicator_text] = sortable_columns_config[k]
|
174
|
+
conf[k = :indicator_class] = sortable_columns_config[k]
|
222
175
|
|
223
176
|
#HELP sortable_column
|
224
|
-
o[k = :column] = options.delete(k) ||
|
177
|
+
o[k = :column] = options.delete(k) || sortable_column_title_to_name(title)
|
225
178
|
o[k = :direction] = options.delete(k).to_s.downcase =~ /\Adesc\z/ ? :desc : :asc
|
226
|
-
o[k = :
|
227
|
-
o[k = :
|
179
|
+
o[k = :link_class] = options.delete(k) || sortable_columns_config[k]
|
180
|
+
o[k = :link_style] = options.delete(k)
|
228
181
|
#HELP /sortable_column
|
229
182
|
|
230
183
|
raise "Unknown option(s): #{options.inspect}" if not options.empty?
|
231
184
|
|
232
185
|
# Parse sort param.
|
233
|
-
pp =
|
186
|
+
pp = parse_sortable_column_sort_param(params[conf[:sort_param]])
|
234
187
|
|
235
188
|
css_class = []
|
236
|
-
if (s = o[:
|
189
|
+
if (s = o[:link_class]).present?
|
237
190
|
css_class << s
|
238
191
|
end
|
239
192
|
|
@@ -247,11 +200,14 @@ module Handles #:nodoc:
|
|
247
200
|
|
248
201
|
html_options = {}
|
249
202
|
html_options[:class] = css_class.join(" ") if css_class.present?
|
250
|
-
html_options[:style] = o[:
|
203
|
+
html_options[:style] = o[:link_style] if o[:link_style].present?
|
204
|
+
|
205
|
+
# Rails 3 / Rails 2 fork.
|
206
|
+
tpl = respond_to?(:view_context) ? view_context : @template
|
251
207
|
|
252
208
|
# Already sorted?
|
253
209
|
if pp[:column] == o[:column].to_s
|
254
|
-
pcs << link_to(title, params.merge({conf[:sort_param] => [("-" if pp[:direction] == :asc), o[:column]].join, conf[:page_param] => 1}), html_options) # Opposite sort order when clicked.
|
210
|
+
pcs << tpl.link_to(title, params.merge({conf[:sort_param] => [("-" if pp[:direction] == :asc), o[:column]].join, conf[:page_param] => 1}), html_options) # Opposite sort order when clicked.
|
255
211
|
|
256
212
|
# Append indicator, if configured.
|
257
213
|
if (s = conf[:indicator_text][pp[:direction]]).present?
|
@@ -259,12 +215,71 @@ module Handles #:nodoc:
|
|
259
215
|
end
|
260
216
|
else
|
261
217
|
# Not sorted.
|
262
|
-
pcs << link_to(title, params.merge({conf[:sort_param] => [("-" if o[:direction] != :asc), o[:column]].join, conf[:page_param] => 1}), html_options)
|
218
|
+
pcs << tpl.link_to(title, params.merge({conf[:sort_param] => [("-" if o[:direction] != :asc), o[:column]].join, conf[:page_param] => 1}), html_options)
|
263
219
|
end
|
264
220
|
|
265
221
|
# For Rails 3 provide #html_safe.
|
266
222
|
(v = pcs.join).respond_to?(:html_safe) ? v.html_safe : v
|
267
223
|
end
|
268
|
-
|
224
|
+
|
225
|
+
# Compile SQL order clause according to current state of sortable columns.
|
226
|
+
#
|
227
|
+
# Basic (kickstart) usage:
|
228
|
+
#
|
229
|
+
# order = sortable_column_order
|
230
|
+
#
|
231
|
+
# <b>WARNING:</b> Basic usage is <b>not recommended</b> for production since it is potentially
|
232
|
+
# vulnerable to SQL injection!
|
233
|
+
#
|
234
|
+
# Production usage with multiple sort criteria, column name validation and defaults:
|
235
|
+
#
|
236
|
+
# order = sortable_column_order do |column, direction|
|
237
|
+
# case column
|
238
|
+
# when "name"
|
239
|
+
# "#{column} #{direction}"
|
240
|
+
# when "created_at", "updated_at"
|
241
|
+
# "#{column} #{direction}, name ASC"
|
242
|
+
# else
|
243
|
+
# "name ASC"
|
244
|
+
# end
|
245
|
+
# end
|
246
|
+
#
|
247
|
+
# Apply order:
|
248
|
+
#
|
249
|
+
# @records = Article.order(order) # Rails 3.
|
250
|
+
# @records = Article.all(:order => order) # Rails 2.
|
251
|
+
def sortable_column_order(&block)
|
252
|
+
conf = {}
|
253
|
+
conf[k = :sort_param] = sortable_columns_config[k]
|
254
|
+
|
255
|
+
# Parse sort param.
|
256
|
+
pp = parse_sortable_column_sort_param(params[conf[:sort_param]])
|
257
|
+
|
258
|
+
order = if block
|
259
|
+
column, direction = pp[:column], pp[:direction]
|
260
|
+
yield(column, direction) # NOTE: Makes RDoc/ri look a little smarter.
|
261
|
+
else
|
262
|
+
# No block -- do a straight mapping.
|
263
|
+
if pp[:column]
|
264
|
+
[pp[:column], pp[:direction]].join(" ")
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# Can be nil.
|
269
|
+
order
|
270
|
+
end
|
271
|
+
|
272
|
+
# Internal use only. Convert title to sortable column name.
|
273
|
+
#
|
274
|
+
# sortable_column_title_to_name("ProductName") # => "product_name"
|
275
|
+
def sortable_column_title_to_name(title) #:nodoc:
|
276
|
+
title.gsub(/(\s)(\S)/) {$2.upcase}.underscore
|
277
|
+
end
|
278
|
+
|
279
|
+
# Internal use only. Access/initialize feature's config.
|
280
|
+
def sortable_columns_config #:nodoc:
|
281
|
+
@sortable_columns_config ||= ::Handles::SortableColumns::Config.new
|
282
|
+
end
|
283
|
+
end # InstanceMethods
|
269
284
|
end # SortableColumns
|
270
285
|
end # Handles
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: handles_sortable_columns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 2
|
10
|
-
version: 0.1.2
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.3
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Alex Fortuna
|
@@ -15,7 +10,7 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date:
|
13
|
+
date: 2011-07-29 00:00:00 +04:00
|
19
14
|
default_executable:
|
20
15
|
dependencies: []
|
21
16
|
|
@@ -26,9 +21,11 @@ executables: []
|
|
26
21
|
extensions: []
|
27
22
|
|
28
23
|
extra_rdoc_files:
|
24
|
+
- README.html
|
29
25
|
- README.md
|
30
26
|
files:
|
31
27
|
- MIT-LICENSE
|
28
|
+
- README.html
|
32
29
|
- README.md
|
33
30
|
- Rakefile
|
34
31
|
- VERSION.yml
|
@@ -37,14 +34,13 @@ files:
|
|
37
34
|
- lib/action_controller/base/handles_sortable_columns.rb
|
38
35
|
- lib/handles/sortable_columns.rb
|
39
36
|
- lib/handles_sortable_columns.rb
|
40
|
-
- spec/handles_sortable_columns_spec.rb
|
41
37
|
has_rdoc: true
|
42
38
|
homepage: http://github.com/dadooda/handles_sortable_columns
|
43
39
|
licenses: []
|
44
40
|
|
45
41
|
post_install_message:
|
46
|
-
rdoc_options:
|
47
|
-
|
42
|
+
rdoc_options: []
|
43
|
+
|
48
44
|
require_paths:
|
49
45
|
- lib
|
50
46
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -52,25 +48,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
48
|
requirements:
|
53
49
|
- - ">="
|
54
50
|
- !ruby/object:Gem::Version
|
55
|
-
hash: 3
|
56
|
-
segments:
|
57
|
-
- 0
|
58
51
|
version: "0"
|
59
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
53
|
none: false
|
61
54
|
requirements:
|
62
55
|
- - ">="
|
63
56
|
- !ruby/object:Gem::Version
|
64
|
-
hash: 3
|
65
|
-
segments:
|
66
|
-
- 0
|
67
57
|
version: "0"
|
68
58
|
requirements: []
|
69
59
|
|
70
60
|
rubyforge_project:
|
71
|
-
rubygems_version: 1.
|
61
|
+
rubygems_version: 1.6.2
|
72
62
|
signing_key:
|
73
63
|
specification_version: 3
|
74
64
|
summary: Sortable Table Columns
|
75
|
-
test_files:
|
76
|
-
|
65
|
+
test_files: []
|
66
|
+
|
@@ -1,42 +0,0 @@
|
|
1
|
-
describe "ClassMethods" do
|
2
|
-
module WrapSortableColumnsClassMethods
|
3
|
-
class MyController < ActionController::Base
|
4
|
-
handles_sortable_columns
|
5
|
-
end
|
6
|
-
end
|
7
|
-
|
8
|
-
describe "#sortable_column_name_from_title" do
|
9
|
-
it "generally works" do
|
10
|
-
tests = [
|
11
|
-
["Product", "product"],
|
12
|
-
["product", "product"],
|
13
|
-
["created_at", "created_at"],
|
14
|
-
["created at", "created_at"],
|
15
|
-
["CreatedAt", "created_at"],
|
16
|
-
["Created At", "created_at"],
|
17
|
-
]
|
18
|
-
|
19
|
-
tests.each do |input, expected|
|
20
|
-
WrapSortableColumnsClassMethods::MyController.sortable_column_name_from_title(input).should == expected
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end # #sortable_column_name_from_title
|
24
|
-
|
25
|
-
describe "#parse_sortable_column_sort_param" do
|
26
|
-
it "generally works" do
|
27
|
-
tests = [
|
28
|
-
["name", {:column => "name", :direction => :asc}],
|
29
|
-
["-name", {:column => "name", :direction => :desc}],
|
30
|
-
[" -name ", {:column => "name", :direction => :desc}],
|
31
|
-
["", {:column => nil, :direction => nil}],
|
32
|
-
["-", {:column => nil, :direction => nil}],
|
33
|
-
["- name", {:column => "name", :direction => :desc}],
|
34
|
-
["--kaka", {:column => nil, :direction => nil}],
|
35
|
-
]
|
36
|
-
|
37
|
-
tests.each do |input, expected|
|
38
|
-
WrapSortableColumnsClassMethods::MyController.parse_sortable_column_sort_param(input).should == expected
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end # #parse_sortable_column_sort_param
|
42
|
-
end # ClassMethods
|