drg_cms 0.6.0.1 → 0.6.1.1.1

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 (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,268 @@
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 common methods used for DRGCMS forms.
27
+ #
28
+ ###########################################################################
29
+ module CmsHelper
30
+ # javascript part created by form helpers
31
+ attr_reader :js
32
+
33
+ ############################################################################
34
+ # Creates code for script action type.
35
+ ############################################################################
36
+ def dc_script_action(yaml)
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>]
42
+ end
43
+
44
+ ############################################################################
45
+ # Will return field form definition if field is defined on form.
46
+ # Field definition will be used for input field on the form.
47
+ ############################################################################
48
+ def dc_get_field_form_definition(name) #:nodoc:
49
+ return 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
62
+ end
63
+
64
+ ############################################################################
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: Array[3]
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
+ label, help = dc_label_help(options)
77
+ # create field object from type and call its render method
78
+ if options['type'].present?
79
+ klass_string = options['type'].camelize
80
+ field_html = if DrgcmsFormFields.const_defined?(klass_string) # when field type defined
81
+ klass = DrgcmsFormFields.const_get(klass_string)
82
+ field = klass.new(self, @record, options).render
83
+ @js << field.js
84
+ @css << field.css
85
+ field.html
86
+ else
87
+ "Error: Field type #{options['type']} not defined!"
88
+ end
89
+ else
90
+ "Error: Field type missing!"
91
+ end
92
+ [field_html, label, help]
93
+ end
94
+
95
+ ############################################################################
96
+ # Return label and help text for a field defined on Form.
97
+ #
98
+ # Parameters:
99
+ # options : Hash : Field definition
100
+ #
101
+ # Returns:
102
+ # label : String : Label text
103
+ # help : String : Help text
104
+ ############################################################################
105
+ def dc_label_help(options)
106
+ # no label or help in comments
107
+ return [nil, nil] if %w(comment action).include?(options['type'])
108
+
109
+ label = options['caption'] || options['text'] || options['label']
110
+ label = if label.blank?
111
+ t_name(options['name'], options['name'].capitalize.gsub('_',' ') )
112
+ elsif options['name']
113
+ t(label, label)
114
+ end
115
+ # help text can be defined in form or in translations starting with helpers. or as helpers.help.collection.field
116
+ help = options['help']
117
+ help ||= "helpers.help.#{@form['table']}.#{options['name']}" if options['name']
118
+ help = t(help, ' ') if help.to_s.match(/helpers\./)
119
+ [label, help]
120
+ end
121
+
122
+ ############################################################################
123
+ # Return label and help for tab on Form.
124
+ #
125
+ # Parameters:
126
+ # options : String : Tab name on form
127
+ #
128
+ # Returns:
129
+ # label : String : Label text
130
+ # help : String : Help text
131
+ ############################################################################
132
+ def dc_tab_label_help(tab_name)
133
+ label = @form['form']['tabs'][tab_name]['caption'] || tab_name
134
+ label = t(label, t_name(label, label))
135
+
136
+ help = @form['form']['tabs'][tab_name]['help'] || "helpers.help.#{@form['table']}.#{tab_name}"
137
+ help = t(help, t_name(help, help))
138
+ help = nil if help.match('helpers.') # help not found in translation
139
+
140
+ [label, help]
141
+ end
142
+
143
+ ############################################################################
144
+ # Creates code for including data entry field in index actions.
145
+ ############################################################################
146
+ def dc_field_action(yaml)
147
+ # assign value if value found in parameters
148
+ if params['record']
149
+ value = params['record'][yaml['name']]
150
+ params["p_#{yaml['name']}"] = value
151
+ end
152
+ # find field definition on form
153
+ if ( field_definition = dc_get_field_form_definition(yaml['name']) )
154
+ # some options may be redefined
155
+ field_definition['size'] = yaml['size'] if yaml['size']
156
+ field, label, help = dc_field_label_help(field_definition)
157
+ else
158
+ yaml['type'] = yaml['field_type']
159
+ field, label, help = dc_field_label_help(yaml)
160
+ end
161
+ # input field will have label as placeholder
162
+ field = field.sub('input',"input placeholder=\"#{label}\"")
163
+ %Q[<li class="no-background">#{field}</li>]
164
+ end
165
+
166
+ ############################################################################
167
+ # Create ex. class="my-class" html code from html options for action
168
+ ############################################################################
169
+ def dc_html_data(yaml)
170
+ return '' if yaml.blank?
171
+ yaml.inject(' ') {|result, e| result = e.last.nil? ? result : result << "#{e.first}=\"#{e.last}\" "}
172
+ end
173
+
174
+ ############################################################################
175
+ # Creates code for link, ajax or windows action for index or form actions.
176
+ #
177
+ # Parameters:
178
+ # yaml: Hash : Action definition
179
+ # record : Object : Currently selected record if available
180
+ # action_active : Boolean : Is action active or disabled
181
+ #
182
+ # Returns:
183
+ # String : HTML code for action
184
+ ############################################################################
185
+ def dc_link_ajax_window_submit_action(yaml, record=nil, action_active=true)
186
+ parms = {}
187
+ caption = yaml['caption'] || yaml['text']
188
+ caption = caption ? t("#{caption.downcase}", caption) : nil
189
+ icon = yaml['icon'] ? "#{fa_icon(yaml['icon'])}" : ''
190
+ # action is not active
191
+ unless dc_is_action_active?(yaml)
192
+ return "<li class=\"dc-link-no\">#{icon} #{caption}</li>"
193
+ end
194
+ # set data-confirm when confirm
195
+ yaml['html'] ||= {}
196
+ confirm = yaml['html']['data-confirm'] || yaml['confirm']
197
+ yaml['html']['data-confirm'] = t(confirm) if confirm.present?
198
+ yaml['html']['title'] ||= yaml['title']
199
+ yaml['html']['title'] = t(yaml['title']) if yaml['title'].present?
200
+ yaml['html']['target'] ||= yaml['target']
201
+ # direct url
202
+ if yaml['url']
203
+ parms['url'] = yaml['url']
204
+ parms['idr'] = dc_document_path(record) if record
205
+ # make url from action controller
206
+ else
207
+ parms['controller'] = yaml['controller'] || 'cmsedit'
208
+ parms['action'] = yaml['action']
209
+ parms['table'] = yaml['table'] || @form['table']
210
+ parms['form_name'] = yaml['form_name']
211
+ parms['control'] = yaml['control'] if yaml['control']
212
+ parms['id'] = record.id if record
213
+ end
214
+ # add current id to parameters
215
+ parms['id'] = dc_document_path(record) if record
216
+ # overwrite with or add additional parameters from environment or record
217
+ yaml['params'].each { |k, v| parms[k] = dc_value_for_parameter(v, record) } if yaml['params']
218
+
219
+ parms['table'] = parms['table'].underscore if parms['table'] # might be CamelCase
220
+ # error if controller parameter is missing
221
+ if parms['controller'].nil? && parms['url'].nil?
222
+ "<li>#{'Controller not defined'}</li>"
223
+ else
224
+ #yaml['caption'] ||= yaml['text']
225
+ html_data = dc_html_data(yaml['html'])
226
+ url = url_for(parms) rescue 'URL error'
227
+ url = nil if parms['url'] == '#'
228
+
229
+ request = yaml['request'] || yaml['method'] || 'get'
230
+ if yaml['type'] == 'ajax' # ajax button
231
+ clas = "dc-link-ajax dc-animate"
232
+ %Q[<li class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}
233
+ data-request="#{request}" title="#{yaml['title']}">#{icon}#{caption}</li>]
234
+
235
+ elsif yaml['type'] == 'submit' # submit button
236
+ # It's dirty hack, but will prevent not authorized message and render index action correctly
237
+ parms[:filter] = 'on'
238
+ url = url_for(parms) rescue 'URL error'
239
+ clas = "dc-action-submit"
240
+ %Q[<li class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}
241
+ data-request="#{request}" title="#{yaml['title']}">#{icon}#{caption}</li>]
242
+
243
+ elsif yaml['type'] == 'link' # link button
244
+ clas = "dc-link dc-animate"
245
+ link = dc_link_to(caption, yaml['icon'], parms, yaml['html'] )
246
+ %Q[<li class="#{clas}">#{action_active ? link : caption}</li>]
247
+
248
+ elsif yaml['type'] == 'window'
249
+ clas = "dc-link dc-animate dc-window-open"
250
+ %Q[<li class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}>#{icon}#{caption}</li>]
251
+
252
+ else
253
+ '<li>Action Type error</li>'
254
+ end
255
+ end
256
+ end
257
+
258
+ ############################################################################
259
+ # Log exception to rails log. Usefull for debugging eval errors.
260
+ ############################################################################
261
+ def dc_log_exception(exception, where = '')
262
+ log = exception ? "\n*** Error:#{where + ':'} #{exception.message}\n#{exception.backtrace.first.inspect}\n" : ''
263
+ log << "DRG Form processing line: #{session[:form_processing]}\n"
264
+
265
+ logger.error log
266
+ end
267
+
268
+ end
@@ -0,0 +1,580 @@
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 CmsIndexHelper
31
+
32
+ ############################################################################
33
+ # Creates action div for cmsedit index action.
34
+ ############################################################################
35
+ def dc_actions_for_index()
36
+ @js = @form['script'] || @form['js'] || ''
37
+ @css = @form['css'] || ''
38
+ return '' if @form['index'].nil? or @form['readonly']
39
+ actions = @form['index']['actions']
40
+ return '' if actions.blank?
41
+
42
+ std_actions = {2 => 'new', 3 => 'sort', 4 => 'filter' }
43
+ if actions.class == String
44
+ actions = dc_define_standard_actions(actions, std_actions)
45
+ elsif actions['standard']
46
+ actions.merge!(std_actions)
47
+ actions['standard'] = nil
48
+ end
49
+
50
+ # start div with hidden spinner image
51
+ html = %(
52
+ <form id="dc-action-menu">
53
+ <span class="dc-spinner">#{fa_icon('spinner lg spin')}</span>
54
+ <ul class="dc-action-menu">)
55
+
56
+ # Remove actions settings and sort
57
+ only_actions = []
58
+ actions.each { |key, value| only_actions << [key, value] if key.class == Integer }
59
+ only_actions.sort_by!(&:first)
60
+ only_actions.each do |key, options|
61
+ session[:form_processing] = "index:actions: #{key}=#{options}"
62
+ next if options.nil? # must be
63
+ url = @parms.clone
64
+ yaml = options.class == String ? {'type' => options} : options # if single definition simulate type parameter
65
+ action = yaml['type'].to_s.downcase
66
+ if action == 'url'
67
+ dc_deprecate "action: url will be deprecated. Use action: link in index: actions! Form #{params['form_name']}"
68
+ action = 'link'
69
+ end
70
+ # if return_to is present link directly to URL
71
+ if action == 'link' and yaml['url']
72
+ url = yaml['url']
73
+ else
74
+ url['controller'] = yaml['controller'] if yaml['controller']
75
+ url['action'] = yaml['action'] || action
76
+ url['table'] = yaml['table'] if yaml['table']
77
+ url['form_name'] = yaml['form_name'] if yaml['form_name']
78
+ url['control'] = yaml['control'] if yaml['control']
79
+ end
80
+ # html link options
81
+ yhtml = yaml['html'] || {}
82
+ yhtml['title'] = yaml['title'] if yaml['title']
83
+
84
+ code = case
85
+ # sort
86
+ when action == 'sort' then
87
+ choices = [['id','id']]
88
+ if @form['index']['sort']
89
+ @form['index']['sort'].split(',').each do |s|
90
+ s.strip!
91
+ choices << [ t("helpers.label.#{@form['table']}.#{s}"), s ]
92
+ end
93
+ end
94
+ fa_icon('sort-alpha-asc') + ' ' + t('drgcms.sort') + ' ' +
95
+ select('sort', 'sort', choices, { include_blank: true },
96
+ { class: 'drgcms_sort', 'data-table' => @form['table'], 'data-form' => params['form_name']} )
97
+
98
+ # filter
99
+ when action == 'filter' then
100
+ caption = t('drgcms.filter')
101
+ caption << '&nbsp;' + fa_icon('caret-down lg') + DcFilter.menu_filter(self)
102
+ # add filter OFF link
103
+ sess = session[@form['table']]
104
+ if sess and sess[:filter]
105
+ caption << '&nbsp;&nbsp;' + dc_link_to(nil,'remove lg',
106
+ { controller: 'cmsedit', filter: 'off', table: @form['table'], form_name: params['form_name'] },
107
+ { title: DcFilter.title4_filter_off(sess[:filter]) })
108
+ end
109
+ caption
110
+
111
+ # new
112
+ when action == 'new' then
113
+ caption = yaml['caption'] || 'drgcms.new'
114
+ dc_link_to(caption,'plus', url, yhtml )
115
+
116
+ # menu
117
+ when action == 'menu' then
118
+ caption = t(options['caption'], options['caption']) + '&nbsp;' + fa_icon('caret-down lg')
119
+ caption + eval(options['eval'])
120
+ =begin
121
+ # reorder
122
+ when action == 'reorder' then
123
+ caption = t('drgcms.reorder')
124
+ parms = @parms.clone
125
+ parms['operation'] = v
126
+ parms['id'] = params[:ids]
127
+ parms['table'] = @form['table']
128
+ dc_link_to( caption, 'reorder', parms, method: :delete )
129
+ =end
130
+ when action == 'script'
131
+ html << dc_script_action(options)
132
+ next
133
+
134
+ when action == 'field'
135
+ html << dc_field_action(yaml)
136
+ next
137
+
138
+ when %w(ajax link window submit).include?(action)
139
+ html << dc_link_ajax_window_submit_action(options, nil)
140
+ next
141
+
142
+ else
143
+ caption = yaml['caption'] || yaml['text']
144
+ icon = yaml['icon'] ? yaml['icon'] : action
145
+ dc_link_to(caption, icon, url, yhtml)
146
+ end
147
+ html << "<li class=\"dc-link dc-animate\">#{code}</li>"
148
+ html << DcFilter.get_filter_field(self) if action == 'filter'
149
+ end
150
+ html << '</ul></form>'
151
+ html.html_safe
152
+ end
153
+
154
+ ############################################################################
155
+ # Creates filter div for cmsedit index/filter action.
156
+ ############################################################################
157
+ def dc_div_filter
158
+ choices = []
159
+ filter = (@form['index'] and @form['index']['filter']) ? @form['index']['filter'] + ',' : ''
160
+ filter << 'id as text_field' # filter id is added by default
161
+ filter.split(',').each do |f|
162
+ f.strip!
163
+ name = f.match(' as ') ? f.split(' ').first : f
164
+ # like another field on the form
165
+ if f.match(' like ')
166
+ a = f.split(' ')
167
+ name = a.first
168
+ f = a.last
169
+ end
170
+ choices << [ t("helpers.label.#{@form['table']}.#{name}", name), f ]
171
+ end
172
+ choices4_operators = t('drgcms.choices4_filter_operators').chomp.split(',').inject([]) {|r,v| r << (v.match(':') ? v.split(':') : v )}
173
+ # currently selected options
174
+ if session[@form['table']] and session[@form['table']][:filter]
175
+ field_name, operators_value, dummy = session[@form['table']][:filter].split("\t")
176
+ else
177
+ field_name, operators_value = nil, nil
178
+ end
179
+ #{ form_tag :table => @form['table'], filter: :on, filter_input: 1, action: :index, method: :post }
180
+ url = url_for(table: @form['table'],form_name: params['form_name'], filter: :on, filter_input: 1, action: :index, controller: :cmsedit)
181
+ html =<<EOT
182
+ <div id="drgcms_filter" class="div-hidden">
183
+ <h1>#{t('drgcms.filter_set')}</h1>
184
+
185
+ #{ select(nil, 'filter_field1', options_for_select(choices, field_name), { include_blank: true }) }
186
+ #{ select(nil, 'filter_oper', options_for_select(choices4_operators, operators_value)) }
187
+ <div class="dc-menu">
188
+ <div class="dc-link dc-animate drgcms_popup_submit" data-url="#{url}">#{fa_icon('check-square-o')} #{t('drgcms.filter_on')}</div>
189
+ <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>
190
+ </div>
191
+ </div>
192
+ EOT
193
+ html.html_safe
194
+ end
195
+
196
+ ############################################################################
197
+ # Creates popup div for setting filter on result set header.
198
+ ############################################################################
199
+ def dc_filter_popup
200
+ html = %Q[<div class="filter-popup" style="display: none;">
201
+ <div>#{t('drgcms.filter_set')}</div>
202
+ <ul>]
203
+ url = url_for(table: @form['table'],form_name: params['form_name'], filter: :on, filter_input: 1, action: :index, controller: :cmsedit)
204
+ t('drgcms.choices4_filter_operators').chomp.split(',').each do |operator_choice|
205
+ caption,choice = operator_choice.split(':')
206
+ html << %Q[<li data-operator="#{choice}" data-url="#{url}">#{caption}</li>]
207
+ end
208
+ html << "</ul></div>"
209
+ html.html_safe
210
+ end
211
+
212
+ ############################################################################
213
+ # Will return title based on @form['title']
214
+ ############################################################################
215
+ def dc_form_title
216
+ return t("helpers.label.#{@form['table']}.tabletitle", @form['table']) if @form['title'].nil?
217
+ return t(@form['title'], @form['title']) if @form['title'].class == String
218
+
219
+ # Hash
220
+ dc_process_eval(@form['title']['eval'], [@form['title']['caption'] || @form['title']['text'], params])
221
+ end
222
+
223
+ ############################################################################
224
+ # Creates title div for index action. Title div also includes paging options
225
+ # and help link
226
+ ############################################################################
227
+ def dc_title_for_index(result = nil)
228
+ dc_table_title(dc_form_title(), result)
229
+ end
230
+
231
+ ############################################################################
232
+ # Determines actions and width of actions column
233
+ ############################################################################
234
+ def dc_actions_column
235
+ actions = @form['result_set']['actions']
236
+ return [{}, 0] if actions.nil? || dc_dont?(actions)
237
+
238
+ # standard actions
239
+ actions = {'standard' => true} if actions.class == String && actions == 'standard'
240
+ std_actions = { 2 => 'edit', 5 => 'delete' }
241
+ if actions['standard']
242
+ actions.merge!(std_actions)
243
+ actions.delete('standard')
244
+ end
245
+
246
+ width = @form['result_set']['actions_width'] || 18*actions.size
247
+ [actions, width]
248
+ end
249
+
250
+ ############################################################################
251
+ # Calculates (blank) space required for actions when @record_footer is rendered
252
+ ############################################################################
253
+ def dc_actions_column_for_footer
254
+ return '' unless @form['result_set']['actions']
255
+
256
+ ignore, width = dc_actions_column
257
+ %Q[<div class="actions" style="width: #{width}px;"></div>].html_safe
258
+ end
259
+
260
+ ############################################################################
261
+ # Creates actions that could be performed on single row of result set.
262
+ ############################################################################
263
+ def dc_actions_for_result(document)
264
+ actions = @form['result_set']['actions']
265
+ return '' if actions.nil? or @form['readonly']
266
+
267
+ actions, width = dc_actions_column()
268
+ html = %Q[<ul class="actions" style="width: #{width}px;">]
269
+ actions.sort_by(&:first).each do |k, v|
270
+ session[:form_processing] = "result_set:actions: #{k}=#{v}"
271
+ parms = @parms.clone
272
+ # if single definition simulate type parameter
273
+ yaml = v.class == String ? { 'type' => v } : v
274
+ # code already includes li tag
275
+ if %w(ajax link window submit).include?(yaml['type'])
276
+ @record = document # otherwise document fields can't be used as parameters
277
+ html << dc_link_ajax_window_submit_action(yaml, document)
278
+ else
279
+ html << '<li class="dc-link">'
280
+ html << case
281
+ when yaml['type'] == 'edit' then
282
+ parms['action'] = 'edit'
283
+ parms['id'] = document.id
284
+ dc_link_to( nil, 'pencil lg', parms )
285
+ when yaml['type'] == 'duplicate' then
286
+ parms['id'] = document.id
287
+ # duplicate string will be added to these fields.
288
+ parms['dup_fields'] = yaml['dup_fields']
289
+ parms['action'] = 'create'
290
+ dc_link_to( nil, 'copy lg', parms, data: { confirm: t('drgcms.confirm_dup') }, method: :post )
291
+ when yaml['type'] == 'delete' then
292
+ parms['action'] = 'destroy'
293
+ parms['id'] = document.id
294
+ #parms['return_to'] = request.url
295
+ dc_link_to( nil, 'remove lg', parms, data: { confirm: t('drgcms.confirm_delete') }, method: :delete )
296
+ # undocumented so far
297
+ when yaml['type'] == 'edit_embedded'
298
+ parms['controller'] = 'cmsedit'
299
+ parms['table'] += ";#{yaml['table']}"
300
+ parms['ids'] ||= ''
301
+ parms['ids'] += "#{document.id};"
302
+ dc_link_to( nil, 'table lg', parms, method: :get )
303
+
304
+ else # error.
305
+ yaml['type'].to_s
306
+ end
307
+ html << '</li>'
308
+ end
309
+ end
310
+ html << '</ul>'
311
+ html.html_safe
312
+ end
313
+
314
+ ############################################################################
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, width = dc_actions_column()
321
+ html << %Q[<div class="actions" style="width:#{width}px;"></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.sort.each do |k, v|
331
+ session[:form_processing] = "result_set:columns: #{k}=#{v}"
332
+ next if v['width'].to_s.match(/hidden|none/i)
333
+
334
+ th = %Q[<div class="th" style="width:#{v['width'] || '15%'};text-align:#{v['align'] || 'left'};" data-name="#{v['name']}"]
335
+ label = v['caption'] || v['label']
336
+ label = (v['name'] ? "helpers.label.#{@form['table']}.#{v['name']}" : '') if label.nil?
337
+ label = t(label) if label.match(/\./)
338
+ # no sorting when embedded documents or custom filter is active
339
+ sort_ok = @form['result_set'].nil? || (@form['result_set'] && @form['result_set']['filter'].nil?)
340
+ sort_ok = sort_ok || (@form['index'] && @form['index']['sort'])
341
+ sort_ok = sort_ok && !dc_dont?(v['sort'], false)
342
+ if @tables.size == 1 and sort_ok
343
+ icon = 'sort lg'
344
+ if v['name'] == sort_field
345
+ icon = sort_direction == '1' ? 'sort-alpha-asc lg' : 'sort-alpha-desc lg'
346
+ end
347
+ th << ">#{dc_link_to(label, icon, sort: v['name'], table: params[:table], form_name: params[:form_name], action: :index, icon_pos: :last )}</div>"
348
+ else
349
+ th << ">#{label}</div>"
350
+ end
351
+ html << "<div class=\"spacer\"></div>" + th
352
+ end
353
+ end
354
+ (html << '</div>').html_safe
355
+ end
356
+
357
+ ############################################################################
358
+ # Creates link for single or double click on result column
359
+ ############################################################################
360
+ def dc_clicks_for_result(document)
361
+ html = ''
362
+ if @form['result_set']['dblclick']
363
+ yaml = @form['result_set']['dblclick']
364
+ opts = {}
365
+ opts[:controller] = yaml['controller'] || 'cmsedit'
366
+ opts[:action] = yaml['action']
367
+ opts[:table] = yaml['table']
368
+ opts[:form_name] = yaml['form_name']
369
+ opts[:method] = yaml['method'] || 'get'
370
+ opts[:id] = document['id']
371
+ opts[:readonly] = yaml['readonly'] if yaml['readonly']
372
+ opts[:window_close] = yaml['window_close'] if yaml['window_close']
373
+ html << ' data-dblclick=' + url_for(opts)
374
+ else
375
+ html << (' data-dblclick=' +
376
+ url_for(action: 'show', controller: 'cmsedit', id: document.id, ids: params[:ids],
377
+ readonly: (params[:readonly] ? 2 : 1), table: params[:table],
378
+ form_name: params[:form_name]) ) if @form['form']
379
+ end
380
+ html
381
+ end
382
+
383
+ ############################################################################
384
+ # Formats value according to format supplied or data type. There is lots of things missing here.
385
+ ############################################################################
386
+ def dc_format_value(value, format=nil)
387
+ return '' if value.nil?
388
+
389
+ klass = value.class.to_s
390
+ if klass.match(/time|date/i)
391
+ CmsCommonHelper.dc_format_date_time(value, format)
392
+ elsif format.to_s[0] == 'N'
393
+ return '' if value == 0 and format.match('z')
394
+
395
+ dec = format[1].blank? ? nil : format[1].to_i
396
+ sep = format[2].blank? ? nil : format[2]
397
+ del = format[3].blank? ? nil : format[3]
398
+ cur = format[4].blank? ? nil : format[4]
399
+ dc_format_number(value, dec, sep, del, cur)
400
+ else
401
+ value.to_s
402
+ end
403
+ end
404
+
405
+ ############################################################################
406
+ # Creates tr code for each row of result set.
407
+ ############################################################################
408
+ def dc_row_for_result(document)
409
+ clas = "dc-#{cycle('odd','even')} " + dc_style_or_class(nil, @form['result_set']['tr_class'], nil, document)
410
+ style = dc_style_or_class('style', @form['result_set']['tr_style'], nil, document)
411
+ "<div id=\"#{document.id}\" class=\"dc-result-data #{clas}\" #{dc_clicks_for_result(document)} #{style}>".html_safe
412
+ end
413
+
414
+ ############################################################################
415
+ # Creates column for each field of result set document.
416
+ ############################################################################
417
+ def dc_columns_for_result(document)
418
+ return '' unless @form['result_set']['columns']
419
+ html = ''
420
+ @form['result_set']['columns'].sort.each do |k,v|
421
+ session[:form_processing] = "result_set:columns: #{k}=#{v}"
422
+ next if v['width'].to_s.match(/hidden|none/i)
423
+
424
+ # convert shortcut to hash
425
+ v = {'name' => v} if v.class == String
426
+ begin
427
+ # eval
428
+ value = if v['eval']
429
+ dc_process_column_eval(v, document)
430
+ # as field
431
+ elsif document.respond_to?(v['name'])
432
+ dc_format_value(document.send( v['name'] ), v['format'])
433
+ # as hash (dc_memory)
434
+ elsif document.class == Hash
435
+ dc_format_value(document[ v['name'] ], v['format'])
436
+ # error
437
+ else
438
+ "??? #{v['name']}"
439
+ end
440
+ rescue Exception => e
441
+ dc_log_exception(e, 'dc_columns_for_result')
442
+ value = '!!!Error'
443
+ end
444
+ html << '<div class="spacer"></div>'
445
+ # set class
446
+ clas = dc_style_or_class(nil, v['td_class'], value, document)
447
+ # set width and align an additional style
448
+ style = dc_style_or_class(nil, v['td_style'] || v['style'], value, document)
449
+ flex_align = v['align'].to_s == 'right' ? 'flex-direction:row-reverse;' : ''
450
+ width_align = %Q[width:#{v['width'] || '15%'};#{flex_align}]
451
+ style = "style=\"#{width_align}#{style}\" "
452
+
453
+ html << "<div class=\"td #{clas}\" #{style}>#{value}</div>"
454
+ end
455
+ html.html_safe
456
+ end
457
+
458
+ private
459
+
460
+ ############################################################################
461
+ # Process eval. Breaks eval option and calls with send method.
462
+ # Parameters:
463
+ # evaluate : String : Expression to be evaluated
464
+ # parameters : Array : array of parameters which will be send to method
465
+ ############################################################################
466
+ def dc_process_eval(evaluate, parameters)
467
+ # evaluate by calling send method
468
+ clas, method = evaluate.split('.')
469
+ if method.nil?
470
+ send(clas, *parameters)
471
+ else
472
+ klass = clas.camelize.constantize
473
+ klass.send(method, *parameters)
474
+ end
475
+ end
476
+
477
+ ############################################################################
478
+ # Split eval expression to array by parameters.
479
+ # Will split dc_name4_value(one ,"two") => ['dc_name4_value', 'one', 'two']
480
+ ############################################################################
481
+ def dc_eval_to_array(expression)
482
+ expression.split(/\ |\,|\(|\)/).delete_if {|e| e.blank? }.map {|e| e.gsub(/\'|\"/,'').strip }
483
+ end
484
+
485
+ ############################################################################
486
+ # Process eval option for field value.
487
+ # Used for processing single field column on result_set or form head.
488
+ ############################################################################
489
+ def dc_process_column_eval(yaml, document)
490
+ # dc_name_for_id
491
+ if yaml['eval'].match(/dc_name4_id|dc_name_for_id/)
492
+ parms = dc_eval_to_array(yaml['eval'])
493
+ if parms.size == 3
494
+ dc_name_for_id(parms[1], parms[2], nil, document[ yaml['name'] ])
495
+ else
496
+ dc_name_for_id(parms[1], parms[2], parms[3], document[ yaml['name'] ])
497
+ end
498
+
499
+ # dc_name_for_value from locale definition
500
+ elsif yaml['eval'].match(/dc_name4_value|dc_name_for_value/)
501
+ parms = dc_eval_to_array(yaml['eval'])
502
+ if parms.size == 1
503
+ dc_name_for_value( @form['table'], yaml['name'], document[ yaml['name'] ] )
504
+ else
505
+ dc_name_for_value( parms[1], parms[2], document[ yaml['name'] ] )
506
+ end
507
+
508
+ # defined in helpers. For example dc_icon_for_boolean
509
+ elsif respond_to?(yaml['eval'])
510
+ send(yaml['eval'], document[yaml['name']])
511
+
512
+ # defined in model
513
+ elsif document.respond_to?(yaml['eval'])
514
+ document.send(yaml['eval'])
515
+
516
+ # special eval
517
+ elsif yaml['eval'].match('eval ')
518
+ # TO DO evaluate with specified parameters
519
+
520
+ # eval with params
521
+ else
522
+ parms = {}
523
+ if yaml['params'].class == String
524
+ parms = dc_value_for_parameter(yaml['params'], document)
525
+ elsif yaml['params'].class == Hash
526
+ yaml['params'].each { |k, v| parms[k] = dc_value_for_parameter(v) }
527
+ else
528
+ parms = document[ yaml['name'] ]
529
+ end
530
+ dc_process_eval(yaml['eval'], parms)
531
+ end
532
+ end
533
+
534
+ ############################################################################
535
+ # Defines style or class for row (tr) or column (td)
536
+ ############################################################################
537
+ def dc_style_or_class(selector, yaml, value, record)
538
+ return '' if yaml.nil?
539
+
540
+ # alias record and value so both names can be used in eval
541
+ field, document = value, record
542
+ html = selector ? "#{selector}=\"" : ''
543
+ begin
544
+ html << if yaml.class == String
545
+ yaml
546
+ # direct evaluate expression
547
+ elsif yaml['eval']
548
+ eval(yaml['eval'])
549
+ elsif yaml['method']
550
+ dc_process_eval(yaml['method'], record)
551
+ end
552
+ rescue Exception => e
553
+ dc_log_exception(e, 'dc_style_or_class')
554
+ end
555
+ html << '"' if selector
556
+ html
557
+ end
558
+
559
+ ############################################################################
560
+ # Get standard actions when actions directive contains single line.
561
+ # Subroutine of dc_actions_for_index
562
+ #
563
+ # Allows for actions: new, filter, standard syntax
564
+ ############################################################################
565
+ def dc_define_standard_actions(actions_params, standard)
566
+ actions = {}
567
+ actions_params.split(',').each do |an_action|
568
+ an_action.strip!
569
+ if an_action == 'standard'
570
+ actions.merge!(standard)
571
+ else
572
+ standard.each do |index, action|
573
+ (actions[index] = action; break) if action == an_action
574
+ end
575
+ end
576
+ end
577
+ actions
578
+ end
579
+
580
+ end