lolita-menu 0.3.6 → 0.4.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.
- checksums.yaml +7 -0
- data/.gitignore +47 -0
- data/Gemfile +8 -11
- data/Rakefile +4 -43
- data/app/assets/javascripts/lolita/menu/autocomplete-rails.js +1 -1
- data/app/assets/javascripts/lolita/menu/menu-items.js +5 -5
- data/app/assets/stylesheets/lolita/menu/application.css +21 -0
- data/app/controllers/menu_items_controller.rb +4 -0
- data/app/controllers/nested_trees_controller.rb +46 -46
- data/app/models/menu.rb +1 -7
- data/app/models/menu_item.rb +13 -17
- data/app/views/components/lolita/menu/nested_tree/_display.html.haml +0 -1
- data/lib/generators/lolita/menu/templates/migrations/create_menu_items.rb +1 -1
- data/lib/lolita-menu/nested_tree.rb +253 -253
- data/lib/lolita-menu/nested_tree/branch_builder.rb +58 -58
- data/lib/lolita-menu/nested_tree/configuration.rb +72 -72
- data/lib/lolita-menu/nested_tree/scope.rb +52 -52
- data/lib/lolita-menu/nested_tree/tree_builder.rb +29 -29
- data/lolita-menu.gemspec +6 -110
- data/spec/models/menu_item_spec.rb +6 -6
- data/spec/models/menu_spec.rb +0 -1
- data/test_orm/active_record.rb +4 -6
- data/test_orm/log/.gitkeep +0 -0
- data/test_orm/rails/config/application.rb +2 -3
- data/test_orm/rails/log/.gitkeep +0 -0
- metadata +34 -129
@@ -4,103 +4,103 @@ require "lolita-menu/nested_tree/branch_builder"
|
|
4
4
|
require "lolita-menu/nested_tree/tree_builder"
|
5
5
|
|
6
6
|
module Lolita
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
7
|
+
module Menu
|
8
|
+
module NestedTree
|
9
|
+
def self.included(base_class)
|
10
|
+
base_class.extend(Lolita::Menu::NestedTree::ClassMethods)
|
11
|
+
base_class.class_eval do
|
12
|
+
include Lolita::Menu::NestedTree::InstanceMethods
|
13
|
+
attr_accessor :place
|
14
|
+
before_create :set_default_positions
|
15
|
+
after_create :put_in_place
|
16
|
+
end
|
17
|
+
if base_class.respond_to?(:after_lolita_loaded)
|
18
|
+
base_class.after_lolita_loaded do
|
19
|
+
if self.lolita_nested_tree.scope_classes.any?
|
20
|
+
parent_scope_columns = self.lolita_nested_tree.scope_classes.first.lolita.list.columns
|
21
|
+
parent_scope_actions = self.lolita_nested_tree.scope_classes.first.lolita.list.actions
|
22
|
+
#parent_scope_columns.actions = self.lolita.list.columns.actions
|
23
|
+
self.lolita.list.columns = parent_scope_columns
|
24
|
+
self.lolita.list.instance_variable_set(:@temp_actions, parent_scope_actions)
|
25
|
+
end
|
26
|
+
self.lolita.list.pagination_method ||= :paginate_nested_tree
|
27
|
+
self.lolita.list.builder = {:name => "/lolita/menu/nested_tree", :state => :display, :if =>{:state =>:display}}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.is_tree?(klass)
|
33
|
+
klass.respond_to?(:lolita_nested_tree) && klass.lolita_nested_tree
|
34
|
+
end
|
35
|
+
|
36
|
+
module ClassMethods
|
37
|
+
|
38
|
+
def paginate_nested_tree(page,per_page,options)
|
39
|
+
if scope_class = self.lolita_nested_tree.scope_classes.first
|
40
|
+
scope_class.page(page).per(per_page)
|
41
|
+
else
|
42
|
+
where(nil)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_root!
|
47
|
+
new_branch = self.build_empty_branch(default_root_position)
|
48
|
+
new_branch.save!
|
49
|
+
new_branch
|
50
|
+
end
|
51
|
+
|
52
|
+
def find_or_create_root(attributes = {})
|
53
|
+
if root = self.with_tree_scope(attributes).root
|
54
|
+
root
|
55
|
+
else
|
56
|
+
root = nil
|
57
|
+
self.with_tree_scope(attributes) do
|
58
|
+
root = create_root!
|
59
|
+
end
|
60
|
+
root
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def default_root_position
|
65
|
+
{
|
66
|
+
:lft=>1,
|
67
|
+
:rgt=>2,
|
68
|
+
:depth=>0,
|
69
|
+
:parent_id=>nil
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def root
|
74
|
+
where(with_tree_scope.merge(:parent_id=>nil)).where("lft>0").order("lft asc").first
|
75
|
+
end
|
76
|
+
|
77
|
+
def with_tree_scope(record_or_hash=nil, &block)
|
78
|
+
if record_or_hash
|
79
|
+
scope_hash = record_or_hash.respond_to?(:to_scope_hash) ? record_or_hash.to_scope_hash : record_or_hash
|
80
|
+
if block_given?
|
81
|
+
begin
|
82
|
+
@lolita_menu_nested_tree_scope = scope_hash
|
83
|
+
instance_eval(&block)
|
84
|
+
ensure
|
85
|
+
@lolita_menu_nested_tree_scope = nil
|
86
|
+
end
|
87
|
+
else
|
88
|
+
where(scope_hash)
|
89
|
+
end
|
90
|
+
else
|
91
|
+
@lolita_menu_nested_tree_scope || {}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def update_whole_tree(items, params = {})
|
96
|
+
begin
|
97
|
+
self.transaction do
|
98
|
+
tree_builder = Lolita::Menu::NestedTree::TreeBuilder.new(self, items, params)
|
99
|
+
tree_builder.update_items
|
100
|
+
true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
104
|
|
105
105
|
def build_empty_branch(attributes)
|
106
106
|
if self.lolita_nested_tree.build_method && self.respond_to?(self.lolita_nested_tree.build_method)
|
@@ -110,166 +110,166 @@ module Lolita
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
|
114
|
-
|
115
|
-
|
113
|
+
def update_item(item)
|
114
|
+
self.where(:id => item.value_for(:item_id)).update_all(item.attribute_value_pairs_hash)
|
115
|
+
end
|
116
116
|
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
def remove_items(ids)
|
118
|
+
self.where(:id => ids).delete_all
|
119
|
+
end
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
121
|
+
def all_tree_item_ids
|
122
|
+
self.all.map(&:id)
|
123
|
+
end
|
124
124
|
|
125
125
|
def only_children
|
126
126
|
where("rgt-lft=1")
|
127
127
|
end
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
128
|
+
end
|
129
|
+
|
130
|
+
module InstanceMethods
|
131
|
+
def root?
|
132
|
+
self.parent_id.nil?
|
133
|
+
end
|
134
|
+
|
135
|
+
def parent
|
136
|
+
@parent ||= self.class.find_by_id(self.parent_id)
|
137
|
+
end
|
138
|
+
|
139
|
+
def parent=(parent_item)
|
140
|
+
@parent = parent_item
|
141
|
+
end
|
142
|
+
|
143
|
+
def children
|
144
|
+
@children ||= self.class.where(:parent_id => self.id).with_tree_scope(self).order("lft asc")
|
145
|
+
end
|
146
|
+
|
147
|
+
def self_and_descendants
|
148
|
+
@self_and_descendants ||= self.class.where("lft>=:left AND rgt<=:right",{
|
149
|
+
:left => self.lft,:right => self.rgt
|
150
|
+
}).with_tree_scope(self).order("lft asc")
|
151
|
+
end
|
152
|
+
|
153
|
+
def descendants
|
154
|
+
@descendants ||= self.class.where("lft>:left AND rgt<:right",{
|
155
|
+
:left => self.lft, :right => self.rgt
|
156
|
+
}).with_tree_scope(self).order("lft asc")
|
157
|
+
end
|
158
|
+
|
159
|
+
def ancestors
|
160
|
+
@ancestors ||= self.class.where("lft<:left AND rgt>:right AND parent_id IS NOT NULL",{
|
161
|
+
:left => self.lft, :right => self.rgt
|
162
|
+
}).with_tree_scope(self).order("lft asc")
|
163
|
+
end
|
164
|
+
|
165
|
+
def parents
|
166
|
+
unless @parent
|
167
|
+
current_parent_id = self.parent_id
|
168
|
+
@parents = self.ancestors.reverse.inject([]){|results,item|
|
169
|
+
if item.parent_id && item.id == current_parent_id
|
170
|
+
current_parent_id = item.parent_id
|
171
|
+
[item] + results
|
172
|
+
else
|
173
|
+
results
|
174
|
+
end
|
175
|
+
}
|
176
|
+
end
|
177
|
+
@parents
|
178
|
+
end
|
179
|
+
|
180
|
+
def only_children
|
181
|
+
@only_children ||= self.class.with_tree_scope(self).order("lft asc")
|
182
|
+
end
|
183
|
+
|
184
|
+
def root
|
185
|
+
if self.parent_id.nil?
|
186
|
+
self
|
187
|
+
else
|
188
|
+
self.class.root
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def append(item)
|
193
|
+
raise ArgumentError, "can't append itself" if self == item
|
194
|
+
append_item(item)
|
195
|
+
recalculate_positions_after(:append)
|
196
|
+
end
|
197
|
+
|
198
|
+
def to_scope_hash
|
199
|
+
self.class.lolita_nested_tree.scope_keys.inject({}) do |result, key|
|
200
|
+
result[key] = self.send(key)
|
201
|
+
result
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
private
|
206
|
+
|
207
|
+
def set_default_positions
|
208
|
+
if am_i_new_root? #|| !scope_ids.all?
|
209
|
+
set_root_position
|
210
|
+
else
|
211
|
+
self.place=:append
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def am_i_new_root?
|
216
|
+
#scope_ids.all? && scope_records.all? &&
|
217
|
+
!(self.class.with_tree_scope(self) do
|
218
|
+
root
|
219
|
+
end)
|
220
|
+
end
|
221
|
+
|
222
|
+
#def scope_ids
|
223
|
+
# self.class.lolita_nested_tree.scope_keys.map do |key|
|
224
|
+
# self.send(key)
|
225
|
+
# end
|
226
|
+
#end
|
227
|
+
|
228
|
+
#def scope_records
|
229
|
+
# self.class.lolita_nested_tree.scope_keys.map do |scope|
|
230
|
+
# scope.constantize.exists?(self.send(scope.foreign_key.to_sym))
|
231
|
+
# end
|
232
|
+
#end
|
233
|
+
|
234
|
+
def put_in_place
|
235
|
+
if place==:append
|
236
|
+
item = self
|
237
|
+
self.class.with_tree_scope(self) do
|
238
|
+
root.append(item)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def set_root_position
|
244
|
+
self.class.default_root_position.each do |method,value|
|
245
|
+
unless self.send(method)
|
246
|
+
self.send(:"#{method}=",value)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def append_item(item)
|
252
|
+
attributes = self.class.with_tree_scope.merge(position_for_append)
|
253
|
+
builder = Lolita::Menu::NestedTree::BranchBuilder.new(nil, attributes)
|
254
|
+
self.class.where(:id => item.id).update_all(builder.attribute_value_pairs_hash)
|
255
|
+
end
|
256
|
+
|
257
|
+
def recalculate_positions_after(action)
|
258
|
+
if action==:append
|
259
|
+
self.class.update_all("rgt=#{self.rgt+2}","id=#{self.id}")
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def position_for_append
|
264
|
+
{
|
265
|
+
:left => self.rgt,
|
266
|
+
:right => self.rgt+1,
|
267
|
+
:depth => self.depth+1,
|
268
|
+
:parent_id => self.id
|
269
|
+
}
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
end
|
274
|
+
end
|
275
275
|
end
|