drg_cms 0.6.0.1 → 0.6.1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/drg_cms/drg_cms.js +454 -145
  3. data/app/assets/javascripts/drg_cms_application.js +1 -1
  4. data/app/assets/stylesheets/drg_cms/drg_cms.css +635 -244
  5. data/app/assets/stylesheets/drg_cms/select-multiple.css +18 -12
  6. data/app/assets/stylesheets/drg_cms_cms.css +1 -1
  7. data/app/controllers/cmsedit_controller.rb +515 -335
  8. data/app/controllers/dc_application_controller.rb +378 -111
  9. data/app/controllers/dc_common_controller.rb +105 -14
  10. data/app/{controllers → controls}/browse_models_control.rb +0 -0
  11. data/app/controls/dc_help_control.rb +126 -0
  12. data/app/{controllers → controls}/dc_page_control.rb +24 -8
  13. data/app/controls/dc_poll_result_control.rb +88 -0
  14. data/app/controls/dc_report.rb +223 -0
  15. data/app/{controllers → controls}/design_element_settings_control.rb +0 -0
  16. data/app/forms/all_options.yml +44 -9
  17. data/app/forms/cms_menu.yml +28 -18
  18. data/app/forms/dc_ad.yml +11 -22
  19. data/app/forms/dc_big_table.yml +1 -0
  20. data/app/forms/dc_big_table_value.yml +1 -0
  21. data/app/forms/dc_category.yml +2 -1
  22. data/app/forms/dc_design.yml +20 -16
  23. data/app/forms/dc_filter.yml +3 -6
  24. data/app/forms/dc_help_1.yml +109 -0
  25. data/app/forms/dc_journal.yml +3 -1
  26. data/app/forms/dc_json_ld.yml +59 -0
  27. data/app/forms/dc_key_value.yml +32 -0
  28. data/app/forms/dc_link.yml +1 -1
  29. data/app/forms/dc_menu.yml +2 -0
  30. data/app/forms/dc_menu_item.yml +2 -0
  31. data/app/forms/dc_page.yml +3 -5
  32. data/app/forms/dc_part.yml +1 -0
  33. data/app/forms/dc_piece.yml +1 -0
  34. data/app/forms/dc_poll.yml +15 -5
  35. data/app/forms/dc_poll_item.yml +2 -1
  36. data/app/forms/dc_poll_result.yml +83 -0
  37. data/app/forms/dc_poll_result_export.yml +35 -0
  38. data/app/forms/dc_seo.yml +33 -0
  39. data/app/forms/dc_simple_menu.yml +2 -0
  40. data/app/forms/dc_site.yml +4 -12
  41. data/app/forms/dc_user.yml +27 -11
  42. data/app/forms/dc_user_role.yml +3 -0
  43. data/app/forms/json_ld_schema.yml +168 -0
  44. data/app/helpers/cms_common_helper.rb +375 -0
  45. data/app/helpers/cms_edit_helper.rb +506 -0
  46. data/app/helpers/cms_helper.rb +268 -0
  47. data/app/helpers/cms_index_helper.rb +580 -0
  48. data/app/helpers/dc_application_helper.rb +218 -306
  49. data/app/models/concerns/dc_page_concern.rb +40 -6
  50. data/app/models/concerns/dc_policy_rule_concern.rb +20 -8
  51. data/app/models/concerns/dc_seo_concern.rb +66 -0
  52. data/app/models/concerns/dc_site_concern.rb +67 -44
  53. data/app/models/concerns/dc_user_concern.rb +57 -18
  54. data/app/models/dc_design.rb +30 -18
  55. data/app/models/dc_filter.rb +22 -13
  56. data/app/models/dc_json_ld.rb +152 -0
  57. data/app/models/dc_key_value.rb +48 -0
  58. data/app/models/dc_key_value_store.rb +1 -0
  59. data/app/models/dc_memory.rb +8 -1
  60. data/app/models/dc_page.rb +0 -1
  61. data/app/models/dc_permission.rb +49 -9
  62. data/app/models/dc_policy.rb +25 -14
  63. data/app/models/dc_policy_role.rb +22 -11
  64. data/app/models/dc_poll.rb +39 -19
  65. data/app/models/dc_poll_result.rb +46 -0
  66. data/app/models/dc_temp.rb +140 -0
  67. data/app/models/dc_user_role.rb +2 -2
  68. data/app/models/drgcms_form_fields.rb +12 -1
  69. data/app/models/drgcms_form_fields/action.rb +61 -0
  70. data/app/models/drgcms_form_fields/comment.rb +8 -4
  71. data/app/models/drgcms_form_fields/date_picker.rb +11 -9
  72. data/app/models/drgcms_form_fields/date_select.rb +1 -1
  73. data/app/models/drgcms_form_fields/datetime_picker.rb +12 -10
  74. data/app/models/drgcms_form_fields/datetime_select.rb +1 -1
  75. data/app/models/drgcms_form_fields/drgcms_field.rb +55 -9
  76. data/app/models/drgcms_form_fields/embedded.rb +26 -16
  77. data/app/models/drgcms_form_fields/file_field.rb +52 -0
  78. data/app/models/drgcms_form_fields/file_select.rb +2 -2
  79. data/app/models/drgcms_form_fields/hash_field.rb +90 -0
  80. data/app/models/drgcms_form_fields/hidden_field.rb +1 -1
  81. data/app/models/drgcms_form_fields/html_field.rb +1 -1
  82. data/app/models/drgcms_form_fields/link_to.rb +2 -2
  83. data/app/models/drgcms_form_fields/method.rb +66 -0
  84. data/app/models/drgcms_form_fields/multitext_autocomplete.rb +23 -14
  85. data/app/models/drgcms_form_fields/number_field.rb +15 -6
  86. data/app/models/drgcms_form_fields/radio.rb +96 -0
  87. data/app/models/drgcms_form_fields/readonly.rb +2 -2
  88. data/app/models/drgcms_form_fields/select.rb +92 -29
  89. data/app/models/drgcms_form_fields/text_area.rb +1 -1
  90. data/app/models/drgcms_form_fields/text_autocomplete.rb +31 -17
  91. data/app/models/drgcms_form_fields/text_field.rb +1 -1
  92. data/app/models/drgcms_form_fields/text_with_select.rb +6 -3
  93. data/app/models/drgcms_form_fields/tree_select.rb +15 -4
  94. data/app/{helpers → renderers}/dc_ad_renderer.rb +0 -0
  95. data/app/{helpers → renderers}/dc_big_menu_renderer.rb +1 -0
  96. data/app/{helpers → renderers}/dc_captcha_renderer.rb +0 -0
  97. data/app/{helpers → renderers}/dc_common_renderer.rb +0 -0
  98. data/app/{helpers → renderers}/dc_gallery_renderer.rb +1 -0
  99. data/app/{helpers → renderers}/dc_menu_renderer.rb +11 -4
  100. data/app/{helpers → renderers}/dc_page_renderer.rb +1 -0
  101. data/app/{helpers → renderers}/dc_part_renderer.rb +5 -4
  102. data/app/{helpers → renderers}/dc_piece_renderer.rb +1 -1
  103. data/app/{helpers → renderers}/dc_poll_renderer.rb +91 -64
  104. data/app/{helpers → renderers}/dc_renderer.rb +1 -0
  105. data/app/{helpers → renderers}/dc_simple_menu_renderer.rb +1 -0
  106. data/app/views/cmsedit/{remove_edit_stuff.js.erb → __remove_edit_stuff.js.erb} +0 -0
  107. data/app/views/cmsedit/{show.html.erb → __show.html.erb} +0 -0
  108. data/app/views/cmsedit/_edit_stuff.html.erb +4 -25
  109. data/app/views/cmsedit/_form.html.erb +4 -3
  110. data/app/views/cmsedit/_result.html.erb +2 -3
  111. data/app/views/cmsedit/edit.html.erb +4 -1
  112. data/app/views/cmsedit/index.html.erb +7 -1
  113. data/app/views/cmsedit/new.html.erb +3 -1
  114. data/app/views/dc_common/_help.html.erb +17 -0
  115. data/app/views/layouts/models.html.erb +2 -1
  116. data/config/locales/drgcms_en.yml +27 -3
  117. data/config/locales/drgcms_sl.yml +32 -5
  118. data/config/locales/models_en.yml +65 -17
  119. data/config/locales/models_sl.yml +69 -18
  120. data/drg_cms.gemspec +1 -1
  121. data/lib/drg_cms.rb +61 -1
  122. data/lib/drg_cms/version.rb +1 -1
  123. data/lib/generators/new_drg_form/new_drg_form_generator.rb +9 -2
  124. data/lib/tasks/database.rake +6 -56
  125. metadata +73 -54
  126. data/app/assets/stylesheets/drg_cms/__jquery-ui.css +0 -339
  127. data/app/helpers/application_helper.rb +0 -2
  128. data/app/helpers/cmsedit_helper.rb +0 -888
  129. data/app/models/dc_dummy.rb +0 -102
  130. data/test/fixtures/drg_cms_test_data.rb +0 -87
