fancygrid 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. data/CHANGELOG +9 -2
  2. data/Gemfile +6 -9
  3. data/Gemfile.lock +88 -103
  4. data/README.md +226 -0
  5. data/ROADMAP +0 -1
  6. data/Rakefile +2 -2
  7. data/VERSION +1 -1
  8. data/app/views/fancygrid/controls.html.haml +34 -0
  9. data/app/views/fancygrid/fancygrid.html.haml +18 -0
  10. data/app/views/fancygrid/search.html.haml +24 -0
  11. data/app/views/fancygrid/sort.html.haml +8 -0
  12. data/app/views/fancygrid/table.html.haml +25 -0
  13. data/config/locales/fancygrid.de.yml +17 -19
  14. data/config/locales/fancygrid.en.yml +14 -17
  15. data/fancygrid.gemspec +48 -88
  16. data/lib/assets/javascripts/fancygrid.js +425 -0
  17. data/lib/assets/javascripts/fancygrid.min.js +15 -0
  18. data/lib/assets/stylesheets/fancygrid.css +177 -0
  19. data/lib/fancygrid.rb +63 -44
  20. data/lib/fancygrid/column.rb +165 -0
  21. data/lib/fancygrid/controller/helper.rb +46 -0
  22. data/lib/fancygrid/grid.rb +171 -317
  23. data/lib/fancygrid/node.rb +85 -490
  24. data/lib/fancygrid/object_wrapper.rb +24 -0
  25. data/lib/fancygrid/orm/active_record.rb +39 -0
  26. data/lib/fancygrid/orm/sql_generator.rb +127 -0
  27. data/lib/fancygrid/view/helper.rb +44 -0
  28. data/lib/fancygrid/view_state.rb +161 -0
  29. data/spec/column_spec.rb +29 -0
  30. data/spec/dummy/app/controllers/application_controller.rb +48 -0
  31. data/spec/dummy/app/views/application/index.html.haml +11 -0
  32. data/spec/dummy/app/views/layouts/application.html.erb +1 -1
  33. data/spec/dummy/config/application.rb +1 -1
  34. data/spec/dummy/config/environments/development.rb +2 -2
  35. data/spec/dummy/config/environments/test.rb +2 -2
  36. data/spec/dummy/config/routes.rb +3 -2
  37. data/spec/dummy/db/development.sqlite3 +0 -0
  38. data/spec/dummy/db/schema.rb +26 -0
  39. data/spec/dummy/public/javascripts/jquery-1.4.2.js +6240 -0
  40. data/spec/dummy/public/javascripts/jquery-fancygrid.js +425 -0
  41. data/spec/dummy/public/javascripts/jquery-ui.js +41 -0
  42. data/spec/dummy/public/stylesheets/fancygrid.css +183 -0
  43. data/spec/node_spec.rb +79 -301
  44. data/spec/spec_helper.rb +0 -29
  45. data/spec/view_state_spec.rb +91 -0
  46. metadata +124 -137
  47. data/.bundle/config +0 -2
  48. data/README.rdoc +0 -299
  49. data/app/views/fancygrid/_cells.html.haml +0 -13
  50. data/app/views/fancygrid/base/controls.html.haml +0 -40
  51. data/app/views/fancygrid/base/list_frame.html.haml +0 -37
  52. data/app/views/fancygrid/base/search.html.haml +0 -33
  53. data/app/views/fancygrid/base/sort.html.haml +0 -20
  54. data/app/views/fancygrid/base/table_frame.html.haml +0 -45
  55. data/config/initializers/fancygrid.rb +0 -67
  56. data/lib/fancygrid/helper.rb +0 -129
  57. data/lib/fancygrid/query_generator.rb +0 -340
  58. data/lib/fancygrid/view.rb +0 -148
  59. data/lib/generators/install_generator.rb +0 -61
  60. data/lib/generators/views_generator.rb +0 -25
  61. data/lib/version.rb +0 -0
  62. data/public/images/fancygrid/add.png +0 -0
  63. data/public/images/fancygrid/clear.png +0 -0
  64. data/public/images/fancygrid/ddn.png +0 -0
  65. data/public/images/fancygrid/dn.png +0 -0
  66. data/public/images/fancygrid/dots.png +0 -0
  67. data/public/images/fancygrid/loading.gif +0 -0
  68. data/public/images/fancygrid/magnifier.png +0 -0
  69. data/public/images/fancygrid/next.png +0 -0
  70. data/public/images/fancygrid/order.png +0 -0
  71. data/public/images/fancygrid/prev.png +0 -0
  72. data/public/images/fancygrid/reload.png +0 -0
  73. data/public/images/fancygrid/remove.png +0 -0
  74. data/public/images/fancygrid/spacer.gif +0 -0
  75. data/public/images/fancygrid/submit.png +0 -0
  76. data/public/images/fancygrid/th_bg.png +0 -0
  77. data/public/images/fancygrid/up.png +0 -0
  78. data/public/images/fancygrid/uup.png +0 -0
  79. data/public/javascripts/fancygrid.js +0 -477
  80. data/public/javascripts/fancygrid.min.js +0 -17
  81. data/public/stylesheets/fancygrid.css +0 -289
  82. data/public/stylesheets/fancygrid.scss +0 -302
  83. data/spec/dummy/log/development.log +0 -0
  84. data/spec/dummy/log/production.log +0 -0
  85. data/spec/dummy/log/server.log +0 -0
  86. data/spec/dummy/log/test.log +0 -1026
  87. data/spec/dummy/public/javascripts/application.js +0 -2
  88. data/spec/dummy/public/javascripts/controls.js +0 -965
  89. data/spec/dummy/public/javascripts/dragdrop.js +0 -974
  90. data/spec/dummy/public/javascripts/effects.js +0 -1123
  91. data/spec/dummy/public/javascripts/prototype.js +0 -6001
  92. data/spec/dummy/public/javascripts/rails.js +0 -175
  93. data/spec/grid_spec.rb +0 -15
  94. data/spec/integration/navigation_spec.rb +0 -9
  95. data/spec/query_generator_spec.rb +0 -358
