publify_core 9.0.0 → 9.2.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 (360) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +92 -37
  3. data/app/assets/javascripts/bootstrap-sprockets.js +8 -0
  4. data/app/assets/javascripts/bootstrap/affix.js +164 -0
  5. data/app/assets/javascripts/bootstrap/alert.js +95 -0
  6. data/app/assets/javascripts/bootstrap/button.js +125 -0
  7. data/app/assets/javascripts/bootstrap/collapse.js +212 -0
  8. data/app/assets/javascripts/bootstrap/dropdown.js +165 -0
  9. data/app/assets/javascripts/bootstrap/modal.js +358 -0
  10. data/app/assets/javascripts/bootstrap/tab.js +155 -0
  11. data/app/assets/javascripts/bootstrap/transition.js +59 -0
  12. data/app/assets/javascripts/lightbox.js +4 -4
  13. data/app/assets/javascripts/publify_admin.js +1 -35
  14. data/app/assets/stylesheets/_bootstrap-compass.scss +9 -0
  15. data/app/assets/stylesheets/_bootstrap-mincer.scss +19 -0
  16. data/app/assets/stylesheets/_bootstrap-sprockets.scss +9 -0
  17. data/app/assets/stylesheets/_bootstrap.scss +42 -0
  18. data/app/assets/stylesheets/administration_structure.css.scss +1 -45
  19. data/app/assets/stylesheets/bootstrap/_alerts.scss +73 -0
  20. data/app/assets/stylesheets/bootstrap/_button-groups.scss +242 -0
  21. data/app/assets/stylesheets/bootstrap/_buttons.scss +168 -0
  22. data/app/assets/stylesheets/bootstrap/_close.scss +37 -0
  23. data/app/assets/stylesheets/bootstrap/_code.scss +69 -0
  24. data/app/assets/stylesheets/bootstrap/_component-animations.scss +38 -0
  25. data/app/assets/stylesheets/bootstrap/_dropdowns.scss +213 -0
  26. data/app/assets/stylesheets/bootstrap/_forms.scss +586 -0
  27. data/app/assets/stylesheets/bootstrap/_grid.scss +94 -0
  28. data/app/assets/stylesheets/bootstrap/_labels.scss +66 -0
  29. data/app/assets/stylesheets/bootstrap/_media.scss +66 -0
  30. data/app/assets/stylesheets/bootstrap/_mixins.scss +37 -0
  31. data/app/assets/stylesheets/bootstrap/_modals.scss +150 -0
  32. data/app/assets/stylesheets/bootstrap/_navbar.scss +479 -0
  33. data/app/assets/stylesheets/bootstrap/_navs.scss +242 -0
  34. data/app/assets/stylesheets/bootstrap/_normalize.scss +427 -0
  35. data/app/assets/stylesheets/bootstrap/_pagination.scss +86 -0
  36. data/app/assets/stylesheets/bootstrap/_panels.scss +222 -0
  37. data/app/assets/stylesheets/bootstrap/_print.scss +99 -0
  38. data/app/assets/stylesheets/bootstrap/_scaffolding.scss +160 -0
  39. data/app/assets/stylesheets/bootstrap/_tables.scss +234 -0
  40. data/app/assets/stylesheets/bootstrap/_theme.scss +224 -0
  41. data/app/assets/stylesheets/bootstrap/_type.scss +296 -0
  42. data/app/assets/stylesheets/bootstrap/_utilities.scss +55 -0
  43. data/app/assets/stylesheets/bootstrap/_variables.scss +638 -0
  44. data/app/assets/stylesheets/bootstrap/_wells.scss +29 -0
  45. data/app/assets/stylesheets/bootstrap/mixins/_alerts.scss +15 -0
  46. data/app/assets/stylesheets/bootstrap/mixins/_background-variant.scss +12 -0
  47. data/app/assets/stylesheets/bootstrap/mixins/_border-radius.scss +18 -0
  48. data/app/assets/stylesheets/bootstrap/mixins/_buttons.scss +56 -0
  49. data/app/assets/stylesheets/bootstrap/mixins/_center-block.scss +7 -0
  50. data/app/assets/stylesheets/bootstrap/mixins/_clearfix.scss +22 -0
  51. data/app/assets/stylesheets/bootstrap/mixins/_forms.scss +82 -0
  52. data/app/assets/stylesheets/bootstrap/mixins/_gradients.scss +56 -0
  53. data/app/assets/stylesheets/bootstrap/mixins/_grid-framework.scss +81 -0
  54. data/app/assets/stylesheets/bootstrap/mixins/_grid.scss +122 -0
  55. data/app/assets/stylesheets/bootstrap/mixins/_hide-text.scss +21 -0
  56. data/app/assets/stylesheets/bootstrap/mixins/_image.scss +28 -0
  57. data/app/assets/stylesheets/bootstrap/mixins/_labels.scss +12 -0
  58. data/app/assets/stylesheets/bootstrap/mixins/_nav-divider.scss +10 -0
  59. data/app/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss +9 -0
  60. data/app/assets/stylesheets/bootstrap/mixins/_opacity.scss +7 -0
  61. data/app/assets/stylesheets/bootstrap/mixins/_pagination.scss +24 -0
  62. data/app/assets/stylesheets/bootstrap/mixins/_panels.scss +20 -0
  63. data/app/assets/stylesheets/bootstrap/mixins/_reset-filter.scss +8 -0
  64. data/app/assets/stylesheets/bootstrap/mixins/_resize.scss +6 -0
  65. data/app/assets/stylesheets/bootstrap/mixins/_responsive-visibility.scss +17 -0
  66. data/app/assets/stylesheets/bootstrap/mixins/_size.scss +10 -0
  67. data/app/assets/stylesheets/bootstrap/mixins/_tab-focus.scss +9 -0
  68. data/app/assets/stylesheets/bootstrap/mixins/_table-row.scss +28 -0
  69. data/app/assets/stylesheets/bootstrap/mixins/_text-emphasis.scss +12 -0
  70. data/app/assets/stylesheets/bootstrap/mixins/_text-overflow.scss +8 -0
  71. data/app/assets/stylesheets/bootstrap/mixins/_vendor-prefixes.scss +222 -0
  72. data/app/assets/stylesheets/lightbox.css +3 -3
  73. data/app/assets/stylesheets/publify_admin.css.scss +0 -1
  74. data/app/controllers/accounts_controller.rb +2 -0
  75. data/app/controllers/admin/base_controller.rb +8 -16
  76. data/app/controllers/admin/content_controller.rb +38 -36
  77. data/app/controllers/admin/dashboard_controller.rb +16 -65
  78. data/app/controllers/admin/feedback_controller.rb +45 -37
  79. data/app/controllers/admin/notes_controller.rb +16 -10
  80. data/app/controllers/admin/pages_controller.rb +19 -29
  81. data/app/controllers/admin/post_types_controller.rb +7 -5
  82. data/app/controllers/admin/profiles_controller.rb +15 -5
  83. data/app/controllers/admin/redirects_controller.rb +9 -5
  84. data/app/controllers/admin/resources_controller.rb +7 -4
  85. data/app/controllers/admin/seo_controller.rb +12 -10
  86. data/app/controllers/admin/settings_controller.rb +7 -5
  87. data/app/controllers/admin/sidebar_controller.rb +6 -5
  88. data/app/controllers/admin/tags_controller.rb +6 -3
  89. data/app/controllers/admin/themes_controller.rb +10 -7
  90. data/app/controllers/admin/users_controller.rb +10 -7
  91. data/app/controllers/articles_controller.rb +49 -33
  92. data/app/controllers/authors_controller.rb +6 -3
  93. data/app/controllers/base_controller.rb +9 -11
  94. data/app/controllers/comments_controller.rb +13 -13
  95. data/app/controllers/content_controller.rb +4 -2
  96. data/app/controllers/feedback_controller.rb +4 -2
  97. data/app/controllers/notes_controller.rb +5 -3
  98. data/app/controllers/setup_controller.rb +15 -12
  99. data/app/controllers/tags_controller.rb +6 -4
  100. data/app/controllers/text_controller.rb +2 -4
  101. data/app/controllers/textfilter_controller.rb +2 -0
  102. data/app/controllers/theme_controller.rb +18 -13
  103. data/app/controllers/xml_controller.rb +2 -0
  104. data/app/helpers/admin/base_helper.rb +28 -29
  105. data/app/helpers/admin/feedback_helper.rb +34 -24
  106. data/app/helpers/articles_helper.rb +4 -2
  107. data/app/helpers/authors_helper.rb +7 -16
  108. data/app/helpers/base_helper.rb +56 -52
  109. data/app/helpers/blog_helper.rb +4 -2
  110. data/app/helpers/xml_helper.rb +3 -1
  111. data/app/jobs/application_job.rb +2 -0
  112. data/app/mailers/notification_mailer.rb +5 -3
  113. data/app/models/ability.rb +25 -23
  114. data/app/models/archives_sidebar.rb +14 -11
  115. data/app/models/article.rb +42 -42
  116. data/app/models/article/factory.rb +14 -6
  117. data/app/models/blog.rb +86 -75
  118. data/app/models/comment.rb +10 -11
  119. data/app/models/config_manager.rb +4 -2
  120. data/app/models/content.rb +37 -50
  121. data/app/models/content_base.rb +10 -4
  122. data/app/models/feedback.rb +21 -17
  123. data/app/models/meta_sidebar.rb +4 -3
  124. data/app/models/note.rb +26 -25
  125. data/app/models/page.rb +9 -8
  126. data/app/models/page_sidebar.rb +4 -2
  127. data/app/models/ping.rb +3 -1
  128. data/app/models/post_type.rb +3 -3
  129. data/app/models/redirect.rb +13 -7
  130. data/app/models/redirection.rb +3 -1
  131. data/app/models/resource.rb +5 -3
  132. data/app/models/search_sidebar.rb +4 -2
  133. data/app/models/sidebar.rb +11 -6
  134. data/app/models/static_sidebar.rb +14 -13
  135. data/app/models/tag.rb +15 -11
  136. data/app/models/tag_sidebar.rb +6 -3
  137. data/app/models/text_filter.rb +85 -11
  138. data/app/models/trackback.rb +7 -11
  139. data/app/models/trigger.rb +7 -4
  140. data/app/models/user.rb +44 -43
  141. data/app/services/title_builder.rb +52 -45
  142. data/app/uploaders/resource_uploader.rb +5 -3
  143. data/app/views/accounts/confirm.html.erb +3 -3
  144. data/app/views/admin/content/_article_list.html.erb +23 -8
  145. data/app/views/admin/content/_form.html.erb +71 -47
  146. data/app/views/admin/content/autosave.js.erb +2 -2
  147. data/app/views/admin/content/edit.html.erb +1 -1
  148. data/app/views/admin/content/index.html.erb +25 -15
  149. data/app/views/admin/content/new.html.erb +2 -2
  150. data/app/views/admin/dashboard/_comment.html.erb +5 -5
  151. data/app/views/admin/dashboard/_comments.html.erb +2 -2
  152. data/app/views/admin/dashboard/_drafts.html.erb +5 -5
  153. data/app/views/admin/dashboard/_overview.html.erb +7 -9
  154. data/app/views/admin/dashboard/_welcome.html.erb +11 -11
  155. data/app/views/admin/dashboard/index.html.erb +12 -7
  156. data/app/views/admin/feedback/_button.html.erb +6 -6
  157. data/app/views/admin/feedback/_feedback.html.erb +3 -3
  158. data/app/views/admin/feedback/_ham.html.erb +27 -9
  159. data/app/views/admin/feedback/_spam.html.erb +26 -16
  160. data/app/views/admin/feedback/article.html.erb +20 -21
  161. data/app/views/admin/feedback/edit.html.erb +14 -15
  162. data/app/views/admin/feedback/{ham.js → ham.js.erb} +0 -0
  163. data/app/views/admin/feedback/index.html.erb +25 -23
  164. data/app/views/admin/feedback/{spam.js → spam.js.erb} +0 -0
  165. data/app/views/admin/migrations/show.html.erb +10 -11
  166. data/app/views/admin/notes/_form.html.erb +13 -13
  167. data/app/views/admin/notes/_list.html.erb +19 -8
  168. data/app/views/admin/notes/_note.html.erb +12 -7
  169. data/app/views/admin/notes/edit.html.erb +6 -1
  170. data/app/views/admin/notes/index.html.erb +5 -1
  171. data/app/views/admin/notes/show.html.erb +2 -2
  172. data/app/views/admin/pages/_form.html.erb +86 -77
  173. data/app/views/admin/pages/_pages.html.erb +11 -4
  174. data/app/views/admin/pages/edit.html.erb +3 -1
  175. data/app/views/admin/pages/index.html.erb +10 -6
  176. data/app/views/admin/pages/new.html.erb +3 -1
  177. data/app/views/admin/post_types/_index_and_form.html.erb +15 -16
  178. data/app/views/admin/post_types/edit.html.erb +1 -1
  179. data/app/views/admin/post_types/index.html.erb +1 -1
  180. data/app/views/admin/profiles/index.html.erb +2 -3
  181. data/app/views/admin/redirects/_index_and_form.html.erb +10 -11
  182. data/app/views/admin/redirects/edit.html.erb +1 -1
  183. data/app/views/admin/redirects/index.html.erb +1 -1
  184. data/app/views/admin/resources/index.html.erb +19 -16
  185. data/app/views/admin/seo/_general.html.erb +23 -47
  186. data/app/views/admin/seo/_permalinks.html.erb +16 -16
  187. data/app/views/admin/seo/_titles.html.erb +63 -64
  188. data/app/views/admin/seo/show.html.erb +14 -19
  189. data/app/views/admin/settings/display.html.erb +22 -25
  190. data/app/views/admin/settings/feedback.html.erb +31 -32
  191. data/app/views/admin/settings/index.html.erb +23 -24
  192. data/app/views/admin/settings/write.html.erb +21 -22
  193. data/app/views/admin/shared/_edit.html.erb +3 -3
  194. data/app/views/admin/shared/_menu.html.erb +26 -26
  195. data/app/views/admin/shared/_twitter_alert.html.erb +1 -1
  196. data/app/views/admin/sidebar/_config.html.erb +5 -5
  197. data/app/views/admin/sidebar/_target_sidebar.html.erb +4 -4
  198. data/app/views/admin/sidebar/index.html.erb +7 -7
  199. data/app/views/admin/tags/_index_and_form.html.erb +11 -12
  200. data/app/views/admin/tags/edit.html.erb +1 -1
  201. data/app/views/admin/tags/index.html.erb +1 -1
  202. data/app/views/admin/themes/index.html.erb +5 -6
  203. data/app/views/admin/users/_form.html.erb +34 -34
  204. data/app/views/admin/users/edit.html.erb +2 -2
  205. data/app/views/admin/users/index.html.erb +10 -12
  206. data/app/views/admin/users/new.html.erb +2 -2
  207. data/app/views/archives_sidebar/_content.html.erb +2 -2
  208. data/app/views/articles/_archives_article.html.erb +3 -3
  209. data/app/views/articles/_article.html.erb +7 -9
  210. data/app/views/articles/_article_author.html.erb +4 -0
  211. data/app/views/articles/_article_content.html.erb +2 -2
  212. data/app/views/articles/_article_excerpt.html.erb +2 -2
  213. data/app/views/articles/_article_links.html.erb +1 -1
  214. data/app/views/articles/_comment_errors.html.erb +1 -1
  215. data/app/views/articles/_comment_form.html.erb +12 -12
  216. data/app/views/articles/_comment_preview.html.erb +3 -3
  217. data/app/views/articles/_password_form.html.erb +4 -4
  218. data/app/views/articles/_trackback.html.erb +2 -2
  219. data/app/views/articles/archives.html.erb +1 -1
  220. data/app/views/articles/feedback_atom_feed.atom.builder +3 -1
  221. data/app/views/articles/feedback_rss_feed.rss.builder +9 -8
  222. data/app/views/articles/index_atom_feed.atom.builder +5 -3
  223. data/app/views/articles/index_rss_feed.rss.builder +10 -9
  224. data/app/views/articles/live_search.html.erb +3 -3
  225. data/app/views/articles/read.html.erb +16 -8
  226. data/app/views/articles/search.html.erb +2 -2
  227. data/app/views/articles/trackback.xml.builder +3 -1
  228. data/app/views/articles/view_page.html.erb +2 -2
  229. data/app/views/authors/show.html.erb +9 -9
  230. data/app/views/authors/show_atom_feed.atom.builder +4 -2
  231. data/app/views/authors/show_rss_feed.rss.builder +10 -9
  232. data/app/views/comments/_comment.html.erb +3 -3
  233. data/app/views/devise/mailer/reset_password_instructions.html.erb +7 -9
  234. data/app/views/devise/passwords/edit.html.erb +4 -4
  235. data/app/views/devise/passwords/new.html.erb +1 -1
  236. data/app/views/devise/registrations/new.html.erb +5 -5
  237. data/app/views/devise/sessions/new.html.erb +3 -3
  238. data/app/views/errors/404.html.erb +2 -2
  239. data/app/views/feedback/index.atom.builder +3 -1
  240. data/app/views/feedback/index.rss.builder +9 -8
  241. data/app/views/layouts/accounts.html.erb +26 -26
  242. data/app/views/layouts/administration.html.erb +31 -31
  243. data/app/views/layouts/default.html.erb +4 -3
  244. data/app/views/layouts/editor.html.erb +5 -19
  245. data/app/views/meta_sidebar/_content.html.erb +2 -2
  246. data/app/views/notes/_note.html.erb +1 -1
  247. data/app/views/notes/index.html.erb +1 -1
  248. data/app/views/notes/show_in_reply.html.erb +1 -1
  249. data/app/views/notification_mailer/_mail_footer.html.erb +3 -3
  250. data/app/views/notification_mailer/article.html.erb +2 -2
  251. data/app/views/notification_mailer/comment.html.erb +5 -5
  252. data/app/views/notification_mailer/notif_user.html.erb +1 -1
  253. data/app/views/page_sidebar/_content.html.erb +1 -1
  254. data/app/views/search_sidebar/_content.html.erb +2 -2
  255. data/app/views/settings/install.html.erb +2 -2
  256. data/app/views/setup/index.html.erb +7 -7
  257. data/app/views/shared/_atom_header.atom.builder +4 -4
  258. data/app/views/shared/_atom_item_article.atom.builder +19 -29
  259. data/app/views/shared/_atom_item_comment.atom.builder +4 -2
  260. data/app/views/shared/_atom_item_trackback.atom.builder +4 -2
  261. data/app/views/shared/_google_analytics.html.erb +8 -0
  262. data/app/views/shared/_page_header.html.erb +9 -12
  263. data/app/views/shared/_rss_item_article.rss.builder +9 -7
  264. data/app/views/shared/_rss_item_comment.rss.builder +3 -1
  265. data/app/views/shared/_rss_item_trackback.rss.builder +3 -1
  266. data/app/views/sidebar/display_plugins.html.erb +1 -1
  267. data/app/views/tag_sidebar/_content.html.erb +1 -1
  268. data/app/views/tags/index.html.erb +1 -1
  269. data/app/views/xml/_googlesitemap_item_article.googlesitemap.builder +2 -0
  270. data/app/views/xml/_googlesitemap_item_category.googlesitemap.builder +2 -0
  271. data/app/views/xml/_googlesitemap_item_page.googlesitemap.builder +2 -0
  272. data/app/views/xml/_googlesitemap_item_tag.googlesitemap.builder +2 -0
  273. data/app/views/xml/sitemap.googlesitemap.builder +4 -2
  274. data/config/i18n-tasks.yml +0 -5
  275. data/config/initializers/devise.rb +10 -4
  276. data/config/initializers/mime_types.rb +3 -1
  277. data/config/locales/da.yml +134 -73
  278. data/config/locales/de.yml +142 -77
  279. data/config/locales/en.yml +128 -68
  280. data/config/locales/es-MX.yml +135 -71
  281. data/config/locales/fr.yml +167 -88
  282. data/config/locales/he.yml +128 -72
  283. data/config/locales/it.yml +136 -74
  284. data/config/locales/ja.yml +110 -66
  285. data/config/locales/lt.yml +153 -76
  286. data/config/locales/nb-NO.yml +123 -67
  287. data/config/locales/nl.yml +140 -77
  288. data/config/locales/pl.yml +329 -240
  289. data/config/locales/pt-BR.yml +137 -72
  290. data/config/locales/ro.yml +148 -72
  291. data/config/locales/ru.yml +161 -71
  292. data/config/locales/zh-CN.yml +106 -61
  293. data/config/locales/zh-TW.yml +109 -63
  294. data/config/routes.rb +68 -63
  295. data/db/migrate/113_initial_schema.rb +191 -191
  296. data/db/migrate/114_fixes_buggy_articles_and_notes.rb +10 -7
  297. data/db/migrate/115_drops_categories_for_tags.rb +5 -4
  298. data/db/migrate/20150207131657_add_missing_indexes.rb +2 -0
  299. data/db/migrate/20150807134129_simplify_redirect_relations.rb +5 -0
  300. data/db/migrate/20150808052637_add_blog_ids.rb +9 -3
  301. data/db/migrate/20150808191127_add_blog_id_to_redirects.rb +2 -0
  302. data/db/migrate/20150810094754_add_blog_id_to_tags.rb +2 -0
  303. data/db/migrate/20160108111120_add_devise_to_users.rb +4 -2
  304. data/db/migrate/20160108184201_move_last_connection_to_last_sign_in_at.rb +2 -0
  305. data/db/migrate/20160110094906_remove_profiles_rights.rb +2 -0
  306. data/db/migrate/20160605103918_replace_profile_id_with_string.rb +2 -0
  307. data/db/migrate/20160605154632_remove_profiles.rb +10 -5
  308. data/db/migrate/20160701061851_demand_blog_id_on_contents.rb +2 -0
  309. data/db/migrate/20160701062604_add_blog_id_to_resources.rb +2 -0
  310. data/db/migrate/20170528093024_move_resources_to_content.rb +2 -0
  311. data/db/migrate/20170528094923_move_tags_to_content.rb +2 -0
  312. data/db/migrate/20170528201606_remove_separate_published_flag.rb +2 -0
  313. data/db/migrate/20170605071626_remove_extra_state_columns_from_feedback.rb +2 -0
  314. data/db/migrate/20170702105201_remove_published_at_from_feedback.rb +2 -0
  315. data/db/migrate/20190208151235_add_text_filter_name_fields.rb +9 -0
  316. data/db/migrate/20190208152646_move_text_filter_to_name.rb +97 -0
  317. data/db/migrate/20190209155717_remove_text_filter_ids.rb +19 -0
  318. data/db/migrate/20190209160610_remove_text_filters.rb +17 -0
  319. data/db/migrate/20200413140440_add_unique_indexes.rb +10 -0
  320. data/db/seeds.rb +8 -20
  321. data/lib/email_notify.rb +3 -1
  322. data/lib/format.rb +4 -12
  323. data/lib/publify_core.rb +36 -35
  324. data/lib/publify_core/engine.rb +11 -4
  325. data/lib/publify_core/lang.rb +5 -1
  326. data/lib/publify_core/testing_support/dns_mock.rb +15 -0
  327. data/lib/publify_core/testing_support/factories.rb +240 -0
  328. data/lib/publify_core/testing_support/feed_assertions.rb +48 -0
  329. data/lib/publify_core/testing_support/fixtures/exploit.svg +4 -0
  330. data/lib/publify_core/testing_support/fixtures/fakepng.png +1 -0
  331. data/lib/publify_core/testing_support/fixtures/otherfile.txt +1 -0
  332. data/lib/publify_core/testing_support/fixtures/testfile.png +0 -0
  333. data/lib/publify_core/testing_support/fixtures/testfile.txt +1 -0
  334. data/lib/publify_core/testing_support/upload_fixtures.rb +15 -0
  335. data/lib/publify_core/version.rb +3 -1
  336. data/lib/publify_guid.rb +3 -1
  337. data/lib/publify_plugins.rb +10 -5
  338. data/lib/publify_textfilter_markdown.rb +38 -25
  339. data/lib/publify_textfilter_none.rb +5 -3
  340. data/lib/publify_textfilter_smartypants.rb +5 -3
  341. data/lib/publify_textfilter_textile.rb +7 -4
  342. data/lib/publify_textfilter_twitterfilter.rb +13 -7
  343. data/lib/publify_time.rb +4 -0
  344. data/lib/sidebar_field.rb +15 -13
  345. data/lib/sidebar_registry.rb +5 -3
  346. data/lib/spam_protection.rb +19 -17
  347. data/lib/tasks/i18n.rake +9 -0
  348. data/lib/tasks/manifest.rake +30 -0
  349. data/lib/tasks/publify_core_tasks.rake +2 -0
  350. data/lib/text_filter_plugin.rb +30 -29
  351. data/lib/theme.rb +5 -5
  352. data/lib/transforms.rb +21 -20
  353. data/themes/plain/javascripts/theme.js +0 -0
  354. metadata +247 -109
  355. data/app/assets/javascripts/widearea.js +0 -486
  356. data/app/assets/stylesheets/widearea.css +0 -133
  357. data/app/controllers/admin/textfilters_controller.rb +0 -6
  358. data/app/views/admin/dashboard/_inbound.html.erb +0 -31
  359. data/app/views/admin/notes/_header.html.erb +0 -6
  360. data/app/views/articles/_protected_article_content.html.erb +0 -6
