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.
@@ -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