drg_cms 0.6.0.3 → 0.6.0.6

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/drg_cms/drg_cms.js +259 -102
  3. data/app/assets/javascripts/drg_cms_cms.js +1 -1
  4. data/app/assets/stylesheets/drg_cms/drg_cms.css +314 -142
  5. data/app/assets/stylesheets/drg_cms/select-multiple.css +11 -2
  6. data/app/controllers/cmsedit_controller.rb +313 -236
  7. data/app/controllers/dc_application_controller.rb +29 -4
  8. data/app/controllers/dc_common_controller.rb +19 -16
  9. data/app/{controllers → controls}/browse_models_control.rb +0 -0
  10. data/app/{controllers → controls}/dc_page_control.rb +24 -8
  11. data/app/controls/dc_poll_result_control.rb +88 -0
  12. data/app/{controllers → controls}/design_element_settings_control.rb +0 -0
  13. data/app/forms/all_options.yml +11 -3
  14. data/app/forms/cms_menu.yml +22 -18
  15. data/app/forms/dc_design.yml +6 -3
  16. data/app/forms/dc_filter.yml +3 -6
  17. data/app/forms/dc_poll_result.yml +74 -0
  18. data/app/forms/dc_poll_result_export.yml +35 -0
  19. data/app/helpers/cmsedit_edit_helper.rb +471 -0
  20. data/app/helpers/cmsedit_helper.rb +151 -821
  21. data/app/helpers/cmsedit_index_helper.rb +567 -0
  22. data/app/helpers/dc_application_helper.rb +48 -31
  23. data/app/models/{dc_dummy.rb → __dc_dummy.rb} +0 -0
  24. data/app/models/dc_filter.rb +12 -5
  25. data/app/models/dc_memory.rb +8 -1
  26. data/app/models/dc_poll.rb +38 -19
  27. data/app/models/dc_poll_result.rb +44 -0
  28. data/app/models/dc_temp.rb +137 -0
  29. data/app/models/drgcms_form_fields/action.rb +61 -0
  30. data/app/models/drgcms_form_fields/comment.rb +8 -4
  31. data/app/models/drgcms_form_fields/date_picker.rb +7 -6
  32. data/app/models/drgcms_form_fields/date_select.rb +1 -1
  33. data/app/models/drgcms_form_fields/datetime_picker.rb +8 -7
  34. data/app/models/drgcms_form_fields/datetime_select.rb +1 -1
  35. data/app/models/drgcms_form_fields/drgcms_field.rb +39 -7
  36. data/app/models/drgcms_form_fields/embedded.rb +7 -2
  37. data/app/models/drgcms_form_fields/file_field.rb +52 -0
  38. data/app/models/drgcms_form_fields/html_field.rb +1 -1
  39. data/app/models/drgcms_form_fields/multitext_autocomplete.rb +7 -4
  40. data/app/models/drgcms_form_fields/number_field.rb +15 -6
  41. data/app/models/drgcms_form_fields/radio.rb +91 -0
  42. data/app/models/drgcms_form_fields/readonly.rb +1 -1
  43. data/app/models/drgcms_form_fields/select.rb +14 -2
  44. data/app/models/drgcms_form_fields/text_area.rb +1 -1
  45. data/app/models/drgcms_form_fields/text_autocomplete.rb +1 -1
  46. data/app/models/drgcms_form_fields/text_field.rb +1 -1
  47. data/app/models/drgcms_form_fields/text_with_select.rb +6 -3
  48. data/app/models/drgcms_form_fields/tree_select.rb +11 -3
  49. data/app/renderers/dc_poll_renderer.rb +29 -11
  50. data/app/views/cmsedit/{remove_edit_stuff.js.erb → __remove_edit_stuff.js.erb} +0 -0
  51. data/app/views/cmsedit/{show.html.erb → __show.html.erb} +0 -0
  52. data/app/views/cmsedit/_edit_stuff.html.erb +2 -4
  53. data/app/views/cmsedit/_form.html.erb +4 -3
  54. data/app/views/cmsedit/_result.html.erb +2 -3
  55. data/app/views/cmsedit/edit.html.erb +2 -1
  56. data/app/views/cmsedit/index.html.erb +6 -1
  57. data/app/views/cmsedit/new.html.erb +1 -1
  58. data/config/locales/drgcms_en.yml +7 -0
  59. data/config/locales/drgcms_sl.yml +8 -1
  60. data/config/locales/models_en.yml +13 -4
  61. data/config/locales/models_sl.yml +13 -2
  62. data/drg_cms.gemspec +1 -1
  63. data/lib/drg_cms.rb +1 -0
  64. data/lib/drg_cms/version.rb +1 -1
  65. data/lib/generators/new_drg_form/new_drg_form_generator.rb +7 -2
  66. metadata +20 -13
  67. data/app/assets/stylesheets/drg_cms/__jquery-ui.css +0 -339
  68. data/test/fixtures/drg_cms_test_data.rb +0 -87
@@ -23,871 +23,201 @@
23
23
 
24
24
  ###########################################################################
25
25
  #
26
- # CmseditHelper module defines helper methods used by cmsedit actions. Output is controlled by
27
- # data found in 3 major sections of DRG CMS form: index, result_set and form sections.
26
+ # CmseditHelper module defines common methods used for DRGCMS forms.
28
27
  #
29
28
  ###########################################################################
30
29
  module CmseditHelper
31
30
  # javascript part created by form helpers
32
31
  attr_reader :js
33
32
 
