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
@@ -0,0 +1,297 @@
1
+ if ENV['RAILS_ROOT']
2
+ environment = File.expand_path('vendor/gems/environment', ENV['RAILS_ROOT'])
3
+ require environment if File.exist?("#{environment}.rb")
4
+ end
5
+
6
+ $:.unshift File.expand_path('../../lib', __FILE__)
7
+
8
+ require 'test/unit'
9
+ require 'action_view'
10
+ require 'action_controller'
11
+ require 'active_model'
12
+ require 'prototype_helper'
13
+
14
+ class Bunny < Struct.new(:Bunny, :id)
15
+ end
16
+
17
+ class Author
18
+ extend ActiveModel::Naming
19
+
20
+ attr_reader :id
21
+ def save; @id = 1 end
22
+ def new_record?; @id.nil? end
23
+ def name
24
+ @id.nil? ? 'new author' : "author ##{@id}"
25
+ end
26
+ end
27
+
28
+ class Article
29
+ extend ActiveModel::Naming
30
+
31
+ attr_reader :id
32
+ attr_reader :author_id
33
+ def save; @id = 1; @author_id = 1 end
34
+ def new_record?; @id.nil? end
35
+ def name
36
+ @id.nil? ? 'new article' : "article ##{@id}"
37
+ end
38
+ end
39
+
40
+ class Author::Nested < Author; end
41
+
42
+ class PrototypeHelperTest < ActionView::TestCase
43
+ attr_accessor :formats, :output_buffer, :template_format
44
+
45
+ def _evaluate_assigns_and_ivars() end
46
+
47
+ def reset_formats(format)
48
+ @format = format
49
+ end
50
+
51
+ def setup
52
+ @record = @author = Author.new
53
+ @article = Article.new
54
+ super
55
+ @template = self
56
+ @controller = Class.new do
57
+ def url_for(options)
58
+ if options.is_a?(String)
59
+ options
60
+ else
61
+ url = "http://www.example.com/"
62
+ url << options[:action].to_s if options and options[:action]
63
+ url << "?a=#{options[:a]}" if options && options[:a]
64
+ url << "&b=#{options[:b]}" if options && options[:a] && options[:b]
65
+ url
66
+ end
67
+ end
68
+ end.new
69
+ end
70
+
71
+
72
+ def test_observe_form
73
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {new Ajax.Request('http://www.example.com/cart_changed', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
74
+ observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" })
75
+ end
76
+
77
+ def test_observe_form_using_function_for_callback
78
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {alert('Form changed')})\n//]]>\n</script>),
79
+ observe_form("cart", :frequency => 2, :function => "alert('Form changed')")
80
+ end
81
+
82
+ def test_observe_field
83
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/reorder_if_empty', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
84
+ observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" })
85
+ end
86
+
87
+ def test_observe_field_using_with_option
88
+ expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(value)})})\n//]]>\n</script>)
89
+ assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id')
90
+ assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)")
91
+ end
92
+
93
+ def test_observe_field_using_json_in_with_option
94
+ expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:{'id':value}})})\n//]]>\n</script>)
95
+ assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
96
+ end
97
+
98
+ def test_observe_field_using_function_for_callback
99
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {alert('Element changed')})\n//]]>\n</script>),
100
+ observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')")
101
+ end
102
+
103
+ def test_observe_field_without_frequency
104
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.EventObserver('glass', function(element, value) {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
105
+ observe_field("glass")
106
+ end
107
+
108
+
109
+ def test_periodically_call_remote
110
+ assert_dom_equal %(<script type="text/javascript">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Updater('schremser_bier', 'http://www.example.com/mehr_bier', {asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>),
111
+ periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" })
112
+ end
113
+
114
+ def test_periodically_call_remote_with_frequency
115
+ assert_dom_equal(
116
+ "<script type=\"text/javascript\">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true})}, 2)\n//]]>\n</script>",
117
+ periodically_call_remote(:frequency => 2)
118
+ )
119
+ end
120
+
121
+
122
+ def test_form_remote_tag
123
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
124
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast })
125
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
126
+ form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast })
127
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
128
+ form_remote_tag(:update => { :failure => "glass_of_water" }, :url => { :action => :fast })
129
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
130
+ form_remote_tag(:update => { :success => 'glass_of_beer', :failure => "glass_of_water" }, :url => { :action => :fast })
131
+ end
132
+
133
+ def test_form_remote_tag_with_method
134
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div>),
135
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put })
136
+ end
137
+
138
+ def test_form_remote_tag_with_block_in_erb
139
+ __in_erb_template = ''
140
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" }
141
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), output_buffer
142
+ end
143
+
144
+ def test_on_callbacks
145
+ callbacks = [:uninitialized, :loading, :loaded, :interactive, :complete, :success, :failure]
146
+ callbacks.each do |callback|
147
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
148
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
149
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
150
+ form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();")
151
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({failure:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
152
+ form_remote_tag(:update => { :failure => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();")
153
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
154
+ form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();")
155
+ end
156
+
157
+ #HTTP status codes 200 up to 599 have callbacks
158
+ #these should work
159
+ 100.upto(599) do |callback|
160
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
161
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
162
+ end
163
+
164
+ #test 200 and 404
165
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, parameters:Form.serialize(this)}); return false;">),
166
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();")
167
+
168
+ #these shouldn't
169
+ 1.upto(99) do |callback|
170
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
171
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
172
+ end
173
+ 600.upto(999) do |callback|
174
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
175
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
176
+ end
177
+
178
+ #test ultimate combo
179
+ assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, onComplete:function(request){c();}, onFailure:function(request){f();}, onLoading:function(request){c1()}, onSuccess:function(request){s()}, parameters:Form.serialize(this)}); return false;\">),
180
+ form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();")
181
+ end
182
+
183
+ def test_remote_form_for_with_record_identification_with_new_record
184
+ remote_form_for(@record, {:html => { :id => 'create-author' }}) {}
185
+
186
+ expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' id='create-author' method='post'></form>)
187
+ assert_dom_equal expected, output_buffer
188
+ end
189
+
190
+ def test_remote_form_for_with_record_identification_without_html_options
191
+ remote_form_for(@record) {}
192
+
193
+ expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' method='post' id='new_author'></form>)
194
+ assert_dom_equal expected, output_buffer
195
+ end
196
+
197
+ def test_remote_form_for_with_record_identification_with_existing_record
198
+ @record.save
199
+ remote_form_for(@record) {}
200
+
201
+ expected = %(<form action='#{author_path(@record)}' id='edit_author_1' method='post' onsubmit="new Ajax.Request('#{author_path(@record)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_author'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>)
202
+ assert_dom_equal expected, output_buffer
203
+ end
204
+
205
+ def test_remote_form_for_with_new_object_in_list
206
+ remote_form_for([@author, @article]) {}
207
+
208
+ expected = %(<form action='#{author_articles_path(@author)}' onsubmit="new Ajax.Request('#{author_articles_path(@author)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_article' method='post' id='new_article'></form>)
209
+ assert_dom_equal expected, output_buffer
210
+ end
211
+
212
+ def test_remote_form_for_with_existing_object_in_list
213
+ @author.save
214
+ @article.save
215
+ remote_form_for([@author, @article]) {}
216
+
217
+ expected = %(<form action='#{author_article_path(@author, @article)}' id='edit_article_1' method='post' onsubmit="new Ajax.Request('#{author_article_path(@author, @article)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_article'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>)
218
+ assert_dom_equal expected, output_buffer
219
+ end
220
+
221
+
222
+ def test_button_to_remote
223
+ assert_dom_equal %(<input class=\"fine\" type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true});\" />),
224
+ button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" })
225
+ assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.reponseText)}});\" />),
226
+ button_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot" })
227
+ assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.reponseText)}});\" />),
228
+ button_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot" })
229
+ assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />),
230
+ button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot" })
231
+ assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />),
232
+ button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
233
+ end
234
+
235
+ def test_submit_to_remote
236
+ assert_dom_equal %(<input name=\"More beer!\" onclick=\"new Ajax.Updater('empty_bottle', 'http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});\" type=\"button\" value=\"1000000\" />),
237
+ submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle")
238
+ end
239
+
240
+
241
+ def test_link_to_remote
242
+ assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
243
+ link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" })
244
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
245
+ link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
246
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
247
+ link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" })
248
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
249
+ link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot" })
250
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
251
+ link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
252
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:false, evalScripts:true}); return false;\">Remote outauthor</a>),
253
+ link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :type => :synchronous)
254
+ assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, insertion:'bottom'}); return false;\">Remote outauthor</a>),
255
+ link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom)
256
+ end
257
+
258
+ def test_link_to_remote_html_options
259
+ assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
260
+ link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } })
261
+ end
262
+
263
+ def test_link_to_remote_url_quote_escaping
264
+ assert_dom_equal %(<a href="#" onclick="new Ajax.Request('http://www.example.com/whatnot\\\'s', {asynchronous:true, evalScripts:true}); return false;">Remote</a>),
265
+ link_to_remote("Remote", { :url => { :action => "whatnot's" } })
266
+ end
267
+
268
+ protected
269
+ def request_forgery_protection_token
270
+ nil
271
+ end
272
+
273
+ def protect_against_forgery?
274
+ false
275
+ end
276
+
277
+ def create_generator
278
+ block = Proc.new { |*args| yield *args if block_given? }
279
+ JavaScriptGenerator.new self, &block
280
+ end
281
+
282
+ def author_path(record)
283
+ "/authors/#{record.id}"
284
+ end
285
+
286
+ def authors_path
287
+ "/authors"
288
+ end
289
+
290
+ def author_articles_path(author)
291
+ "/authors/#{author.id}/articles"
292
+ end
293
+
294
+ def author_article_path(author, article)
295
+ "/authors/#{author.id}/articles/#{article.id}"
296
+ end
297
+ end
@@ -0,0 +1,5 @@
1
+ *SVN*
2
+
3
+ * Make Upload Progress work with edge Rails [4388] and higher, retain compatibility to earlier builds
4
+
5
+ * Make Upload Progress work with edge Rails [3526] and higher, retain compatibility to earlier builds
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2004 Sean Treadway, Thomas Fuchs
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,45 @@
1
+ =Overview
2
+
3
+ The upload progress plugin will alter your rails CGI handling to track the uploaded status of multipart/form encoded posts. The plugin will also add helper methods to create an AJAX updating progress bar.
4
+
5
+ ==Installing
6
+
7
+ Run "script/plugin upload_progress" or checkout the source into your plugins folder.
8
+
9
+ svn checkout http://dev.rubyonrails.com/svn/plugins/upload_progress
10
+
11
+ Expand this archive in your Rails.root/vendor/plugins directory. The resulting plugin directory should look like:
12
+
13
+ Rails.root/vendor/plugins/upload_progress/
14
+ Rails.root/vendor/plugins/upload_progress/README.txt
15
+ Rails.root/vendor/plugins/upload_progress/Rakefile
16
+ Rails.root/vendor/plugins/upload_progress/init.rb
17
+ Rails.root/vendor/plugins/upload_progress/public/
18
+ Rails.root/vendor/plugins/upload_progress/public/stylesheets/
19
+ Rails.root/vendor/plugins/upload_progress/public/stylesheets/upload_progress.css
20
+ Rails.root/vendor/plugins/upload_progress/lib/
21
+ Rails.root/vendor/plugins/upload_progress/doc/
22
+ Rails.root/vendor/plugins/upload_progress/test/
23
+
24
+ The stylesheets included in public/stylesheets are used as a guideline for styling your progress bar and status messages. You can copy them directly into your own public/stylesheets folder or copy and paste.
25
+
26
+ ==Documentation
27
+
28
+ You can create the documentation by running:
29
+
30
+ rake rdoc
31
+
32
+ ==Requirements
33
+
34
+ The requirments for getting periodic upload progress updates can be found here:
35
+
36
+ http://sean.treadway.info/articles/2005/07/18/upload-progress-checklist
37
+
38
+ ==Credits
39
+
40
+ Sean Treadway <seant@superchannel.org> http://sean.treadway.info
41
+ Thomas Fuchs <thomas@fesch.at> http://mir.aculo.us
42
+
43
+ ==License
44
+
45
+ This plugin is released under the MIT license. See MIT-LICENSE for details
@@ -5,18 +5,19 @@ require 'rake/rdoctask'
5
5
  desc 'Default: run unit tests.'
