scriptorium 0.6.1 → 0.7.2

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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/assets/icons/social/reddit.png +0 -0
  3. data/assets/icons/social/x-logo.png +0 -0
  4. data/assets/imagenotfound.jpg +0 -0
  5. data/bin/sblog +84 -5
  6. data/bin/scriptorium +1 -0
  7. data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +0 -1
  8. data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +0 -29
  9. data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +0 -19
  10. data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +1 -1
  11. data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +1 -1
  12. data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +1 -1
  13. data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +0 -10
  14. data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +1 -4
  15. data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
  16. data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
  17. data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
  18. data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
  19. data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
  20. data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
  21. data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
  22. data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
  23. data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
  24. data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
  25. data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
  26. data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
  27. data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
  28. data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
  29. data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
  30. data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
  31. data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
  32. data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
  33. data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
  34. data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
  35. data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
  36. data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
  37. data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
  38. data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
  39. data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
  40. data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
  41. data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
  42. data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
  43. data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
  44. data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
  45. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
  46. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
  47. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
  48. data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
  49. data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
  50. data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
  51. data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
  52. data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
  53. data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
  54. data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
  55. data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
  56. data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
  57. data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
  58. data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
  59. data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
  60. data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
  61. data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
  62. data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
  63. data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
  64. data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
  65. data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
  66. data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
  67. data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
  68. data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
  69. data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
  70. data/doc/imported/0018-ruby-puns/post.html +46 -0
  71. data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
  72. data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
  73. data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
  74. data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
  75. data/doc/imported/0020-fffff/metadata.txt +7 -0
  76. data/doc/imported/0020-fffff/post.html +24 -0
  77. data/doc/imported/0020-fffff/source.lt3 +12 -0
  78. data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
  79. data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
  80. data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
  81. data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
  82. data/doc/imported/0023-doctor-sleep/post.html +63 -0
  83. data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
  84. data/doc/imported/0024-just-a-test/metadata.txt +7 -0
  85. data/doc/imported/0024-just-a-test/post.html +24 -0
  86. data/doc/imported/0024-just-a-test/source.lt3 +12 -0
  87. data/doc/imported/import_summary.txt +98 -0
  88. data/doc/livetext-informal-spec.txt +65 -0
  89. data/doc/myuserdoc/ch-0.lt3 +31 -0
  90. data/doc/myuserdoc/ch-1.lt3 +37 -0
  91. data/doc/myuserdoc/ch-10.lt3 +22 -0
  92. data/doc/myuserdoc/ch-2.lt3 +37 -0
  93. data/doc/myuserdoc/ch-3.lt3 +19 -0
  94. data/doc/myuserdoc/ch-4.lt3 +43 -0
  95. data/doc/myuserdoc/ch-5.lt3 +22 -0
  96. data/doc/myuserdoc/ch-6.lt3 +19 -0
  97. data/doc/myuserdoc/ch-7.lt3 +16 -0
  98. data/doc/myuserdoc/ch-8.lt3 +13 -0
  99. data/doc/myuserdoc/ch-9.lt3 +19 -0
  100. data/doc/myuserdoc/tweak.rb +18 -0
  101. data/doc/{userdoc-toc.txt → myuserdoc/userdoc-toc.txt} +27 -27
  102. data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
  103. data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
  104. data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
  105. data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
  106. data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
  107. data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
  108. data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
  109. data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
  110. data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
  111. data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
  112. data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
  113. data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
  114. data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
  115. data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
  116. data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
  117. data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
  118. data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
  119. data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
  120. data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
  121. data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
  122. data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
  123. data/doc/old-posts/0024-just-a-test.lt3 +12 -0
  124. data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
  125. data/doc/old-repo +1 -0
  126. data/doc/reddit_integration.md +2 -2
  127. data/doc/user.lt3 +0 -3
  128. data/lib/scriptorium/api.rb +1811 -78
  129. data/lib/scriptorium/banner_svg.rb +55 -68
  130. data/lib/scriptorium/contract.rb +3 -2
  131. data/lib/scriptorium/exceptions.rb +133 -102
  132. data/lib/scriptorium/helpers.rb +282 -82
  133. data/lib/scriptorium/post.rb +81 -17
  134. data/lib/scriptorium/reddit.rb +1 -1
  135. data/lib/scriptorium/repo.rb +478 -164
  136. data/lib/scriptorium/standard_files.rb +30 -396
  137. data/lib/scriptorium/support/common_js/clipboard.js +35 -0
  138. data/lib/scriptorium/support/common_js/content-loader.js +187 -0
  139. data/lib/scriptorium/support/common_js/navigation.js +52 -0
  140. data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
  141. data/lib/scriptorium/support/config/reddit_template.txt +17 -0
  142. data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/social.txt +1 -0
  143. data/lib/scriptorium/support/highlight/css.txt +2 -0
  144. data/lib/scriptorium/support/highlight/custom.css +119 -0
  145. data/lib/scriptorium/support/highlight/js.txt +1 -0
  146. data/lib/scriptorium/support/post_index/config.txt +15 -0
  147. data/lib/scriptorium/support/post_index/style.css +55 -0
  148. data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
  149. data/{test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 → lib/scriptorium/support/templates/initial_post.lt3} +5 -5
  150. data/lib/scriptorium/support/templates/post.lt3 +104 -0
  151. data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt → lib/scriptorium/support/theme/header.lt3} +1 -1
  152. data/lib/scriptorium/theme.rb +83 -70
  153. data/lib/scriptorium/version.rb +2 -2
  154. data/lib/scriptorium/view.rb +194 -149
  155. data/lib/scriptorium.rb +24 -1
  156. data/lib/skeleton.rb +4 -1
  157. data/scriptorium.gemspec +2 -1
  158. data/test/WEB_INTEGRATION_README.md +196 -0
  159. data/test/all +40 -0
  160. data/test/banner_svg/unit.rb +267 -35
  161. data/test/config/deployment.txt +5 -0
  162. data/test/integration/integration_test.rb +7 -7
  163. data/test/integration/preview_flow_test.rb +94 -0
  164. data/test/livetext_plugin_test.rb +453 -182
  165. data/test/manual/banner-tests/test01.html +82 -18
  166. data/test/manual/banner-tests/test02.html +82 -18
  167. data/test/manual/banner-tests/test03.html +82 -18
  168. data/test/manual/banner-tests/test04.html +89 -25
  169. data/test/manual/banner-tests/test05.html +89 -25
  170. data/test/manual/banner-tests/test06.html +89 -25
  171. data/test/manual/banner-tests/test07.html +89 -25
  172. data/test/manual/banner-tests/test08.html +82 -18
  173. data/test/manual/banner-tests/test09.html +82 -18
  174. data/test/manual/banner-tests/test10.html +82 -18
  175. data/test/manual/banner-tests/test11.html +82 -18
  176. data/test/manual/banner-tests/test12.html +82 -18
  177. data/test/manual/banner-tests/test13.html +82 -18
  178. data/test/manual/banner-tests/test14.html +82 -18
  179. data/test/manual/banner-tests/test15.html +82 -18
  180. data/test/manual/banner-tests/test16.html +82 -18
  181. data/test/manual/banner-tests/test17.html +82 -18
  182. data/test/manual/banner-tests/test18.html +90 -26
  183. data/test/manual/banner-tests/test19.html +90 -26
  184. data/test/manual/banner-tests/test20.html +90 -26
  185. data/test/manual/banner-tests/test21.html +90 -26
  186. data/test/manual/banner-tests/test22.html +90 -26
  187. data/test/manual/banner-tests/test23.html +90 -26
  188. data/test/manual/banner-tests/test24.html +90 -26
  189. data/test/manual/banner-tests/test25.html +89 -25
  190. data/test/manual/banner_environment.rb +15 -2
  191. data/test/manual/codemirror_demo.html +773 -0
  192. data/test/manual/create_posts_for_web.rb +114 -0
  193. data/test/manual/preview_manual_test.rb +129 -0
  194. data/test/manual/test_banner_features.rb +14 -14
  195. data/test/manual/test_banner_integration.rb +115 -0
  196. data/test/manual/test_banner_radial.rb +87 -0
  197. data/test/manual/test_syntax_highlighting.rb +60 -40
  198. data/test/support/preview_utils.rb +88 -0
  199. data/test/test_gem_assets.rb +48 -0
  200. data/test/test_helpers.rb +10 -0
  201. data/test/tui_editor_integration_test.rb +15 -15
  202. data/test/tui_integration_test.rb +687 -441
  203. data/test/unit/api.rb +757 -37
  204. data/test/unit/asset_management.rb +195 -221
  205. data/test/unit/backup_test.rb +451 -0
  206. data/test/unit/contract_test.rb +1 -23
  207. data/test/unit/core.rb +415 -61
  208. data/test/unit/deploy_config_test.rb +248 -0
  209. data/test/unit/deploy_test.rb +312 -21
  210. data/test/unit/edit_post_test.rb +168 -0
  211. data/test/unit/gem_asset_management.rb +36 -42
  212. data/test/unit/livetext_basic.rb +23 -35
  213. data/test/unit/livetext_compatibility.rb +7 -14
  214. data/test/unit/parse_cmd_test.rb +260 -0
  215. data/test/unit/{symlink_test.rb → permalink_copy_test.rb} +47 -49
  216. data/test/unit/post.rb +91 -26
  217. data/test/unit/post_index_config_test.rb +258 -0
  218. data/test/unit/post_state_helpers_test.rb +137 -0
  219. data/test/unit/read_commented_file_test.rb +8 -6
  220. data/test/unit/repo.rb +75 -54
  221. data/test/unit/social_test.rb +41 -44
  222. data/test/unit/syntax_highlighting.rb +70 -0
  223. data/test/unit/theme_management_test.rb +91 -0
  224. data/test/unit/view.rb +79 -12
  225. data/test/unit/widgets.rb +8 -8
  226. data/test/web_integration_test.rb +231 -0
  227. data/test/web_test_helper.rb +218 -0
  228. data/test/web_workflow_test.rb +527 -0
  229. data/ui/tui/bin/scriptorium +885 -415
  230. data/ui/web/app/app.rb +1398 -176
  231. data/ui/web/app/assets/livetext_mode.js +244 -0
  232. data/ui/web/app/error_helpers.rb +16 -16
  233. data/ui/web/app/views/advanced_config.erb +8 -2
  234. data/ui/web/app/views/asset_management.erb +56 -0
  235. data/ui/web/app/views/backup_management.erb +238 -0
  236. data/ui/web/app/views/config_widget.erb +232 -0
  237. data/ui/web/app/views/dashboard.erb +64 -72
  238. data/ui/web/app/views/deploy_config.erb +3 -0
  239. data/ui/web/app/views/edit_pages.erb +170 -2
  240. data/ui/web/app/views/edit_post.erb +130 -9
  241. data/ui/web/app/views/edit_theme.erb +73 -0
  242. data/ui/web/app/views/edit_theme_file.erb +74 -0
  243. data/ui/web/app/views/theme_management.erb +130 -0
  244. data/ui/web/app/views/view_dashboard.erb +666 -25
  245. data/ui/web/app/views/widgets.erb +249 -0
  246. data/ui/web/bin/scriptorium-web +35 -24
  247. data/ui/web/tmp/timing.log +17 -0
  248. data/ui/web/tmp/web_server.log +0 -5
  249. metadata +190 -116
  250. data/assets/back-icon.png +0 -0
  251. data/assets/icons/facebook.svg +0 -1
  252. data/assets/icons/github.svg +0 -1
  253. data/assets/icons/instagram.svg +0 -1
  254. data/assets/icons/reddit.svg +0 -1
  255. data/assets/icons/x.svg +0 -1
  256. data/assets/icons/youtube.svg +0 -1
  257. data/bin/scriptorium +0 -1511
  258. data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +0 -34
  259. data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +0 -50
  260. data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +0 -73
  261. data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +0 -70
  262. data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +0 -110
  263. data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +0 -73
  264. data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +0 -124
  265. data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +0 -46
  266. data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +0 -97
  267. data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +0 -211
  268. data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +0 -141
  269. data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +0 -211
  270. data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +0 -134
  271. data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +0 -41
  272. data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +0 -49
  273. data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +0 -46
  274. data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +0 -41
  275. data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +0 -41
  276. data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +0 -256
  277. data/lib/scriptorium/syntax_highlighter.rb +0 -234
  278. data/test/manual/deploy_symlink_demo.rb +0 -142
  279. data/test/manual/symlink_demo.rb +0 -117
  280. data/test/manual/test2.rb +0 -12
  281. data/test/manual/test_banner_from_file.rb +0 -150
  282. data/test/manual/test_banner_in_header.rb +0 -35
  283. data/test/manual/test_code_highlighting.rb +0 -68
  284. data/test/manual/test_complex_header.rb +0 -74
  285. data/test/manual/test_empty_header.rb +0 -32
  286. data/test/manual/test_radial_custom.rb +0 -58
  287. data/test/manual/test_radial_large_radius.rb +0 -52
  288. data/test/manual/test_svg_debug.rb +0 -47
  289. data/test/pages-demo/config/currentview.txt +0 -1
  290. data/test/pages-demo/views/demo/config/common.js +0 -57
  291. data/test/pages-demo/views/demo/config/footer.txt +0 -1
  292. data/test/pages-demo/views/demo/config/global-head.txt +0 -8
  293. data/test/pages-demo/views/demo/config/header.txt +0 -1
  294. data/test/pages-demo/views/demo/config/layout.txt +0 -1
  295. data/test/pages-demo/views/demo/config/left.txt +0 -1
  296. data/test/pages-demo/views/demo/config/main.txt +0 -1
  297. data/test/pages-demo/views/demo/config/right.txt +0 -1
  298. data/test/pages-demo/views/demo/config.txt +0 -3
  299. data/test/pages-demo/views/demo/output/panes/footer.html +0 -1
  300. data/test/pages-demo/views/demo/output/panes/header.html +0 -1
  301. data/test/pages-demo/views/demo/output/panes/left.html +0 -1
  302. data/test/pages-demo/views/demo/output/panes/main.html +0 -1
  303. data/test/pages-demo/views/demo/output/panes/right.html +0 -1
  304. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +0 -5
  305. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +0 -4
  306. data/test/scriptorium-TEST-1754622690-146/config/common.js +0 -57
  307. data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +0 -1
  308. data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +0 -9
  309. data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +0 -1
  310. data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +0 -4
  311. data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +0 -3
  312. data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +0 -8
  313. data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +0 -6
  314. data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +0 -1
  315. data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +0 -1
  316. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +0 -1
  317. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +0 -1
  318. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +0 -14
  319. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +0 -13
  320. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +0 -1
  321. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +0 -5
  322. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +0 -4
  323. data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +0 -57
  324. data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +0 -5
  325. data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +0 -2
  326. data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +0 -9
  327. data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +0 -4
  328. data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +0 -5
  329. data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +0 -3
  330. data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +0 -5
  331. data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +0 -3
  332. data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +0 -7
  333. data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +0 -3
  334. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +0 -3
  335. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +0 -3
  336. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +0 -3
  337. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +0 -3
  338. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +0 -3
  339. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +0 -1
  340. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +0 -1
  341. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +0 -1
  342. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +0 -1
  343. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +0 -1
  344. data/ui/web/tmp/web_server.pid +0 -1
  345. /data/{test/pages-demo/views/demo/config/bootstrap_css.txt → lib/scriptorium/support/bootstrap/css.txt} +0 -0
  346. /data/{test/pages-demo/views/demo/config/bootstrap_js.txt → lib/scriptorium/support/bootstrap/js.txt} +0 -0
  347. /data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/reddit.txt +0 -0
  348. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout → lib/scriptorium/support/templates}/layout.txt +0 -0
  349. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt → lib/scriptorium/support/theme/footer.lt3} +0 -0
  350. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt → lib/scriptorium/support/theme/left.lt3} +0 -0
  351. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt → lib/scriptorium/support/theme/main.lt3} +0 -0
  352. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt → lib/scriptorium/support/theme/right.lt3} +0 -0
  353. /data/test/manual/banner-tests/{config.txt → svg.txt} +0 -0
  354. /data/test/manual/{test6.rb → test_advanced_widgets.rb} +0 -0
  355. /data/test/manual/{test1.rb → test_basic_posts.rb} +0 -0
  356. /data/test/manual/{test4.rb → test_layout_widgets.rb} +0 -0
  357. /data/test/manual/{test5.rb → test_pagination.rb} +0 -0
  358. /data/test/manual/{test3.rb → test_random_posts.rb} +0 -0
