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
@@ -6,6 +6,7 @@
6
6
  <title>
7
7
  <%= t('inline_forms.general.application_title') %> v<%= InlineForms::VERSION %>
8
8
  </title>
9
+ <%= stylesheet_link_tag "inline_forms_fonts" %>
9
10
  <%= stylesheet_link_tag "inline_forms/devise" %>
10
11
  <%= stylesheet_link_tag "inline_forms_devise" %>
11
12
  <%= csrf_meta_tags %>
@@ -1,16 +1,18 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html lang="<%= I18n.locale %>">
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title><%= t('application_name') + " v" + InlineForms::VERSION -%></title>
7
7
  <%= stylesheet_link_tag "application" %>
8
+ <%= stylesheet_link_tag "inline_forms_fonts" %>
8
9
  <%= stylesheet_link_tag "inline_forms/inline_forms" %>
9
- <%= stylesheet_link_tag "https://unpkg.com/trix@1.3.1/dist/trix.css" %>
10
+ <%= stylesheet_link_tag "trix" %>
11
+ <%= inline_forms_user_color_overrides_style %>
10
12
  <%= csrf_meta_tags %>
11
13
  </head>
12
14
 
13
- <body>
15
+ <body class="<%= inline_forms_body_theme_class %>">
14
16
  <%= render "inline_forms/header" %>
15
17
  <%# Read string keys (FlashHash stores strings); avoid `notice`/`alert` helpers %>
16
18
  <%# so we do not depend on add_flash_types wiring in every layout context. %>
@@ -38,6 +40,7 @@
38
40
  import { Turbo } from "<%= asset_path('turbo.min.js') %>"
39
41
  window.Turbo = Turbo
40
42
  </script>
41
- <%= javascript_include_tag "https://unpkg.com/trix@1.3.1/dist/trix.js" %>
43
+ <%# Trix 2 (vendored; no CDN). Self-registers its custom elements on load. %>
44
+ <%= javascript_include_tag "trix.min" %>
42
45
  </body>
43
46
  </html>
data/archived/README.md CHANGED
@@ -12,6 +12,8 @@ This directory is the **versioned archive** for inline_forms capabilities that a
12
12
  | `:tree`, `:move` | **Archived** | **7.7.0** | [`form_elements/tree/`](form_elements/tree/) — host `#children`, `#hash_tree_to_collection`, `#add_child` |
