imagine_cms 3.0.0.beta6 → 3.0.0.beta7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (278) hide show
  1. data/README.rdoc +1 -1
  2. data/app/assets/images/codepress/line-numbers.png +0 -0
  3. data/app/assets/images/cropper/marqueeHoriz.gif +0 -0
  4. data/app/assets/images/cropper/marqueeVert.gif +0 -0
  5. data/app/assets/images/management/btn_add.gif +0 -0
  6. data/app/assets/images/management/btn_archive.gif +0 -0
  7. data/app/assets/images/management/btn_delete.gif +0 -0
  8. data/app/assets/images/management/btn_duplicate.gif +0 -0
  9. data/app/assets/images/management/btn_edit.gif +0 -0
  10. data/app/assets/images/management/btn_help.gif +0 -0
  11. data/app/assets/images/management/btn_new_page.gif +0 -0
  12. data/app/assets/images/management/btn_preview.gif +0 -0
  13. data/app/assets/images/management/btn_properties.gif +0 -0
  14. data/app/assets/images/management/btn_restore.gif +0 -0
  15. data/app/assets/images/management/btn_top_delete.gif +0 -0
  16. data/app/assets/images/management/btn_top_duplicate.gif +0 -0
  17. data/app/assets/images/management/btn_top_edit.gif +0 -0
  18. data/app/assets/images/management/btn_top_new.gif +0 -0
  19. data/app/assets/images/management/btn_top_preview.gif +0 -0
  20. data/app/assets/images/management/btn_top_properties.gif +0 -0
  21. data/app/assets/{manage → images/management}/bullet.gif +0 -0
  22. data/app/assets/images/management/cvv2_graphic.gif +0 -0
  23. data/app/assets/images/management/error.gif +0 -0
  24. data/app/assets/images/management/gallery_index.gif +0 -0
  25. data/app/assets/images/management/gallery_preview_overlay.png +0 -0
  26. data/app/assets/images/management/gallery_small_drag_overlay.png +0 -0
  27. data/app/assets/images/management/gallery_small_overlay.png +0 -0
  28. data/app/assets/images/management/gallery_sort.gif +0 -0
  29. data/app/assets/images/management/icon_download.gif +0 -0
  30. data/app/assets/images/management/icon_locked.png +0 -0
  31. data/app/assets/images/management/icon_page.gif +0 -0
  32. data/app/assets/images/management/icon_time.gif +0 -0
  33. data/app/assets/images/management/icon_unlocked.png +0 -0
  34. data/app/assets/images/management/page_loading.gif +0 -0
  35. data/app/assets/{manage → images/management}/start.gif +0 -0
  36. data/app/assets/images/management/vcard.gif +0 -0
  37. data/app/assets/javascripts/builder.js +101 -0
  38. data/app/assets/javascripts/codepress/codepress.html +36 -0
  39. data/app/assets/javascripts/codepress/codepress.js +130 -0
  40. data/app/assets/javascripts/codepress/engines/gecko.js +240 -0
  41. data/{vendor/gems/acts_as_tree/test/abstract_unit.rb → app/assets/javascripts/codepress/engines/khtml.js} +0 -0
  42. data/app/assets/javascripts/codepress/engines/msie.js +263 -0
  43. data/{vendor/gems/acts_as_tree/test/database.yml → app/assets/javascripts/codepress/engines/older.js} +0 -0
  44. data/app/assets/javascripts/codepress/engines/opera.js +259 -0
  45. data/app/assets/javascripts/codepress/languages/css.js +23 -0
  46. data/app/assets/javascripts/codepress/languages/generic.js +25 -0
  47. data/app/assets/javascripts/codepress/languages/html.js +63 -0
  48. data/app/assets/javascripts/codepress/languages/java.js +24 -0
  49. data/app/assets/javascripts/codepress/languages/javascript.js +30 -0
  50. data/app/assets/javascripts/codepress/languages/perl.js +27 -0
  51. data/app/assets/javascripts/codepress/languages/php.js +60 -0
  52. data/app/assets/javascripts/codepress/languages/ruby.js +26 -0
  53. data/app/assets/javascripts/codepress/languages/sql.js +30 -0
  54. data/app/assets/javascripts/codepress/languages/text.js +9 -0
  55. data/app/assets/javascripts/cropper.js +568 -0
  56. data/app/assets/javascripts/dojo/dojo.js +14155 -0
  57. data/app/assets/javascripts/dojo/src/html/images/shadowB.png +0 -0
  58. data/app/assets/javascripts/dojo/src/html/images/shadowBL.png +0 -0
  59. data/app/assets/javascripts/dojo/src/html/images/shadowBR.png +0 -0
  60. data/app/assets/javascripts/dojo/src/html/images/shadowL.png +0 -0
  61. data/app/assets/javascripts/dojo/src/html/images/shadowR.png +0 -0
  62. data/app/assets/javascripts/dojo/src/html/images/shadowT.png +0 -0
  63. data/app/assets/javascripts/dojo/src/html/images/shadowTL.png +0 -0
  64. data/app/assets/javascripts/dojo/src/html/images/shadowTR.png +0 -0
  65. data/app/assets/javascripts/dojo/src/widget/templates/Editor2/showtableborder_gecko.css +19 -0
  66. data/app/assets/javascripts/dojo/src/widget/templates/HslColorPicker.svg +30 -0
  67. data/app/assets/javascripts/dojo/src/widget/templates/buttons/aggregate.gif +0 -0
  68. data/app/assets/javascripts/dojo/src/widget/templates/buttons/aggregate.psd +0 -0
  69. data/app/assets/javascripts/dojo/src/widget/templates/buttons/backcolor.gif +0 -0
  70. data/app/assets/javascripts/dojo/src/widget/templates/buttons/bg-fade.png +0 -0
  71. data/app/assets/javascripts/dojo/src/widget/templates/buttons/bold.gif +0 -0
  72. data/app/assets/javascripts/dojo/src/widget/templates/buttons/cancel.gif +0 -0
  73. data/app/assets/javascripts/dojo/src/widget/templates/buttons/copy.gif +0 -0
  74. data/app/assets/javascripts/dojo/src/widget/templates/buttons/createlink.gif +0 -0
  75. data/app/assets/javascripts/dojo/src/widget/templates/buttons/cut.gif +0 -0
  76. data/app/assets/javascripts/dojo/src/widget/templates/buttons/delete.gif +0 -0
  77. data/app/assets/javascripts/dojo/src/widget/templates/buttons/forecolor.gif +0 -0
  78. data/app/assets/javascripts/dojo/src/widget/templates/buttons/hilitecolor.gif +0 -0
  79. data/app/assets/javascripts/dojo/src/widget/templates/buttons/indent.gif +0 -0
  80. data/app/assets/javascripts/dojo/src/widget/templates/buttons/inserthorizontalrule.gif +0 -0
  81. data/app/assets/javascripts/dojo/src/widget/templates/buttons/insertimage.gif +0 -0
  82. data/app/assets/javascripts/dojo/src/widget/templates/buttons/insertorderedlist.gif +0 -0
  83. data/app/assets/javascripts/dojo/src/widget/templates/buttons/inserttable.gif +0 -0
  84. data/app/assets/javascripts/dojo/src/widget/templates/buttons/insertunorderedlist.gif +0 -0
  85. data/app/assets/javascripts/dojo/src/widget/templates/buttons/italic.gif +0 -0
  86. data/app/assets/javascripts/dojo/src/widget/templates/buttons/justifycenter.gif +0 -0
  87. data/app/assets/javascripts/dojo/src/widget/templates/buttons/justifyfull.gif +0 -0
  88. data/app/assets/javascripts/dojo/src/widget/templates/buttons/justifyleft.gif +0 -0
  89. data/app/assets/javascripts/dojo/src/widget/templates/buttons/justifyright.gif +0 -0
  90. data/app/assets/javascripts/dojo/src/widget/templates/buttons/left_to_right.gif +0 -0
  91. data/app/assets/javascripts/dojo/src/widget/templates/buttons/list_bullet_indent.gif +0 -0
  92. data/app/assets/javascripts/dojo/src/widget/templates/buttons/list_bullet_outdent.gif +0 -0
  93. data/app/assets/javascripts/dojo/src/widget/templates/buttons/list_num_indent.gif +0 -0
  94. data/app/assets/javascripts/dojo/src/widget/templates/buttons/list_num_outdent.gif +0 -0
  95. data/app/assets/javascripts/dojo/src/widget/templates/buttons/outdent.gif +0 -0
  96. data/app/assets/javascripts/dojo/src/widget/templates/buttons/paste.gif +0 -0
  97. data/app/assets/javascripts/dojo/src/widget/templates/buttons/redo.gif +0 -0
  98. data/app/assets/javascripts/dojo/src/widget/templates/buttons/removeformat.gif +0 -0
  99. data/app/assets/javascripts/dojo/src/widget/templates/buttons/right_to_left.gif +0 -0
  100. data/app/assets/javascripts/dojo/src/widget/templates/buttons/save.gif +0 -0
  101. data/app/assets/javascripts/dojo/src/widget/templates/buttons/sep.gif +0 -0
  102. data/app/assets/javascripts/dojo/src/widget/templates/buttons/space.gif +0 -0
  103. data/app/assets/javascripts/dojo/src/widget/templates/buttons/strikethrough.gif +0 -0
  104. data/app/assets/javascripts/dojo/src/widget/templates/buttons/subscript.gif +0 -0
  105. data/app/assets/javascripts/dojo/src/widget/templates/buttons/superscript.gif +0 -0
  106. data/app/assets/javascripts/dojo/src/widget/templates/buttons/underline.gif +0 -0
  107. data/app/assets/javascripts/dojo/src/widget/templates/buttons/undo.gif +0 -0
  108. data/app/assets/javascripts/dojo/src/widget/templates/buttons/wikiword.gif +0 -0
  109. data/app/assets/javascripts/dojo/src/widget/templates/check.gif +0 -0
  110. data/app/assets/javascripts/dojo/src/widget/templates/decrementMonth.gif +0 -0
  111. data/app/assets/javascripts/dojo/src/widget/templates/decrementWeek.gif +0 -0
  112. data/app/assets/javascripts/dojo/src/widget/templates/grabCorner.gif +0 -0
  113. data/app/assets/javascripts/dojo/src/widget/templates/images/floatingPaneClose.gif +0 -0
  114. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaAccordionOff.gif +0 -0
  115. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaAccordionSelected.gif +0 -0
  116. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaActive-c.gif +0 -0
  117. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaActive-l.gif +0 -0
  118. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaActive-r.gif +0 -0
  119. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaBarBg.gif +0 -0
  120. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaButton-c.gif +0 -0
  121. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaButton-l.gif +0 -0
  122. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaButton-r.gif +0 -0
  123. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaDisabled-c.gif +0 -0
  124. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaDisabled-l.gif +0 -0
  125. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaDisabled-r.gif +0 -0
  126. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaMenuBg.gif +0 -0
  127. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaPressed-c.gif +0 -0
  128. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaPressed-l.gif +0 -0
  129. data/app/assets/javascripts/dojo/src/widget/templates/images/soriaPressed-r.gif +0 -0
  130. data/app/assets/javascripts/dojo/src/widget/templates/images/tab_close.gif +0 -0
  131. data/app/assets/javascripts/dojo/src/widget/templates/images/toolbar-bg.gif +0 -0
  132. data/app/assets/javascripts/dojo/src/widget/templates/incrementMonth.gif +0 -0
  133. data/app/assets/javascripts/dojo/src/widget/templates/incrementWeek.gif +0 -0
  134. data/app/assets/javascripts/dojo/src/widget/templates/richtextframe.html +24 -0
  135. data/app/assets/javascripts/imagine.js +1385 -0
  136. data/app/assets/javascripts/jquery_no_conflict.js +9405 -0
  137. data/app/assets/stylesheets/codepress/codepress.css +7 -0
  138. data/app/assets/stylesheets/codepress/languages/css.css +10 -0
  139. data/app/assets/stylesheets/codepress/languages/generic.css +9 -0
  140. data/app/assets/stylesheets/codepress/languages/html.css +18 -0
  141. data/app/assets/stylesheets/codepress/languages/java.css +7 -0
  142. data/app/assets/stylesheets/codepress/languages/javascript.css +8 -0
  143. data/app/assets/stylesheets/codepress/languages/perl.css +11 -0
  144. data/app/assets/stylesheets/codepress/languages/php.css +12 -0
  145. data/app/assets/stylesheets/codepress/languages/ruby.css +10 -0
  146. data/app/assets/stylesheets/codepress/languages/sql.css +10 -0
  147. data/app/assets/stylesheets/codepress/languages/text.css +5 -0
  148. data/app/assets/stylesheets/cropper.css +182 -0
  149. data/app/assets/stylesheets/management.css +96 -0
  150. data/app/assets/stylesheets/reset.css +58 -0
  151. data/app/controllers/cms/content_controller.rb +318 -2
  152. data/app/controllers/management/cms_controller.rb +1669 -0
  153. data/app/controllers/management/user_controller.rb +4 -4
  154. data/app/controllers/management/users_controller.rb +18 -4
  155. data/app/controllers/util_controller.rb +45 -0
  156. data/app/helpers/cms_application_helper.rb +662 -15
  157. data/app/models/cms_content_sweeper.rb +21 -0
  158. data/app/models/cms_page.rb +126 -0
  159. data/app/models/cms_page_object.rb +23 -0
  160. data/app/models/cms_page_tag.rb +5 -0
  161. data/app/models/cms_page_version.rb +3 -0
  162. data/app/models/cms_snippet.rb +16 -0
  163. data/app/models/cms_template.rb +29 -0
  164. data/app/models/user.rb +6 -3
  165. data/app/views/management/cms/_complete_gallery.html.erb +5 -0
  166. data/app/views/management/cms/_create_file_link.html.erb +21 -0
  167. data/app/views/management/cms/_crop_feature_image.html.erb +188 -0
  168. data/app/views/management/cms/_crop_image.html.erb +188 -0
  169. data/app/views/management/cms/_crop_results.html.erb +1 -0
  170. data/app/views/management/cms/_crop_results_feature_image.html.erb +1 -0
  171. data/app/views/management/cms/_crop_results_thumb.html.erb +1 -0
  172. data/app/views/management/cms/_crop_thumb.html.erb +188 -0
  173. data/app/views/management/cms/_dialogs.html.erb +39 -0
  174. data/app/views/management/cms/_edit_page.html.erb +176 -0
  175. data/app/views/management/cms/_gallery_index.html.erb +10 -0
  176. data/app/views/management/cms/_gallery_setup.html.erb +22 -0
  177. data/app/views/management/cms/_image.html.erb +3 -0
  178. data/app/views/management/cms/_image_details.html.erb +26 -0
  179. data/app/views/management/cms/_image_draggable.html.erb +4 -0
  180. data/app/views/management/cms/_list_page.html.erb +8 -0
  181. data/app/views/management/cms/_list_page_select.html.erb +8 -0
  182. data/app/views/management/cms/_list_pages.html.erb +1 -0
  183. data/app/views/management/cms/_list_pages_select.html.erb +1 -0
  184. data/app/views/management/cms/_page_attribute.html.erb +6 -0
  185. data/app/views/management/cms/_page_list.html.erb +171 -0
  186. data/app/views/management/cms/_page_list_source_folder.html.erb +20 -0
  187. data/app/views/management/cms/_page_list_source_tag.html.erb +18 -0
  188. data/app/views/management/cms/_select_gallery.html.erb +117 -0
  189. data/app/views/management/cms/_snippet.html.erb +3 -0
  190. data/app/views/management/cms/_sort_images.html.erb +15 -0
  191. data/app/views/management/cms/_temp.html.erb +3 -0
  192. data/app/views/management/cms/_template_options.html.erb +21 -0
  193. data/app/views/management/cms/_template_reference.html.erb +42 -0
  194. data/app/views/management/cms/_upload_feature_image.html.erb +35 -0
  195. data/app/views/management/cms/_upload_file.html.erb +31 -0
  196. data/app/views/management/cms/_upload_image.html.erb +74 -0
  197. data/app/views/management/cms/_upload_thumb.html.erb +35 -0
  198. data/app/views/management/cms/edit_master.html.erb +48 -0
  199. data/app/views/management/cms/edit_page_content.html.erb +4 -0
  200. data/app/views/management/cms/edit_snippet.html.erb +47 -0
  201. data/app/views/management/cms/edit_template.html.erb +48 -0
  202. data/app/views/management/cms/gallery_management.html.erb +108 -0
  203. data/app/views/management/cms/index.html.erb +20 -0
  204. data/app/views/management/cms/page_tags_for_lookup.html.erb +5 -0
  205. data/app/views/management/cms/pages.html.erb +99 -0
  206. data/app/views/management/cms/permission_denied.html.erb +1 -0
  207. data/app/views/management/cms/select_page.html.erb +57 -0
  208. data/app/views/management/cms/snippets.html.erb +14 -0
  209. data/app/views/management/cms/templates.html.erb +14 -0
  210. data/app/views/management/cms/toolbar_edit.html.erb +269 -0
  211. data/app/views/management/cms/toolbar_preview.html.erb +109 -0
  212. data/app/views/util/_calendar_days.html.erb +72 -0
  213. data/app/views/util/_calendar_month_year.html.erb +1 -0
  214. data/app/views/util/_date_picker.html.erb +56 -0
  215. data/app/views/util/_message.html.erb +1 -0
  216. data/app/views/util/_show_message.js.erb +6 -0
  217. data/app/views/util/_tab.html.erb +4 -0
  218. data/config/routes.rb +4 -1
  219. data/imagine_cms.gemspec +4 -0
  220. data/{vendor/gems → lib}/acts_as_versioned/.document +0 -0
  221. data/{vendor/gems → lib}/acts_as_versioned/.gitignore +2 -0
  222. data/{vendor/gems → lib}/acts_as_versioned/CHANGELOG +0 -0
  223. data/lib/acts_as_versioned/Gemfile +7 -0
  224. data/{vendor/gems → lib}/acts_as_versioned/MIT-LICENSE +0 -0
  225. data/{vendor/gems → lib}/acts_as_versioned/README +0 -0
  226. data/{vendor/gems → lib}/acts_as_versioned/RUNNING_UNIT_TESTS +0 -0
  227. data/{vendor/gems → lib}/acts_as_versioned/Rakefile +1 -1
  228. data/{vendor/gems → lib}/acts_as_versioned/acts_as_versioned.gemspec +4 -4
  229. data/{vendor/gems → lib}/acts_as_versioned/init.rb +0 -0
  230. data/{vendor/gems → lib}/acts_as_versioned/lib/acts_as_versioned.rb +109 -107
  231. data/{vendor/gems → lib}/acts_as_versioned/test/abstract_unit.rb +0 -0
  232. data/{vendor/gems → lib}/acts_as_versioned/test/database.yml +0 -0
  233. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/authors.yml +0 -0
  234. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/landmark.rb +0 -0
  235. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/landmark_versions.yml +0 -0
  236. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/landmarks.yml +0 -0
  237. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/locked_pages.yml +0 -0
  238. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/locked_pages_revisions.yml +0 -0
  239. data/{vendor/gems/acts_as_versioned/test/fixtures/migrations/1_add_versioned_tables.rb → lib/acts_as_versioned/test/fixtures/migrations/2_add_versioned_tables.rb} +0 -0
  240. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/page.rb +0 -0
  241. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/page_versions.yml +0 -0
  242. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/pages.yml +0 -0
  243. data/{vendor/gems → lib}/acts_as_versioned/test/fixtures/widget.rb +0 -0
  244. data/{vendor/gems → lib}/acts_as_versioned/test/migration_test.rb +0 -1
  245. data/{vendor/gems → lib}/acts_as_versioned/test/schema.rb +0 -0
  246. data/{vendor/gems → lib}/acts_as_versioned/test/versioned_test.rb +0 -0
  247. data/lib/extensions/action_controller.rb +154 -143
  248. data/lib/imagine_cms/engine.rb +33 -12
  249. data/lib/imagine_cms/version.rb +1 -1
  250. data/lib/imagine_cms.rb +30 -6
  251. data/lib/prototype_legacy_helper/README.markdown +13 -0
  252. data/lib/prototype_legacy_helper/init.rb +1 -0
  253. data/lib/prototype_legacy_helper/lib/prototype_legacy_helper.rb +430 -0
  254. data/lib/prototype_legacy_helper/test/test_prototype_helper.rb +297 -0
  255. data/lib/upload_progress/CHANGELOG +5 -0
  256. data/lib/upload_progress/MIT-LICENSE +20 -0
  257. data/lib/upload_progress/README +45 -0
  258. data/{vendor/gems/acts_as_tree → lib/upload_progress}/Rakefile +6 -5
  259. data/lib/upload_progress/init.rb +7 -0
  260. data/lib/upload_progress/lib/multipart_progress.rb +176 -0
  261. data/lib/upload_progress/lib/progress.rb +145 -0
  262. data/lib/upload_progress/lib/upload_progress.rb +303 -0
  263. data/lib/upload_progress/lib/upload_progress_helper.rb +425 -0
  264. data/lib/upload_progress/public/stylesheets/upload_progress.css +21 -0
  265. data/lib/upload_progress/test/multipart_progress_testx.rb +364 -0
  266. data/lib/upload_progress/test/upload_progress_helper_testx.rb +134 -0
  267. data/lib/upload_progress/test/upload_progress_testx.rb +88 -0
  268. metadata +305 -43
  269. data/app/assets/manage/btn_delete.gif +0 -0
  270. data/vendor/gems/.DS_Store +0 -0
  271. data/vendor/gems/acts_as_tree/README +0 -26
  272. data/vendor/gems/acts_as_tree/init.rb +0 -1
  273. data/vendor/gems/acts_as_tree/lib/active_record/acts/tree.rb +0 -96
  274. data/vendor/gems/acts_as_tree/test/acts_as_tree_test.rb +0 -219
  275. data/vendor/gems/acts_as_tree/test/fixtures/mixin.rb +0 -0
  276. data/vendor/gems/acts_as_tree/test/fixtures/mixins.yml +0 -0
  277. data/vendor/gems/acts_as_tree/test/schema.rb +0 -0
  278. data/vendor/gems/acts_as_versioned/Gemfile +0 -7