@@ -28,7 +28,7 @@ class BannerSVGTest < Minitest::Test
28
28
 
29
29
  def teardown
30
30
  # Clean up any test files if needed
31
- File.delete("config.txt") if File.exist?("config.txt")
31
+ File.delete("svg.txt") if File.exist?("svg.txt")
32
32
  end
33
33
 
34
34
  # Test handle_style method
@@ -124,7 +124,7 @@ class BannerSVGTest < Minitest::Test
124
124
 
125
125
  def test_016_handle_xy_unknown_which
126
126
  # Should raise an error for invalid "which" value
127
- assert_raises(CannotHandleXYInvalidWhich) do
127
+ assert_raises(XYInvalidWhich) do
128
128
  @banner.handle_xy("unknown", "30%", "40%")
129
129
  end
130
130
  end
@@ -183,7 +183,7 @@ class BannerSVGTest < Minitest::Test
183
183
 
184
184
  def test_025_parse_header_svg_with_gradient
185
185
  # Create a temporary config file with gradient
186
- File.write("config.txt", "back.linear red blue lr")
186
+ File.write("svg.txt", "back.linear red blue lr")
187
187
 
188
188
  @banner.parse_header_svg
189
189
 
@@ -192,12 +192,12 @@ class BannerSVGTest < Minitest::Test
192
192
  assert_equal "lr", @banner.instance_variable_get(:@gradient_direction)
