virgo 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +37 -0
  4. data/app/assets/javascripts/tinymce/manifest.coffee +1 -0
  5. data/app/assets/javascripts/tinymce/plugins/image_manager/plugin.coffee +234 -0
  6. data/app/assets/javascripts/virgo/admin/page_modules/edit_form.coffee +4 -0
  7. data/app/assets/javascripts/virgo/admin/page_modules/edit_subject_form.coffee +29 -0
  8. data/app/assets/javascripts/virgo/admin/posts/edit_locking.coffee +35 -0
  9. data/app/assets/javascripts/virgo/admin/posts/form.coffee +183 -0
  10. data/app/assets/javascripts/virgo/admin/slides/form.coffee +27 -0
  11. data/app/assets/javascripts/virgo/admin/slideshows/form.coffee +26 -0
  12. data/app/assets/javascripts/virgo/admin_only.coffee +1 -0
  13. data/app/assets/javascripts/virgo/application.coffee +51 -0
  14. data/app/assets/javascripts/virgo/common.coffee +83 -0
  15. data/app/assets/javascripts/virgo/common/character_counter.coffee +27 -0
  16. data/app/assets/javascripts/virgo/components/header.coffee +47 -0
  17. data/app/assets/javascripts/virgo/components/media_modal.coffee +151 -0
  18. data/app/assets/javascripts/virgo/components/share_bar.coffee +53 -0
  19. data/app/assets/javascripts/virgo/components/slideshow.coffee +35 -0
  20. data/app/assets/javascripts/virgo/lib/jquery-ui-multiselect.js +342 -0
  21. data/app/assets/javascripts/virgo/lib/jquery.browser.js +184 -0
  22. data/app/assets/javascripts/virgo/lib/jquery.cookie.js +114 -0
  23. data/app/assets/javascripts/virgo/lib/jquery.pjax.js +932 -0
  24. data/app/assets/javascripts/virgo/lib/jquery_ext.coffee +0 -0
  25. data/app/assets/javascripts/virgo/lib/manifest.coffee +5 -0
  26. data/app/assets/javascripts/virgo/lib/ouibounce.js +194 -0
  27. data/app/assets/javascripts/virgo/page_modules.coffee +175 -0
  28. data/app/assets/javascripts/virgo/posts/show.coffee +32 -0
  29. data/app/assets/stylesheets/tinymce/skin.sass +2 -0
  30. data/app/assets/stylesheets/tinymce/skins/railspress/content.min.sass +82 -0
  31. data/app/assets/stylesheets/tinymce/skins/railspress/fonts/tinymce-small.eot +0 -0
  32. data/app/assets/stylesheets/tinymce/skins/railspress/fonts/tinymce-small.svg +62 -0
  33. data/app/assets/stylesheets/tinymce/skins/railspress/fonts/tinymce-small.ttf +0 -0
  34. data/app/assets/stylesheets/tinymce/skins/railspress/fonts/tinymce-small.woff +0 -0
  35. data/app/assets/stylesheets/tinymce/skins/railspress/fonts/tinymce.eot +0 -0
  36. data/app/assets/stylesheets/tinymce/skins/railspress/fonts/tinymce.svg +63 -0
  37. data/app/assets/stylesheets/tinymce/skins/railspress/fonts/tinymce.ttf +0 -0
  38. data/app/assets/stylesheets/tinymce/skins/railspress/fonts/tinymce.woff +0 -0
  39. data/app/assets/stylesheets/tinymce/skins/railspress/img/anchor.gif +0 -0
  40. data/app/assets/stylesheets/tinymce/skins/railspress/img/loader.gif +0 -0
  41. data/app/assets/stylesheets/tinymce/skins/railspress/img/object.gif +0 -0
  42. data/app/assets/stylesheets/tinymce/skins/railspress/img/trans.gif +0 -0
  43. data/app/assets/stylesheets/tinymce/skins/railspress/skin.min.sass +1703 -0
  44. data/app/assets/stylesheets/virgo/_common.sass +65 -0
  45. data/app/assets/stylesheets/virgo/admin.sass +301 -0
  46. data/app/assets/stylesheets/virgo/admin/columns.sass +3 -0
  47. data/app/assets/stylesheets/virgo/admin/images.sass +14 -0
  48. data/app/assets/stylesheets/virgo/admin/media_modal.sass +72 -0
  49. data/app/assets/stylesheets/virgo/admin/post.sass +102 -0
  50. data/app/assets/stylesheets/virgo/admin/slideshow.sass +35 -0
  51. data/app/assets/stylesheets/virgo/admin/users.sass +2 -0
  52. data/app/assets/stylesheets/virgo/admin_only.sass +1 -0
  53. data/app/assets/stylesheets/virgo/application.sass +605 -0
  54. data/app/assets/stylesheets/virgo/columns.sass +51 -0
  55. data/app/assets/stylesheets/virgo/install.sass +15 -0
  56. data/app/assets/stylesheets/virgo/lib/bootstrap/bootstrap-imports.sass +9 -0
  57. data/app/assets/stylesheets/virgo/lib/bootstrap/bootstrap-overrides.sass +51 -0
  58. data/app/assets/stylesheets/virgo/lib/bootstrap/bootstrap-variables.sass +27 -0
  59. data/app/assets/stylesheets/virgo/lib/jquery-ui-multiselect.css +30 -0
  60. data/app/assets/stylesheets/virgo/lib/manifest.sass +3 -0
  61. data/app/assets/stylesheets/virgo/lib/ouibounce.css +222 -0
  62. data/app/assets/stylesheets/virgo/lib/select2-imports.sass +8 -0
  63. data/app/assets/stylesheets/virgo/page_modules.sass +54 -0
  64. data/app/assets/stylesheets/virgo/pages/authors.sass +30 -0
  65. data/app/assets/stylesheets/virgo/posts.sass +782 -0
  66. data/app/assets/stylesheets/virgo/search.sass +36 -0
  67. data/app/assets/stylesheets/virgo/ui.sass +434 -0
  68. data/app/assets/stylesheets/virgo/users.sass +9 -0
  69. data/app/controllers/virgo/admin/base_controller.rb +22 -0
  70. data/app/controllers/virgo/admin/categories_controller.rb +90 -0
  71. data/app/controllers/virgo/admin/columns_controller.rb +65 -0
  72. data/app/controllers/virgo/admin/images_controller.rb +89 -0
  73. data/app/controllers/virgo/admin/media_modal_controller.rb +101 -0
  74. data/app/controllers/virgo/admin/newsletters_controller.rb +37 -0
  75. data/app/controllers/virgo/admin/page_modules_controller.rb +62 -0
  76. data/app/controllers/virgo/admin/pages_controller.rb +6 -0
  77. data/app/controllers/virgo/admin/posts_controller.rb +173 -0
  78. data/app/controllers/virgo/admin/sites_controller.rb +31 -0
  79. data/app/controllers/virgo/admin/slides_controller.rb +71 -0
  80. data/app/controllers/virgo/admin/slideshows_controller.rb +66 -0
  81. data/app/controllers/virgo/admin/tags_controller.rb +98 -0
  82. data/app/controllers/virgo/admin/users/sessions_controller.rb +21 -0
  83. data/app/controllers/virgo/admin/users_controller.rb +84 -0
  84. data/app/controllers/virgo/application_controller.rb +151 -0
  85. data/app/controllers/virgo/categories_controller.rb +20 -0
  86. data/app/controllers/virgo/columns_controller.rb +24 -0
  87. data/app/controllers/virgo/images_controller.rb +9 -0
  88. data/app/controllers/virgo/install_controller.rb +46 -0
  89. data/app/controllers/virgo/page_modules_controller.rb +23 -0
  90. data/app/controllers/virgo/pages_controller.rb +29 -0
  91. data/app/controllers/virgo/posts_controller.rb +101 -0
  92. data/app/controllers/virgo/search_controller.rb +35 -0
  93. data/app/controllers/virgo/subscribers_controller.rb +54 -0
  94. data/app/controllers/virgo/tags_controller.rb +15 -0
  95. data/app/controllers/virgo/users/confirmations_controller.rb +18 -0
  96. data/app/controllers/virgo/users/passwords_controller.rb +31 -0
  97. data/app/controllers/virgo/users/registrations_controller.rb +41 -0
  98. data/app/controllers/virgo/users/sessions_controller.rb +32 -0
  99. data/app/controllers/virgo/users_controller.rb +15 -0
  100. data/app/helpers/virgo/admin/post_helper.rb +54 -0
  101. data/app/helpers/virgo/admin_helper.rb +15 -0
  102. data/app/helpers/virgo/application_helper.rb +124 -0
  103. data/app/helpers/virgo/hooks_helper.rb +30 -0
  104. data/app/helpers/virgo/page_modules_helper.rb +4 -0
  105. data/app/helpers/virgo/post_helper.rb +159 -0
  106. data/app/helpers/virgo/render_helper.rb +33 -0
  107. data/app/helpers/virgo/search_helper.rb +49 -0
  108. data/app/helpers/virgo/shortcode_helper.rb +7 -0
  109. data/app/helpers/virgo/text_helper.rb +12 -0
  110. data/app/helpers/virgo/video_helper.rb +34 -0
  111. data/app/models/concerns/virgo/common/slug_history.rb +36 -0
  112. data/app/models/concerns/virgo/common/uuid.rb +22 -0
  113. data/app/models/concerns/virgo/post/recommendations.rb +15 -0
  114. data/app/models/concerns/virgo/post/search.rb +100 -0
  115. data/app/models/concerns/virgo/user/search.rb +39 -0
  116. data/app/models/virgo/ability.rb +59 -0
  117. data/app/models/virgo/category.rb +44 -0
  118. data/app/models/virgo/column.rb +25 -0
  119. data/app/models/virgo/form_model.rb +19 -0
  120. data/app/models/virgo/image.rb +63 -0
  121. data/app/models/virgo/page_module.rb +42 -0
  122. data/app/models/virgo/page_module_post.rb +8 -0
  123. data/app/models/virgo/post.rb +391 -0
  124. data/app/models/virgo/post_category.rb +8 -0
  125. data/app/models/virgo/post_search.rb +7 -0
  126. data/app/models/virgo/post_tag.rb +10 -0
  127. data/app/models/virgo/site.rb +36 -0
  128. data/app/models/virgo/slide.rb +23 -0
  129. data/app/models/virgo/slideshow.rb +37 -0
  130. data/app/models/virgo/slug_history.rb +5 -0
  131. data/app/models/virgo/subscriber.rb +5 -0
  132. data/app/models/virgo/tag.rb +34 -0
  133. data/app/models/virgo/user.rb +145 -0
  134. data/app/uploaders/virgo/application_uploader.rb +11 -0
  135. data/app/uploaders/virgo/avatar_uploader.rb +21 -0
  136. data/app/uploaders/virgo/featured_image_uploader.rb +28 -0
  137. data/app/uploaders/virgo/image_uploader.rb +40 -0
  138. data/app/uploaders/virgo/slide_uploader.rb +19 -0
  139. data/app/views/layouts/virgo/admin.haml +16 -0
  140. data/app/views/layouts/virgo/admin/site_settings.haml +14 -0
  141. data/app/views/layouts/virgo/application.haml +63 -0
  142. data/app/views/layouts/virgo/errors.haml +42 -0
  143. data/app/views/layouts/virgo/main.haml +5 -0
  144. data/app/views/layouts/virgo/posts.haml +10 -0
  145. data/app/views/virgo/admin/categories/_form.haml +19 -0
  146. data/app/views/virgo/admin/categories/edit.haml +7 -0
  147. data/app/views/virgo/admin/categories/index.haml +38 -0
  148. data/app/views/virgo/admin/categories/modal_form.haml +11 -0
  149. data/app/views/virgo/admin/categories/new.haml +7 -0
  150. data/app/views/virgo/admin/categories/success_modal.haml +14 -0
  151. data/app/views/virgo/admin/columns/_form.haml +30 -0
  152. data/app/views/virgo/admin/columns/edit.haml +1 -0
  153. data/app/views/virgo/admin/columns/index.haml +30 -0
  154. data/app/views/virgo/admin/columns/new.haml +1 -0
  155. data/app/views/virgo/admin/images/_form.haml +46 -0
  156. data/app/views/virgo/admin/images/edit.haml +1 -0
  157. data/app/views/virgo/admin/images/index.haml +32 -0
  158. data/app/views/virgo/admin/images/new.haml +1 -0
  159. data/app/views/virgo/admin/media_modal/_image_settings.haml +17 -0
  160. data/app/views/virgo/admin/media_modal/_library_panel.haml +26 -0
  161. data/app/views/virgo/admin/media_modal/_upload_panel.haml +21 -0
  162. data/app/views/virgo/admin/media_modal/_upload_success.haml +7 -0
  163. data/app/views/virgo/admin/media_modal/index.haml +19 -0
  164. data/app/views/virgo/admin/newsletters/changelog.haml +25 -0
  165. data/app/views/virgo/admin/newsletters/edit.haml +6 -0
  166. data/app/views/virgo/admin/page_modules/edit.haml +33 -0
  167. data/app/views/virgo/admin/page_modules/edit_subject.haml +43 -0
  168. data/app/views/virgo/admin/pages/help.haml +114 -0
  169. data/app/views/virgo/admin/posts/_author_dropdown.haml +1 -0
  170. data/app/views/virgo/admin/posts/_categories_form.haml +7 -0
  171. data/app/views/virgo/admin/posts/_category.haml +22 -0
  172. data/app/views/virgo/admin/posts/_form.haml +201 -0
  173. data/app/views/virgo/admin/posts/_revisions.haml +40 -0
  174. data/app/views/virgo/admin/posts/edit.haml +9 -0
  175. data/app/views/virgo/admin/posts/index.haml +59 -0
  176. data/app/views/virgo/admin/posts/new.haml +1 -0
  177. data/app/views/virgo/admin/posts/revision_detail.haml +28 -0
  178. data/app/views/virgo/admin/posts/revisions.haml +3 -0
  179. data/app/views/virgo/admin/sites/edit.haml +12 -0
  180. data/app/views/virgo/admin/slides/_form.haml +41 -0
  181. data/app/views/virgo/admin/slides/edit.haml +1 -0
  182. data/app/views/virgo/admin/slides/new.haml +1 -0
  183. data/app/views/virgo/admin/slideshows/_form.haml +49 -0
  184. data/app/views/virgo/admin/slideshows/edit.haml +1 -0
  185. data/app/views/virgo/admin/slideshows/index.haml +43 -0
  186. data/app/views/virgo/admin/slideshows/new.haml +1 -0
  187. data/app/views/virgo/admin/tags/_form.haml +16 -0
  188. data/app/views/virgo/admin/tags/edit.haml +7 -0
  189. data/app/views/virgo/admin/tags/index.haml +33 -0
  190. data/app/views/virgo/admin/tags/modal_form.haml +12 -0
  191. data/app/views/virgo/admin/tags/new.haml +7 -0
  192. data/app/views/virgo/admin/tags/success_modal.haml +14 -0
  193. data/app/views/virgo/admin/users/_form.haml +62 -0
  194. data/app/views/virgo/admin/users/edit.haml +1 -0
  195. data/app/views/virgo/admin/users/index.haml +34 -0
  196. data/app/views/virgo/admin/users/new.haml +1 -0
  197. data/app/views/virgo/application/sitemap.xml.builder +0 -0
  198. data/app/views/virgo/authors/_profile_long.haml +13 -0
  199. data/app/views/virgo/authors/_profile_short.haml +10 -0
  200. data/app/views/virgo/categories/show.haml +24 -0
  201. data/app/views/virgo/columns/index.haml +19 -0
  202. data/app/views/virgo/columns/show.haml +18 -0
  203. data/app/views/virgo/common/_admin_navbar.haml +100 -0
  204. data/app/views/virgo/common/_alerts.haml +40 -0
  205. data/app/views/virgo/common/_analytics.html.erb +1 -0
  206. data/app/views/virgo/common/_base_errors.haml +8 -0
  207. data/app/views/virgo/common/_category_heading.haml +26 -0
  208. data/app/views/virgo/common/_disqus.html.erb +24 -0
  209. data/app/views/virgo/common/_disqus_comment_count.html.erb +12 -0
  210. data/app/views/virgo/common/_fb_api.html.erb +30 -0
  211. data/app/views/virgo/common/_fonts.html.erb +1 -0
  212. data/app/views/virgo/common/_footer.haml +13 -0
  213. data/app/views/virgo/common/_footer_javascript.html.erb +0 -0
  214. data/app/views/virgo/common/_header_analytics.html.erb +9 -0
  215. data/app/views/virgo/common/_list_signup.haml +20 -0
  216. data/app/views/virgo/common/_ouibounce_modal.haml +26 -0
  217. data/app/views/virgo/common/_public_nav.haml +58 -0
  218. data/app/views/virgo/common/_search_form.haml +8 -0
  219. data/app/views/virgo/common/_share_bar.haml +45 -0
  220. data/app/views/virgo/common/_user_vars.haml +2 -0
  221. data/app/views/virgo/errors/404.haml +10 -0
  222. data/app/views/virgo/errors/500.haml +10 -0
  223. data/app/views/virgo/images/_shortcode.haml +4 -0
  224. data/app/views/virgo/install/index.haml +58 -0
  225. data/app/views/virgo/install/success.haml +12 -0
  226. data/app/views/virgo/page_modules/_latest_posts.haml +29 -0
  227. data/app/views/virgo/page_modules/_popular_posts.haml +51 -0
  228. data/app/views/virgo/pages/authors.haml +8 -0
  229. data/app/views/virgo/pages/home.haml +0 -0
  230. data/app/views/virgo/pages/show.haml +6 -0
  231. data/app/views/virgo/posts/_author_info.haml +16 -0
  232. data/app/views/virgo/posts/_post_full.haml +63 -0
  233. data/app/views/virgo/posts/_post_short.haml +30 -0
  234. data/app/views/virgo/posts/_post_thumb_box.haml +13 -0
  235. data/app/views/virgo/posts/_recommendations.haml +12 -0
  236. data/app/views/virgo/posts/_sidebar_thumb.haml +4 -0
  237. data/app/views/virgo/posts/index.haml +22 -0
  238. data/app/views/virgo/posts/latest.haml +16 -0
  239. data/app/views/virgo/posts/more.haml +10 -0
  240. data/app/views/virgo/posts/rss.xml.builder +17 -0
  241. data/app/views/virgo/posts/show.haml +17 -0
  242. data/app/views/virgo/search/_form.haml +5 -0
  243. data/app/views/virgo/search/_item.haml +22 -0
  244. data/app/views/virgo/search/index.haml +11 -0
  245. data/app/views/virgo/search/new.haml +4 -0
  246. data/app/views/virgo/shortcode_templates/blockquote.haml +9 -0
  247. data/app/views/virgo/shortcode_templates/h1.haml +1 -0
  248. data/app/views/virgo/shortcode_templates/h2.haml +1 -0
  249. data/app/views/virgo/shortcode_templates/h3.haml +1 -0
  250. data/app/views/virgo/shortcode_templates/h4.haml +1 -0
  251. data/app/views/virgo/shortcode_templates/image.haml +17 -0
  252. data/app/views/virgo/shortcode_templates/pullquote.haml +3 -0
  253. data/app/views/virgo/shortcode_templates/slideshow.haml +35 -0
  254. data/app/views/virgo/shortcode_templates/tweet.haml +3 -0
  255. data/app/views/virgo/shortcode_templates/video.haml +8 -0
  256. data/app/views/virgo/subscribers/_success_modal.haml +13 -0
  257. data/app/views/virgo/subscribers/modal.haml +15 -0
  258. data/app/views/virgo/tags/show.haml +16 -0
  259. data/app/views/virgo/users/confirmations/new.html.haml +10 -0
  260. data/app/views/virgo/users/devise_mailer/confirmation_instructions.html.erb +7 -0
  261. data/app/views/virgo/users/devise_mailer/reset_password_instructions.html.haml +6 -0
  262. data/app/views/virgo/users/devise_mailer/unlock_instructions.html.haml +5 -0
  263. data/app/views/virgo/users/passwords/edit.html.haml +14 -0
  264. data/app/views/virgo/users/passwords/new.html.haml +14 -0
  265. data/app/views/virgo/users/registrations/edit.html.haml +30 -0
  266. data/app/views/virgo/users/registrations/new.html.haml +13 -0
  267. data/app/views/virgo/users/sessions/new.html.haml +12 -0
  268. data/app/views/virgo/users/shared/_links.haml +26 -0
  269. data/app/views/virgo/users/show.haml +11 -0
  270. data/app/views/virgo/users/unlocks/new.html.haml +9 -0
  271. data/config/initializers/action_mailer.rb +7 -0
  272. data/config/initializers/active_record.rb +72 -0
  273. data/config/initializers/active_record_symbolize.rb +18 -0
  274. data/config/initializers/assets.rb +17 -0
  275. data/config/initializers/backtrace_silencers.rb +7 -0
  276. data/config/initializers/carrierwave.rb +36 -0
  277. data/config/initializers/cookies_serializer.rb +3 -0
  278. data/config/initializers/devise.rb +257 -0
  279. data/config/initializers/filter_parameter_logging.rb +4 -0
  280. data/config/initializers/hash.rb +5 -0
  281. data/config/initializers/inflections.rb +16 -0
  282. data/config/initializers/mime_types.rb +4 -0
  283. data/config/initializers/nil_class.rb +13 -0
  284. data/config/initializers/non_digest_assets.rb +3 -0
  285. data/config/initializers/paper_trail.rb +30 -0
  286. data/config/initializers/schema_plus.rb +5 -0
  287. data/config/initializers/session_store.rb +3 -0
  288. data/config/initializers/shortcode.rb +12 -0
  289. data/config/initializers/simple_form.rb +170 -0
  290. data/config/initializers/simple_form_bootstrap.rb +136 -0
  291. data/config/initializers/string.rb +5 -0
  292. data/config/initializers/time_formatting.rb +23 -0
  293. data/config/initializers/wrap_parameters.rb +14 -0
  294. data/config/locales/devise.en.yml +60 -0
  295. data/config/routes.rb +96 -0
  296. data/config/schedule.rb +3 -0
  297. data/db/migrate/20150729174510_create_virgo_schema.rb +225 -0
  298. data/lib/generators/virgo/install/install_generator.rb +16 -0
  299. data/lib/generators/virgo/views/views_generator.rb +22 -0
  300. data/lib/tasks/virgo_tasks.rake +7 -0
  301. data/lib/virgo.rb +4 -0
  302. data/lib/virgo/development_mail_interceptor.rb +6 -0
  303. data/lib/virgo/email_validator.rb +6 -0
  304. data/lib/virgo/engine.rb +73 -0
  305. data/lib/virgo/reduce_validator.rb +6 -0
  306. data/lib/virgo/upload_helpers.rb +89 -0
  307. data/lib/virgo/version.rb +3 -0
  308. data/lib/virgo/view_help.rb +3 -0
  309. metadata +1051 -0