@@ -1,12 +1,655 @@
1
1
  module CmsApplicationHelper
2
2
 
3
+ # Saves the current request to the session so that it can be replayed later
4
+ # (for example, after authentication). Only params of type String, Hash and
5
+ # Array will be saved. save_request is called in a before_filter in
6
+ # application.rb.
7
+ #
8
+ # Two levels of saved params are required so that params can be unsaved in
9
+ # the event of a 404 or other event that would make the current param set an
10
+ # unlikely or undesirable candidate for replaying.
11
+ def save_user_request
12
+ return if params[:action] == 'login'
13
+
14
+ session[:old_saved_user_uri] = session[:saved_user_uri];
15
+ session[:old_saved_user_params] = session[:saved_user_params] || {};
16
+ saved_params = params.reject { |k, v| !(v.kind_of?(String) || v.kind_of?(Hash) || v.kind_of?(Array)) }
17
+ saved_params.each { |key, val| saved_params[key] = val.reject { |k, v| !(v.kind_of?(String) || v.kind_of?(Hash) || v.kind_of?(Array)) } if val.kind_of?(Hash) }
18
+ session[:saved_user_uri] = request.url
19
+ session[:saved_user_params] = saved_params
20
+ end
21
+
22
+ # Returns a User object corresponding to the currently logged in user, or returns false
23
+ # and redirects to the login page if not logged in.
24
+ def authenticate_user
25
+ # if user is not logged in, record the current request and redirect
26
+ if !session[:user_authenticated]
27
+ if User.find(:all).size == 0
28
+ flash[:notice] = 'No users exist in the system. Please create one now.'
29
+ redirect_to :controller => '/management/user', :action => 'create_first'
30
+ else
31
+ flash[:notice] = 'This is an admin-only function. To continue, please log in.'
32
+ save_user_request
33
+ redirect_to :controller => '/management/user', :action => 'login'
34
+ end
35
+
36
+ return false
37
+ end
38
+
39
+ @user = User.find(session[:user_id]) rescue nil
40
+ session[:user_is_superuser] = @user.is_superuser rescue nil
41
+
42
+ @user
43
+ end
44
+
45
+ # Takes a symbol/string or array of symbols/strings and returns true if user has all
46
+ # of the named permissions.
47
+ #
48
+ # Result is stored in the session to speed up future checks.
49
+ def user_has_permissions?(*permission_set)
50
+ return false if !(@user ||= authenticate_user)
51
+
52
+ if !permission_set.is_a? Array
53
+ permission_set = [ permission_set ]
54
+ end
55
+
56
+ if session[:user_is_superuser]
57
+ for perm in permission_set
58
+ perm = perm.to_s
59
+ session[('user_can_' + perm).to_sym] ||= true
60
+ end
61
+ return true
62
+ end
63
+
64
+ for perm in permission_set
65
+ perm = perm.to_s
66
+ session[('user_can_' + perm).to_sym] = @user.send('can_' + perm)
67
+ # logger.debug "user_can_#{perm} = #{@user.send('can_' + perm)}"
68
+ return session[('user_can_' + perm).to_sym]
69
+ end
70
+ end
71
+ alias :user_has_permission? :user_has_permissions?
72
+
73
+ # Returns true if a Member is logged in.
74
+ def is_logged_in?
75
+ session[:authenticated]
76
+ end
77
+
78
+ # Returns true if a User is logged in.
79
+ def is_logged_in_user?
80
+ session[:user_authenticated]
81
+ end
82
+
83
+ # Returns true if the user is editing the current page.
84
+ # (This just means that we are rendering :controller => 'management/cms', :action => 'edit_page_content'.)
85
+ def is_editing_page?
86
+ params[:controller] == 'management/cms' && params[:action] == 'edit_page_content'
87
+ end
88
+
89
+ # Determines whether the input string is a valid email address per RFC specification
90
+ def valid_email_address?(addr, perform_mx_lookup = false)
91
+ valid = true
92
+
93
+ # simplified regex for speed... the original can basically lock up the system on longish addresses
94
+ # valid = valid && addr.to_s =~ /\A([\w\d]+(?:[\w\d\!\#\$\%\&\*\+\-\/\=\?\^\`\{\|\}\~\.]*[\w\d]+)*)@((?:[\w\d]+(?:[-]*[\w\d]+)*\.)+[\w]{2,})\z/
95
+ valid = valid && addr.to_s =~ /\A([\w\d\!\#\$\%\&\*\+\-\/\=\?\^\`\{\|\}\~\.]+)@((?:[\w\d]+(?:[-]*[\w\d]+)*\.)+[\w]{2,})\z/
96
+ user, host = $1, $2
97
+
98
+ if perform_mx_lookup
99
+ begin
100
+ # require 'net/dns'
101
+ res = Net::DNS::Resolver.new
102
+ valid = valid && res.mx(host).size > 0
103
+ rescue Exception => e
104
+ logger.error(e)
105
+ end
106
+ end
107
+
108
+ valid
109
+ end
110
+
111
+ ### COMPAT: convert_content_path
112
+ def convert_content_path
113
+ logger.debug "DEPRECATION WARNING (Imagine CMS) WARNING: convert_content_path called"
114
+ params[:content_path] = params[:content_path].to_s.split('/') rescue []
115
+ end
116
+
117
+ ### COMPAT - template_exists?
118
+ def template_exists?(template, extension = nil)
119
+ # ignore extension
120
+ logger.debug("DEPRECATION WARNING (Imagine CMS) WARNING: template_exists? called")
121
+ partial = File.join(File.dirname(template), '_' + File.basename(template))
122
+ lookup_context.find_all(template).any? || lookup_context.find_all(partial).any?
123
+ end
124
+
125
+ ### COMPAT - template_exists?
126
+ def url_for_current
127
+ logger.debug("DEPRECATION WARNING (Imagine CMS) WARNING: url_for_current called")
128
+ request.fullpath
129
+ end
130
+
131
+ # Returns the first non-empty string in its arg list. Clearly, depends on nil_empty plugin.
132
+ def first_non_empty(*args)
133
+ while !args.empty?
134
+ ret = args.shift
135
+ return ret unless ret.to_s.empty?
136
+ end
137
+ return ''
138
+ end
139
+
140
+ ### COMPAT - log_error
141
+ def log_error(e)
142
+ # noop
143
+ logger.debug("DEPRECATION WARNING (Imagine CMS) WARNING: log_error called")
144
+ logger.error(e)
145
+ end
146
+
147
+ def convert_invalid_chars_in_params
148
+ dig_deep(params) { |s| convert_invalid_chars!(s) }
149
+ end
150
+
151
+ def dig_deep(hash, &block)
152
+ if hash.instance_of? String
153
+ yield(hash)
154
+ elsif hash.kind_of? Hash
155
+ hash.each_key { |h| dig_deep(hash[h]) { |s| block.call(s) } }
156
+ else
157
+ nil
158
+ end
159
+ end
160
+
161
+ def convert_invalid_chars!(s)
162
+ # leave commented out until we're sure these are still needed
163
+
164
+ # s.gsub!(/\xe2\x80\x98/, '‘') # ‘
165
+ # s.gsub!(/\xe2\x80\x99/, '’') # ’
166
+ # s.gsub!(/\xe2\x80\x9c/, '“') # “
167
+ # s.gsub!(/\xe2\x80\x9d/, '”') # ”
168
+ # s.gsub!(/\xe2\x80\x93/, '–') # –
169
+ # s.gsub!(/\xe2\x80\x94/, '—') # —
170
+ # s.gsub!(/\xe2\x80\xa2/, '•') # •
171
+ # s.gsub!(/\xe2\x80\xa6/, '…') # …
172
+ # s.gsub!(/\xe2\x80\xa8/, ' ') # (space)
173
+ # s.gsub!(/\xe2\x84\xa2/, '™') # ™
174
+ #
175
+ # s.gsub!(/\xc2\xae/, '®') # ®
176
+ # s.gsub!(/\xc2\xab/, '«') # «
177
+ # s.gsub!(/\xc2\xbb/, '»') # »
178
+ # s.gsub!(/\xc2\xbd/, '½') # ½
179
+ # s.gsub!(/\xc2\xbc/, '¼') # ¼
180
+ #
181
+ # s.gsub!(/\xc4\x80/, 'Ā') # Ā
182
+ # s.gsub!(/\xc4\x81/, 'ā') # ā
183
+ # s.gsub!(/\xc4\x92/, 'Ē') # Ē
184
+ # s.gsub!(/\xc4\x93/, 'ē') # ē
185
+ # s.gsub!(/\xc4\xaa/, 'Ī') # Ī
186
+ # s.gsub!(/\xc4\xab/, 'ī') # ī
187
+ # s.gsub!(/\xc5\x8c/, 'Ō') # Ō
188
+ # s.gsub!(/\xc5\x8d/, 'ō') # ō
189
+ # s.gsub!(/\xc5\xaa/, 'Ū') # Ū
190
+ # s.gsub!(/\xc5\xab/, 'ū') # ū
191
+ #
192
+ # s.gsub!(/\xc3\x84/, 'Ä') # Ä
193
+ # s.gsub!(/\xc3\x8b/, 'Ë') # Ë
194
+ # s.gsub!(/\xc3\x8f/, 'Ï') # Ï
195
+ # s.gsub!(/\xc3\x96/, 'Ö') # Ö
196
+ # s.gsub!(/\xc3\x9c/, 'Ü') # Ü
197
+ # s.gsub!(/\xc3\xa4/, 'ä') # ä
198
+ # s.gsub!(/\xc3\xab/, 'ë') # ë
199
+ # s.gsub!(/\xc3\xaf/, 'ï') # ï
200
+ # s.gsub!(/\xc3\xb6/, 'ö') # ö
201
+ # s.gsub!(/\xc3\xbc/, 'ü') # ü
202
+ #
203
+ # s.gsub!(/\xc3\x81/, 'Á') # Á
204
+ # s.gsub!(/\xc3\x89/, 'É') # É
205
+ # s.gsub!(/\xc3\x8d/, 'Í') # Í
206
+ # s.gsub!(/\xc3\x93/, 'Ó') # Ó
207
+ # s.gsub!(/\xc3\x9a/, 'Ú') # Ú
208
+ # s.gsub!(/\xc3\xa1/, 'á') # á
209
+ # s.gsub!(/\xc3\xa9/, 'é') # é
210
+ # s.gsub!(/\xc3\xad/, 'í') # í
211
+ # s.gsub!(/\xc3\xb3/, 'ó') # ó
212
+ # s.gsub!(/\xc3\xba/, 'ú') # ú
213
+ #
214
+ # s.gsub!(/\xc5\x98/, 'Ř') # Ř
215
+ # s.gsub!(/\xc5\x99/, 'ř') # ř
216
+ #
217
+ # s.gsub!(/\x85/, '…') # …
218
+ # s.gsub!(/\x8b/, '&lt;') # <
219
+ # s.gsub!(/\x9b/, '&gt;') # >
220
+ # s.gsub!(/\x91/, '&lsquo;') # ‘
221
+ # s.gsub!(/\x92/, '&rsquo;') # ’
222
+ # s.gsub!(/\x93/, '&ldquo;') # “
223
+ # s.gsub!(/\x94/, '&rdquo;') # ”
224
+ # s.gsub!(/\x97/, '&mdash;') # —
225
+ # s.gsub!(/\x99/, '&trade;') # ™
226
+ # s.gsub!(/\x95/, '*')
227
+ # s.gsub!(/\x96/, '-')
228
+ # s.gsub!(/\x98/, '~')
229
+ # s.gsub!(/\x88/, '^')
230
+ # s.gsub!(/\x82/, ',')
231
+ # s.gsub!(/\x84/, ',,')
232
+ # s.gsub!(/\x89/, 'o/oo')
233
+ # s.gsub!(/\x8c/, 'OE')
234
+ # s.gsub!(/\x9c/, 'oe')
235
+ end
236
+
237
+ # Convert from GMT/UTC to local time (based on time zone setting in session[:time_zone])
238
+ def gm_to_local(time)
239
+ ActiveSupport::TimeZone.new(session[:time_zone] || 'UTC').utc_to_local(time)
240
+ end
241
+
242
+ # Convert from local time to GMT/UTC (based on time zone setting in session[:time_zone])
243
+ def local_to_gm(time)
244
+ ActiveSupport::TimeZone.new(session[:time_zone] || 'UTC').local_to_utc(time)
245
+ end
246
+
247
+ # Convert a time object into a formatted date/time string
248
+ def ts_to_str(ts)
249
+ return '' if ts == nil
250
+ gm_to_local(ts).strftime('%a %b %d, %Y') + ' at ' +
251
+ gm_to_local(ts).strftime('%I:%M%p').downcase + ' ' + (session[:time_zone_abbr] || '')
252
+ end
253
+
254
+ # Convert a time object into a formatted time string (no date)
255
+ def ts_to_time_str(ts)
256
+ return '' if ts == nil
257
+ gm_to_local(ts).strftime('%I:%M:%S%p').downcase
258
+ end
259
+
260
+ # Convert times to a standard format (e.g. 1:35pm)
261
+ def time_to_str(t, convert = true)
262
+ return '' if t == nil
263
+ if convert
264
+ gm_to_local(t).strftime("%I").to_i.to_s + gm_to_local(t).strftime(":%M%p").downcase
265
+ else
266
+ t.strftime("%I").to_i.to_s + t.strftime(":%M%p").downcase
267
+ end
268
+ end
269
+
270
+ # Convert times to a standard format (e.g. 1:35pm)
271
+ def date_to_str(t, convert = true)
272
+ return '' if t == nil
273
+ if convert
274
+ gm_to_local(t).strftime("%m").to_i.to_s + '/' + gm_to_local(t).strftime("%d").to_i.to_s + gm_to_local(t).strftime("/%Y")
275
+ else
276
+ t.strftime("%m").to_i.to_s + '/' + t.strftime("%d").to_i.to_s + t.strftime("/%Y")
277
+ end
278
+ end
279
+
280
+
281
+
282
+ def load_page_objects(obj_type = nil, name = nil)
283
+ if params[:version].to_i > 0 && params[:version].to_i != @pg.published_version
284
+ if is_logged_in_user?
285
+ if user_has_permission?(:manage_cms)
286
+ @pg.revert_to(params[:version].to_i)
287
+ end
288
+ else
289
+ authenticate_user
290
+ return false
291
+ end
292
+ elsif @pg.version != @pg.published_version
293
+ @pg.revert_to(@pg.published_version)
294
+ end
295
+
296
+ @page_objects = HashObject.new
297
+ conditions = [ 'cms_page_version = ?' ]
298
+ cond_vars = [ @pg.version ]
299
+
300
+ if obj_type
301
+ conditions << 'obj_type = ?'
302
+ cond_vars << obj_type
303
+ end
304
+ if name
305
+ conditions << 'name = ?'
306
+ cond_vars << name
307
+ end
308
+
309
+ @pg.objects.find(:all, :conditions => [ conditions.join(' and ') ].concat(cond_vars)).each do |obj|
310
+ @page_objects["obj-#{obj.obj_type.to_s}-#{obj.name}"] = obj.content
311
+ end
312
+ end
313
+
314
+ def page_list_items(pg, key, options = {})
315
+ pages = []
316
+ instance_tags_include = []
317
+ instance_tags_exclude = []
318
+ instance_tags_require = []
319
+
320
+ conditions = [ 'cms_pages.published_version >= 0', 'cms_pages.published_date is not null', 'cms_pages.published_date < NOW()' ]
321
+ cond_vars = []
322
+
323
+ if options[:start_date]
324
+ options[:start_date] = Time.parse(options[:start_date]) if options[:start_date].is_a? String
325
+ conditions << 'cms_pages.article_date >= ?'
326
+ cond_vars << options[:start_date]
327
+ end
328
+ if options[:end_date]
329
+ options[:end_date] = Time.parse(options[:end_date]) if options[:end_date].is_a? String
330
+ conditions << 'cms_pages.article_date < ?'
331
+ cond_vars << (options[:end_date] + 1.day)
332
+ end
333
+
334
+ @page_objects["#{key}-sources-tag-count"] = @page_objects["#{key}-sources-tag-count"].to_i
335
+
336
+ for i in 0...@page_objects["#{key}-sources-tag-count"]
337
+ case @page_objects["#{key}-sources-tag#{i}-behavior"]
338
+ when 'include'
339
+ instance_tags_include << @page_objects["#{key}-sources-tag#{i}"]
340
+ when 'exclude'
341
+ instance_tags_exclude << @page_objects["#{key}-sources-tag#{i}"]
342
+ when 'require'
343
+ instance_tags_require << @page_objects["#{key}-sources-tag#{i}"]
344
+ end
345
+ end
346
+ include_tags = instance_tags_include.map { |t| t.strip }.reject { |t| t.empty? }
347
+ exclude_tags = instance_tags_exclude.map { |t| t.strip }.reject { |t| t.empty? }
348
+ require_tags = instance_tags_require.map { |t| t.strip }.reject { |t| t.empty? }
349
+
350
+ if include_tags.empty?
351
+ include_tags = (options[:include_tags] || '').split(',').map { |t| t.strip }.reject { |t| t.empty? }
352
+ include_tags.each do |t|
353
+ i = @page_objects["#{key}-sources-tag-count"]
354
+ @page_objects["#{key}-sources-tag#{i}"] = t
355
+ @page_objects["#{key}-sources-tag#{i}-behavior"] = 'include'
356
+ @page_objects["#{key}-sources-tag-count"] += 1
357
+ end
358
+ end
359
+ if exclude_tags.empty?
360
+ exclude_tags = (options[:exclude_tags] || '').split(',').map { |t| t.strip }.reject { |t| t.empty? }
361
+ exclude_tags.each do |t|
362
+ i = @page_objects["#{key}-sources-tag-count"]
363
+ @page_objects["#{key}-sources-tag#{i}"] = t
364
+ @page_objects["#{key}-sources-tag#{i}-behavior"] = 'exclude'
365
+ @page_objects["#{key}-sources-tag-count"] += 1
366
+ end
367
+ end
368
+ if require_tags.empty?
369
+ require_tags = (options[:require_tags] || '').split(',').map { |t| t.strip }.reject { |t| t.empty? }
370
+ require_tags.each do |t|
371
+ i = @page_objects["#{key}-sources-tag-count"]
372
+ @page_objects["#{key}-sources-tag#{i}"] = t
373
+ @page_objects["#{key}-sources-tag#{i}-behavior"] = 'require'
374
+ @page_objects["#{key}-sources-tag-count"] += 1
375
+ end
376
+ end
377
+
378
+ # pull all folder content
379
+ folders = []
380
+ for i in 0...@page_objects["#{key}-sources-folder-count"].to_i
381
+ folders << HashObject.new(:src => @page_objects["#{key}-sources-folder#{i}"].strip,
382
+ :expand_folders => @page_objects["#{key}-sources-folder#{i}-expand-folders"])
383
+ end
384
+ folders = folders.reject { |f| f.src.empty? }
385
+
386
+ if folders.empty?
387
+ folders = (options[:folders] || '').split(',').map do |f|
388
+ bits = f.strip.split(':')
389
+
390
+ obj = HashObject.new
391
+ obj.src = bits[0]
392
+ obj.expand_folders = 'true'
393
+
394
+ while bit = bits.shift
395
+ case bit
396
+ when 'expand-folders'
397
+ ;
398
+ when 'no-expand-folders'
399
+ obj.expand_folders = 'false'
400
+ end
401
+ end
402
+
403
+ obj
404
+ end
405
+ folders = folders.reject { |f| f.src.empty? }
406
+
407
+ @page_objects["#{key}-sources-folder-count"] = folders.size
408
+ folders.each_with_index do |f, i|
409
+ @page_objects["#{key}-sources-folder#{i}"] = f.src
410
+ @page_objects["#{key}-sources-folder#{i}-expand-folders"] = f.expand_folders
411
+ end
412
+ end
413
+
414
+ # exclude expired items if specified
415
+ if @page_objects["#{key}-include-expired"]
416
+ if @page_objects["#{key}-include-expired"] == 'false'
417
+ conditions << '(cms_pages.expires = ? OR (cms_pages.expires = ? AND cms_pages.expiration_date >= ?))'
418
+ cond_vars << false
419
+ cond_vars << true
420
+ cond_vars << Time.now
421
+ end
422
+ end
423
+
424
+ folders.each do |f|
425
+ begin
426
+ if f.expand_folders && f.expand_folders == 'false'
427
+ f.src = f.src.slice(1...f.src.length) if f.src.slice(0,1) == '/'
428
+ parent_page = CmsPage.find_by_path(f.src)
429
+ pages.concat parent_page.children.find(:all, :include => [ :tags ], :conditions => [ conditions.join(' and ') ].concat(cond_vars))
430
+ else
431
+ if f.src == '/'
432
+ pages.concat CmsPage.find(:all, :include => [ :tags ], :conditions => [ conditions.join(' and ') ].concat(cond_vars))
433
+ else
434
+ f.src = f.src.slice(1...f.src.length) if f.src.slice(0,1) == '/'
435
+ fconditions = conditions.dup
436
+ fconditions << 'path like ?'
437
+ fcond_vars = cond_vars.dup
438
+ fcond_vars << f.src+'/%'
439
+ pages.concat CmsPage.find(:all, :include => [ :tags ], :conditions => [ fconditions.join(' and ') ].concat(fcond_vars))
440
+ end
441
+ end
442
+ rescue Exception => e
443
+ logger.debug e
444
+ end
445
+ end
446
+
447
+ # pull all include tag content
448
+ include_tags.each do |tag|
449
+ pages.concat CmsPageTag.find_all_by_name(tag, :include => [ :page ], :conditions => [ conditions.join(' and ') ].concat(cond_vars)).map { |cpt| cpt.page }
450
+ end
451
+
452
+ # dump anything that has an excluded tag
453
+ exclude_tags.each do |tag|
454
+ pages.reject! { |page| page.tags.reject { |t| t.name != tag } != [] }
455
+ end
456
+
457
+ # dump anything that does not have a required tag
458
+ require_tags.each do |tag|
459
+ pages.reject! { |page| page.tags.reject { |t| t.name != tag } == [] }
460
+ end
461
+
462
+ if pg && (options[:exclude_current] === true || @page_objects["#{key}-exclude-current"] == 'true')
463
+ pages.reject! { |page| page == pg }
464
+ end
465
+
466
+ # set some reasonable defaults in case the sort keys are nil
467
+ pages.each { |pg| pg.article_date ||= Time.now; pg.position ||= 0; pg.title ||= '' }
468
+ pri_sort_key = first_non_empty(@page_objects["#{key}-sort-first-field"], options[:primary_sort_key], 'article_date')
469
+ pri_sort_dir = first_non_empty(@page_objects["#{key}-sort-first-direction"], options[:primary_sort_direction], 'asc')
470
+ sec_sort_key = first_non_empty(@page_objects["#{key}-sort-second-field"], options[:secondary_sort_key], 'position')
471
+ sec_sort_dir = first_non_empty(@page_objects["#{key}-sort-second-direction"], options[:secondary_sort_direction], 'asc')
472
+ @page_objects["#{key}-sort-first-field"] ||= pri_sort_key
473
+ @page_objects["#{key}-sort-first-direction"] ||= pri_sort_dir
474
+ @page_objects["#{key}-sort-second-field"] ||= sec_sort_key
475
+ @page_objects["#{key}-sort-second-direction"] ||= sec_sort_dir
476
+
477
+ keys_with_dir = [ [ pri_sort_key, pri_sort_dir ], [ sec_sort_key, sec_sort_dir ] ]
478
+ pages.sort! do |a,b|
479
+ index = 0
480
+ result = 0
481
+ while result == 0 && index < keys_with_dir.size
482
+ key = keys_with_dir[index][0]
483
+ aval = a.send(key)
484
+ bval = b.send(key)
485
+
486
+ if !aval
487
+ result = 1
488
+ elsif !bval
489
+ result = -1
490
+ else
491
+ result = aval <=> bval
492
+ end
493
+
494
+ result *= -1 if keys_with_dir[index][1] && keys_with_dir[index][1].downcase == 'desc'
495
+ index += 1
496
+ end
497
+
498
+ result
499
+ end
500
+
501
+ offset = first_non_empty(@page_objects["#{key}-item-offset"], options[:item_offset], 0).to_i
502
+ pages = pages[offset, pages.size] || []
503
+
504
+ # randomize if requested
505
+ randomize = first_non_empty(@page_objects["#{key}-use-randomization"], options[:use_randomization], 'false').to_s == 'true'
506
+ random_pool_size = first_non_empty(@page_objects["#{key}-random-pool-size"], options[:random_pool_size], '').to_i
507
+ if randomize
508
+ if random_pool_size > 0
509
+ pages = pages.first(random_pool_size)
510
+ end
511
+
512
+ n = pages.length
513
+ for i in 0...n
514
+ r = rand(n-1).floor
515
+ pages[r], pages[i] = pages[i], pages[r]
516
+ end
517
+ end
518
+
519
+ pages
520
+ end
521
+
522
+ def substitute_placeholders(html, page, extra_attributes = {})
523
+ return html unless page
524
+
525
+ temp = html.dup
526
+
527
+ # mangle anything inside of an insert_object so that it won't be caught (yet)
528
+ temp.gsub!(/(insert_object\()((?:\(.*?\)|[^()]*?)*)(\))/) do |match|
529
+ one, two, three = $1, $2, $3
530
+ one + two.gsub(/<#/, '<!#') + three
531
+ end
532
+
533
+ # first, extras passed in args
534
+ extra_attributes.each do |k,v|
535
+ temp.gsub!(/<#\s*#{k.to_s}\s*#>/, v.to_s)
536
+ end
537
+
538
+ # next, page object attributes and template options (from page properties)
539
+ page.objects.find(:all, :conditions => [ "obj_type = 'attribute'" ]).each do |obj|
540
+ temp.gsub!(/<#\s*#{obj.name}\s*#>/, (obj.content || '').to_s)
541
+ end
542
+ page.objects.find(:all, :conditions => [ "obj_type = 'option'" ]).each do |obj|
543
+ temp.gsub!(/<#\s*option_#{obj.name.gsub(/[^\w\d]/, '_')}\s*#>/, obj.content || '')
544
+ end
545
+
546
+ # path is kind of a special case, we like to see it with a leading /
547
+ temp.gsub!(/<#\s*path\s*#>/, '/' + (page.path || ''))
548
+
549
+ # substitute tags in a helpful way
550
+ temp.gsub!(/<#\s*tags\s*#>/, page.tags.map { |t| t.name }.join(', '))
551
+ temp.gsub!(/<#\s*tags_as_css_classes\s*#>/, page.tags_as_css_classes)
552
+
553
+ # use full date/time format for created_on and updated_on
554
+ temp.gsub!(/<#\s*created_on\s*#>/, "#{page.created_on.getlocal.strftime('%a')} #{date_to_str(page.created_on)} #{time_to_str(page.created_on)}") if page.created_on
555
+ temp.gsub!(/<#\s*updated_on\s*#>/, "#{page.updated_on.getlocal.strftime('%a')} #{date_to_str(page.updated_on)} #{time_to_str(page.updated_on)}") if page.updated_on
556
+
557
+ # handle any custom substitutions
558
+ temp = substitute_placeholders_custom(temp, page)
559
+
560
+ # finally, toss in the rest of the generic class attributes
561
+ (page.attributes.map { |c| c.first } +
562
+ [ 'article_date_month', 'article_date_mon', 'article_date_day', 'article_date_year', 'article_date_yr' ]).each do |attr|
563
+ begin
564
+ val = page.send(attr.downcase.underscore)
565
+ case val.class.to_s
566
+ when 'String'
567
+ val
568
+ when 'Time'
569
+ val = val.strftime("(%a) ") + val.strftime("%B ") + val.day.to_s + val.strftime(", %Y")
570
+ when 'NilClass'
571
+ val = ''
572
+ else
573
+ # logger.error "#{attr} (#{val.class}): #{val}"
574
+ end
575
+ rescue
576
+ # val = '<!-- attribute not found -->'
577
+ val = ''
578
+ end
579
+ temp.gsub!(/<#\s*#{attr}\s*#>/, val.to_s)
580
+ end
581
+ # temp.gsub!(/<#\s*(.*?)\s*#>/, "<!-- attribute not found -->")
582
+ temp.gsub!(/<#\s*(.*?)\s*#>/, '')
583
+
584
+ # unmangle mangled stuff
585
+ temp.gsub!(/(insert_object\()((?:\(.*?\)|[^()]*?)*)(\))/) do |match|
586
+ one, two, three = $1, $2, $3
587
+ one + two.gsub(/<!#/, '<#') + three
588
+ end
589
+
590
+ temp.html_safe
591
+ end
592
+
593
+ # override this method to do your own custom subtitutions
594
+ def substitute_placeholders_custom(temp, page)
595
+ # an example:
596
+ # begin
597
+ # temp.gsub!(/<#\s*upcoming_event_date\s*#>/, page.article_date.strftime("<span class=\"month\">%b</span><span class=\"day\">%d</span>"))
598
+ # rescue
599
+ # end
600
+
601
+ # remember to return your modified copy of temp
602
+ temp
603
+ end
604
+
605
+
606
+ def template_option(name, type = :string)
607
+ return nil unless @pg
608
+
609
+ @template_options ||= {}
610
+ @template_options[name] = type
611
+
612
+ key = name.gsub(/[^\w\d]/, '_')
613
+ obj = @pg.objects.find_by_name("#{type}-#{key}", :conditions => [ "obj_type = 'option'" ])
614
+ return nil unless obj
615
+
616
+ case type
617
+ when :checkbox
618
+ obj.content == "1"
619
+ else
620
+ obj.content
621
+ end
622
+ end
623
+
624
+
625
+ def breadcrumbs(options = {})
626
+ # only works on CCS pages
627
+ if @pg
628
+ separator = options.delete(:separator) || ' &raquo; '
629
+ link_class = options.delete(:link_class)
630
+
631
+ pg = @pg
632
+ ret = pg.title
633
+
634
+ while pg = pg.parent
635
+ if pg.published_version >= 0
636
+ ret = "<a href=\"/#{pg.path}\" class=\"#{link_class}\">#{pg.title}</a>" + separator + ret
637
+ end
638
+ end
639
+
640
+ return ret
641
+ else
642
+ return ''
643
+ end
644
+ end
645
+
3
646
  # Get an array of all times, useful in select's (5 minute interval by default)
4
647
  def all_times_array(interval = 5)
5
648
  a = []
6
649
  (0..23).each do |h|
7
650
  (0..59).each do |m|
8
651
  next unless m % interval == 0
9
- t = Time.mktime(2000, 1, 1, h, m)
652
+ t = Time.utc(2000, 1, 1, h, m)
10
653
  a << t.strftime("%I").to_i.to_s + t.strftime(":%M%p").downcase
11
654
  end
12
655
  end
@@ -41,11 +684,11 @@ module CmsApplicationHelper
41
684
  if errors.size > 0
42
685
  ret << " title=\"#{h errors.join('; ')}\""
43
686
  end
44
- ret << '><img src="/images/interface/form_error.gif" width="17" height="17" border="0" />'
687
+ ret << '><img src="/assets/interface/form_error.gif" width="17" height="17" border="0" />'
45
688
  ret << '</div>'
46
689
 
47
690
  ret << "<div id=\"#{object_name}_#{method_name}_loading\" class=\"form-loading\" style=\"display: none;\">"
48
- ret << "<img src=\"/images/interface/form_loading.gif\" width=\"16\" height=\"16\" border=\"0\" style=\"margin: 0 1px 1px 0;\" />"
691
+ ret << "<img src=\"/assets/interface/form_loading.gif\" width=\"16\" height=\"16\" border=\"0\" style=\"margin: 0 1px 1px 0;\" />"
49
692
  ret << "</div>"
50
693
 
51
694
  if errors.size > 0 && options[:display_messages]
@@ -78,10 +721,10 @@ module CmsApplicationHelper
78
721
  def flash_message
79
722
  output = ''.html_safe
80
723
  if (flash[:error] || @error || '') != ''
81
- output << content_tag('div', :class => 'alert alert-error') { flash[:error] || @error }
724
+ output << content_tag('div', :class => 'alert alert-error error') { flash[:error] || @error }
82
725
  end
83
726
  if (flash[:notice] || @notice || '') != ''
84
- output << content_tag('div', :class => 'alert alert-info') { flash[:notice] || @notice }
727
+ output << content_tag('div', :class => 'alert alert-info notice') { flash[:notice] || @notice }
85
728
  end
86
729
  output
87
730
  end
@@ -151,14 +794,17 @@ module CmsApplicationHelper
151
794
 
152
795
  # Creates a mailto: link that is encoded to prevent most harvesting attempts.
153
796
  def encoded_mail_to(email, link_text = nil)
797
+ email = h(email)
154
798
  url = ''
155
799
  text = ''
156
- email.length.times do |i|
157
- url << (i % 2 == 0 ? sprintf("%%%x", email[i]) : email[i])
158
- text << (i % 4 == 0 ? '<span>' << email[i] << '</span>' : email[i])
800
+
801
+ # this only works with ascii, but email addresses are supposed to be ascii
802
+ email.bytes.to_a.each_with_index do |b, i|
803
+ url << (i % 2 == 0 ? sprintf("%%%x", b) : b)
804
+ text << (i % 4 == 0 ? '<span>' << b << '</span>' : b)
159
805
  end
160
806
 
161
- "<a href=\"mailto:#{url}\">#{link_text || text}</a>"
807
+ "<a href=\"mailto:#{url}\">#{link_text || text}</a>".html_safe
162
808
  end
163
809
 
164
810
  # Display a date picker with an ajax calendar.
@@ -221,18 +867,18 @@ module CmsApplicationHelper
221
867
 
222
868
  ret = <<EOF
223
869
  <span><a href="#" onclick="showDatePicker('#{object}', '#{method_prefix}'); return false;"><span id="date_picker_#{object}_#{method_prefix}_value">#{default_value.strftime('%a %m/%d/%y')}</span></a></span>
224
- <span id="date_picker_#{object}_#{method_prefix}icon"><a href="#" onclick="showDatePicker('#{object}', '#{method_prefix}'); return false;"><img src="/images/interface/icon_time.gif" style="float: none" alt="date picker" /></a></span>
870
+ <span id="date_picker_#{object}_#{method_prefix}icon"><a href="#" onclick="showDatePicker('#{object}', '#{method_prefix}'); return false;"><img src="/assets/interface/icon_time.gif" style="float: none" alt="date picker" /></a></span>
225
871
  <div id="date_picker_#{object}_#{method_prefix}main" style="display: none; background-color: white; border: 1px solid gray; padding: 3px; z-index: 101;" class="date-picker-main">
226
872
  <table width="190">
227
873
  <tr>
228
- <td><a href="#" onclick="dpPrevMonth('#{object}', '#{method_prefix}', #{min_year}); #{h(draw_calendar)}; return false;"><img src="/images/interface/arrow_previous.gif" border="0" alt="Previous" style="float: left; padding: 2px 0 0 6px; margin: 0;" /></a></td>
874
+ <td><a href="#" onclick="dpPrevMonth('#{object}', '#{method_prefix}', #{min_year}); #{h(draw_calendar)}; return false;"><img src="/assets/interface/arrow_previous.gif" border="0" alt="Previous" style="float: left; padding: 2px 0 0 6px; margin: 0;" /></a></td>
229
875
  <td colspan="5" align="center">
230
876
  <nobr>
231
877
  #{ select_tag object + '_' + method_prefix + '_month_sel', options_for_select(months_hash, default_value.month.to_s), :class => 'form', :style => 'border: 1px solid gray; font-size: 11px; padding: 0; margin: 0;', :onchange => h(draw_calendar) }
232
878
  #{ select_tag object + '_' + method_prefix + '_year_sel', options_for_select((min_year..max_year).to_a, default_value.year), :class => 'form', :style => 'border: 1px solid gray; font-size: 11px; padding: 0; margin: 0;', :onchange => h(draw_calendar) }
233
879
  </nobr>
234
880
  </td>
235
- <td><a href="#" onclick="dpNextMonth('#{object}', '#{method_prefix}', '#{max_year}'); #{h(draw_calendar)}; return false;"><img src="/images/interface/arrow_next.gif" border="0" alt="Next" style="float: right; padding: 2px 6px 0 0; margin: 0;" /></a></td>
881
+ <td><a href="#" onclick="dpNextMonth('#{object}', '#{method_prefix}', '#{max_year}'); #{h(draw_calendar)}; return false;"><img src="/assets/interface/arrow_next.gif" border="0" alt="Next" style="float: right; padding: 2px 6px 0 0; margin: 0;" /></a></td>
236
882
  </tr>
237
883
  </table>
238
884
  <div id="date_picker_#{object}_#{method_prefix}_days" class="date-picker-days"></div>
@@ -245,6 +891,7 @@ module CmsApplicationHelper
245
891
  </div>
246
892
  EOF
247
893
  ret += javascript_tag(draw_calendar)
894
+ ret.html_safe
248
895
  end
249
896
 
250
897
  # Display a clickable ajax event calendar.
@@ -290,7 +937,7 @@ EOF
290
937
  @css_prefix = css_prefix
291
938
  @popout_direction = popout_direction
292
939
 
293
- first_of_month = Time.mktime(@year, @month, 1)
940
+ first_of_month = Time.utc(@year, @month, 1)
294
941
  last_of_month = first_of_month.end_of_month
295
942
  events = @calendar.events.find(:all, :conditions => [ 'start_date >= ? and start_date <= ?', first_of_month, last_of_month ])
296
943
 
@@ -305,7 +952,7 @@ EOF
305
952
  <td class="#{css_prefix}container">
306
953
  <table class="#{css_prefix}head" cellspacing="0" cellpadding="0" border="0">
307
954
  <tr class="#{css_prefix}head">
308
- <td class="#{css_prefix}head #{css_prefix}head_prev_month"><a href="#" onclick="dpPrevMonth('event', 'calendar', #{min_year}); #{draw_calendar}; return false;"><img src="/images/interface/arrow_previous.gif" border="0" alt="Previous" style="float: left; padding-left: 2px;" /></a></td>
955
+ <td class="#{css_prefix}head #{css_prefix}head_prev_month"><a href="#" onclick="dpPrevMonth('event', 'calendar', #{min_year}); #{draw_calendar}; return false;"><img src="/assets/interface/arrow_previous.gif" border="0" alt="Previous" style="float: left; padding-left: 2px;" /></a></td>
309
956
  <td class="#{css_prefix}head #{css_prefix}head_month_select">
310
957
  <div#{options[:show_selects] ? '' : ' style="display: none"'}>
311
958
  #{ select 'event_calendar', 'month_sel', months_hash, { :selected => Time.now.month.to_s }, :class => 'form', :style => 'font-size: 11px;', :onchange => draw_calendar }
@@ -315,7 +962,7 @@ EOF
315
962
  #{render '/util/_calendar_month_year'}
316
963
  </div>
317
964
  </td>
318
- <td class="#{css_prefix}head #{css_prefix}head_next_month"><a href="#" onclick="dpNextMonth('event', 'calendar', '#{max_year}'); #{draw_calendar}; return false;"><img src="/images/interface/arrow_next.gif" border="0" alt="Next" style="float: right; padding-right: 2px;" /></a></td>
965
+ <td class="#{css_prefix}head #{css_prefix}head_next_month"><a href="#" onclick="dpNextMonth('event', 'calendar', '#{max_year}'); #{draw_calendar}; return false;"><img src="/assets/interface/arrow_next.gif" border="0" alt="Next" style="float: right; padding-right: 2px;" /></a></td>
319
966
  </tr>
320
967
  </table>
321
968
  </td>