13
13
  | `:absence_list` | **Removed** (source not in repo) | **6.3.0** | See [CHANGELOG](../CHANGELOG.md#630---2026-05-03); vendor from git history or app copy |
14
14
  | `:ckeditor`, `:text_area_without_ckeditor` | **Archived** | **8.1.21** | [`form_elements/ckeditor/`](form_elements/ckeditor/) — use `:rich_text` or `:plain_text` / `:plain_text_area` |
15
+ | `:question_list` | **Archived** | **8.1.30** | [`form_elements/question_list/`](form_elements/question_list/) — hardcoded host `Question` model |
16
+ | `:dnsrecords` | **Archived** | **8.1.30** | [`form_elements/dns_records/`](form_elements/dns_records/) — host `a_records`/`djbdns_line` APIs |
15
17
 
16
18
  Programmatic registry: `InlineForms::ARCHIVED_FORM_ELEMENTS` in `lib/inline_forms.rb` (boot-time check if a model still declares an archived symbol).
17
19
 
@@ -0,0 +1,25 @@
1
+ # dns_records (archived)
2
+
3
+ **Archived in gem version:** 8.1.30
4
+ **Reason:** App-specific leftover from a DNS-admin application. The show helper calls `object.a_records`, `object.template_a_records` and `record.djbdns_line(name)` — host APIs no other app has. Edit and update were empty methods. Never registered in `FormElementRegistry::ENTRIES` (the helper methods are named `dnsrecords_*`, so the attribute-list symbol was `:dnsrecords`).
5
+
6
+ ## What it was
7
+
8
+ | Method | Behavior |
9
+ |--------|----------|
10
+ | `dnsrecords_show` | One `djbdns_line` per A record, `<br/>`-joined, raw |
11
+ | `dnsrecords_edit` | empty |
12
+ | `dnsrecords_update` | empty |
13
+
14
+ ## Restore
15
+
16
+ ```bash
17
+ cp archived/form_elements/dns_records/lib/inline_forms/form_elements/dns_records_helper.rb \
18
+ lib/inline_forms/form_elements/
19
+ ```
20
+
21
+ Remove `:dnsrecords` from `InlineForms::ARCHIVED_FORM_ELEMENTS`. Your app must provide `a_records` / `template_a_records` returning objects with `djbdns_line(name)`.
22
+
23
+ ## Turbo
24
+
25
+ Display-only; no Turbo concerns.
@@ -0,0 +1,25 @@
1
+ # question_list (archived)
2
+
3
+ **Archived in gem version:** 8.1.30
4
+ **Reason:** App-specific leftover. The edit helper hardcodes a host `Question` model with a `subquestions` association (survey-style app), the show helper iterates a HABTM-ish collection of `_presentation`s, and the update writes `<attribute singular>_ids`. No example app ever exercised it, and it cannot render without that exact host schema.
5
+
6
+ ## What it was
7
+
8
+ | Method | Behavior |
9
+ |--------|----------|
10
+ | `question_list_show` | `<ul>` of the association's `_presentation`s, each linking to inline edit |
11
+ | `question_list_edit` | Static nested `<ul>` of ALL `Question.all` + `question.subquestions` (read-only markup, despite being the edit state) |
12
+ | `question_list_update` | `object.<attr singular>_ids = params[attr].keys` |
13
+
14
+ ## Restore
15
+
16
+ ```bash
17
+ cp archived/form_elements/question_list/lib/inline_forms/form_elements/question_list_helper.rb \
18
+ lib/inline_forms/form_elements/
19
+ ```
20
+
21
+ Re-add `:question_list => :no_migration` to `FormElementRegistry::ENTRIES` and remove `:question_list` from `InlineForms::ARCHIVED_FORM_ELEMENTS`. Your app must define `Question` (with `subquestions`) and the HABTM association named by the attribute.
22
+
23
+ ## Turbo
24
+
25
+ Pre-Turbo markup; the edit state renders no form inputs, so it never round-tripped through the 7.x UJS → Turbo migration. Expect to rework it if restored.
data/inline_forms.gemspec CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
+
2
3
  $:.push File.expand_path("../lib", __FILE__)
3
4
  require "inline_forms/version"
4
5
  require "inline_forms/gem_files"
@@ -7,17 +8,17 @@ Gem::Specification.new do |s|
7
8
  s.name = "inline_forms"
8
9
  s.version = InlineForms::VERSION
9
10
  s.platform = Gem::Platform::RUBY
10
- s.authors = ["Ace Suares", "Lemuel Boyce", "Manuel Ortega"]
11
- s.email = ["ace@suares.com"]
12
- s.homepage = %q{http://github.com/acesuares/inline_forms}
13
- s.summary = %q{Inline editing of forms for Rails 8.}
14
- s.description = %q{Inline Forms eases setup of admin-style forms with inline editing. Field lists are declared on the model. Requires Rails 8.1.x, Ruby >= 4.0, and validation_hints ~> 8.}
15
- s.licenses = ["MIT"]
11
+ s.authors = [ "Ace Suares", "Lemuel Boyce", "Manuel Ortega" ]
12
+ s.email = [ "ace@suares.com" ]
13
+ s.homepage = %q(http://github.com/acesuares/inline_forms)
14
+ s.summary = %q(Inline editing of forms for Rails 8.)
15
+ s.description = %q(Inline Forms eases setup of admin-style forms with inline editing. Field lists are declared on the model. Requires Rails 8.1.x, Ruby >= 4.0, and validation_hints ~> 8.)
16
+ s.licenses = [ "MIT" ]
16
17
  s.required_ruby_version = ">= 4.0.0"
17
18
 
18
19
  s.files = InlineFormsGemFiles.gem_files(include_installer: false)
19
20
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
- s.require_paths = ["lib"]
21
+ s.require_paths = [ "lib" ]
21
22
 
22
23
  s.add_dependency("validation_hints", ">= 8.1.4", "< 9.0")
23
24
  s.add_dependency("rails", ">= 8.1", "< 8.2")
@@ -13,6 +13,37 @@ Description:
13
13
  rejected. `_presentation`, `_list_order`, `_list_search`, and `_order` are
14
14
  skipped unless you pass `--replace`.
15
15
 
16
+ Placement:
17
+ By default a new attribute_list row is inserted above the model's trailing
18
+ "metadata" block (its `:info` rows / created_at / updated_at, and a
19
+ `:header` directly above them) rather than at the very end, so an editable
20
+ field does not land inside the read-only info section. Override with:
21
+
22
+ --before=ATTR insert the new row before an existing attribute
23
+ --after=ATTR insert the new row after an existing attribute
24
+
25
+ If the named anchor is not found, the generator warns and falls back to the
26
+ default placement.
27
+
28
+ Value-bearing form elements:
29
+ Choice elements (dropdown_with_values, dropdown_with_integers,
30
+ dropdown_with_values_with_stars, radio_button, check_box,
31
+ scale_with_integers, scale_with_values) need a values hash as the 3rd row
32
+ element. The generator inserts a placeholder `{ 1 => 'one', 2 => 'two' }`
33
+ and warns; edit it to your real values.
34
+
35
+ Constraints and caveats:
36
+ - Additive only: the generated migration uses `add_column` / `add_reference`
37
+ (nullable, no default). Renaming, dropping, or making a column NOT NULL
38
+ (and the SQLite table-rebuild that would require) is out of scope; do
39
+ those by hand.
40
+ - Run `bundle exec rails db:migrate` after generating: the model row is
41
+ written immediately, but the column only exists once the migration runs.
42
+ - PaperTrail: versions recorded before this migration have no value for the
43
+ new column, so reverting an old record leaves the new column at its
44
+ default (nil), and the versions panel shows no history for it prior to
45
+ the migration.
46
+
16
47
  Example:
17
48
  rails generate inline_forms_addto User occupation:text_field birthdate:date organization:dropdown bio:rich_text
18
49
 
@@ -33,11 +33,27 @@ class InlineFormsAddtoGenerator < Rails::Generators::NamedBase
33
33
  INSTALL_TIME_ONLY_NAMES = %w[_no_model _no_migration _id _enabled].freeze
34
34
  REPLACE_ONLY_NAMES = %w[_presentation _list_order _list_search _order].freeze
35
35
 
36
+ # Form elements that render a set of choices and therefore need a values
37
+ # hash as the 3rd element of their attribute_list row. Emitting the bare
38
+ # 2-element row for these raises at show time, so we insert a placeholder
39
+ # hash and warn the user to fill it in. Canonical list lives in InlineForms
40
+ # (shared with the schema GUI/preview).
41
+ VALUE_BEARING_ELEMENTS = InlineForms::VALUE_BEARING_FORM_ELEMENTS
42
+
43
+ # attribute_list rows whose form element (or name) marks the start of the
44
+ # trailing "metadata" block. The smart-default placement inserts new rows
45
+ # above this block instead of at the very end of the list.
46
+ METADATA_ROW_NAMES = %w[created_at updated_at].freeze
47
+
36
48
  argument :attributes, type: :array, banner: "[name:form_element]..."
37
49
  class_option :allow_unknown, type: :boolean, default: false,
38
50
  desc: "Allow unknown field types (legacy behavior: comment generated lines instead of failing)."
39
51
  class_option :replace, type: :boolean, default: false,
40
52
  desc: "Replace existing _presentation/_list_order/_list_search instead of skipping."
53
+ class_option :before, type: :string, default: nil,
54
+ desc: "Insert the new attribute_list row before this existing attribute name."
55
+ class_option :after, type: :string, default: nil,
56
+ desc: "Insert the new attribute_list row after this existing attribute name."
41
57
 
42
58
  source_root File.expand_path("inline_forms_addto/templates", __dir__)
43
59
 
@@ -94,6 +110,10 @@ class InlineFormsAddtoGenerator < Rails::Generators::NamedBase
94
110
  next if INSTALL_TIME_ONLY_NAMES.include?(attribute.name)
95
111
  next if REPLACE_ONLY_NAMES.include?(attribute.name)
96
112
  next unless attribute.migration?
113
+ # A :header is a display-only separator in the attribute list; it has
114
+ # no backing column, so it must not emit a migration line (otherwise
115
+ # `foo:header` created a pointless `foo` string column).
116
+ next if attribute.attribute_type == :header
97
117
 
98
118
  if attribute.column_type == :belongs_to
99
119
  @migration_lines << " add_reference :#{table_name}, :#{attribute.name}, foreign_key: true\n"
@@ -106,7 +126,7 @@ class InlineFormsAddtoGenerator < Rails::Generators::NamedBase
106
126
  return if @migration_lines.empty?
107
127
 
108
128
  template "add_columns_migration.erb",
109
- "db/migrate/#{time_stamp}_#{migration_file_basename}.rb"
129
+ "db/migrate/#{unique_time_stamp}_#{migration_file_basename}.rb"
110
130
  end
111
131
 
112
132
  def update_model
@@ -146,6 +166,20 @@ class InlineFormsAddtoGenerator < Rails::Generators::NamedBase
146
166
  end
147
167
  end
148
168
 
169
+ # Run last (Thor invokes public methods in definition order). The model
170
+ # row was injected above, but it references a column that does not exist
171
+ # until the generated migration is applied; rendering the model before
172
+ # then raises. Remind the user loudly. No-op when no migration was written
173
+ # (e.g. only has_many/rich_text/habtm additions).
174
+ def remind_to_migrate
175
+ return if @migration_lines.nil? || @migration_lines.empty?
176
+
177
+ say ""
178
+ say " Next step: apply the generated migration before rendering #{model_class_name}:", :yellow
179
+ say " bundle exec rails db:migrate", :yellow
180
+ say " (the attribute_list row was added now, but its column only exists after migrating.)", :yellow
181
+ end
182
+
149
183
  private
150
184
 
151
185
  def model_file_name
@@ -204,43 +238,181 @@ class InlineFormsAddtoGenerator < Rails::Generators::NamedBase
204
238
  end
205
239
 
206
240
  # Inserts a new row into the existing `inline_forms_attribute_list`
207
- # method. Falls back to appending a fresh method when the model has
208
- # only `attr_writer :inline_forms_attribute_list` (inherited from
209
- # `ApplicationRecord`) and no body.
241
+ # method. Falls back to appending a fresh method when the model has no
242
+ # generator-shaped list (e.g. only the inherited
243
+ # `attr_writer :inline_forms_attribute_list` and no body).
244
+ #
245
+ # Row-aware, not regex-greedy: we locate the `[` after
246
+ # `@inline_forms_attribute_list ||=` and bracket-depth scan to its
247
+ # matching `]`, so the edit survives `].freeze`, trailing comments, and
248
+ # any methods defined after the list. Placement honors `--after`/`--before`
249
+ # (by attribute name) and otherwise lands above the trailing metadata block
250
+ # (`:info` rows / created_at / updated_at, and a `:header` directly above
251
+ # them) instead of after it.
210
252
  def add_attribute_list_row!(attribute)
211
- content = File.read(File.join(destination_root, model_file_path))
212
- row = " [ :#{attribute.name}, :#{attribute.attribute_type} ],\n"
253
+ path = File.join(destination_root, model_file_path)
254
+ content = File.read(path)
213
255
 
214
- if content.match?(/@inline_forms_attribute_list \|\|=\s*\[/)
215
- if content.match?(/\[\s*:#{Regexp.escape(attribute.name)}\s*,/)
216
- say_status :identical, "#{model_file_path}: row :#{attribute.name}", :blue
217
- return
218
- end
219
- # Insert before the closing `]` of the array, keeping appended order.
220
- # Match against the file's full text and write it back so we work
221
- # around Thor's `gsub_file` block-arg quirk (the block sees only the
222
- # full match, no $1/$2). MatchData captures are explicit here.
223
- m = content.match(/(@inline_forms_attribute_list \|\|=\s*\[(?:.|\n)*?)(\n\s*\]\s*\n\s*end)/)
224
- if m
225
- replacement = m[1] + "\n" + row.chomp + m[2]
226
- new_content = content.sub(m[0], replacement)
227
- File.write(File.join(destination_root, model_file_path), new_content)
228
- say_status :insert, "#{model_file_path}: row :#{attribute.name}", :green
229
- else
230
- say_status :warn, "#{model_file_path}: could not locate end of @inline_forms_attribute_list, skipping :#{attribute.name}", :yellow
231
- end
232
- else
256
+ # Idempotent: skip if a row for this attribute already exists anywhere.
257
+ if content.match?(/\[\s*:#{Regexp.escape(attribute.name)}\s*,/)
258
+ say_status :identical, "#{model_file_path}: row :#{attribute.name}", :blue
259
+ return
260
+ end
261
+
262
+ bounds = attribute_list_bounds(content)
263
+ unless bounds
233
264
  say_status :warn, "#{model_file_path}: no inline_forms_attribute_list found, appending a fresh method", :yellow
234
265
  body = <<~RUBY.gsub(/^/, " ")
235
266
 
236
267
  def inline_forms_attribute_list
237
268
  @inline_forms_attribute_list ||= [
238
- [ :#{attribute.name}, :#{attribute.attribute_type} ],
269
+ #{attribute_row_literal(attribute)},
239
270
  ]
240
271
  end
241
272
  RUBY
242
273
  inject_into_class model_file_path, model_class_name, body
274
+ return
275
+ end
276
+
277
+ warn_if_value_bearing!(attribute)
278
+
279
+ open_idx, close_idx = bounds
280
+ inner = content[(open_idx + 1)...close_idx]
281
+ lines = inner.lines
282
+ indent = detect_row_indent(lines)
283
+ new_line = "#{indent}#{attribute_row_literal(attribute)},\n"
284
+
285
+ insert_at, note = insertion_index(lines, attribute)
286
+
287
+ # Keep the array valid: ensure the row we insert after ends with a comma.
288
+ if insert_at.positive?
289
+ prev = lines[insert_at - 1]
290
+ if prev && prev.match?(/\S/) && !prev.match?(/,\s*\z/)
291
+ lines[insert_at - 1] = prev.sub(/(\S)(\s*)\z/, "\\1,\\2")
292
+ end
293
+ end
294
+
295
+ lines.insert(insert_at, new_line)
296
+ new_content = content[0..open_idx] + lines.join + content[close_idx..-1]
297
+ File.write(path, new_content)
298
+ say_status :insert, "#{model_file_path}: row :#{attribute.name}#{note}", :green
299
+ end
300
+
301
+ # Returns [open_bracket_index, close_bracket_index] for the
302
+ # `@inline_forms_attribute_list ||= [ ... ]` array literal, or nil when the
303
+ # model has no such list. Bracket-depth scan; nested `[ ]` (e.g. an
304
+ # options_disabled array inside a choice row) balances correctly.
305
+ def attribute_list_bounds(content)
306
+ m = content.match(/@inline_forms_attribute_list\s*\|\|=\s*\[/)
307
+ return nil unless m
308
+
309
+ open_idx = m.end(0) - 1 # index of the '[' itself
310
+ depth = 0
311
+ i = open_idx
312
+ while i < content.length
313
+ case content[i]
314
+ when "[" then depth += 1
315
+ when "]"
316
+ depth -= 1
317
+ return [ open_idx, i ] if depth.zero?
318
+ end
319
+ i += 1
320
+ end
321
+ nil
322
+ end
323
+
324
+ # Decide where the new row goes. Returns [line_index, status_note].
325
+ def insertion_index(lines, _attribute)
326
+ if (anchor = options[:after].to_s) != ""
327
+ idx = row_line_index(lines, anchor)
328
+ return [ idx + 1, " (after :#{anchor})" ] if idx
329
+ say_status :warn, "#{model_file_path}: --after #{anchor} not found; using default placement", :yellow
330
+ elsif (anchor = options[:before].to_s) != ""
331
+ idx = row_line_index(lines, anchor)
332
+ return [ idx, " (before :#{anchor})" ] if idx
333
+ say_status :warn, "#{model_file_path}: --before #{anchor} not found; using default placement", :yellow
334
+ end
335
+
336
+ if (meta = metadata_start_index(lines))
337
+ return [ meta, " (above metadata)" ]
338
+ end
339
+
340
+ [ last_row_index(lines) + 1, "" ]
341
+ end
342
+
343
+ def row_line_index(lines, name)
344
+ lines.index { |l| row_name(l) == name.to_s }
345
+ end
346
+
347
+ def row_name(line)
348
+ m = line.match(/\A\s*\[\s*:(\w+)\s*,/)
349
+ m && m[1]
350
+ end
351
+
352
+ def row_element(line)
353
+ m = line.match(/\A\s*\[\s*:\w+\s*,\s*:(\w+)/)
354
+ m && m[1]
355
+ end
356
+
357
+ # Index of the first row that starts the trailing metadata block. If a
358
+ # `:header` sits directly above that row, the header is treated as the
359
+ # block start (so the new field lands above the header, not between it and
360
+ # its info rows). nil when the list has no metadata block.
361
+ def metadata_start_index(lines)
362
+ first = nil
363
+ lines.each_with_index do |l, i|
364
+ if row_element(l) == "info" || METADATA_ROW_NAMES.include?(row_name(l))
365
+ first = i
366
+ break
367
+ end
368
+ end
369
+ return nil unless first
370
+
371
+ prev = first - 1
372
+ (prev >= 0 && row_element(lines[prev]) == "header") ? prev : first
373
+ end
374
+
375
+ def last_row_index(lines)
376
+ idx = nil
377
+ lines.each_with_index { |l, i| idx = i if row_name(l) }
378
+ idx || (lines.length - 1)
379
+ end
380
+
381
+ def detect_row_indent(lines)
382
+ lines.each do |l|
383
+ m = l.match(/\A(\s*)\[/)
384
+ return m[1] if m
385
+ end
386
+ " " # 6 spaces, matching the create-time template
387
+ end
388
+
389
+ # `[ :name, :element ]`, or `[ :name, :element, { 1 => 'one', 2 => 'two' } ]`
390
+ # for value-bearing choice elements (a placeholder the user then edits).
391
+ def attribute_row_literal(attribute)
392
+ el = attribute.attribute_type
393
+ if VALUE_BEARING_ELEMENTS.include?(el)
394
+ "[ :#{attribute.name}, :#{el}, { 1 => 'one', 2 => 'two' } ]"
395
+ else
396
+ "[ :#{attribute.name}, :#{el} ]"
397
+ end
398
+ end
399
+
400
+ def warn_if_value_bearing!(attribute)
401
+ return unless VALUE_BEARING_ELEMENTS.include?(attribute.attribute_type)
402
+
403
+ say_status :warn,
404
+ "#{model_file_path}: :#{attribute.name} is a #{attribute.attribute_type}; " \
405
+ "edit the placeholder values hash { 1 => 'one', ... }",
406
+ :yellow
407
+ end
408
+
409
+ def unique_time_stamp
410
+ base = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
411
+ dir = File.join(destination_root, "db", "migrate")
412
+ existing = Dir.glob(File.join(dir, "*.rb")).filter_map do |f|
413
+ File.basename(f)[/\A(\d{14})/, 1]&.to_i
243
414
  end
415
+ [ base, (existing.max || 0) + 1 ].max.to_s.rjust(14, "0")
244
416
  end
245
417
 
246
418
  def replace_special!(attribute)
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+
2
3
  require "rails/generators"
3
4
  require "rails/generators/generated_attribute"
4
5
  require "inline_forms"
@@ -106,11 +107,11 @@ Rails::Generators::GeneratedAttribute.class_eval do
106
107
 
107
108
  def migration?
108
109
  not ( column_type == :no_migration ||
109
- SPECIAL_GENERATOR_NAMES.include?(name) )
110
+ SPECIAL_GENERATOR_NAMES.include?(name))
110
111
  end
111
112
 
112
113
  def attribute?
113
114
  not ( SPECIAL_GENERATOR_NAMES.include?(name) ||
114
- relation? )
115
+ relation?)
115
116
  end
116
117
  end
@@ -8,7 +8,7 @@ class ApplicationRecord < ActiveRecord::Base
8
8
  # in the inline_forms versions panel as a meaningless "empty" row whose
9
9
  # Restore link reifies the same state (no-op). Excluding `:touch` here
10
10
  # suppresses that noise without affecting real attribute updates.
11
- has_paper_trail on: [:create, :update, :destroy]
11
+ has_paper_trail on: [ :create, :update, :destroy ]
12
12
 
13
13
  attr_writer :inline_forms_attribute_list
14
14
 
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+
2
3
  module InlineForms
3
4
  class ArchivedFormElementError < StandardError; end
4
5
 
@@ -8,53 +9,65 @@ module InlineForms
8
9
  geo_code_curacao: {
9
10
  archived_in_version: "7.6.0",
10
11
  archive_path: "archived/form_elements/geo_code_curacao",
11
- summary: "Curaçao street geocode (MySQL Zones/Buurten/Straatcode, jQuery autocomplete, UJS list_streets).",
12
+ summary: "Curaçao street geocode (MySQL Zones/Buurten/Straatcode, jQuery autocomplete, UJS list_streets)."
12
13
  },
13
14
  chicas_photo_list: {
14
15
  archived_in_version: "7.6.0",
15
16
  archive_path: "archived/form_elements/chicas",
16
- summary: "Chicas app read-only member photo gallery (show-only).",
17
+ summary: "Chicas app read-only member photo gallery (show-only)."
17
18
  },
18
19
  chicas_family_photo_list: {
19
20
  archived_in_version: "7.6.0",
20
21
  archive_path: "archived/form_elements/chicas",
21
- summary: "Chicas app read-only family member photo gallery (show-only).",
22
+ summary: "Chicas app read-only family member photo gallery (show-only)."
22
23
  },
23
24
  chicas_dropdown_with_family_members: {
24
25
  archived_in_version: "7.6.0",
25
26
  archive_path: "archived/form_elements/chicas",
26
- summary: "Chicas client picker via family.clients; moves CarrierWave upload dir on update.",
27
+ summary: "Chicas client picker via family.clients; moves CarrierWave upload dir on update."
27
28
  },
28
29
  kansen_slider: {
29
30
  archived_in_version: "7.6.0",
30
31
  archive_path: "archived/form_elements/kansen_slider",
31
- summary: "jQuery UI slider for integer-coded chance scale; uses model attribute_values.",
32
+ summary: "jQuery UI slider for integer-coded chance scale; uses model attribute_values."
32
33
  },
33
34
  tree: {
34
35
  archived_in_version: "7.7.0",
35
36
  archive_path: "archived/form_elements/tree",
36
- summary: "Self-referential children list via parent.children; requires host tree APIs (see README).",
37
+ summary: "Self-referential children list via parent.children; requires host tree APIs (see README)."
37
38
  },
38
39
  move: {
39
40
  archived_in_version: "7.7.0",
40
41
  archive_path: "archived/form_elements/tree",
41
- summary: "Reparent via hash_tree_to_collection + add_child (host must implement; pairs with :tree).",
42
+ summary: "Reparent via hash_tree_to_collection + add_child (host must implement; pairs with :tree)."
42
43
  },
43
44
  absence_list: {
44
45
  removed_in_version: "6.3.0",
45
46
  archive_path: nil,
46
- summary: "Project-specific absence list UI; removed without a copy in this repo (see CHANGELOG 6.3.0).",
47
+ summary: "Project-specific absence list UI; removed without a copy in this repo (see CHANGELOG 6.3.0)."
47
48
  },
48
49
  ckeditor: {
49
50
  archived_in_version: "8.1.21",
50
51
  archive_path: "archived/form_elements/ckeditor",
51
- summary: "Legacy CKEditor form element; use :rich_text (ActionText) instead.",
52
+ summary: "Legacy CKEditor form element; use :rich_text (ActionText) instead."
52
53
  },
53
54
  text_area_without_ckeditor: {
54
55
  archived_in_version: "8.1.21",
55
56
  archive_path: "archived/form_elements/ckeditor",
56
- summary: "Legacy plain-text alias; use :plain_text or :plain_text_area instead.",
57
+ summary: "Legacy plain-text alias; use :plain_text or :plain_text_area instead."
58
+ },
59
+ question_list: {
60
+ archived_in_version: "8.1.30",
61
+ archive_path: "archived/form_elements/question_list",
62
+ summary: "Survey-app checklist hardcoding a host Question model with subquestions."
57
63
  },
64
+ # The helper methods were named dnsrecords_* (no underscore), so the
65
+ # attribute-list symbol in host apps was :dnsrecords.
66
+ dnsrecords: {
67
+ archived_in_version: "8.1.30",
68
+ archive_path: "archived/form_elements/dns_records",
69
+ summary: "DNS-admin display of djbdns A-record lines via host a_records/djbdns_line APIs."
70
+ }
58
71
  }.freeze
59
72
 
60
73
  def self.validate_no_archived_form_elements_for!(klass)