tabulatr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|