tableficate 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.markdown +120 -0
  5. data/Rakefile +1 -0
  6. data/app/views/tableficate/_column_header.html.erb +8 -0
  7. data/app/views/tableficate/_data.html.erb +1 -0
  8. data/app/views/tableficate/_input_filter.html.erb +4 -0
  9. data/app/views/tableficate/_input_range_filter.html.erb +6 -0
  10. data/app/views/tableficate/_row.html.erb +5 -0
  11. data/app/views/tableficate/_select_filter.html.erb +4 -0
  12. data/app/views/tableficate/_table.html.erb +36 -0
  13. data/changelog.markdown +2 -0
  14. data/lib/generators/tableficate/table/table_generator.rb +17 -0
  15. data/lib/generators/tableficate/table/templates/table.rb +5 -0
  16. data/lib/generators/tableficate/theme/theme_generator.rb +15 -0
  17. data/lib/tableficate/action_column.rb +15 -0
  18. data/lib/tableficate/active_record_extension.rb +20 -0
  19. data/lib/tableficate/base.rb +37 -0
  20. data/lib/tableficate/column.rb +33 -0
  21. data/lib/tableficate/engine.rb +4 -0
  22. data/lib/tableficate/exceptions.rb +3 -0
  23. data/lib/tableficate/filters/filter.rb +19 -0
  24. data/lib/tableficate/filters/input_filters.rb +64 -0
  25. data/lib/tableficate/filters/select_filter.rb +11 -0
  26. data/lib/tableficate/finder.rb +79 -0
  27. data/lib/tableficate/helper.rb +37 -0
  28. data/lib/tableficate/table.rb +57 -0
  29. data/lib/tableficate/utils.rb +7 -0
  30. data/lib/tableficate/version.rb +3 -0
  31. data/lib/tableficate.rb +17 -0
  32. data/spec/action_column_spec.rb +21 -0
  33. data/spec/active_record_extension_spec.rb +9 -0
  34. data/spec/base_spec.rb +103 -0
  35. data/spec/column_spec.rb +54 -0
  36. data/spec/filter_spec.rb +30 -0
  37. data/spec/finder_spec.rb +35 -0
  38. data/spec/input_filter_spec.rb +90 -0
  39. data/spec/select_filter_spec.rb +10 -0
  40. data/spec/spec_helper.rb +3 -0
  41. data/spec/table_spec.rb +94 -0
  42. data/spec/test_app/.gitignore +4 -0
  43. data/spec/test_app/Gemfile +21 -0
  44. data/spec/test_app/README +261 -0
  45. data/spec/test_app/Rakefile +7 -0
  46. data/spec/test_app/app/assets/images/rails.png +0 -0
  47. data/spec/test_app/app/assets/javascripts/application.js +9 -0
  48. data/spec/test_app/app/assets/stylesheets/application.css +7 -0
  49. data/spec/test_app/app/controllers/application_controller.rb +3 -0
  50. data/spec/test_app/app/helpers/application_helper.rb +2 -0
  51. data/spec/test_app/app/mailers/.gitkeep +0 -0
  52. data/spec/test_app/app/models/.gitkeep +0 -0
  53. data/spec/test_app/app/models/nobel_prize.rb +3 -0
  54. data/spec/test_app/app/models/nobel_prize_winner.rb +3 -0
  55. data/spec/test_app/app/views/layouts/application.html.erb +14 -0
  56. data/spec/test_app/config/application.rb +48 -0
  57. data/spec/test_app/config/boot.rb +6 -0
  58. data/spec/test_app/config/database.yml +25 -0
  59. data/spec/test_app/config/environment.rb +5 -0
  60. data/spec/test_app/config/environments/development.rb +30 -0
  61. data/spec/test_app/config/environments/production.rb +60 -0
  62. data/spec/test_app/config/environments/test.rb +42 -0
  63. data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
  64. data/spec/test_app/config/initializers/inflections.rb +10 -0
  65. data/spec/test_app/config/initializers/mime_types.rb +5 -0
  66. data/spec/test_app/config/initializers/secret_token.rb +7 -0
  67. data/spec/test_app/config/initializers/session_store.rb +8 -0
  68. data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
  69. data/spec/test_app/config/locales/en.yml +5 -0
  70. data/spec/test_app/config/routes.rb +58 -0
  71. data/spec/test_app/config.ru +4 -0
  72. data/spec/test_app/db/migrate/20111007154222_create_nobel_prize_winners.rb +30 -0
  73. data/spec/test_app/db/migrate/20111010191626_create_nobel_prizes.rb +34 -0
  74. data/spec/test_app/db/schema.rb +27 -0
  75. data/spec/test_app/db/seeds.rb +7 -0
  76. data/spec/test_app/db/test.sqlite3 +0 -0
  77. data/spec/test_app/doc/README_FOR_APP +2 -0
  78. data/spec/test_app/lib/assets/.gitkeep +0 -0
  79. data/spec/test_app/lib/tasks/.gitkeep +0 -0
  80. data/spec/test_app/log/.gitkeep +0 -0
  81. data/spec/test_app/public/404.html +26 -0
  82. data/spec/test_app/public/422.html +26 -0
  83. data/spec/test_app/public/500.html +26 -0
  84. data/spec/test_app/public/favicon.ico +0 -0
  85. data/spec/test_app/public/index.html +241 -0
  86. data/spec/test_app/public/robots.txt +5 -0
  87. data/spec/test_app/script/rails +6 -0
  88. data/spec/test_app/vendor/assets/stylesheets/.gitkeep +0 -0
  89. data/spec/test_app/vendor/plugins/.gitkeep +0 -0
  90. data/spec/utils_spec.rb +11 -0
  91. data/tableficate.gemspec +26 -0
  92. metadata +245 -0
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in tablificate.gemspec
4
+ gemspec
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,4 @@
1
+ <div>
2
+ <%= tableficate_label_tag(filter) %>
3
+ <%= tableficate_text_field_tag(filter) %>
4
+ </div>
@@ -0,0 +1,6 @@
1
+ <div>
2
+ <%= tableficate_label_tag(filter.start) %>
3
+ <%= tableficate_text_field_tag(filter.start) %>
4
+ <%= tableficate_label_tag(filter.stop) %>
5
+ <%= tableficate_text_field_tag(filter.stop) %>
6
+ </div>
@@ -0,0 +1,5 @@
1
+ <tr>
2
+ <% columns.each do |column| %>
3
+ <%= tableficate_data_tag row, column %>
4
+ <% end %>
5
+ </tr>
@@ -0,0 +1,4 @@
1
+ <div>
2
+ <%= tableficate_label_tag(filter) %>
3
+ <%= tableficate_select_tag(filter) %>
4
+ </div>
@@ -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 %>
@@ -0,0 +1,2 @@
1
+ ## 0.1.0
2
+ * initial release
@@ -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,5 @@
1
+ class <%= class_name %> < Tableficate::Base
2
+ <% if scope -%>
3
+ scope :<%= scope.tableize %>
4
+ <% end -%>
5
+ 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,15 @@
1
+ module Tableficate
2
+ class ActionColumn < Column
3
+ def initialize(table, options = {}, block)
4
+ super(table, '', options, &block)
5
+ end
6
+
7
+ def show_sort?
8
+ false
9
+ end
10
+
11
+ def is_sorted?(dir = nil)
12
+ false
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,4 @@
1
+ module Tableficate
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module Tableficate
2
+ class MissingScope < StandardError; end
3
+ 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,11 @@
1
+ module Tableficate
2
+ class SelectFilter < Filter
3
+ attr_reader :choices
4
+
5
+ def initialize(table, name, choices, options = {})
6
+ super(table, name, options)
7
+
8
+ @choices = choices
9
+ end
10
+ end
11
+ 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