@@ -1,533 +1,128 @@
1
-
2
- module Fancygrid#:nodoc:
1
+ module Fancygrid
3
2
 
4
3
  class Node
5
4
 
6
- # Top level node. Must be a Fancygrid::Grid instance
7
- attr_accessor :root
8
-
9
- # Parent node. Can be a Fancygrid::Grid or Fancygrid::Node instance or <tt>nil</tt>
10
- attr_accessor :parent
11
-
12
- # Collection of Fancygrid::Node's that define fields or nested resources of
13
- # this node
14
- attr_accessor :children
15
-
16
-
17
- # User defined name of this field or table
18
- attr_accessor :name
19
-
20
- # Class constant of the model that is represented by this node
21
- attr_accessor :record_klass
22
-
23
- # Table name of the model that is represented by this node
24
- attr_accessor :record_table_name
5
+ # The fancygrid root node.
6
+ attr_reader :root
25
7
 
8
+ # The paent node.
9
+ attr_reader :parent
26
10
 
27
- # Specifies the column position from left to right in the final table
28
- attr_accessor :position
29
-
30
- # Specifies the search value of this column
31
- attr_accessor :search_value
32
-
33
- # Specifies whether this column is searchable or not
34
- attr_accessor :searchable
35
-
36
- # Specifies whether this column is formatted with a custom rendering code
37
- attr_accessor :formatable
38
-
39
- # Specifies whether this column is rendered or not
40
- attr_accessor :visible
41
-
42
- # Specifies whether this column refers to a database field and has a selector
43
- attr_accessor :selectable
44
-
45
- # Specifies the custom block to use on a record to resolve a value for rendering
46
- attr_accessor :proc_block
11
+ # Array of child nodes.
12
+ attr_reader :children
13
+
14
+ # The name of this node.
15
+ attr_reader :name
47
16
 
17
+ # The corresponding resource class.
18
+ attr_reader :resource_class
48
19
 
