imagine_cms 3.0.0.beta6 → 3.0.0.beta7

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 (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>