@@ -1,7 +1,7 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # Methods added to this helper will be available to all templates in the application.
4
- require 'digest/sha1'
4
+ require "digest/sha1"
5
5
 
6
6
  module BaseHelper
7
7
  include BlogHelper
@@ -9,8 +9,8 @@ module BaseHelper
9
9
  # Need to rewrite this one, quick hack to test my changes.
10
10
  attr_reader :page_title
11
11
 
12
- def render_sidebars(*sidebars)
13
- rendered_sidebars = (sidebars.blank? ? Sidebar.order(:active_position) : sidebars).map do |sb|
12
+ def render_sidebars
13
+ rendered_sidebars = Sidebar.order(:active_position).map do |sb|
14
14
  @sidebar = sb
15
15
  sb.parse_request(content_array, params)
16
16
  render_sidebar(sb)
@@ -19,11 +19,12 @@ module BaseHelper
19
19
  rescue => e
20
20
  logger.error e
21
21
  logger.error e.backtrace.join("\n")
22
- I18n.t('errors.render_sidebar')
22
+ I18n.t("errors.render_sidebar")
23
23
  end
24
24
 
25
25
  def render_sidebar(sidebar)
26
- render_to_string(partial: sidebar.content_partial, locals: sidebar.to_locals_hash, layout: false)
26
+ render_to_string(partial: sidebar.content_partial, locals: sidebar.to_locals_hash,
27
+ layout: false)
27
28
  end