49
- def initialize(root, parent, name)
50
- raise "root element must be an instance of Fancygrid::Grid" unless root.is_a?(Fancygrid::Grid)
51
- self.root = root
52
- self.parent = parent
53
- self.name = name
54
- self.children = nil
55
- end
56
-
57
-
58
- # Creates a child node with given <tt>name</tt>, <tt>klass</tt> and <tt>table_name</tt>.
59
- # See +initialize_node+ method for more information
60
- def columns_for(name, klass = nil, table_name = nil, options = nil, &block)
61
- raise ArgumentError, "Missing block" unless block_given?
62
- node = Fancygrid::Node.new(self.root, self, name)
63
- node.initialize_node(name, klass, table_name, options)
20
+ # The table name of the resource class.
21
+ attr_reader :table_name
22
+
23
+ # Initializes the node.
24
+ #
25
+ def initialize(parent, name, options = {})
26
+ raise ArgumentError, "expected parent to be a Node" if !parent.nil? && !parent.is_a?(Fancygrid::Node)
27
+ raise ArgumentError, "name must not be blank" if name.blank?
64
28
 
65
- self.children ||= []
66
- self.children << node
29
+ @parent = parent
30
+ @name = name
31
+ @children = []
32
+ @root = self.get_root
67
33
 
68
- yield node
69
- end
70
-
71
- # Creates a child leaf for this node. A leaf represents a column in the final table.
72
- # === options
73
- # * <tt>:visible</tt> _TrueClass_ value specifying whether the column is rendered to the final table or not
74
- # * <tt>:searchable</tt> _TrueClass_ value specifying whether the column has a search field in the final table or not
75
- # * <tt>:formatable</tt> _TrueClass_ value specifying whether the column is formatted with custom rendering code or not
76
- # * <tt>:selectable</tt> _TrueClass_ value specifying whether the column is a database field and has a selector
77
- # * <tt>:proc</tt> _Proc_ block that should be run to retrieve a value from a record
78
- def column(name, options = nil)
79
- node = Fancygrid::Node.new(self.root, self, name)
80
- node.initialize_node(name, self.record_klass, self.record_table_name)
81
- node.initialize_leaf(options)
34
+ @resource_class = options.fetch(:class) do
35
+ self.name.to_s.classify.constantize
36
+ end
82
37
 
83
- self.children ||= []
84
- self.children << node
85
- root.insert_node(node)
86
- #root.leafs << node
87
- end
88
-
89
- # Creates a <tt>column</tt> for each value in the <tt>names</tt> array with the passed <tt>options</tt>.
90
- def columns(names, options)
91
- names.flatten.each do |name|
92
- column(name, options)
38
+ @table_name = options.fetch(:table_name) do
39
+ if self.resource_class.respond_to?(:table_name)
40
+ self.resource_class.table_name
41
+ else
42
+ self.resource_class.name.tableize
43
+ end
93
44
  end
45
+
46
+ self.parent.add_child self if self.parent.present?
94
47
  end
95
48
 
96
- # Creates a <tt>column</tt> for each value in the <tt>names</tt> argument
97
- # Sets the following <tt>options</tt> if not already set in the <tt>options</tt> argument
98
- # * <tt>:searchable => true</tt>
99
- # * <tt>:formatable => false</tt>
100
- # * <tt>:visible => true</tt>
101
- # * <tt>:selectable => true</tt>
102
- # === Example
103
- #
104
- # node.attributes(:status)
105
- #
106
- # # is a shortcut for
49
+ # Creates and yields a child node.
107
50
  #
108
- # node.column(:status, {
109
- # :searchable => true,
110
- # :formatable => false,
111
- # :visible => true,
112
- # :selectable => true,
113
- # })
114
- def attributes(*names)
115
- options = names.extract_options!
116
- options[:searchable] = true if options[:searchable].nil?
117
- options[:formatable] = false if options[:formatable].nil?
118
- options[:visible] = true if options[:visible].nil?
119
- options[:selectable] = true if options[:selectable].nil?
120
- columns(names, options)
51
+ def columns_for(name, options = {})# :yields:
52
+ node = Fancygrid::Node.new(self, name, options)
53
+ yield node if block_given?
54
+ return node
121
55
  end
122
56
 
123
- # Creates a <tt>column</tt> for each value in the <tt>names</tt> argument.
124
- # Sets the following <tt>options</tt> if not already set in the <tt>options</tt> argument
125
- # * <tt>:searchable => false</tt>
126
- # * <tt>:formatable => false</tt>
127
- # * <tt>:visible => true</tt>
128
- # * <tt>:selectable => false</tt>
129
- # === Example
130
- #
131
- # node.methods(:status)
57
+ # Creates and adds a column to this node.
132
58
  #
