drg_cms 0.5.52.12 → 0.6.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +5 -5
  2. data/app/assets/javascripts/drg_cms/drg_cms.js +395 -120
  3. data/app/assets/javascripts/drg_cms/jstree.min.js +6 -6
  4. data/app/assets/javascripts/drg_cms_application.js +1 -1
  5. data/app/assets/stylesheets/drg_cms/drg_cms.css +476 -215
  6. data/app/assets/stylesheets/drg_cms/jstree.css +6 -12
  7. data/app/assets/stylesheets/drg_cms/select-multiple.css +19 -13
  8. data/app/assets/stylesheets/drg_cms_cms.css +1 -1
  9. data/app/controllers/cmsedit_controller.rb +474 -233
  10. data/app/controllers/dc_application_controller.rb +264 -41
  11. data/app/controllers/dc_common_controller.rb +75 -63
  12. data/app/{controllers → controls}/browse_models_control.rb +0 -0
  13. data/app/{controllers → controls}/dc_page_control.rb +24 -8
  14. data/app/controls/dc_poll_result_control.rb +88 -0
  15. data/app/controls/dc_report.rb +227 -0
  16. data/app/{controllers → controls}/design_element_settings_control.rb +0 -0
  17. data/app/forms/all_options.yml +70 -12
  18. data/app/forms/cms_menu.yml +26 -17
  19. data/app/forms/dc_ad.yml +11 -22
  20. data/app/forms/dc_big_table.yml +1 -0
  21. data/app/forms/dc_big_table_value.yml +1 -0
  22. data/app/forms/dc_design.yml +19 -16
  23. data/app/forms/dc_filter.yml +3 -6
  24. data/app/forms/dc_gallery.yml +53 -0
  25. data/app/forms/dc_json_ld.yml +59 -0
  26. data/app/forms/dc_key_value.yml +32 -0
  27. data/app/forms/dc_link.yml +16 -10
  28. data/app/forms/dc_menu_item.yml +6 -0
  29. data/app/forms/dc_page.yml +2 -7
  30. data/app/forms/dc_poll.yml +16 -9
  31. data/app/forms/dc_poll_item.yml +2 -1
  32. data/app/forms/dc_poll_result.yml +83 -0
  33. data/app/forms/dc_poll_result_export.yml +35 -0
  34. data/app/forms/dc_removed_url.yml +42 -0
  35. data/app/forms/dc_seo.yml +33 -0
  36. data/app/forms/dc_site.yml +2 -6
  37. data/app/forms/json_ld_schema.yml +168 -0
  38. data/app/helpers/cms_common_helper.rb +311 -0
  39. data/app/helpers/cms_edit_helper.rb +498 -0
  40. data/app/helpers/cms_helper.rb +230 -0
  41. data/app/helpers/cms_index_helper.rb +564 -0
  42. data/app/helpers/dc_application_helper.rb +195 -268
  43. data/app/models/{dc_dummy.rb → __dc_dummy.rb} +0 -0
  44. data/app/models/concerns/dc_page_concern.rb +31 -6
  45. data/app/models/concerns/dc_seo_concern.rb +66 -0
  46. data/app/models/concerns/dc_site_concern.rb +12 -1
  47. data/app/models/concerns/dc_user_concern.rb +5 -3
  48. data/app/models/dc_design.rb +2 -0
  49. data/app/models/dc_filter.rb +37 -20
  50. data/app/models/dc_gallery.rb +64 -0
  51. data/app/models/dc_json_ld.rb +152 -0
  52. data/app/models/dc_key_value.rb +48 -0
  53. data/app/models/dc_link.rb +1 -0
  54. data/app/models/dc_memory.rb +26 -4
  55. data/app/models/dc_page.rb +1 -2
  56. data/app/models/dc_permission.rb +30 -0
  57. data/app/models/dc_poll.rb +39 -19
  58. data/app/models/dc_poll_result.rb +46 -0
  59. data/app/models/dc_removed_url.rb +54 -0
  60. data/app/models/dc_temp.rb +140 -0
  61. data/app/models/drgcms_form_fields.rb +6 -1642
  62. data/app/models/drgcms_form_fields/action.rb +61 -0
  63. data/app/models/drgcms_form_fields/check_box.rb +72 -0
  64. data/app/models/drgcms_form_fields/comment.rb +53 -0
  65. data/app/models/drgcms_form_fields/date_picker.rb +104 -0
  66. data/app/models/drgcms_form_fields/date_select.rb +68 -0
  67. data/app/models/drgcms_form_fields/datetime_picker.rb +89 -0
  68. data/app/models/drgcms_form_fields/datetime_select.rb +73 -0
  69. data/app/models/drgcms_form_fields/drgcms_field.rb +287 -0
  70. data/app/models/drgcms_form_fields/embedded.rb +97 -0
  71. data/app/models/drgcms_form_fields/file_field.rb +52 -0
  72. data/app/models/drgcms_form_fields/file_select.rb +70 -0
  73. data/app/models/drgcms_form_fields/hash_field.rb +86 -0
  74. data/app/models/drgcms_form_fields/hidden_field.rb +52 -0
  75. data/app/models/drgcms_form_fields/html_field.rb +70 -0
  76. data/app/models/drgcms_form_fields/journal_diff.rb +60 -0
  77. data/app/models/drgcms_form_fields/link_to.rb +69 -0
  78. data/app/models/drgcms_form_fields/method.rb +65 -0
  79. data/app/models/drgcms_form_fields/multitext_autocomplete.rb +204 -0
  80. data/app/models/drgcms_form_fields/number_field.rb +92 -0
  81. data/app/models/drgcms_form_fields/password_field.rb +62 -0
  82. data/app/models/drgcms_form_fields/radio.rb +96 -0
  83. data/app/models/drgcms_form_fields/readonly.rb +79 -0
  84. data/app/models/drgcms_form_fields/select.rb +226 -0
  85. data/app/models/drgcms_form_fields/submit_tag.rb +58 -0
  86. data/app/models/drgcms_form_fields/text_area.rb +68 -0
  87. data/app/models/drgcms_form_fields/text_autocomplete.rb +155 -0
  88. data/app/models/drgcms_form_fields/text_field.rb +56 -0
  89. data/app/models/drgcms_form_fields/text_with_select.rb +95 -0
  90. data/app/models/drgcms_form_fields/tree_select.rb +169 -0
  91. data/app/{helpers → renderers}/dc_ad_renderer.rb +0 -0
  92. data/app/{helpers → renderers}/dc_big_menu_renderer.rb +1 -0
  93. data/app/{helpers → renderers}/dc_captcha_renderer.rb +0 -0
  94. data/app/{helpers → renderers}/dc_common_renderer.rb +0 -0
  95. data/app/renderers/dc_gallery_renderer.rb +95 -0
  96. data/app/{helpers → renderers}/dc_menu_renderer.rb +11 -4
  97. data/app/{helpers → renderers}/dc_page_renderer.rb +21 -3
  98. data/app/{helpers → renderers}/dc_part_renderer.rb +5 -4
  99. data/app/{helpers → renderers}/dc_piece_renderer.rb +1 -1
  100. data/app/{helpers → renderers}/dc_poll_renderer.rb +86 -51
  101. data/app/{helpers → renderers}/dc_renderer.rb +1 -0
  102. data/app/{helpers → renderers}/dc_simple_menu_renderer.rb +1 -0
  103. data/app/views/cmsedit/{remove_edit_stuff.js.erb → __remove_edit_stuff.js.erb} +0 -0
  104. data/app/views/cmsedit/{show.html.erb → __show.html.erb} +0 -0
  105. data/app/views/cmsedit/_edit_stuff.html.erb +4 -25
  106. data/app/views/cmsedit/_form.html.erb +4 -3
  107. data/app/views/cmsedit/_result.html.erb +2 -3
  108. data/app/views/cmsedit/edit.html.erb +2 -1
  109. data/app/views/cmsedit/index.html.erb +6 -1
  110. data/app/views/cmsedit/new.html.erb +1 -1
  111. data/config/locales/drgcms_en.yml +15 -3
  112. data/config/locales/drgcms_sl.yml +18 -6
  113. data/config/locales/models_en.yml +103 -19
  114. data/config/locales/models_sl.yml +102 -17
  115. data/drg_cms.gemspec +3 -3
  116. data/lib/drg_cms.rb +6 -2
  117. data/lib/drg_cms/version.rb +2 -2
  118. data/lib/generators/new_drg_form/new_drg_form_generator.rb +9 -2
  119. data/lib/tasks/database.rake +6 -56
  120. data/lib/tasks/dc_cleanup.rake +1 -1
  121. metadata +106 -61
  122. data/app/assets/stylesheets/drg_cms/__jquery-ui.css +0 -339
  123. data/app/helpers/application_helper.rb +0 -2
  124. data/app/helpers/cmsedit_helper.rb +0 -844
  125. data/test/fixtures/drg_cms_test_data.rb +0 -87