193
193
 
194
194
  # Clean up
195
- File.delete("config.txt") if File.exist?("config.txt")
195
+ File.delete("svg.txt") if File.exist?("svg.txt")
196
196
  end
197
197
 
198
198
  def test_026_parse_header_svg_without_gradient
199
199
  # Create a temporary config file without gradient
200
- File.write("config.txt", "back.color #fff")
200
+ File.write("svg.txt", "back.color #fff")
201
201
 
202
202
  @banner.parse_header_svg
203
203
 
@@ -207,7 +207,7 @@ class BannerSVGTest < Minitest::Test
207
207
  assert_equal "#fff", @banner.instance_variable_get(:@background)
208
208
 
209
209
  # Clean up
210
- File.delete("config.txt") if File.exist?("config.txt")
210
+ File.delete("svg.txt") if File.exist?("svg.txt")
211
211
  end
212
212
 
213
213
  # Test radial gradient functionality
@@ -225,7 +225,7 @@ class BannerSVGTest < Minitest::Test
225
225
 
226
226
  def test_029_parse_header_svg_with_radial_gradient
227
227
  # Create a temporary config file with radial gradient
228
- File.write("config.txt", "back.radial red blue")
228
+ File.write("svg.txt", "back.radial red blue")
229
229
 
230
230
  @banner.parse_header_svg