133
- # # is a shortcut for
134
- #
135
- # node.column(:status, {
136
- # :searchable => false,
137
- # :formatable => false,
138
- # :visible => true,
139
- # :selectable => false,
140
- # })
141
- def methods(*names)
142
- options = names.extract_options!
143
- options[:searchable] = false if options[:searchable].nil?
144
- options[:formatable] = false if options[:formatable].nil?
145
- options[:visible] = true if options[:visible].nil?
146
- options[:selectable] = options[:selectable].nil? ? options[:searchable] : options[:selectable]
147
- columns(names, options)
59
+ def column(name, options = {})
60
+ options[:class] ||= self.resource_class
61
+ options[:table_name] ||= self.table_name
62
+ Fancygrid::Column.new(self, name, options)
148
63
  end
149
64
 
150
- # Creates a <tt>column</tt> for each value in the <tt>names</tt> argument.
151
- # Sets the following <tt>options</tt> if not already set in the <tt>options</tt> argument
152
- # * <tt>:searchable => false</tt>
153
- # * <tt>:formatable => true</tt>
154
- # * <tt>:visible => true</tt>
155
- # * <tt>:selectable => false</tt>
156
- # === Example
157
- #
158
- # node.rendered(:status)
159
- #
160
- # # is a shortcut for
65
+ # Creates and adds a column for each given parameter.
66
+ # The columns are marked to be not selectable and not searchable.
161
67
  #
162
- # node.column(:status, {
163
- # :searchable => false,
164
- # :formatable => true,
165
- # :visible => true,
166
- # :selectable => false,
167
- # })
168
- def rendered(*names)
68
+ def columns(*names)
169
69
  options = names.extract_options!
170
- options[:searchable] = false if options[:searchable].nil?
171
- options[:formatable] = true if options[:formatable].nil?
172
- options[:visible] = true if options[:visible].nil?
173
- options[:selectable] = options[:selectable].nil? ? options[:searchable] : options[:selectable]
174
- columns(names, options)
70
+ options[:searchable] = options.fetch(:searchable, false)
71
+ options[:selectable] = options.fetch(:selectable, false)
72
+ options[:value_proc] = Proc.new if block_given?
73
+ names.flatten.map { |name| self.column(name, options) }
175
74
  end
176
75
 
177
- # Creates a <tt>column</tt> for each value in the <tt>names</tt> argument.
178
- # Sets the following <tt>options</tt> if not already set in the <tt>options</tt> argument
179
- # * <tt>:searchable => true</tt>
180
- # * <tt>:formatable => false</tt>
181
- # * <tt>:visible => false</tt>
182
- # * <tt>:selectable => true</tt>
183
- # === Example
184
- #
185
- # node.hidden(:status)
186
- #
187
- # # is a shortcut for
76
+ # Creates and adds a column for each given parameter.
77
+ # The columns are marked as selectable and searchable.
188
78
  #
189
- # node.column(:status, {
190
- # :searchable => true,
191
- # :formatable => false,
192
- # :visible => false,
193
- # :selectable => true,
194
- # })
195
- def hidden(*names)
79
+ def attributes(*names)
196
80
  options = names.extract_options!
197
- options[:searchable] = true if options[:searchable].nil?
198
- options[:formatable] = false if options[:formatable].nil?
199
- options[:visible] = false if options[:visible].nil?
200
- options[:selectable] = true if options[:selectable].nil?
81
+ options[:searchable] = options.fetch(:searchable, true)
82
+ options[:selectable] = options.fetch(:selectable, true)
201
83
  columns(names, options)
202
84
  end
203
85
 
204
- # Creates a <tt>column</tt> for each value in the <tt>names</tt> argument.
205
- # Sets the following <tt>options</tt> if not already set in the <tt>options</tt> argument
206
- # * <tt>:searchable => false</tt>
207
- # * <tt>:formatable => false</tt>
208
- # * <tt>:visible => true</tt>
209
- # * <tt>:selectable => false</tt>
210
- # * <tt>:proc => proc</tt>
211
- # === Example
212
- #
213
- # node.proc(:status) do |record|
214
- # record.status
215
- # end
216
- #
217
- # # is a shortcut for
86
+ # Gets a dot separated string of names of all parent nodes including own.
218
87
  #