@@ -0,0 +1,506 @@
1
+ #--
2
+ # Copyright (c) 2012+ Damjan Rems
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ ###########################################################################
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.
28
+ #
29
+ ###########################################################################
30
+ module CmsEditHelper
31
+
32
+ ############################################################################
33
+ # Will return value when internal or additional parameters are defined in action
34
+ # Subroutine of dc_actions_for_form.
35
+ ############################################################################
36
+ def dc_value_for_parameter(param, current_document = nil)#:nodoc:
37
+ if param.class == Hash
38
+ dc_internal_var(param['object'] ||= 'record', param['method'], current_document)
39
+ elsif param.to_s.match(/record|document/)
40
+ current_document ? current_document : @record
41
+ else
42
+ param
43
+ end
44
+ end
45
+
46
+ ############################################################################
47
+ # Creates actions div for edit form.
48
+ #
49
+ # Displaying readonly form turned out to be challenge. For now when readonly parameter
50
+ # has value 2, back link will force readonly form. Value 1 or not set will result in
51
+ # normal link.
52
+ ############################################################################
53
+ def dc_is_action_active?(options)
54
+ if options['when_new']
55
+ dc_deprecate("when_option will be deprecated and replaced by active: not_new_record! Form #{params[:form_name]}")
56
+ return !(dc_dont?(options['when_new']) && @record.new_record?)
57
+ end
58
+ return true unless options['active']
59
+
60
+ # alias record and document so both can be used in eval
61
+ record = document = @record
62
+ option = options['active']
63
+ case
64
+ # usually only for test
65
+ when option.class == TrueClass || option['eval'].class == TrueClass then true
66
+ when option.class == String then
67
+ if option.match(/new_record/i)
68
+ (@record.new_record? && option == 'new_record') || (!@record.new_record? && option == 'not_new_record')
69
+ elsif option.match(/\./)
70
+ # shortcut for method and eval option
71
+ dc_process_eval(option, self)
72
+ else
73
+ eval(option['eval'])
74
+ end
75
+ # direct evaluate expression
76
+ when option['eval'] then
77
+ eval(option['eval'])
78
+ when option['method'] then
79
+ # if record present send record otherwise send self as parameter
80
+ dc_process_eval(option['method'], self)
81
+ else
82
+ false
83
+ end
84
+ end
85
+
86
+ ############################################################################
87
+ # Creates actions div for edit form.
88
+ #
89
+ # Displaying readonly form turned out to be challenge. For now when readonly parameter
90
+ # has value 2, back link will force readonly form. Value 1 or not set will result in
91
+ # normal link.
92
+ ############################################################################
93
+ def dc_actions_for_form(position)
94
+ # create standard actions
95
+ std_actions = {1 => 'back', 2 => {'type' => 'submit', 'caption' => 'drgcms.save'},
96
+ 3 => {'type' => 'submit', 'caption' => 'drgcms.save&back'} }
97
+ # when edit only
98
+ unless @record.try(:id).nil?
99
+ std_actions.merge!({6 => 'new'} )
100
+ std_actions.merge!(@record.active ? {5 => 'disable'} : {5 => 'enable'} ) if @record.respond_to?('active')
101
+ std_actions.merge!({7 => 'refresh'} )
102
+ end
103
+ actions = @form['form']['actions']
104
+ # shortcut for actions: standard
105
+ actions = nil if actions.class == String && actions == 'standard'
106
+ # standard actions
107
+ actions = std_actions if actions.nil?
108
+ # readonly
109
+ actions = {1 => 'back'} if @form['readonly']
110
+ actions = {1 => 'close'} if params[:window_close]
111
+ # Actions are strictly forbidden
112
+ if @form['form']['actions'] and dc_dont?(@form['form']['actions'])
113
+ actions = []
114
+ elsif actions['standard']
115
+ actions.merge!(std_actions)
116
+ actions['standard'] = nil
117
+ end
118
+ # Update save and save&back
119
+ actions.each do |k,v|
120
+ if v.class == String
121
+ if v.match(/save\&back/i)
122
+ actions[k] = {'type' => 'submit', 'caption' => 'drgcms.save&back'}
123
+ elsif v == 'save'
124
+ actions[k] = {'type' => 'submit', 'caption' => 'drgcms.save'}
125
+ end
126
+ end
127
+ end
128
+ # remove standard option and sort so that standard actions come first
129
+ actions.delete('standard')
130
+ actions = actions.to_a.sort {|x,y| x[0] <=> y[0]}
131
+ # Add spinner to the beginning
132
+ html = %Q[<span class="dc-spinner">#{fa_icon('spinner lg spin')}</span><ul class="dc-menu #{position}">]
133
+
134
+ actions.each do |key, options|
135
+ session[:form_processing] = "form:actions: #{key} #{options}"
136
+ next if options.nil? # yes it happends
137
+ parms = @parms.clone
138
+ if options.class == String
139
+ next if params[:readonly] and !options.match(/back|close/)
140
+
141
+ html << '<li class="dc-link dc-animate">'
142
+ html << case
143
+ when (options == 'back' or options == 'cancle') then
144
+ # If return_to is present link directly to URL
145
+ if parms['xreturn_to'] # disabled for now
146
+ dc_link_to( 'drgcms.back','arrow-left', parms['return_to'] )
147
+ else
148
+ parms['action'] = 'index'
149
+ parms['readonly'] = parms['readonly'].to_s.to_i < 2 ? nil : 1
150
+ dc_link_to( 'drgcms.back','arrow-left', parms )
151
+ end
152
+
153
+ when options == 'delete' then
154
+ parms['operation'] = options
155
+ parms['id'] = @record.id
156
+ dc_link_to( 'drgcms.delete','remove', parms, data: { confirm: t('drgcms.confirm_delete') }, method: :delete )
157
+
158
+ when options == 'new' then
159
+ parms['action'] = options
160
+ dc_link_to( 'drgcms.new', 'plus', parms)
161
+
162
+ when (options == 'enable' or options == 'disable') then
163
+ parms['operation'] = options
164
+ parms['id'] = @record.id
165
+ icon = (options == 'enable' ? 'thumbs-o-up' : 'thumbs-o-down')
166
+ dc_link_to( "drgcms.#{options}",icon, parms, method: :delete )
167
+
168
+ when options == 'edit' then
169
+ parms['operation'] = options
170
+ parms['id'] = @record.id
171
+ dc_link_to( "drgcms.#{options}",options, parms )
172
+
173
+ when options == 'refresh' then
174
+ "<div onclick='window.location.href=window.location.href;'>#{fa_icon('refresh')} #{t('drgcms.refresh')}</div></li>"
175
+
176
+ when options == 'close' then
177
+ close = params[:window_close].to_i
178
+ if close < 2
179
+ "<div onclick='window.close();'>#{fa_icon('close')} #{t('drgcms.close')}</div></li>"
180
+ else
181
+ "<div onclick='history.back();'>#{fa_icon('close')} #{t('drgcms.close')}</div></li>"
182
+ end
183
+ else
184
+ "err1 #{key}=>#{options}"
185
+ end
186
+ html << '</td>'
187
+ # non standard actions
188
+ else
189
+ options['title'] = t("#{options['title'].downcase}", options['title']) if options['title']
190
+ html << case
191
+ # submit button
192
+ when options['type'] == 'submit'
193
+ caption = options['caption'] || 'drgcms.save'
194
+ icon = options['icon'] || 'save'
195
+ prms = {}
196
+ options['params'].each { |k,v| prms[k] = dc_value_for_parameter(v) } if options['params']
197
+ if dc_is_action_active?(options)
198
+ '<li class="dc-link-submit dc-animate">' +
199
+ dc_submit_tag(caption, icon, {:data => prms, :title => options['title'] }) +
200
+ '</li>'
201
+ else
202
+ "<li class=\"dc-link-no\">#{fa_icon(icon)} #{caption}</li>"
203
+ end
204
+
205
+ # delete with some sugar added
206
+ when options['type'] == 'delete'
207
+ parms['id'] = @record.id
208
+ parms.merge!(options['params'])
209
+ caption = options['caption'] || 'drgcms.delete'
210
+ icon = options['icon'] || 'remove'
211
+ '<li class="dc-link dc-animate">' +
212
+ dc_link_to( caption, icon, parms, data: t('drgcms.confirm_delete'), method: :delete ) +
213
+ '</li>'
214
+
215
+ # ajax or link button
216
+ when %w(ajax link window).include?(options['type'])
217
+ dc_link_ajax_window_submit_action(options, @record)
218
+
219
+ # Javascript action
220
+ when options['type'] == 'script'
221
+ dc_script_action(options)
222
+ else
223
+ '<li>err2</li>'
224
+ end
225
+ end
226
+ end
227
+ (html << '</ul>').html_safe
228
+ end
229
+
230
+ ############################################################################
231
+ # Create background div and table definitions for result set.
232
+ ############################################################################
233
+ def dc_background_for_result(start)
234
+ if start == :start
235
+ html = '<div class="dc-result-div" '
236
+ html << (@form['result_set']['table_style'] ? 'style="overflow-x: scroll;" >' : '>')
237
+
238
+ html << "\n<div class=\"dc-result #{@form['result_set']['table_class']}\" "
239
+ html << (@form['result_set']['table_style'] ? "style=\"#{@form['result_set']['table_style']}\" >" : '>')
240
+ else
241
+ html = '</div></div>'
242
+ end
243
+ html.html_safe
244
+ end
245
+
246
+ ############################################################################
247
+ # Checks if value is defined and sets default. If values are sent it also checks
248
+ # if value is found in values. If not it will report error and set value to default.
249
+ # Subroutine of dc_fields_for_tab.
250
+ ############################################################################
251
+ def dc_check_and_default(value, default, values=nil) #:nodoc:
252
+ return default if value.nil?
253
+ # check if value is within allowed values
254
+ if values
255
+ if !values.index(value)
256
+ # parameters should be in downcase. Check downcase version.
257
+ if n = values.index(value.downcase)
258
+ return values[n]
259
+ else
260
+ logger.error("DRG Forms: Value #{value} not within values [#{values.join(',')}]. Default #{default} used!")
261
+ return default
262
+ end
263
+ end
264
+ end
265
+ value
266
+ end
267
+
268
+ ############################################################################
269
+ # Creates input fields for one tab. Subroutine of dc_fields_for_form.
270
+ ############################################################################
271
+ def dc_fields_for_tab(fields_on_tab) #:nodoc:
272
+ html = '<div class="dc-form">'
273
+ labels_pos = dc_check_and_default(@form['form']['labels_pos'], 'right', ['top', 'left', 'right'])
274
+ hidden_fields, odd_even = '', nil
275
+ group_option, group_count = 0, 0
276
+ reset_cycle()
277
+ # Select form fields and sort them by key
278
+ form_fields = fields_on_tab.select {|field| field.class == Integer }
279
+ form_fields.to_a.sort.each do |number, options|
280
+ session[:form_processing] = "form:fields: #{number}=#{options}"
281
+ # ignore if edit_only singe field is required
282
+ next if params[:edit_only] and params[:edit_only] != options['name']
283
+ # hidden_fields. Add them at the end
284
+ if options['type'] == 'hidden_field'
285
+ hidden_fields << DrgcmsFormFields::HiddenField.new(self, @record, options).render
286
+ next
287
+ end
288
+ # label
289
+ field_html,label,help = dc_field_label_help(options)
290
+ # Line separator
291
+ html << dc_top_bottom_line(:top, options)
292
+ # Beginning of new row
293
+ if group_count == 0
294
+ html << '<div class="row-div">'
295
+ odd_even = cycle('odd','even')
296
+ group_count = options['group'] || 1
297
+ group_option = options['group'] || 1
298
+ end
299
+ #
300
+ html << if labels_pos == 'top'
301
+ %Q[
302
+ <div class="dc-form-label-top dc-color-#{odd_even} dc-align-left" title="#{help}">
303
+ <label for="record_#{options['name']}">#{label} </label>
304
+ <div id="td_record_#{options['name']}">#{field_html}</div>
305
+ </div> ]
306
+ else
307
+ # no label
308
+ if dc_dont?(options['caption'])
309
+ label = ''
310
+ label_width = 0
311
+ data_width = 100
312
+ elsif group_option > 1
313
+ label_width = group_option != group_count ? 10 : 14
314
+ data_width = 21
315
+ else
316
+ label_width = 14
317
+ data_width = 85
318
+ end
319
+ %Q[
320
+ <div class="dc-form-label dc-color-#{odd_even} dc-align-#{labels_pos} dc-width-#{label_width}" title="#{help}">
321
+ <label for="record_#{options['name']}">#{label} </label>
322
+ </div>
323
+ <div id="td_record_#{options['name']}" class="dc-form-field dc-color-#{odd_even} dc-width-#{data_width}">#{field_html}</div>
324
+ ]
325
+ end
326
+ # check if group end
327
+ if (group_count -= 1) == 0
328
+ html << '</div>'
329
+ # insert dummy div when only two fields in group
330
+ html << '<div></div>' if group_option == 2
331
+ end
332
+
333
+ html << dc_top_bottom_line(:bottom, options)
334
+ end
335
+ html << '</div>' << hidden_fields
336
+ end
337
+
338
+ ############################################################################
339
+ # Creates edit form from fields or tabs options
340
+ ############################################################################
341
+ def dc_fields_for_form
342
+ html, tabs, tab_data = '',[], ''
343
+ @js ||= ''
344
+ @css ||= ''
345
+ # Only fields defined
346
+ if (form_fields = @form['form']['fields'])
347
+ html << "<div id='data_fields' " + (@form['form']['height'] ? "style=\"height: #{@form['form']['height']}px;\">" : '>')
348
+ html << dc_fields_for_tab(form_fields) + '</div>'
349
+ else
350
+ # there are multiple tabs on form
351
+ first = true # first tab
352
+ @form['form']['tabs'].keys.sort.each do |tab_name|
353
+ next if tab_name.match('actions')
354
+ # Tricky when editing single field. If field is not present on the tab skip to next tab
355
+ if params[:edit_only]
356
+ is_on_tab = false
357
+ @form['form']['tabs'][tab_name].each { |k, v| is_on_tab = true if params[:edit_only] == v['name'] }
358
+ next unless is_on_tab
359
+ end
360
+ # first div is displayed, all others are hidden
361
+ tab_data << "<div id=\"data_#{tab_name.delete("\s\n")}\""
362
+ tab_data << ' class="div-hidden"' unless first
363
+ tab_data << " style=\"height: #{@form['form']['height']}px;\"" if @form['form']['height']
364
+ tab_data << ">#{dc_fields_for_tab(@form['form']['tabs'][tab_name])}</div>"
365
+
366
+ tab_label, tab_title = dc_tab_label_help(tab_name)
367
+ tabs << [tab_name, tab_label, tab_title]
368
+ first = false
369
+ end
370
+ # make it all work together
371
+ html << '<ul class="dc-form-ul" >'
372
+ first = true # first tab must be selected
373
+ tabs.each do |tab_name, tab_label, tab_title|
374
+ html << %(<li id="li_#{tab_name}" data-div="#{tab_name.delete("\s\n")}" title="#{tab_title}" class="dc-form-li)
375
+ html << ' dc-form-li-selected' if first
376
+ html << "\">#{tab_label}</li>"
377
+ first = false
378
+ end
379
+ html << '</ul>'
380
+ html << tab_data
381
+ end
382
+ # add last_updated_at hidden field so controller can check if record was updated in db during editing
383
+ html << hidden_field(nil, :last_updated_at, value: @record.updated_at.to_i) if @record.respond_to?(:updated_at)
384
+ # add form time stamp to prevent double form submit
385
+ html << hidden_field(nil, :form_time_stamp, value: Time.now.to_i)
386
+ # add javascript code if defined by form
387
+ @js << "\n#{@form['script']}"
388
+ @css << "\n#{@form['css']}"
389
+ html.html_safe
390
+ end
391
+
392
+ ############################################################################
393
+ # Creates head form div. Head form div is used to display header data usefull
394
+ # to be seen even when tabs are switched.
395
+ ############################################################################
396
+ def dc_head_for_form
397
+ @css ||= ''
398
+ head = @form['form']['head']
399
+ return '' if head.nil?
400
+ html = %(<div class="dc-head #{head['class']}">\n<div class="dc-row">)
401
+ split = head['split'] || 4
402
+ percent = 100/split
403
+ current = 0
404
+ head_fields = head.select {|field| field.class == Integer }
405
+ head_fields.to_a.sort.each do |number, options|
406
+ session[:form_processing] = "form: head: #{number}=#{options}"
407
+ # Label
408
+ caption = options['caption']
409
+ span = options['span'] || 1
410
+ @css << "\n#{options['css']}" unless options['css'].blank?
411
+ label = if caption.blank?
412
+ ''
413
+ elsif options['name'] == caption
414
+ t_name(options['name'], options['name'].capitalize.gsub('_',' ') )
415
+ else
416
+ t(caption, caption)
417
+ end
418
+ # Field value
419
+ begin
420
+ field = if options['eval']
421
+ dc_process_column_eval(options, @record)
422
+ else
423
+ @record.send(options['name'])
424
+ end
425
+ rescue Exception => e
426
+ dc_log_exception(e, 'dc_head_for_form')
427
+ field = '!!!Error'
428
+ end
429
+ #
430
+ klass = dc_style_or_class(nil, options['class'], field, @record)
431
+ style = dc_style_or_class(nil, options['style'], field, @record)
432
+ html << %Q[<div class="dc-column #{klass}" style="width:#{percent*span}%;#{style}">
433
+ #{label.blank? ? '' : "<span class=\"label\">#{label}</span>"}
434
+ <span id="head-#{options['name']}" class="field">#{field}</span>
435
+ </div>]
436
+ current += span
437
+ if current == split
438
+ html << %Q[</div>\n<div class="dc-row">]
439
+ current = 0
440
+ end
441
+ end
442
+ html << '</div></div>'
443
+ html.html_safe
444
+ end
445
+
446
+ ############################################################################
447
+ # Returns username for id. Subroutine of dc_document_statistics
448
+ ###########################################################################
449
+ def dc_document_user_for(field_name) #:nodoc:
450
+ if @record[field_name]
451
+ u = DcUser.find(@record[field_name])
452
+ return u ? u.name : @record[field_name]
453
+ end
454
+ # nil
455
+ end
456
+
457
+ ############################################################################
458
+ # Creates current document statistics div (created_by, created_at, ....) at the bottom of edit form.
459
+ # + lots of more. At the moment also adds icon for dumping current document as json text.
460
+ ############################################################################
461
+ def dc_document_statistics
462
+ return '' if @record.new_record? or dc_dont?(@form['form']['info'])
463
+ html = %Q[<div id="dc-document-info">#{fa_icon('info-circle lg')}</div> <div id="dc-document-info-popup" class="div-hidden"> ]
464
+ #
465
+ u = dc_document_user_for('created_by')
466
+ html << %Q[<div><span>#{t('drgcms.created_by', 'Created by')}: </span><span>#{u}</span></div>] if u
467
+ u = dc_document_user_for('updated_by')
468
+ html << %Q[<div><span>#{t('drgcms.updated_by', 'Updated by')}: </span><span>#{u}</span></div>] if u
469
+ html << %Q[<div><span>#{t('drgcms.created_at', 'Created at')}: </span><span>#{dc_format_value(@record.created_at)}</span></div>] if @record['created_at']
470
+ html << %Q[<div><span>#{t('drgcms.updated_at', 'Updated at')}: </span><span>#{dc_format_value(@record.updated_at)}</span></div>] if @record['updated_at']
471
+ # copy to clipboard icon
472
+ parms = params.clone
473
+ parms[:controller] = 'dc_common'
474
+ parms[:action] = 'copy_clipboard'
475
+ url = url_for(parms.permit!)
476
+ html << fa_icon('copy lg', class: 'dc-link-img dc-link-ajax dc-animate',
477
+ 'data-url' => url, 'data-request' => 'get', title: t('drgcms.doc_copy_clipboard') )
478
+
479
+ url = url_for(controller: :cmsedit, action: :index, table: 'dc_journal', filter: 'on',
480
+ filter_oper: 'eq', filter_field: 'doc_id', filter_value: @record.id)
481
+ html << fa_icon('history lg', class: 'dc-link-img dc-animate dc-window-open',
482
+ 'data-url' => url, title: t('helpers.label.dc_journal.tabletitle') )
483
+
484
+ (html << '</div></div>').html_safe
485
+ end
486
+
487
+ private
488
+
489
+ ############################################################################
490
+ # Creates top or bottom horizontal line on form.
491
+ #
492
+ # @param [String] location (top or bottom)
493
+ # @param [Object] options yaml field definition
494
+ #
495
+ # @return [String] html code for drawing a line
496
+ ############################################################################
497
+ def dc_top_bottom_line(location, options)
498
+ if options["#{location}-line"] || options['line'].to_s == location.to_s
499
+ '<div class="dc-separator"></div>'
500
+ else
501
+ ''
502
+ end
503
+ end
504
+
505
+
506
+ end