agile_rails 0.0.0.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 (259) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +285 -0
  5. data/Rakefile +39 -0
  6. data/agile_rails.gemspec +36 -0
  7. data/app/assets/fonts/ibm-plex-sans-300.woff2 +0 -0
  8. data/app/assets/fonts/ibm-plex-sans-400.woff2 +0 -0
  9. data/app/assets/fonts/ibm-plex-sans-500.woff2 +0 -0
  10. data/app/assets/fonts/ibm-plex-sans-600.woff2 +0 -0
  11. data/app/assets/fonts/ibm-plex-sans-700.woff2 +0 -0
  12. data/app/assets/fonts/ibm-plex-sans-italic.woff2 +0 -0
  13. data/app/assets/images/32px.png +0 -0
  14. data/app/assets/images/throbber.gif +0 -0
  15. data/app/assets/javascripts/agile/agile.js +1489 -0
  16. data/app/assets/javascripts/agile/jquery-migrate.js +702 -0
  17. data/app/assets/javascripts/agile/jquery.bpopup.js +372 -0
  18. data/app/assets/javascripts/agile/jquery.datetimepicker.js +1353 -0
  19. data/app/assets/javascripts/agile/jstree.min.js +6 -0
  20. data/app/assets/javascripts/agile/select-multiple.js +459 -0
  21. data/app/assets/javascripts/agile/some_scripts.js +33 -0
  22. data/app/assets/javascripts/agile.js +22 -0
  23. data/app/assets/javascripts/agile_application.js +22 -0
  24. data/app/assets/javascripts/agile_editor.js +22 -0
  25. data/app/assets/stylesheets/agile/agile.css +1882 -0
  26. data/app/assets/stylesheets/agile/agile_apps.css +149 -0
  27. data/app/assets/stylesheets/agile/jquery.datetimepicker.css +304 -0
  28. data/app/assets/stylesheets/agile/jstree.css +1107 -0
  29. data/app/assets/stylesheets/agile/select-multiple.css +110 -0
  30. data/app/assets/stylesheets/agile/th-bg.png +0 -0
  31. data/app/assets/stylesheets/agile/theme.css +49 -0
  32. data/app/assets/stylesheets/agile.css +21 -0
  33. data/app/assets/stylesheets/agile_application.css +20 -0
  34. data/app/assets/stylesheets/agile_editor.css +19 -0
  35. data/app/controllers/agile_application_controller.rb +735 -0
  36. data/app/controllers/agile_common_controller.rb +345 -0
  37. data/app/controllers/agile_controller.rb +977 -0
  38. data/app/controllers/agile_main_controller.rb +36 -0
  39. data/app/controls/agile_control.rb +120 -0
  40. data/app/controls/agile_report.rb +364 -0
  41. data/app/controls/ar_category_control.rb +39 -0
  42. data/app/controls/ar_help_control.rb +139 -0
  43. data/app/controls/ar_image_control.rb +180 -0
  44. data/app/controls/ar_journal_control.rb +47 -0
  45. data/app/controls/ar_menu_item_control.rb +55 -0
  46. data/app/controls/ar_page_control.rb +64 -0
  47. data/app/controls/ar_poll_result_control.rb +84 -0
  48. data/app/controls/ar_setup_control.rb +62 -0
  49. data/app/controls/belongs_to_control.rb +61 -0
  50. data/app/controls/browse_models_control.rb +98 -0
  51. data/app/controls/settings_form_control.rb +137 -0
  52. data/app/forms/agile_help.yml +112 -0
  53. data/app/forms/agile_menu.yml +140 -0
  54. data/app/forms/agile_report_defaults.yml +39 -0
  55. data/app/forms/all_options.yml +810 -0
  56. data/app/forms/ar_ad.yml +121 -0
  57. data/app/forms/ar_big_table.yml +60 -0
  58. data/app/forms/ar_big_table_value.yml +52 -0
  59. data/app/forms/ar_browse_fields.yml +35 -0
  60. data/app/forms/ar_browse_models.yml +48 -0
  61. data/app/forms/ar_category.yml +73 -0
  62. data/app/forms/ar_category_as_tree.yml +31 -0
  63. data/app/forms/ar_design.yml +75 -0
  64. data/app/forms/ar_filter.yml +52 -0
  65. data/app/forms/ar_folder_permission.yml +56 -0
  66. data/app/forms/ar_folder_rule.yml +48 -0
  67. data/app/forms/ar_gallery.yml +55 -0
  68. data/app/forms/ar_image.yml +126 -0
  69. data/app/forms/ar_image_search.yml +83 -0
  70. data/app/forms/ar_journal.yml +76 -0
  71. data/app/forms/ar_json_ld.yml +56 -0
  72. data/app/forms/ar_key_value.yml +33 -0
  73. data/app/forms/ar_key_value_store.yml +33 -0
  74. data/app/forms/ar_link.yml +60 -0
  75. data/app/forms/ar_menu.yml +67 -0
  76. data/app/forms/ar_menu_item.yml +141 -0
  77. data/app/forms/ar_page.yml +187 -0
  78. data/app/forms/ar_part.yml +91 -0
  79. data/app/forms/ar_permission.yml +52 -0
  80. data/app/forms/ar_permission_rule.yml +40 -0
  81. data/app/forms/ar_piece.yml +106 -0
  82. data/app/forms/ar_policy.yml +64 -0
  83. data/app/forms/ar_policy_rule.yml +42 -0
  84. data/app/forms/ar_policy_rule_nocms.yml +40 -0
  85. data/app/forms/ar_poll.yml +118 -0
  86. data/app/forms/ar_poll_item.yml +78 -0
  87. data/app/forms/ar_poll_result.yml +88 -0
  88. data/app/forms/ar_poll_result_export.yml +35 -0
  89. data/app/forms/ar_removed_url.yml +41 -0
  90. data/app/forms/ar_role.yml +43 -0
  91. data/app/forms/ar_seo.yml +32 -0
  92. data/app/forms/ar_setup.yml +45 -0
  93. data/app/forms/ar_site.yml +149 -0
  94. data/app/forms/ar_steps_template.yml +51 -0
  95. data/app/forms/ar_user.yml +140 -0
  96. data/app/forms/ar_user_role.yml +57 -0
  97. data/app/forms/help/dc_category_as_tree.en +4 -0
  98. data/app/forms/help/dc_category_as_tree.sl +5 -0
  99. data/app/forms/json_ld_schema.yml +168 -0
  100. data/app/helpers/agile_application_helper.rb +1162 -0
  101. data/app/helpers/agile_category_helper.rb +128 -0
  102. data/app/helpers/agile_common_helper.rb +308 -0
  103. data/app/helpers/agile_edit_helper.rb +645 -0
  104. data/app/helpers/agile_helper.rb +509 -0
  105. data/app/helpers/agile_index_helper.rb +677 -0
  106. data/app/helpers/ar_image_helper.rb +128 -0
  107. data/app/models/agile_form_fields/action.rb +61 -0
  108. data/app/models/agile_form_fields/agile_form_field.rb +322 -0
  109. data/app/models/agile_form_fields/belongs_to.rb +112 -0
  110. data/app/models/agile_form_fields/check_box.rb +73 -0
  111. data/app/models/agile_form_fields/comment.rb +62 -0
  112. data/app/models/agile_form_fields/date_picker.rb +104 -0
  113. data/app/models/agile_form_fields/date_select.rb +68 -0
  114. data/app/models/agile_form_fields/datetime_picker.rb +88 -0
  115. data/app/models/agile_form_fields/datetime_select.rb +73 -0
  116. data/app/models/agile_form_fields/file_field.rb +52 -0
  117. data/app/models/agile_form_fields/file_select.rb +69 -0
  118. data/app/models/agile_form_fields/hidden_field.rb +51 -0
  119. data/app/models/agile_form_fields/html_field.rb +69 -0
  120. data/app/models/agile_form_fields/journal_diff.rb +62 -0
  121. data/app/models/agile_form_fields/link_to.rb +69 -0
  122. data/app/models/agile_form_fields/method.rb +66 -0
  123. data/app/models/agile_form_fields/multitext_autocomplete.rb +215 -0
  124. data/app/models/agile_form_fields/number_field.rb +92 -0
  125. data/app/models/agile_form_fields/password_field.rb +63 -0
  126. data/app/models/agile_form_fields/radio_button.rb +95 -0
  127. data/app/models/agile_form_fields/readonly.rb +77 -0
  128. data/app/models/agile_form_fields/select.rb +281 -0
  129. data/app/models/agile_form_fields/submit_tag.rb +58 -0
  130. data/app/models/agile_form_fields/text_area.rb +61 -0
  131. data/app/models/agile_form_fields/text_autocomplete.rb +171 -0
  132. data/app/models/agile_form_fields/text_field.rb +55 -0
  133. data/app/models/agile_form_fields/text_with_select.rb +94 -0
  134. data/app/models/agile_form_fields/tree_select.rb +170 -0
  135. data/app/models/ar_big_table.rb +82 -0
  136. data/app/models/ar_big_table_value.rb +53 -0
  137. data/app/models/ar_category.rb +109 -0
  138. data/app/models/ar_design.rb +116 -0
  139. data/app/models/ar_filter.rb +200 -0
  140. data/app/models/ar_folder_permission.rb +50 -0
  141. data/app/models/ar_folder_rule.rb +47 -0
  142. data/app/models/ar_gallery.rb +53 -0
  143. data/app/models/ar_image.rb +198 -0
  144. data/app/models/ar_internals.rb +60 -0
  145. data/app/models/ar_journal.rb +46 -0
  146. data/app/models/ar_json_ld.rb +131 -0
  147. data/app/models/ar_key_value_store.rb +128 -0
  148. data/app/models/ar_link.rb +48 -0
  149. data/app/models/ar_memory.rb +172 -0
  150. data/app/models/ar_menu.rb +144 -0
  151. data/app/models/ar_menu_item.rb +106 -0
  152. data/app/models/ar_page.rb +74 -0
  153. data/app/models/ar_part.rb +66 -0
  154. data/app/models/ar_permission.rb +180 -0
  155. data/app/models/ar_permission_rule.rb +65 -0
  156. data/app/models/ar_policy.rb +78 -0
  157. data/app/models/ar_policy_rule.rb +65 -0
  158. data/app/models/ar_poll.rb +74 -0
  159. data/app/models/ar_poll_item.rb +47 -0
  160. data/app/models/ar_poll_result.rb +38 -0
  161. data/app/models/ar_removed_url.rb +42 -0
  162. data/app/models/ar_role.rb +84 -0
  163. data/app/models/ar_setup.rb +115 -0
  164. data/app/models/ar_site.rb +68 -0
  165. data/app/models/ar_temp.rb +150 -0
  166. data/app/models/ar_user.rb +72 -0
  167. data/app/models/ar_user_group.rb +38 -0
  168. data/app/models/ar_user_role.rb +54 -0
  169. data/app/models/ar_visit.rb +41 -0
  170. data/app/models/concerns/ar_page_concern.rb +128 -0
  171. data/app/models/concerns/ar_part_concern.rb +48 -0
  172. data/app/models/concerns/ar_piece_concern.rb +48 -0
  173. data/app/models/concerns/ar_policy_rule_concern.rb +87 -0
  174. data/app/models/concerns/ar_seo_concern.rb +66 -0
  175. data/app/models/concerns/ar_site_concern.rb +103 -0
  176. data/app/models/concerns/ar_user_concern.rb +195 -0
  177. data/app/renderers/agile_common_renderer.rb +93 -0
  178. data/app/renderers/agile_renderer.rb +59 -0
  179. data/app/renderers/ar_ad_renderer.rb +219 -0
  180. data/app/renderers/ar_captcha_renderer.rb +113 -0
  181. data/app/renderers/ar_common_renderer.rb +90 -0
  182. data/app/renderers/ar_gallery_renderer.rb +107 -0
  183. data/app/renderers/ar_menu_renderer.rb +195 -0
  184. data/app/renderers/ar_page_renderer.rb +147 -0
  185. data/app/renderers/ar_part_renderer.rb +235 -0
  186. data/app/renderers/ar_piece_renderer.rb +119 -0
  187. data/app/renderers/ar_poll_renderer.rb +272 -0
  188. data/app/views/agile/_edit_stuff.html.erb +57 -0
  189. data/app/views/agile/_form.html.erb +24 -0
  190. data/app/views/agile/_result.html.erb +28 -0
  191. data/app/views/agile/edit.html.erb +13 -0
  192. data/app/views/agile/error.html.erb +2 -0
  193. data/app/views/agile/index.html.erb +14 -0
  194. data/app/views/agile/login.html.erb +19 -0
  195. data/app/views/agile/new.html.erb +12 -0
  196. data/app/views/agile_common/_help.html.erb +18 -0
  197. data/app/views/agile_common/_iframe_edit.html.erb +2 -0
  198. data/app/views/agile_common/paste_clipboard.html.erb +17 -0
  199. data/app/views/layouts/agile.html.erb +17 -0
  200. data/app/views/layouts/content.html.erb +20 -0
  201. data/app/views/models/dump_models.html.erb +47 -0
  202. data/config/initializers/kaminari_patch.rb +56 -0
  203. data/config/locales/agile_de.yml +138 -0
  204. data/config/locales/agile_en.yml +162 -0
  205. data/config/locales/agile_sl.yml +163 -0
  206. data/config/locales/datetimepicker.yml +19 -0
  207. data/config/locales/de.yml +231 -0
  208. data/config/locales/en.yml +13 -0
  209. data/config/locales/kaminari.yml +26 -0
  210. data/config/locales/models_en.yml +1032 -0
  211. data/config/locales/models_sl.yml +1065 -0
  212. data/config/locales/sl.yml +211 -0
  213. data/db/migrate/20240120160001_add_sessions_table.rb +12 -0
  214. data/db/migrate/20240120160002_ar_big_table.rb +17 -0
  215. data/db/migrate/20240120160003_ar_big_table_value.rb +18 -0
  216. data/db/migrate/20240120160004_ar_category.rb +22 -0
  217. data/db/migrate/20240120160005_ar_design.rb +20 -0
  218. data/db/migrate/20240120160006_ar_filter.rb +17 -0
  219. data/db/migrate/20240120160007_ar_gallery.rb +21 -0
  220. data/db/migrate/20240120160008_ar_journal.rb +19 -0
  221. data/db/migrate/20240120160009_ar_key_value_store.rb +11 -0
  222. data/db/migrate/20240120160010_ar_link.rb +19 -0
  223. data/db/migrate/20240120160011_ar_memory.rb +8 -0
  224. data/db/migrate/20240120160012_ar_menu.rb +21 -0
  225. data/db/migrate/20240120160013_ar_menu_item.rb +28 -0
  226. data/db/migrate/20240120160014_ar_page.rb +50 -0
  227. data/db/migrate/20240120160015_ar_part.rb +33 -0
  228. data/db/migrate/20240120160016_ar_permission.rb +16 -0
  229. data/db/migrate/20240120160017_ar_permission_rule.rb +17 -0
  230. data/db/migrate/20240120160018_ar_piece.rb +28 -0
  231. data/db/migrate/20240120160019_ar_policy.rb +21 -0
  232. data/db/migrate/20240120160020_ar_policy_rule.rb +18 -0
  233. data/db/migrate/20240120160021_ar_poll.rb +27 -0
  234. data/db/migrate/20240120160022_ar_poll_item.rb +23 -0
  235. data/db/migrate/20240120160023_ar_poll_result.rb +14 -0
  236. data/db/migrate/20240120160024_ar_removed_url.rb +16 -0
  237. data/db/migrate/20240120160025_ar_role.rb +17 -0
  238. data/db/migrate/20240120160026_ar_site.rb +37 -0
  239. data/db/migrate/20240120160027_ar_temp.rb +11 -0
  240. data/db/migrate/20240120160028_ar_user.rb +42 -0
  241. data/db/migrate/20240120160029_ar_user_group.rb +12 -0
  242. data/db/migrate/20240120160030_ar_user_role.rb +18 -0
  243. data/db/migrate/20240120160031_ar_visit.rb +15 -0
  244. data/db/migrate/20240703016001_ar_setup.rb +16 -0
  245. data/db/migrate/20240703016002_ar_folder_permission.rb +15 -0
  246. data/db/migrate/20240703016003_ar_folder_rule.rb +14 -0
  247. data/db/migrate/20250115000001_ar_image.rb +25 -0
  248. data/lib/agile/configuration.rb +43 -0
  249. data/lib/agile/engine.rb +29 -0
  250. data/lib/agile/version.rb +27 -0
  251. data/lib/agile.rb +282 -0
  252. data/lib/agile_rails.rb +1 -0
  253. data/lib/generators/agile/USAGE +11 -0
  254. data/lib/generators/agile/new_form_generator.rb +369 -0
  255. data/lib/generators/convert_to_ar/convert_to_ar_generator.rb +158 -0
  256. data/lib/tasks/agile_db_clone.rake +132 -0
  257. data/lib/tasks/agile_db_export_to_yaml.rake +37 -0
  258. data/lib/tasks/agile_db_migrate.rake +35 -0
  259. metadata +414 -0