@@ -0,0 +1,30 @@
1
+ module Virgo
2
+ module HooksHelper
3
+ def hook(hook_name)
4
+ body = ""
5
+
6
+ (@hook_content[hook_name] || []).each do |markup|
7
+ body += raw(markup)
8
+ end
9
+
10
+ body
11
+ end
12
+
13
+ def for_hook(hook_name, &block)
14
+ markup = capture(&block)
15
+
16
+ add_hook_content(hook_name, markup)
17
+
18
+ "" # just in case the user echoes the helper invocation
19
+ end
20
+
21
+ private
22
+
23
+ # do not call directly
24
+ def add_hook_content(hook_name, content)
25
+ @hook_content ||= {}
26
+ @hook_content[hook_name] ||= []
27
+ @hook_content[hook_name] << content
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ module Virgo
2
+ module PageModulesHelper
3
+ end
4
+ end
@@ -0,0 +1,159 @@
1
+ module Virgo
2
+ module PostHelper
3
+ def post_status_label(post)
4
+ if post.draft?
5
+ "<span class='label label-danger'>Draft</span>".html_safe
6
+ elsif post.assigned?
7
+ "<span class='label label-info'>Assigned</span>".html_safe
8
+ elsif post.published?
9
+ "<span class='label label-primary'>Published</span>".html_safe
10
+ elsif post.killed?
11
+ "<span class='label label-danger'>Hidden</span>".html_safe
12
+ elsif post.hidden?
13
+ "<span class='label label-warning'>Hidden</span>".html_safe
14
+ end
15
+ end
16
+
17
+ def post_categories(post)
18
+ post.categories.map(&:name).join(", ")
19
+ end
20
+
21
+ def post_tags(post)
22
+ post.tags.map(&:name).join(", ")
23
+ end
24
+
25
+ def truncate_post_to_read_more(post, opts={})
26
+ include_link = true if opts[:link].nil?
27
+
28
+ text = post.rendered_body
29
+
30
+ idx = text.index("[read-more]")
31
+
32
+ if opts[:length]
33
+ if idx.nil? || (opts[:length] < idx)
34
+ return truncate(strip_tags(text), length: opts[:length])
35
+ end
36
+ end
37
+
38
+ if idx
39
+ result = text[0..(idx-1)] + "<span class='ellipse'>...</span>"
40
+
41
+ if include_link
42
+ result += "<div class='read-more-link-wrap'>"
43
+ result += link_to("Read More", post_detail_path(post), class: 'read-more-link')
44
+ result += "</div>"
45
+ end
46
+ else
47
+ result = text
48
+ end
49
+
50
+ result.html_safe
51
+ end
52
+
53
+ def post_category_label(post)
54
+ if post.categories.any?
55
+ category = post.categories.order(navbar_weight: :asc).first
56
+
57
+ html = "
58
+ <div class='category-label'>
59
+ <span class='category-name'>#{category.name}</span>
60
+ </div>
61
+ "
62
+
63
+ html.html_safe
64
+ else
65
+ ""
66
+ end
67
+ end
68
+
69
+ def post_byline(post, opts={})
70
+ html = "
71
+ <div class='post-byline'>
72
+ <span class='post-by'>By</span> "
73
+
74
+ unless opts[:no_links]
75
+ html += link_to(post.author.pretty_name, user_path(post.author), class: 'post-author-link')
76
+ else
77
+ html += "<span class='post-author-name'>#{post.author.pretty_name}</span>"
78
+ end
79
+
80
+ html += "<span class='bullet'>&bull;</span>
81
+ <span class='post-date'>#{local_time (post.publish_at || post.created_at), post_time_format}</span>
82
+ </div>"
83
+
84
+ html.html_safe
85
+ end
86
+
87
+ def featured_post_text(post, opts={})
88
+ if post.excerpt.present? && post.show_excerpt?
89
+ html = "
90
+ <div class='featured-post-excerpt'>
91
+ #{truncate post.excerpt, length: 414}
92
+ "
93
+
94
+ if opts[:read_more] != false
95
+ html += "#{link_to "Read More", post_detail_path(post), class: 'read-more-link'}"
96
+ end
97
+
98
+ html += "</div>"
99
+
100
+ html.html_safe
101
+ else
102
+ "".html_safe
103
+ end
104
+ end
105
+
106
+ def post_tag(post)
107
+ if post.tags.any?
108
+ tag = post.post_tags.by_position.first.tag
109
+ "
110
+ <div class='post-tag'>
111
+ <span class='post-tag-text'>#{tag.name}</span>
112
+ </div>
113
+ ".html_safe
114
+ else
115
+ ""
116
+ end
117
+ end
118
+
119
+ def post_excerpt(post)
120
+ if post.excerpt.present? && post.show_excerpt?
121
+ "
122
+ <div class='post-body post-excerpt'>
123
+ #{post.excerpt}
124
+ <div class='read-more-link-wrap'>
125
+ #{link_to "Read More", post_detail_path(post), class: 'read-more-link'}
126
+ </div>
127
+ </div>
128
+ ".html_safe
129
+ else
130
+ "
131
+ <div class='post-body'>
132
+ #{truncate_post_to_read_more(post)}
133
+ </div>
134
+ ".html_safe
135
+ end
136
+ end
137
+
138
+ def post_banner_image_url(post)
139
+ if post.show_feature_image_on_post_page
140
+ post.featured_image.try(:image).try(:url, :wide)
141
+ end
142
+ end
143
+
144
+ def rss_post(xml, post)
145
+ xml.item {
146
+ xml.guid(post.uuid)
147
+ xml.pubDate(post.publish_at.to_s(:rfc822))
148
+ xml.title(post.headline)
149
+ xml.author(post.author.byline)
150
+ xml.link(post.permalink)
151
+ xml.description(post.rendered_body)
152
+
153
+ if post.featured_image
154
+ xml.tag!("media:content", {"url" => post.thumb_image.image.url(:email), "medium" => "image"})
155
+ end
156
+ }
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,33 @@
1
+ module Virgo
2
+ module RenderHelper
3
+ def with_format(format, &block)
4
+ old_formats = formats
5
+ self.formats = [format]
6
+ block.call
7
+ self.formats = old_formats
8
+ nil
9
+ end
10
+
11
+ # render_to_string, except force formats = [:html]
12
+ # if none are explicitly provided (so you can call
13
+ # from a controller action body responding to a json
14
+ # request and still render out a html partial by default)
15
+ def render_content(*args, &block)
16
+ augmented_args = _normalize_args(*args, &block)
17
+
18
+ augmented_args[:formats] ||= []
19
+
20
+ augmented_args[:formats] = [:html] unless augmented_args[:formats].include?(:html)
21
+
22
+ # declare so below reference is not block-local
23
+ content = ""
24
+
25
+ # necessary to not receive warnings (see above)
26
+ with_format :html do
27
+ content = render_to_string(augmented_args)
28
+ end
29
+
30
+ content.html_safe
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,49 @@
1
+ module Virgo
2
+ module SearchHelper
3
+
4
+ # Extracts the portion of the document that matches query text.
5
+ # Consider refactoring into a complex activerecord
6
+ # query leveraging "ts_headling". For present though
7
+ # we will perform this with a regex (on the document,
8
+ # which is constructed at the query level -
9
+ # see app/models/concerns/questions/search.rb)
10
+ def search_snippet(document, query, opts={})
11
+ length = opts[:length] || 300
12
+
13
+ start_padding = opts[:start_padding] || 30
14
+
15
+ words = query.split(" ")
16
+
17
+ text = original_text = document
18
+
19
+ matcher = Regexp.new(Regexp.union(words).source, Regexp::IGNORECASE)
20
+
21
+ if text.length > length
22
+ first_keyword_occurrence = text =~ matcher
23
+
24
+ if first_keyword_occurrence && first_keyword_occurrence > start_padding
25
+ start_offset = first_keyword_occurrence - start_padding
26
+ else
27
+ start_offset = 0
28
+ end
29
+
30
+ truncated = text.slice(start_offset, text.length)
31
+
32
+ text = truncated.slice(0, length)
33
+
34
+ if text.length < length
35
+ # pad beginning with existing text
36
+ padding_length = length - text.length
37
+ padding_text = original_text.slice(0, padding_length)
38
+ text = "...#{padding_text}...#{text}..."
39
+ else
40
+ text = "...#{text}..."
41
+ end
42
+ end
43
+
44
+ highlighted = text.gsub(matcher) { |match| "<strong class='match'>#{match}</strong>" }
45
+
46
+ highlighted.html_safe
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,7 @@
1
+ module Virgo
2
+ module ShortcodeHelper
3
+ def render_shortcodes(text)
4
+ Shortcode.process(text).try(:html_safe)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ # Source:
2
+ # http://blog.madebydna.com/all/code/2010/06/04/ruby-helper-to-cleanly-truncate-html.html
3
+
4
+ require 'nokogiri'
5
+
6
+ module Virgo
7
+ module TextHelper
8
+ def strip_read_more(text)
9
+ text.gsub('[read-more]', '').html_safe
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,34 @@
1
+ module Virgo
2
+ module VideoHelper
3
+ def video_provider(video_url='')
4
+ if video_url.include?('vimeo')
5
+ :vimeo
6
+ else
7
+ :youtube
8
+ end
9
+ end
10
+
11
+ def youtube_embed_url(youtube_url)
12
+ if youtube_url[/youtu\.be\/([^\?]*)/]
13
+ youtube_id = $1
14
+ else
15
+ # Regex from # http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url/4811367#4811367
16
+ youtube_url[/^.*((v\/)|(embed\/)|(watch\?))\??v?=?([^\&\?]*).*/]
17
+ youtube_id = $5
18
+ end
19
+ "http://www.youtube.com/embed/#{youtube_id}"
20
+ end
21
+
22
+ def vimeo_embed_url(video_url)
23
+ vimeo_regex = /https?:\/\/(www\.)?vimeo.com\/(\d+)/
24
+
25
+ result = video_url.match(vimeo_regex)
26
+
27
+ video_id = result ? result[2] : nil
28
+
29
+ if video_id
30
+ "https://player.vimeo.com/video/#{video_id}"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ module Virgo
2
+ module Common::SlugHistory
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_many :slug_histories, as: :record
7
+
8
+ after_save :generate_slug_history_item
9
+
10
+ def self.find_by_historic_slug(slug_val)
11
+ slugs = ::Virgo::SlugHistory.where(record_type: self.to_s, slug: slug_val)
12
+ slugs.order(created_at: :asc).last.try(:record)
13
+ end
14
+
15
+ def self.find_by_id_or_historic_slug!(id_val)
16
+ record = self.find_by(slug: id_val)
17
+
18
+ record = self.find_by(id: id_val) if record.nil?
19
+
20
+ record = self.find_by_historic_slug(id_val) if record.nil?
21
+
22
+ raise ActiveRecord::RecordNotFound if record.nil?
23
+
24
+ record
25
+ end
26
+
27
+ private
28
+
29
+ def generate_slug_history_item
30
+ if slug_changed? && !slug_was.blank?
31
+ slug_histories.create!(record: self, slug: slug_was)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,22 @@
1
+ module Virgo
2
+ module Common
3
+ module Uuid
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before_validation :generate_uuid, on: :create
8
+
9
+ private
10
+
11
+ def generate_uuid(opts={})
12
+ if uuid.blank? || opts[:force] == true
13
+ self.uuid = loop do
14
+ random_uuid = SecureRandom.hex(8)
15
+ break random_uuid unless self.class.where(uuid: random_uuid).exists?
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Virgo
2
+ class Post < ActiveRecord::Base
3
+ module Recommendations
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def recommendations
8
+ if post_tags.any?
9
+ Post.where.not(id: id).joins(:tags).where("post_tags.tag_id IN (?)", post_tags.pluck(:tag_id)).uniq.order(created_at: :desc).by_similarity_to(headline)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,100 @@
1
+ module Virgo
2
+ class Post < ActiveRecord::Base
3
+ module Search
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ scope :search, ->(filters=nil) {
8
+ filters ||= {}
9
+
10
+ items = all
11
+
12
+
13
+ if filters[:post_type].present?
14
+ items = items.where(post_type: filters[:post_type])
15
+ else
16
+ items = items.where(post_type: 'post') # default
17
+ end
18
+
19
+ if filters[:category].present?
20
+ filters[:category_ids] = [filters[:category]]
21
+ end
22
+
23
+ if filters[:category_ids].present?
24
+ filters[:category_ids].each_with_index do |id, i|
25
+ items = items.joins(
26
+ "INNER JOIN post_categories pc#{i} ON posts.id = pc#{i}.post_id AND pc#{i}.category_id = #{id.to_i}"
27
+ )
28
+ end
29
+ end
30
+
31
+ if filters[:status].present?
32
+ items = items.where(status: filters[:status])
33
+ end
34
+
35
+ if filters[:tag_ids].present?
36
+ filters[:tag_ids].each_with_index do |id, i|
37
+ items = items.joins(
38
+ "INNER JOIN post_tags pt#{i} ON posts.id = pt#{i}.post_id AND pt#{i}.tag_id = #{id.to_i}"
39
+ )
40
+ end
41
+ end
42
+
43
+ if filters[:term].present?
44
+ items = items.where("posts.headline ILIKE :term", term: "%#{filters[:term]}%")
45
+ end
46
+
47
+ if filters[:user_ids].present?
48
+ items = items.where("posts.author_id IN (?)", filters[:user_ids])
49
+ end
50
+
51
+ if filters[:month].present?
52
+ month = Chronic.parse(filters[:month])
53
+
54
+ items = items.for_month(month)
55
+ end
56
+
57
+ items
58
+ }
59
+
60
+ scope :search_by_similarity, ->(term){
61
+ items = posts.publicly_viewable
62
+
63
+ if term.present?
64
+ parts = term.split(" ")
65
+ queries = []
66
+ vals = {}
67
+
68
+ parts.each_with_index do |part, i|
69
+ vals[:"term_#{i}"] = "%#{part}%"
70
+
71
+ queries << "(virgo_posts.search_document ILIKE :term_#{i})"
72
+ end
73
+
74
+ query = queries.join(" OR ")
75
+
76
+ items = items.where(query, vals)
77
+
78
+ longest_term = parts.max_by {|t| t.length}
79
+
80
+ items = items.by_similarity_to(longest_term)
81
+ end
82
+
83
+ items
84
+ }
85
+
86
+ scope :by_similarity_to, ->(text) {
87
+ sanitized = connection.quote(text)
88
+ select("virgo_posts.*, SIMILARITY(virgo_posts.search_document, #{sanitized}) AS search_similarity").order("search_similarity DESC")
89
+ }
90
+
91
+ def self.reindex!
92
+ ::Post.find_each do |post|
93
+ post.send :generate_search_document, force: true
94
+ post.save!
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end