icentris-rules 0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +33 -0
- data/app/assets/images/pyr_rules/ui-anim_basic_16x16.gif +0 -0
- data/app/assets/javascripts/pyr_rules/rules.js +135 -0
- data/app/assets/stylesheets/pyr_rules/rules.css.scss +258 -0
- data/app/assets/stylesheets/scaffold.css +57 -0
- data/app/controllers/pyr_rules/actions_controller.rb +22 -0
- data/app/controllers/pyr_rules/events_controller.rb +17 -0
- data/app/controllers/pyr_rules/rules_controller.rb +233 -0
- data/app/helpers/pyr_rules/actions_helper.rb +2 -0
- data/app/helpers/pyr_rules/events_helper.rb +95 -0
- data/app/helpers/pyr_rules/rules_helper.rb +10 -0
- data/app/models/pyr_rules.rb +3 -0
- data/app/models/pyr_rules/action.rb +116 -0
- data/app/models/pyr_rules/rule.rb +201 -0
- data/app/rules/pyr_rules/action_handler.rb +94 -0
- data/app/rules/pyr_rules/controller_event_emitter.rb +34 -0
- data/app/rules/pyr_rules/email_action_handler.rb +6 -0
- data/app/rules/pyr_rules/event_concerns.rb +23 -0
- data/app/rules/pyr_rules/event_config_loader.rb +97 -0
- data/app/rules/pyr_rules/event_subscriber.rb +36 -0
- data/app/rules/pyr_rules/model_creation_handler.rb +25 -0
- data/app/rules/pyr_rules/model_event_emitter.rb +80 -0
- data/app/rules/pyr_rules/rule_context.rb +20 -0
- data/app/rules/pyr_rules/rules_config.rb +87 -0
- data/app/rules/pyr_rules/rules_engine.rb +38 -0
- data/app/rules/pyr_rules/web_request_logger.rb +6 -0
- data/app/views/pyr_rules/actions/index.html.erb +12 -0
- data/app/views/pyr_rules/events/_sidebar.html.erb +8 -0
- data/app/views/pyr_rules/events/index.html.erb +72 -0
- data/app/views/pyr_rules/events/show.html.erb +11 -0
- data/app/views/pyr_rules/rules/_form.html.erb +28 -0
- data/app/views/pyr_rules/rules/_ready_headers.js.erb +11 -0
- data/app/views/pyr_rules/rules/_rule_context_field.html.erb +10 -0
- data/app/views/pyr_rules/rules/_rules.html.erb +34 -0
- data/app/views/pyr_rules/rules/add_action_mapping.js.erb +13 -0
- data/app/views/pyr_rules/rules/edit.html.erb +14 -0
- data/app/views/pyr_rules/rules/index.html.erb +5 -0
- data/app/views/pyr_rules/rules/lookup_sub_properties.js.erb +13 -0
- data/app/views/pyr_rules/rules/new.html.erb +11 -0
- data/app/views/pyr_rules/rules/remove_action_mapping.js.erb +15 -0
- data/app/views/pyr_rules/rules/show.html.erb +98 -0
- data/app/views/shared/_action.html.erb +41 -0
- data/app/views/shared/_action_field_mapping.html.erb +33 -0
- data/app/views/shared/_event.html.erb +21 -0
- data/app/views/shared/_rule.html.erb +27 -0
- data/config/routes.rb +32 -0
- data/config/security.yml +9 -0
- data/db/seeds.rb +1 -0
- data/lib/pyr_rules.rb +34 -0
- data/lib/pyr_rules/engine.rb +72 -0
- data/lib/pyr_rules/generators/dummy_generator.rb +27 -0
- data/lib/pyr_rules/version.rb +3 -0
- data/lib/tasks/pyr_rules_tasks.rake +57 -0
- metadata +224 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
body { background-color: #fff; color: #333; }
|
2
|
+
|
3
|
+
body, p, ol, ul, td {
|
4
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
5
|
+
font-size: 13px;
|
6
|
+
line-height: 18px;
|
7
|
+
}
|
8
|
+
|
9
|
+
pre {
|
10
|
+
background-color: #eee;
|
11
|
+
padding: 10px;
|
12
|
+
font-size: 11px;
|
13
|
+
}
|
14
|
+
|
15
|
+
a { color: #000; }
|
16
|
+
a:visited { color: #666; }
|
17
|
+
a:hover { color: #fff; background-color:#000; }
|
18
|
+
|
19
|
+
div.field, div.actions {
|
20
|
+
margin-bottom: 10px;
|
21
|
+
}
|
22
|
+
|
23
|
+
#notice {
|
24
|
+
color: green;
|
25
|
+
}
|
26
|
+
|
27
|
+
.field_with_errors {
|
28
|
+
padding: 2px;
|
29
|
+
background-color: red;
|
30
|
+
display: table;
|
31
|
+
}
|
32
|
+
|
33
|
+
#error_explanation {
|
34
|
+
width: 450px;
|
35
|
+
border: 2px solid red;
|
36
|
+
padding: 7px;
|
37
|
+
padding-bottom: 0;
|
38
|
+
margin-bottom: 20px;
|
39
|
+
background-color: #f0f0f0;
|
40
|
+
}
|
41
|
+
|
42
|
+
#error_explanation h2 {
|
43
|
+
text-align: left;
|
44
|
+
font-weight: bold;
|
45
|
+
padding: 5px 5px 5px 15px;
|
46
|
+
font-size: 12px;
|
47
|
+
margin: -7px;
|
48
|
+
margin-bottom: 0px;
|
49
|
+
background-color: #c00;
|
50
|
+
color: #fff;
|
51
|
+
}
|
52
|
+
|
53
|
+
#error_explanation ul li {
|
54
|
+
font-size: 12px;
|
55
|
+
list-style: square;
|
56
|
+
}
|
57
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class PyrRules::ActionsController < ApplicationController
|
2
|
+
|
3
|
+
def create
|
4
|
+
@rule = PyrRules::Rule.find(params[:rule_id])
|
5
|
+
@action = @rule.actions.create!(params[:pyr_rules_action])
|
6
|
+
|
7
|
+
redirect_to (params[:event_id].presence ? pyr_rules_event_rule_url(@rule, event_id: params[:event_id]) : pyr_rules_rule_url(@rule)), :notice => "Action created!"
|
8
|
+
end
|
9
|
+
|
10
|
+
def destroy
|
11
|
+
@rule = PyrRules::Rule.find(params[:rule_id])
|
12
|
+
@rule.actions.delete(@rule.actions.find(params[:id]))
|
13
|
+
|
14
|
+
redirect_to (params[:event_id].presence ? pyr_rules_event_rule_url(@rule, event_id: params[:event_id]) : pyr_rules_rule_url(@rule)), :notice => "Action deleted!"
|
15
|
+
end
|
16
|
+
|
17
|
+
def index
|
18
|
+
@actions_config = PyrRules::ActionHandler.actions_config
|
19
|
+
@actions = @actions_config.map{|type,needs| a= PyrRules::Action.new;a.type=type;a}
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class PyrRules::EventsController < ApplicationController
|
2
|
+
def index
|
3
|
+
@events_tree = PyrRules::RulesConfig.events_tree
|
4
|
+
respond_to do |format|
|
5
|
+
format.html
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def show
|
10
|
+
@event = PyrRules::RulesConfig.event params[:id]
|
11
|
+
@pyr_rules_rules = PyrRules::Rule.where(event: @event[:name]).all
|
12
|
+
respond_to do |format|
|
13
|
+
format.html
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
module PyrRules
|
2
|
+
class RulesController < ApplicationController
|
3
|
+
|
4
|
+
# before_filter :admin_required # If you include Rules, you want this controller SECURE!!!
|
5
|
+
|
6
|
+
def lookup_events
|
7
|
+
r = Regexp.new(".*#{params[:q]}.*", "i")
|
8
|
+
list = PyrRules::RulesConfig.events.grep r
|
9
|
+
render json: list.first(10).map{|e| {id: e.gsub("::","__") ,value: e}}
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_event
|
13
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
14
|
+
event = params[:event].gsub("__","::") rescue nil
|
15
|
+
@pyr_rules_rule.events << event unless @pyr_rules_rule.events.index event
|
16
|
+
if @pyr_rules_rule.save
|
17
|
+
redirect_to :back, notice: "#{event} is a trigger for this rule"
|
18
|
+
else
|
19
|
+
redirect_to :back, error: "Could not add event: #{event}. Suggest you check the logs and maybe this will help, too: #{@pyr_rules_rule.errors}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def remove_event
|
24
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
25
|
+
event = params[:event].gsub("__","::") rescue nil
|
26
|
+
@pyr_rules_rule.events.delete event
|
27
|
+
if @pyr_rules_rule.save
|
28
|
+
redirect_to :back, notice: "#{event} is no longer a trigger for this rule"
|
29
|
+
else
|
30
|
+
redirect_to :back, error: "Could not remove event: #{event}. Suggest you check the logs and maybe this will help, too: #{@pyr_rules_rule.errors}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def lookup_actions
|
35
|
+
r = Regexp.new(".*#{params[:q]}.*", "i")
|
36
|
+
list = PyrRules::ActionHandler.action_listing.map(&:to_s).grep r
|
37
|
+
render json: list.first(10).map{|a| {id: a.gsub("::","__") ,value: a}}
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_action
|
41
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
42
|
+
action = params[:action_class].gsub("__","::") rescue nil
|
43
|
+
@pyr_rules_rule.actions << PyrRules::Action.new(type: action)
|
44
|
+
if @pyr_rules_rule.save
|
45
|
+
redirect_to :back, notice: "Added event: #{action}"
|
46
|
+
else
|
47
|
+
redirect_to :back, error: "Could not add event: #{action}. Suggest you check the logs and maybe this will help, too: #{@pyr_rules_rule.errors}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def remove_action
|
52
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
53
|
+
action_id = params[:action_id] rescue nil
|
54
|
+
action = @pyr_rules_rule.actions.detect{|a| a.id.to_s == action_id}
|
55
|
+
action.delete if action
|
56
|
+
if @pyr_rules_rule.save
|
57
|
+
redirect_to :back, notice: "Action deleted"
|
58
|
+
else
|
59
|
+
redirect_to :back, error: "Could not remove action. Suggest you check the logs and maybe this will help, too: #{@pyr_rules_rule.errors}"
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def lookup_sub_properties
|
65
|
+
@rule = PyrRules::Rule.find(params[:rule_id])
|
66
|
+
@div_id = request[:div_id]
|
67
|
+
@path = params[:path]
|
68
|
+
@ctx = @rule.lookup_path(@path)
|
69
|
+
respond_to do |format|
|
70
|
+
format.js {}
|
71
|
+
format.json { render json: @ctx }
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_action_mapping
|
78
|
+
PyrRules::Action.add_mapping_type_equivalency(:messaging_user, [:user, :tree_user, :contact])
|
79
|
+
PyrRules::Action.add_mapping_type_equivalency(:object, [:user, :messaging_user, :contact, :string])
|
80
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
81
|
+
action_id = params[:action_id]
|
82
|
+
rule_field = params[:rule_field]
|
83
|
+
action_field = params[:action_field]
|
84
|
+
@action = @pyr_rules_rule.actions.detect{|a| a.id.to_s == action_id}
|
85
|
+
@was_mapped = @action.context_mapping[action_field]
|
86
|
+
@action_field_name = action_field.split(":").first
|
87
|
+
@action_field_type = action_field.split(":").last
|
88
|
+
if @action_field_type == :class_lookup
|
89
|
+
klazz = rule_field.constantize
|
90
|
+
@action.context_mapping[action_field] = rule_field
|
91
|
+
@pyr_rules_rule.save
|
92
|
+
else
|
93
|
+
@rule_field_name = rule_field.split(":").first
|
94
|
+
rule_type = rule_field.split(":").last
|
95
|
+
if PyrRules::Action.check_mapping_type?(@action_field_type, rule_type)
|
96
|
+
@action.context_mapping[action_field] = rule_field
|
97
|
+
@pyr_rules_rule.save
|
98
|
+
else
|
99
|
+
@error = "Illegal field type mapping from #{rule_type} to #{@action_field_type}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
respond_to do |format|
|
103
|
+
format.html { redirect_to pyr_rules_rule_path(@pyr_rules_rule) }
|
104
|
+
format.js {}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
def remove_action_mapping
|
110
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
111
|
+
action_id = params[:action_id]
|
112
|
+
action_field = params[:action_field]
|
113
|
+
@action = @pyr_rules_rule.actions.detect{|a| a.id.to_s == action_id}
|
114
|
+
@action_field_name = action_field.split(":").first
|
115
|
+
@action_field_type = action_field.split(":").last
|
116
|
+
mapped_from = @action.context_mapping[action_field]
|
117
|
+
if mapped_from
|
118
|
+
@action.context_mapping[action_field] = nil
|
119
|
+
@rule_field_name = mapped_from.split(":").first
|
120
|
+
@rule_field_type = mapped_from.split(":").last
|
121
|
+
@message = "Removed field mapping for #{@action_field_name}"
|
122
|
+
else
|
123
|
+
@message = "#{action_field} was not mapped"
|
124
|
+
end
|
125
|
+
@pyr_rules_rule.save
|
126
|
+
respond_to do |format|
|
127
|
+
format.html { redirect_to pyr_rules_rule_path(@pyr_rules_rule) }
|
128
|
+
format.js {}
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def reload_rules_engine
|
133
|
+
c = PyrRules::RulesEngine.reload_configuration
|
134
|
+
notice = "Loaded #{c[:events].try(:size) || '0'} Events and #{c[:actions].try(:size) || '0'} Actions "
|
135
|
+
redirect_to :back, notice: notice
|
136
|
+
end
|
137
|
+
|
138
|
+
# GET /pyr_rules/rules
|
139
|
+
# GET /pyr_rules/rules.json
|
140
|
+
def index
|
141
|
+
@pyr_rules_rules = params[:event_id].presence ? PyrRules::Rule.where(event: params[:event_id]).all : PyrRules::Rule.all
|
142
|
+
|
143
|
+
respond_to do |format|
|
144
|
+
format.html # index.html.erb
|
145
|
+
format.json { render json: @pyr_rules_rules }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# GET /pyr_rules/rules/1
|
150
|
+
# GET /pyr_rules/rules/1.json
|
151
|
+
def show
|
152
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
153
|
+
|
154
|
+
respond_to do |format|
|
155
|
+
format.html # show.html.erb
|
156
|
+
format.json { render json: @pyr_rules_rule }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# GET /pyr_rules/rules/new
|
161
|
+
# GET /pyr_rules/rules/new.json
|
162
|
+
def new
|
163
|
+
@pyr_rules_rule = PyrRules::Rule.new
|
164
|
+
@pyr_rules_rule.event = params[:event_id] if params[:event_id]
|
165
|
+
|
166
|
+
respond_to do |format|
|
167
|
+
format.html # new.html.erb
|
168
|
+
format.json { render json: @pyr_rules_rule }
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# GET /pyr_rules/rules/1/edit
|
173
|
+
def edit
|
174
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
175
|
+
end
|
176
|
+
|
177
|
+
# POST /pyr_rules/rules
|
178
|
+
# POST /pyr_rules/rules.json
|
179
|
+
def create
|
180
|
+
@pyr_rules_rule = PyrRules::Rule.new(params[:pyr_rules_rule])
|
181
|
+
|
182
|
+
respond_to do |format|
|
183
|
+
if @pyr_rules_rule.save
|
184
|
+
format.html { redirect_to (params[:event_id].presence ? pyr_rules_event_rule_url(@pyr_rules_rule, event_id: params[:event_id]) : pyr_rules_rule_url(@pyr_rules_rule)), notice: 'Rule was successfully created.' }
|
185
|
+
format.json { render json: @pyr_rules_rule, status: :created, location: @pyr_rules_rule }
|
186
|
+
else
|
187
|
+
format.html { render action: "new" }
|
188
|
+
format.json { render json: @pyr_rules_rule.errors, status: :unprocessable_entity }
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# PUT /pyr_rules/rules/1
|
194
|
+
# PUT /pyr_rules/rules/1.json
|
195
|
+
def update
|
196
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
197
|
+
# {"action"=>{"522e0313a4c6b2154c000001"=>{"template"=>{"name"=>"asdf"}}}}
|
198
|
+
action_update = params[:pyr_rules_rule].delete(:action) rescue nil
|
199
|
+
if action_update
|
200
|
+
action_id = action_update.keys.first
|
201
|
+
action = @pyr_rules_rule.actions.detect{|a| a.id.to_s == action_id}
|
202
|
+
puts "Updating Rule #{@pyr_rules_rule.name}- Action #{action.class}"
|
203
|
+
template_name = action_update.values.first[:template].keys.first
|
204
|
+
template_value = action_update.values.first[:template].values.first
|
205
|
+
puts "TemplateName[#{template_name}] TemplateValue[#{template_value}]"
|
206
|
+
action.template[template_name] = template_value
|
207
|
+
@pyr_rules_rule.save!
|
208
|
+
end
|
209
|
+
respond_to do |format|
|
210
|
+
if @pyr_rules_rule.update_attributes(params[:pyr_rules_rule])
|
211
|
+
format.html { redirect_to (params[:event_id].presence ? pyr_rules_event_rule_url(@pyr_rules_rule, event_id: params[:event_id]) : pyr_rules_rule_url(@pyr_rules_rule)), notice: 'Rule was successfully updated.' }
|
212
|
+
format.json { head :no_content }
|
213
|
+
else
|
214
|
+
format.html { render action: "edit" }
|
215
|
+
format.json { render json: @pyr_rules_rule.errors, status: :unprocessable_entity }
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# DELETE /pyr_rules/rules/1
|
221
|
+
# DELETE /pyr_rules/rules/1.json
|
222
|
+
def destroy
|
223
|
+
@pyr_rules_rule = PyrRules::Rule.find(params[:id])
|
224
|
+
@pyr_rules_rule.destroy
|
225
|
+
|
226
|
+
respond_to do |format|
|
227
|
+
format.html { redirect_to (params[:event_id].presence ? pyr_rules_event_rules_url(event_id: params[:event_id]) : pyr_rules_rules_url) }
|
228
|
+
format.json { head :no_content }
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# :model_events=>
|
2
|
+
# {"PyrCommunity"=>
|
3
|
+
# {"Blog"=>
|
4
|
+
# {:context=>
|
5
|
+
# {"id"=>{:type=>:integer},
|
6
|
+
# "title"=>{:type=>:string},
|
7
|
+
# "author_id"=>{:type=>:integer},
|
8
|
+
# "disqus_shortname"=>{:type=>:string},
|
9
|
+
# "background_tile"=>{:type=>:boolean},
|
10
|
+
# "background_blur"=>{:type=>:integer},
|
11
|
+
# "footer"=>{:type=>:text},
|
12
|
+
# "description"=>{:type=>:text},
|
13
|
+
# "twitter"=>{:type=>:string},
|
14
|
+
# "google_analytics"=>{:type=>:string},
|
15
|
+
# "background_uid"=>{:type=>:string},
|
16
|
+
# "logo_uid"=>{:type=>:string},
|
17
|
+
# "created_at"=>{:type=>:datetime},
|
18
|
+
# "updated_at"=>{:type=>:datetime}},
|
19
|
+
# :actions=>[:create, :update, :delete]}
|
20
|
+
# }
|
21
|
+
# },
|
22
|
+
# "PyrCore"=>
|
23
|
+
# {"Lead"=>
|
24
|
+
# {:context=>
|
25
|
+
# {"id"=>{:type=>:integer},
|
26
|
+
# "first_name"=>{:type=>:string},
|
27
|
+
# "last_name"=>{:type=>:string},
|
28
|
+
# "email"=>{:type=>:string},
|
29
|
+
# "phone"=>{:type=>:string},
|
30
|
+
# "lead_group"=>{:type=>:string},
|
31
|
+
# "comments"=>{:type=>:text},
|
32
|
+
# "user_id"=>{:type=>:integer},
|
33
|
+
# "created_at"=>{:type=>:datetime},
|
34
|
+
# "updated_at"=>{:type=>:datetime}},
|
35
|
+
# :actions=>[:create, :update, :delete]}}}}
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
module PyrRules::EventsHelper
|
40
|
+
|
41
|
+
|
42
|
+
def render_tree(events_tree)
|
43
|
+
stack = []
|
44
|
+
content_tag :div, id: "events_tree" do
|
45
|
+
body = ""
|
46
|
+
events_tree.each do |event_type, sub_events|
|
47
|
+
body += _render_and_recurse(event_type, sub_events, stack) + "\n"
|
48
|
+
end
|
49
|
+
body.html_safe
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def _render_and_recurse(key,children,stack)
|
55
|
+
return "" if key.blank? # escape - don't render context variables
|
56
|
+
body = ""
|
57
|
+
if key == :actions # render each action as a leaf
|
58
|
+
children.each do |action|
|
59
|
+
body += _render_action_leaf(action, stack)
|
60
|
+
end
|
61
|
+
elsif key == :context
|
62
|
+
body = content_tag :div, class: "collapse-group", style:"block:inline;margin-left:30px;padding:5px;" do
|
63
|
+
content_tag :div, id:"#{stack.join('_')}_context", class: "collapse", style: "block:inline;padding:5px;min-height:30px;" do
|
64
|
+
context = children.collect{|k,v| "<b>#{k}</b> (<i>#{v}</i>)"}.join("<br/>")
|
65
|
+
inner_body = "<a class='btn btn-mini' data-toggle='collapse' data-target='##{stack.join('_')}_context'>context</a>".html_safe
|
66
|
+
inner_body += "<div class='collapse-group'>#{context}</div>".html_safe
|
67
|
+
inner_body += "<div style='clear:both;'></div>".html_safe
|
68
|
+
end
|
69
|
+
end
|
70
|
+
else
|
71
|
+
stack.push key
|
72
|
+
body += content_tag :div, class: "collapse-group", style: "margin-left:30px;position:relative;" do
|
73
|
+
content_tag :div, id:"#{stack.join('_')}", class: "collapse", style: "padding:5px;min-height:30px;" do
|
74
|
+
inner_body = "<a class='btn btn-mini' data-toggle='collapse' data-target='##{stack.join('_')}'>+</a><span style='font-weight:bold;'>#{key.to_s.titleize}</span>"
|
75
|
+
children.each do |child_key, grandkids|
|
76
|
+
#inner_body += " " * stack.size
|
77
|
+
inner_body += _render_and_recurse(child_key, grandkids, stack) + "\n"
|
78
|
+
end
|
79
|
+
inner_body.html_safe
|
80
|
+
end
|
81
|
+
end
|
82
|
+
stack.pop
|
83
|
+
end
|
84
|
+
body.html_safe
|
85
|
+
end
|
86
|
+
|
87
|
+
def _render_action_leaf(action_name, stack)
|
88
|
+
name = "#{stack.join('::')}_#{action_name}"
|
89
|
+
content_tag :div, id: name, style:"margin-left:30px;padding:5px;" do
|
90
|
+
content_tag :input, name: name, type: "checkbox" do
|
91
|
+
"<span style='margin-left:10px;'>#{action_name.to_s}</span>".html_safe
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|