231
231
 
@@ -233,12 +233,12 @@ class BannerSVGTest < Minitest::Test
233
233
  assert_equal "blue", @banner.instance_variable_get(:@radial_end_color)
234
234
 
235
235
  # Clean up
236
- File.delete("config.txt") if File.exist?("config.txt")
236
+ File.delete("svg.txt") if File.exist?("svg.txt")
237
237
  end
238
238
 
239
239
  def test_030_radial_gradient_priority_over_linear
240
240
  # Create a temporary config file with both gradients
241
- File.write("config.txt", "back.linear green yellow lr\nback.radial red blue")
241
+ File.write("svg.txt", "back.linear green yellow lr\nback.radial red blue")
242
242
 
243
243
  @banner.parse_header_svg
244
244
 
@@ -251,7 +251,7 @@ class BannerSVGTest < Minitest::Test
251
251
  assert_equal "yellow", @banner.instance_variable_get(:@gradient_end_color)
252
252
 
253
253
  # Clean up
254
- File.delete("config.txt") if File.exist?("config.txt")
254
+ File.delete("svg.txt") if File.exist?("svg.txt")
255
255
  end
256
256
 
257
257
  # Test image background functionality
@@ -267,19 +267,19 @@ class BannerSVGTest < Minitest::Test
267
267
 
268
268
  def test_033_parse_header_svg_with_image_background
269
269
  # Create a temporary config file with image background
270
- File.write("config.txt", "back.image background.jpg")
270
+ File.write("svg.txt", "back.image background.jpg")
271
271
 
272
272
  @banner.parse_header_svg
273
273
 
274
274
  assert_equal "background.jpg", @banner.instance_variable_get(:@image_background)
275
275
 
276
276
  # Clean up
277
- File.delete("config.txt") if File.exist?("config.txt")
277
+ File.delete("svg.txt") if File.exist?("svg.txt")
278
278
  end
279
279
 
280
280
  def test_034_image_background_priority_over_all
281
281
  # Create a temporary config file with all background types
282
- File.write("config.txt", "back.color #fff\nback.linear green yellow lr\nback.radial red blue\nback.image background.jpg")
282
+ File.write("svg.txt", "back.color #fff\nback.linear green yellow lr\nback.radial red blue\nback.image background.jpg")
283
283
 
284
284
  @banner.parse_header_svg
285
285
 
@@ -294,7 +294,7 @@ class BannerSVGTest < Minitest::Test
294
294
  assert_equal "blue", @banner.instance_variable_get(:@radial_end_color)
295
295
 
296
296
  # Clean up
297
- File.delete("config.txt") if File.exist?("config.txt")
297
+ File.delete("svg.txt") if File.exist?("svg.txt")
298
298
  end