@@ -0,0 +1,311 @@
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
+ # Common methods which may also come handy in controllers or models or any
27
+ # other module of program.
28
+ #
29
+ # Usage: include CmsCommonHelper
30
+ ####################################################################
31
+ module CmsCommonHelper
32
+
33
+ ####################################################################
34
+ # Wrapper for i18 t method, with some spice added. If translation is not found English
35
+ # translation value will be returned. And if still not found default value will be returned if passed.
36
+ #
37
+ # Parameters:
38
+ # [key] String. String to be translated into locale.
39
+ # [default] String. Value returned if translation is not found.
40
+ #
41
+ # Example:
42
+ # t('translate.this','Enter text for ....')
43
+ #
44
+ # Returns:
45
+ # String. Translated text.
46
+ ####################################################################
47
+ def self.t(key, default=nil)
48
+ c = I18n.t(key)
49
+ if c.class == Hash or c.match( 'translation missing' )
50
+ c = I18n.t(key, locale: 'en')
51
+ # Still not found. Return default if set
52
+ if c.class == Hash or c.match( 'translation missing' )
53
+ c = default.nil? ? key : default
54
+ end
55
+ end
56
+ c
57
+ end
58
+
59
+ ####################################################################
60
+ def t(key, default=nil) #:nodoc
61
+ CmsCommonHelper.t(key, default)
62
+ end
63
+
64
+ ####################################################################
65
+ # Returns table (collection) name translation for usage in dialog title. Tablename
66
+ # title is provided by helpers.label.table_name.tabletitle locale.
67
+ #
68
+ # Parameters:
69
+ # [tablename] String. Table (collection) name to be translated.
70
+ # [default] String. Value returned if translation is not found.
71
+ #
72
+ # Returns:
73
+ # String. Translated text.
74
+ ####################################################################
75
+ def t_tablename(tablename, default=nil)
76
+ t('helpers.label.' + tablename + '.tabletitle', default || tablename)
77
+ end
78
+
79
+ ############################################################################
80
+ # Returns label for field translated to current locale for usage on data entry form.
81
+ # Translation is provided by lang.helpers.label.table_name.field_name locale. If
82
+ # translation is not found method will capitalize field_name and replace '_' with ' '.
83
+ ############################################################################
84
+ def t_name(field_name, default='')
85
+ c = t("helpers.label.#{@form['table']}.#{field_name}", default)
86
+ c = field_name.capitalize.gsub('_',' ') if c.match( 'translation missing' )
87
+ c
88
+ end
89
+
90
+ ###########################################################################
91
+ # When select field is used on form options for select can be provided by
92
+ # helpers.label.table_name.choices4_name locale. This is how select
93
+ # field options are translated. Method returns selected choice translated
94
+ # to current locale.
95
+ #
96
+ # Parameters:
97
+ # [model] String. Table (collection) model name (lowercase).
98
+ # [field] String. Field name used.
99
+ # [value] String. Value of field which translation will be returned.
100
+ #
101
+ # Example:
102
+ # # usage in program. Choice values for state are 'Deactivated:0,Active:1,Waiting:2'
103
+ # dc_name4_value('dc_user', 'state', @record.active )
104
+ #
105
+ # # usage in form
106
+ # columns:
107
+ # 2:
108
+ # name: state
109
+ # eval: dc_name4_value dc_user, state
110
+ #
111
+ # Returns:
112
+ # String. Descriptive text (translated) for selected choice value.
113
+ ############################################################################
114
+ def self.dc_name_for_value(model, field, value)
115
+ return '' if value.nil?
116
+ c = t('helpers.label.' + model + '.choices4_' + field )
117
+ a = c.chomp.split(',').inject([]) {|r,v| r << v.split(':') }
118
+ a.each {|e| return e.first if e.last.to_s == value.to_s }
119
+ '???'
120
+ end
121
+
122
+ ############################################################################
123
+ def dc_name_for_value(model, field, value)
124
+ CmsCommonHelper.dc_name_for_value(model, field, value)
125
+ end
126
+
127
+ ############################################################################
128
+ #
129
+ ############################################################################
130
+ def dc_name4_value(model, field, value) #nodoc
131
+ #dc_deprecate('dc_name4_value will be deprecated. Use dc_name_for_value instead.')
132
+ CmsCommonHelper.dc_name_for_value(model, field, value)
133
+ end
134
+
135
+ ############################################################################
136
+ # Return choices for field in model if choices are defined in localization text.
137
+ #
138
+ # Parameters:
139
+ # [model] String. Table (collection) model name (lowercase).
140
+ # [field] String. Field name used.
141
+ #
142
+ # Example:
143
+ # dc_choices4_field('dc_user', 'state' )
144
+ #
145
+ # Returns:
146
+ # Array. Choices for select input field
147
+ ############################################################################
148
+ def self.dc_choices_for_field(model, field)
149
+ c = CmsCommonHelper.t('helpers.label.' + model + '.choices4_' + field )
150
+ return ['error'] if c.match( 'translation missing' )
151
+ c.chomp.split(',').inject([]) {|r,v| r << v.split(':') }
152
+ end
153
+
154
+ ############################################################################
155
+ def dc_choices_for_field(model, field)
156
+ CmsCommonHelper.dc_choices_for_field(model, field)
157
+ end
158
+
159
+ ############################################################################
160
+ #
161
+ ############################################################################
162
+ def dc_choices4_field(model, field) #nodoc
163
+ #dc_deprecate('dc_choices4_field will be deprecated. Use dc_choices_for_field instead.')
164
+ CmsCommonHelper.dc_choices_for_field(model, field)
165
+ end
166
+
167
+ ############################################################################
168
+ # Will return descriptive text for id key when field in one table (collection) has belongs_to
169
+ # relation to other table.
170
+ #
171
+ # Parameters:
172
+ # [model] String. Table (collection) model name (lowercase).
173
+ # [field] String. Field name holding the value of descriptive text.
174
+ # [field_name] String. ID field name. This is by default id, but can be any other
175
+ # (preferred unique) field.
176
+ # [value] Value of id_field. Usually a BSON Key but can be any other data type.
177
+ #
178
+ # Example:
179
+ # # usage in program.
180
+ # dc_name4_id('dc_user', 'name', nil, dc_page.created_by)
181
+ #
182
+ # # usage in form
183
+ # columns:
184
+ # 2:
185
+ # name: site_id
186
+ # eval: dc_name4_id,site,name
187
+ # # username is saved to document instead of user.id field
188
+ # 5:
189
+ # name: user
190
+ # eval: dc_name4_id,dc_user,name,username
191
+ #
192
+ # Returns:
193
+ # String. Name (descriptive value) for specified key in table.
194
+ ############################################################################
195
+ def dc_name_for_id(model, field, field_name, id=nil)
196
+ return '' if id.nil?
197
+ field_name = (field_name || 'id').strip.to_sym
198
+ field = field.strip.to_sym
199
+
200
+ model = model.strip.classify.constantize if model.class == String
201
+ rec = Mongoid::QueryCache.cache { model.find_by(field_name => id) }
202
+ rec.nil? ? '' : (rec.send(field) rescue 'not defined')
203
+ end
204
+
205
+ ############################################################################
206
+ #
207
+ ############################################################################
208
+ def dc_name4_id(model, field, field_name, id=nil) #nodoc
209
+ #dc_deprecate('dc_name4_id will be deprecated. Use dc_name_for_id instead.')
210
+ dc_name_for_id(model, field, field_name, id)
211
+ end
212
+
213
+ ############################################################################
214
+ # Return html code for icon presenting boolean value. Icon is a picture of checked or unchecked box.
215
+ #
216
+ # Parameters:
217
+ # [value] Boolean.
218
+ #
219
+ # Example:
220
+ # # usage from program
221
+ # dc_icon4_boolean(some_value)
222
+ #
223
+ # # usage from form description
224
+ # columns:
225
+ # 10:
226
+ # name: active
227
+ # eval: dc_icon4_boolean
228
+ ############################################################################
229
+ def dc_icon_for_boolean(value=false)
230
+ dc_dont?(value, true) ? fa_icon('square-o lg') : fa_icon('check-square-o lg')
231
+ end
232
+
233
+ ############################################################################
234
+ #
235
+ ############################################################################
236
+ def dc_icon4_boolean(value=false) #nodoc
237
+ #dc_deprecate('dc_icon4_boolean will be deprecated. Use dc_icon_for_boolean instead.')
238
+ dc_icon_for_boolean(value)
239
+ end
240
+
241
+ ############################################################################
242
+ # Returns html code for displaying date/time formatted by strftime. Will return '' if value is nil.
243
+ #
244
+ # Parameters:
245
+ # [value] Date/DateTime/Time.
246
+ # [format] String. strftime format mask. Defaults to locale's default format.
247
+ ############################################################################
248
+ def self.dc_format_date_time(value, format=nil)
249
+ return '' if value.blank?
250
+
251
+ format ||= value.class == Date ? t('date.formats.default') : t('time.formats.default')
252
+ if format.size == 1
253
+ format = format.match(/d/i) ? t('date.formats.default') : t('time.formats.default')
254
+ end
255
+ value.strftime(format)
256
+ end
257
+
258
+ def dc_format_date_time(value, format=nil) #:nodoc:
259
+ CmsCommonHelper.dc_format_date_time(value, format)
260
+ end
261
+
262
+ ####################################################################
263
+ #
264
+ ####################################################################
265
+ def dc_date_time(value, format) #:nodoc:
266
+ dc_deprecate 'dc_date_time will be deprecated! Use dc_format_date_time instead.'
267
+ dc_format_date_time(value, format)
268
+ end
269
+
270
+ ############################################################################
271
+ # Returns html code for displaying formatted number.
272
+ #
273
+ # Parameters:
274
+ # [value] Numeric number.
275
+ # [decimals] Integer. Number of decimals
276
+ # [separator] String. Decimals separator
277
+ # [delimiter] String. Thousands delimiter.
278
+ # [currency] String. Currency symbol if applied to result string.
279
+ ############################################################################
280
+ def self.dc_format_number(value=0, decimals=nil, separator=nil, delimiter=nil, currency=nil)
281
+ decimals ||= I18n.t('number.currency.format.precision')
282
+ separator ||= I18n.t('number.currency.format.separator')
283
+ separator = '' if decimals == 0
284
+ delimiter ||= I18n.t('number.currency.format.delimiter')
285
+ whole, dec = value.to_s.split('.')
286
+ whole = '0' if whole.blank?
287
+ # remove and remember sign
288
+ sign = ''
289
+ if whole[0] == '-'
290
+ whole.delete_prefix!('-')
291
+ sign << '-'
292
+ end
293
+ # format decimals
294
+ dec ||= '0'
295
+ dec = dec[0,decimals]
296
+ while dec.size < decimals do dec += '0' end
297
+ # slice whole on chunks of 3
298
+ ar = []
299
+ while whole.size > 0 do
300
+ n = whole.size >=3 ? 3 : whole.size
301
+ ar << whole.slice!(n*-1,n)
302
+ end
303
+ # put it all back and format
304
+ "#{sign}#{ar.reverse.join(delimiter)}#{separator}#{dec}"
305
+ end
306
+
307
+ def dc_format_number(value=0, decimals=nil, separator=nil, delimiter=nil, currency=nil) #:nodoc:
308
+ CmsCommonHelper.dc_format_number(value, decimals, separator, delimiter, currency)
309
+ end
310
+
311
+ end
@@ -0,0 +1,498 @@
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)#:nodoc:
37
+ if param.class == Hash
38
+ dc_internal_var(param['object'] || 'record', param['method'])
39
+ else
40
+ param
41
+ end
42
+ end
43
+
44
+ ############################################################################
45
+ # Creates actions div for edit form.
46
+ #
47
+ # Displaying readonly form turned out to be challenge. For now when readonly parameter
48
+ # has value 2, back link will force readonly form. Value 1 or not set will result in
49
+ # normal link.
50
+ ############################################################################
51
+ def dc_is_action_active?(options)
52
+ if options['when_new']
53
+ dc_deprecate("when_option will be deprecated and replaced by active: not_new_record! Form #{params[:form_name]}")
54
+ return !(dc_dont?(options['when_new']) and @record.new_record?)
55
+ end
56
+ return true unless options['active']
57
+ # alias record and document so both can be used in eval
58
+ record = document = @record
59
+ option = options['active']
60
+ case
61
+ # usually only for test
62
+ when option.class == TrueClass || option['eval'].class == TrueClass then true
63
+ when option.class == String then
64
+ if option.match(/new_record/i)
65
+ (@record.new_record? && option == 'new_record') || (!@record.new_record? && option == 'not_new_record')
66
+ elsif option.match(/\./)
67
+ # shortcut for method and eval option
68
+ parms = @record ? @record : params
69
+ dc_process_eval(option,parms)
70
+ else
71
+ eval(option['eval'])
72
+ end
73
+ # direct evaluate expression
74
+ when option['eval'] then
75
+ eval(option['eval'])
76
+ when option['method'] then
77
+ # if record present send record otherwise send params as parameter
78
+ parms = @record ? @record : params
79
+ dc_process_eval(option['method'],parms)
80
+ else
81
+ false
82
+ end
83
+ end
84
+
85
+ ############################################################################
86
+ # Creates actions div for edit form.
87
+ #
88
+ # Displaying readonly form turned out to be challenge. For now when readonly parameter
89
+ # has value 2, back link will force readonly form. Value 1 or not set will result in
90
+ # normal link.
91
+ ############################################################################
92
+ def dc_actions_for_form(position)
93
+ # create standard actions
94
+ std_actions = {1 => 'back', 2 => {'type' => 'submit', 'caption' => 'drgcms.save'},
95
+ 3 => {'type' => 'submit', 'caption' => 'drgcms.save&back'} }
96
+ # when edit only
97
+ unless @record.try(:id).nil?
98
+ std_actions.merge!({6 => 'new'} )
99
+ std_actions.merge!(@record.active ? {5 => 'disable'} : {5 => 'enable'} ) if @record.respond_to?('active')
100
+ std_actions.merge!({7 => 'refresh'} )
101
+ end
102
+ actions = @form['form']['actions']
103
+ # shortcut for actions: standard
104
+ actions = nil if actions.class == String && actions == 'standard'
105
+ # standard actions
106
+ actions = std_actions if actions.nil?
107
+ # readonly
108
+ actions = {1 => 'back'} if @form['readonly']
109
+ actions = {1 => 'close'} if params[:window_close]
110
+ # Actions are strictly forbidden
111
+ if @form['form']['actions'] and dc_dont?(@form['form']['actions'])
112
+ actions = []
113
+ elsif actions['standard']
114
+ actions.merge!(std_actions)
115
+ actions['standard'] = nil
116
+ end
117
+ # Update save and save&back
118
+ actions.each do |k,v|
119
+ if v.class == String
120
+ if v.match(/save\&back/i)
121
+ actions[k] = {'type' => 'submit', 'caption' => 'drgcms.save&back'}
122
+ elsif v == 'save'
123
+ actions[k] = {'type' => 'submit', 'caption' => 'drgcms.save'}
124
+ end
125
+ end
126
+ end
127
+ # remove standard option and sort so that standard actions come first
128
+ actions.delete('standard')
129
+ actions = actions.to_a.sort {|x,y| x[0] <=> y[0]}
130
+ # Add spinner to the beginning
131
+ html = %Q[<span class="dc-spinner">#{fa_icon('spinner lg spin')}</span><ul class="dc-menu #{position}">]
132
+
133
+ actions.each do |key, options|
134
+ session[:form_processing] = "form:actions: #{key} #{options}"
135
+ next if options.nil? # yes it happends
136
+ parms = @parms.clone
137
+ if options.class == String
138
+ next if params[:readonly] and !options.match(/back|close/)
139
+
140
+ html << '<li class="dc-link dc-animate">'
141
+ html << case
142
+ when (options == 'back' or options == 'cancle') then
143
+ # If return_to is present link directly to URL
144
+ if parms['xreturn_to'] # disabled for now
145
+ dc_link_to( 'drgcms.back','arrow-left', parms['return_to'] )
146
+ else
147
+ parms['action'] = 'index'
148
+ parms['readonly'] = parms['readonly'].to_s.to_i < 2 ? nil : 1
149
+ dc_link_to( 'drgcms.back','arrow-left', parms )
150
+ end
151
+
152
+ when options == 'delete' then
153
+ parms['operation'] = options
154
+ parms['id'] = @record.id
155
+ dc_link_to( 'drgcms.delete','remove', parms, data: { confirm: t('drgcms.confirm_delete') }, method: :delete )
156
+
157
+ when options == 'new' then
158
+ parms['action'] = options
159
+ dc_link_to( 'drgcms.new', 'plus', parms)
160
+
161
+ when (options == 'enable' or options == 'disable') then
162
+ parms['operation'] = options
163
+ parms['id'] = @record.id
164
+ icon = (options == 'enable' ? 'thumbs-o-up' : 'thumbs-o-down')
165
+ dc_link_to( "drgcms.#{options}",icon, parms, method: :delete )
166
+
167
+ when options == 'edit' then
168
+ parms['operation'] = options
169
+ parms['id'] = @record.id
170
+ dc_link_to( "drgcms.#{options}",options, parms )
171
+
172
+ when options == 'refresh' then
173
+ "<div onclick='window.location.href=window.location.href;'>#{fa_icon('refresh')} #{t('drgcms.refresh')}</div></li>"
174
+
175
+ when options == 'close' then
176
+ close = params[:window_close].to_i
177
+ if close < 2
178
+ "<div onclick='window.close();'>#{fa_icon('close')} #{t('drgcms.close')}</div></li>"
179
+ else
180
+ "<div onclick='history.back();'>#{fa_icon('close')} #{t('drgcms.close')}</div></li>"
181
+ end
182
+ else
183
+ "err1 #{key}=>#{options}"
184
+ end
185
+ html << '</td>'
186
+ # non standard actions
187
+ else
188
+ options['title'] = t("#{options['title'].downcase}", options['title']) if options['title']
189
+ html << case
190
+ # submit button
191
+ when options['type'] == 'submit'
192
+ caption = options['caption'] || 'drgcms.save'
193
+ icon = options['icon'] || 'save'
194
+ prms = {}
195
+ options['params'].each { |k,v| prms[k] = dc_value_for_parameter(v) } if options['params']
196
+ if dc_is_action_active?(options)
197
+ '<li class="dc-link-submit dc-animate">' +
198
+ dc_submit_tag(caption, icon, {:data => prms, :title => options['title'] }) +
199
+ '</li>'
200
+ else
201
+ "<li class=\"dc-link-no\">#{fa_icon(icon)} #{caption}</li>"
202
+ end
203
+
204
+ # delete with some sugar added
205
+ when options['type'] == 'delete'
206
+ parms['id'] = @record.id
207
+ parms.merge!(options['params'])
208
+ caption = options['caption'] || 'drgcms.delete'
209
+ icon = options['icon'] || 'remove'
210
+ '<li class="dc-link dc-animate">' +
211
+ dc_link_to( caption, icon, parms, data: t('drgcms.confirm_delete'), method: :delete ) +
212
+ '</li>'
213
+
214
+ # ajax or link button
215
+ when %w(ajax link window).include?(options['type'])
216
+ dc_link_ajax_window_submit_action(options, @record)
217
+
218
+ # Javascript action
219
+ when options['type'] == 'script'
220
+ dc_script_action(options)
221
+ else
222
+ '<li>err2</li>'
223
+ end
224
+ end
225
+ end
226
+ (html << '</ul>').html_safe
227
+ end
228
+
229
+ ############################################################################
230
+ # Create background div and table definitions for result set.
231
+ ############################################################################
232
+ def dc_background_for_result(start)
233
+ if start == :start
234
+ html = '<div class="dc-result-div" '
235
+ html << (@form['result_set']['table_style'] ? 'style="overflow-x: scroll;" >' : '>')
236
+ #
237
+ html << "\n<div class=\"dc-result #{@form['result_set']['table_class']}\" "
238
+ html << (@form['result_set']['table_style'] ? "style=\"#{@form['result_set']['table_style']}\" >" : '>')
239
+ else
240
+ html = '</div></div>'
241
+ end
242
+ html.html_safe
243
+ end
244
+
245
+ ############################################################################
246
+ # Checks if value is defined and sets default. If values are sent it also checks
247
+ # if value is found in values. If not it will report error and set value to default.
248
+ # Subroutine of dc_fields_for_tab.
249
+ ############################################################################
250
+ def dc_check_and_default(value, default, values=nil) #:nodoc:
251
+ return default if value.nil?
252
+ # check if value is within allowed values
253
+ if values
254
+ if !values.index(value)
255
+ # parameters should be in downcase. Check downcase version.
256
+ if n = values.index(value.downcase)
257
+ return values[n]
258
+ else
259
+ logger.error("DRG Forms: Value #{value} not within values [#{values.join(',')}]. Default #{default} used!")
260
+ return default
261
+ end
262
+ end
263
+ end
264
+ value
265
+ end
266
+
267
+ ############################################################################
268
+ # Creates input fields for one tab. Subroutine of dc_fields_for_form.
269
+ ############################################################################
270
+ def dc_fields_for_tab(fields_on_tab) #:nodoc:
271
+ html = '<div class="dc-form">'
272
+ labels_pos = dc_check_and_default(@form['form']['labels_pos'], 'right', ['top', 'left', 'right'])
273
+ hidden_fields, odd_even = '', nil
274
+ group_option, group_count = 0, 0
275
+ reset_cycle()
276
+ # Select form fields and sort them by key
277
+ form_fields = fields_on_tab.select {|field| field.class == Integer }
278
+ form_fields.to_a.sort.each do |number, options|
279
+ session[:form_processing] = "form:fields: #{number}=#{options}"
280
+ # ignore if edit_only singe field is required
281
+ next if params[:edit_only] and params[:edit_only] != options['name']
282
+ # hidden_fields. Add them at the end
283
+ if options['type'] == 'hidden_field'
284
+ hidden_fields << DrgcmsFormFields::HiddenField.new(self, @record, options).render
285
+ next
286
+ end
287
+ # label
288
+ field_html,label,help = dc_field_label_help(options)
289
+ # Line separator
290
+ html << dc_top_bottom_line(:top, options)
291
+ # Beginning of new row
292
+ if group_count == 0
293
+ html << '<div class="row-div">'
294
+ odd_even = cycle('odd','even')
295
+ group_count = options['group'] || 1
296
+ group_option = options['group'] || 1
297
+ end
298
+ #
299
+ html << if labels_pos == 'top'
300
+ %Q[
301
+ <div class="dc-form-label-top dc-color-#{odd_even} dc-align-left" title="#{help}">
302
+ <label for="record_#{options['name']}">#{label} </label>
303
+ <div id="td_record_#{options['name']}">#{field_html}</div>
304
+ </div> ]
305
+ else
306
+ # no label
307
+ if dc_dont?(options['caption'])
308
+ label = ''
309
+ label_width = 0
310
+ data_width = 100
311
+ elsif group_option > 1
312
+ label_width = group_option != group_count ? 10 : 14
313
+ data_width = 21
314
+ else
315
+ label_width = 14
316
+ data_width = 85
317
+ end
318
+ %Q[
319
+ <div class="dc-form-label dc-color-#{odd_even} dc-align-#{labels_pos} dc-width-#{label_width}" title="#{help}">
320
+ <label for="record_#{options['name']}">#{label} </label>
321
+ </div>
322
+ <div id="td_record_#{options['name']}" class="dc-form-field dc-color-#{odd_even} dc-width-#{data_width}">#{field_html}</div>
323
+ ]
324
+ end
325
+ # check if group end
326
+ if (group_count -= 1) == 0
327
+ html << '</div>'
328
+ # insert dummy div when only two fields in group
329
+ html << '<div></div>' if group_option == 2
330
+ end
331
+
332
+ html << dc_top_bottom_line(:bottom, options)
333
+ end
334
+ html << '</div>' << hidden_fields
335
+ end
336
+
337
+ ############################################################################
338
+ # Creates edit form div.
339
+ ############################################################################
340
+ def dc_fields_for_form()
341
+ html, tabs, tab_data = '',[], ''
342
+ @js ||= ''
343
+ @css ||= ''
344
+ # Only fields defined
345
+ if (form_fields = @form['form']['fields'])
346
+ html << "<div id='data_fields' " + (@form['form']['height'] ? "style=\"height: #{@form['form']['height']}px;\">" : '>')
347
+ html << dc_fields_for_tab(form_fields) + '</div>'
348
+ else
349
+ # there are multiple tabs on form
350
+ first = true # first tab
351
+ @form['form']['tabs'].keys.sort.each do |tab_name|
352
+ next if tab_name.match('actions')
353
+ # Tricky. If field name is not on the tab skip to next tab
354
+ if params[:edit_only]
355
+ is_on_tab = false
356
+ @form['form']['tabs'][tab_name].each {|k,v| is_on_tab = true if params[:edit_only] == v['name'] }
357
+ next unless is_on_tab
358
+ end
359
+ # first div is displayed, all others are hidden
360
+ tab_data << "<div id=\"data_#{tab_name.delete("\s\n")}\""
361
+ tab_data << ' class="div-hidden"' unless first
362
+ tab_data << " style=\"height: #{@form['form']['height']}px;\"" if @form['form']['height']
363
+ tab_data << ">#{dc_fields_for_tab(@form['form']['tabs'][tab_name])}</div>"
364
+ tab_label = @form['form']['tabs'][tab_name]['caption'] || tab_name
365
+ tabs << [tab_name, tab_label]
366
+ first = false
367
+ end
368
+ # make it all work together
369
+ html << '<ul class="dc-form-ul" >'
370
+ first = true # first tab must be selected
371
+ tabs.each do |tab_name, tab_label|
372
+ html << "<li id=\"li_#{tab_name}\" data-div=\"#{tab_name.delete("\s\n")}\" class=\"dc-form-li"
373
+ html << ' dc-form-li-selected' if first
374
+ html << "\">#{t(tab_label, t_name(tab_label, tab_label))}</li>"
375
+ first = false
376
+ end
377
+ html << '</ul>'
378
+ html << tab_data
379
+ end
380
+ # add last_updated_at hidden field so controller can check if record was updated in db during editing
381
+ html << hidden_field(nil, :last_updated_at, value: @record.updated_at.to_i) if @record.respond_to?(:updated_at)
382
+ # add form time stamp to prevent double form submit
383
+ html << hidden_field(nil, :form_time_stamp, value: Time.now.to_i)
384
+ # add javascript code if defined by form
385
+ @js << "\n#{@form['script']}"
386
+ @css << "\n#{@form['css']}"
387
+ html.html_safe
388
+ end
389
+
390
+ ############################################################################
391
+ # Creates head form div. Head form div is used to display header data usefull
392
+ # to be seen even when tabs are switched.
393
+ ############################################################################
394
+ def dc_head_for_form()
395
+ @css ||= ''
396
+ head = @form['form']['head']
397
+ return '' if head.nil?
398
+ html = %Q[<div class="dc-head #{head['class']}">\n<div class="dc-row">]
399
+ split = head['split'] || 4
400
+ percent = 100/split
401
+ current = 0
402
+ head_fields = head.select {|field| field.class == Integer }
403
+ head_fields.to_a.sort.each do |number, options|
404
+ session[:form_processing] = "form: head: #{number}=#{options}"
405
+ # Label
406
+ caption = options['caption']
407
+ span = options['span'] || 1
408
+ @css << "\n#{options['css']}" unless options['css'].blank?
409
+ label = if caption.blank?
410
+ ''
411
+ elsif options['name'] == caption
412
+ t_name(options['name'], options['name'].capitalize.gsub('_',' ') )
413
+ else
414
+ t(caption, caption)
415
+ end
416
+ # Field value
417
+ begin
418
+ field = if options['eval']
419
+ dc_process_column_eval(options, @record)
420
+ else
421
+ @record.send(options['name'])
422
+ end
423
+ rescue Exception => e
424
+ dc_log_exception(e)
425
+ field = '!!!Error'
426
+ end
427
+ #
428
+ klass = dc_style_or_class(nil, options['class'], field, @record)
429
+ style = dc_style_or_class(nil, options['style'], field, @record)
430
+ html << %Q[<div class="dc-column #{klass}" style="width:#{percent*span}%;#{style}">
431
+ #{label.blank? ? '' : "<span class=\"label\">#{label}</span>"}
432
+ <span class="field">#{field}</span>
433
+ </div>]
434
+ current += span
435
+ if current == split
436
+ html << %Q[</div>\n<div class="dc-row">]
437
+ current = 0
438
+ end
439
+ end
440
+ html << '</div></div>'
441
+ html.html_safe
442
+ end
443
+
444
+ ############################################################################
445
+ # Returns username for id. Subroutine of dc_document_statistics
446
+ ###########################################################################
447
+ def dc_document_user_for(field_name) #:nodoc:
448
+ if @record[field_name]
449
+ u = DcUser.find(@record[field_name])
450
+ return u ? u.name : @record[field_name]
451
+ end
452
+ # nil
453
+ end
454
+
455
+ ############################################################################
456
+ # Creates current document statistics div (created_by, created_at, ....) at the bottom of edit form.
457
+ # + lots of more. At the moment also adds icon for dumping current document as json text.
458
+ ############################################################################
459
+ def dc_document_statistics
460
+ return '' if @record.new_record? or dc_dont?(@form['form']['info'])
461
+ html = %Q[<div id="dc-document-info">#{fa_icon('info-circle lg')}</div> <div id="dc-document-info-popup" class="div-hidden"> ]
462
+ #
463
+ u = dc_document_user_for('created_by')
464
+ html << %Q[<div><span>#{t('drgcms.created_by', 'Created by')}: </span><span>#{u}</span></div>] if u
465
+ u = dc_document_user_for('updated_by')
466
+ html << %Q[<div><span>#{t('drgcms.updated_by', 'Updated by')}: </span><span>#{u}</span></div>] if u
467
+ html << %Q[<div><span>#{t('drgcms.created_at', 'Created at')}: </span><span>#{dc_format_value(@record.created_at)}</span></div>] if @record['created_at']
468
+ html << %Q[<div><span>#{t('drgcms.updated_at', 'Updated at')}: </span><span>#{dc_format_value(@record.updated_at)}</span></div>] if @record['updated_at']
469
+ # copy to clipboard icon
470
+ parms = params.clone
471
+ parms[:controller] = 'dc_common'
472
+ parms[:action] = 'copy_clipboard'
473
+ url = url_for(parms.permit!)
474
+ html << fa_icon('copy 2x', class: 'dc-link-img dc-link-ajax dc-animate',
475
+ 'data-url' => url, 'data-request' => 'get', title: t('drgcms.doc_copy_clipboard') )
476
+ (html << '</div></div>').html_safe
477
+ end
478
+
479
+ private
480
+
481
+ ############################################################################
482
+ # Creates top or bottom horizontal line on form.
483
+ #
484
+ # @param [String] location (top or bottom)
485
+ # @param [Object] options yaml field definition
486
+ #
487
+ # @return [String] html code for drawing a line
488
+ ############################################################################
489
+ def dc_top_bottom_line(location, options)
490
+ if options["#{location}-line"] || options['line'].to_s == location.to_s
491
+ '<div class="dc-separator"></div>'
492
+ else
493
+ ''
494
+ end
495
+ end
496
+
497
+
498
+ end