tabulatr 0.0.1
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/.gitignore +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +106 -0
- data/LICENSE +23 -0
- data/README.textile +284 -0
- data/Rakefile +11 -0
- data/assets/simple_table.png +0 -0
- data/assets/tabulatr.css +107 -0
- data/lib/initializers/action_view.rb +31 -0
- data/lib/initializers/active_record.rb +32 -0
- data/lib/initializers/mark_as_localizable.rb +43 -0
- data/lib/initializers/mongoid.rb +34 -0
- data/lib/tabulatr/tabulatr/batch_actions.rb +52 -0
- data/lib/tabulatr/tabulatr/check_controls.rb +43 -0
- data/lib/tabulatr/tabulatr/data_cell.rb +118 -0
- data/lib/tabulatr/tabulatr/filter_cell.rb +130 -0
- data/lib/tabulatr/tabulatr/finder/find_for_active_record_table.rb +162 -0
- data/lib/tabulatr/tabulatr/finder/find_for_mongoid_table.rb +116 -0
- data/lib/tabulatr/tabulatr/finder.rb +82 -0
- data/lib/tabulatr/tabulatr/formattr.rb +51 -0
- data/lib/tabulatr/tabulatr/header_cell.rb +94 -0
- data/lib/tabulatr/tabulatr/paginator.rb +88 -0
- data/lib/tabulatr/tabulatr/row_builder.rb +115 -0
- data/lib/tabulatr/tabulatr/settings.rb +221 -0
- data/lib/tabulatr/tabulatr.rb +238 -0
- data/lib/tabulatr.rb +34 -0
- data/tabulatr.gemspec +26 -0
- metadata +143 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following 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 OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
# buggy like hell
|
25
|
+
if Object.const_defined? "Mongoid"
|
26
|
+
raise "Mongoid support is buggy like hell as of now"
|
27
|
+
module Mongoid::Document
|
28
|
+
module ClassMethods
|
29
|
+
def find_for_table(params, opts={}, &block)
|
30
|
+
Tabulatr.find_for_mongoid_table(self, params, opts, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following 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 OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
class Tabulatr
|
25
|
+
|
26
|
+
# render the select tag for batch actions
|
27
|
+
def render_batch_actions
|
28
|
+
make_tag(:div, :class => @table_options[:batch_actions_div_class]) do
|
29
|
+
concat(t(@table_options[:batch_actions_label])) if @table_options[:batch_actions_label]
|
30
|
+
iname = "#{@classname}#{TABLE_FORM_OPTIONS[:batch_postfix]}"
|
31
|
+
case @table_options[:batch_actions_type]
|
32
|
+
when :select
|
33
|
+
make_tag(:select, :name => iname, :class => @table_options[:batch_actions_class]) do
|
34
|
+
concat("<option></option>")
|
35
|
+
@table_options[:batch_actions].each do |n,v|
|
36
|
+
make_tag(:option, :value => n) do
|
37
|
+
concat(v)
|
38
|
+
end # </option>
|
39
|
+
end # each
|
40
|
+
end # </select>
|
41
|
+
when :buttons
|
42
|
+
@table_options[:batch_actions].each do |n,v|
|
43
|
+
make_tag(:input, :type => 'submit', :value => v,
|
44
|
+
:name => "#{iname}[#{n}]",
|
45
|
+
:class => @table_options[:batch_actions_class])
|
46
|
+
end # each
|
47
|
+
else raise "Use either :select or :buttons for :batch_actions_type"
|
48
|
+
end # case
|
49
|
+
end # </div>
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following 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 OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
class Tabulatr
|
25
|
+
|
26
|
+
def render_select_controls
|
27
|
+
make_tag(:div, :class => @table_options[:select_controls_div_class]) do
|
28
|
+
iname = "#{@classname}#{TABLE_FORM_OPTIONS[:checked_postfix]}"
|
29
|
+
@table_options[:select_controls].each do |name|
|
30
|
+
raise "Invalid check control '#{name}' requested." unless [:select_all,
|
31
|
+
:select_none, :select_visible, :unselect_visible,
|
32
|
+
:select_filtered, :unselect_filtered].member?(name)
|
33
|
+
topts = {
|
34
|
+
:type => 'submit',
|
35
|
+
:value => t(@table_options["#{name}_label"]),
|
36
|
+
:name => "#{iname}[#{name}]" }
|
37
|
+
topts[:class] = @table_options["#{name}_class"] if @table_options["#{name}_class"]
|
38
|
+
make_tag(:input, topts)
|
39
|
+
end
|
40
|
+
end # </div>
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following 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 OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
class Tabulatr
|
25
|
+
|
26
|
+
# the method used to actually define the data cells of the columns,
|
27
|
+
# taking the name of the attribute and a hash of options.
|
28
|
+
#
|
29
|
+
# The following options are evaluated here:
|
30
|
+
# <tt>:td_html</tt>:: a hash with html-attributes added to the <ts>s created
|
31
|
+
# <tt>:method</tt>:: the actual method invoked on the record to retrieve the
|
32
|
+
# value for the column, or false if name is to be used.
|
33
|
+
# <tt>:fromat</tt>:: either a String by which the value is <tt>sprinf</tt>ed,
|
34
|
+
# a proc/lambda to which the value is passed or false if
|
35
|
+
# no specific formatting is desired.
|
36
|
+
def data_column(name, opts={}, &block)
|
37
|
+
raise "Not in data mode!" if @row_mode != :data
|
38
|
+
opts = normalize_column_options opts
|
39
|
+
make_tag(:td, opts[:td_html]) do
|
40
|
+
href = if opts[:link].class == Symbol || opts[:link].class == String
|
41
|
+
@view.send(opts[:link], @record)
|
42
|
+
elsif opts[:link].respond_to?(:call)
|
43
|
+
opts[:link].call(@record)
|
44
|
+
else
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
make_tag((href ? :a : nil), :href => href) do
|
48
|
+
if block_given?
|
49
|
+
concat(yield(@record))
|
50
|
+
else
|
51
|
+
val = @record.send(opts[:method] || name)
|
52
|
+
format = opts[:format]
|
53
|
+
concat(
|
54
|
+
if format.is_a?(Proc) then format.call(val)
|
55
|
+
elsif format.is_a?(String) then h(format % val)
|
56
|
+
elsif format.is_a?(Symbol) then Tabulatr::Formattr.format(format, val)
|
57
|
+
else h(val.to_s)
|
58
|
+
end)
|
59
|
+
end # block_given?
|
60
|
+
end # </a>
|
61
|
+
end # </td>
|
62
|
+
end
|
63
|
+
|
64
|
+
# the method used to actually define the data cells of the columns,
|
65
|
+
# taking the name of the attribute and a hash of options.
|
66
|
+
#
|
67
|
+
# The following options are evaluated here:
|
68
|
+
# <tt>:td_html</tt>:: a hash with html-attributes added to the <ts>s created
|
69
|
+
# <tt>:method</tt>:: the actual method invoked on the record to retrieve the
|
70
|
+
# value for the column, or false if name is to be used.
|
71
|
+
# <tt>:fromat</tt>:: either a String by which the value is <tt>sprinf</tt>ed,
|
72
|
+
# a proc/lambda to which the value is passed or false if
|
73
|
+
# no specific formatting is desired.
|
74
|
+
def data_association(relation, name, opts={}, &block)
|
75
|
+
raise "Not in data mode!" if @row_mode != :data
|
76
|
+
opts = normalize_column_options opts
|
77
|
+
if block_given?
|
78
|
+
return yield(@record)
|
79
|
+
end
|
80
|
+
assoc = @record.class.reflect_on_association(relation)
|
81
|
+
make_tag(:td, opts[:td_html]) do
|
82
|
+
concat(if assoc.collection?
|
83
|
+
@record.send relation
|
84
|
+
else
|
85
|
+
[ @record.send(relation.to_sym) ]
|
86
|
+
end.map do |r|
|
87
|
+
val = h(r.send(opts[:method] || name))
|
88
|
+
val = opts[:format].call(val) if opts[:format].class == Proc
|
89
|
+
val = (opts[:format] % val) if opts[:format].class == String
|
90
|
+
val
|
91
|
+
end.join(opts[:join_symbol]))
|
92
|
+
end # </td>
|
93
|
+
end
|
94
|
+
|
95
|
+
def data_checkbox(opts={}, &block)
|
96
|
+
raise "Whatever that's for!" if block_given?
|
97
|
+
iname = "#{@classname}#{@table_form_options[:checked_postfix]}[current_page][]"
|
98
|
+
make_tag(:td, opts[:td_html]) do
|
99
|
+
checked = @checked[:selected].member?(@record.id.to_s) ? :checked : nil
|
100
|
+
make_tag(:input, :type => 'checkbox', :name => iname,
|
101
|
+
:id => "#{@classname}#{@table_form_options[:checked_postfix]}_#{@record.id.to_s}",
|
102
|
+
:value => @record.id, :checked => checked)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def data_action(opts={}, &block)
|
107
|
+
raise "Not in data mode!" if @row_mode != :data
|
108
|
+
opts = normalize_column_options opts
|
109
|
+
make_tag(:td, opts[:td_html]) do
|
110
|
+
if block_given?
|
111
|
+
concat(yield(@record))
|
112
|
+
else
|
113
|
+
raise "Always give a block ino action columns"
|
114
|
+
end # block_given?
|
115
|
+
end # </td>
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following 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 OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
class Tabulatr
|
25
|
+
|
26
|
+
# the method used to actually define the filters of the columns,
|
27
|
+
# taking the name of the attribute and a hash of options.
|
28
|
+
#
|
29
|
+
# The following options are evaluated here:
|
30
|
+
# <tt>:filter_html</tt>:: a hash with html-attributes added to the <ts>s created
|
31
|
+
# <tt>:filter</tt>:: may take different values:
|
32
|
+
# <tt>false</tt>:: no filter is output for this column
|
33
|
+
# a container:: the keys of the hash are used to define a <tt>select</tt>
|
34
|
+
# where the values are the <tt>value</tt> of the <tt>options</tt>.
|
35
|
+
# an Array:: the elements of that array are used to define a
|
36
|
+
# <tt>select</tt>
|
37
|
+
# a String:: a <tt>select</tt> is created with that String as options
|
38
|
+
# you can use ActionView#collection_select and the like
|
39
|
+
def filter_column(name, opts={}, &block)
|
40
|
+
raise "Not in filter mode!" if @row_mode != :filter
|
41
|
+
opts = normalize_column_options(opts)
|
42
|
+
value = @filters[name]
|
43
|
+
make_tag(:td, opts[:filter_html]) do
|
44
|
+
of = opts[:filter]
|
45
|
+
iname = "#{@classname}#{@table_form_options[:filter_postfix]}[#{name}]"
|
46
|
+
filter_tag(of, iname, value, opts)
|
47
|
+
end # </td>
|
48
|
+
end
|
49
|
+
|
50
|
+
# the method used to actually define the filters of the columns,
|
51
|
+
# taking the name of the attribute and a hash of options.
|
52
|
+
#
|
53
|
+
# The following options are evaluated here:
|
54
|
+
# <tt>:filter_html</tt>:: a hash with html-attributes added to the <ts>s created
|
55
|
+
# <tt>:filter</tt>:: may take different values:
|
56
|
+
# <tt>false</tt>:: no filter is output for this column
|
57
|
+
# a Hash:: the keys of the hash are used to define a <tt>select</tt>
|
58
|
+
# where the values are the <tt>value</tt> of the <tt>options</tt>.
|
59
|
+
# an Array:: the elements of that array are used to define a
|
60
|
+
# <tt>select</tt>
|
61
|
+
# a subclass of <tt>ActiveRecord::Base</tt>:: a <tt>select</tt> is created
|
62
|
+
# with all instances
|
63
|
+
def filter_association(relation, name, opts={}, &block)
|
64
|
+
raise "Not in filter mode!" if @row_mode != :filter
|
65
|
+
opts = normalize_column_options(opts)
|
66
|
+
filters = (@filters[@table_form_options[:associations_filter]] || {})
|
67
|
+
value = filters["#{relation}.#{name}"]
|
68
|
+
make_tag(:td, opts[:filter_html]) do
|
69
|
+
of = opts[:filter]
|
70
|
+
iname = "#{@classname}#{@table_form_options[:filter_postfix]}[#{@table_form_options[:associations_filter]}][#{relation}.#{name}]"
|
71
|
+
filter_tag(of, iname, value, opts)
|
72
|
+
end # </td>
|
73
|
+
end
|
74
|
+
|
75
|
+
def filter_checkbox(opts={}, &block)
|
76
|
+
raise "Whatever that's for!" if block_given?
|
77
|
+
make_tag(:td, opts[:filter_html]) do
|
78
|
+
iname = "#{@classname}#{@table_form_options[:checked_postfix]}"
|
79
|
+
make_tag(:input, :type => 'hidden', :name => "#{iname}[checked_ids]", :value => @checked[:checked_ids])
|
80
|
+
make_tag(:input, :type => 'hidden', :name => "#{iname}[visible]", :value => @checked[:visible])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def filter_action(opts={}, &block)
|
85
|
+
raise "Not in filter mode!" if @row_mode != :filter
|
86
|
+
opts = normalize_column_options(opts)
|
87
|
+
make_tag(:td, opts[:filter_html]) do
|
88
|
+
concat(t(opts[:filter])) unless [true, false, nil].member?(opts[:filter])
|
89
|
+
end # </td>
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def filter_tag(of, iname, value, opts)
|
95
|
+
if !of
|
96
|
+
""
|
97
|
+
elsif of.is_a?(Hash) or of.is_a?(Array) or of.is_a?(String)
|
98
|
+
make_tag(:select, :name => iname) do
|
99
|
+
if of.class.is_a?(String)
|
100
|
+
concat(of)
|
101
|
+
else
|
102
|
+
concat("<option></option>")
|
103
|
+
t = options_for_select(of)
|
104
|
+
concat(t.sub("value=\"#{value}\"", "value=\"#{value}\" selected=\"selected\""))
|
105
|
+
end
|
106
|
+
end # </select>
|
107
|
+
elsif opts[:filter] == :range
|
108
|
+
make_tag(:input, :type => :text, :name => "#{iname}[from]",
|
109
|
+
:style => "width:#{opts[:filter_width]}",
|
110
|
+
:value => value ? value[:from] : '')
|
111
|
+
concat(t(opts[:range_filter_symbol]))
|
112
|
+
make_tag(:input, :type => :text, :name => "#{iname}[to]",
|
113
|
+
:style => "width:#{opts[:filter_width]}",
|
114
|
+
:value => value ? value[:to] : '')
|
115
|
+
elsif opts[:filter] == :checkbox
|
116
|
+
checkbox_value = opts[:checkbox_value]
|
117
|
+
checkbox_label = opts[:checkbox_label]
|
118
|
+
concat(check_box_tag(iname, checkbox_value, false, {}))
|
119
|
+
concat(checkbox_label)
|
120
|
+
elsif opts[:filter] == :like
|
121
|
+
make_tag(:input, :type => :text, :name => "#{iname}[like]",
|
122
|
+
:style => "width:#{opts[:filter_width]}",
|
123
|
+
:value => value ? value[:like] : '')
|
124
|
+
else
|
125
|
+
make_tag(:input, :type => :text, :name => "#{iname}", :style => "width:#{opts[:filter_width]}",
|
126
|
+
:value => value)
|
127
|
+
end # if
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following 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 OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
# These are extensions for use from ActionController instances
|
25
|
+
# In a seperate class call only for clearity
|
26
|
+
module Tabulatr::Finder
|
27
|
+
|
28
|
+
# -------------------------------------------------------------------
|
29
|
+
# Called if SomeActveRecordSubclass::find_for_table(params) is called
|
30
|
+
#
|
31
|
+
def self.find_for_active_record_table(klaz, params, o={}, &block)
|
32
|
+
form_options = Tabulatr.table_form_options
|
33
|
+
cname = class_to_param(klaz)
|
34
|
+
params ||= {}
|
35
|
+
opts = Tabulatr.finder_options.merge(o)
|
36
|
+
# before we do anything else, we find whether there's something to do for batch actions
|
37
|
+
checked_param = ActiveSupport::HashWithIndifferentAccess.new({:checked_ids => '', :current_page => []}).
|
38
|
+
merge(params["#{cname}#{form_options[:checked_postfix]}"] || {})
|
39
|
+
checked_ids = uncompress_id_list(checked_param[:checked_ids])
|
40
|
+
new_ids = checked_param[:current_page]
|
41
|
+
selected_ids = checked_ids + new_ids
|
42
|
+
batch_param = params["#{cname}#{form_options[:batch_postfix]}"]
|
43
|
+
if batch_param.present? and block_given?
|
44
|
+
batch_param = batch_param.keys.first.to_sym if batch_param.is_a?(Hash)
|
45
|
+
yield(Invoker.new(batch_param, selected_ids))
|
46
|
+
end
|
47
|
+
|
48
|
+
# firstly, get the conditions from the filters
|
49
|
+
includes = []
|
50
|
+
filter_param = (params["#{cname}#{form_options[:filter_postfix]}"] || {})
|
51
|
+
precondition = opts[:precondition] || "(1=1)"
|
52
|
+
conditions = filter_param.inject([precondition.dup, []]) do |c, t|
|
53
|
+
n, v = t
|
54
|
+
# FIXME n = name_escaping(n)
|
55
|
+
if (n != form_options[:associations_filter])
|
56
|
+
condition_from("#{klaz.table_name}.#{n}",v,c)
|
57
|
+
else
|
58
|
+
v.inject(c) do |c,t|
|
59
|
+
n,v = t
|
60
|
+
assoc, att = n.split(".").map(&:to_sym)
|
61
|
+
r = klaz.reflect_on_association(assoc)
|
62
|
+
includes << assoc
|
63
|
+
tname = r.table_name
|
64
|
+
nn = "#{tname}.#{att}"
|
65
|
+
condition_from(nn,v,c)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
conditions = [conditions.first] + conditions.last
|
70
|
+
|
71
|
+
# secondly, find the order_by stuff
|
72
|
+
sortparam = params["#{cname}#{form_options[:sort_postfix]}"]
|
73
|
+
if sortparam
|
74
|
+
if sortparam[:_resort]
|
75
|
+
order_by = sortparam[:_resort].first.first
|
76
|
+
order_direction = sortparam[:_resort].first.last.first.first
|
77
|
+
else
|
78
|
+
order_by = sortparam.first.first
|
79
|
+
order_direction = sortparam.first.last.first.first
|
80
|
+
end
|
81
|
+
raise "SECURITY violation, sort field name is '#{n}'" unless /^[\w]+$/.match order_direction
|
82
|
+
raise "SECURITY violation, sort field name is '#{n}'" unless /^[\d\w]+$/.match order_by
|
83
|
+
order = "#{order_by} #{order_direction}"
|
84
|
+
else
|
85
|
+
if opts[:default_order]
|
86
|
+
l = opts[:default_order].split(" ")
|
87
|
+
raise(":default_order parameter should be of the form 'id asc' or 'name desc'.") \
|
88
|
+
if l.length == 0 or l.length > 2
|
89
|
+
order_by = l[0]
|
90
|
+
order_direction = l[1] || 'asc'
|
91
|
+
order = "#{order_by} #{order_direction}"
|
92
|
+
else
|
93
|
+
order = order_by = order_direction = nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# thirdly, get the pagination data
|
98
|
+
pops = params["#{cname}#{form_options[:pagination_postfix]}"] || {}
|
99
|
+
paginate_options = Tabulatr.paginate_options.merge(opts).merge(pops)
|
100
|
+
pagesize = (pops[:pagesize] || opts[:default_pagesize] || paginate_options[:pagesize]).to_f
|
101
|
+
page = paginate_options[:page].to_i
|
102
|
+
page += 1 if paginate_options[:page_right]
|
103
|
+
page -= 1 if paginate_options[:page_left]
|
104
|
+
c = klaz.count :conditions => conditions, :include => includes
|
105
|
+
pages = (c/pagesize).ceil
|
106
|
+
page = [1, [page, pages].min].max
|
107
|
+
|
108
|
+
# then, we obey any "select" buttons if pushed
|
109
|
+
if checked_param[:select_all]
|
110
|
+
all = klaz.find :all, :conditions => precondition, :select => :id
|
111
|
+
selected_ids = all.map { |r| r.id.to_s }
|
112
|
+
elsif checked_param[:select_none]
|
113
|
+
selected_ids = []
|
114
|
+
elsif checked_param[:select_visible]
|
115
|
+
visible_ids = uncompress_id_list(checked_param[:visible])
|
116
|
+
selected_ids = (selected_ids + visible_ids).sort.uniq
|
117
|
+
elsif checked_param[:unselect_visible]
|
118
|
+
visible_ids = uncompress_id_list(checked_param[:visible])
|
119
|
+
selected_ids = (selected_ids - visible_ids).sort.uniq
|
120
|
+
elsif checked_param[:select_filtered]
|
121
|
+
all = klaz.find :all, :conditions => conditions, :select => :id, :include => includes
|
122
|
+
selected_ids = (selected_ids + all.map { |r| r.id.to_s }).sort.uniq
|
123
|
+
elsif checked_param[:unselect_filtered]
|
124
|
+
all = klaz.find :all, :conditions => conditions, :select => :id, :include => includes
|
125
|
+
selected_ids = (selected_ids - all.map { |r| r.id.to_s }).sort.uniq
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
# Now, actually find the stuff
|
130
|
+
found = klaz.find :all, :conditions => conditions,
|
131
|
+
:limit => pagesize.to_i, :offset => ((page-1)*pagesize).to_i,
|
132
|
+
:order => order, :include => includes
|
133
|
+
|
134
|
+
# finally, inject methods to retrieve the current 'settings'
|
135
|
+
fio = Tabulatr.finder_inject_options
|
136
|
+
found.define_singleton_method(fio[:filters]) do filter_param end
|
137
|
+
found.define_singleton_method(fio[:classname]) do cname end
|
138
|
+
found.define_singleton_method(fio[:pagination]) do
|
139
|
+
{ :page => page, :pagesize => pagesize, :count => c, :pages => pages,
|
140
|
+
:pagesizes => paginate_options[:pagesizes],
|
141
|
+
:total => klaz.count(:conditions => precondition) }
|
142
|
+
end
|
143
|
+
found.define_singleton_method(fio[:sorting]) do
|
144
|
+
order ? { :by => order_by, :direction => order_direction } : nil
|
145
|
+
end
|
146
|
+
visible_ids = (found.map { |r| r.id.to_s })
|
147
|
+
checked_ids = compress_id_list(selected_ids - visible_ids)
|
148
|
+
visible_ids = compress_id_list(visible_ids)
|
149
|
+
found.define_singleton_method(fio[:checked]) do
|
150
|
+
{ :selected => selected_ids,
|
151
|
+
:checked_ids => checked_ids,
|
152
|
+
:visible => visible_ids
|
153
|
+
}
|
154
|
+
end
|
155
|
+
found.define_singleton_method(fio[:store_data]) do
|
156
|
+
opts[:store_data] || {}
|
157
|
+
end
|
158
|
+
|
159
|
+
found
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Peter Horn, Provideal GmbH
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following 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 OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
# These are extensions for use from ActionController instances
|
25
|
+
# In a seperate class call only for clearity
|
26
|
+
module Tabulatr::Finder
|
27
|
+
|
28
|
+
# ----------------------------------------------------------------
|
29
|
+
# Called if SomeMongoidDocument::find_for_table(params) is called
|
30
|
+
#
|
31
|
+
def self.find_for_mongoid_table(klaz, params, opts={})
|
32
|
+
# firstly, get the conditions from the filters
|
33
|
+
cname = class_to_param(klaz)
|
34
|
+
filter_param = (params["#{cname}#{TABLE_FORM_OPTIONS[:filter_postfix]}"] || {})
|
35
|
+
conditions = filter_param.inject({}) do |c, t|
|
36
|
+
n, v = t
|
37
|
+
nc = c
|
38
|
+
# FIXME n = name_escaping(n)
|
39
|
+
raise "SECURITY violation, field name is '#{n}'" unless /^[\d\w]+$/.match n
|
40
|
+
if v.class == String
|
41
|
+
if v.present?
|
42
|
+
nc[n.to_sym] = v
|
43
|
+
end
|
44
|
+
elsif v.is_a?(Hash)
|
45
|
+
if v[:like]
|
46
|
+
if v[:like].present?
|
47
|
+
nc[n.to_sym] = Regexp.new("#{v[:like]}")
|
48
|
+
end
|
49
|
+
else
|
50
|
+
nc[n.to_sym.gte] = "#{v[:from]}" if v[:from].present?
|
51
|
+
nc[n.to_sym.lte] = "#{v[:to]}" if v[:to].present?
|
52
|
+
end
|
53
|
+
else
|
54
|
+
raise "Wrong filter type: #{v.class}"
|
55
|
+
end
|
56
|
+
nc
|
57
|
+
end
|
58
|
+
|
59
|
+
# secondly, find the order_by stuff
|
60
|
+
# FIXME: Implement me! PLEEEZE!
|
61
|
+
sortparam = params["#{cname}#{TABLE_FORM_OPTIONS[:sort_postfix]}"]
|
62
|
+
if sortparam
|
63
|
+
if sortparam[:_resort]
|
64
|
+
order_by = sortparam[:_resort].first.first
|
65
|
+
order_direction = sortparam[:_resort].first.last.first.first
|
66
|
+
else
|
67
|
+
order_by = sortparam.first.first
|
68
|
+
order_direction = sortparam.first.last.first.first
|
69
|
+
end
|
70
|
+
raise "SECURITY violation, sort field name is '#{n}'" unless /^[\w]+$/.match order_direction
|
71
|
+
raise "SECURITY violation, sort field name is '#{n}'" unless /^[\d\w]+$/.match order_by
|
72
|
+
order = [order_by, order_direction]
|
73
|
+
else
|
74
|
+
order = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
# thirdly, get the pagination data
|
78
|
+
paginate_options = PAGINATE_OPTIONS.merge(opts).
|
79
|
+
merge(params["#{cname}#{TABLE_FORM_OPTIONS[:pagination_postfix]}"] || {})
|
80
|
+
page = paginate_options[:page].to_i
|
81
|
+
page += 1 if paginate_options[:page_right]
|
82
|
+
page -= 1 if paginate_options[:page_left]
|
83
|
+
pagesize = paginate_options[:pagesize].to_f
|
84
|
+
c = klaz.count :conditions => conditions
|
85
|
+
pages = (c/pagesize).ceil
|
86
|
+
page = [1, [page, pages].min].max
|
87
|
+
|
88
|
+
# Now, actually find the stuff
|
89
|
+
found = klaz.find(:conditions => conditions)
|
90
|
+
found = found.order_by([order]) if order
|
91
|
+
found = found.paginate(:page => page, :per_page => pagesize)
|
92
|
+
|
93
|
+
# finally, inject methods to retrieve the current 'settings'
|
94
|
+
found.define_singleton_method(fio[:filters]) do filter_param end
|
95
|
+
found.define_singleton_method(fio[:classname]) do cname end
|
96
|
+
found.define_singleton_method(fio[:pagination]) do
|
97
|
+
{:page => page, :pagesize => pagesize, :count => c, :pages => pages,
|
98
|
+
:pagesizes => paginate_options[:pagesizes]}
|
99
|
+
end
|
100
|
+
found.define_singleton_method(fio[:sorting]) do
|
101
|
+
order ? { :by => order_by, :direction => order_direction } : nil
|
102
|
+
end
|
103
|
+
checked_param = params["#{cname}#{TABLE_FORM_OPTIONS[:checked_postfix]}"]
|
104
|
+
checked_ids = checked_param[:checked].split(TABLE_FORM_OPTIONS[:checked_separator])
|
105
|
+
new_ids = checked_param[:current_page] || []
|
106
|
+
selected_ids = checked_ids + new_ids
|
107
|
+
ids = found.map { |r| r.id.to_s }
|
108
|
+
checked_ids = selected_ids - ids
|
109
|
+
found.define_singleton_method(fio[:checked]) do
|
110
|
+
{ :selected => selected_ids,
|
111
|
+
:checked_ids => checked_ids.join(TABLE_FORM_OPTIONS[:checked_separator]) }
|
112
|
+
end
|
113
|
+
found
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|