299
299
 
300
300
  # Test initialization
@@ -332,31 +332,31 @@ class BannerSVGTest < Minitest::Test
332
332
  end
333
333
 
334
334
  def test_037_read_commented_file_with_empty_file
335
- File.write("config.txt", "")
336
- result = @banner.read_commented_file("config.txt")
335
+ File.write("svg.txt", "")
336
+ result = @banner.read_commented_file("svg.txt")
337
337
  assert_equal [], result
338
338
  end
339
339
 
340
340
  def test_038_read_commented_file_with_comments_only
341
- File.write("config.txt", "# This is a comment\n# Another comment\n # Indented comment")
342
- result = @banner.read_commented_file("config.txt")
341
+ File.write("svg.txt", "# This is a comment\n# Another comment\n # Indented comment")
342
+ result = @banner.read_commented_file("svg.txt")
343
343
  assert_equal [], result
344
344
  end
345
345
 
346
346
  def test_039_read_commented_file_with_mixed_content
347
- File.write("config.txt", "# Comment\nback.color #fff\n# Another comment\nback.linear red blue\n# End comment")
348
- result = @banner.read_commented_file("config.txt")
347
+ File.write("svg.txt", "# Comment\nback.color #fff\n# Another comment\nback.linear red blue\n# End comment")
348
+ result = @banner.read_commented_file("svg.txt")
349
349
  assert_equal ["back.color #fff", "back.linear red blue"], result
350
350
  end
351
351
 
352
352
  def test_040_read_commented_file_with_trailing_comments
353
- File.write("config.txt", "back.color #fff # This is a color\nback.linear red blue # Gradient")
354
- result = @banner.read_commented_file("config.txt")
353
+ File.write("svg.txt", "back.color #fff # This is a color\nback.linear red blue # Gradient")
354
+ result = @banner.read_commented_file("svg.txt")
355
355
  assert_equal ["back.color #fff", "back.linear red blue"], result
356
356
  end
357
357
 
358
358
  def test_041_parse_header_svg_with_malformed_config_line
359
- File.write("config.txt", "back.color\nback.linear\nback.radial")
359
+ File.write("svg.txt", "back.color\nback.linear\nback.radial")
360
360
  @banner.parse_header_svg
361
361
  # Should handle gracefully without raising exceptions
362
362
  # Malformed lines should be ignored, leaving default values
@@ -372,7 +372,7 @@ class BannerSVGTest < Minitest::Test
372
372
 
373
373
  def test_043_handle_aspect_with_invalid_numeric_values
374
374
  # Should raise an error for invalid numeric value
375
- assert_raises(CannotHandleAspectInvalidValue) do
375
+ assert_raises(AspectInvalidValue) do
376
376
  @banner.handle_aspect("invalid")
377
377
  end
378
378
  end
@@ -455,13 +455,15 @@ class BannerSVGTest < Minitest::Test
455
455
  def test_052_svg_output_text_has_required_attributes
456
456
  svg_output = @banner.parse_header_svg
457
457
 
458
+
459
+
458
460
  # Check text attributes
459
461
  # Note: assert_present is a nonstandard assertion from TestHelpers
460
462
  assert_present(svg_output, "text-anchor='start'")
461
463
  assert_present(svg_output, "fill='#374151'")
462
464
  assert_present(svg_output, 'font-family: Verdana')
463
- assert_present(svg_output, 'font-size: 48px') # title
464
- assert_present(svg_output, 'font-size: 24px') # subtitle
465
+ assert_present(svg_output, 'font-size: 48.0px') # title (base_font_size * 0.8)
466
+ assert_present(svg_output, 'font-size: 24.0px') # subtitle (base_font_size * 0.4)
465
467
  end
466
468
 
467
469
  def test_053_svg_output_with_linear_gradient
@@ -520,7 +522,7 @@ class BannerSVGTest < Minitest::Test
520
522
  @banner.handle_xy("subtitle", "15%", "25%")
521
523
  svg_output = @banner.parse_header_svg
522
524
 
523
- # Check text positioning
525
+ # Check text positioning - coordinates are now in the SVG text elements
524
526
  assert_present(svg_output, "x='10%'")
525
527
  assert_present(svg_output, "y='20%'")
526
528
  assert_present(svg_output, "x='15%'")
@@ -576,7 +578,7 @@ class BannerSVGTest < Minitest::Test
576
578
  subtitle.xy 50% 70%
577
579
  CONFIG
578
580
 
579
- File.write("config.txt", config_content)
581
+ File.write("svg.txt", config_content)
580
582
  @banner.parse_header_svg
581
583
 
582
584
  # Verify all settings were applied
@@ -605,7 +607,7 @@ class BannerSVGTest < Minitest::Test
605
607
  def test_061_end_to_end_workflow
606
608
  # Test complete workflow from config to final output
607
609
  config_content = "back.color #e0e0e0\ntext.color #000\ntitle.style bold\nsubtitle.xy 10% 80%"
608
- File.write("config.txt", config_content)
610
+ File.write("svg.txt", config_content)
609
611
 
610
612
  # Parse config
611
613
  @banner.parse_header_svg
@@ -645,8 +647,8 @@ class BannerSVGTest < Minitest::Test
645
647
  # Check for JavaScript variables
646
648
  assert_present(js_output, 'const svgWidth = window.innerWidth')
647
649
  assert_present(js_output, 'const aspectRatio = 8.0')
648
- assert_present(js_output, 'const titleScale = 0.8')
649
- assert_present(js_output, 'const subtitleScale = 0.4')
650
+ assert_present(js_output, 'const titleFontSize = 0.8 * 60')
651
+ assert_present(js_output, 'const subtitleFontSize = 0.4 * 60')
650
652
  end
