icentris-rules 0.9
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 +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
|