inline_forms 8.1.21 → 8.1.42

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 (424) hide show
  1. checksums.yaml +4 -4
  2. data/.forgejo/workflows/ci.yml +63 -0
  3. data/.forgejo/workflows/full-gate.yml +77 -0
  4. data/.gitignore +10 -5
  5. data/.rubocop.yml +31 -0
  6. data/.rubocop_todo.yml +151 -0
  7. data/CHANGELOG.md +305 -0
  8. data/CLAUDE.md +68 -0
  9. data/Gemfile +18 -2
  10. data/README.rdoc +23 -6
  11. data/Rakefile +53 -12
  12. data/app/assets/fonts/opensans-v44-latin-italic.woff2 +0 -0
  13. data/app/assets/fonts/opensans-v44-latin-regular.woff2 +0 -0
  14. data/app/assets/javascripts/inline_forms/inline_forms.js +30 -43
  15. data/app/assets/stylesheets/inline_forms/_foundation_icons.scss +6 -12
  16. data/app/assets/stylesheets/inline_forms/_theme.scss +134 -0
  17. data/app/assets/stylesheets/inline_forms/devise.scss +14 -13
  18. data/app/assets/stylesheets/inline_forms/foundation_and_overrides.scss +4 -0
  19. data/app/assets/stylesheets/inline_forms/inline_forms.scss +59 -68
  20. data/app/assets/stylesheets/inline_forms_fonts.css.erb +39 -0
  21. data/app/controllers/inline_forms_application_controller.rb +8 -4
  22. data/app/controllers/inline_forms_controller.rb +88 -14
  23. data/app/helpers/inline_forms_helper.rb +58 -15
  24. data/app/models/concerns/inline_forms/soft_deletable.rb +11 -12
  25. data/app/validators/curacao_id_number_validator.rb +5 -6
  26. data/app/validators/is_curacao_phone_validator.rb +2 -3
  27. data/app/validators/is_email_address_validator.rb +3 -3
  28. data/app/validators/must_be_a_value_validator.rb +6 -6
  29. data/app/views/inline_forms/_new.html.erb +4 -1
  30. data/app/views/inline_forms/_pending_migration_row.html.erb +15 -0
  31. data/app/views/inline_forms/_show.html.erb +5 -2
  32. data/app/views/inline_forms/field_pending.html.erb +10 -0
  33. data/app/views/layouts/application.html.erb +6 -3
  34. data/app/views/layouts/devise.html.erb +1 -0
  35. data/app/views/layouts/inline_forms.html.erb +7 -4
  36. data/archived/README.md +2 -0
  37. data/archived/form_elements/dns_records/README.md +25 -0
  38. data/archived/form_elements/question_list/README.md +25 -0
  39. data/inline_forms.gemspec +8 -7
  40. data/lib/generators/inline_forms_addto/USAGE +31 -0
  41. data/lib/generators/inline_forms_addto_generator.rb +198 -26
  42. data/lib/generators/inline_forms_attribute_overrides.rb +3 -2
  43. data/lib/generators/templates/application_record.rb +1 -1
  44. data/lib/inline_forms/archived_form_elements.rb +23 -10
  45. data/lib/inline_forms/attribute_list.rb +191 -0
  46. data/lib/inline_forms/form_element_from_callee.rb +1 -0
  47. data/lib/inline_forms/form_element_registry.rb +32 -32
  48. data/lib/inline_forms/form_elements/color_field_helper.rb +44 -0
  49. data/lib/inline_forms/form_elements/date_helper.rb +4 -1
  50. data/lib/inline_forms/form_elements/dropdown_with_other_helper.rb +25 -113
  51. data/lib/inline_forms/form_elements/month_year_picker_helper.rb +13 -2
  52. data/lib/inline_forms/form_elements/multi_image_field_helper.rb +18 -6
  53. data/lib/inline_forms/form_elements/slider_with_values_helper.rb +31 -64
  54. data/lib/inline_forms/form_elements/time_helper.rb +3 -1
  55. data/lib/inline_forms/gem_files.rb +27 -0
  56. data/lib/inline_forms/schema_apply.rb +85 -0
  57. data/lib/inline_forms/schema_intent.rb +76 -0
  58. data/lib/inline_forms/schema_label.rb +65 -0
  59. data/lib/inline_forms/schema_preview.rb +135 -0
  60. data/lib/inline_forms/tabs.rb +175 -0
  61. data/lib/inline_forms/turbo_tabs_builder.rb +20 -13
  62. data/lib/inline_forms/version.rb +2 -1
  63. data/lib/inline_forms.rb +145 -45
  64. data/lib/locales/inline_forms.en.yml +2 -0
  65. data/lib/locales/inline_forms.nl.yml +2 -0
  66. data/test/archived_form_elements_test.rb +34 -4
  67. data/test/attribute_list_test.rb +165 -0
  68. data/test/dummy/app/controllers/application_controller.rb +24 -0
  69. data/test/dummy/app/controllers/gizmos_controller.rb +4 -0
  70. data/test/dummy/app/controllers/machines_controller.rb +4 -0
  71. data/test/dummy/app/controllers/parts_controller.rb +4 -0
  72. data/test/dummy/app/controllers/widgets_controller.rb +4 -0
  73. data/test/dummy/app/helpers/application_helper.rb +13 -0
  74. data/test/dummy/app/models/application_record.rb +26 -0
  75. data/test/dummy/app/models/gizmo.rb +25 -0
  76. data/test/dummy/app/models/kind.rb +8 -0
  77. data/test/dummy/app/models/machine.rb +23 -0
  78. data/test/dummy/app/models/part.rb +16 -0
  79. data/test/dummy/app/models/widget.rb +39 -0
  80. data/test/dummy/app/views/_inline_forms_tabs.html.erb +40 -0
  81. data/test/dummy/config/application.rb +37 -0
  82. data/test/dummy/config/database.yml +3 -0
  83. data/test/dummy/config/environment.rb +5 -0
  84. data/test/dummy/config/initializers/inline_forms.rb +6 -0
  85. data/test/dummy/config/initializers/paper_trail_yaml_safe_load.rb +28 -0
  86. data/test/dummy/config/routes.rb +31 -0
  87. data/test/inline_forms_addto_generator_test.rb +220 -0
  88. data/test/integration/inline_forms_crud_test.rb +141 -0
  89. data/test/integration/legacy_elements_test.rb +42 -0
  90. data/test/integration/native_inputs_test.rb +138 -0
  91. data/test/integration/open_after_create_test.rb +85 -0
  92. data/test/integration/pending_migration_gate_test.rb +75 -0
  93. data/test/integration/schema_batch_pipeline_test.rb +189 -0
  94. data/test/integration/schema_edit_test.rb +141 -0
  95. data/test/integration/schema_preview_test.rb +65 -0
  96. data/test/integration_test_helper.rb +121 -0
  97. data/test/plain_text_configuration_test.rb +3 -3
  98. data/test/schema_apply_test.rb +73 -0
  99. data/test/schema_intent_test.rb +53 -0
  100. data/test/schema_label_test.rb +61 -0
  101. data/test/tabs_test.rb +98 -0
  102. data/test/user_model_config_test.rb +1 -0
  103. data/vendor/assets/javascripts/trix.min.js +7 -0
  104. data/vendor/assets/stylesheets/trix.css +470 -0
  105. metadata +91 -320
  106. data/app/assets/images/jquery-ui/animated-overlay.gif +0 -0
  107. data/app/assets/images/jquery-ui/ui-bg_diagonal-maze_20_6e4f1c_10x10.png +0 -0
  108. data/app/assets/images/jquery-ui/ui-bg_diagonal-maze_40_000000_10x10.png +0 -0
  109. data/app/assets/images/jquery-ui/ui-bg_diagonals-medium_20_d34d17_40x40.png +0 -0
  110. data/app/assets/images/jquery-ui/ui-bg_diagonals-small_0_aaaaaa_40x40.png +0 -0
  111. data/app/assets/images/jquery-ui/ui-bg_diagonals-small_25_c5ddfc_40x40.png +0 -0
  112. data/app/assets/images/jquery-ui/ui-bg_diagonals-small_40_db4865_40x40.png +0 -0
  113. data/app/assets/images/jquery-ui/ui-bg_diagonals-small_50_262626_40x40.png +0 -0
  114. data/app/assets/images/jquery-ui/ui-bg_diagonals-small_50_93c3cd_40x40.png +0 -0
  115. data/app/assets/images/jquery-ui/ui-bg_diagonals-small_50_ff3853_40x40.png +0 -0
  116. data/app/assets/images/jquery-ui/ui-bg_diagonals-small_75_ccd232_40x40.png +0 -0
  117. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_15_0b3e6f_40x40.png +0 -0
  118. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_15_444444_40x40.png +0 -0
  119. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  120. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  121. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_20_e69700_40x40.png +0 -0
  122. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_22_1484e6_40x40.png +0 -0
  123. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_26_2293f7_40x40.png +0 -0
  124. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_75_f3d8d8_40x40.png +0 -0
  125. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_8_333333_40x40.png +0 -0
  126. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_90_eeeeee_40x40.png +0 -0
  127. data/app/assets/images/jquery-ui/ui-bg_diagonals-thick_95_ffdc2e_40x40.png +0 -0
  128. data/app/assets/images/jquery-ui/ui-bg_diamond_10_4f4221_10x8.png +0 -0
  129. data/app/assets/images/jquery-ui/ui-bg_diamond_20_372806_10x8.png +0 -0
  130. data/app/assets/images/jquery-ui/ui-bg_diamond_25_675423_10x8.png +0 -0
  131. data/app/assets/images/jquery-ui/ui-bg_diamond_25_d5ac5d_10x8.png +0 -0
  132. data/app/assets/images/jquery-ui/ui-bg_diamond_8_261803_10x8.png +0 -0
  133. data/app/assets/images/jquery-ui/ui-bg_diamond_8_443113_10x8.png +0 -0
  134. data/app/assets/images/jquery-ui/ui-bg_dots-medium_30_0b58a2_4x4.png +0 -0
  135. data/app/assets/images/jquery-ui/ui-bg_dots-medium_80_ffff38_4x4.png +0 -0
  136. data/app/assets/images/jquery-ui/ui-bg_dots-small_20_333333_2x2.png +0 -0
  137. data/app/assets/images/jquery-ui/ui-bg_dots-small_30_a32d00_2x2.png +0 -0
  138. data/app/assets/images/jquery-ui/ui-bg_dots-small_35_35414f_2x2.png +0 -0
  139. data/app/assets/images/jquery-ui/ui-bg_dots-small_40_00498f_2x2.png +0 -0
  140. data/app/assets/images/jquery-ui/ui-bg_dots-small_65_a6a6a6_2x2.png +0 -0
  141. data/app/assets/images/jquery-ui/ui-bg_fine-grain_10_eceadf_60x60.png +0 -0
  142. data/app/assets/images/jquery-ui/ui-bg_fine-grain_10_f8f7f6_60x60.png +0 -0
  143. data/app/assets/images/jquery-ui/ui-bg_fine-grain_15_eceadf_60x60.png +0 -0
  144. data/app/assets/images/jquery-ui/ui-bg_fine-grain_15_f7f3de_60x60.png +0 -0
  145. data/app/assets/images/jquery-ui/ui-bg_fine-grain_15_ffffff_60x60.png +0 -0
  146. data/app/assets/images/jquery-ui/ui-bg_fine-grain_65_654b24_60x60.png +0 -0
  147. data/app/assets/images/jquery-ui/ui-bg_fine-grain_68_b83400_60x60.png +0 -0
  148. data/app/assets/images/jquery-ui/ui-bg_flat_0_303030_40x100.png +0 -0
  149. data/app/assets/images/jquery-ui/ui-bg_flat_0_333333_40x100.png +0 -0
  150. data/app/assets/images/jquery-ui/ui-bg_flat_0_4c4c4c_40x100.png +0 -0
  151. data/app/assets/images/jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  152. data/app/assets/images/jquery-ui/ui-bg_flat_0_e69700_40x100.png +0 -0
  153. data/app/assets/images/jquery-ui/ui-bg_flat_0_e6b900_40x100.png +0 -0
  154. data/app/assets/images/jquery-ui/ui-bg_flat_0_eeeeee_40x100.png +0 -0
  155. data/app/assets/images/jquery-ui/ui-bg_flat_10_000000_40x100.png +0 -0
  156. data/app/assets/images/jquery-ui/ui-bg_flat_15_cd0a0a_40x100.png +0 -0
  157. data/app/assets/images/jquery-ui/ui-bg_flat_30_cccccc_40x100.png +0 -0
  158. data/app/assets/images/jquery-ui/ui-bg_flat_40_292929_40x100.png +0 -0
  159. data/app/assets/images/jquery-ui/ui-bg_flat_50_5c5c5c_40x100.png +0 -0
  160. data/app/assets/images/jquery-ui/ui-bg_flat_55_994d53_40x100.png +0 -0
  161. data/app/assets/images/jquery-ui/ui-bg_flat_55_999999_40x100.png +0 -0
  162. data/app/assets/images/jquery-ui/ui-bg_flat_55_c0402a_40x100.png +0 -0
  163. data/app/assets/images/jquery-ui/ui-bg_flat_55_eeeeee_40x100.png +0 -0
  164. data/app/assets/images/jquery-ui/ui-bg_flat_55_fafafa_40x100.png +0 -0
  165. data/app/assets/images/jquery-ui/ui-bg_flat_55_fbec88_40x100.png +0 -0
  166. data/app/assets/images/jquery-ui/ui-bg_flat_55_ffffff_40x100.png +0 -0
  167. data/app/assets/images/jquery-ui/ui-bg_flat_65_ffffff_40x100.png +0 -0
  168. data/app/assets/images/jquery-ui/ui-bg_flat_75_aaaaaa_40x100.png +0 -0
  169. data/app/assets/images/jquery-ui/ui-bg_flat_75_ba9217_40x100.png +0 -0
  170. data/app/assets/images/jquery-ui/ui-bg_flat_75_ddd4b0_40x100.png +0 -0
  171. data/app/assets/images/jquery-ui/ui-bg_flat_75_ffffff_40x100.png +0 -0
  172. data/app/assets/images/jquery-ui/ui-bg_glass_100_e4f1fb_1x400.png +0 -0
  173. data/app/assets/images/jquery-ui/ui-bg_glass_100_f5f0e5_1x400.png +0 -0
  174. data/app/assets/images/jquery-ui/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  175. data/app/assets/images/jquery-ui/ui-bg_glass_100_f8f8f8_1x400.png +0 -0
  176. data/app/assets/images/jquery-ui/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  177. data/app/assets/images/jquery-ui/ui-bg_glass_15_5f391b_1x400.png +0 -0
  178. data/app/assets/images/jquery-ui/ui-bg_glass_20_555555_1x400.png +0 -0
  179. data/app/assets/images/jquery-ui/ui-bg_glass_25_cb842e_1x400.png +0 -0
  180. data/app/assets/images/jquery-ui/ui-bg_glass_35_dddddd_1x400.png +0 -0
  181. data/app/assets/images/jquery-ui/ui-bg_glass_40_0078a3_1x400.png +0 -0
  182. data/app/assets/images/jquery-ui/ui-bg_glass_40_0a0a0a_1x400.png +0 -0
  183. data/app/assets/images/jquery-ui/ui-bg_glass_40_111111_1x400.png +0 -0
  184. data/app/assets/images/jquery-ui/ui-bg_glass_40_ffc73d_1x400.png +0 -0
  185. data/app/assets/images/jquery-ui/ui-bg_glass_45_0078ae_1x400.png +0 -0
  186. data/app/assets/images/jquery-ui/ui-bg_glass_50_3baae3_1x400.png +0 -0
  187. data/app/assets/images/jquery-ui/ui-bg_glass_55_1c1c1c_1x400.png +0 -0
  188. data/app/assets/images/jquery-ui/ui-bg_glass_55_f1fbe5_1x400.png +0 -0
  189. data/app/assets/images/jquery-ui/ui-bg_glass_55_f8da4e_1x400.png +0 -0
  190. data/app/assets/images/jquery-ui/ui-bg_glass_55_fbf5d0_1x400.png +0 -0
  191. data/app/assets/images/jquery-ui/ui-bg_glass_55_fbf8ee_1x400.png +0 -0
  192. data/app/assets/images/jquery-ui/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  193. data/app/assets/images/jquery-ui/ui-bg_glass_55_fcf0ba_1x400.png +0 -0
  194. data/app/assets/images/jquery-ui/ui-bg_glass_60_000000_1x400.png +0 -0
  195. data/app/assets/images/jquery-ui/ui-bg_glass_60_eeeeee_1x400.png +0 -0
  196. data/app/assets/images/jquery-ui/ui-bg_glass_65_ffffff_1x400.png +0 -0
  197. data/app/assets/images/jquery-ui/ui-bg_glass_70_ede4d4_1x400.png +0 -0
  198. data/app/assets/images/jquery-ui/ui-bg_glass_75_79c9ec_1x400.png +0 -0
  199. data/app/assets/images/jquery-ui/ui-bg_glass_75_d0e5f5_1x400.png +0 -0
  200. data/app/assets/images/jquery-ui/ui-bg_glass_75_dadada_1x400.png +0 -0
  201. data/app/assets/images/jquery-ui/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  202. data/app/assets/images/jquery-ui/ui-bg_glass_80_d7ebf9_1x400.png +0 -0
  203. data/app/assets/images/jquery-ui/ui-bg_glass_85_dfeffc_1x400.png +0 -0
  204. data/app/assets/images/jquery-ui/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  205. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_100_ece8da_500x100.png +0 -0
  206. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_16_121212_500x100.png +0 -0
  207. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_20_111111_500x100.png +0 -0
  208. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_20_1c160d_500x100.png +0 -0
  209. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_25_333333_500x100.png +0 -0
  210. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_25_453326_500x100.png +0 -0
  211. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_30_3d3644_500x100.png +0 -0
  212. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_30_44372c_500x100.png +0 -0
  213. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  214. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_45_817865_500x100.png +0 -0
  215. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_45_e14f1c_500x100.png +0 -0
  216. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_50_6eac2c_500x100.png +0 -0
  217. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_55_000000_500x100.png +0 -0
  218. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_55_5c9ccc_500x100.png +0 -0
  219. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_60_fece2f_500x100.png +0 -0
  220. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_70_ffdd57_500x100.png +0 -0
  221. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_75_2191c0_500x100.png +0 -0
  222. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_85_9fda58_500x100.png +0 -0
  223. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_90_fff9e5_500x100.png +0 -0
  224. data/app/assets/images/jquery-ui/ui-bg_gloss-wave_95_f6ecd5_500x100.png +0 -0
  225. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_100_eeeeee_1x100.png +0 -0
  226. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_100_f2f5f7_1x100.png +0 -0
  227. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_100_f4f0ec_1x100.png +0 -0
  228. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_100_f5f3e5_1x100.png +0 -0
  229. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_100_f6f6f6_1x100.png +0 -0
  230. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_100_f9f9f9_1x100.png +0 -0
  231. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_100_fafaf4_1x100.png +0 -0
  232. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_15_459e00_1x100.png +0 -0
  233. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_15_888888_1x100.png +0 -0
  234. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_20_0972a5_1x100.png +0 -0
  235. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_30_285c00_1x100.png +0 -0
  236. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_40_aaaaaa_1x100.png +0 -0
  237. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_55_555555_1x100.png +0 -0
  238. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_65_fee4bd_1x100.png +0 -0
  239. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_70_000000_1x100.png +0 -0
  240. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_75_f5f5b5_1x100.png +0 -0
  241. data/app/assets/images/jquery-ui/ui-bg_highlight-hard_95_cccccc_1x100.png +0 -0
  242. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_100_dcd9de_1x100.png +0 -0
  243. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_100_deedf7_1x100.png +0 -0
  244. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_100_eae6ea_1x100.png +0 -0
  245. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  246. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_100_f6f6f6_1x100.png +0 -0
  247. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_100_f9f9f9_1x100.png +0 -0
  248. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_100_feeebd_1x100.png +0 -0
  249. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_15_cc0000_1x100.png +0 -0
  250. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_20_201913_1x100.png +0 -0
  251. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_20_619226_1x100.png +0 -0
  252. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_25_0073ea_1x100.png +0 -0
  253. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_25_30273a_1x100.png +0 -0
  254. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_25_67b021_1x100.png +0 -0
  255. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_25_ffef8f_1x100.png +0 -0
  256. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_33_003147_1x100.png +0 -0
  257. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_33_3a8104_1x100.png +0 -0
  258. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_35_222222_1x100.png +0 -0
  259. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_35_adadad_1x100.png +0 -0
  260. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_44_444444_1x100.png +0 -0
  261. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_45_5f5964_1x100.png +0 -0
  262. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_50_4eb305_1x100.png +0 -0
  263. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_50_aaaaaa_1x100.png +0 -0
  264. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_50_dddddd_1x100.png +0 -0
  265. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_60_4ca20b_1x100.png +0 -0
  266. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_60_dddddd_1x100.png +0 -0
  267. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  268. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  269. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_80_eeeeee_1x100.png +0 -0
  270. data/app/assets/images/jquery-ui/ui-bg_highlight-soft_95_ffedad_1x100.png +0 -0
  271. data/app/assets/images/jquery-ui/ui-bg_inset-hard_100_eeeeee_1x100.png +0 -0
  272. data/app/assets/images/jquery-ui/ui-bg_inset-hard_100_f5f8f9_1x100.png +0 -0
  273. data/app/assets/images/jquery-ui/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
  274. data/app/assets/images/jquery-ui/ui-bg_inset-hard_45_cd0a0a_1x100.png +0 -0
  275. data/app/assets/images/jquery-ui/ui-bg_inset-hard_55_ffeb80_1x100.png +0 -0
  276. data/app/assets/images/jquery-ui/ui-bg_inset-hard_75_999999_1x100.png +0 -0
  277. data/app/assets/images/jquery-ui/ui-bg_inset-soft_100_f4f0ec_1x100.png +0 -0
  278. data/app/assets/images/jquery-ui/ui-bg_inset-soft_10_201913_1x100.png +0 -0
  279. data/app/assets/images/jquery-ui/ui-bg_inset-soft_10_285c00_1x100.png +0 -0
  280. data/app/assets/images/jquery-ui/ui-bg_inset-soft_15_121212_1x100.png +0 -0
  281. data/app/assets/images/jquery-ui/ui-bg_inset-soft_15_2b2922_1x100.png +0 -0
  282. data/app/assets/images/jquery-ui/ui-bg_inset-soft_25_000000_1x100.png +0 -0
  283. data/app/assets/images/jquery-ui/ui-bg_inset-soft_30_f58400_1x100.png +0 -0
  284. data/app/assets/images/jquery-ui/ui-bg_inset-soft_30_ffffff_1x100.png +0 -0
  285. data/app/assets/images/jquery-ui/ui-bg_inset-soft_50_c9c9c9_1x100.png +0 -0
  286. data/app/assets/images/jquery-ui/ui-bg_loop_25_000000_21x21.png +0 -0
  287. data/app/assets/images/jquery-ui/ui-bg_white-lines_85_f7f7ba_40x100.png +0 -0
  288. data/app/assets/images/jquery-ui/ui-icons_000000_256x240.png +0 -0
  289. data/app/assets/images/jquery-ui/ui-icons_004276_256x240.png +0 -0
  290. data/app/assets/images/jquery-ui/ui-icons_00498f_256x240.png +0 -0
  291. data/app/assets/images/jquery-ui/ui-icons_0073ea_256x240.png +0 -0
  292. data/app/assets/images/jquery-ui/ui-icons_0078ae_256x240.png +0 -0
  293. data/app/assets/images/jquery-ui/ui-icons_056b93_256x240.png +0 -0
  294. data/app/assets/images/jquery-ui/ui-icons_070603_256x240.png +0 -0
  295. data/app/assets/images/jquery-ui/ui-icons_0a82eb_256x240.png +0 -0
  296. data/app/assets/images/jquery-ui/ui-icons_0b54d5_256x240.png +0 -0
  297. data/app/assets/images/jquery-ui/ui-icons_1f1f1f_256x240.png +0 -0
  298. data/app/assets/images/jquery-ui/ui-icons_217bc0_256x240.png +0 -0
  299. data/app/assets/images/jquery-ui/ui-icons_222222_256x240.png +0 -0
  300. data/app/assets/images/jquery-ui/ui-icons_228ef1_256x240.png +0 -0
  301. data/app/assets/images/jquery-ui/ui-icons_2694e8_256x240.png +0 -0
  302. data/app/assets/images/jquery-ui/ui-icons_2e83ff_256x240.png +0 -0
  303. data/app/assets/images/jquery-ui/ui-icons_3383bb_256x240.png +0 -0
  304. data/app/assets/images/jquery-ui/ui-icons_3572ac_256x240.png +0 -0
  305. data/app/assets/images/jquery-ui/ui-icons_3d3d3d_256x240.png +0 -0
  306. data/app/assets/images/jquery-ui/ui-icons_3d80b3_256x240.png +0 -0
  307. data/app/assets/images/jquery-ui/ui-icons_454545_256x240.png +0 -0
  308. data/app/assets/images/jquery-ui/ui-icons_469bdd_256x240.png +0 -0
  309. data/app/assets/images/jquery-ui/ui-icons_4b8e0b_256x240.png +0 -0
  310. data/app/assets/images/jquery-ui/ui-icons_4ca300_256x240.png +0 -0
  311. data/app/assets/images/jquery-ui/ui-icons_4eb305_256x240.png +0 -0
  312. data/app/assets/images/jquery-ui/ui-icons_5fa5e3_256x240.png +0 -0
  313. data/app/assets/images/jquery-ui/ui-icons_666666_256x240.png +0 -0
  314. data/app/assets/images/jquery-ui/ui-icons_6da8d5_256x240.png +0 -0
  315. data/app/assets/images/jquery-ui/ui-icons_70b2e1_256x240.png +0 -0
  316. data/app/assets/images/jquery-ui/ui-icons_72a7cf_256x240.png +0 -0
  317. data/app/assets/images/jquery-ui/ui-icons_72b42d_256x240.png +0 -0
  318. data/app/assets/images/jquery-ui/ui-icons_734d99_256x240.png +0 -0
  319. data/app/assets/images/jquery-ui/ui-icons_808080_256x240.png +0 -0
  320. data/app/assets/images/jquery-ui/ui-icons_847e71_256x240.png +0 -0
  321. data/app/assets/images/jquery-ui/ui-icons_888888_256x240.png +0 -0
  322. data/app/assets/images/jquery-ui/ui-icons_88a206_256x240.png +0 -0
  323. data/app/assets/images/jquery-ui/ui-icons_8DC262_256x240.png +0 -0
  324. data/app/assets/images/jquery-ui/ui-icons_8c291d_256x240.png +0 -0
  325. data/app/assets/images/jquery-ui/ui-icons_8d78a5_256x240.png +0 -0
  326. data/app/assets/images/jquery-ui/ui-icons_98d2fb_256x240.png +0 -0
  327. data/app/assets/images/jquery-ui/ui-icons_999999_256x240.png +0 -0
  328. data/app/assets/images/jquery-ui/ui-icons_9bcc60_256x240.png +0 -0
  329. data/app/assets/images/jquery-ui/ui-icons_9ccdfc_256x240.png +0 -0
  330. data/app/assets/images/jquery-ui/ui-icons_9fda58_256x240.png +0 -0
  331. data/app/assets/images/jquery-ui/ui-icons_a83300_256x240.png +0 -0
  332. data/app/assets/images/jquery-ui/ui-icons_a8a3ae_256x240.png +0 -0
  333. data/app/assets/images/jquery-ui/ui-icons_aaaaaa_256x240.png +0 -0
  334. data/app/assets/images/jquery-ui/ui-icons_add978_256x240.png +0 -0
  335. data/app/assets/images/jquery-ui/ui-icons_b83400_256x240.png +0 -0
  336. data/app/assets/images/jquery-ui/ui-icons_b8ec79_256x240.png +0 -0
  337. data/app/assets/images/jquery-ui/ui-icons_bbbbbb_256x240.png +0 -0
  338. data/app/assets/images/jquery-ui/ui-icons_bd7b00_256x240.png +0 -0
  339. data/app/assets/images/jquery-ui/ui-icons_c02669_256x240.png +0 -0
  340. data/app/assets/images/jquery-ui/ui-icons_c47a23_256x240.png +0 -0
  341. data/app/assets/images/jquery-ui/ui-icons_c98000_256x240.png +0 -0
  342. data/app/assets/images/jquery-ui/ui-icons_cb672b_256x240.png +0 -0
  343. data/app/assets/images/jquery-ui/ui-icons_cc0000_256x240.png +0 -0
  344. data/app/assets/images/jquery-ui/ui-icons_cccccc_256x240.png +0 -0
  345. data/app/assets/images/jquery-ui/ui-icons_cd0a0a_256x240.png +0 -0
  346. data/app/assets/images/jquery-ui/ui-icons_d19405_256x240.png +0 -0
  347. data/app/assets/images/jquery-ui/ui-icons_d8e7f3_256x240.png +0 -0
  348. data/app/assets/images/jquery-ui/ui-icons_e0fdff_256x240.png +0 -0
  349. data/app/assets/images/jquery-ui/ui-icons_e1e463_256x240.png +0 -0
  350. data/app/assets/images/jquery-ui/ui-icons_e3ddc9_256x240.png +0 -0
  351. data/app/assets/images/jquery-ui/ui-icons_e8e2b5_256x240.png +0 -0
  352. data/app/assets/images/jquery-ui/ui-icons_e9cd86_256x240.png +0 -0
  353. data/app/assets/images/jquery-ui/ui-icons_eb990f_256x240.png +0 -0
  354. data/app/assets/images/jquery-ui/ui-icons_ebccce_256x240.png +0 -0
  355. data/app/assets/images/jquery-ui/ui-icons_ed9f26_256x240.png +0 -0
  356. data/app/assets/images/jquery-ui/ui-icons_ededed_256x240.png +0 -0
  357. data/app/assets/images/jquery-ui/ui-icons_eeeeee_256x240.png +0 -0
  358. data/app/assets/images/jquery-ui/ui-icons_ef8c08_256x240.png +0 -0
  359. data/app/assets/images/jquery-ui/ui-icons_efec9f_256x240.png +0 -0
  360. data/app/assets/images/jquery-ui/ui-icons_f08000_256x240.png +0 -0
  361. data/app/assets/images/jquery-ui/ui-icons_f1fd86_256x240.png +0 -0
  362. data/app/assets/images/jquery-ui/ui-icons_f29a00_256x240.png +0 -0
  363. data/app/assets/images/jquery-ui/ui-icons_f2ec64_256x240.png +0 -0
  364. data/app/assets/images/jquery-ui/ui-icons_f35f07_256x240.png +0 -0
  365. data/app/assets/images/jquery-ui/ui-icons_f5e175_256x240.png +0 -0
  366. data/app/assets/images/jquery-ui/ui-icons_f7a50d_256x240.png +0 -0
  367. data/app/assets/images/jquery-ui/ui-icons_f9bd01_256x240.png +0 -0
  368. data/app/assets/images/jquery-ui/ui-icons_f9f2bd_256x240.png +0 -0
  369. data/app/assets/images/jquery-ui/ui-icons_fadc7a_256x240.png +0 -0
  370. data/app/assets/images/jquery-ui/ui-icons_fbc856_256x240.png +0 -0
  371. data/app/assets/images/jquery-ui/ui-icons_fbdb93_256x240.png +0 -0
  372. data/app/assets/images/jquery-ui/ui-icons_fcd113_256x240.png +0 -0
  373. data/app/assets/images/jquery-ui/ui-icons_fcdd4a_256x240.png +0 -0
  374. data/app/assets/images/jquery-ui/ui-icons_ff0084_256x240.png +0 -0
  375. data/app/assets/images/jquery-ui/ui-icons_ff7519_256x240.png +0 -0
  376. data/app/assets/images/jquery-ui/ui-icons_ffcf29_256x240.png +0 -0
  377. data/app/assets/images/jquery-ui/ui-icons_ffd27a_256x240.png +0 -0
  378. data/app/assets/images/jquery-ui/ui-icons_ffe180_256x240.png +0 -0
  379. data/app/assets/images/jquery-ui/ui-icons_ffeb33_256x240.png +0 -0
  380. data/app/assets/images/jquery-ui/ui-icons_ffffff_256x240.png +0 -0
  381. data/app/assets/stylesheets/jquery_ui/jquery.ui.accordion.css.scss +0 -39
  382. data/app/assets/stylesheets/jquery_ui/jquery.ui.all.css.scss +0 -14
  383. data/app/assets/stylesheets/jquery_ui/jquery.ui.autocomplete.css.scss +0 -17
  384. data/app/assets/stylesheets/jquery_ui/jquery.ui.base.css.scss +0 -27
  385. data/app/assets/stylesheets/jquery_ui/jquery.ui.button.css.scss +0 -115
  386. data/app/assets/stylesheets/jquery_ui/jquery.ui.core.css.scss +0 -92
  387. data/app/assets/stylesheets/jquery_ui/jquery.ui.datepicker.css.scss +0 -179
  388. data/app/assets/stylesheets/jquery_ui/jquery.ui.dialog.css.scss +0 -70
  389. data/app/assets/stylesheets/jquery_ui/jquery.ui.menu.css.scss +0 -80
  390. data/app/assets/stylesheets/jquery_ui/jquery.ui.progressbar.css.scss +0 -29
  391. data/app/assets/stylesheets/jquery_ui/jquery.ui.resizable.css.scss +0 -79
  392. data/app/assets/stylesheets/jquery_ui/jquery.ui.selectable.css.scss +0 -16
  393. data/app/assets/stylesheets/jquery_ui/jquery.ui.slider.css.scss +0 -74
  394. data/app/assets/stylesheets/jquery_ui/jquery.ui.spinner.css.scss +0 -66
  395. data/app/assets/stylesheets/jquery_ui/jquery.ui.tabs.css.scss +0 -53
  396. data/app/assets/stylesheets/jquery_ui/jquery.ui.theme.css.scss +0 -408
  397. data/app/assets/stylesheets/jquery_ui/jquery.ui.tooltip.css.scss +0 -20
  398. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.base.css.scss +0 -78
  399. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.black-tie.css.scss +0 -80
  400. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.blitzer.css.scss +0 -80
  401. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.cupertino.css.scss +0 -80
  402. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.dark-hive.css.scss +0 -80
  403. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.dot-luv.css.scss +0 -80
  404. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.eggplant.css.scss +0 -80
  405. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.excite-bike.css.scss +0 -80
  406. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.flick.css.scss +0 -80
  407. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.hot-sneaks.css.scss +0 -80
  408. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.humanity.css.scss +0 -80
  409. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.le-frog.css.scss +0 -80
  410. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.mint-choc.css.scss +0 -80
  411. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.overcast.css.scss +0 -80
  412. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.pepper-grinder.css.scss +0 -80
  413. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.redmond.css.scss +0 -80
  414. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.smoothness.css.scss +0 -80
  415. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.south-street.css.scss +0 -80
  416. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.start.css.scss +0 -80
  417. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.sunny.css.scss +0 -80
  418. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.swanky-purse.css.scss +0 -80
  419. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.trontastic.css.scss +0 -80
  420. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.ui-darkness.css.scss +0 -80
  421. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.ui-lightness.css.scss +0 -80
  422. data/app/assets/stylesheets/jquery_ui/themes/_jquery.ui.vader.css.scss +0 -80
  423. /data/{lib → archived/form_elements/dns_records/lib}/inline_forms/form_elements/dns_records_helper.rb +0 -0
  424. /data/{lib → archived/form_elements/question_list/lib}/inline_forms/form_elements/question_list_helper.rb +0 -0
