tabulatr 0.0.1

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