@@ -0,0 +1,645 @@
1
+ #--
2
+ # Copyright (c) 2024+ 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
+ # AgileEditHelper module defines helper methods used by AgileRails form edit action. Output is controlled by
27
+ # data found in 3 major sections of AgileRails form: index, data_set and form sections.
28
+ #
29
+ ###########################################################################
30
+ module AgileEditHelper
31
+
32
+ ############################################################################
33
+ # Will return value when internal or additional parameters are defined in action
34
+ # Subroutine of agile_actions_for_form.
35
+ ############################################################################
36
+ def agile_value_for_parameter(param, current_document = nil)#:nodoc:
37
+ if param.class == Hash
38
+ agile_internal_var(param['object'] ||= 'record', param['method'], current_document)
39
+ elsif param.to_s.match(/record|document/)
40
+ current_document ? current_document : @record
41
+ else
42
+ param
43
+ end
44
+ end
45
+
46
+ ############################################################################
47
+ # Creates actions div for edit form.
48
+ #
49
+ # Displaying readonly form turned out to be challenge. For now when readonly parameter
50
+ # has value 2, back link will force readonly form. Value 1 or not set will result in
51
+ # normal link.
52
+ ############################################################################
53
+ def agile_is_action_active?(options)
54
+ return true unless options['active']
55
+
56
+ # alias record and document so both can be used in eval
57
+ record = document = @record
58
+ option = options['active']
59
+ case
60
+ # usually only for test
61
+ when option.class == TrueClass || option['eval'].class == TrueClass then true
62
+
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
+ agile_process_eval(option, self)
69
+ else
70
+ eval(option['eval'])
71
+ end
72
+
73
+ # direct evaluate expression
74
+ when option['eval'] then
75
+ eval(option['eval'])
76
+
77
+ # if record present send record otherwise send self as parameter
78
+ when option['method'] then
79
+ agile_process_eval(option['method'], self)
80
+
81
+ else
82
+ false
83
+ end
84
+ end
85
+
86
+ ############################################################################
87
+ # Creates actions div for edit form.
88
+ #
89
+ # Displaying readonly form turned out to be challenge. For now when readonly parameter
90
+ # has value 2, back link will force readonly form. Value 1 or not set will result in
91
+ # normal link.
92
+ ############################################################################
93
+ def agile_actions_for_form(position)
94
+ actions_pos = agile_check_and_default(@form['form']['actions_position'], Agile.config(:default_actions_position), %w[top bottom both])
95
+ return '' if actions_pos != 'both' && (position != actions_pos)# == 'bottom') || (position == 'bottom' && actions_pos == 'top')
96
+
97
+ # create standard actions
98
+ actions = @form['form']['actions'] || {}
99
+ std_actions = Agile.config(:form_standard_actions)
100
+ std_actions = { 1 => 'back' } if @form['readonly'] # readonly
101
+ if actions.class == String
102
+ actions = process_standard_actions(actions, std_actions)
103
+ elsif actions['standard']
104
+ actions.merge!(std_actions)
105
+ actions.delete('standard')
106
+ end
107
+
108
+ # some actions have meaning only when editing
109
+ if @record.try(:id).nil?
110
+ actions_remove_action(actions, 'new', 'enable', 'refresh')
111
+ # enable disable if active field is present
112
+ elsif @record.has_attribute?(:active)
113
+ index = actions.find { |k, v| v.is_a?(String) && v == 'enable' }
114
+ actions[index.first] = (@record.active ? 'disable' : 'enable') if index
115
+ else
116
+ actions_remove_action(actions, 'enable')
117
+ end
118
+ # Actions are strictly forbidden
119
+ if @form['form']['actions'] && agile_dont?(@form['form']['actions'])
120
+ actions = []
121
+ end
122
+
123
+ # request for close window button present
124
+ if actions.kind_of?(Hash) && params[:window_close].present?
125
+ case params[:window_close].to_i
126
+ when 0
127
+ actions[1] = 'close'
128
+ actions_remove_action(actions, 'new')
129
+
130
+ when 1, 2
131
+ actions = { 1 => 'close' }
132
+ end
133
+ # if save & back present with close action change it to save
134
+ index = actions.find { |k, v| v.is_a?(String) && v == 'save&back' }
135
+ actions[index.first] = 'save' if index
136
+ end
137
+
138
+ # select only integer keys and sort
139
+ actions = actions.to_a.select{ _1.first.is_a?(Integer) }.sort{ |x, y| x[0] <=> y[0] }
140
+ # Add spinner to the beginning
141
+ html = %(<span class="ar-spinner">#{mi_icon('settings-o spin')}</span><ul class="ar-edit-menu #{position}">)
142
+
143
+ actions.each do |key, options|
144
+ session[:form_processing] = "form:actions: #{key} #{options}"
145
+ next if options.nil? # yes it happens
146
+
147
+ parms = @form_params.clone
148
+ if options.class == String
149
+ next if @form['readonly'] && !options.match(/back|close/)
150
+
151
+ partial =
152
+ case options
153
+
154
+ when 'save&back', 'save'
155
+ html += form_submit_action(options) # already comes with li tags
156
+ next
157
+
158
+ when 'back', 'cancel'
159
+ # If return_to is present link directly to URL
160
+ if parms['xreturn_to'] # disabled for now
161
+ agile_link_to( 'agile.back', 'arrow_back', parms['return_to'], class: 'ar-link' )
162
+ else
163
+ parms['action'] = 'index'
164
+ parms['readonly'] = parms['readonly'].to_s.to_i < 2 ? nil : 1
165
+
166
+ agile_link_to( 'agile.back', 'arrow_back', parms, class: 'ar-link' )
167
+ end
168
+
169
+ when 'new'
170
+ parms['action'] = options
171
+ agile_link_to( 'agile.new', 'add', parms, class: 'ar-link')
172
+
173
+ when 'enable', 'disable'
174
+ parms['operation'] = options
175
+ parms['id'] = @record.id
176
+ icon = (options == 'enable' ? 'check_box-o' : 'check_box_outline_blank')
177
+ agile_link_to( "agile.#{options}",icon, parms, method: :delete, class: 'ar-link' )
178
+
179
+ when 'refresh'
180
+ %(<div class="ar-link refresh">#{mi_icon('refresh')} #{t('agile.refresh')}</div>)
181
+
182
+ when 'close'
183
+ close = params[:window_close].to_i
184
+ if close < 2
185
+ %(<div class="ar-link close">#{mi_icon('close')} #{t('agile.close')}</div>)
186
+ else
187
+ %(<div class="ar-link back">#{mi_icon('close')} #{t('agile.close')}</div>)
188
+ end
189
+
190
+ else
191
+ "err1 #{key}=>#{options}"
192
+ end
193
+ html += "<li>#{partial}</li>"
194
+
195
+ # non standard actions
196
+ else
197
+ # action will be displayed when show: always or readonly option is declared and form is readonly
198
+ next if @form['readonly'] && !%w[readonly always].include?(options['show'].to_s)
199
+
200
+ options['title'] = t("#{options['title'].downcase}", options['title']) if options['title']
201
+ html +=
202
+ case
203
+ # submit button
204
+ when options['type'] == 'submit'
205
+ form_submit_action(options)
206
+
207
+ # ajax or link button
208
+ when %w(ajax link window popup).include?(options['type'])
209
+ agile_link_ajax_window_submit_action(options, @record)
210
+
211
+ # Javascript action
212
+ when options['type'] == 'script'
213
+ agile_script_action(options)
214
+ else
215
+ '<li>err2</li>'
216
+ end
217
+ end
218
+
219
+ end
220
+ (html += '</ul>').html_safe
221
+ end
222
+
223
+ ############################################################################
224
+ # Create background div and table definitions for dataset.
225
+ ############################################################################
226
+ def agile_background_for_dataset(start)
227
+ if start == :start
228
+ style = @form.dig('index', 'data_set', 'table_style')
229
+ html = '<div class="ar-result-div" '
230
+ html += (style ? 'style="overflow-x: scroll;" >' : '>')
231
+
232
+ html += "\n<div class=\"ar-result #{@form['index']['data_set']['table_class']}\" "
233
+ html += ( style ? "style=\"#{style}\" >" : '>')
234
+ else
235
+ html = '</div></div>'
236
+ end
237
+ html.html_safe
238
+ end
239
+
240
+ ############################################################################
241
+ # Checks if value is defined and sets default. If values are sent it also checks
242
+ # if value is found in values. If not it will report error and set value to default.
243
+ # Subroutine of agile_fields_for_tab.
244
+ ############################################################################
245
+ def agile_check_and_default(value, default, values = nil) #:nodoc:
246
+ return default if value.nil?
247
+ # check if value is within allowed values
248
+ if values
249
+ if !values.index(value)
250
+ # parameters should be in downcase. Check downcase version.
251
+ if n = values.index(value.downcase)
252
+ return values[n]
253
+ else
254
+ logger.error("AgileRails Forms: Value #{value} not within values [#{values.join(',')}]. Default #{default} used!")
255
+ return default
256
+ end
257
+ end
258
+ end
259
+ value
260
+ end
261
+
262
+ ############################################################################
263
+ # Creates input fields defined in form options
264
+ ############################################################################
265
+ def agile_fields_for_form
266
+ html = "<div id='data_fields' " + (@form['form']['height'] ? "style=\"height: #{@form['form']['height']}px;\">" : '>')
267
+ @js ||= ''
268
+ @css ||= ''
269
+ # fields
270
+ if (form_fields = @form['form']['fields'])
271
+ html += agile_input_form(form_fields) + '</div>'
272
+ elsif @form['form']['tabs'] #tabs
273
+ html = agile_tabs_form()
274
+ end
275
+ # add last_updated_at hidden field so controller can check if record was updated in db during editing
276
+ html += hidden_field(nil, :last_updated_at, value: @record.updated_at.to_i) if @record.respond_to?(:updated_at)
277
+ # add form time stamp to prevent double form submit
278
+ html += hidden_field(nil, :form_time_stamp, value: Time.now.to_i)
279
+ # add javascript code if defined by form
280
+ @js += "\n#{@form['script']} #{@form['js']}"
281
+ @css += "\n#{@form['css']}\n#{@form['form']['css']}"
282
+ html.html_safe
283
+ end
284
+
285
+ ############################################################################
286
+ # Creates head form div. Head form div is used to display header data useful
287
+ # to be seen even when tabs are switched.
288
+ ############################################################################
289
+ def agile_head_for_form
290
+ @css ||= ''
291
+ head = @form['form']['head']
292
+ return '' if head.nil?
293
+
294
+ html = %(<div class="ar-head #{head['class']}">\n<div class="ar-row">)
295
+ split = head['split'] || 4
296
+ percent = 100/split
297
+ current = 0
298
+ head_fields = head.select {|field| field.class == Integer }
299
+ head_fields.to_a.sort.each do |number, options|
300
+ session[:form_processing] = "form: head: #{number}=#{options}"
301
+ # Label
302
+ caption = options['caption']
303
+ span = options['span'] || 1
304
+ @css += "\n#{options['css']}" unless options['css'].blank?
305
+ label = if caption.blank?
306
+ ''
307
+ elsif options['name'] == caption
308
+ t_label_for_field(options['name'], options['name'].capitalize.gsub('_',' ') )
309
+ else
310
+ t(caption, caption)
311
+ end
312
+ # Field value
313
+ begin
314
+ field = if options['eval']
315
+ agile_process_column_eval(options, @record)
316
+ else
317
+ @record.send(options['name'])
318
+ end
319
+ rescue Exception => e
320
+ agile_log_exception(e, 'agile_head_for_form')
321
+ field = '!!!Error'
322
+ end
323
+ #
324
+ klass = agile_style_or_class(nil, options['class'], field, @record)
325
+ style = agile_style_or_class(nil, options['style'], field, @record)
326
+ html += %(<div class="ar-column #{klass}" style="width:#{percent*span}%;#{style}">
327
+ #{label.blank? ? '' : "<span class=\"label\">#{label}</span>"}
328
+ <span id="head-#{options['name']}" class="field">#{field}</span>
329
+ </div>)
330
+ current += span
331
+ if current == split
332
+ html += %(</div>\n<div class="ar-row">)
333
+ current = 0
334
+ end
335
+ end
336
+ html += '</div></div>'
337
+ html.html_safe
338
+ end
339
+
340
+ ############################################################################
341
+ # Returns username for id. Subroutine of agile_document_statistics
342
+ ###########################################################################
343
+ def agile_document_user_for(field_name) #:nodoc:
344
+ return if @record[field_name].nil?
345
+
346
+ user = ArUser.find(@record[field_name])
347
+ user ? user.name : @record[field_name]
348
+ end
349
+
350
+ ############################################################################
351
+ # Creates current document statistics div (created_by, created_at, ....) at the bottom of edit form.
352
+ # + lots of more. At the moment also adds icon for dumping current record as json text.
353
+ ############################################################################
354
+ def agile_document_statistics
355
+ return '' if @record.id.nil? || agile_dont?(@form['form']['info'])
356
+
357
+ html = %(<div id="ar-document-info">#{mi_icon('info md-18')}</div> <div id="ar-document-info-popup" class="div-hidden">)
358
+ u = agile_document_user_for('created_by')
359
+ html += %(<div><span>#{t('agile.created_by', 'Created by')}: </span><span>#{u}</span></div>) if u
360
+ u = agile_document_user_for('updated_by')
361
+ html += %(<div><span>#{t('agile.updated_by', 'Updated by')}: </span><span>#{u}</span></div>) if u
362
+
363
+ html += %(<div><span>#{t('agile.created_at', 'Created at')}: </span><span>#{agile_format_value(@record.created_at)}</span></div>) if @record['created_at']
364
+ html += %(<div><span>#{t('agile.updated_at', 'Updated at')}: </span><span>#{agile_format_value(@record.updated_at)}</span></div>) if @record['updated_at']
365
+ # copy to clipboard icon
366
+ parms = params.clone
367
+ parms[:controller] = :agile_common
368
+ parms[:action] = :copy_clipboard
369
+ url = url_for(parms.permit!)
370
+ html += '<div>'
371
+ html += mi_icon('content_copy-o md-18', class: 'ar-link-img ar-link-ajax',
372
+ 'data-url' => url, 'data-request' => 'get', title: t('agile.copy_clipboard') )
373
+
374
+ url = url_for(controller: :agile, action: :run, table: 'ar_journal', control: 'agile.filter_on',
375
+ filter_oper: 'eq', filter_field: 'id', filter_value: "#{@form['table']};#{@record.id}")
376
+
377
+ html += mi_icon('history md-18', class: 'ar-link-img ar-window-open',
378
+ 'data-url' => url, title: t('helpers.label.ar_journal.table_title') )
379
+ html += %(<span>ID: </span>
380
+ <span id="record-id" class="hover" onclick="agile_copy_to_clipboard('record-id');" title="Copy document ID to clipboard">#{@record.id}
381
+ </span>)
382
+
383
+ (html += '</div></div>').html_safe
384
+ end
385
+
386
+ ############################################################################
387
+ # Updates form prior to processing form
388
+ ############################################################################
389
+ def agile_update_form
390
+ # update form for steps options
391
+ if @form.dig('form', 'steps')
392
+ agile_update_form_steps
393
+ end
394
+ end
395
+
396
+ ############################################################################
397
+ # If form is divided into two parts, this method gathers html to be painted
398
+ # on right side of the form pane.
399
+ ############################################################################
400
+ def agile_form_left
401
+ yaml = @form.dig('form', 'form_left')
402
+ return '' unless yaml
403
+
404
+ html = ''
405
+ html += agile_process_eval(yaml['eval'], self) if yaml['eval']
406
+
407
+ html.html_safe
408
+ end
409
+
410
+ private
411
+
412
+ ############################################################################
413
+ # Creates top or bottom horizontal line on form.
414
+ #
415
+ # @param [String] location (top or bottom)
416
+ # @param [Object] options yaml field definition
417
+ #
418
+ # @return [String] html code for drawing a line
419
+ ############################################################################
420
+ def agile_top_bottom_line(location, options)
421
+ if options["#{location}-line"] || options['line'].to_s == location.to_s
422
+ '</div><div class="ar-form-section"><div class="ar-separator"></div>'
423
+ else
424
+ ''
425
+ end
426
+ end
427
+
428
+ ############################################################################
429
+ # Creates submit action on form. Subroutine of agile_actions_for_form.
430
+ ############################################################################
431
+ def form_submit_action(options) #:nodoc:
432
+ if options.is_a?(String)
433
+ options = { 'type' => 'submit', 'caption' => t("agile.#{options}"), 'params' => {} }
434
+ end
435
+ caption = options['caption'] || 'agile.save'
436
+ icon = options['icon'] || 'save'
437
+ parameters = {}
438
+ options['params'].each { |k, v| parameters[k] = agile_value_for_parameter(v) } if options['params']
439
+ if agile_is_action_active?(options)
440
+ '<li>' +
441
+ agile_submit_tag(caption, icon, { data: parameters, title: options['title'] }) +
442
+ '</li>'
443
+ else
444
+ %(<li><div class="ar-link-no">#{mi_icon(icon)} #{caption}</div></li>)
445
+ end
446
+ end
447
+
448
+ ############################################################################
449
+ # Creates input fields for one tab. Subroutine of agile_fields_for_form.
450
+ ############################################################################
451
+ def agile_input_form(fields_on_tab) #:nodoc:
452
+ html = '<div class="ar-form"><div class="ar-form-section">'
453
+ labels_pos = agile_check_and_default(@form['form']['labels_position'], Agile.config(:default_labels_position), %w[top left])
454
+ hidden_fields = ''
455
+ group_option, group_count = 0, 0
456
+ # Select form fields and sort them by key
457
+ form_fields = fields_on_tab.select { |field| field.is_a?(Integer) }
458
+ form_fields.to_a.sort.each do |number, options|
459
+ session[:form_processing] = "form:fields: #{number}=#{options}"
460
+ # ignore if edit_only singe field is required
461
+ next if params[:edit_only] && params[:edit_only] != options['name']
462
+ next if options.nil?
463
+
464
+ # hidden_fields. Add them at the end
465
+ if options['type'] == 'hidden_field'
466
+ hidden_fields << AgileFormFields::HiddenField.new(self, @record, options).render
467
+ next
468
+ end
469
+ # label
470
+ field_html, label, help = agile_field_label_help(options)
471
+ label = nil if agile_dont?(options['caption'])
472
+ # Line separator
473
+ html += agile_top_bottom_line(:top, options)
474
+ # Beginning of new row
475
+ if group_count == 0
476
+ html += '<div class="row-div">'
477
+ group_count = options['group'] || 1
478
+ group_option = options['group'] || 1
479
+ end
480
+ html += if labels_pos == 'top'
481
+ data_width = case group_option
482
+ when 2 then (group_count == 2 ? 40 : 70)
483
+ when 3 then [30, 30, 40][group_count - 1]
484
+ else 100
485
+ end
486
+ label = label.nil? ? '' : %(<label for="record_#{options['name']}">#{label} </label>)
487
+ %(
488
+ <div class="ar-form-label-top ar-align-left ar-width-#{data_width}" title="#{help}">
489
+ #{label}
490
+ <div id="td_record_#{options['name']}">#{field_html}</div>
491
+ </div> )
492
+ else
493
+ # no label
494
+ if label.nil?
495
+ label = ''
496
+ label_width = 0
497
+ data_width = 100
498
+ elsif group_option > 1
499
+ label_width = group_option != group_count ? 10 : 14
500
+ data_width = 21
501
+ else
502
+ label_width = 14
503
+ data_width = 85
504
+ end
505
+ help.gsub!('<br>',"\n") if help.present?
506
+ %(
507
+ <div class="ar-form-label ar-align-right ar-width-#{label_width}" title="#{help}">
508
+ <label for="record_#{options['name']}">#{label} </label>
509
+ </div>
510
+ <div id="td_record_#{options['name']}" class="ar-form-field ar-width-#{data_width}">#{field_html}</div>
511
+ )
512
+ end
513
+ # check if group end
514
+ if (group_count -= 1) == 0
515
+ html += '</div>'
516
+ # insert dummy div when only two fields in group
517
+ html += '<div></div>' if group_option == 2
518
+ end
519
+
520
+ html += agile_top_bottom_line(:bottom, options)
521
+ end
522
+ html += '</div></div>' + hidden_fields
523
+ end
524
+
525
+ ############################################################################
526
+ # Will create html code required for input form with steps defined
527
+ ############################################################################
528
+ def agile_steps_one_element(element, tab_name = nil)
529
+ def add_one_step(key, tab_name, key_number)
530
+ fields = tab_name ? @form['form']['tabs'][tab_name] : @form['form']['fields']
531
+ { key_number => fields[key] }
532
+ end
533
+
534
+ key_number, fields = 0, {}
535
+ element.to_s.split(',').each do |particle|
536
+ if particle.match('-')
537
+ tabs_fields = tab_name ? @form['form']['tabs'][tab_name] : @form['form']['fields']
538
+ next if tabs_fields.nil?
539
+
540
+ start, to_end = particle.split('-').map(&:to_i)
541
+ tabs_fields.each_key { |key| fields.merge!(add_one_step(key, tab_name, key_number += 10)) if (start..to_end).include?(key) }
542
+ else
543
+ fields.merge!(add_one_step(particle.to_i, tab_name, key_number += 10))
544
+ end
545
+ end
546
+ fields
547
+ end
548
+
549
+ ############################################################################
550
+ # Will create html code required for input form with steps defined and update
551
+ # actions.
552
+ ############################################################################
553
+ def agile_update_form_steps
554
+ def add_step_to_form(index, step, next_step)
555
+ @form['form']['actions'][index]['params']['step'] = step
556
+ @form['form']['actions'][index]['params']['next_step'] = next_step
557
+ end
558
+
559
+ form = {}
560
+ step = params[:step].to_i
561
+ step_data = @form['form']['steps'].to_a[step - 1]
562
+
563
+ step_data.last.each do |element|
564
+ if element.first == 'fields'
565
+ form.merge!(agile_steps_one_element(element.second))
566
+ elsif element.first == 'tabs'
567
+ element.last.each do |tab_name, data|
568
+ form.merge!(agile_steps_one_element(data, tab_name))
569
+ end
570
+ end
571
+ end
572
+ # fraction updates of newly created form
573
+ form.deep_merge!(step_data.last['update']) if step_data.last['update']
574
+ # update steps data on form
575
+ add_step_to_form(10, step, step - 1)
576
+ add_step_to_form(20, step, step + 1)
577
+ add_step_to_form(100, step, step + 1)
578
+ # remove not needed steps
579
+ if step < 2
580
+ @form['form']['actions'].delete(10)
581
+ elsif step == @form['form']['steps'].size
582
+ @form['form']['actions'].delete(20)
583
+ end
584
+ @form['form']['actions'].delete(100) unless step == @form['form']['steps'].size
585
+ # update form_name and control name if defined
586
+ %w[1 10 20 100].each do |i|
587
+ next unless @form['form']['actions'][i.to_i]
588
+
589
+ @form['form']['actions'][i.to_i]['form_name'] = AgileHelper.form_param(params)
590
+ control = @form['control'] ? @form['control'] : @form['table']
591
+ @form['form']['actions'][i.to_i]['control'].sub!('x.', "#{control}.")
592
+ end
593
+
594
+ @form['form']['form_left'] ||= { 'eval' => 'agile_steps_menu_get'}
595
+ @form['form']['fields'] = form
596
+ end
597
+
598
+ ############################################################################
599
+ # Will create html code required for input form with tabs
600
+ ############################################################################
601
+ def agile_tabs_form
602
+ html, tabs, tab_data = '', [], ''
603
+ first_tab = true # first tab
604
+ tab_type = @form['form']['type'] || 'default'
605
+ tab_class = @form['form']['class'] || ''
606
+ tab_style = @form['form']['style'] || ''
607
+
608
+ @form['form']['tabs'].keys.sort.each do |tab_name|
609
+ next if tab_name.match('options')
610
+
611
+ # Tricky when editing single field. If field is not present on the tab skip to next tab
612
+ if params[:edit_only]
613
+ is_on_tab = false
614
+ @form['form']['tabs'][tab_name].each_value { |v| is_on_tab = true if params[:edit_only] == v['name'] }
615
+ next unless is_on_tab
616
+ end
617
+ tab_index = tab_name.delete("\s\n")
618
+ tab_label, tab_title = agile_tab_label_help(tab_name)
619
+ tabs << [tab_name, tab_label, tab_title, tab_index]
620
+
621
+ klass = "#{tab_type == 'accordion' ? 'ar-accordion' : ''} ar-form-accordion #{first_tab ? 'open' : ''} #{tab_class}"
622
+ tab_data += %(<div id="acc_#{tab_index}" class="#{klass}" title="#{tab_title}">#{tab_label}</div>)
623
+ tab_data += %(<div id="data_#{tab_index}")
624
+ tab_data += ' class="div-hidden"' unless first_tab
625
+ tab_data += (@form['form']['style'] ? %( style="#{tab_style};">) : '>')
626
+ tab_data += "#{agile_input_form(@form['form']['tabs'][tab_name])}</div>"
627
+ first_tab = false
628
+ end
629
+
630
+ if tab_type != 'accordion' #
631
+ # make it all work together
632
+ html += '<ul class="ar-form-ul" >'
633
+ first = true # first tab must be selected
634
+ tabs.each do |tab_name, tab_label, tab_title, tab_index|
635
+ html += %(<li id="li_#{tab_index}" data-div="#{tab_index}" title="#{tab_title}" class="ar-form-li)
636
+ html += ' ar-form-li-selected' if first
637
+ html += "\">#{tab_label}</li>"
638
+ first = false
639
+ end
640
+ html += '</ul>'
641
+ end
642
+ html + tab_data
643
+ end
644
+
645
+ end