@@ -5,35 +5,34 @@ module InlineForms
5
5
  module_eval(<<~'INLINE_FORMS_FORM_ELEMENT', __FILE__, __LINE__ + 1)
6
6
  # -*- encoding : utf-8 -*-
7
7
 
8
- # slider_with_values
8
+ # slider_with_values -- native <input type="range"> since 8.1.26 (replaces
9
+ # the jQuery UI slider and its inline <script>). The label text next to the
10
+ # slider is kept in sync by initInlineFormsWidgets (class hook
11
+ # `slider_with_values`, labels in data-slider-values, target <output> id in
12
+ # data-slider-output); helpers emit no per-field scripts.
9
13
  def slider_with_values_show(object, attribute)
10
14
  values = attribute_values(object, attribute)
11
15
  value = object.send(attribute).to_i # should be an int
12
- display_value = values.assoc(value)[1] # values should be [ [ 0, value ], [ 3, value2 ] .... ] and we lookup the key, not the place in the array!
16
+ # values should be [ [ 0, value ], [ 3, value2 ] .... ] and we lookup the
17
+ # key, not the place in the array! A value with no entry (e.g. 0 when the
18
+ # values hash starts at 1) falls back to the bare number instead of
19
+ # crashing (pre-8.1.26 code did values.assoc(value)[1] unguarded).
20
+ display_value = (pair = values.assoc(value)) ? pair[1] : value.to_s
13
21
  css_id = "#{object.class.to_s.underscore}_#{object.id}_#{attribute}"
