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,509 @@
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
+ # AgileHelper module defines common methods used for AgileRails forms.
27
+ #
28
+ ###########################################################################
29
+ module AgileHelper
30
+ # javascript part created by form helpers
31
+ attr_reader :js
32
+
33
+ ############################################################################
34
+ # Creates code for script action type.
35
+ ############################################################################
36
+ def agile_script_action(yaml)
37
+ icon = agile_icon_for_link yaml['icon']
38
+ yaml['html'] ||= {}
39
+ yaml['html']['data-url'] = 'script'
40
+ yaml['html']['data-request'] = 'script'
41
+ yaml['html']['data-script'] = (yaml['js'] || yaml['script']).to_s
42
+ yaml['html']['class'] ||= 'ar-link-ajax'
43
+ attributes = yaml['html'].map { |k, v| "#{k}=\"#{v}\"" }.join(' ')
44
+ %(<li><div #{attributes}>#{icon} #{ t(yaml['caption'], yaml['caption']) }</div></li>)
45
+ end
46
+
47
+ ############################################################################
48
+ # Will return field form definition if field is defined on form. Field definition
49
+ # will then be used for creating filter input field.
50
+ ############################################################################
51
+ def self.get_field_form_definition(name, form) #:nodoc:
52
+ return if form['form'].nil?
53
+
54
+ found = nil
55
+ if form['form']['tabs']
56
+ form['form']['tabs'].each do |tab, data|
57
+ found = data.find{ |k, v| k.is_a?(Integer) && v['name'] == name }
58
+ break if found
59
+ end
60
+ elsif form['form']['fields']
61
+ found = form['form']['fields'].find{ |k, v| k.is_a?(Integer) && v['name'] == name }
62
+ end
63
+ found ? found.last : nil
64
+ end
65
+
66
+ ############################################################################
67
+ # Return field code, label and help text for a field defined on a AgileRails Form.
68
+ #
69
+ # Parameters:
70
+ # options : Hash : Field definition
71
+ #
72
+ # Returns: Array[3]
73
+ # field_html : String : HTML code for field definition
74
+ # label : String : Label text
75
+ # help : String : Help text
76
+ ############################################################################
77
+ def agile_field_label_help(options)
78
+ label, help = agile_label_help(options)
79
+ # create field object from type and call its render method
80
+ if options['type'].present?
81
+ klass_string = options['type'].camelize
82
+ field_html = if AgileFormFields.const_defined?(klass_string) # when field type defined
83
+ klass = AgileFormFields.const_get(klass_string)
84
+ field = klass.new(self, @record, options).render
85
+ @js += field.js
86
+ @css += field.css
87
+ field.html
88
+ else
89
+ "Error: Field type #{options['type']} not defined!"
90
+ end
91
+ else
92
+ "Error: Field type missing!"
93
+ end
94
+ [field_html, label, help]
95
+ end
96
+
97
+ ############################################################################
98
+ # Return label and help text for a field defined on Form.
99
+ #
100
+ # Parameters:
101
+ # options : Hash : Field definition
102
+ #
103
+ # Returns:
104
+ # label : String : Label text
105
+ # help : String : Help text
106
+ ############################################################################
107
+ def agile_label_help(options)
108
+ # no label or help in comments
109
+ return [nil, nil] if %w[comment action].include?(options['type'])
110
+
111
+ label = options['caption'] || options['text'] || options['label']
112
+ #label = '' if options['type'] == 'check_box'
113
+ if options['name']
114
+ label = if label.to_s.empty?
115
+ t_label_for_field(options['name'], options['name'].capitalize.gsub('_',' ') )
116
+ elsif options['name']
117
+ t(label, label)
118
+ end
119
+ end
120
+ # help text can be defined in form or in translations starting with helpers. or as helpers.help.collection.field
121
+ help = options['help']
122
+ if help.blank?
123
+ help = if options['name']
124
+ # if defined as i18n_prefix replace "label" with "help"
125
+ prefix = @form['i18n_prefix'] ? @form['i18n_prefix'].sub('label', 'help') : "helpers.help.#{@form['table']}"
126
+ "#{prefix}.#{options['name']}"
127
+ end
128
+ help = help.to_s
129
+ end
130
+ help = t(help, ' ') if help.to_s.match(/help\./)
131
+
132
+ [label, help]
133
+ end
134
+
135
+ ############################################################################
136
+ # Return label and help for tab on Form.
137
+ #
138
+ # Parameters:
139
+ # options : String : Tab name on form
140
+ #
141
+ # Returns:
142
+ # label : String : Label text
143
+ # help : String : Help text
144
+ ############################################################################
145
+ def agile_tab_label_help(tab_name)
146
+ label = @form.dig('form', 'tabs', tab_name, 'caption') || tab_name
147
+ label = t(label, t_label_for_field(label, label))
148
+ help = @form.dig('form', 'tabs', tab_name, 'help') || "helpers.help.#{@form['table']}.#{tab_name}"
149
+ help = t(help, t_label_for_field(help, help))
150
+ help = nil if help.match('helpers.') # help not found in translation
151
+
152
+ [label, help]
153
+ end
154
+
155
+ ############################################################################
156
+ # Creates code for including data entry field in index actions.
157
+ ############################################################################
158
+ def agile_field_action(yaml)
159
+ # assign value if value found in parameters
160
+ if params['record']
161
+ value = params['record'][yaml['name']]
162
+ params["p_#{yaml['name']}"] = value
163
+ end
164
+ # find field definition on form
165
+ if ( field_definition = AgileHelper.get_field_form_definition(yaml['name'], @form) )
166
+ # some options may be redefined
167
+ field_definition['size'] = yaml['size'] if yaml['size']
168
+ field, label, help = agile_field_label_help(field_definition)
169
+ else
170
+ yaml['type'] = yaml['field_type']
171
+ field, label, help = agile_field_label_help(yaml)
172
+ end
173
+ # input field will have label as placeholder
174
+ field = field.sub('input',"input placeholder=\"#{label}\"")
175
+ %(<li class="no-background">#{field}</li>)
176
+ end
177
+
178
+ ############################################################################
179
+ # Create ex. class="my-class" html code from html options for action
180
+ ############################################################################
181
+ def agile_get_html_data(yaml)
182
+ return '' if yaml.blank?
183
+
184
+ yaml.reject{ |k, v| v.nil? }.map{ |k, v| "#{k}=\"#{v}\"" }.join(' ')
185
+ end
186
+
187
+ ############################################################################
188
+ # There are several options for defining caption (caption,label, text). This method
189
+ # will ensure that caption is returned anyhow provided.
190
+ ############################################################################
191
+ def agile_get_caption(yaml)
192
+ yaml['caption'] || yaml['text'] || yaml['label']
193
+ end
194
+
195
+ ############################################################################
196
+ # Creates code for link, ajax or windows action for index or form actions.
197
+ #
198
+ # Parameters:
199
+ # yaml: Hash : Action definition
200
+ # record : Object : Currently selected record if available
201
+ # action_active : Boolean : Is action active or disabled
202
+ #
203
+ # Returns:
204
+ # String : HTML code for action
205
+ ############################################################################
206
+ def agile_link_ajax_window_submit_action(yaml, record = nil, action_active = true)
207
+ parms = {}
208
+ caption = agile_get_caption(yaml)
209
+ caption = caption ? t(caption.downcase.to_s, caption) : nil
210
+ icon = yaml['icon'] ? mi_icon(yaml['icon']).to_s : ''
211
+ # action is not active
212
+ unless agile_is_action_active?(yaml)
213
+ return %(<li><div class="ar-link-no">#{icon} #{caption}</div></li>)
214
+ end
215
+ # set data-confirm when confirm shortcut present
216
+ yaml['html'] ||= {}
217
+ text = yaml['html']['data-confirm'] || yaml['confirm']
218
+ yaml['html']['data-confirm'] = t(text) if text.present?
219
+
220
+ text = yaml['html']['title'] || yaml['title']
221
+ yaml['html']['title'] = t(text) if text.present?
222
+
223
+ yaml['html']['target'] ||= yaml['target']
224
+ # direct url
225
+ if yaml['url']
226
+ parms['url'] = yaml['url']
227
+ parms['idr'] = record.id if record
228
+ # make url from action controller
229
+ else
230
+ parms['controller'] = yaml['controller'] || :agile
231
+ parms['action'] = yaml['action']
232
+ parms['table'] = yaml['table'] || @form['table']
233
+ parms['form_name'] = yaml['form_name']
234
+ parms['control'] = yaml['control'] if yaml['control']
235
+ parms['id'] = record.id if record
236
+ end
237
+ # add current id to parameters
238
+ parms['id'] = record.id if record
239
+ # overwrite with or add additional parameters from environment or record
240
+ yaml['params'].each { |k, v| parms[k] = agile_value_for_parameter(v, record) } if yaml['params']
241
+
242
+ parms['table'] = parms['table'].underscore if parms['table'] # might be CamelCase
243
+ # error if controller parameter is missing
244
+ return "<li>#{'Controller not defined'}</li>" if parms['controller'].nil? && parms['url'].nil?
245
+
246
+ html_data = agile_get_html_data(yaml['html'])
247
+ url_forward_params(parms)
248
+ url = url_for(parms) rescue 'URL error'
249
+ url = nil if parms['url'] == '#'
250
+ request = yaml['request'] || yaml['method'] || 'get'
251
+
252
+ code = case yaml['type']
253
+ # ajax button
254
+ when 'ajax'
255
+ clas = 'ar-link-ajax'
256
+ %(<div class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}
257
+ data-request="#{request}" title="#{yaml['title']}">#{icon}#{caption}</div>)
258
+
259
+ # submit button
260
+ when 'submit'
261
+ # It's dirty hack, but will prevent not authorized message and render index action correctly
262
+ parms[:filter] = 'on'
263
+ url = url_for(parms) rescue 'URL error'
264
+ clas = 'ar-action-submit'
265
+ %(<div class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}
266
+ data-request="#{request}" title="#{yaml['title']}">#{icon}#{caption}</div>)
267
+
268
+ # link button
269
+ when 'link'
270
+ yaml['html'] = agile_yaml_add_option(yaml['html'], class: 'ar-link')
271
+ link = agile_link_to(caption, yaml['icon'], parms, yaml['html'] )
272
+ (action_active ? link : caption).to_s
273
+
274
+ # open window
275
+ when 'window'
276
+ clas = 'ar-link ar-window-open'
277
+ %(<div class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}>#{icon}#{caption}</div>)
278
+
279
+ # popup dialog
280
+ when 'popup'
281
+ clas = 'ar-link ar-popup-open'
282
+ %(<div class="#{clas}" data-url="#{action_active ? url : ''}" #{html_data}>#{icon}#{caption}</div>)
283
+
284
+ else
285
+ 'Type error!'
286
+ end
287
+ "<li>#{code}</li>"
288
+ end
289
+
290
+ ############################################################################
291
+ # Add new option to yaml. Subroutine of agile_link_ajax_window_submit_action.
292
+ ############################################################################
293
+ def agile_yaml_add_option(source, options) #nodoc
294
+ options.each do |k, v|
295
+ key = k.to_s
296
+ source[key] ||= ''
297
+ # only if not already present
298
+ source[key] += " #{v}" unless source[key].match(v.to_s)
299
+ end
300
+ source
301
+ end
302
+
303
+ ############################################################################
304
+ # Log exception to rails log. Usefull for debugging eval errors.
305
+ ############################################################################
306
+ def agile_log_exception(exception, msg = '')
307
+ log = "\n*** ERROR ***\n"
308
+ log += exception ? "#{msg}: #{exception.message}\n#{exception.backtrace.first.inspect}\n" : msg.to_s
309
+ log += "\nAgileRails Form: #{AgileHelper.form_param(params)}, line: #{session[:form_processing]}\n"
310
+
311
+ logger.error log
312
+ end
313
+
314
+ ############################################################################
315
+ # Will return form id, to be used on each form for simpler css selecting.
316
+ ############################################################################
317
+ def agile_form_id
318
+ %( id=#{AgileHelper.form_param(params) || AgileHelper.table_param(params)} )
319
+ end
320
+
321
+ ############################################################################
322
+ # Will return form_name from parameter regardless if set as form_name or just f.
323
+ ############################################################################
324
+ def self.form_param(params)
325
+ params[:form_name] || params[:f]
326
+ end
327
+
328
+ ############################################################################
329
+ # Will return table name from parameter regardless if set as table or just t.
330
+ ############################################################################
331
+ def self.table_param(params)
332
+ params[:table] || params[:t]
333
+ end
334
+
335
+ ########################################################################
336
+ # Searches forms path for file_name and returns full file name or nil if not found.
337
+ #
338
+ # @param [String] Form file name. File name can be passed as gem_name.filename. This can
339
+ # be useful when you are extending form but want to retain same name as original form
340
+ # For example. You are extending agile_user form from AgileRails gem and want to
341
+ # retain same agile_user form name, because it is used in AgileRails application menu.
342
+ # This can be done by setting agile_rails.agile_user as extend option.
343
+ #
344
+ # @return [String] Form file name including path or nil if not found.
345
+ ########################################################################
346
+ def self.form_file_find(form_file)
347
+ form_path = nil
348
+ form_path, form_file = form_file.split(/\.|\//) if form_file.match(/\.|\//)
349
+
350
+ Agile.paths(:forms).reverse.each do |path|
351
+ f = "#{path}/#{form_file}.yml"
352
+ return f if File.exist?(f) && (form_path.nil? || path.to_s.match(/\/#{form_path}(-|\/)/i))
353
+ end
354
+ raise "Exception: Form file #{form_file}.yml not found!"
355
+ end
356
+
357
+ ########################################################################
358
+ # Merges two forms when current form extends other form. Subroutine of agile_form_read.
359
+ # With a little help of https://www.ruby-forum.com/topic/142809
360
+ ########################################################################
361
+ def self.forms_merge(hash1, hash2)
362
+ target = hash1.dup
363
+ hash2.keys.each do |key|
364
+ if hash2[key].is_a?(Hash) && hash1[key].is_a?(Hash)
365
+ target[key] = AgileHelper.forms_merge(hash1[key], hash2[key])
366
+ next
367
+ end
368
+ target[key] = hash2[key] == '/' ? nil : hash2[key]
369
+ end
370
+ # delete keys with nil value
371
+ target.delete_if { |k, v| v.nil? }
372
+ end
373
+
374
+ ####################################################################
375
+ # Wrapper for i18 t method, with some spice added. If translation is not found English
376
+ # translation value will be returned. And if still not found default value will be returned if passed.
377
+ #
378
+ # Parameters:
379
+ # [key] String. String to be translated into locale.
380
+ # [default] String. Value returned if translation is not found.
381
+ #
382
+ # Example:
383
+ # t('translate.this','Enter text for ....')
384
+ #
385
+ # Returns:
386
+ # String. Translated text.
387
+ ####################################################################
388
+ def self.t(key, default = nil)
389
+ return default if key.nil?
390
+
391
+ c = I18n.t(key)
392
+ if c.class == Hash || c.match(/translation missing/i)
393
+ c = I18n.t(key, locale: 'en')
394
+ # Still not found. Return default if set
395
+ if c.class == Hash || c.match(/translation missing/i)
396
+ c = default.nil? ? key : default
397
+ end
398
+ end
399
+ c
400
+ end
401
+
402
+ ###########################################################################
403
+ # When select field is used on form options for select can be provided by
404
+ # helpers.label.table_name.choices_for_name locale. This is how select
405
+ # field options are translated. Method returns selected choice translated
406
+ # to current locale.
407
+ #
408
+ # Parameters:
409
+ # [model] String. Table (table) model name (lowercase).
410
+ # [field] String. Field name used.
411
+ # [value] String. Value of field which translation will be returned.
412
+ #
413
+ # Example:
414
+ # # usage in program. Choice values for state are 'Deactivated:0,Active:1,Waiting:2'
415
+ # agile_text_for_value('agile_user', 'state', @record.active )
416
+ #
417
+ # # usage in form
418
+ # columns:
419
+ # 2:
420
+ # name: state
421
+ # eval: agile_text_for_value agile_user, state
422
+ #
423
+ # Returns:
424
+ # String. Descriptive text (translated) for selected choice value.
425
+ ############################################################################
426
+ def self.name_for_value(model, field, value)
427
+ return '' if value.nil?
428
+
429
+ choices = t("helpers.label.#{model}.choices_for_#{field}")
430
+ values = choices.chomp.split(',').map{ _1.split(':') }
431
+ values.each{ |e| return e.first if e.last.to_s == value.to_s }
432
+ '???'
433
+ end
434
+
435
+ ############################################################################
436
+ # Returns html code for displaying date/time formatted by strftime. Will return '' if value is nil.
437
+ #
438
+ # Parameters:
439
+ # [value] Date/DateTime/Time.
440
+ # [format] String. strftime format mask. Defaults to locale's default format.
441
+ ############################################################################
442
+ def self.format_date_time(value, format = nil)
443
+ return '' if value.blank?
444
+
445
+ format ||= value.class == Date ? t('date.formats.default') : t('time.formats.default')
446
+ if format.size == 1
447
+ format = format.match(/d/i) ? t('date.formats.default') : t('time.formats.default')
448
+ end
449
+ #value.localtime.strftime(format)
450
+ value.strftime(format)
451
+ end
452
+
453
+ ############################################################################
454
+ # Returns html code for displaying formatted number.
455
+ #
456
+ # Parameters:
457
+ # [value] Numeric number.
458
+ # [decimals] Integer. Number of decimals
459
+ # [separator] String. Decimals separator
460
+ # [delimiter] String. Thousands delimiter.
461
+ # [currency] String. Currency symbol if applied to result string.
462
+ ############################################################################
463
+ def self.format_number(value = 0, decimals = nil, separator = nil, delimiter = nil, currency = nil)
464
+ decimals ||= I18n.t('number.currency.format.precision')
465
+ separator ||= I18n.t('number.currency.format.separator')
466
+ separator = '' if decimals == 0
467
+ delimiter ||= I18n.t('number.currency.format.delimiter')
468
+ whole, dec = value.to_s.split('.')
469
+ whole = '0' if whole.blank?
470
+ # remove and remember sign
471
+ sign = ''
472
+ if whole[0] == '-'
473
+ whole.delete_prefix!('-')
474
+ sign = '-'
475
+ end
476
+ # format decimals
477
+ dec ||= '0'
478
+ dec = dec.ljust(decimals, '0')[0, decimals]
479
+ # slice whole on chunks of 3
480
+ whole_a = []
481
+ while whole.size > 0 do
482
+ n = whole.size >= 3 ? 3 : whole.size
483
+ whole_a << whole.slice!(n*-1, n)
484
+ end
485
+ # put it all back
486
+ "#{sign}#{whole_a.reverse.join(delimiter)}#{separator}#{dec}"
487
+ end
488
+
489
+ ####################################################################
490
+ # Returns true if parameter has value of 0, false, no, none or -.
491
+ # Returns value of default if parameter has nil value.
492
+ #
493
+ # Parameters:
494
+ # [what] String/boolean/Integer.
495
+ # [default] Default value when what has value of nil. False by default.
496
+ #
497
+ # Example:
498
+ # agile_dont?('none') # => true
499
+ # agile_dont?('-') # => true
500
+ # agile_dont?(1) # => false
501
+ # agile_dont?(nil, true) # => true
502
+ ####################################################################
503
+ def self.dont?(what, default = false)
504
+ return default if what.nil?
505
+
506
+ %w(0 n - no none false).include?(what.to_s.downcase.strip)
507
+ end
508
+
509
+ end