iquest-simple_table 0.3.6 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.ruby-version +1 -1
- data/bench/.ruby-version +1 -0
- data/bench/bench.rb +136 -0
- data/bench/templates/kaminari/_paginator.html.erb +0 -0
- data/bench/templates/simple_table.html.erb +10 -0
- data/bench/templates/table.html.erb +15 -0
- data/iquest-simple_table.gemspec +4 -2
- data/lib/iquest/simple_table/attribute_description.rb +2 -4
- data/lib/iquest/simple_table/table_builder.rb +174 -222
- data/lib/iquest/simple_table/table_helper.rb +2 -2
- data/lib/iquest/simple_table/version.rb +1 -1
- metadata +37 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45e5c0239f2c37302736ee01e5bd1465eea65bf2
|
4
|
+
data.tar.gz: b9172276ac0091318da04c4be5ff4a131f195c87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5290739813210936128ea1be2e03298e431d74b9b973ed1745ed75cdf05da38457165ee89040f10a6ce51107981e54bd1bb25abd59a01983a3c547cda539eda
|
7
|
+
data.tar.gz: ec02416131cbafd96908be1eddd0fd968c945bfd062497db3093fdbd45e6412ff8eea1c3f390b28dbb426bd36d24761872e2ca2941ee27fac26b666fc2a78db5
|
data/.rubocop.yml
ADDED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.2.7
|
data/bench/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.2
|
data/bench/bench.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'bundler/inline'
|
6
|
+
rescue LoadError => e
|
7
|
+
$stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler'
|
8
|
+
raise e
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'optparse'
|
12
|
+
|
13
|
+
options = {}
|
14
|
+
OptionParser.new do |opts|
|
15
|
+
opts.banner = "Usage: bench.rb [options]"
|
16
|
+
|
17
|
+
opts.on("-m", "--[no-]mem", "Memory profile") do |v|
|
18
|
+
options[:mem] = v
|
19
|
+
end
|
20
|
+
opts.on("-b", "--[no-]bench", "Benchmark IPS") do |v|
|
21
|
+
options[:bench] = v
|
22
|
+
end
|
23
|
+
opts.on("-t", "--[no-]time", "Method timing") do |v|
|
24
|
+
options[:time] = v
|
25
|
+
end
|
26
|
+
end.parse!
|
27
|
+
|
28
|
+
gemfile(true) do
|
29
|
+
source 'https://rubygems.org'
|
30
|
+
|
31
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
32
|
+
|
33
|
+
# Activate the gem you are reporting the issue against.
|
34
|
+
gem 'rails', '5.2.0'
|
35
|
+
gem 'activerecord', '5.2.0'
|
36
|
+
gem 'benchmark-ips'
|
37
|
+
gem 'kaminari'
|
38
|
+
gem 'memory_profiler'
|
39
|
+
gem 'ransack', '1.8.8', require: false
|
40
|
+
gem 'iquest-simple_table', path: '../', require: false
|
41
|
+
gem 'timeasure'
|
42
|
+
end
|
43
|
+
|
44
|
+
require 'rails/all'
|
45
|
+
|
46
|
+
class BenchApp < Rails::Application
|
47
|
+
config.root = __dir__
|
48
|
+
config.session_store :cookie_store, key: 'cookie_store_key'
|
49
|
+
secrets.secret_key_base = 'secret_key_base'
|
50
|
+
|
51
|
+
config.logger = Logger.new($stdout)
|
52
|
+
Rails.logger = config.logger
|
53
|
+
end
|
54
|
+
|
55
|
+
require 'iquest/simple_table'
|
56
|
+
|
57
|
+
class ApplicationController < ActionController::Base
|
58
|
+
layout false
|
59
|
+
prepend_view_path('templates')
|
60
|
+
end
|
61
|
+
|
62
|
+
class Foo
|
63
|
+
include ActiveModel::Model
|
64
|
+
ATTRIBUTES = %i(a b c d e f g h).freeze
|
65
|
+
attr_accessor *ATTRIBUTES
|
66
|
+
delegate :each, :map, to: :attributes
|
67
|
+
|
68
|
+
def attributes
|
69
|
+
ATTRIBUTES.map { |a| send(a) }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def render(template, **assigns)
|
74
|
+
ApplicationController.render(
|
75
|
+
template: template.to_s,
|
76
|
+
layout: nil,
|
77
|
+
locals: assigns
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def memory_profile(title)
|
82
|
+
report = MemoryProfiler.report(top: 10, ingnore_files: /memory_profiler/) do
|
83
|
+
yield
|
84
|
+
end
|
85
|
+
puts '=' * 80
|
86
|
+
puts title
|
87
|
+
puts '=' * 80
|
88
|
+
report.pretty_print
|
89
|
+
end
|
90
|
+
|
91
|
+
today = Date.today
|
92
|
+
now = Time.now
|
93
|
+
collection = Array.new(100) { Foo.new(a: 0, b: 1, c: 2, d: 3, e: 4, f: 5, g: today, h: now) }
|
94
|
+
table = Kaminari.paginate_array(collection).page(1).per(100)
|
95
|
+
|
96
|
+
if options[:mem]
|
97
|
+
memory_profile 'table' do
|
98
|
+
render 'table', table: table
|
99
|
+
end
|
100
|
+
|
101
|
+
memory_profile 'simple_table' do
|
102
|
+
render 'simple_table', table: table
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if options[:bench]
|
107
|
+
Benchmark.ips do |x|
|
108
|
+
x.report('table') { render 'table', table: table }
|
109
|
+
x.report('simple_table') { render 'simple_table', table: table }
|
110
|
+
|
111
|
+
x.compare!
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if options[:time]
|
116
|
+
require 'timeasure'
|
117
|
+
|
118
|
+
module Iquest
|
119
|
+
module SimpleTable
|
120
|
+
class TableBuilder
|
121
|
+
include Timeasure
|
122
|
+
tracked_instance_methods :to_s
|
123
|
+
tracked_private_instance_methods :render_table_row, :attr_class
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
require 'pp'
|
129
|
+
|
130
|
+
Timeasure::Profiling::Manager.prepare
|
131
|
+
render 'simple_table', table: table
|
132
|
+
report = Timeasure::Profiling::Manager.export
|
133
|
+
report.each do |item|
|
134
|
+
pp item
|
135
|
+
end
|
136
|
+
end
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
<table>
|
3
|
+
<% table.each do |row| %>
|
4
|
+
<tr>
|
5
|
+
<td><%= row.a %></td>
|
6
|
+
<td><%= row.b %></td>
|
7
|
+
<td><%= row.c %></td>
|
8
|
+
<td><%= row.d %></td>
|
9
|
+
<td><%= row.e %></td>
|
10
|
+
<td><%= row.f %></td>
|
11
|
+
<td><%= l(row.g) %></td>
|
12
|
+
<td><%= l(row.h) %></td>
|
13
|
+
</tr>
|
14
|
+
<% end %>
|
15
|
+
</table>
|
data/iquest-simple_table.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Iquest::SimpleTable::VERSION
|
9
9
|
spec.authors = ["Pavel Dusanek"]
|
10
10
|
spec.email = ["dusanek@iquest.cz"]
|
11
|
-
spec.description =
|
12
|
-
spec.summary =
|
11
|
+
spec.description = "Simple table helper"
|
12
|
+
spec.summary = "Simple table helper, taht supports filtering through Ransack"
|
13
13
|
spec.homepage = "https://github.com/iquest/iquest-simple_table"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -21,4 +21,6 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_runtime_dependency 'ransack_simple_form', '>= 0.1.0'
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.3"
|
23
23
|
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "relaxed-rubocop"
|
25
|
+
spec.add_development_dependency "rubocop"
|
24
26
|
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
module Iquest
|
2
2
|
module SimpleTable
|
3
3
|
module AttributeDescription
|
4
|
-
|
5
4
|
def human_attribute_description(attribute, options = {})
|
6
5
|
parts = attribute.to_s.split(".")
|
7
6
|
attribute = parts.pop
|
8
7
|
namespace = parts.join("/") unless parts.empty?
|
9
|
-
attributes_scope = "#{
|
8
|
+
attributes_scope = "#{i18n_scope}.descriptions"
|
10
9
|
|
11
10
|
if namespace
|
12
11
|
defaults = lookup_ancestors.map do |klass|
|
@@ -24,7 +23,6 @@ module Iquest
|
|
24
23
|
options[:default] = ''
|
25
24
|
I18n.translate(defaults.shift, options)
|
26
25
|
end
|
27
|
-
|
28
26
|
end
|
29
27
|
end
|
30
|
-
end
|
28
|
+
end
|
@@ -8,6 +8,19 @@ module Iquest
|
|
8
8
|
delegate :sort_link, :search_form_for, to: :parent
|
9
9
|
delegate :polymorphic_path, :polymorphic_url, to: :parent
|
10
10
|
delegate :l, :t, :dom_id, to: :parent
|
11
|
+
delegate :render, :render_to_string, to: :parent
|
12
|
+
CLASS_DELIMITER = ' '.freeze
|
13
|
+
EMPTY_STRING = ''.freeze
|
14
|
+
DEFAULT_FORMATTER = ->(value) do
|
15
|
+
case value
|
16
|
+
when Time
|
17
|
+
l(value)
|
18
|
+
when Date
|
19
|
+
l(value)
|
20
|
+
else
|
21
|
+
value
|
22
|
+
end
|
23
|
+
end
|
11
24
|
|
12
25
|
def initialize(parent, collection_or_search, options = {})
|
13
26
|
@parent = parent
|
@@ -18,208 +31,146 @@ module Iquest
|
|
18
31
|
elsif collection_or_search.is_a?(ActiveRecord::Relation) || collection_or_search.is_a?(ActiveRecord::AssociationRelation)
|
19
32
|
@collection = collection_or_search
|
20
33
|
@klass = @collection.klass
|
21
|
-
elsif collection_or_search.is_a?(Array) && (search = collection_or_search.detect {|o| o.is_a?(Ransack::Search)})
|
34
|
+
elsif collection_or_search.is_a?(Array) && (search = collection_or_search.detect { |o| o.is_a?(Ransack::Search) })
|
22
35
|
@search = search
|
23
36
|
@collection = search.result
|
24
37
|
@klass = @collection.klass
|
25
|
-
options[:search_url] ||= polymorphic_path(collection_or_search.map {|o| o.is_a?(Ransack::Search) ? o.klass : o})
|
26
|
-
elsif collection_or_search.is_a?(Array) && (collection = collection_or_search.detect {|o| o.is_a?(ActiveRecord::Relation) || o.is_a?(ActiveRecord::AssociationRelation)})
|
38
|
+
options[:search_url] ||= polymorphic_path(collection_or_search.map { |o| o.is_a?(Ransack::Search) ? o.klass : o })
|
39
|
+
elsif collection_or_search.is_a?(Array) && (collection = collection_or_search.detect { |o| o.is_a?(ActiveRecord::Relation) || o.is_a?(ActiveRecord::AssociationRelation) })
|
27
40
|
@collection = collection
|
28
41
|
@klass = @collection.klass
|
29
42
|
elsif collection_or_search.is_a?(Array) && (collection_or_search.any? || options[:class])
|
30
43
|
@collection = collection_or_search
|
31
44
|
@klass = options[:class] || collection_or_search.first.class
|
32
|
-
else
|
45
|
+
else
|
33
46
|
raise TypeError, 'ActiveRecord::Relation, ActiveRecord::AssociationRelation, Ransack::Search or Array of ActiveModel like objects expected'
|
34
47
|
end
|
35
48
|
apply_pagination
|
36
|
-
#draper
|
49
|
+
# draper
|
37
50
|
@collection = @collection.decorate if @collection.respond_to?(:decorate)
|
38
|
-
options[:search_url] ||=
|
51
|
+
options[:search_url] ||= begin
|
52
|
+
polymorphic_path(@klass)
|
53
|
+
rescue NoMethodError
|
54
|
+
nil
|
55
|
+
end
|
39
56
|
@options = options
|
40
57
|
@table_id = "table_#{@klass}".pluralize.parameterize
|
41
58
|
@columns = {}.with_indifferent_access
|
42
59
|
@actions = []
|
43
60
|
@collection_actions = []
|
44
|
-
@search_input_default_options = {label: false, placeholder: false}.with_indifferent_access
|
61
|
+
@search_input_default_options = { label: false, placeholder: false }.with_indifferent_access
|
62
|
+
@attr_classes = {}
|
45
63
|
end
|
46
64
|
|
47
65
|
def column(*args, &block)
|
48
66
|
attr = args.first
|
49
67
|
options = args.extract_options!
|
50
|
-
search = options.delete(:search)
|
68
|
+
search = options.delete(:search)
|
51
69
|
@columns[attr] = options
|
52
70
|
@columns[attr][:label] ||= column_label(attr)
|
53
|
-
#iniciaizce search options
|
71
|
+
# iniciaizce search options
|
54
72
|
if search.is_a?(Symbol) || search.is_a?(String)
|
55
|
-
@columns[attr][:search] = {search.to_sym => {}}
|
73
|
+
@columns[attr][:search] = { search.to_sym => {} }
|
56
74
|
elsif search.is_a? Array
|
57
|
-
@columns[attr][:search] = search.
|
75
|
+
@columns[attr][:search] = search.each_with_object({}) { |s, h| h[s.to_sym] = {}; }
|
58
76
|
elsif search.is_a? Hash
|
59
77
|
@columns[attr][:search] = search
|
60
78
|
end
|
61
|
-
@columns[attr][:formatter] ||= block
|
62
|
-
@columns[attr][:sort] ||= attr.to_s.tr('.','_') unless @columns[attr][:sort] == false #sort link attr
|
79
|
+
@columns[attr][:formatter] ||= block_given? ? block : DEFAULT_FORMATTER
|
80
|
+
@columns[attr][:sort] ||= attr.to_s.tr('.', '_') unless @columns[attr][:sort] == false # sort link attr
|
63
81
|
@columns[attr][:html] ||= {}
|
82
|
+
@columns[attr][:html][:class] = @columns[attr][:html][:class].join(CLASS_DELIMITER) if @columns[attr][:html][:class].is_a?(Array)
|
83
|
+
@columns[attr][:html][:class] ||= ''
|
64
84
|
end
|
65
85
|
|
66
86
|
def action(*args, &block)
|
67
|
-
|
87
|
+
_action = args.first
|
68
88
|
options = args.extract_options!
|
69
89
|
options[:proc] = block if block_given?
|
70
90
|
@actions << options
|
71
91
|
end
|
72
92
|
|
73
|
-
def collection_action(*args
|
93
|
+
def collection_action(*args)
|
74
94
|
action = args.first
|
75
95
|
if action.is_a? String
|
76
96
|
@collection_actions << action
|
77
97
|
elsif block_given?
|
78
|
-
@collection_actions <<
|
79
|
-
end
|
98
|
+
@collection_actions << yield
|
99
|
+
end
|
80
100
|
end
|
81
101
|
|
82
|
-
def new_link(*
|
102
|
+
def new_link(*_args)
|
83
103
|
ActiveSupport::Deprecation.warn("Iquest::SimpleTable#new_link does nothing. Use collection_action")
|
84
104
|
end
|
85
105
|
|
86
|
-
def search_link(*
|
106
|
+
def search_link(*_args, &block)
|
87
107
|
@search_button = block if block_given?
|
88
108
|
end
|
89
109
|
|
90
|
-
def reset_link(*
|
110
|
+
def reset_link(*_args, &block)
|
91
111
|
@reset_button = block if block_given?
|
92
112
|
end
|
93
113
|
|
114
|
+
WRAPPER_TEMPLATE = '<div class="filter-table-block">
|
115
|
+
<%= content %>
|
116
|
+
<div class="paginate-block"><%= paginate @collection if @collection.respond_to?(:current_page) %></div>
|
117
|
+
<div class="totals-block"><%= page_entries_info @collection, entry_name: @klass.model_name.human if @collection.respond_to?(:current_page) %></div>
|
118
|
+
</div>'.freeze
|
119
|
+
WRAPPER_ERB = ERB.new(WRAPPER_TEMPLATE)
|
120
|
+
|
94
121
|
def to_s
|
95
|
-
|
96
|
-
|
97
|
-
render_table_with_search
|
98
|
-
end
|
99
|
-
else
|
100
|
-
content_tag :div, '', class: 'filter-table-block' do
|
101
|
-
render_table_without_search
|
102
|
-
end
|
103
|
-
end
|
122
|
+
content = render_table
|
123
|
+
WRAPPER_ERB.result(binding).html_safe
|
104
124
|
end
|
105
125
|
|
106
126
|
private
|
107
|
-
def render_table_without_search
|
108
|
-
table = content_tag :table, id: @table_id, class: @options[:html][:class] << %w(table table-hover table-striped) do
|
109
|
-
render_table_header + render_table_body + render_table_footer
|
110
|
-
end
|
111
|
-
|
112
|
-
out = if @options[:responsive]
|
113
|
-
content_tag :div, class: 'table-responsive' do
|
114
|
-
table
|
115
|
-
end
|
116
|
-
else
|
117
|
-
table
|
118
|
-
end
|
119
|
-
|
120
|
-
out + render_pagination + render_footer_actions
|
121
|
-
end
|
122
127
|
|
128
|
+
TABLE_TEMPLATE = '
|
129
|
+
<% if @options[:responsive] %><div class="table-responsive"><%end%>
|
130
|
+
<table id="<%= @table_id %>" class="<%= @options[:html][:class].join(CLASS_DELIMITER) %> table table-hover table-striped">
|
131
|
+
<thead>
|
132
|
+
<tr class="labels">
|
133
|
+
<th class="collection-actions"><%= @collection_actions.join %></th>
|
134
|
+
<% columns.each do |attr, options| %>
|
135
|
+
<%= content_tag :th, class: options[:class], data: options[:data] do
|
136
|
+
render_label(attr)
|
137
|
+
end %>
|
138
|
+
<% end %>
|
139
|
+
<% if @search %>
|
140
|
+
<%= render_search_inputs %>
|
141
|
+
<% end %>
|
142
|
+
</tr>
|
143
|
+
</thead>
|
144
|
+
<tbody class="rowlink" data-link="row" data-target="a.rowlink">
|
145
|
+
<% collection.each do |item| %>
|
146
|
+
<%= render_table_row(item) %>
|
147
|
+
<% end %>
|
148
|
+
</tbody>
|
149
|
+
<tfoot class=""><tr class=""></tr></tfoot>
|
150
|
+
</table>
|
151
|
+
<% if @options[:responsive] %></div><%end%>
|
152
|
+
'.freeze
|
153
|
+
TABLE_ERB = ERB.new(TABLE_TEMPLATE)
|
123
154
|
include RansackSimpleForm::FormHelper
|
124
155
|
|
125
|
-
def
|
126
|
-
|
127
|
-
@
|
128
|
-
|
129
|
-
|
130
|
-
end
|
131
|
-
|
132
|
-
def render_table_header
|
133
|
-
content_tag :thead, class: 'header' do
|
134
|
-
render_column_labels + render_search_inputs
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def render_column_labels
|
139
|
-
content_tag :tr, class:'labels' do
|
140
|
-
rendered_columns = columns.map do |col, opts|
|
141
|
-
render_column_label(col)
|
142
|
-
end.join.html_safe
|
143
|
-
render_collection_actions + rendered_columns
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def render_collection_actions
|
148
|
-
content_tag :th, class:'collection-actions' do
|
149
|
-
@collection_actions.join.html_safe
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def render_search_inputs
|
154
|
-
return '' unless @search
|
155
|
-
content_tag :tr, class:'filters' do
|
156
|
-
rendered_columns = columns.map do |col, opts|
|
157
|
-
render_column_search_inputs(col, opts)
|
158
|
-
end.join.html_safe
|
159
|
-
render_buttons + rendered_columns
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
def render_column_search_inputs(column, options)
|
164
|
-
content_tag :th, class: options[:class], data: options[:data] do
|
165
|
-
if options[:search]
|
166
|
-
options[:search].map do |search, options|
|
167
|
-
render_search_input(search, options)
|
168
|
-
end.join.html_safe
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
def render_search_input(search, options = {})
|
174
|
-
input_options = @search_input_default_options.merge(options).symbolize_keys
|
175
|
-
search_form.input search.dup, input_options
|
176
|
-
end
|
177
|
-
|
178
|
-
def render_buttons
|
179
|
-
content_tag :th, class:'search-action' do
|
180
|
-
out = content_tag :div, class:'btn-group' do
|
181
|
-
link_to(t('simple_table.reset', default: 'reset').html_safe, '?' , class: 'search-reset btn btn-default') +
|
182
|
-
search_form.button( :submit, t('simple_table.search', default: 'search').html_safe, class: 'search-button btn btn-default')
|
156
|
+
def render_table
|
157
|
+
if @search
|
158
|
+
ransack_simple_form_for @search, url: @options[:search_url] do |f|
|
159
|
+
@search_form = f
|
160
|
+
TABLE_ERB.result(binding).html_safe
|
183
161
|
end
|
184
|
-
|
185
|
-
|
186
|
-
end
|
187
|
-
|
188
|
-
def render_table_body
|
189
|
-
content_tag :tbody, class: 'rowlink', data: {link: 'row', target: 'a.rowlink'} do
|
190
|
-
collection.map do |item|
|
191
|
-
render_table_row(item)
|
192
|
-
end.join.html_safe
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def render_table_row(item)
|
197
|
-
row_id = "row_#{dom_id(item)}" rescue nil
|
198
|
-
content_tag :tr, id: row_id do
|
199
|
-
rendered_columns = columns.map do |col|
|
200
|
-
render_value_cell(col, item)
|
201
|
-
end.join.html_safe
|
202
|
-
render_actions(item) + rendered_columns
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
|
207
|
-
def render_column_label(column)
|
208
|
-
options = @columns[column]
|
209
|
-
|
210
|
-
content_tag :th, class: options[:class], data: options[:data] do
|
211
|
-
render_label(column)
|
162
|
+
else
|
163
|
+
TABLE_ERB.result(binding).html_safe
|
212
164
|
end
|
213
165
|
end
|
214
166
|
|
215
|
-
def render_label(
|
216
|
-
attr = column
|
167
|
+
def render_label(attr)
|
217
168
|
options = @columns[attr]
|
218
169
|
label = options[:label] || attr.to_s
|
219
|
-
sort = options[:sort]
|
170
|
+
sort = options[:sort]
|
220
171
|
if @search && sort
|
221
172
|
sort_attr = attr
|
222
|
-
sort_options = {}
|
173
|
+
sort_options = {}
|
223
174
|
if sort.is_a?(Hash)
|
224
175
|
sort_attr = sort.keys.first
|
225
176
|
sort_options = sort[sort_attr]
|
@@ -234,130 +185,132 @@ module Iquest
|
|
234
185
|
end
|
235
186
|
end
|
236
187
|
|
237
|
-
def
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
cell_value = render_value(obj, value, &formatter)
|
245
|
-
cell_classes = []
|
246
|
-
cell_classes << "rowlink-skip" if include_link?(cell_value)
|
247
|
-
cell_classes << "#{options[:html][:class]}"
|
248
|
-
content_tag :td, class: cell_classes do
|
249
|
-
"#{cell_value}".html_safe
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
def get_value(attr, obj)
|
254
|
-
if attr.is_a? Symbol
|
255
|
-
obj.try(attr)
|
256
|
-
elsif attr.is_a? String
|
257
|
-
attr.split('.').inject(obj, :try)
|
188
|
+
def render_search_inputs
|
189
|
+
return EMPTY_STRING unless @search
|
190
|
+
content_tag :tr, class: 'filters' do
|
191
|
+
rendered_columns = columns.map do |col, opts|
|
192
|
+
render_column_search_inputs(col, opts)
|
193
|
+
end.join.html_safe
|
194
|
+
render_buttons + rendered_columns
|
258
195
|
end
|
259
196
|
end
|
260
197
|
|
261
|
-
def
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
value = args.second
|
268
|
-
if block_given?
|
269
|
-
case block.arity
|
270
|
-
when 1
|
271
|
-
block.call(value)
|
272
|
-
when 2
|
273
|
-
block.call(object, value)
|
274
|
-
else
|
275
|
-
block.call
|
198
|
+
def render_column_search_inputs(_column, options)
|
199
|
+
content_tag :th, class: options[:class], data: options[:data] do
|
200
|
+
if options[:search]
|
201
|
+
options[:search].map do |search, opts|
|
202
|
+
render_search_input(search, opts)
|
203
|
+
end.join.html_safe
|
276
204
|
end
|
277
|
-
else
|
278
|
-
format_value(value)
|
279
205
|
end
|
280
|
-
|
281
206
|
end
|
282
207
|
|
283
|
-
def
|
284
|
-
|
285
|
-
|
286
|
-
l(value)
|
287
|
-
when Date
|
288
|
-
l(value)
|
289
|
-
else
|
290
|
-
value
|
291
|
-
end
|
208
|
+
def render_search_input(search, options = {})
|
209
|
+
input_options = @search_input_default_options.merge(options).symbolize_keys
|
210
|
+
search_form.input search.dup, input_options
|
292
211
|
end
|
293
212
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
end
|
300
|
-
end
|
213
|
+
BUTTONS_TEMPLATE = %q(<th class="search-action"><div class="btn-group">
|
214
|
+
<%= link_to(t('simple_table.reset', default: 'reset').html_safe, '?', class: 'search-reset btn btn-default') %>
|
215
|
+
<%= search_form.button( :submit, t('simple_table.search', default: 'search').html_safe, class: 'search-button btn btn-default') %>
|
216
|
+
</div></th>).freeze # FIXME change link_to url
|
217
|
+
BUTTONS_ERB = ERB.new(BUTTONS_TEMPLATE)
|
301
218
|
|
302
|
-
def
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
219
|
+
def render_buttons
|
220
|
+
BUTTONS_ERB.result(binding).html_safe
|
221
|
+
end
|
222
|
+
|
223
|
+
ROWLINK_SKIP = 'rowlink-skip'.freeze
|
224
|
+
TR_TEMPLATE = '<tr id="<%= row_id %>"><%= actions %>
|
225
|
+
<% columns.each do |attr, options| %>
|
226
|
+
<%
|
227
|
+
options = columns[attr]
|
228
|
+
value = get_value(attr, object)
|
229
|
+
html_class = options[:html][:class]
|
230
|
+
html_class << " #{ROWLINK_SKIP}" if include_link?(value)
|
231
|
+
%>
|
232
|
+
<td class="<%= html_class %>"><%= value %></td>
|
233
|
+
<% end %>
|
234
|
+
</tr>'.freeze
|
235
|
+
TR_ERB = ERB.new(TR_TEMPLATE)
|
236
|
+
|
237
|
+
def render_table_row(object)
|
238
|
+
row_id = begin
|
239
|
+
"row_#{dom_id(object)}"
|
240
|
+
rescue StandardError
|
241
|
+
nil
|
242
|
+
end
|
243
|
+
actions = render_actions(object)
|
244
|
+
TR_ERB.result(binding).html_safe
|
245
|
+
end
|
246
|
+
|
247
|
+
METHOD_DELIMITER = '.'.freeze
|
307
248
|
|
308
|
-
def
|
309
|
-
|
310
|
-
|
311
|
-
|
249
|
+
def get_value(attr, obj)
|
250
|
+
value = if attr.is_a? Symbol
|
251
|
+
obj.send(attr) if obj.respond_to?(attr)
|
252
|
+
elsif attr.is_a? String
|
253
|
+
attr.split(METHOD_DELIMITER).inject(obj, :try)
|
254
|
+
end
|
255
|
+
formatter = @columns[attr][:formatter] || DEFAULT_FORMATTER
|
256
|
+
case formatter.arity
|
257
|
+
when 1
|
258
|
+
parent.instance_exec value, &formatter
|
259
|
+
when 2
|
260
|
+
parent.instance_exec obj, value, &formatter
|
261
|
+
else
|
262
|
+
parent.instance_exec(&formatter)
|
312
263
|
end
|
313
264
|
end
|
314
265
|
|
315
|
-
|
316
|
-
content_tag :div, '', class: 'paginate-block' do
|
317
|
-
paginate @collection if @collection.respond_to?(:current_page)
|
318
|
-
end
|
319
|
-
|
320
|
-
end
|
266
|
+
LINK_PATTERN = '<a'.freeze
|
321
267
|
|
322
|
-
def
|
323
|
-
|
324
|
-
|
325
|
-
end
|
268
|
+
def include_link?(string)
|
269
|
+
return false unless string.is_a?(String)
|
270
|
+
string.include?(LINK_PATTERN)
|
326
271
|
end
|
327
272
|
|
328
|
-
|
329
|
-
|
273
|
+
ACTIONS_TEMPLATE = '<td class="rowlink-skip">
|
274
|
+
<% @actions.each do |action|
|
275
|
+
<%= options[:proc].call(obj) if options[:proc].is_a? Proc %>
|
276
|
+
</td>'
|
330
277
|
|
278
|
+
def render_actions(item)
|
279
|
+
content_tag :td, class: 'rowlink-skip' do
|
280
|
+
@actions.map do |action|
|
281
|
+
render_action(item, action)
|
282
|
+
end.join.html_safe
|
283
|
+
end
|
331
284
|
end
|
332
285
|
|
333
|
-
def
|
334
|
-
|
286
|
+
def render_action(obj, **options)
|
287
|
+
options[:proc].call(obj) if options[:proc].is_a? Proc
|
335
288
|
end
|
336
289
|
|
337
|
-
def column_label(attr)
|
290
|
+
def column_label(attr)
|
338
291
|
if attr_class(attr).respond_to?(:human_attribute_name)
|
339
292
|
attr_class(attr).try(:human_attribute_name, attr)
|
340
293
|
elsif @search
|
341
|
-
Ransack::Translate.attribute(attr.to_s.tr(
|
294
|
+
Ransack::Translate.attribute(attr.to_s.tr(METHOD_DELIMITER, '_'), context: @search.context)
|
342
295
|
else
|
343
296
|
attr.to_s.humanize
|
344
297
|
end
|
345
|
-
end
|
298
|
+
end
|
346
299
|
|
347
300
|
def description(attr)
|
348
|
-
|
349
|
-
|
350
|
-
end
|
301
|
+
return ''.html_safe unless attr_class(attr).respond_to?(:human_attribute_description)
|
302
|
+
description = attr_class(attr).try(:human_attribute_description, attr)
|
351
303
|
if description.present?
|
352
304
|
"<div class=\"description\">#{description}</div>".html_safe
|
353
305
|
else
|
354
|
-
|
306
|
+
''.html_safe
|
355
307
|
end
|
356
308
|
end
|
357
309
|
|
358
310
|
def attr_class(attr)
|
359
|
-
attr
|
360
|
-
|
311
|
+
return @attr_classes[attr] if @attr_classes.key?(attr)
|
312
|
+
@attr_classes[attr] ||= attr.to_s.split(METHOD_DELIMITER)[0..-2].inject(@klass) { |klass, assoc| klass.try(:reflect_on_association, assoc).try(:klass) }
|
313
|
+
end
|
361
314
|
|
362
315
|
def column_count
|
363
316
|
@columns.count
|
@@ -372,7 +325,6 @@ module Iquest
|
|
372
325
|
def search_action
|
373
326
|
:get
|
374
327
|
end
|
375
|
-
|
376
328
|
end
|
377
329
|
end
|
378
330
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iquest-simple_table
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pavel Dusanek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ransack_simple_form
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: relaxed-rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
55
83
|
description: Simple table helper
|
56
84
|
email:
|
57
85
|
- dusanek@iquest.cz
|
@@ -60,11 +88,17 @@ extensions: []
|
|
60
88
|
extra_rdoc_files: []
|
61
89
|
files:
|
62
90
|
- ".gitignore"
|
91
|
+
- ".rubocop.yml"
|
63
92
|
- ".ruby-version"
|
64
93
|
- Gemfile
|
65
94
|
- LICENSE.txt
|
66
95
|
- README.md
|
67
96
|
- Rakefile
|
97
|
+
- bench/.ruby-version
|
98
|
+
- bench/bench.rb
|
99
|
+
- bench/templates/kaminari/_paginator.html.erb
|
100
|
+
- bench/templates/simple_table.html.erb
|
101
|
+
- bench/templates/table.html.erb
|
68
102
|
- config/locale/en.yml
|
69
103
|
- iquest-simple_table.gemspec
|
70
104
|
- lib/iquest/simple_table.rb
|
@@ -92,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
126
|
version: '0'
|
93
127
|
requirements: []
|
94
128
|
rubyforge_project:
|
95
|
-
rubygems_version: 2.
|
129
|
+
rubygems_version: 2.4.5.2
|
96
130
|
signing_key:
|
97
131
|
specification_version: 4
|
98
132
|
summary: Simple table helper, taht supports filtering through Ransack
|