14
22
  if value == 0
15
23
  out = "?" # we use this as the 'unknown' value. So in the data, 0 should always be the unknown value. This gives problems with sliders where the real value is 0.
16
24
  else
25
+ # <progress> (not a disabled <input type=range>): the show panel is
26
+ # wrapped in the inline-edit link, and a disabled input would swallow
27
+ # the click; progress is non-interactive so the click-to-edit works.
17
28
  out = "".html_safe
18
- out << "<div class='slider slider_#{attribute.to_s}' id='slider_#{css_id}'></div>".html_safe
19
- out << "<div class='slider_value' id='value_#{css_id}'>#{display_value}</div>".html_safe
20
- out << "<div style='clear: both' />".html_safe
21
- out << "<input type='hidden' name='_#{object.class.to_s.underscore}[#{attribute}]' value='0' id='input_#{css_id}' />".html_safe
22
- out << ('<script>
23
- $(function() {
24
- var displayvalues = ' + values.collect {|x| x[1]}.inspect + ';
25
- $( "#slider_' + css_id + '" ).slider(
26
- {
27
- value:' + value.to_s + ',
28
- range: "min",
29
- disabled: true,
30
- min: 0,
31
- max: ' + values.length.to_s + ',
32
- step: 1,
33
- }
34
- );
35
- });
36
- </script>').html_safe
29
+ out << content_tag(:progress, nil,
30
+ value: value,
31
+ max: values.collect(&:first).max.to_i,
32
+ class: "slider slider_#{attribute}",
33
+ id: "slider_#{css_id}")
34
+ out << content_tag(:div, display_value, class: 'slider_value', id: "value_#{css_id}")
35
+ out << "<div style='clear: both'></div>".html_safe
37
36
  end
38
37
  link_to_inline_edit object, attribute, out, from_callee: __callee__
39
38
  end
@@ -43,56 +42,24 @@ module InlineForms
43
42
  values = attribute_values(object, attribute)
44
43
  value = object.send(attribute).to_i # should be an int, will be 0 if nil
45
44
  css_id = "#{object.class.to_s.underscore}_#{object.id}_#{attribute}"
46
- display_value = values.assoc(value)[1] # values should be [ [ 0, value ], [ 3, value2 ] .... ] and we lookup the key, not the place in the array!
45
+ display_value = (pair = values.assoc(value)) ? pair[1] : value.to_s
46
+ labels = values.collect { |x| x[1] }
47
47
  out = "".html_safe
48
- out << "<div class='slider slider_#{attribute.to_s}' id='slider_#{css_id}'></div>".html_safe
49
- out << "<div class='slider_value' id='value_#{css_id}'>#{display_value}</div>".html_safe
50
- out << "<div style='clear: both' />".html_safe
51
- out << "<input type='hidden' name='_#{object.class.to_s.underscore}[#{attribute}]' value='0' id='input_#{css_id}' />".html_safe
52
- out << ('<script>
53
- $(function() {
54
- var displayvalues = ' + values.collect {|x| x[1]}.inspect + ';
55
- $( "#slider_' + css_id + '" ).slider(
56
- {
57
- value:' + value.to_s + ',
58
- range: "min",
59
- min: 0,
60
- max: 5,
61
- step: 1,
62
- slide: function( event, ui ) {
63
- $( "#input_' + css_id + '" ).val( ui.value );
64
- $( "#value_' + css_id + '" ).html( displayvalues[ui.value] );
65
- }
66
- }
67
- );').html_safe
68
- out << ('$( "#value_' + css_id + '" ).html(displayvalues[' + value.to_s + ']);').html_safe
69
- out << ('$( "#input_' + css_id + '" ).val(' + value.to_s + ');').html_safe
70
- out << ('});
71
- </script>').html_safe
48
+ out << range_field_tag("_#{object.class.to_s.underscore}[#{attribute}]", value,
49
+ id: "input_#{css_id}",
50
+ class: "slider slider_#{attribute} slider_with_values",
51
+ in: 0..(values.collect(&:first).max.to_i),
52
+ step: 1,
53
+ data: { slider_values: labels.to_json,
54
+ slider_output: "value_#{css_id}" })
55
+ out << content_tag(:output, display_value, class: 'slider_value', id: "value_#{css_id}")
56
+ out << "<div style='clear: both'></div>".html_safe
72
57
  out
73
58
  end
74
59
 
75
60
  def slider_with_values_update(object, attribute)
76
61
  object[attribute.to_sym] = params[('_' + object.class.to_s.underscore).to_sym][attribute.to_sym]
77
62
  end
78
-
79
- #<style>
80
- # #demo-frame > div.demo { padding: 10px !important; };
81
- # </style>
82
- #
83
- #
84
- #
85
- #<div class="demo">
86
- #
87
- #<p>
88
- # <label for="amount">Donation amount ($50 increments):</label>
89
- # <input type="text" id="amount" style="border:0; color:#f6931f; font-weight:bold;" />
90
- #</p>
91
- #
92
- #<div id="slider"></div>
93
- #
94
- #</div><!-- End demo -->
95
- #
96
63
  INLINE_FORMS_FORM_ELEMENT
97
64
  end
98
65
  end
@@ -10,9 +10,11 @@ module InlineForms
10
10
  link_to_inline_edit object, attribute, object.send(attribute).nil? ? "<i class='fi-plus'></i>".html_safe : object.send(attribute).to_datetime.strftime("%l:%M%P"), from_callee: __callee__
11
11
  end
12
12
 
13
+ # Native <input type="time"> (8.1.25; replaces the jQuery timepicker).
14
+ # Submits 24h "HH:MM", which Active Record casts directly to a time column.
13
15
  def time_select_edit(object, attribute)
14
16
  css_id = 'timepicker_' + object.class.to_s.underscore + '_' + object.id.to_s + '_' + attribute.to_s
15
- out = text_field_tag attribute, ( object.send(attribute).nil? ? "" : object.send(attribute).to_datetime.strftime("%l:%M%P") ), :id => css_id, :class =>'timepicker'
17
+ time_field_tag attribute, ( object.send(attribute).nil? ? "" : object.send(attribute).to_datetime.strftime("%H:%M") ), :id => css_id, :class => 'time_select'
16
18
  end
17
19
 
18
20
  def time_select_update(object, attribute)
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
+
2
3
  module InlineFormsGemFiles
3
4
  INSTALLER_FILE_PREFIXES = %w[
4
5
  bin/inline_forms
@@ -8,6 +9,24 @@ module InlineFormsGemFiles
8
9
  inline_forms_installer.gemspec
9
10
  ].freeze
10
11
 
12
+ # The schema-GUI gem lives in its own subdirectory with its own gemspec
13
+ # (inline_forms_schema_edit/inline_forms_schema_edit.gemspec) and packages
14
+ # its files itself; exclude the whole subtree from BOTH gems here.
15
+ SCHEMA_GUI_FILE_PREFIXES = %w[
16
+ inline_forms_schema_edit/
17
+ ].freeze
18
+
19
+ # Scratch / local-notes dir. It holds working notes and, crucially, secrets
20
+ # such as stuff/forgejo-token (mode 0600, only used by CI pushes to forgejo).
21
+ # It must NEVER be packaged into a gem. Do not rely on git ignore for this:
22
+ # gem_files sweeps untracked files too, and the global excludes file that
23
+ # ignores stuff/ is per-machine (present here, absent on the release box), so
24
+ # the token leaked into `gem build` on the release machine. Exclude it hard,
25
+ # independent of any ignore configuration.
26
+ EXCLUDED_FILE_PREFIXES = %w[
27
+ stuff/
28
+ ].freeze
29
+
11
30
  module_function
12
31
 
13
32
  REPO_ROOT = File.expand_path("../..", __dir__)
@@ -31,6 +50,14 @@ module InlineFormsGemFiles
31
50
 
32
51
  files.select! { |f| File.file?(File.join(REPO_ROOT, f)) }
33
52
 
53
+ files.reject! do |f|
54
+ EXCLUDED_FILE_PREFIXES.any? { |prefix| f == prefix || f.start_with?(prefix) }
55
+ end
56
+
57
+ files.reject! do |f|
58
+ SCHEMA_GUI_FILE_PREFIXES.any? { |prefix| f == prefix || f.start_with?(prefix) }
59
+ end
60
+
34
61
  files.reject do |f|
35
62
  installer_file = INSTALLER_FILE_PREFIXES.any? { |prefix| f == prefix || f.start_with?(prefix) }
36
63
  include_installer ? !installer_file : installer_file
@@ -0,0 +1,85 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require "shellwords"
4
+
5
+ module InlineForms
6
+ # Skeleton of the "apply" step of the staging pipeline: turn an approved
7
+ # SchemaIntent into the ordered shell commands a developer would run by hand
8
+ # (generate the migration + model edit, migrate, test, commit, restart). This
9
+ # is the rare, expensive, deliberate step — see the staging doc.
10
+ #
11
+ # The engine does NOT execute these itself by default: which host runs them
12
+ # (a rake task on a single-server box, or a CI job after a PR on a clustered
13
+ # deploy) is an app decision. #commands returns the plan for inspection;
14
+ # #run! executes it via an injectable runner (defaults to Kernel#system) and
15
+ # stops at the first failure, so an app/rake task can opt in.
16
+ class SchemaApply
17
+ STEPS = %i[generate migrate].freeze
18
+
19
+ # In-process generate-only executor used by the schema GUI: runs the addto
20
+ # generator against the app's tree (edits the model, writes the migration
21
+ # file) but never migrates. Overridable so tests can record the args
22
+ # instead of mutating the working tree.
23
+ DEFAULT_GENERATE_EXECUTOR = lambda do |args, destination_root|
24
+ require "generators/inline_forms_addto_generator"
25
+ InlineFormsAddtoGenerator.start(args, destination_root: destination_root)
26
+ end
27
+
28
+ attr_reader :intent
29
+
30
+ def initialize(intent, runner: nil)
31
+ @intent = intent
32
+ @runner = runner || ->(cmd) { system(*cmd) }
33
+ end
34
+
35
+ # Run the addto generator in-process (model edit + migration file) WITHOUT
36
+ # running db:migrate. Returns the path of the migration it created (or nil
37
+ # when the executor did not create one, e.g. a recording test executor).
38
+ # The caller (GUI) then tells the user to run `rails db:migrate` + restart;
39
+ # the pending-migration gate covers the interim.
40
+ def generate!(destination_root:, executor: DEFAULT_GENERATE_EXECUTOR)
41
+ before = addto_migrations(destination_root)
42
+ executor.call(intent.generator_args, destination_root)
43
+ # Only report a migration this run actually created. nil is correct and
44
+ # expected for a :header (no column -> no migration) and must NOT fall
45
+ # back to a pre-existing migration file.
46
+ (addto_migrations(destination_root) - before).max
47
+ end
48
+
49
+ # `rails g inline_forms_addto <Model> <attr:fe> [--after=..]`.
50
+ def generator_command
51
+ %w[bundle exec rails g inline_forms_addto] + intent.generator_args
52
+ end
53
+
54
+ def migrate_command
55
+ %w[bundle exec rails db:migrate]
56
+ end
57
+
58
+ # Ordered plan (each value is an argv array).
59
+ def commands
60
+ { generate: generator_command, migrate: migrate_command }
61
+ end
62
+
63
+ # Human-readable plan (what an app would show before the user confirms).
64
+ def preview_plan
65
+ STEPS.map { |step| "#{step}: #{Shellwords.join(commands.fetch(step))}" }
66
+ end
67
+
68
+ # Execute generate -> migrate, stopping at the first failure. Returns the
69
+ # step that failed, or nil on success. NOT run in tests (would shell out);
70
+ # an app/rake task calls this after approval + a git-clean check.
71
+ def run!
72
+ STEPS.each do |step|
73
+ ok = @runner.call(commands.fetch(step))
74
+ return step unless ok
75
+ end
76
+ nil
77
+ end
78
+
79
+ private
80
+
81
+ def addto_migrations(destination_root)
82
+ Dir.glob(File.join(destination_root.to_s, "db", "migrate", "*_inline_forms_add_to_*.rb"))
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,76 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module InlineForms
4
+ # A *proposed* schema change: "add attribute X of form-element Y to model Z,
5
+ # at this position". This is the unit the end-user-facing staging pipeline
6
+ # (see stuff/2026-07-11-end-user-schema-changes-staging-and-pending-gate.md)
7
+ # drafts, previews, and finally applies.
8
+ #
9
+ # It is a plain value object — deliberately NOT an ActiveRecord model. Where
10
+ # intents are persisted (a drafts table) and edited (a GUI) is an app-level
11
+ # concern; the engine only needs the structured description plus the mapping
12
+ # to the generator that realizes it. Nothing renders from an intent at
13
+ # runtime, so it is an audit/work-queue artifact, not config-as-data.
14
+ #
15
+ # STATUS is advisory metadata for a persisting app: draft -> approved ->
16
+ # applied (or failed).
17
+ class SchemaIntent
18
+ STATUSES = %i[draft approved applied failed].freeze
19
+
20
+ attr_reader :model_name, :attribute, :form_element, :values, :disabled, :after, :before
21
+ attr_accessor :status
22
+
23
+ def initialize(model_name:, attribute:, form_element:,
24
+ values: nil, disabled: nil, after: nil, before: nil, status: :draft)
25
+ @model_name = model_name.to_s
26
+ @attribute = attribute.to_sym
27
+ @form_element = form_element.to_sym
28
+ @values = values
29
+ @disabled = disabled
30
+ @after = after&.to_sym
31
+ @before = before&.to_sym
32
+ self.status = status
33
+ end
34
+
35
+ def status=(value)
36
+ sym = value.to_sym
37
+ unless STATUSES.include?(sym)
38
+ raise ArgumentError, "unknown status #{value.inspect} (expected one of #{STATUSES.inspect})"
39
+ end
40
+
41
+ @status = sym
42
+ end
43
+
44
+ # The model class this intent targets. Raises NameError if it is not
45
+ # defined (an app should validate the name before drafting).
46
+ def model_class
47
+ model_name.constantize
48
+ end
49
+
50
+ # The `attr:form_element` token exactly as the generator expects it.
51
+ def column_token
52
+ "#{attribute}:#{form_element}"
53
+ end
54
+
55
+ # argv for `rails g inline_forms_addto <Model> <attr:form_element> [--after=..]`.
56
+ def generator_args
57
+ args = [ model_name, column_token ]
58
+ args << "--after=#{after}" if after
59
+ args << "--before=#{before}" if before
60
+ args
61
+ end
62
+
63
+ def to_h
64
+ {
65
+ model_name: model_name,
66
+ attribute: attribute,
67
+ form_element: form_element,
68
+ values: values,
69
+ disabled: disabled,
70
+ after: after,
71
+ before: before,
72
+ status: status
73
+ }
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,65 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ module InlineForms
7
+ # Writes a human label for a model attribute (or header) into a locale file,
8
+ # so `human_attribute_name` renders it. Used by the schema GUI's optional
9
+ # "Label" field. Like the header/field edits, this is a code/config change
10
+ # that lands in the working tree (git-tracked) — never the DB.
11
+ #
12
+ # The label is merged (not clobbered) into
13
+ # config/locales/inline_forms_labels.<locale>.yml
14
+ # under the key inline_forms renders from:
15
+ # <locale>: activerecord: attributes: <model_i18n_key>: <attribute>: "Label"
16
+ #
17
+ # A dedicated file (rather than editing an existing app locale file) keeps the
18
+ # write a whole-document load -> deep_merge -> dump, which is robust against
19
+ # comments/formatting concerns.
20
+ module SchemaLabel
21
+ module_function
22
+
23
+ def file_path(destination_root, locale)
24
+ File.join(destination_root.to_s, "config", "locales", "inline_forms_labels.#{locale}.yml")
25
+ end
26
+
27
+ def i18n_key_for(model_class)
28
+ if model_class.respond_to?(:model_name)
29
+ model_class.model_name.i18n_key.to_s
30
+ else
31
+ model_class.to_s.underscore
32
+ end
33
+ end
34
+
35
+ # Merge the label into the locale file and return its path.
36
+ def write(destination_root:, model_class:, attribute:, label:, locale:)
37
+ path = file_path(destination_root, locale)
38
+ key = i18n_key_for(model_class)
39
+ existing = load_document(path)
40
+ addition = {
41
+ locale.to_s => {
42
+ "activerecord" => {
43
+ "attributes" => {
44
+ key => { attribute.to_s => label.to_s }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ merged = existing.deep_merge(addition)
50
+
51
+ FileUtils.mkdir_p(File.dirname(path))
52
+ File.write(path, merged.to_yaml)
53
+ path
54
+ end
55
+
56
+ def load_document(path)
57
+ return {} unless File.exist?(path)
58
+
59
+ loaded = YAML.safe_load(File.read(path))
60
+ loaded.is_a?(Hash) ? loaded : {}
61
+ rescue StandardError
62
+ {}
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,135 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module InlineForms
4
+ # Cheap preview of a SchemaIntent, WITHOUT running a migration or booting a
5
+ # second app. The trick (see the staging doc): declare the proposed attribute
6
+ # as a *virtual* typed attribute on a throwaway subclass of the target model,
7
+ # so it reads/writes in memory with no column, and render the stock inline
8
+ # forms against an AttributeList that has the proposed row spliced in at the
9
+ # requested position. The real class and its table are untouched.
10
+ #
11
+ # obj, list = InlineForms::SchemaPreview.build(intent, existing_record)
12
+ # # render "inline_forms/show" with @object = obj,
13
+ # # @inline_forms_attribute_list = list (the controller already supports
14
+ # # this per-request override — see attr_writer :inline_forms_attribute_list)
15
+ #
16
+ # Scope of the stab: scalar attributes preview fully. Relation dropdowns
17
+ # (backed by a foreign key + association) and uploader/rich_text fields need
18
+ # model-side wiring the preview does not synthesize; #supported? reports this
19
+ # so a caller can fall back to a "available after apply" placeholder.
20
+ module SchemaPreview
21
+ module_function
22
+
23
+ # Map an AR column type (from the engine's form-element maps) to an
24
+ # ActiveModel::Type symbol for a virtual attribute.
25
+ COLUMN_TYPE_TO_VIRTUAL = {
26
+ string: :string,
27
+ text: :string,
28
+ integer: :integer,
29
+ decimal: :decimal,
30
+ float: :float,
31
+ boolean: :boolean,
32
+ date: :date,
33
+ time: :time,
34
+ datetime: :datetime,
35
+ timestamp: :datetime
36
+ }.freeze
37
+
38
+ # Form elements the GUI must not offer as "add a scalar field":
39
+ # * :header / :info are not real fields — :header is a display-only
40
+ # separator (adding one via addto would create a pointless string
41
+ # column), :info is read-only over an existing column.
42
+ # * uploaders need a mounted CarrierWave uploader; :money_field a
43
+ # monetize declaration; :devise_password_field a Devise model; :pdf_link
44
+ # a route — a virtual attribute alone cannot faithfully preview them.
45
+ PREVIEW_UNSUPPORTED_FORM_ELEMENTS = %i[
46
+ header
47
+ info
48
+ image_field
49
+ audio_field
50
+ file_field
51
+ multi_image_field
52
+ simple_file_field
53
+ pdf_link
54
+ money_field
55
+ devise_password_field
56
+ ].freeze
57
+
58
+ # Returns [preview_object, attribute_list]. `base_record` seeds the preview
59
+ # object's existing attributes when given (so the rest of the form shows
60
+ # real data); otherwise a blank instance is used.
61
+ def build(intent, base_record = nil)
62
+ base_class = intent.model_class
63
+ list = attribute_list_for(base_class, intent)
64
+ preview = preview_class_for(base_class, intent)
65
+
66
+ object = base_record ? preview.new(base_record.attributes) : preview.new
67
+ object.inline_forms_attribute_list = list
68
+ [ object, list ]
69
+ end
70
+
71
+ # False when the intent's form element needs model-side wiring the preview
72
+ # cannot synthesize (relations, uploaders, rich_text).
73
+ def supported?(intent)
74
+ !virtual_type(intent.form_element).nil?
75
+ end
76
+
77
+ # The sorted list of form elements the GUI offers (those that preview via a
78
+ # virtual attribute): scalar text/number/date/boolean/choice elements.
79
+ def supported_form_elements
80
+ candidates = InlineForms::SPECIAL_COLUMN_TYPES.keys +
81
+ InlineForms::DEFAULT_FORM_ELEMENTS.values
82
+ candidates.uniq.select { |fe| !virtual_type(fe).nil? }.sort
83
+ end
84
+
85
+ # The AttributeList the preview should render: the model's current list with
86
+ # the proposed row inserted at --after/--before (falling back to append).
87
+ def attribute_list_for(base_class, intent)
88
+ current = base_class.new.inline_forms_attribute_list
89
+ list = InlineForms::AttributeList.wrap(current.map(&:dup))
90
+ opts = { values: intent.values, disabled: intent.disabled }.compact
91
+
92
+ # Value-bearing choice elements need a values hash or their _edit/_show
93
+ # helper raises. Mirror the addto generator: inject a placeholder the user
94
+ # edits after apply (so preview and apply produce the same row).
95
+ if opts[:values].nil? && InlineForms::VALUE_BEARING_FORM_ELEMENTS.include?(intent.form_element)
96
+ opts[:values] = InlineForms::PLACEHOLDER_VALUES
97
+ end
98
+
99
+ if intent.after && list.include_attribute?(intent.after)
100
+ list.insert_after(intent.after, intent.attribute, intent.form_element, **opts)
101
+ elsif intent.before && list.include_attribute?(intent.before)
102
+ list.insert_before(intent.before, intent.attribute, intent.form_element, **opts)
103
+ else
104
+ list.field(intent.attribute, intent.form_element, **opts)
105
+ end
106
+ list
107
+ end
108
+
109
+ # A throwaway subclass with the proposed attribute declared virtual (when
110
+ # supported), masquerading as the base class so partials/routes resolve.
111
+ def preview_class_for(base_class, intent)
112
+ type = virtual_type(intent.form_element)
113
+ klass = Class.new(base_class)
114
+ klass.attribute(intent.attribute, type) if type
115
+
116
+ base_name = base_class.name
117
+ base_model_name = base_class.model_name
118
+ klass.define_singleton_method(:name) { base_name }
119
+ klass.define_singleton_method(:model_name) { base_model_name }
120
+ klass
121
+ end
122
+
123
+ def virtual_type(form_element)
124
+ fe = form_element.to_sym
125
+ return nil if PREVIEW_UNSUPPORTED_FORM_ELEMENTS.include?(fe)
126
+
127
+ column_type =
128
+ InlineForms::SPECIAL_COLUMN_TYPES[fe] ||
129
+ (InlineForms::DEFAULT_FORM_ELEMENTS.value?(fe) ? :string : nil)
130
+ return nil if column_type.nil? || column_type == :no_migration || column_type == :belongs_to
131
+
132
+ COLUMN_TYPE_TO_VIRTUAL[column_type]
133
+ end
134
+ end
135
+ end