34
- ############################################################################
35
- # Get standard actions when actions directive contains single line.
36
- # Subroutine of dc_actions_for_index
37
- #
38
- # Allows for actions: new, filter, standard syntax
39
- ############################################################################
40
- def define_standard_actions(actions_params, standard)
41
- actions = {}
42
- actions_params.split(',').each do |an_action|
43
- an_action.strip!
44
- if an_action == 'standard'
45
- actions.merge!(standard)
46
- else
47
- standard.each do |index, action|
48
- (actions[index] = action; break) if action == an_action
49
- end
50
- end
51
- end
52
- actions
53
- end
54
-
55
- ############################################################################
56
- # Creates action div for cmsedit index action.
57
- ############################################################################
58
- def dc_actions_for_index()
59
- return '' if @form['index'].nil? or @form['readonly']
60
- actions = @form['index']['actions']
61
- return '' if actions.nil? or actions.size == 0
62
- std_actions = {2 => 'new', 3 => 'sort', 4 => 'filter' }
63
- if actions.class == String
64
- actions = define_standard_actions(actions, std_actions)
65
- elsif actions['standard']
66
- actions.merge!(std_actions)
67
- actions['standard'] = nil
68
- end
69
-
70
- # start div with hidden spinner image
71
- html = <<EOT
72
- <div id="dc-action-menu">
73
- <span class="dc-spinner div-hidden">#{fa_icon('spinner lg spin')}</span>
74
- <ul class="dc-action-menu">
75
- EOT
76
- # Remove actions settings and sort
77
- only_actions = []
78
- actions.each { |key, value| only_actions << [key, value] if key.class == Integer }
79
- only_actions.sort_by!(&:first)
80
- only_actions.each do |element|
81
- k,v = element
82
- session[:form_processing] = "index:actions: #{k}=#{v}"
83
- next if v.nil? # must be
84
- url = @parms.clone
85
- yaml = v.class == String ? {'type' => v} : v # if single definition simulate type parameter
86
- action = yaml['type'].to_s.downcase
87
- if action == 'url'
88
- dc_deprecate "action: url will be deprecated. Use action: link in index: actions"
89
- action = 'link'
90
- end
91
- # if return_to is present link directly to URL
92
- if action == 'link' and yaml['url']
93
- url = yaml['url']
94
- else
95
- url['controller'] = yaml['controller'] if yaml['controller']
96
- url['action'] = yaml['action'] || action
97
- url['table'] = yaml['table'] if yaml['table']
98
- url['form_name'] = yaml['form_name'] if yaml['form_name']
99
- end
100
- # html link options
101
- yhtml = yaml['html'] || {}
102
- yhtml['title'] = yaml['title'] if yaml['title']
103
- code = case
104
- # sort
105
- when action == 'sort' then
106
- choices = [['id','id']]
107
- if @form['index']['sort']
108
- @form['index']['sort'].split(',').each do |s|
109
- s.strip!
110
- choices << [ t("helpers.label.#{@form['table']}.#{s}"), s ]
111
- end
112
- end
113
- fa_icon('sort-alpha-asc') + ' ' + t('drgcms.sort') + ' ' +
114
- select('sort', 'sort', choices, { include_blank: true },
115
- { class: 'drgcms_sort', 'data-table' => @form['table']} )
116
- # filter
117
- when action == 'filter' then
118
- caption = t('drgcms.filter')
119
- caption << '&nbsp;' + fa_icon('caret-down lg') + DcFilter.menu_filter(self)
120
- # add filter OFF link
121
- s = session[@form['table']]
122
- if s and s[:filter]
123
- caption << '&nbsp;&nbsp;' + dc_link_to(nil,'remove lg', {controller: 'cmsedit',
124
- filter: 'off', table: @form['table']}, { title: DcFilter.title4_filter_off(s[:filter]) })
125
- end
126
- caption
127
- # new
128
- when action == 'new' then
129
- caption = yaml['caption'] || 'drgcms.new'
130
- dc_link_to(caption,'plus', url, yhtml )
131
- # menu
132
- when action == 'menu' then
133
- caption = t(v['caption'], v['caption']) + '&nbsp;' + fa_icon('caret-down lg')
134
- caption + eval(v['eval'])
135
- =begin
136
- # reorder
137
- when action == 'reorder' then
138
- caption = t('drgcms.reorder')
139
- parms = @parms.clone
140
- parms['operation'] = v
141
- parms['id'] = params[:ids]
142
- parms['table'] = @form['table']
143
- dc_link_to( caption, 'reorder', parms, method: :delete )
144
- =end
145
- when action == 'script'
146
- html << dc_script_action(v)
147
- next
148
- else
149
- caption = yaml['caption'] || yaml['text']
150
- icon = yaml['icon'] ? yaml['icon'] : action
151
- dc_link_to(caption, icon, url, yhtml)
152
- end
153
- html << "<li class=\"dc-animate\">#{code}</li>"
154
- end
155
- html << '</ul>'
156
- html << DcFilter.get_filter_field(self)
157
- html << '</div>'
158
- html.html_safe
159
- end
160
-
161
- ############################################################################
162
- # Creates filter div for cmsedit index/filter action.
163
- ############################################################################
164
- def dc_div_filter()
165
- choices = []
166
- filter = (@form['index'] and @form['index']['filter']) ? @form['index']['filter'] + ',' : ''
167
- filter << 'id as text_field' # filter id is added by default
168
- filter.split(',').each do |f|
169
- f.strip!
170
- name = f.match(' as ') ? f.split(' ').first : f
171
- # like another field on the form
172
- if f.match(' like ')
173
- a = f.split(' ')
174
- name = a.first
175
- f = a.last
176
- end
177
- choices << [ t("helpers.label.#{@form['table']}.#{name}", name), f ]
178
- end
179
- choices4_operators = t('drgcms.choices4_filter_operators').chomp.split(',').inject([]) {|r,v| r << (v.match(':') ? v.split(':') : v )}
180
- # currently selected options
181
- if session[@form['table']] and session[@form['table']][:filter]
182
- field_name, operators_value, dummy = session[@form['table']][:filter].split("\t")
183
- else
184
- field_name, operators_value = nil, nil
185
- end
186
- #{ form_tag :table => @form['table'], filter: :on, filter_input: 1, action: :index, method: :post }
187
- url = url_for(table: @form['table'],form_name: params['form_name'], filter: :on, filter_input: 1, action: :index, controller: :cmsedit)
188
- html =<<EOT
189
- <div id="drgcms_filter" class="div-hidden">
190
- <h1>#{t('drgcms.filter_set')}</h1>
191
-
192
- #{ select(nil, 'filter_field1', options_for_select(choices, field_name), { include_blank: true }) }
193
- #{ select(nil, 'filter_oper', options_for_select(choices4_operators, operators_value)) }
194
- <div class="dc-menu">
195
- <div class="dc-link dc-animate drgcms_popup_submit" data-url="#{url}">#{fa_icon('check-square-o')} #{t('drgcms.filter_on')}</div>
196
- <div class="dc-link dc-animate">#{dc_link_to('drgcms.filter_off','close', {action: :index, filter: 'off', table: @form['table'], form_name: params['form_name']}) }</div>
197
- </div>
198
- </div>
199
- EOT
200
- html.html_safe
201
- end
202
-
203
- ############################################################################
204
- # Creates title div for cmsedit index result set records. Title div also includes paging
205
- # options.
206
- ############################################################################
207
- def dc_table_title_for_result(result=nil)
208
- title = if @form['title'] # form has title section
209
- t(@form['title'], @form['title'])
210
- else # get name from translations
211
- t("helpers.label.#{@form['table']}.tabletitle", @form['table'])
212
- end
213
- dc_table_title(title, result)
214
- end
215
-
216
- ############################################################################
217
- # Creates code for link or ajax action type. Subroutine of dc_actions_for_result.
218
- ############################################################################
219
- def dc_link_or_ajax_action(yaml, parms) #:nodoc:
220
- rest = {}
221
- rest['method'] = yaml['method'] || yaml['request'] || 'get'
222
- rest['caption'] = yaml['caption'] || yaml['text']
223
- rest['class'] = 'dc-animate'
224
- rest['title'] = yaml['title']
225
-
226
- if yaml['type'] == 'link'
227
- dc_link_to(yaml['caption'], yaml['icon'], parms, rest )
228
- else
229
- rest['data-url'] = url_for(parms)
230
- rest['class'] << " fa fa-#{yaml['icon']}"
231
- fa_icon(yaml['icon'], rest )
232
- end
233
- end
234
-
235
33
  ############################################################################