219
- # node.column(:status, {
220
- # :searchable => false,
221
- # :formatable => false,
222
- # :visible => true,
223
- # :selectable => false,
224
- # :proc => Proc.new { |record| record.status }
225
- # })
226
- def proc(name, options=nil)
227
- raise "Missing block" unless block_given?
228
- options ||= {}
229
- options[:searchable] = false if options[:searchable].nil?
230
- options[:formatable] = false if options[:formatable].nil?
231
- options[:visible] = true if options[:visible].nil?
232
- options[:selectable] = options[:selectable].nil? ? options[:searchable] : options[:selectable]
233
- options[:proc] = Proc.new
234
- column(name, options)
235
- end
236
-
237
- # Gets a value indicating whether this node is a leaf or not.
238
- # === Example
239
- #
240
- # grid = Fancygrid::Grid.new(:ticket) # is_leaf? => false
241
- # grid.column(:column) # is_leaf? => true
242
- # grid.attributes(:title) # is_leaf? => true
243
- # grid.methods(:status) # is_leaf? => true
244
- # grid.rendered(:foo) # is_leaf? => true
245
- # grid.hidden(:bar) # is_leaf? => true
246
- #
247
- # grid.columns_for(:project) do |p| # is_leaf? => false
248
- # p.attributes(:description) # is_leaf? => true
249
- # end
250
- def is_leaf?
251
- self.children.nil?
252
- end
253
-
254
- # Returns the <tt>tag_name</tt> of this node if it is a leaf. Otherwise returns <tt>nil</tt>.
255
- # === Example
256
- #
257
- # grid = Fancygrid::Grid.new(:ticket) # tag_name => nil
258
- # grid.attributes(:title) # tag_name => "tickets[title]"
259
- # grid.attributes(:status) # tag_name => "tickets[status]"
260
- #
261
- # grid.columns_for(:project) do |p| # tag_name => nil
262
- # p.attributes(:description) # tag_name => "projects[description]"
263
- # end
264
- def tag_name
265
- if is_leaf? && @tag_name.nil?
266
- @tag_name = "#{self.record_table_name}[#{self.name}]"
267
- end
268
- @tag_name
269
- end
270
-
271
- # Returns the database select name of this node if it is a leaf and is selectable.
272
- # Otherwise returns <tt>nil</tt>. The <tt>select_name</tt> is used in the
273
- # finder <tt>:select</tt> option to select fields from database.
274
- # === Example
275
- #
276
- # grid = Fancygrid::Grid.new(:ticket) # select_name => nil
277
- # grid.attributes(:title) # select_name => "tickets.title"
278
- # grid.attributes(:status) # select_name => "tickets.status"
279
- # grid.methods(:foo) # select_name => nil
280
- #
281
- # grid.columns_for(:project) do |p| # select_name => nil
282
- # p.attributes(:description) # select_name => "projects.description"
283
- # end
284
- def select_name
285
- if is_leaf? && selectable && @select_name.nil?
286
- @select_name = "#{self.record_table_name}.#{self.name}"
287
- end
288
- @select_name
289
- end
290
-
291
- # Returns the css selector of this node if it is a leaf. Otherwise returns
292
- # <tt>nil</tt>. The <tt>css_class</tt> is there to identify a column in the rendered output
293
- # and consist of the <tt>record_table_name</tt> and the leafs +name+
294
- # === Example
295
- #
296
- # grid = Fancygrid::Grid.new(:ticket) # css_class => nil
297
- # grid.attributes(:title) # css_class => "tickets title"
298
- # grid.attributes(:status) # css_class => "tickets status"
299
- #
300
- # grid.columns_for(:project) do |p| # css_class => nil
301
- # p.attributes(:description) # css_class => "projects description"
302
- # end
303
- def css_class
304
- if is_leaf? && @css_class.nil?
305
- @css_class = []
306
- @css_class << self.record_table_name
307
- @css_class << self.name
308
- @css_class << "fg-orderable" if self.searchable
309
- @css_class = @css_class.join(" ")
310
- end
311
- @css_class
312
- end
313
-
314
- def applied_sort_order
315
- return "" unless root.view
316
-
317
- # get the sort order from the view. it may look like this: "table.column ASC"
318
- sort_order = root.view.get_sort_order.to_s
319
- sort_order = sort_order.gsub(self.select_name.to_s, "").gsub(" ", "")
320
- if %w(ASC DESC).include?(sort_order)
321
- sort_order
322
- else
323
- ""
324
- end
325
- end
326
-
327
- def search_input_kind
328
- return @search_input_kind if @search_input_kind
329
-
330
- @search_input_kind = :none
331
- root.search_formats.each do |key, values|
332
- next unless values.is_a? Hash
333
- @search_input_kind = key if values.keys.include?(self.select_name)
334
- end
335
-
336
- @search_input_kind
337
- end
338
-
339
- def search_input_options
340
- return @search_input_options if @search_input_options
341
-
342
- @search_input_options = {}
343
-
344
- root.search_formats.each do |key, values|
345
- next unless values.is_a? Hash
346
- opts = values[self.select_name.to_s]
347
- @search_input_options = opts if opts.is_a?(Hash)
88
+ def name_chain
89
+ if @name_chain.nil?
90
+ prefix = (parent and parent.name_chain)
91
+ @name_chain = [prefix, self.name].compact.join(".")
348
92
  end
