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