6
6
  task :default => :test
7
7
 
8
- desc 'Test acts_as_tree plugin.'
8
+ desc 'Test the upload progress plugin.'
9
9
  Rake::TestTask.new(:test) do |t|
10
10
  t.libs << 'lib'
11
11
  t.pattern = 'test/**/*_test.rb'
12
12
  t.verbose = true
13
13
  end
14
14
 
15
- desc 'Generate documentation for acts_as_tree plugin.'
15
+ desc 'Generate documentation for the upload progress plugin.'
16
16
  Rake::RDocTask.new(:rdoc) do |rdoc|
17
17
  rdoc.rdoc_dir = 'rdoc'
18
- rdoc.title = 'acts_as_tree'
19
- rdoc.options << '--line-numbers' << '--inline-source'
20
- rdoc.rdoc_files.include('README')
18
+ rdoc.title = 'Upload progress'
19
+ rdoc.options << '--line-numbers --inline-source'
20
+ rdoc.rdoc_files.include('README.txt')
21
21
  rdoc.rdoc_files.include('lib/**/*.rb')
22
22
  end
23
+
@@ -0,0 +1,7 @@
1
+ require 'multipart_progress'
2
+ require 'progress'
3
+ require 'upload_progress'
4
+ require 'upload_progress_helper'
5
+
6
+ ActionController::Base.send(:include, UploadProgress)
7
+ ActionView::Base.send(:include, UploadProgress::UploadProgressHelper)
@@ -0,0 +1,176 @@
1
+ # == Overview
2
+ #
3
+ # This module will extend the CGI module with methods to track the upload
4
+ # progress for multipart forms for use with progress meters. The progress is
5
+ # saved in the session to be used from any request from any server with the
6
+ # same session. In other words, this module will work across application
7
+ # instances.
8
+ #
9
+ # === Usage
10
+ #
11
+ # Just do your file-uploads as you normally would, but include an upload_id in
12
+ # the query string of your form action. Your form post action should look
13
+ # like:
14
+ #
15
+ # <form method="post" enctype="multipart/form-data" action="postaction?upload_id=SOMEIDYOUSET">
16
+ # <input type="file" name="client_file"/>
17
+ # </form>
18
+ #
19
+ # Query the upload state in a progress by reading the progress from the session
20
+ #
21
+ # class UploadController < ApplicationController
22
+ # def upload_status
23
+ # render :text => "Percent complete: " + @session[:uploads]['SOMEIDYOUSET'].completed_percent"
24
+ # end
25
+ # end
26
+ #
27
+ # === Session options
28
+ #
29
+ # Upload progress uses the session options defined in
30
+ # ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS. If you are passing
31
+ # custom session options to your dispatcher then please follow the
32
+ # "recommended way to change session options":http://wiki.rubyonrails.com/rails/show/HowtoChangeSessionOptions
33
+ #
34
+ # === Update frequency
35
+ #
36
+ # During an upload, the progress will be written to the session every 2
37
+ # seconds. This prevents excessive writes yet maintains a decent picture of
38
+ # the upload progress for larger files.
39
+ #
40
+ # User interfaces that update more often that every 2 seconds will display the same results.
41
+ # Consider this update frequency when designing your progress polling.
42
+ #
43
+
44
+ require 'cgi'
45
+
46
+ class CGI #:nodoc:
47
+ class ProgressIO < SimpleDelegator #:nodoc:
48
+ MIN_SAVE_INTERVAL = 1.0 # Number of seconds between session saves
49
+
50
+ attr_reader :progress, :session
51
+
52
+ def initialize(orig_io, progress, session)
53
+ @session = session
54
+ @progress = progress
55
+
56
+ @start_time = Time.now
57
+ @last_save_time = @start_time
58
+ save_progress
59
+
60
+ super(orig_io)
61
+ end
62
+
63
+ def read(*args)
64
+ data = __getobj__.read(*args)
65
+
66
+ if data and data.size > 0
67
+ now = Time.now
68
+ elapsed = now - @start_time
69
+ progress.update!(data.size, elapsed)
70
+
71
+ if now - @last_save_time > MIN_SAVE_INTERVAL
72
+ save_progress
73
+ @last_save_time = now
74
+ end
75
+ else
76
+ ActionController::Base.logger.debug("CGI::ProgressIO#read returns nothing when it should return nil if IO is finished: [#{args.inspect}], a cancelled upload or old FCGI bindings. Resetting the upload progress")
77
+
78
+ progress.reset!
79
+ save_progress
80
+ end
81
+
82
+ data
83
+ end
84
+
85
+ def save_progress
86
+ @session.update
87
+ end
88
+
89
+ def finish
90
+ @session.update
91
+ ActionController::Base.logger.debug("Finished processing multipart upload in #{@progress.elapsed_seconds.to_s}s")
92
+ end
93
+ end
94
+
95
+ module QueryExtension #:nodoc:
96
+ # Need to do lazy aliasing on the instance that we are extending because of the way QueryExtension
97
+ # gets included for each instance of the CGI object rather than on a module level. This method is a
98
+ # bit obtrusive because we are overriding CGI::QueryExtension::extended which could be used in the
99
+ # future. Need to research a better method
100
+ def self.extended(obj)
101
+ obj.instance_eval do
102
+ # unless defined? will prevent clobbering the progress IO on multiple extensions
103
+ alias :stdinput_without_progress :stdinput unless defined? stdinput_without_progress
104
+ alias :stdinput :stdinput_with_progress
105
+ end
106
+ end
107
+
108
+ def stdinput_with_progress
109
+ @stdin_with_progress or stdinput_without_progress
110
+ end
111
+
112
+ private
113
+ # Bootstrapped on UploadProgress::upload_status_for
114
+ def read_multipart_with_progress(boundary, content_length)
115
+ begin
116
+ begin
117
+ # Session disabled if the default session options have been set to 'false'
118
+ options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS
119
+ raise RuntimeError.new("Multipart upload progress disabled, no session options") unless options
120
+
121
+ options = options.stringify_keys
122
+
123
+ # Pull in the application controller to satisfy any dependencies on class definitions
124
+ # of instances stored in the session.
125
+ # Be sure to stay compatible with Rails 1.0/const_load!
126
+ if Object.const_defined?(:Controllers) and Controllers.respond_to?(:const_load!)
127
+ Controllers.const_load!(:ApplicationController, "application") unless Controllers.const_defined?(:ApplicationController)
128
+ else
129
+ require_dependency('application.rb') unless Object.const_defined?(:ApplicationController)
130
+ end
131
+
132
+ # Assumes that @cookies has already been setup
133
+ # Raises nomethod if upload_id is not defined
134
+ @params = CGI::parse(read_params_from_query)
135
+ upload_id = @params[(options['upload_key'] || 'upload_id')].first
136
+ raise RuntimeError.new("Multipart upload progress disabled, no upload id in query string") unless upload_id
137
+
138
+ upload_progress = UploadProgress::Progress.new(content_length)
139
+
140
+ session = Session.new(self, options)
141
+ session[:uploads] = {} unless session[:uploads]
142
+ session[:uploads].delete(upload_id) # in case the same upload id is used twice
143
+ session[:uploads][upload_id] = upload_progress
144
+
145
+ @stdin_with_progress = CGI::ProgressIO.new(stdinput_without_progress, upload_progress, session)
146
+ ActionController::Base.logger.debug("Multipart upload with progress (id: #{upload_id}, size: #{content_length})")
147
+ rescue
148
+ ActionController::Base.logger.debug("Exception during setup of read_multipart_with_progress: #{$!}")
149
+ end
150
+ ensure
151
+ begin
152
+ params = read_multipart_without_progress(boundary, content_length)
153
+ @stdin_with_progress.finish if @stdin_with_progress.respond_to? :finish
154
+ ensure
155
+ @stdin_with_progress = nil
156
+ session.close if session
157
+ end
158
+ end
159
+ params
160
+ end
161
+
162
+ # Required because of changes in [4388]
163
+ unless private_instance_methods.include?("read_params_from_query")
164
+ def read_params_from_query
165
+ read_params(:get,nil)
166
+ end
167
+ end
168
+
169
+ # Prevent redefinition of aliases on multiple includes
170
+ unless private_instance_methods.include?("read_multipart_without_progress")
171
+ alias_method :read_multipart_without_progress, :read_multipart
172
+ alias_method :read_multipart, :read_multipart_with_progress
173
+ end
174
+
175
+ end
176
+ end