651
653
 
652
654
  def test_063_javascript_with_custom_settings
@@ -659,15 +661,15 @@ class BannerSVGTest < Minitest::Test
659
661
 
660
662
  # Check that custom values are interpolated into JavaScript
661
663
  assert_present(js_output, 'const aspectRatio = 4.0')
662
- assert_present(js_output, 'const titleScale = 1.5')
663
- assert_present(js_output, 'const subtitleScale = 0.6')
664
+ assert_present(js_output, 'const titleFontSize = 1.5 * 60')
665
+ assert_present(js_output, 'const subtitleFontSize = 0.6 * 60')
664
666
  assert_present(js_output, "fill='#ff0000'")
665
667
  end
666
668
 
667
669
  def test_064_background_priority_integration
668
670
  # Test that background priority works correctly in full workflow
669
671
  config_content = "back.color #fff\nback.linear red blue\nback.radial green yellow\nback.image bg.jpg"
670
- File.write("config.txt", config_content)
672
+ File.write("svg.txt", config_content)
671
673
 
672
674
  @banner.parse_header_svg
673
675
  svg_output = @banner.parse_header_svg
@@ -718,7 +720,7 @@ class BannerSVGTest < Minitest::Test
718
720
  assert_equal "end", @banner.instance_variable_get(:@subtitle_text_anchor)
719
721
 
720
722
  # Should raise an error for invalid direction
721
- assert_raises(CannotHandleAlignInvalidDirection) do
723
+ assert_raises(AlignInvalidDirection) do
722
724
  @banner.handle_text_align("invalid")
723
725
  end
724
726
  end
@@ -765,4 +767,234 @@ class BannerSVGTest < Minitest::Test
765
767
  assert_match(/Warning: title.align x=50% conflicts with title.xy x=5%/, captured)
766
768
  end
767
769
 
