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.
- data/CHANGELOG +9 -2
- data/Gemfile +6 -9
- data/Gemfile.lock +88 -103
- data/README.md +226 -0
- data/ROADMAP +0 -1
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/app/views/fancygrid/controls.html.haml +34 -0
- data/app/views/fancygrid/fancygrid.html.haml +18 -0
- data/app/views/fancygrid/search.html.haml +24 -0
- data/app/views/fancygrid/sort.html.haml +8 -0
- data/app/views/fancygrid/table.html.haml +25 -0
- data/config/locales/fancygrid.de.yml +17 -19
- data/config/locales/fancygrid.en.yml +14 -17
- data/fancygrid.gemspec +48 -88
- data/lib/assets/javascripts/fancygrid.js +425 -0
- data/lib/assets/javascripts/fancygrid.min.js +15 -0
- data/lib/assets/stylesheets/fancygrid.css +177 -0
- data/lib/fancygrid.rb +63 -44
- data/lib/fancygrid/column.rb +165 -0
- data/lib/fancygrid/controller/helper.rb +46 -0
- data/lib/fancygrid/grid.rb +171 -317
- data/lib/fancygrid/node.rb +85 -490
- data/lib/fancygrid/object_wrapper.rb +24 -0
- data/lib/fancygrid/orm/active_record.rb +39 -0
- data/lib/fancygrid/orm/sql_generator.rb +127 -0
- data/lib/fancygrid/view/helper.rb +44 -0
- data/lib/fancygrid/view_state.rb +161 -0
- data/spec/column_spec.rb +29 -0
- data/spec/dummy/app/controllers/application_controller.rb +48 -0
- data/spec/dummy/app/views/application/index.html.haml +11 -0
- data/spec/dummy/app/views/layouts/application.html.erb +1 -1
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/environments/development.rb +2 -2
- data/spec/dummy/config/environments/test.rb +2 -2
- data/spec/dummy/config/routes.rb +3 -2
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +26 -0
- data/spec/dummy/public/javascripts/jquery-1.4.2.js +6240 -0
- data/spec/dummy/public/javascripts/jquery-fancygrid.js +425 -0
- data/spec/dummy/public/javascripts/jquery-ui.js +41 -0
- data/spec/dummy/public/stylesheets/fancygrid.css +183 -0
- data/spec/node_spec.rb +79 -301
- data/spec/spec_helper.rb +0 -29
- data/spec/view_state_spec.rb +91 -0
- metadata +124 -137
- data/.bundle/config +0 -2
- data/README.rdoc +0 -299
- data/app/views/fancygrid/_cells.html.haml +0 -13
- data/app/views/fancygrid/base/controls.html.haml +0 -40
- data/app/views/fancygrid/base/list_frame.html.haml +0 -37
- data/app/views/fancygrid/base/search.html.haml +0 -33
- data/app/views/fancygrid/base/sort.html.haml +0 -20
- data/app/views/fancygrid/base/table_frame.html.haml +0 -45
- data/config/initializers/fancygrid.rb +0 -67
- data/lib/fancygrid/helper.rb +0 -129
- data/lib/fancygrid/query_generator.rb +0 -340
- data/lib/fancygrid/view.rb +0 -148
- data/lib/generators/install_generator.rb +0 -61
- data/lib/generators/views_generator.rb +0 -25
- data/lib/version.rb +0 -0
- data/public/images/fancygrid/add.png +0 -0
- data/public/images/fancygrid/clear.png +0 -0
- data/public/images/fancygrid/ddn.png +0 -0
- data/public/images/fancygrid/dn.png +0 -0
- data/public/images/fancygrid/dots.png +0 -0
- data/public/images/fancygrid/loading.gif +0 -0
- data/public/images/fancygrid/magnifier.png +0 -0
- data/public/images/fancygrid/next.png +0 -0
- data/public/images/fancygrid/order.png +0 -0
- data/public/images/fancygrid/prev.png +0 -0
- data/public/images/fancygrid/reload.png +0 -0
- data/public/images/fancygrid/remove.png +0 -0
- data/public/images/fancygrid/spacer.gif +0 -0
- data/public/images/fancygrid/submit.png +0 -0
- data/public/images/fancygrid/th_bg.png +0 -0
- data/public/images/fancygrid/up.png +0 -0
- data/public/images/fancygrid/uup.png +0 -0
- data/public/javascripts/fancygrid.js +0 -477
- data/public/javascripts/fancygrid.min.js +0 -17
- data/public/stylesheets/fancygrid.css +0 -289
- data/public/stylesheets/fancygrid.scss +0 -302
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/production.log +0 -0
- data/spec/dummy/log/server.log +0 -0
- data/spec/dummy/log/test.log +0 -1026
- data/spec/dummy/public/javascripts/application.js +0 -2
- data/spec/dummy/public/javascripts/controls.js +0 -965
- data/spec/dummy/public/javascripts/dragdrop.js +0 -974
- data/spec/dummy/public/javascripts/effects.js +0 -1123
- data/spec/dummy/public/javascripts/prototype.js +0 -6001
- data/spec/dummy/public/javascripts/rails.js +0 -175
- data/spec/grid_spec.rb +0 -15
- data/spec/integration/navigation_spec.rb +0 -9
- data/spec/query_generator_spec.rb +0 -358
data/lib/fancygrid/node.rb
CHANGED
@@ -1,533 +1,128 @@
|
|
1
|
-
|
2
|
-
module Fancygrid#:nodoc:
|
1
|
+
module Fancygrid
|
3
2
|
|
4
3
|
class Node
|
5
4
|
|
6
|
-
#
|
7
|
-
|
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
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
#
|
31
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
66
|
-
|
29
|
+
@parent = parent
|
30
|
+
@name = name
|
31
|
+
@children = []
|
32
|
+
@root = self.get_root
|
67
33
|
|
68
|
-
|
69
|
-
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
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
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
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
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
151
|
-
#
|
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
|
-
|
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] =
|
171
|
-
options[:
|
172
|
-
options[:
|
173
|
-
|
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
|
178
|
-
#
|
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
|
-
|
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] =
|
198
|
-
options[:
|
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
|
-
#
|
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
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
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
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
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
|
-
#
|
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
|
-
|
440
|
-
|
441
|
-
|
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
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
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
|
-
|
524
|
-
|
525
|
-
|
526
|
-
self.
|
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
|