28
29
 
29
30
  def themeable_stylesheet_link_tag(name)
@@ -31,14 +32,20 @@ module BaseHelper
31
32
  stylesheet_link_tag "/stylesheets/theme/#{name}.css" if File.exist? src
32
33
  end
33
34
 
35
+ def themeable_javascript_include_tag(name)
36
+ src = this_blog.current_theme.path + "/javascripts/#{name}.js"
37
+ javascript_include_tag "/javascripts/theme/#{name}.js" if File.exist? src
38
+ end
39
+
34
40
  def render_to_string(*args, &block)
35
41
  controller.send(:render_to_string, *args, &block)
36
42
  end
37
43
 
38
- def link_to_permalink(item, title, anchor = nil, style = nil, nofollow = nil, only_path = false)
44
+ def link_to_permalink(item, title, anchor = nil, style = nil, nofollow = nil,
45
+ only_path = false)
39
46
  options = {}
40
47
  options[:class] = style if style
41
- options[:rel] = 'nofollow' if nofollow
48
+ options[:rel] = "nofollow" if nofollow
42
49
  url = item.permalink_url(anchor, only_path)
43
50
  if url
44
51
  link_to title, url, options
@@ -51,9 +58,10 @@ module BaseHelper
51
58
  begin
52
59
  avatar_class = this_blog.plugin_avatar.constantize
