tableficate 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.markdown +120 -0
- data/Rakefile +1 -0
- data/app/views/tableficate/_column_header.html.erb +8 -0
- data/app/views/tableficate/_data.html.erb +1 -0
- data/app/views/tableficate/_input_filter.html.erb +4 -0
- data/app/views/tableficate/_input_range_filter.html.erb +6 -0
- data/app/views/tableficate/_row.html.erb +5 -0
- data/app/views/tableficate/_select_filter.html.erb +4 -0
- data/app/views/tableficate/_table.html.erb +36 -0
- data/changelog.markdown +2 -0
- data/lib/generators/tableficate/table/table_generator.rb +17 -0
- data/lib/generators/tableficate/table/templates/table.rb +5 -0
- data/lib/generators/tableficate/theme/theme_generator.rb +15 -0
- data/lib/tableficate/action_column.rb +15 -0
- data/lib/tableficate/active_record_extension.rb +20 -0
- data/lib/tableficate/base.rb +37 -0
- data/lib/tableficate/column.rb +33 -0
- data/lib/tableficate/engine.rb +4 -0
- data/lib/tableficate/exceptions.rb +3 -0
- data/lib/tableficate/filters/filter.rb +19 -0
- data/lib/tableficate/filters/input_filters.rb +64 -0
- data/lib/tableficate/filters/select_filter.rb +11 -0
- data/lib/tableficate/finder.rb +79 -0
- data/lib/tableficate/helper.rb +37 -0
- data/lib/tableficate/table.rb +57 -0
- data/lib/tableficate/utils.rb +7 -0
- data/lib/tableficate/version.rb +3 -0
- data/lib/tableficate.rb +17 -0
- data/spec/action_column_spec.rb +21 -0
- data/spec/active_record_extension_spec.rb +9 -0
- data/spec/base_spec.rb +103 -0
- data/spec/column_spec.rb +54 -0
- data/spec/filter_spec.rb +30 -0
- data/spec/finder_spec.rb +35 -0
- data/spec/input_filter_spec.rb +90 -0
- data/spec/select_filter_spec.rb +10 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/table_spec.rb +94 -0
- data/spec/test_app/.gitignore +4 -0
- data/spec/test_app/Gemfile +21 -0
- data/spec/test_app/README +261 -0
- data/spec/test_app/Rakefile +7 -0
- data/spec/test_app/app/assets/images/rails.png +0 -0
- data/spec/test_app/app/assets/javascripts/application.js +9 -0
- data/spec/test_app/app/assets/stylesheets/application.css +7 -0
- data/spec/test_app/app/controllers/application_controller.rb +3 -0
- data/spec/test_app/app/helpers/application_helper.rb +2 -0
- data/spec/test_app/app/mailers/.gitkeep +0 -0
- data/spec/test_app/app/models/.gitkeep +0 -0
- data/spec/test_app/app/models/nobel_prize.rb +3 -0
- data/spec/test_app/app/models/nobel_prize_winner.rb +3 -0
- data/spec/test_app/app/views/layouts/application.html.erb +14 -0
- data/spec/test_app/config/application.rb +48 -0
- data/spec/test_app/config/boot.rb +6 -0
- data/spec/test_app/config/database.yml +25 -0
- data/spec/test_app/config/environment.rb +5 -0
- data/spec/test_app/config/environments/development.rb +30 -0
- data/spec/test_app/config/environments/production.rb +60 -0
- data/spec/test_app/config/environments/test.rb +42 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/inflections.rb +10 -0
- data/spec/test_app/config/initializers/mime_types.rb +5 -0
- data/spec/test_app/config/initializers/secret_token.rb +7 -0
- data/spec/test_app/config/initializers/session_store.rb +8 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/test_app/config/locales/en.yml +5 -0
- data/spec/test_app/config/routes.rb +58 -0
- data/spec/test_app/config.ru +4 -0
- data/spec/test_app/db/migrate/20111007154222_create_nobel_prize_winners.rb +30 -0
- data/spec/test_app/db/migrate/20111010191626_create_nobel_prizes.rb +34 -0
- data/spec/test_app/db/schema.rb +27 -0
- data/spec/test_app/db/seeds.rb +7 -0
- data/spec/test_app/db/test.sqlite3 +0 -0
- data/spec/test_app/doc/README_FOR_APP +2 -0
- data/spec/test_app/lib/assets/.gitkeep +0 -0
- data/spec/test_app/lib/tasks/.gitkeep +0 -0
- data/spec/test_app/log/.gitkeep +0 -0
- data/spec/test_app/public/404.html +26 -0
- data/spec/test_app/public/422.html +26 -0
- data/spec/test_app/public/500.html +26 -0
- data/spec/test_app/public/favicon.ico +0 -0
- data/spec/test_app/public/index.html +241 -0
- data/spec/test_app/public/robots.txt +5 -0
- data/spec/test_app/script/rails +6 -0
- data/spec/test_app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/test_app/vendor/plugins/.gitkeep +0 -0
- data/spec/utils_spec.rb +11 -0
- data/tableficate.gemspec +26 -0
- metadata +245 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2011 SEI Meetings & Incentives
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# Tableficate
|
2
|
+
A DSL for easy table creation with sorting and filtering. It tries to do to tables what simple_form and formtastic have done for forms. Below you'll find basic documentation with more compelete docs forthcoming.
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
$ gem install tableficate
|
7
|
+
|
8
|
+
If you're using Bundler, add this to your Gemfile:
|
9
|
+
|
10
|
+
gem 'tableficate'
|
11
|
+
|
12
|
+
## Support
|
13
|
+
|
14
|
+
### Ruby
|
15
|
+
1.9+
|
16
|
+
|
17
|
+
### Rails
|
18
|
+
3.1+
|
19
|
+
|
20
|
+
### Templating
|
21
|
+
Any templating engine can be used. The default theme uses ERB.
|
22
|
+
|
23
|
+
### Database Framework
|
24
|
+
ActiveRecord
|
25
|
+
|
26
|
+
### Pagination
|
27
|
+
Any pagination can be used. The default theme has built-in support for Kaminari and will_paginate.
|
28
|
+
|
29
|
+
## Basic Usage
|
30
|
+
Let's say that we want to create a table that lists active accounts in the system with their time of creation and the name on the account.
|
31
|
+
|
32
|
+
Our controller:
|
33
|
+
|
34
|
+
@accounts = Accounts.active.tableficate(params[:accounts]).page(params.try(:[], :accounts_page) || 1)
|
35
|
+
|
36
|
+
Here we're getting active accounts, calling tableficate and then paginating with Kaminari. Tableficate works on Arel objects and passes out an Arel so you can add things like pagination. We pass in the params for the table we'll create in the view. By default the params are stored under the primary table name of the query.
|
37
|
+
|
38
|
+
Our View:
|
39
|
+
|
40
|
+
<%= table_for @accounts, show_sorts: true do |t|
|
41
|
+
t.column :id, header: 'Account Number'
|
42
|
+
t.column :created_at do |account|
|
43
|
+
account.created_at.strftime('%m/%d/%Y')
|
44
|
+
end
|
45
|
+
t.column :first_name
|
46
|
+
t.column :last_name
|
47
|
+
t.actions do |account|
|
48
|
+
link_to('View', account_path(account))
|
49
|
+
end
|
50
|
+
|
51
|
+
t.input_filter :first_name
|
52
|
+
t.input_filter :last_name
|
53
|
+
%>
|
54
|
+
|
55
|
+
This creates a sortable table with two filters, 4 data columns and an action column. Column headers are automatically generated but can be overridden as seen on the "id" column. The column output can also be overridden by passing a block to the call. This setup provides easy table creation but only covers basic functionality. Some of the more advanced functionality requires you to wrap your scope in a special table model.
|
56
|
+
|
57
|
+
Having created the basic table we now want to default the sorting to show newest accounts first and we want the first and last name to be merged into one name column. First we'll need to create a table model.
|
58
|
+
|
59
|
+
In "app/tables/" we'll create a new table model. This can be done using a generator.
|
60
|
+
|
61
|
+
$ rails generate tableficate:table AccountReport
|
62
|
+
|
63
|
+
Our table model:
|
64
|
+
|
65
|
+
class AccountReport < Tableficate::Base
|
66
|
+
scope do
|
67
|
+
Accounts.active
|
68
|
+
end
|
69
|
+
|
70
|
+
default_sort(:created_at, 'DESC')
|
71
|
+
|
72
|
+
column(:full_name, sort: 'first_name ASC, last_name ASC')
|
73
|
+
|
74
|
+
filter(:full_name) do |value, scope|
|
75
|
+
first_name, last_name = value.split(/\s+/)
|
76
|
+
|
77
|
+
if last_name.nil?
|
78
|
+
scope.where(['first_name LIKE ? OR last_name LIKE ?', first_name, first_name])
|
79
|
+
else
|
80
|
+
scope.where(['first_name LIKE ? AND last_name LIKE ?', first_name, last_name])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
We've defined a scope that we're wrapping. Then we provide a default sorting and explain how to sort and filter a new column called ":full_name".
|
86
|
+
|
87
|
+
Our new controller:
|
88
|
+
|
89
|
+
@accounts = AccountReport.tableficate(params[:accounts]).page(params.try(:[], :accounts_page) || 1)
|
90
|
+
|
91
|
+
The only change here is that "Accounts.active" has changed to "AccountReport".
|
92
|
+
|
93
|
+
Our new view:
|
94
|
+
|
95
|
+
<%= table_for @accounts, show_sorts: true do |t|
|
96
|
+
t.column :id, header: 'Account Number'
|
97
|
+
t.column :created_at do |account|
|
98
|
+
account.created_at.strftime('%m/%d/%Y')
|
99
|
+
end
|
100
|
+
t.column :full_name
|
101
|
+
t.actions do |account|
|
102
|
+
link_to('View', account_path(account))
|
103
|
+
end
|
104
|
+
|
105
|
+
t.input_filter :full_name
|
106
|
+
%>
|
107
|
+
|
108
|
+
In the view we've merged the first and last name into a new full name column. Now we have default sorting, sortable columns and a full name filter.
|
109
|
+
|
110
|
+
## Themes
|
111
|
+
|
112
|
+
New themes can be created using the theme generator.
|
113
|
+
|
114
|
+
$ rails generate tableficate:theme NAME
|
115
|
+
|
116
|
+
The theme can then be applied to a table by passing "theme: 'NAME'" to the "table_for" call.
|
117
|
+
|
118
|
+
<%= table_for @accounts, theme: 'foo' do |t|
|
119
|
+
...
|
120
|
+
%>
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<th>
|
2
|
+
<%= column.header %>
|
3
|
+
<% table_params = (params[column.table.as] || {}) %>
|
4
|
+
<% if column.show_sort? %>
|
5
|
+
<%= link_to 'A', url_for(params.merge(column.table.as => table_params.merge({sort: column.name.to_s, dir: 'asc'}))) %><% if column.is_sorted?('asc') %>*<% end %>
|
6
|
+
<%= link_to 'D', url_for(params.merge(column.table.as => table_params.merge({sort: column.name.to_s, dir: 'desc'}))) %><% if column.is_sorted?('desc') %>*<% end %>
|
7
|
+
<% end %>
|
8
|
+
</th>
|
@@ -0,0 +1 @@
|
|
1
|
+
<td><%= column.value(row) %></td>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<% if table.filters.any? %>
|
2
|
+
<%= form_tag '', method: :get do %>
|
3
|
+
<% if params[table.as] and params[table.as][:sort] %>
|
4
|
+
<%= hidden_field_tag("#{table.as}[sort]", params[table.as][:sort]) %>
|
5
|
+
<% end %>
|
6
|
+
<% if params[table.as] and params[table.as][:dir] %>
|
7
|
+
<%= hidden_field_tag("#{table.as}[dir]", params[table.as][:dir]) %>
|
8
|
+
<% end %>
|
9
|
+
<% table.filters.each do |filter| %>
|
10
|
+
<%= tableficate_filter_tag filter %>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<%= submit_tag('Filter') %>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<% if defined? ::Kaminari %>
|
18
|
+
<%= paginate(table.rows, param_name: "#{table.as}_page") %>
|
19
|
+
<% elsif defined? ::WillPaginate %>
|
20
|
+
<%= will_paginate(table.rows, param_name: "#{table.as}_page") %>
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
<%= content_tag(:table, table.options[:html]) do %>
|
24
|
+
<thead>
|
25
|
+
<tr>
|
26
|
+
<% table.columns.each do |column| %>
|
27
|
+
<%= tableficate_header_tag column %>
|
28
|
+
<% end %>
|
29
|
+
</tr>
|
30
|
+
</thead>
|
31
|
+
<tbody>
|
32
|
+
<% table.rows.each do |row| %>
|
33
|
+
<%= tableficate_row_tag row, table.columns %>
|
34
|
+
<% end %>
|
35
|
+
</tbody>
|
36
|
+
<% end %>
|
data/changelog.markdown
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Tableficate
|
2
|
+
class TableGenerator < Rails::Generators::NamedBase
|
3
|
+
desc('Create a Tableficate table model.')
|
4
|
+
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
|
7
|
+
TABLES_PATH = 'app/tables'
|
8
|
+
|
9
|
+
argument :scope, required: false
|
10
|
+
|
11
|
+
def create_table
|
12
|
+
empty_directory(TABLES_PATH)
|
13
|
+
|
14
|
+
template('table.rb', "#{TABLES_PATH}/#{file_name.underscore}.rb")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Tableficate
|
2
|
+
class ThemeGenerator < Rails::Generators::NamedBase
|
3
|
+
desc('Create a Tableficate theme.')
|
4
|
+
|
5
|
+
VIEW_PATH = 'app/views/tableficate'
|
6
|
+
|
7
|
+
source_root File.expand_path("../../../../../#{VIEW_PATH}", __FILE__)
|
8
|
+
|
9
|
+
def create_theme
|
10
|
+
empty_directory(VIEW_PATH)
|
11
|
+
|
12
|
+
directory('', "#{VIEW_PATH}/#{file_name}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Tableficate
|
2
|
+
module ActiveRecordExtension
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
extend Tableficate::Finder
|
7
|
+
|
8
|
+
self.scope :tableficate_ext, ->{} do
|
9
|
+
def tableficate_add_data(key, value)
|
10
|
+
@tableficate_data ||= {}
|
11
|
+
@tableficate_data[key] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def tableficate_get_data
|
15
|
+
@tableficate_data || {}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Tableficate
|
2
|
+
class Base
|
3
|
+
extend Tableficate::Finder
|
4
|
+
|
5
|
+
def self.scope(model = nil, &block)
|
6
|
+
if block_given?
|
7
|
+
@scope = block.call
|
8
|
+
else
|
9
|
+
@scope = model.to_s.camelize.constantize
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.default_sort(name, dir = 'asc')
|
14
|
+
@default_sort = [name, dir]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.column(name, options = {})
|
18
|
+
@sort ||= {}
|
19
|
+
|
20
|
+
@sort[name] = options[:sort] if options[:sort].present?
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.filter(name, options = {}, &block)
|
24
|
+
@filter ||= {}
|
25
|
+
|
26
|
+
if block_given?
|
27
|
+
@filter[name] = block
|
28
|
+
else
|
29
|
+
options.reverse_merge!(
|
30
|
+
field: name
|
31
|
+
)
|
32
|
+
|
33
|
+
@filter[name] = options
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Tableficate
|
2
|
+
class Column
|
3
|
+
attr_reader :name, :header, :table
|
4
|
+
|
5
|
+
def initialize(table, name, options = {}, &block)
|
6
|
+
@table = table
|
7
|
+
@name = name
|
8
|
+
@options = options
|
9
|
+
@block = block
|
10
|
+
|
11
|
+
@header = @options.delete(:header) || name.to_s.titleize
|
12
|
+
end
|
13
|
+
|
14
|
+
def value(row)
|
15
|
+
if @block
|
16
|
+
@block.call(row).html_safe
|
17
|
+
else
|
18
|
+
row.send(@name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def show_sort?
|
23
|
+
!!@options[:show_sort]
|
24
|
+
end
|
25
|
+
|
26
|
+
def is_sorted?(dir = nil)
|
27
|
+
is_sorted = @table.current_sort[:column] == self.name
|
28
|
+
is_sorted = @table.current_sort[:dir] == dir if is_sorted and dir
|
29
|
+
|
30
|
+
is_sorted
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Tableficate
|
2
|
+
class Filter
|
3
|
+
attr_reader :name, :label, :options, :template, :table, :field_name
|
4
|
+
|
5
|
+
def initialize(table, name, options = {})
|
6
|
+
@table = table
|
7
|
+
@name = name
|
8
|
+
@options = options
|
9
|
+
|
10
|
+
@template = self.class.name.demodulize.underscore
|
11
|
+
@label = @options[:label] || table.columns.detect{|column| column.name == @name}.try(:header) || name.to_s.titleize
|
12
|
+
@field_name = "#{table.as}[filter][#{@name}]"
|
13
|
+
end
|
14
|
+
|
15
|
+
def field_value(params)
|
16
|
+
params[:filter][@name] rescue ''
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Tableficate
|
2
|
+
class InputFilter < Filter
|
3
|
+
def initialize(table, name, options = {})
|
4
|
+
super(table, name, options)
|
5
|
+
|
6
|
+
type = @options[:field_options][:type] rescue 'text'
|
7
|
+
|
8
|
+
if not Dir.glob('app/views/' + Tableficate::Utils::template_path("_#{type}_#{@template}.html.*", table.options[:theme])).empty?
|
9
|
+
@template = "#{type}_#{@template}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class InputStartFilter < InputFilter
|
15
|
+
def initialize(table, name, options = {})
|
16
|
+
super(table, name, options)
|
17
|
+
|
18
|
+
@field_name += '[start]'
|
19
|
+
end
|
20
|
+
|
21
|
+
def name
|
22
|
+
"#{@name}_start".to_sym
|
23
|
+
end
|
24
|
+
|
25
|
+
def field_value(params)
|
26
|
+
params[:filter][@name][:start] rescue ''
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class InputStopFilter < InputFilter
|
31
|
+
def initialize(table, name, options = {})
|
32
|
+
super(table, name, options)
|
33
|
+
|
34
|
+
@field_name += '[stop]'
|
35
|
+
end
|
36
|
+
|
37
|
+
def name
|
38
|
+
"#{@name}_stop".to_sym
|
39
|
+
end
|
40
|
+
|
41
|
+
def field_value(params)
|
42
|
+
params[:filter][@name][:stop] rescue ''
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class InputRangeFilter < Filter
|
47
|
+
attr_reader :start, :stop
|
48
|
+
|
49
|
+
def initialize(table, name, options = {})
|
50
|
+
start_options = options.delete(:start) || {}
|
51
|
+
stop_options = options.delete(:stop) || {}
|
52
|
+
|
53
|
+
super(table, name, options)
|
54
|
+
|
55
|
+
start_options.reverse_merge!(@options)
|
56
|
+
start_options.reverse_merge!(label: self.label)
|
57
|
+
stop_options.reverse_merge!(@options)
|
58
|
+
stop_options.reverse_merge!(label: self.label)
|
59
|
+
|
60
|
+
@start = InputStartFilter.new(table, name, start_options)
|
61
|
+
@stop = InputStopFilter.new(table, name, stop_options)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Tableficate
|
2
|
+
module Finder
|
3
|
+
def tableficate(params)
|
4
|
+
scope = @scope || self
|
5
|
+
raise Tableficate::MissingScope unless scope.new.kind_of?(ActiveRecord::Base)
|
6
|
+
|
7
|
+
# filtering
|
8
|
+
if params
|
9
|
+
if params[:filter]
|
10
|
+
params[:filter].each do |name, value|
|
11
|
+
next if value.blank? or (value.is_a?(Hash) and value.all?{|key, value| value.blank?})
|
12
|
+
|
13
|
+
name = name.to_sym
|
14
|
+
value.strip! if value.is_a?(String)
|
15
|
+
|
16
|
+
if @filter and @filter[name]
|
17
|
+
if @filter[name].is_a?(Proc)
|
18
|
+
scope = @filter[name].call(value, scope)
|
19
|
+
elsif value.is_a?(String)
|
20
|
+
value = "%#{value}%" if @filter[name][:match] == 'contains'
|
21
|
+
|
22
|
+
scope = scope.where(["#{get_full_column_name(@filter[name][:field])} LIKE ?", value])
|
23
|
+
elsif value.is_a?(Array)
|
24
|
+
full_column_name = get_full_column_name(@filter[name][:field])
|
25
|
+
|
26
|
+
if @filter[name][:match] == 'contains'
|
27
|
+
scope = scope.where([
|
28
|
+
Array.new(value.size, "#{full_column_name} LIKE ?").join(' OR '),
|
29
|
+
*value.map{|v| "%#{v}%"}
|
30
|
+
])
|
31
|
+
else
|
32
|
+
scope = scope.where(["#{full_column_name} IN(?)", value])
|
33
|
+
end
|
34
|
+
elsif value.is_a?(Hash)
|
35
|
+
scope = scope.where(["#{get_full_column_name(@filter[name][:field])} BETWEEN :start AND :stop", value])
|
36
|
+
end
|
37
|
+
elsif value.is_a?(Array)
|
38
|
+
scope = scope.where(["#{get_full_column_name(name.to_s.gsub(/\W/, ''))} IN(?)", value])
|
39
|
+
elsif value.is_a?(Hash)
|
40
|
+
scope = scope.where(["#{get_full_column_name(name.to_s.gsub(/\W/, ''))} BETWEEN :start AND :stop", value])
|
41
|
+
else
|
42
|
+
scope = scope.where(["#{get_full_column_name(name.to_s.gsub(/\W/, ''))} LIKE ?", value])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# sorting
|
49
|
+
column = params.try(:[], :sort).try(:gsub, /\W/, '') || @default_sort.try(:[], 0)
|
50
|
+
dir = (params.try(:[], :dir) || @default_sort.try(:[], 1) || 'asc').downcase
|
51
|
+
if column.present?
|
52
|
+
scope = scope.order(@sort.try(:[], column.to_sym) || "#{get_full_column_name(column.to_s)} ASC")
|
53
|
+
scope = scope.reverse_order if dir == 'desc'
|
54
|
+
end
|
55
|
+
|
56
|
+
# return an arel object with our data attached
|
57
|
+
scope = scope.tableficate_ext
|
58
|
+
sorting = {column: nil, dir: nil}
|
59
|
+
if column.present?
|
60
|
+
sorting[:column] = column.to_sym
|
61
|
+
sorting[:dir] = ['asc', 'desc'].include?(dir) ? dir : 'asc'
|
62
|
+
end
|
63
|
+
scope.tableficate_add_data(:current_sort, sorting)
|
64
|
+
scope
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_full_column_name(name)
|
68
|
+
name = name.to_s
|
69
|
+
scope = @scope || self
|
70
|
+
|
71
|
+
if scope.column_names.include?(name)
|
72
|
+
"#{scope.table_name}.#{name}"
|
73
|
+
else
|
74
|
+
name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
private :get_full_column_name
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Tableficate
|
2
|
+
module Helper
|
3
|
+
def table_for(rows, options = {})
|
4
|
+
t = Tableficate::Table.new(self, rows, options, rows.tableficate_get_data)
|
5
|
+
yield(t)
|
6
|
+
t.render
|
7
|
+
end
|
8
|
+
|
9
|
+
def tableficate_header_tag(column)
|
10
|
+
render partial: Tableficate::Utils::template_path('column_header', column.table.options[:theme]), locals: {column: column}
|
11
|
+
end
|
12
|
+
|
13
|
+
def tableficate_data_tag(row, column)
|
14
|
+
render partial: Tableficate::Utils::template_path('data', column.table.options[:theme]), locals: {row: row, column: column}
|
15
|
+
end
|
16
|
+
|
17
|
+
def tableficate_row_tag(row, columns)
|
18
|
+
render partial: Tableficate::Utils::template_path('row', columns.first.table.options[:theme]), locals: {row: row, columns: columns}
|
19
|
+
end
|
20
|
+
|
21
|
+
def tableficate_filter_tag(filter)
|
22
|
+
render partial: Tableficate::Utils::template_path(filter.template, filter.table.options[:theme]), locals: {filter: filter}
|
23
|
+
end
|
24
|
+
|
25
|
+
def tableficate_label_tag(filter)
|
26
|
+
label_tag(filter.field_name, filter.label, filter.options[:label_options] || {})
|
27
|
+
end
|
28
|
+
|
29
|
+
def tableficate_text_field_tag(filter)
|
30
|
+
text_field_tag(filter.field_name, filter.field_value(params[filter.table.as]), filter.options[:field_options] || {})
|
31
|
+
end
|
32
|
+
|
33
|
+
def tableficate_select_tag(filter)
|
34
|
+
select_tag(filter.field_name, filter.choices, filter.options)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Tableficate
|
2
|
+
class Table
|
3
|
+
attr_reader :columns, :rows, :current_sort, :filters, :options, :as
|
4
|
+
|
5
|
+
def initialize(template, rows, options, data)
|
6
|
+
@template = template
|
7
|
+
@rows = rows
|
8
|
+
@columns = []
|
9
|
+
@filters = []
|
10
|
+
@as = options[:as] || rows.table_name
|
11
|
+
|
12
|
+
@options = {
|
13
|
+
show_sorts: false,
|
14
|
+
theme: ''
|
15
|
+
}.merge(options)
|
16
|
+
|
17
|
+
@current_sort = data[:current_sort]
|
18
|
+
end
|
19
|
+
|
20
|
+
def column(name, options = {}, &block)
|
21
|
+
options.reverse_merge!(
|
22
|
+
show_sort: @options[:show_sorts]
|
23
|
+
)
|
24
|
+
|
25
|
+
@columns.push(Column.new(self, name, options, &block))
|
26
|
+
end
|
27
|
+
|
28
|
+
def actions(options = {}, &block)
|
29
|
+
@columns.push(ActionColumn.new(self, options, block))
|
30
|
+
end
|
31
|
+
|
32
|
+
def show_sort?
|
33
|
+
self.columns.any?{|column| column.show_sort?}
|
34
|
+
end
|
35
|
+
|
36
|
+
def input_filter(name, options = {})
|
37
|
+
@filters.push(InputFilter.new(self, name, options))
|
38
|
+
end
|
39
|
+
|
40
|
+
def input_range_filter(name, options = {})
|
41
|
+
@filters.push(InputRangeFilter.new(self, name, options))
|
42
|
+
end
|
43
|
+
|
44
|
+
def select_filter(name, choices, options = {})
|
45
|
+
@filters.push(SelectFilter.new(self, name, choices, options))
|
46
|
+
end
|
47
|
+
|
48
|
+
def render(options = {})
|
49
|
+
options.reverse_merge!(
|
50
|
+
partial: Tableficate::Utils::template_path('table', @options[:theme]),
|
51
|
+
locals: {table: self}
|
52
|
+
)
|
53
|
+
|
54
|
+
@template.render options
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|