770
+ # ========================================
771
+ # Banner SVG Validation Error Tests
772
+ # ========================================
773
+
774
+ def test_072_banner_svg_validation_exceptions
775
+ # Test that exception classes exist
776
+ assert InvalidBackground
777
+ assert InvalidGradient
778
+ assert InvalidImage
779
+ assert InvalidFont
780
+ assert InvalidColor
781
+ assert InvalidAspect
782
+ assert InvalidAlign
783
+ assert InvalidXY
784
+ end
785
+
786
+ def test_073_background_validation_exceptions
787
+ # Test that exception classes exist
788
+ assert BackgroundNoArgs
789
+ assert BackgroundFirstArgNil
790
+ assert BackgroundFirstArgEmpty
791
+
792
+ # Test actual exception raising
793
+ assert_raises(BackgroundNoArgs) do
794
+ @banner.handle_background
795
+ end
796
+
797
+ assert_raises(BackgroundFirstArgNil) do
798
+ @banner.handle_background(nil)
799
+ end
800
+
801
+ assert_raises(BackgroundFirstArgEmpty) do
802
+ @banner.handle_background("")
803
+ end
804
+ end
805
+
806
+ def test_074_gradient_validation_exceptions
807
+ # Test that exception classes exist
808
+ assert LinearGradientNoArgs
809
+ assert LinearGradientStartColorNil
810
+ assert LinearGradientArgEmpty
811
+ assert RadialGradientNoArgs
812
+ assert RadialGradientStartColorNil
813
+ assert RadialGradientArgEmpty
814
+
815
+ # Test actual exception raising for linear gradient
816
+ assert_raises(LinearGradientNoArgs) do
817
+ @banner.handle_linear_gradient
818
+ end
819
+
820
+ assert_raises(LinearGradientStartColorNil) do
821
+ @banner.handle_linear_gradient(nil, "blue")
822
+ end
823
+
824
+ assert_raises(LinearGradientStartColorNil) do
825
+ @banner.handle_linear_gradient("", "blue")
826
+ end
827
+
828
+ assert_raises(LinearGradientArgEmpty) do
829
+ @banner.handle_linear_gradient("red", "")
830
+ end
831
+
832
+ # Test actual exception raising for radial gradient
833
+ assert_raises(RadialGradientNoArgs) do
834
+ @banner.handle_radial_gradient
835
+ end
836
+
837
+ assert_raises(RadialGradientStartColorNil) do
838
+ @banner.handle_radial_gradient(nil, "yellow")
839
+ end
840
+
841
+ assert_raises(RadialGradientStartColorNil) do
842
+ @banner.handle_radial_gradient("", "yellow")
843
+ end
844
+
845
+ assert_raises(RadialGradientArgEmpty) do
846
+ @banner.handle_radial_gradient("green", "")
847
+ end
848
+ end
849
+
850
+ def test_075_image_background_validation_exceptions
851
+ # Test that exception classes exist
852
+ assert ImageBackgroundNoArgs
853
+ assert ImageBackgroundFirstArgNil
854
+ assert ImageBackgroundFirstArgEmpty
855
+
856
+ # Test actual exception raising
857
+ assert_raises(ImageBackgroundNoArgs) do
858
+ @banner.handle_image_background
859
+ end
860
+
861
+ assert_raises(ImageBackgroundFirstArgNil) do
862
+ @banner.handle_image_background(nil)
863
+ end
864
+
865
+ assert_raises(ImageBackgroundFirstArgEmpty) do
866
+ @banner.handle_image_background("")
867
+ end
868
+ end
869
+
870
+ def test_076_aspect_validation_exceptions
871
+ # Test that exception classes exist
872
+ assert AspectNoArgs
873
+ assert AspectFirstArgNil
874
+ assert AspectFirstArgEmpty
875
+ assert AspectInvalidValue
876
+
877
+ # Test actual exception raising
878
+ assert_raises(AspectNoArgs) do
879
+ @banner.handle_aspect
880
+ end
881
+
882
+ assert_raises(AspectFirstArgNil) do
883
+ @banner.handle_aspect(nil)
884
+ end
885
+
886
+ assert_raises(AspectFirstArgEmpty) do
887
+ @banner.handle_aspect("")
888
+ end
889
+
890
+ assert_raises(AspectInvalidValue) do
891
+ @banner.handle_aspect("invalid")
892
+ end
893
+ end
894
+
895
+ def test_077_font_validation_exceptions
896
+ # Test that exception classes exist
897
+ assert FontArgsNil
898
+ assert FontArgNil
899
+ assert FontArgEmpty
900
+
901
+ # Test actual exception raising
902
+ assert_raises(FontArgNil) do
903
+ @banner.handle_font(nil)
904
+ end
905
+
906
+ assert_raises(FontArgNil) do
907
+ @banner.handle_font("Arial", nil)
908
+ end
909
+
910
+ assert_raises(FontArgEmpty) do
911
+ @banner.handle_font("Arial", "")
912
+ end
913
+ end
914
+
915
+ def test_078_text_color_validation_exceptions
916
+ # Test that exception classes exist
917
+ assert TextColorNoArgs
918
+ assert TextColorFirstArgNil
919
+ assert TextColorFirstArgEmpty
920
+
921
+ # Test actual exception raising
922
+ assert_raises(TextColorNoArgs) do
923
+ @banner.handle_text_color
924
+ end
925
+
926
+ assert_raises(TextColorFirstArgNil) do
927
+ @banner.handle_text_color(nil)
928
+ end
929
+
930
+ assert_raises(TextColorFirstArgEmpty) do
931
+ @banner.handle_text_color("")
932
+ end
933
+ end
934
+
935
+ def test_079_xy_validation_exceptions
936
+ # Test that exception classes exist
937
+ assert XYWhichNil
938
+ assert XYWhichEmpty
939
+ assert XYInvalidWhich
940
+
941
+ # Test actual exception raising
942
+ assert_raises(XYWhichNil) do
943
+ @banner.handle_xy(nil, "5%", "70%")
944
+ end
945
+
946
+ assert_raises(XYWhichEmpty) do
947
+ @banner.handle_xy("", "5%", "70%")
948
+ end
949
+
950
+ assert_raises(XYInvalidWhich) do
951
+ @banner.handle_xy("invalid", "5%", "70%")
952
+ end
953
+ end
954
+
955
+ def test_080_align_validation_exceptions
956
+ # Test that exception classes exist
957
+ assert AlignNoArgs
958
+ assert AlignDirectionNil
959
+ assert AlignArgEmpty
960
+ assert AlignInvalidDirection
961
+
962
+ # Test actual exception raising
963
+ assert_raises(AlignNoArgs) do
964
+ @banner.handle_text_align
965
+ end
966
+
967
+ assert_raises(AlignDirectionNil) do
968
+ @banner.handle_text_align(nil)
969
+ end
970
+
971
+ assert_raises(AlignDirectionNil) do
972
+ @banner.handle_text_align("")
973
+ end
974
+
975
+ assert_raises(AlignInvalidDirection) do
976
+ @banner.handle_text_align("invalid")
977
+ end
978
+ end
979
+
980
+ def test_081_color_validation_exceptions
981
+ # Test that exception classes exist
982
+ assert ColorNoArgs
983
+ assert ColorFirstArgNil
984
+ assert ColorFirstArgEmpty
985
+
986
+ # Test actual exception raising
987
+ assert_raises(ColorNoArgs) do
988
+ @banner.handle_title_color
989
+ end
990
+
991
+ assert_raises(ColorFirstArgNil) do
992
+ @banner.handle_title_color(nil)
993
+ end
994
+
995
+ assert_raises(ColorFirstArgEmpty) do
996
+ @banner.handle_title_color("")
997
+ end
998
+ end
999
+
768
1000
  end
@@ -0,0 +1,5 @@
1
+ user blogtest
2
+ server gymnos.media
3
+ docroot /var/www/gymnos
4
+ path blogtest
5
+ proto https
@@ -33,7 +33,7 @@ class IntegrationTest < Minitest::Test
33
33
  output = @sample_view.dir/:output/:panes/"header.html"
34
34
  assert File.exist?(output), "Expected header.html to exist"
35
35
  content = File.read(output)
36
- assert_includes content, "<h1>", "Expected header content to include <h1>"
36
+ assert_includes_concise_string content, "<h1>", "Expected header content to include <h1>"
37
37
  end
38
38
 
39
39
  def test_002_posts_generated_and_indexed_across_multiple_views
@@ -63,7 +63,7 @@ class IntegrationTest < Minitest::Test
63
63
  posts_content = File.read(@repo.root/:views/"blog1"/:output/"index.html")
64
64
  posts = @repo.all_posts("blog1")
65
65
  posts.each do |post|
66
- assert_includes posts_content, post.title
66
+ assert_includes_concise_string posts_content, post.title, "Post title should appear in index"
67
67
  month, day, year = post.pubdate_month_day_year
68
68
  assert_includes posts_content, month + " " + day
69
69
  assert_includes posts_content, year
@@ -95,9 +95,9 @@ class IntegrationTest < Minitest::Test
95
95
  @repo.all_posts("blog1").each do |post|