349
-
350
- @search_input_options
93
+ return @name_chain
351
94
  end
352
-
353
- def search_select_collection
354
- return @search_select_collection if @search_select_collection
355
-
356
- opts = search_input_options
357
-
358
- collection = opts[:collection] || []
359
- text_method = opts[:text_method] || "id"
360
- value_method = opts[:value_method] || "to_s"
361
-
362
- collection = collection.map do |item|
363
- [item.send(text_method), item.send(value_method)]
364
- end
365
-
366
- if opts[:prompt]
367
- collection.insert(0, [opts[:prompt], ""])
368
- else
369
- collection.insert(0, ["", ""])
370
- end
371
-
372
-
373
- @search_select_collection = collection
374
- end
375
-
376
- # Returns the internationalization path for this node if it is a leaf.
377
- # Otherwise returns nil. The <tt>i18n_path</tt> is used to lookup the <tt>human_name</tt>
378
- # of this node and is the <tt>trace_path</tt> preceded with the value from
379
- # <tt>Fancygrid.i18n_scope</tt>
380
- def i18n_path
381
- if is_leaf? && @i18n_path.nil?
382
- @i18n_path = "#{Fancygrid.i18n_scope}.tables.#{self.trace_path}"
383
- end
384
- @i18n_path
385
- end
386
-
387
- # Returns the trace path of this node. A trace path is the path from the
388
- # root node to this node including all names joined with a dot <tt>.</tt>
389
- # === Example
390
- #
391
- # grid = Fancygrid::Grid.new(:ticket)
392
- # grid.columns_for(:project) do |p|
393
- # p.trace_path # => "ticket.project"
394
- # end
395
- # grid.trace_path # => "ticket"
396
-
397
- def trace_path
398
- unless @trace_path
399
- prefix = (parent and parent.trace_path)
400
- @trace_path = [prefix, self.name].compact.join(".")
401
- end
402
- @trace_path
403
- end
404
-
405
- # Sets the human name on this node
406
- def human_name= value
407
- @human_name = value
408
- end
409
-
410
- # Returns a human name of this node if it is a leaf. Otherwie returns <tt>nil</tt>.
411
- def human_name
412
- if is_leaf? && @human_name.nil?
413
- default = self.name.to_s.humanize
414
- if self.record_klass.respond_to?(:human_attribute_name)
415
- default = self.record_klass.human_attribute_name(self.name, :default => default)
416
- end
417
- @human_name = I18n.t(self.i18n_path, :default => default)
418
- end
419
- @human_name
95
+
96
+ # Returns true if this node is the root node of the tree.
97
+ #
98
+ def root?
99
+ self.root.equal?(self)
420
100
  end
421
101
 
