thoughtbot-sortable_table 0.0.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.
- data/MIT-LICENSE +20 -0
- data/README.textile +140 -0
- data/Rakefile +31 -0
- data/TODO.textile +2 -0
- data/lib/sortable_table.rb +2 -0
- data/lib/sortable_table/app/controllers/application_controller.rb +95 -0
- data/lib/sortable_table/app/helpers/application_helper.rb +64 -0
- data/rails/init.rb +1 -0
- metadata +67 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Dan Croak
|
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.textile
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
h1. Sortable Table
|
2
|
+
|
3
|
+
Sort HTML tables in your Rails app.
|
4
|
+
|
5
|
+
h2. Install
|
6
|
+
|
7
|
+
script/plugin install git://github.com/thoughtbot/sortable_table.git
|
8
|
+
|
9
|
+
In app/controllers/application_controller.rb:
|
10
|
+
|
11
|
+
class ApplicationController < ActionController::Base
|
12
|
+
include SortableTable::App::Controllers::ApplicationController
|
13
|
+
end
|
14
|
+
|
15
|
+
In app/helpers/application_helper.rb:
|
16
|
+
|
17
|
+
module ApplicationHelper
|
18
|
+
include SortableTable::App::Helpers::ApplicationHelper
|
19
|
+
end
|
20
|
+
|
21
|
+
h2. Testing
|
22
|
+
|
23
|
+
<pre><code>
|
24
|
+
context "enough Users to sort" do
|
25
|
+
setup do
|
26
|
+
5.times { Factory :user }
|
27
|
+
end
|
28
|
+
|
29
|
+
should_sort_by_attributes :name, :email, :age, :group => "groups.name"
|
30
|
+
|
31
|
+
context "GET to #index" do
|
32
|
+
setup { get :index }
|
33
|
+
|
34
|
+
should_display_sortable_table_header_for :name, :email, :age, :group
|
35
|
+
end
|
36
|
+
end
|
37
|
+
</code></pre>
|
38
|
+
|
39
|
+
This is the common case for a RESTful UsersController.
|
40
|
+
|
41
|
+
* should_sort_by_attributes tests that the controller's index action can sort by the attributes.
|
42
|
+
* should_display_sortable_header_for tests that a sortable header displays for the attributes.
|
43
|
+
|
44
|
+
h2. Controller
|
45
|
+
|
46
|
+
<pre><code>
|
47
|
+
class UsersController < Admin::BaseController
|
48
|
+
sortable_attributes :name, :email, :age, :group => "groups.name"
|
49
|
+
|
50
|
+
def index
|
51
|
+
@users = User.paginate :page => params[:page], :order => sort_order
|
52
|
+
end
|
53
|
+
end
|
54
|
+
</code></pre>
|
55
|
+
|
56
|
+
sortable_attributes defines a sort_order method that gets called in your action.
|
57
|
+
|
58
|
+
If the index action is rendered without a params[:sort] option, @users will be sorted by :name, the first option in the list of sortable_attributes.
|
59
|
+
|
60
|
+
h2. View
|
61
|
+
|
62
|
+
<pre><code>
|
63
|
+
<h1>Users</h1>
|
64
|
+
<table>
|
65
|
+
<tr>
|
66
|
+
<%= sortable_table_header :name => "Name", :sort => "name" %>
|
67
|
+
<%= sortable_table_header :name => "Email", :sort => "email" %>
|
68
|
+
<%= sortable_table_header :name => "Age", :sort => "age" %>
|
69
|
+
<%= sortable_table_header :name => "Group", :sort => "group" %>
|
70
|
+
</tr>
|
71
|
+
<% @users.each do |user| %>
|
72
|
+
<tr>
|
73
|
+
<td><%= html_escape(user.name) %></td>
|
74
|
+
<td><%= html_escape(user.email) %></td>
|
75
|
+
<td><%= html_escape(user.age) %></td>
|
76
|
+
<td><%= html_escape(user.group.name) %></td>
|
77
|
+
</tr>
|
78
|
+
<% end %>
|
79
|
+
</table>
|
80
|
+
</code></pre>
|
81
|
+
|
82
|
+
sortable_table_header creates a table header containing a link with the correct :sort and :order params. It also has a class of "ascending" or "descending" so you can add styles with arrows. You can add your own styles as well.
|
83
|
+
|
84
|
+
h2. Example styles
|
85
|
+
|
86
|
+
th.ascending a {
|
87
|
+
background: url(/images/sort-ascending-arrow.gif) 0% 50% no-repeat;
|
88
|
+
padding-left: 15px;
|
89
|
+
}
|
90
|
+
|
91
|
+
th.descending a {
|
92
|
+
background: url(/images/sort-descending-arrow.gif) 0% 50% no-repeat;
|
93
|
+
padding-left: 15px;
|
94
|
+
}
|
95
|
+
|
96
|
+
h2. Overriding defaults
|
97
|
+
|
98
|
+
h3. should_sort_by_attributes
|
99
|
+
|
100
|
+
Opinionated defaults:
|
101
|
+
|
102
|
+
* GET to :index
|
103
|
+
* collection same name as controller (@users for UsersController)
|
104
|
+
* model name same name as controller (User for UsersController
|
105
|
+
|
106
|
+
If you need to test another action (or a nested controller), pass a block:
|
107
|
+
|
108
|
+
should_sort_by_attributes :age do |sort, order|
|
109
|
+
get :show, :sort => sort, :order => order, :group_id => @group.id
|
110
|
+
end
|
111
|
+
|
112
|
+
If you need to test another collection or model name, use should_sort_by.
|
113
|
+
|
114
|
+
h3. should_sort_by
|
115
|
+
|
116
|
+
The :collection, :model_name, and :action options of should_sort_by.
|
117
|
+
|
118
|
+
context "with a non-standard collection name" do
|
119
|
+
action = lambda { |sort, order| get :members, :sort => sort, :order => order }
|
120
|
+
should_sort_by :name, { :collection => "members",
|
121
|
+
:model_name => "user",
|
122
|
+
:action => action } do |user|
|
123
|
+
user.name
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
h3. sort_order
|
128
|
+
|
129
|
+
The default sort order is descending. This applies to the first time you click on a table header. You can override this to be ascending:
|
130
|
+
|
131
|
+
def index
|
132
|
+
@users = User.find :all, :order => sort_order("ascending")
|
133
|
+
end
|
134
|
+
|
135
|
+
Authors
|
136
|
+
-------
|
137
|
+
|
138
|
+
Dan Croak, Joe Ferris, Jason Morrison and Boston.rb.
|
139
|
+
|
140
|
+
Copyright (c) 2008 Dan Croak, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
test_files_pattern = 'test/rails_root/test/{unit,functional,other}/**/*_test.rb'
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.libs << 'lib'
|
8
|
+
t.pattern = test_files_pattern
|
9
|
+
t.verbose = false
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Run the test suite"
|
13
|
+
task :default => :test
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.version = '0.0.5'
|
17
|
+
s.name = "sortable_table"
|
18
|
+
s.summary = "Sort HTML tables in a Rails app."
|
19
|
+
s.email = "dcroak@thoughtbot.com"
|
20
|
+
s.homepage = "http://github.com/dancroak/sortable_table"
|
21
|
+
s.description = "Sort HTML tables in a Rails app."
|
22
|
+
s.authors = ["Dan Croak", "Joe Ferris", "Jon Yurek", "Boston.rb"]
|
23
|
+
s.files = FileList["[A-Z]*", "{lib,rails}/**/*"]
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Generate a gemspec file"
|
27
|
+
task :gemspec do
|
28
|
+
File.open("#{spec.name}.gemspec", 'w') do |f|
|
29
|
+
f.write spec.to_yaml
|
30
|
+
end
|
31
|
+
end
|
data/TODO.textile
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
module SortableTable
|
2
|
+
module App
|
3
|
+
module Controllers
|
4
|
+
module ApplicationController
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
include InstanceMethods
|
9
|
+
extend ClassMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def sortable_attributes(*args)
|
15
|
+
mappings = pop_hash_from_list(args)
|
16
|
+
acceptable_columns = join_array_and_hash_values(args, mappings)
|
17
|
+
define_sort_order(acceptable_columns, mappings)
|
18
|
+
end
|
19
|
+
|
20
|
+
def pop_hash_from_list(*args)
|
21
|
+
if args.last.is_a?(Hash)
|
22
|
+
args.pop
|
23
|
+
else
|
24
|
+
{}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def join_array_and_hash_values(array, hash)
|
29
|
+
array.collect { |each| each.to_s } +
|
30
|
+
hash.values.collect { |each| each.to_s }
|
31
|
+
end
|
32
|
+
|
33
|
+
def define_sort_order(acceptable_columns, mappings)
|
34
|
+
define_method(:default_sort_column) do
|
35
|
+
acceptable_columns.first
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_accessor :sortable_table_direction
|
39
|
+
|
40
|
+
define_method(:sort_order) do |*default|
|
41
|
+
default = default.first
|
42
|
+
direction = default_sort_direction(params[:order], default)
|
43
|
+
column = params[:sort] || default_sort_column
|
44
|
+
self.sortable_table_direction = direction
|
45
|
+
if params[:sort] && acceptable_columns.include?(column)
|
46
|
+
column = mappings[column.to_sym] || column
|
47
|
+
handle_compound_sorting(column, sql_sort_direction(direction))
|
48
|
+
else
|
49
|
+
"#{acceptable_columns.first} #{sql_sort_direction(direction)}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
helper_method :sort_order, :default_sort_column, :sortable_table_direction
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module InstanceMethods
|
58
|
+
def default_sort_direction(order, default)
|
59
|
+
case
|
60
|
+
when ! order.blank? then normalize_direction(order)
|
61
|
+
when default.is_a?(Hash) && default[:default] then normalize_direction(default[:default])
|
62
|
+
else "descending"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def sql_sort_direction(direction)
|
67
|
+
case direction
|
68
|
+
when "ascending", "asc" then "asc"
|
69
|
+
when "descending", "desc" then "desc"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def normalize_direction(direction)
|
74
|
+
case direction
|
75
|
+
when "ascending", "asc" then "ascending"
|
76
|
+
when "descending", "desc" then "descending"
|
77
|
+
else raise RuntimeError.new("Direction must be ascending, asc, descending, or desc")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def handle_compound_sorting(column, direction)
|
82
|
+
if column.is_a?(Array)
|
83
|
+
column.collect { |each| "#{each} #{direction}" }.join(',')
|
84
|
+
else
|
85
|
+
"#{column} #{direction}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module SortableTable
|
2
|
+
module App
|
3
|
+
module Helpers
|
4
|
+
module ApplicationHelper
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
include InstanceMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
def sortable_table_header(opts = {})
|
14
|
+
raise ArgumentError if opts[:name].nil? || opts[:sort].nil?
|
15
|
+
anchor = opts[:anchor].blank? ? "" : "##{opts[:anchor]}"
|
16
|
+
content_tag :th,
|
17
|
+
link_to(opts[:name],
|
18
|
+
sortable_url(opts) + anchor,
|
19
|
+
:title => opts[:title]),
|
20
|
+
:class => sortable_table_header_classes(opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
def sortable_table_header_classes(opts)
|
24
|
+
class_names = []
|
25
|
+
class_names << sortable_table_header_class(opts)
|
26
|
+
class_names << opts[:class]
|
27
|
+
class_names.compact.blank? ? nil : class_names.compact.join(" ")
|
28
|
+
end
|
29
|
+
|
30
|
+
def sortable_table_header_class(opts)
|
31
|
+
if re_sort?(opts) || sorting_default?(opts)
|
32
|
+
sortable_table_direction
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def sorting_default?(opts)
|
37
|
+
params[:sort].nil? && opts[:sort] == default_sort_column
|
38
|
+
end
|
39
|
+
|
40
|
+
def re_sort?(opts)
|
41
|
+
params[:sort] == opts[:sort]
|
42
|
+
end
|
43
|
+
|
44
|
+
def reverse_order(order)
|
45
|
+
order == 'ascending' ? 'descending' : 'ascending'
|
46
|
+
end
|
47
|
+
|
48
|
+
def sortable_url(opts)
|
49
|
+
url_for(params.merge(:sort => opts[:sort], :order => link_sort_order(opts), :page => 1))
|
50
|
+
end
|
51
|
+
|
52
|
+
def link_sort_order(opts)
|
53
|
+
if re_sort? opts
|
54
|
+
reverse_order params[:order]
|
55
|
+
else
|
56
|
+
reverse_order sortable_table_direction
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "sortable_table"
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: thoughtbot-sortable_table
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dan Croak
|
8
|
+
- Joe Ferris
|
9
|
+
- Jon Yurek
|
10
|
+
- Boston.rb
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
|
15
|
+
date: 2009-02-26 21:00:00 -08:00
|
16
|
+
default_executable:
|
17
|
+
dependencies: []
|
18
|
+
|
19
|
+
description: Sort HTML tables in a Rails app.
|
20
|
+
email: dcroak@thoughtbot.com
|
21
|
+
executables: []
|
22
|
+
|
23
|
+
extensions: []
|
24
|
+
|
25
|
+
extra_rdoc_files: []
|
26
|
+
|
27
|
+
files:
|
28
|
+
- MIT-LICENSE
|
29
|
+
- Rakefile
|
30
|
+
- README.textile
|
31
|
+
- TODO.textile
|
32
|
+
- lib/sortable_table
|
33
|
+
- lib/sortable_table/app
|
34
|
+
- lib/sortable_table/app/controllers
|
35
|
+
- lib/sortable_table/app/controllers/application_controller.rb
|
36
|
+
- lib/sortable_table/app/helpers
|
37
|
+
- lib/sortable_table/app/helpers/application_helper.rb
|
38
|
+
- lib/sortable_table.rb
|
39
|
+
- rails/init.rb
|
40
|
+
has_rdoc: false
|
41
|
+
homepage: http://github.com/dancroak/sortable_table
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.2.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Sort HTML tables in a Rails app.
|
66
|
+
test_files: []
|
67
|
+
|