236
34
  # Creates code for script action type.
237
35
  ############################################################################
238
36
  def dc_script_action(yaml)
239
- data = {'request' => 'script', 'script' => yaml['js']}
240
- %Q[<li class="dc-link-ajax dc-animate">#{ dc_link_to(yaml['caption'], yaml['icon'], '#', data: data ) }</li>]
241
- end
242
-
243
- ############################################################################
244
- # Determines actions and width of actions column
245
- ############################################################################
246
- def dc_actions_column()
247
- actions = @form['result_set']['actions']
248
- # standard actions
249
- actions = {'standard' => true} if actions.class == String && actions == 'standard'
250
- std_actions = {' 2' => 'edit', ' 3' => 'delete'}
251
- actions.merge!(std_actions) if actions['standard']
252
- #
253
- width = @form['result_set']['actions_width'] || 20*actions.size
254
- [ actions, "<div class=\"actions\" style=\"width: #{width}px;\">" ]
37
+ # data = {'request' => 'script', 'script' => yaml['js'] || yaml['script'] }
38
+ # %Q[<li class="dc-link-ajax with-link dc-animate">#{ dc_link_to(yaml['caption'], yaml['icon'], '#', data: data ) }</li>]
39
+ icon = dc_icon_for_link yaml['icon']
40
+ data = %Q[data-request="script" data-script="#{yaml['js'] || yaml['script']}"]
41
+ %Q[<li class="dc-link-ajax dc-animate" #{data}>#{icon} #{ t(yaml['caption'],yaml['caption']) }</li>]
255
42
  end
256
43
 
257
44
  ############################################################################
258
- # Creates actions that could be performed on single row of result set.
45
+ # Will return field form definition if field is defined on form.
46
+ # Field definition will be used for input field on the form.
259
47
  ############################################################################
260
- def dc_actions_for_result(document)
261
- actions = @form['result_set']['actions']
262
- return '' if actions.nil? or @form['readonly']
263
- #
264
- actions, html = dc_actions_column()
265
- actions.each do |k,v|
266
- session[:form_processing] = "result_set:actions: #{k}=#{v}"
267
- next if k == 'standard' # ignore standard definition
268
- parms = @parms.clone
269
- yaml = v.class == String ? {'type' => v} : v # if single definition simulate type parameter
270
- html << case
271
- when yaml['type'] == 'edit' then
272
- parms['action'] = 'edit'
273
- parms['id'] = document.id
274
- dc_link_to( nil, 'pencil lg', parms )
275
- when yaml['type'] == 'duplicate' then
276
- parms['id'] = document.id
277
- # duplicate string will be added to these fields.
278
- parms['dup_fields'] = yaml['dup_fields']
279
- parms['action'] = 'create'
280
- dc_link_to( nil, 'copy lg', parms, data: { confirm: t('drgcms.confirm_dup') }, method: :post )
281
- when yaml['type'] == 'delete' then
282
- parms['action'] = 'destroy'
283
- parms['id'] = document.id
284
- parms['return_to'] = request.url
285
- dc_link_to( nil, 'remove lg', parms, data: { confirm: t('drgcms.confirm_delete') }, method: :delete )
286
- # undocumented so far
287
- when yaml['type'] == 'edit_embedded'
288
- parms['controller'] = 'cmsedit'
289
- parms['table'] += ";#{yaml['table']}"
290
- parms['ids'] ||= ''
291
- parms['ids'] += "#{document.id};"
292
- dc_link_to( nil, 'table lg', parms, method: :get )
293
- when yaml['type'] == 'link' || yaml['type'] == 'ajax' then
294
- if yaml['url']
295
- parms['controller'] = yaml['url']
296
- parms['idr'] = document.id
297
- else
298
- parms['id'] = document.id
299
- end
300
- parms['controller'] = yaml['controller'] if yaml['controller']
301
- parms['action'] = yaml['action'] if yaml['action']
302
- parms['table'] = yaml['table'] if yaml['table']
303
- parms['form_name'] = yaml['form_name'] if yaml['form_name']
304
- parms['target'] = yaml['target'] if yaml['target']
305
- dc_link_or_ajax_action(yaml, parms)
306
- else # error.
307
- yaml['type'].to_s
308
- end
309
- end
310
- html << '</div>'
311
- html.html_safe
48
+ def dc_get_field_form_definition(name) #:nodoc:
49
+ return nil if @form['form'].nil?
50
+
51
+ @form['form']['tabs'].each do |tab|
52
+ # Array with 2 elements. First is tabname, second is data
53
+ my_fields = tab.last
54
+ my_fields.each {|k,v| return v if (k.class == Integer and v['name'] == name) }
55
+ end if @form['form']['tabs'] # I know. But nice.
56
+ #
57
+ @form['form']['fields'].each do |field|
58
+ next unless field.first.class == Integer # options
59
+ return field.last if field.last['name'] == name
60
+ end if @form['form']['fields']
61
+ nil
312
62
  end
313
63
 
314
64
  ############################################################################
315
- # Creates header div for result set.
316
- ############################################################################
317
- def dc_header_for_result()
318
- html = '<div class="dc-result-header">'
319
- if @form['result_set']['actions'] and !@form['readonly']
320
- ignore, code = dc_actions_column()
321
- html << code + '</div>'
322
- end
323
- # preparation for sort icon
324
- sort_field, sort_direction = nil, nil
325
- if session[@form['table']]
326
- sort_field, sort_direction = session[@form['table']][:sort].to_s.split(' ')
327
- end
328
- #
329
- if (columns = @form['result_set']['columns'])
330
- columns.each do |k,v|
331
- session[:form_processing] = "result_set:columns: #{k}=#{v}"
332
- #
333
- th = %Q[<div class="th" style="width: #{v['width'] || '15%'};text-align: #{v['align'] || 'left'};"]
334
- v = {'name' => v} if v.class == String
335
- caption = v['caption'] || t("helpers.label.#{@form['table']}.#{v['name']}")
336
- # no sorting when embedded documents or custom filter is active
337
- sort_ok = @form['result_set'].nil? || (@form['result_set'] && @form['result_set']['filter'].nil?)
338
- sort_ok = sort_ok || (@form['index'] && @form['index']['sort'])
339
- if @tables.size == 1 and sort_ok
340
- icon = 'sort lg'
341
- if v['name'] == sort_field
342
- icon = sort_direction == '1' ? 'sort-alpha-asc lg' : 'sort-alpha-desc lg'
343
- end
344
- th << ">#{dc_link_to(caption, icon, sort: v['name'], table: params[:table], form_name: params[:form_name], action: :index, icon_pos: :last )}</div>"
345
- else
346
- th << ">#{caption}</div>"
347
- end
348
- html << "<div class=\"spacer\"></div>" + th
65
+ # Return field code, label and help text for a field defined on a DRG Form.
66
+ #
67
+ # Parameters:
68
+ # options : Hash : Field definition
69
+ #
70
+ # Returns:
71
+ # field_html : String : HTML code for field definition
72
+ # label : String : Label text
73
+ # help : String : Help text
74
+ ############################################################################
75
+ def dc_field_label_help(options)
76
+ # no label or help in comments
77
+ unless %w(comment action).include?(options['type'])
78
+ caption = options['caption'] || options['text']
79
+ label = if caption.blank?
80
+ t_name(options['name'], options['name'].capitalize.gsub('_',' ') )
81
+ elsif options['name']
82
+ t(caption, caption)
349
83
  end
84
+ # help text can be defined in form or in translations starting with helpers. or as helpers.help.collection.field
85
+ help = if options['help']
86
+ options['help'].match('helpers.') ? t(options['help']) : options['help']
87
+ end
88
+ help ||= t('helpers.help.' + @form['table'] + '.' + options['name'],' ') if options['name']
350
89
  end
351
- (html << '</div>').html_safe
352
- end
353
-
354
- ############################################################################
355
- # Creates link for single or double click on result column
356
- ############################################################################
357
- def dc_clicks_for_result(document)
358
- html = ''
359
- if @form['result_set']['dblclick']
360
- yaml = @form['result_set']['dblclick']
361
- opts = {}
362
- opts[:controller] = yaml['controller'] || 'cmsedit'
363
- opts[:action] = yaml['action']
364
- opts[:table] = yaml['table']
365
- opts[:form_name] = yaml['form_name']
366
- opts[:method] = yaml['method'] || 'get'
367
- opts[:id] = document['id']
368
- html << ' data-dblclick=' + url_for(opts)
369
- else
370
- html << (' data-dblclick=' +
371
- url_for(action: 'show', controller: 'cmsedit', id: document.id,
372
- readonly: (params[:readonly] ? 2 : 1), table: params[:table],
373
- form_name: params[:form_name], ids: params[:ids]) ) if @form['form']
90
+ # create field object from class and call its render method
91
+ klass_string = options['type'].camelize
92
+ field_html = if DrgcmsFormFields.const_defined?(klass_string) # when field type defined
93
+ klass = DrgcmsFormFields.const_get(klass_string)
94
+ field = klass.new(self, @record, options).render
95
+ @js << field.js
96
+ @css << field.css
97
+ field.html
98
+ else # litle error string
99
+ "Error: Field type #{options['type']} not defined!"
374
100
  end
375
- html
101
+ [field_html, label, help]
376
102
  end
377
103
 
378
104
  ############################################################################
379
- # Formats value according to format supplied or data type. There is lots of things missing here.
105
+ # Creates code for including data entry field in index actions.
380
106
  ############################################################################
381
- def dc_format_value(value, format=nil)
382
- return '' if value.nil?
383
- klass = value.class.to_s
384
- case when klass.match('Time') then
385
- format ||= t('time.formats.default')
386
- value.strftime(format)
387
- when klass.match('Date') then
388
- format ||= t('date.formats.default')
389
- value.strftime(format)
390
- when format.to_s[0] == 'N' then
391
- dec = format[1].blank? ? nil : format[1].to_i
392
- sep = format[2].blank? ? nil : format[2]
393
- del = format[3].blank? ? nil : format[3]
394
- cur = format[4].blank? ? nil : format[4]
395
- dc_format_number(value, dec, sep, del, cur)
396
- else
397
- value.to_s
107
+ def dc_field_action(yaml)
108
+ # assign value if value found in parameters
109
+ if params['record']
110
+ value = params['record'][yaml['name']]
111
+ params["p_#{yaml['name']}"] = value
398
112
  end
399
- end
400
-
401
- ############################################################################
402
- # Defines style or class for row (tr) or column (td)
403
- ############################################################################
404
- def dc_style_or_class(selector, yaml, value, record)
405
- return '' if yaml.nil?
406
- # alias record and value so both names can be used in eval
407
- field = value
408
- document = record
409
- html = selector ? "#{selector}=\"" : ''
410
- html << if yaml.class == String
411
- yaml
113
+ #
114
+ if ( field_definition = dc_get_field_form_definition(yaml['name']) )
115
+ field, label, help = dc_field_label_help(field_definition)
412
116
  else
413
- (yaml['eval'] ? eval(yaml['eval']) : '') rescue 'background-color:red;'
117
+ yaml['type'] = yaml['field_type']
118
+ field, label, help = dc_field_label_help(yaml)
414
119
  end
415
- html << '"' if selector
416
- html
417
- end
418
-
419
- ############################################################################
420
- # Creates tr code for each row of result set.
421
- ############################################################################
422
- def dc_row_for_result(document)
423
- clas = "dc-#{cycle('odd','even')} " + dc_style_or_class(nil, @form['result_set']['tr_class'], nil, document)
424
- style = dc_style_or_class('style', @form['result_set']['tr_style'], nil, document)
425
- "<div class=\"dc-result-data #{clas}\" #{dc_clicks_for_result(document)} #{style}>".html_safe
120
+ # input field will have label as placeholder
121
+ field = field.sub('input',"input placeholder=\"#{label}\"")
122
+ %Q[<li class="no-background">#{field}</li>]
123
+
426
124
  end
427
125
 
428
126
  ############################################################################
429
- # Creates column for each field of result set document.
430
- ############################################################################
431
- def dc_columns_for_result(document)
432
- html = ''
433
- return html unless @form['result_set']['columns']
434
- #
435
- @form['result_set']['columns'].each do |k,v|
436
- session[:form_processing] = "result_set:columns: #{k}=#{v}"
437
- # convert shortcut to hash
438
- v = {'name' => v} if v.class == String
439
- # eval
440
- value = if v['eval']
441
- if v['eval'].match('dc_name4_id')
442
- a = v['eval'].split(',')
443
- if a.size == 3
444
- dc_name4_id(a[1], a[2], nil, document[ v['name'] ])
445
- else
446
- dc_name4_id(a[1], a[2], a[3], document[ v['name'] ])
447
- end
448
- elsif v['eval'].match('dc_name4_value')
449
- dc_name4_value( @form['table'], v['name'], document[ v['name'] ] )
450
- elsif v['eval'].match('eval ')
451
- # evaluate with specified parameters
452
- else
453
- if v['params']
454
- if v['params'] == 'document' # pass document as parameter when all
455
- eval( "#{v['eval']} document")
456
- else # list of fields delimeted by ,
457
- params = v['params'].chomp.split(',').inject('') do |result,e|
458
- result << (e.match(/\.|\:|\(/) ? e : "document['#{e.strip}']") + ','
459
- end
460
- params.chomp!(',')
461
- eval( "#{v['eval']} #{params}")
462
- end
463
- else
464
- eval( "#{v['eval']} '#{document[ v['name'] ]}'")
465
- end
466
- end
467
- # as field
468
- elsif document.respond_to?(v['name'])
469
- dc_format_value(document.send( v['name'] ), v['format'])
470
- # as hash (dc_memory)
471
- elsif document.class == Hash
472
- dc_format_value(document[ v['name'] ], v['format'])
473
- # error
474
- else
475
- "!!! #{v['name']}"
476
- end
477
127
  #
478
- td = '<div class="spacer"></div><div class="td" '
479
- td << dc_style_or_class('class', v['td_class'], value, document)
480
-
481
- width_align = %Q[width: #{v['width'] || '15%'};text-align: #{v['align'] || 'left'};]
482
- style = dc_style_or_class('style', v['td_style'] || v['style'], value, document)
483
- style = if style.size > 1
484
- # remove trailing " add width and add trailing " back
485
- style.delete_suffix('"') + width_align + '"'
486
- else
487
- # create style string
488
- "style=\"#{width_align}\""
489
- end
490
- html << "#{td} #{style}>#{value}</div>"
491
- end
492
- html.html_safe
493
- end
494
-
495
- ############################################################################
496
- # Will return value for parameter required on form
497
128
  ############################################################################
498
- def dc_value_for_parameter(param)
499
- if param.class == Hash
500
- dc_internal_var(param['object'] || 'record', param['method'])
501
- else
502
- param
503
- end
129
+ def dc_html_data(yaml)
130
+ return '' if yaml.blank?
131
+ yaml.inject(' ') {|result, e| result << "#{e.first}=\"#{e.last}\" "}
504
132
  end
505
133
 
506
134
  ############################################################################
507
- # Creates actions div for edit form.
135
+ # Creates code for link, ajax or windows action for index or form actions.
508
136
  #
509
- # Displaying readonly form turned out to be challenge. For now when readonly parameter
510
- # has value 2, back link will force readonly form. Value 1 or not set will result in
511
- # normal link.
512
- ############################################################################
513
- def dc_actions_for_form()
514
- # create standard actions
515
- std_actions = {' 1' => 'back', ' 2' => {'type' => 'submit', 'caption' => 'drgcms.save'},
516
- ' 3' => {'type' => 'submit', 'caption' => 'drgcms.save&back'} }
517
- # when edit only
518
- unless @record.id.nil?
519
- std_actions.merge!({' 6' => 'new'} )
520
- std_actions.merge!(@record.active ? {' 5' => 'disable'} : {' 5' => 'enable'} ) if @record.respond_to?('active')
521
- std_actions.merge!({' 7' => 'refresh'} )
522
- end
523
- actions = @form['form']['actions']
524
- # shortcut for actions: standard
525
- actions = nil if actions.class == String && actions == 'standard'
526
- # standard actions
527
- actions = std_actions if actions.nil?
528
- # readonly
529
- actions = {' 1' => 'back'} if @form['readonly']
530
- # Actions are strictly forbidden
531
- if @form['form']['actions'] and dc_dont?(@form['form']['actions'])
532
- actions = []
533
- elsif actions['standard']
534
- actions.merge!(std_actions)
535
- actions['standard'] = nil
536
- end
537
- # Update save and save&back
538
- actions.each do |k,v|
539
- if v.class == String
540
- if v.match(/save\&back/i)
541
- actions[k] = {'type' => 'submit', 'caption' => 'drgcms.save&back'}
542
- elsif v == 'save'
543
- actions[k] = {'type' => 'submit', 'caption' => 'drgcms.save'}
544
- end
545
- end
546
- end
547
- # Sort so that standard actions come first
548
- actions = actions.to_a.sort {|x,y| x[0].to_s <=> y[0].to_s}
549
- # Add spinner to the beginning
550
- c = %Q[<span class="dc-spinner div-hidden">#{fa_icon('spinner lg spin')}</span><ul class="dc-menu">]
551
-
552
- actions.each do |element|
553
- session[:form_processing] = "form:actions: #{element}"
554
- v = element[1]
555
- next if v.nil? # yes it happends
556
- # on_save_ok should't go inside td tags
557
- if (element[0] == 'on_save_ok') then
558
- c << hidden_field_tag(:on_save_ok, v)
559
- next
560
- end
561
- #
562
- action_active = !(dc_dont?(v['when_new']) and @record.new_record?)
563
- # p [v['caption'], action_active]
564
- parms = @parms.clone
565
- if v.class == String
566
- next if params[:readonly] and !(v == 'back')
567
-
568
- c << '<li class="dc-link dc-animate">'
569
- c << case
570
- when (v == 'back' or v == 'cancle') then
571
- # If return_to is present link directly to URL
572
- if parms['xreturn_to'] # disabled for now
573
- dc_link_to( 'drgcms.back','arrow-left', parms['return_to'] )
574
- else
575
- parms['action'] = 'index'
576
- parms['readonly'] = parms['readonly'].to_s.to_i < 2 ? nil : 1
577
- dc_link_to( 'drgcms.back','arrow-left', parms )
578
- end
579
- when v == 'delete' then
580
- parms['operation'] = v
581
- parms['id'] = @record.id
582
- dc_link_to( 'drgcms.delete','remove', parms, data: { confirm: t('drgcms.confirm_delete') }, method: :delete )
583
- when v == 'new' then
584
- parms['action'] = v
585
- dc_link_to( 'drgcms.new', 'plus', parms)
586
- when (v == 'enable' or v == 'disable') then
587
- parms['operation'] = v
588
- parms['id'] = @record.id
589
- icon = (v == 'enable' ? 'thumbs-o-up' : 'thumbs-o-down')
590
- dc_link_to( "drgcms.#{v}",icon, parms, method: :delete )
591
- when v == 'edit' then
592
- parms['operation'] = v
593
- parms['id'] = @record.id
594
- dc_link_to( "drgcms.#{v}",v, parms )
595
- when v == 'refresh' then
596
- "<span onclick='window.location.href=window.location.href;'>#{fa_icon('refresh')} #{t('drgcms.refresh')}</span></li>"
597
- else
598
- "err1 #{element[0]}=>#{v}"
599
- end
600
- c << '</td>'
601
- # non standard actions
602
- else
603
- c << case
604
- # submit button
605
- when v['type'] == 'submit'
606
- caption = v['caption'] || 'drgcms.save'
607
- icon = v['icon'] || 'save'
608
- if action_active
609
- '<li class="dc-link-submit dc-animate">' +
610
- dc_submit_tag(caption, icon, {:data => v['params'], :title => v['title'] }) +
611
- '</li>'
612
- else
613
- "<li class=\"dc-link-no\">#{fa_icon(icon)} #{caption}</li>"
614
- end
615
-
616
- # delete with some sugar added
617
- when v['type'] == 'delete'
618
- parms['id'] = @record.id
619
- parms.merge!(v['params'])
620
- caption = v['caption'] || 'drgcms.delete'
621
- icon = v['icon'] || 'remove'
622
- '<li class="dc-link dc-animate">' +
623
- dc_link_to( caption, icon, parms, data: t('drgcms.confirm_delete'), method: :delete ) +
624
- '</li>'
625
-
626
- # ajax or link button
627
- when v['type'] == 'ajax' || v['type'] == 'link' || v['type'] == 'window'
628
- parms = {}
629
- # direct url
630
- if v['url']
631
- parms['controller'] = v['url']
632
- parms['idr'] = dc_document_path(@record)
633
- # make url from action controller
634
- else
635
- parms['controller'] = v['controller']
636
- parms['action'] = v['action']
637
- parms['table'] = v['table']
638
- parms['form_name'] = v['form_name']
639
- end
640
- # add current id to parameters
641
- parms['id'] = dc_document_path(@record)
642
- # overwrite with or add additional parameters when params defined
643
- v['params'].each { |k,v| parms[k] = dc_value_for_parameter(v) } if v['params']
644
- parms['table'] = parms['table'].underscore if parms['table'] # might be CamelCase
645
- # error if controller parameter is missing
646
- if parms['controller'].nil?
647
- "<li>#{t('drgcms.error')}</li>"
648
- else
649
- v['caption'] ||= v['text']
650
- caption = t("#{v['caption'].downcase}", v['caption'])
651
- #
652
- url = url_for(parms) rescue ''
653
- request = v['request'] || v['method'] || 'get'
654
- icon = v['icon'] ? "#{fa_icon(v['icon'])} " : ''
655
- if v['type'] == 'ajax' # ajax button
656
- clas = action_active ? "dc-link-ajax dc-animate" : "dc-link-no"
657
- %Q[<li class="#{clas}" data-url="#{action_active ? url : ''}"
658
- data-request="#{request}" title="#{v['title']}">#{icon}#{caption}</li>]
659
- elsif v['type'] == 'link' # link button
660
- clas = action_active ? "dc-link dc-animate" : "dc-link-no"
661
- %Q[<li class="#{clas}">#{action_active ? dc_link_to(v['caption'],v['icon'], parms, {target: v['target']} ) : caption}</li>]
662
- elsif v['type'] == 'window'
663
- clas = action_active ? "dc-link dc-animate dc-window-open" : "dc-link-no"
664
- %Q[<li class="#{clas}" data-url="#{action_active ? url : ''}">#{icon}#{caption}</li>]
665
- else
666
- 'Action Type error'
667
- end
668
- end
669
-
670
- # Javascript action
671
- when v['type'] == 'script'
672
- dc_script_action(v)
673
- else
674
- '<li>err2</li>'
675
- end
676
- end
677
- end
678
- (c << '</ul>').html_safe
679
- end
680
-
681
- ############################################################################
682
- # Create background div and table definitions for result set.
683
- ############################################################################
684
- def dc_background_for_result(start)
685
- if start == :start
686
- html = '<div class="dc-result-div" '
687
- html << (@form['result_set']['table_style'] ? 'style="overflow-x: scroll;" >' : '>')
688
- #
689
- html << "\n<div class=\"dc-result #{@form['result_set']['table_class']}\" "
690
- html << (@form['result_set']['table_style'] ? "style=\"#{@form['result_set']['table_style']}\" >" : '>')
137
+ # Parameters:
138
+ # yaml: Hash : Action definition
139
+ # record : Object : Currently selected record if available
140
+ # action_active : Boolean : Is action active or disabled
141
+ #
142
+ # Returns:
143
+ # String : HTML code for action
144
+ ############################################################################
145
+ def dc_link_ajax_window_submit_action(yaml, record=nil, action_active=true)
146
+ parms = {}
147
+ caption = yaml['caption'] ? t("#{yaml['caption'].downcase}", yaml['caption']) : nil
148
+ icon = yaml['icon'] ? "#{fa_icon(yaml['icon'])}" : ''
149
+ # action is not active
150
+ unless dc_is_action_active?(yaml)
151
+ return "<li class=\"dc-link-no\">#{icon} #{caption}</li>"
152
+ end
153
+ # set data-confirm when confirm
154
+ yaml['html'] ||= {}
155
+ confirm = yaml['html']['data-confirm'] || yaml['confirm']
156
+ yaml['html']['data-confirm'] = t(confirm) unless confirm.blank?
157
+ # direct url
158
+ if yaml['url']
159
+ parms['controller'] = yaml['url']
160
+ parms['idr'] = dc_document_path(record) if record
161
+ # make url from action controller
691
162
  else
692
- html = '</div></div>'
693
- end
694
- html.html_safe
695
- end
696
-
697
- ############################################################################
698
- # Checks if value is defined and sets default. If values are sent it also checks
699
- # if value is found in values. If not it will report error and set value to default.
700
- # Subroutine of dc_fields_for_tab.
701
- ############################################################################
702
- def dc_check_and_default(value, default, values=nil) #:nodoc:
703
- return default if value.nil?
704
- # check if value is within allowed values
705
- if values
706
- if !values.index(value)
707
- # parameters should be in downcase. Check downcase version.
708
- if n = values.index(value.downcase)
709
- return values[n]
710
- else
711
- logger.error("DRG Forms: Value #{value} not within values [#{values.join(',')}]. Default #{default} used!")
712
- return default
713
- end
714
- end
715
- end
716
- value
717
- end
718
-
719
- ############################################################################
720
- # Creates top or bottom horizontal line on form.
721
- ############################################################################
722
- def top_bottom_line(options)
723
- '<div class="dc-separator"></div>'
724
- end
163
+ parms['controller'] = yaml['controller'] || 'cmsedit'
164
+ parms['action'] = yaml['action']
165
+ parms['table'] = yaml['table']
166
+ parms['form_name'] = yaml['form_name']
167
+ parms['control'] = yaml['control'] if yaml['control']
168
+ parms['id'] = record.id if record
169
+ end
170
+ # add current id to parameters
171
+ parms['id'] = dc_document_path(record) if record
172
+ # overwrite with or add additional parameters from environment or record
173
+ yaml['params'].each { |k,v| parms[k] = dc_value_for_parameter(v) } if yaml['params']
174
+ parms['table'] = parms['table'].underscore if parms['table'] # might be CamelCase
175
+ # error if controller parameter is missing
176
+ if parms['controller'].nil? && parms['url'].nil?
177
+ "<li>#{'Controller not defined'}</li>"
178
+ else
179
+ yaml['caption'] ||= yaml['text']
180
+
181
+ html_data = dc_html_data(yaml['html'])
182
+ #
183
+ url = url_for(parms) rescue 'URL error'
184
+ request = yaml['request'] || yaml['method'] || 'get'
185
+ if yaml['type'] == 'ajax' # ajax button
186
+ clas = "dc-link-ajax dc-animate"
187
+ %Q[<li class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}
188
+ data-request="#{request}" title="#{yaml['title']}">#{icon}#{caption}</li>]
189
+
190
+ elsif yaml['type'] == 'submit' # submit button
191
+ # It's dirty hack, but will prevent not authorized message and render index action correctly
192
+ parms[:filter] = 'on'
193
+ url = url_for(parms) rescue 'URL error'
194
+ clas = "dc-action-submit"
195
+ %Q[<li class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}
196
+ data-request="#{request}" title="#{yaml['title']}">#{icon}#{caption}</li>]
197
+
198
+ elsif yaml['type'] == 'link' # link button
199
+ clas = "dc-link dc-animate"
200
+ link = dc_link_to(yaml['caption'],yaml['icon'], parms, {target: yaml['target'], html: yaml['html']} )
201
+ %Q[<li class="#{clas}">#{action_active ? link : caption}</li>]
202
+
203
+ elsif yaml['type'] == 'window'
204
+ clas = "dc-link dc-animate dc-window-open"
205
+ %Q[<li class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}>#{icon}#{caption}</li>]
725
206
 
726
- ############################################################################
727
- # Creates input fields for one tab. Subroutine of dc_fields_for_form.
728
- ############################################################################
729
- def dc_fields_for_tab(fields_on_tab) #:nodoc:
730
- @js ||= ''
731
- html = '<div class="dc-form">'
732
- labels_pos = dc_check_and_default(@form['form']['labels_pos'], 'right', ['top','left','right'])
733
- hidden_fields = ''
734
- odd_even = nil
735
- group_option, group_count = 0, 0
736
- reset_cycle()
737
- # options and fields must be separated before sorting
738
- # form_options = fields.select {|field| field.class != Integer }
739
- # columns = form_options.try(:[],'columns') || 1
740
- # Select form fields and sort them by key
741
- form_fields = fields_on_tab.select {|field| field.class == Integer }
742
- form_fields.to_a.sort.each do |element|
743
- options = element.last
744
- session[:form_processing] = "form:fields: #{element.first}=#{options}"
745
- # ignore if edit_only singe field is required
746
- next if params[:edit_only] and params[:edit_only] != options['name']
747
- # hidden_fields. Add them at the end
748
- if options['type'] == 'hidden_field'
749
- hidden_fields << DrgcmsFormFields::HiddenField.new(self, @record, options).render
750
- next
751
- end
752
- # label
753
- caption = options['caption'] || options['text']
754
- label = if !caption.blank?
755
- t(caption, caption)
756
- elsif options['name']
757
- t_name(options['name'], options['name'].capitalize.gsub('_',' ') )
758
- end
759
- # help text can be defined in form or in translations starting with helpers. or as helpers.help.collection.field
760
- help = if options['help']
761
- options['help'].match('helpers.') ? t(options['help']) : options['help']
762
- end
763
- help ||= t('helpers.help.' + @form['table'] + '.' + options['name'],' ') if options['name']
764
- # create field object from class and call its render method
765
- klas_string = options['type'].camelize
766
- field_html = if DrgcmsFormFields.const_defined?(klas_string) # check if field type is defined
767
- klas = DrgcmsFormFields.const_get(klas_string)
768
- field = klas.new(self, @record, options).render
769
- @js << field.js
770
- field.html
771
- else # litle error string
772
- "Error: Code for field type #{options['type']} not defined!"
773
- end
774
- # Line separator
775
- html << top_bottom_line(options['top-line']) if options['top-line']
776
- # Begining of new row
777
- if group_count == 0
778
- html << '<div class="row-div">'
779
- odd_even = cycle('odd','even')
780
- group_count = options['group'] || 1
781
- group_option = options['group'] || 1
782
- end
783
- #
784
- html << if labels_pos == 'top'
785
- %Q[
786
- <div class="dc-form-label-top dc-color-#{odd_even} dc-align-left" title="#{help}">
787
- <label for="record_#{options['name']}">#{label} </label>
788
- <div id="td_record_#{options['name']}">#{field_html}</div>
789
- </div> ]
790
207
  else
791
- label_width = 14
792
- # less place for label when more then 1 field per row
793
- label_width = 10 if group_option > 1 and group_option != group_count
794
- data_width = (94 - 10*group_option)/group_option
795
- %Q[
796
- <div class="dc-form-label dc-color-#{odd_even} dc-align-#{labels_pos}" style="width:#{label_width}%;" title="#{help}">
797
- <label for="record_#{options['name']}">#{label} </label>
798
- </div>
799
- <div id="td_record_#{options['name']}" class="dc-form-field dc-color-#{odd_even}" style="width:#{data_width}%;">#{field_html}</div>
800
- ]
208
+ '<li>Action Type error</li>'
801
209
  end
802
- # check if must go to next row
803
- group_count -= 1
804
- html << '</div>' if group_count == 0
805
- html << top_bottom_line(options['bottom-line']) if options['bottom-line']
806
210
  end
807
- html << '</div>' << hidden_fields
808
211
  end
809
212
 
810
213
  ############################################################################
811
- # Creates edit form div.
812
- ############################################################################
813
- def dc_fields_for_form()
814
- html, tabs, tab_data = '',[], ''
815
- # Only fields defined
816
- if (form_fields = @form['form']['fields'])
817
- html << "<div id='data_fields' " + (@form['form']['height'] ? "style=\"height: #{@form['form']['height']}px;\">" : '>')
818
- html << dc_fields_for_tab(form_fields) + '</div>'
819
- else
820
- # there are multiple tabs on form
821
- first = true # first tab
822
- @form['form']['tabs'].keys.sort.each do |tab_name|
823
- next if tab_name.match('actions')
824
- # Tricky. If field name is not on the tab skip to next tab
825
- if params[:edit_only]
826
- is_on_tab = false
827
- @form['form']['tabs'][tab_name].each {|k,v| is_on_tab = true if params[:edit_only] == v['name'] }
828
- next unless is_on_tab
829
- end
830
- # first div is displayed, all others are hidden
831
- tab_data << "<div id=\"data_#{tab_name.delete("\s\n")}\""
832
- tab_data << ' class="div-hidden"' unless first
833
- tab_data << " style=\"height: #{@form['form']['height']}px;\"" if @form['form']['height']
834
- tab_data << ">#{dc_fields_for_tab(@form['form']['tabs'][tab_name])}</div>"
835
- tab_label = @form['form']['tabs'][tab_name]['caption'] || tab_name
836
- tabs << [tab_name, tab_label]
837
- first = false
838
- end
839
- # make it all work together
840
- html << '<ul class="dc-form-ul" >'
841
- first = true # first tab must be selected
842
- tabs.each do |tab_name, tab_label|
843
- html << "<li id=\"li_#{tab_name}\" data-div=\"#{tab_name.delete("\s\n")}\" class=\"dc-form-li"
844
- html << ' dc-form-li-selected' if first
845
- html << "\">#{t(tab_label, t_name(tab_label))}</li>"
846
- first = false
847
- end
848
- html << '</ul>'
849
- html << tab_data
850
- end
851
- # add last_updated_at hidden field so controller can check if record was updated in db during editing
852
- html << hidden_field(nil, :last_updated_at, value: @record.updated_at.to_i) if @record.respond_to?(:updated_at)
853
- # add form time stamp to prevent double form submit
854
- html << hidden_field(nil, :form_time_stamp, value: Time.now.to_i)
855
- html.html_safe
856
- end
857
-
858
- ############################################################################
859
- # Returns username for id. Subroutine of dc_document_statistics
860
- ############################################################################
861
- def _get_user_for(field_name) #:nodoc:
862
- if @record[field_name]
863
- u = DcUser.find(@record[field_name])
864
- return u ? u.name : @record[field_name]
865
- end
866
- # nil
867
- end
868
-
869
- ############################################################################
870
- # Creates current document statistics div (created_by, created_at, ....) at the bottom of edit form.
871
- # + lots of more. At the moment also adds icon for dumping current document as json text.
872
- ############################################################################
873
- def dc_document_statistics
874
- return '' if @record.new_record? or dc_dont?(@form['form']['info'])
875
- html = %Q[<div id="dc-document-info">#{fa_icon('info-circle lg')}</div> <div id="dc-document-info-popup" class="div-hidden"> ]
876
214
  #
877
- u = _get_user_for('created_by')
878
- html << %Q[<div><span>#{t('drgcms.created_by', 'Created by')}: </span><span>#{u}</span></div>] if u
879
- u = _get_user_for('updated_by')
880
- html << %Q[<div><span>#{t('drgcms.updated_by', 'Updated by')}: </span><span>#{u}</span></div>] if u
881
- html << %Q[<div><span>#{t('drgcms.created_at', 'Created at')}: </span><span>#{dc_format_value(@record.created_at)}</span></div>] if @record['created_at']
882
- html << %Q[<div><span>#{t('drgcms.updated_at', 'Updated at')}: </span><span>#{dc_format_value(@record.updated_at)}</span></div>] if @record['updated_at']
883
- # copy to clipboard icon
884
- parms = params.clone
885
- parms[:controller] = 'dc_common'
886
- parms[:action] = 'copy_clipboard'
887
- url = url_for(parms.permit!)
888
- html << fa_icon('copy 2x', class: 'dc-link-img dc-link-ajax dc-animate',
889
- 'data-url' => url, 'data-request' => 'get', title: t('drgcms.doc_copy_clipboard') )
890
- (html << '</div></div>').html_safe
215
+ ############################################################################
216
+ def dc_log_exception(exception)
217
+ log = exception ? "\n!!!Error: #{exception.message}\n#{exception.backtrace.first.inspect}\n" : ''
218
+ log << "DRG Form processing line: #{session[:form_processing]}\n"
219
+
220
+ logger.error log
891
221
  end
892
-
222
+
893
223
  end