422
- # Gets a value from given <tt>record</tt> using the nodes <tt>trace_path</tt>.
423
- # === Example
424
- #
425
- # # having a node with the following trace path
426
- # node # trace_path => "ticket.project.description"
427
- #
428
- # # and a ticket model with an assigned project
429
- # ticket = new Ticket(project)
430
- #
431
- # # then the following are the same
432
- # node.value_from(ticket)
433
- # ticket.project.description
434
- #
435
- # ---
436
- # If the node has a proc, then the trace path is ignored
437
- # === Example
102
+ # Collects all columns into the given collection
438
103
  #
439
- # # having a node with the following trace path
440
- # node # trace_path => "ticket.project.description"
441
- # # and we assign a proc to the node
442
- # node.proc_block = Proc.new { |record| record.project.description }
443
- #
444
- # # and a ticket model with an assigned project
445
- # ticket = new Ticket(project)
446
- #
447
- # # then the following are the same
448
- # node.value_from(ticket)
449
- # ticket.proc_block.call(ticket)
450
- # ticket.project.description
451
- def value_from record
452
- root.log("Resolve '#{self.trace_path}' from '#{record}' (#{record.to_param})")
453
-
454
- if self.proc_block
455
- return proc_block.call(record)
104
+ def collect_columns collection
105
+ self.children.each do |child|
106
+ child.collect_columns collection
456
107
  end
457
-
458
- # default result value is an empty string
459
- value = ""
460
-
461
- # create an array from the nodes trace path and shift the first name away
462
- # since the first name should reference the passed record
463
- reflection_path = self.trace_path.split(/\./)
464
- reflection_path.shift
465
-
466
- # set the current evaluated object and iterate over all reflection path tokens
467
- evaluated = record
468
- while reflection_path.length > 0
469
- token = reflection_path.shift
470
- if(token.blank? || evaluated.nil? || !evaluated.respond_to?(token))
471
- root.log("Step >> '#{evaluated.to_s}'.'#{token}' cant be resolved")
472
- break
473
- end
474
-
475
- value = evaluated.send(token)
476
- root.log("Step >> '#{evaluated.to_s}'.'#{token}' is '#{value.to_s}'")
477
-
478
- evaluated = value
479
- end
480
-
481
- return value
108
+ return collection
482
109
  end
483
-
484
- # Searches for a node in the sub tree with given trace <tt>path</tt>
485
- def find_by_path path
486
- path = path.split(".") unless path.is_a?(Array)
487
-
488
- if (path.first == self.name.to_s)
489
- path.shift
490
- return self if (path.empty?)
491
110
 
492
-
493
- children.each do |node|
494
- result = node.find_by_path(path)
495
- return result if result
496
- end
497
- end
498
-
499
- return nil
500
- end
111
+ protected
501
112
 
502
- protected
503
- def initialize_node(name, klass = nil, table_name = nil, options = nil)
504
- self.name = name
505
- if klass.is_a? Class
506
- self.record_klass = klass
507
- else
508
- self.record_klass = self.name.to_s.classify.constantize
509
- end
510
- if table_name
511
- self.record_table_name = table_name
512
- elsif self.record_klass.respond_to?(:table_name)
513
- self.record_table_name = self.record_klass.table_name
514
- else
515
- self.record_table_name = self.record_klass.name.tableize
516
- end
113
+ # Adds a child to this node.
114
+ #
115
+ def add_child(node)
116
+ raise ArgumentError, "node must be a Fancygrid::Node" unless node.is_a? Fancygrid::Node
117
+ raise ArgumentError, "node must not be a root node" if node.root?
118
+ raise ArgumentError, "node with name #{node.name} has been already inserted" if self.children.any? { |child| child.name == node.name }
119
+ self.children << node
517
120
  end
518
-
519
- # Reads the given options and applies to the nodes attributes
520
- def initialize_leaf options = nil
521
- options ||= {}
522
121
 
523
- self.searchable = options[:searchable]
524
- self.formatable = options[:formatable]
525
- self.visible = options[:visible]
526
- self.search_value = options[:search_value]
527
- self.human_name = options[:human_name]
528
- self.selectable = options[:selectable]
529
- self.proc_block = options[:proc] if options[:proc].is_a? Proc
122
+ # Gets the root node of this tree
123
+ #
124
+ def get_root
125
+ self.parent.nil? ? self : self.parent.get_root
530
126
  end
531
-
532
127
  end
533
128
  end