96
96
  next unless post.pubdate && post.title
97
97
  month, day, year = post.pubdate_month_day_year
98
- assert_includes content, month + " " + day + "</div>", "Expected pubdate #{month} #{day} to appear"
99
- assert_includes content, year + "</div>", "Expected year #{year} to appear"
100
- assert_includes content, post.title, "Expected title #{post.title} to appear"
98
+ assert_includes_concise_string content, month + " " + day + ",", "Expected pubdate #{month} #{day} to appear"
99
+ assert_includes_concise_string content, year + "</div>", "Expected year #{year} to appear"
100
+ assert_includes_concise_string content, post.title, "Expected title #{post.title} to appear"
101
101
  end
102
102
  end
103
103
 
@@ -249,8 +249,8 @@ class IntegrationTest < Minitest::Test
249
249
  assert_present(index_html, *targets)
250
250
  assert_ordered(index_html, *targets)
251
251
  FileUtils.cp(index_file, "/tmp/testcms1.html")
252
- post_div = %[class="index-entry"]
253
- num_posts = index_html.scan(/#{Regexp.escape(post_div)}/).length
252
+ post_links = %[onclick="load_main]
253
+ num_posts = index_html.scan(/#{Regexp.escape(post_links)}/).length
254
254
  assert_equal 7, num_posts, "Expected 7 posts, found #{num_posts}"
255
255
  end
256
256
 
@@ -0,0 +1,94 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../../lib/scriptorium'
3
+ require_relative '../test_helpers'
4
+ require 'fileutils'
5
+ require_relative '../support/preview_utils'
6
+
7
+ class PreviewFlowTest < Minitest::Test
8
+ include TestHelpers
9
+
10
+ def setup
11
+ @repo_name = "test/scriptorium-TEST"
12
+ @view_name = "preview_test_view"
13
+
14
+ @api = Scriptorium::API.new
15
+ # Ensure a clean slate before creating the repo
16
+ begin
17
+ FileUtils.rm_rf(@repo_name)
18
+ backup_dir = File.join(File.dirname(@repo_name), 'backup-scriptorium-TEST')
19
+ FileUtils.rm_rf(backup_dir)
20
+ rescue => e
21
+ puts "[Integration] Warning: cleanup failed: #{e.message}"
22
+ end
23
+ @api.create_repo(@repo_name)
24
+ @api.open_repo(@repo_name)
25
+ @api.create_view(@view_name, "Preview Test View")
26
+
27
+ # Add a couple of posts
28
+ @api.create_post("Final Test Post", "ADD BLURB HERE")
29
+ @api.create_post("Another New Post", "ADD BLURB HERE")
30
+
31
+ # Configure date format with break and small pagination (via shared helper)
32
+ PreviewUtils.write_post_index_config(@repo_name, @view_name, {
33
+ "posts.per.page" => "5",
34
+ "entry.date.format" => "month dd break yyyy"
35
+ })
36
+
37
+ # Upload a global image and reference it from the first post via .image
38
+ test_asset = Tempfile.new(['previewflow', '.jpg'])
39
+ begin
40
+ test_asset.write("x")
41
+ test_asset.close
42
+ @api.upload_asset(test_asset.path, filename: "previewflow.jpg")
43
+ ensure
44
+ test_asset.unlink rescue nil
45
+ end
46
+
47
+ # Insert image reference into post 0001
48
+ src1 = "#{@repo_name}/posts/0001/source.lt3"
49
+ File.write(src1, ".image previewflow.jpg\n\nHello")
50
+
51
+ # Generate view
52
+ @api.generate_view(@view_name)
53
+ end
54
+
55
+ def teardown
56
+ FileUtils.rm_rf(@repo_name)
57
+ end
58
+
59
+ def test_post_index_has_table_and_formatted_dates
60
+ post_index = "#{@repo_name}/views/#{@view_name}/output/post_index.html"
61
+ assert File.exist?(post_index), "Expected post_index.html to exist"
62
+ content = File.read(post_index)
63
+ assert_includes content, "<table", "post_index should be wrapped in a table"
64
+ assert_includes content, "<br>", "post_index should include a line break in the date"
65
+ end
66
+
67
+ def test_paginated_page_table_wrapper
68
+ page1 = "#{@repo_name}/views/#{@view_name}/output/page1.html"
69
+ assert File.exist?(page1), "Expected page1.html to exist"
70
+ content = File.read(page1)
71
+ assert_includes content, "<table", "page1 should be wrapped in a table"
72
+ end
73
+
74
+ def test_index_inlines_table_content
75
+ index = "#{@repo_name}/views/#{@view_name}/output/index.html"
76
+ assert File.exist?(index), "Expected index.html to exist"
77
+ content = File.read(index)
78
+ # The main section should include a table from post_index inclusion
79
+ assert_includes content, "<table", "index should inline post_index table"
80
+ end
81
+
82
+ def test_post_page_references_assets_relatively
83
+ # Verify that the first post page references ../assets/ for the image
84
+ # Find slug for post 0001 from its meta
85
+ meta = File.read("#{@repo_name}/posts/0001/meta.txt")
86
+ slug = meta.lines.grep(/^post.slug\s+/).first.split.last
87
+ post_html = "#{@repo_name}/views/#{@view_name}/output/posts/#{slug}"
88
+ assert File.exist?(post_html), "Expected post HTML to exist"
89
+ html = File.read(post_html)
90
+ assert_includes html, "<img src=../assets/previewflow.jpg", "Post image should use ../assets/ path"
91
+ end
92
+ end
93
+
94
+