53
60
  rescue NameError
54
- return ''
61
+ return ""
55
62
  end
56
- return '' unless avatar_class.respond_to?(:get_avatar)
63
+ return "" unless avatar_class.respond_to?(:get_avatar)
64
+
57
65
  avatar_class.get_avatar(options)
58
66
  end
59
67
 
@@ -63,18 +71,21 @@ module BaseHelper
63
71
 
64
72
  def markup_help_popup(markup, text)
65
73
  if markup && markup.commenthelp.size > 1
66
- link_to text, url_for(controller: 'articles', action: 'markup_help', id: markup.id), onclick: "return popup(this, 'Publify Markup Help')"
74
+ link_to(text,
75
+ url_for(controller: "articles", action: "markup_help", id: markup.name),
76
+ onclick: "return popup(this, 'Publify Markup Help')")
67
77
  else
68
- ''
78
+ ""
69
79
  end
70
80
  end
71
81
 
72
82
  def onhover_show_admin_tools(type, id = nil)
73
- admin_id = "#admin_#{[type, id].compact.join('_')}"
83
+ admin_id = "#admin_#{[type, id].compact.join("_")}"
74
84
  tag = []
75
- tag << %{ onmouseover="if (getCookie('publify_user_profile') == 'admin') { $('#{admin_id}').show(); }" }
85
+ tag << %{ onmouseover="if (getCookie('publify_user_profile') == 'admin')\
86
+ { $('#{admin_id}').show(); }" }
76
87
  tag << %{ onmouseout="$('#{admin_id}').hide();" }
77
- safe_join(tag, ' ')
88
+ safe_join(tag, " ")
78
89
  end
79
90
 
80
91
  def feed_title
@@ -91,66 +102,55 @@ module BaseHelper
91
102
  content.html(what)
92
103
  end
93
104
 
94
- def display_user_avatar(user, size = 'avatar', klass = 'alignleft')
105
+ def display_user_avatar(user, size = "avatar", klass = "alignleft")
95
106
  if user.resource.present?
96
107
  avatar_path = case size
97
- when 'thumb'
108
+ when "thumb"
98
109
  user.resource.upload.thumb.url
99
- when 'medium'
110
+ when "medium"
100
111
  user.resource.upload.medium.url
101
- when 'large'
112
+ when "large"
102
113
  user.resource.upload.large.url
103
114
  else
104
115
  user.resource.upload.avatar.url
105
116
  end
106
117
  return if avatar_path.nil?
118
+
107
119
  avatar_url = this_blog.file_url(avatar_path)
108
120
  elsif user.twitter_profile_image.present?
109
121
  avatar_url = user.twitter_profile_image
110
122
  end
111
123
  return unless avatar_url
124
+
112
125
  image_tag(avatar_url, alt: user.nickname, class: klass)
113
126
  end
114
127
 
115
128
  def author_picture(status)
116
129
  return if status.user.twitter_profile_image.blank?
117
130
 
118
- image_tag(status.user.twitter_profile_image, class: 'alignleft', alt: status.user.nickname)
119
- end
120
-
121
- def google_analytics
122
- unless this_blog.google_analytics.empty?
123
- <<-HTML
124
- <script type="text/javascript">
125
- var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
126
- document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
127
- </script>
128
- <script type="text/javascript">
129
- var pageTracker = _gat._getTracker("#{this_blog.google_analytics}");
130
- pageTracker._trackPageview();
131
- </script>
132
- HTML
133
- end
131
+ image_tag(status.user.twitter_profile_image, class: "alignleft",
132
+ alt: status.user.nickname)
134
133
  end
135
134
 
136
135
  def page_header_includes
137
136
  content_array.map(&:whiteboard).map do |w|
138
- w.select { |k, _v| k =~ /^page_header_/ }.map do |_, v|
137
+ w.select { |k, _v| k.start_with?("page_header_") }.map do |_, v|
139
138
  v = v.chomp
140
139
  # trim the same number of spaces from the beginning of each line
141
140
  # this way plugins can indent nicely without making ugly source output
142
- spaces = /\A[ \t]*/.match(v)[0].gsub(/\t/, ' ')
143
- v.gsub!(/^#{spaces}/, ' ') # add 2 spaces to line up with the assumed position of the surrounding tags
141
+ spaces = /\A[ \t]*/.match(v)[0].gsub(/\t/, " ")
142
+ # add 2 spaces to line up with the assumed position of the surrounding tags
143
+ v.gsub!(/^#{spaces}/, " ")
144
144
  end
145
145
  end.flatten.uniq.join("\n")
146
146
  end
147
147
 
148
148
  def feed_atom
149
- feed_for('atom')
149
+ feed_for("atom")
150
150
  end
151
151
 
152
152
  def feed_rss
153
- feed_for('rss')
153
+ feed_for("rss")
154
154
  end
155
155
 
156
156
  def content_array
@@ -175,40 +175,43 @@ module BaseHelper
175
175
 
176
176
  def display_date_and_time(timestamp)
177
177
  return if timestamp.blank?
178
- if this_blog.date_format == 'setting_date_format_distance_of_time_in_words'
178
+
179
+ if this_blog.date_format == "setting_date_format_distance_of_time_in_words"
179
180
  timeago_tag timestamp, date_only: false
180
181
  else
181
- "#{display_date(timestamp)} #{t('helper.at')} #{display_time(timestamp)}"
182
+ "#{display_date(timestamp)} #{t("helper.at")} #{display_time(timestamp)}"
182
183
  end
183
184
  end
184
185
 
185
186
  def show_meta_keyword
186
187
  return unless this_blog.use_meta_keyword
187
- meta_tag 'keywords', @keywords if @keywords.present?
188
+
189
+ meta_tag "keywords", @keywords if @keywords.present?
188
190
  end
189
191
 
190
192
  def stop_index_robots?(blog)
191
193
  stop = (params[:year].present? || params[:page].present?)
192
- stop = blog.unindex_tags if controller_name == 'tags'
193
- stop = blog.unindex_categories if controller_name == 'categories'
194
+ stop = blog.unindex_tags if controller_name == "tags"
195
+ stop = blog.unindex_categories if controller_name == "categories"
194
196
  stop
195
197
  end
196
198
 
197
199
  def get_reply_context_url(reply)
198
- link_to(reply['user']['name'], reply['user']['entities']['url']['urls'][0]['expanded_url'])
200
+ link_to(reply["user"]["name"],
201
+ reply["user"]["entities"]["url"]["urls"][0]["expanded_url"])
199
202
  rescue
200
- link_to(reply['user']['name'], "https://twitter.com/#{reply['user']['name']}")
203
+ link_to(reply["user"]["name"], "https://twitter.com/#{reply["user"]["name"]}")
201
204
  end
202
205
 
203
206
  def get_reply_context_twitter_link(reply)
204
- link_to(display_date_and_time(reply['created_at'].to_time.in_time_zone),
205
- "https://twitter.com/#{reply['user']['screen_name']}/status/#{reply['id_str']}")
207
+ link_to(display_date_and_time(reply["created_at"].to_time.in_time_zone),
208
+ "https://twitter.com/#{reply["user"]["screen_name"]}/status/#{reply["id_str"]}")
206
209
  end
207
210
 
208
211
  private
209
212
 
210
213
  def feed_for(type)
211
- if params[:action] == 'search'
214
+ if params[:action] == "search"
212
215
  url_for(only_path: false, format: type, q: params[:q])
213
216
  elsif !@article.nil?
214
217
  @article.feed_url(type)
@@ -223,7 +226,8 @@ module BaseHelper
223
226
  # show the excerpt, or else we show the body
224
227
  def fetch_html_content_for_feeds(item, this_blog)
225
228
  if item.password_protected?
226
- "<p>This article is password protected. Please <a href='#{item.permalink_url}'>fill in your password</a> to read it</p>"
229
+ "<p>This article is password protected. Please " \
230
+ "<a href='#{item.permalink_url}'>fill in your password</a> to read it</p>"
227
231
  elsif this_blog.hide_extended_on_rss
228
232
  if item.excerpt? && !item.excerpt.empty?
229
233
  item.excerpt
@@ -247,7 +251,7 @@ module BaseHelper
247
251
  if this_blog.dofollowify
248
252
  link_to(text, url)
249
253
  else
250
- link_to(text, url, rel: 'nofollow')
254
+ link_to(text, url, rel: "nofollow")
251
255
  end
252
256
  end
253
257
  end
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BlogHelper
2
4
  # The base URL for this request, calculated by looking up the URL for the main
3
5
  # blog index page.
4
6
  def blog_base_url
5
- url_for(controller: '/articles', action: 'index').gsub(%r{/$}, '')
7
+ url_for(controller: "/articles", action: "index").gsub(%r{/$}, "")
6
8
  end
7
9
 
8
10
  # Find the blog whose base_url matches the current location.
9
11
  def this_blog
10
- @blog ||= Blog.find_blog(blog_base_url)
12
+ @this_blog ||= Blog.find_blog(blog_base_url)
11
13
  end
12
14
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module XmlHelper
2
4
  def collection_lastmod(collection)
3
5
  article_updated = collection.contents.order(updated_at: :desc).first
@@ -8,7 +10,7 @@ module XmlHelper
8
10
  times.push article_published.updated_at if article_published
9
11
 
10
12
  if times.empty?
11
- Time.at(0).xmlschema
13
+ Time.zone.at(0).xmlschema
12
14
  else
13
15
  times.max.xmlschema
14
16
  end
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ApplicationJob < ActiveJob::Base
2
4
  end
@@ -1,4 +1,6 @@
1
- class NotificationMailer < ActionMailer::Base
1
+ # frozen_string_literal: true
2
+
3
+ class NotificationMailer < ApplicationMailer
2
4
  helper :base
3
5
  layout nil
4
6
 
@@ -20,7 +22,7 @@ class NotificationMailer < ActionMailer::Base
20
22
  @user = user
21
23
  # TODO: Make user blog-dependent
22
24
  @blog = Blog.first
23
- build_mail @blog, @user, 'Welcome to Publify'
25
+ build_mail @blog, @user, "Welcome to Publify"
24
26
  end
25
27
 
26
28
  private
@@ -30,7 +32,7 @@ class NotificationMailer < ActionMailer::Base
30
32
  end
31
33
 
32
34
  def build_mail(blog, user, subject)
33
- headers['X-Mailer'] = "Publify #{PublifyCore::VERSION}"
35
+ headers["X-Mailer"] = "Publify #{PublifyCore::VERSION}"
34
36
  mail(from: blog.email_from,
35
37
  to: user.email,
36
38
  subject: make_subject(blog, subject))
@@ -1,4 +1,6 @@
1
- require 'cancancan'
1
+ # frozen_string_literal: true
2
+
3
+ require "cancancan"
2
4
 
3
5
  class Ability
4
6
  include CanCan::Ability
@@ -7,14 +9,14 @@ class Ability
7
9
  return unless user
8
10
 
9
11
  case user.profile
10
- when 'admin'
12
+ when "admin"
11
13
  add_admin_abilities
12
14
  add_publisher_abilities
13
15
  add_contributor_abilities
14
- when 'publisher'
16
+ when "publisher"
15
17
  add_publisher_abilities
16
18
  add_contributor_abilities
17
- when 'contributor'
19
+ when "contributor"
18
20
  add_contributor_abilities
19
21
  end
20
22
  end
@@ -22,30 +24,30 @@ class Ability
22
24
  private
23
25
 
24
26
  def add_admin_abilities
25
- can :manage, 'admin/migrations'
26
- can :manage, 'admin/seo'
27
- can :manage, 'admin/settings'
28
- can :manage, 'admin/sidebar'
29
- can :manage, 'admin/textfilters'
30
- can :manage, 'admin/themes'
31
- can :manage, 'admin/users'
27
+ can :manage, "admin/migrations"
28
+ can :manage, "admin/seo"
29
+ can :manage, "admin/settings"
30
+ can :manage, "admin/sidebar"
31
+ can :manage, "admin/textfilters"
32
+ can :manage, "admin/themes"
33
+ can :manage, "admin/users"
32
34
  end
33
35
 
34
36
  def add_publisher_abilities
35
- can :manage, 'admin/content'
36
- can :manage, 'admin/feedback'
37
- can :manage, 'admin/notes'
38
- can :manage, 'admin/pages'
39
- can :manage, 'admin/post_types'
40
- can :manage, 'admin/redirects'
41
- can :manage, 'admin/resources'
42
- can :manage, 'admin/tags'
43
-
44
- can :manage, 'articles'
37
+ can :manage, "admin/content"
38
+ can :manage, "admin/feedback"
39
+ can :manage, "admin/notes"
40
+ can :manage, "admin/pages"
41
+ can :manage, "admin/post_types"
42
+ can :manage, "admin/redirects"
43
+ can :manage, "admin/resources"
44
+ can :manage, "admin/tags"
45
+
46
+ can :manage, "articles"
45
47
  end
46
48
 
47
49
  def add_contributor_abilities
48
- can :manage, 'admin/dashboard'
49
- can :manage, 'admin/profiles'
50
+ can :manage, "admin/dashboard"
51
+ can :manage, "admin/profiles"
50
52
  end
51
53
  end
@@ -1,17 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ArchivesSidebar < Sidebar
2
- description 'Displays links to monthly archives'
3
- setting :title, 'Archives'
4
- setting :show_count, true, label: 'Show article counts', input_type: :checkbox
5
- setting :count, 10, label: 'Number of Months'
4
+ description "Displays links to monthly archives"
5
+ setting :title, "Archives"
6
+ setting :show_count, true, label: "Show article counts", input_type: :checkbox
7
+ setting :count, 10, label: "Number of Months"
6
8
 
7
9
  attr_accessor :archives
8
10
 
9
11
  def self.date_funcs
10
- @date_func ||=
11
- if Content.connection.class.name =~ /SQLite3Adapter/
12
+ @date_funcs ||=
13
+ if /SQLite3Adapter/.match?(Content.connection.class.name)
12
14
  ["strftime('%Y', published_at) as year", "strftime('%m', published_at) as month"]
13
15
  else
14
- ['extract(year from published_at) as year', 'extract(month from published_at) as month']
16
+ ["extract(year from published_at) as year",
17
+ "extract(month from published_at) as month"]
15
18
  end
16
19
  end
17
20
 
@@ -23,17 +26,17 @@ class ArchivesSidebar < Sidebar
23
26
  # DB-specific code.
24
27
  date_funcs = self.class.date_funcs
25
28
 
26
- article_counts = Article.published.select('count(*) as count', *date_funcs).
27
- group(:year, :month).reorder('year desc', 'month desc').limit(count.to_i)
29
+ article_counts = Article.published.select("count(*) as count", *date_funcs).
30
+ group(:year, :month).reorder("year desc", "month desc").limit(count.to_i)
28
31
 
29
32
  @archives = article_counts.map do |entry|
30
33
  month = entry.month.to_i
31
34
  year = entry.year.to_i
32
35
  {
33
- name: I18n.l(Date.new(year, month), format: '%B %Y'),
36
+ name: I18n.l(Date.new(year, month), format: "%B %Y"),
34
37
  month: month,
35
38
  year: year,
36
- article_count: entry.count
39
+ article_count: entry.count,
37
40
  }
38
41
  end
39
42
  end
@@ -1,8 +1,8 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'aasm'
4
- require 'uri'
5
- require 'net/http'
3
+ require "aasm"
4
+ require "uri"
5
+ require "net/http"
6
6
 
7
7
  class Article < Content
8
8
  include PublifyGuid
@@ -21,28 +21,26 @@ class Article < Content
21
21
  has_many :triggers, as: :pending_item
22
22
  has_many :comments, dependent: :destroy
23
23
 
24
- before_create :create_guid
25
24
  before_save :set_permalink
25
+ before_create :create_guid
26
26
  after_save :keywords_to_tags, :shorten_url
27
27
 
28
28
  scope :child_of, ->(article_id) { where(parent_id: article_id) }
29
- scope :published_since, ->(time) {
30
- published.where('published_at > ?', time).order(default_order)
31
- }
32
- scope :withdrawn, -> { where(state: 'withdrawn').order(default_order) }
33
- scope :pending, -> { where(state: 'publication_pending'). order(default_order) }
29
+ scope :published_since, ->(time) { published.where("published_at > ?", time) }
30
+ scope :withdrawn, -> { where(state: "withdrawn").order(default_order) }
31
+ scope :pending, -> { where(state: "publication_pending").order(default_order) }
34
32
 
35
33
  scope :bestof, lambda {
36
34
  joins(:feedback).
37
- where('feedback.type' => 'Comment',
38
- 'contents.state' => 'published').
39
- group('contents.id').
40
- order('count(feedback.id) DESC').
41
- select('contents.*, count(feedback.id) as comment_count').
35
+ where("feedback.type" => "Comment",
36
+ "contents.state" => "published").
37
+ group("contents.id").
38
+ select("contents.*, count(feedback.id) as comment_count").
39
+ order("comment_count DESC").
42
40
  limit(5)
43
41
  }
44
42
 
45
- setting :password, :string, ''
43
+ setting :password, :string, ""
46
44
 
47
45
  attr_accessor :draft, :keywords
48
46
 
@@ -81,6 +79,7 @@ class Article < Content
81
79
 
82
80
  def set_permalink
83
81
  return if draft? || permalink.present?
82
+
84
83
  self.permalink = title.to_permalink
85
84
  end
86
85
 
@@ -90,7 +89,7 @@ class Article < Content
90
89
 
91
90
  def post_type
92
91
  post_type = self[:post_type]
93
- post_type = 'read' if post_type.blank?
92
+ post_type = "read" if post_type.blank?
94
93
  post_type
95
94
  end
96
95
 
@@ -107,19 +106,21 @@ class Article < Content
107
106
  scoped = scoped.send(params[:state])
108
107
  end
109
108
 
110
- scoped.order('created_at DESC')
109
+ scoped.order("created_at DESC")
111
110
  end
112
111
 
113
112
  # FIXME: Use keyword params to clean up call sites.
114
113
  def permalink_url(anchor = nil, only_path = false)
115
114
  return unless published?
115
+
116
116
  @cached_permalink_url ||= {}
117
- @cached_permalink_url["#{anchor}#{only_path}"] ||= blog.url_for(permalink_url_options, anchor: anchor, only_path: only_path)
117
+ @cached_permalink_url["#{anchor}#{only_path}"] ||=
118
+ blog.url_for(permalink_url_options, anchor: anchor, only_path: only_path)
118
119
  end
119
120
 
120
121
  def save_attachments!(files)
121
122
  files ||= {}
122
- files.values.each { |f| save_attachment!(f) }
123
+ files.each_value { |f| save_attachment!(f) }
123
124
  end
124
125
 
125
126
  def save_attachment!(file)
@@ -135,28 +136,30 @@ class Article < Content
135
136
  end
136
137
 
137
138
  def feed_url(format)
138
- "#{permalink_url}.#{format.gsub(/\d/, '')}"
139
+ "#{permalink_url}.#{format.gsub(/\d/, "")}"
139
140
  end
140
141
 
141
142
  def next
142
- Article.where('published_at > ?', published_at).order('published_at asc').limit(1).first
143
+ Article.where("published_at > ?", published_at).order("published_at asc").
144
+ limit(1).first
143
145
  end
144
146
 
145
147
  def previous
146
- Article.where('published_at < ?', published_at).order('published_at desc').limit(1).first
148
+ Article.where("published_at < ?", published_at).order("published_at desc").
149
+ limit(1).first
147
150
  end
148
151
 
149
152
  def publication_month
150
- published_at.strftime('%Y-%m')
153
+ published_at.strftime("%Y-%m")
151
154
  end
152
155
 
153
156
  def self.publication_months
154
- result = select('published_at').where('published_at is not NULL').where(type: 'Article')
157
+ result = select("published_at").where("published_at is not NULL").where(type: "Article")
155
158
  result.map { |it| [it.publication_month] }.uniq
156
159
  end
157
160
 
158
- # Finds one article which was posted on a certain date and matches the supplied dashed-title
159
- # params is a Hash
161
+ # Finds one article which was posted on a certain date and matches the
162
+ # supplied dashed-title params is a Hash
160
163
  def self.requested_article(params)
161
164
  date_range = PublifyTime.delta(params[:year], params[:month], params[:day])
162
165
 
@@ -165,6 +168,7 @@ class Article < Content
165
168
  req_params[:published_at] = date_range if date_range
166
169
 
167
170
  return if req_params.empty? # no search if no params send
171
+
168
172
  article = published.find_by(req_params)
169
173
  return article if article
170
174
 
@@ -206,9 +210,7 @@ class Article < Content
206
210
  def html_urls
207
211
  urls = []
208
212
  html.gsub(/<a\s+[^>]*>/) do |tag|
209
- if tag =~ /\bhref=(["']?)([^ >"]+)\1/
210
- urls.push(Regexp.last_match[2].strip)
211
- end
213
+ urls.push(Regexp.last_match[2].strip) if tag =~ /\bhref=(["']?)([^ >"]+)\1/
212
214
  end
213
215
  urls.uniq
214
216
  end
@@ -223,10 +225,6 @@ class Article < Content
223
225
  published_at.to_i > blog.sp_article_auto_close.days.ago.to_i
224
226
  end
225
227
 
226
- def content_fields
227
- [:body, :extended]
228
- end
229
-
230
228
  # The web interface no longer distinguishes between separate "body" and
231
229
  # "extended" fields, and instead edits everything in a single edit field,
232
230
  # separating the extended content using "\<!--more-->".
@@ -234,7 +232,7 @@ class Article < Content
234
232
  if extended.blank?
235
233
  body
236
234
  else
237
- body + "\n<!--more-->\n" + extended
235
+ "#{body}\n<!--more-->\n#{extended}"
238
236
  end
239
237
  end
240
238
 
@@ -243,7 +241,7 @@ class Article < Content
243
241
  def body_and_extended=(value)
244
242
  parts = value.split(/\n?<!--more-->\n?/, 2)
245
243
  self.body = parts[0]
246
- self.extended = parts[1] || ''
244
+ self.extended = parts[1] || ""
247
245
  end
248
246
 
249
247
  def password_protected?
@@ -260,11 +258,13 @@ class Article < Content
260
258
 
261
259
  def allow_comments?
262
260
  return allow_comments unless allow_comments.nil?
261
+
263
262
  blog.default_allow_comments
264
263
  end
265
264
 
266
265
  def allow_pings?
267
266
  return allow_pings unless allow_pings.nil?
267
+
268
268
  blog.default_allow_pings
269
269
  end
270
270
 
@@ -284,11 +284,11 @@ class Article < Content
284
284
 
285
285
  def permalink_url_options
286
286
  format_url = blog.permalink_format.dup
287
- format_url.gsub!('%year%', published_at.year.to_s)
288
- format_url.gsub!('%month%', sprintf('%.2d', published_at.month))
289
- format_url.gsub!('%day%', sprintf('%.2d', published_at.day))
290
- format_url.gsub!('%title%', URI.encode(permalink.to_s))
291
- if format_url[0, 1] == '/'
287
+ format_url.gsub!("%year%", published_at.year.to_s)
288
+ format_url.gsub!("%month%", sprintf("%<month>.2d", month: published_at.month))
289
+ format_url.gsub!("%day%", sprintf("%<day>.2d", day: published_at.day))
290
+ format_url.gsub!("%title%", URI::DEFAULT_PARSER.escape(permalink.to_s))
291
+ if format_url[0, 1] == "/"
292
292
  format_url[1..-1]
293
293
  else
294
294
  format_url
@@ -297,6 +297,6 @@ class Article < Content
297
297
 
298
298
  def trigger_publication
299
299
  # TODO: Skip if already published, update when published_at changes
300
- Trigger.post_action(published_at, self, 'publish!')
300
+ Trigger.post_action(published_at, self, "publish!")
301
301
  end
302
302
  end