zena 0.15.0

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 (1826) hide show
  1. data/History.txt +18 -0
  2. data/README.txt +133 -0
  3. data/app/controllers/application_controller.rb +3 -0
  4. data/app/controllers/comments_controller.rb +141 -0
  5. data/app/controllers/data_entries_controller.rb +81 -0
  6. data/app/controllers/discussions_controller.rb +48 -0
  7. data/app/controllers/documents_controller.rb +136 -0
  8. data/app/controllers/groups_controller.rb +99 -0
  9. data/app/controllers/iformats_controller.rb +78 -0
  10. data/app/controllers/links_controller.rb +98 -0
  11. data/app/controllers/nodes_controller.rb +497 -0
  12. data/app/controllers/preferences_controller.rb +52 -0
  13. data/app/controllers/relations_controller.rb +95 -0
  14. data/app/controllers/sessions_controller.rb +41 -0
  15. data/app/controllers/sites_controller.rb +112 -0
  16. data/app/controllers/users_controller.rb +139 -0
  17. data/app/controllers/versions_controller.rb +268 -0
  18. data/app/controllers/virtual_classes_controller.rb +95 -0
  19. data/app/helpers/application_helper.rb +4 -0
  20. data/app/helpers/documents_helper.rb +13 -0
  21. data/app/helpers/nodes_helper.rb +20 -0
  22. data/app/helpers/versions_helper.rb +18 -0
  23. data/app/models/book.rb +242 -0
  24. data/app/models/cache.rb +52 -0
  25. data/app/models/cached_page.rb +134 -0
  26. data/app/models/comment.rb +125 -0
  27. data/app/models/contact.rb +32 -0
  28. data/app/models/contact_content.rb +70 -0
  29. data/app/models/contact_version.rb +40 -0
  30. data/app/models/data_entry.rb +162 -0
  31. data/app/models/discussion.rb +65 -0
  32. data/app/models/document.rb +146 -0
  33. data/app/models/document_content.rb +186 -0
  34. data/app/models/document_version.rb +13 -0
  35. data/app/models/dyn_attribute.rb +4 -0
  36. data/app/models/group.rb +142 -0
  37. data/app/models/iformat.rb +146 -0
  38. data/app/models/image.rb +96 -0
  39. data/app/models/image_content.rb +189 -0
  40. data/app/models/image_version.rb +21 -0
  41. data/app/models/link.rb +121 -0
  42. data/app/models/node.rb +1752 -0
  43. data/app/models/note.rb +58 -0
  44. data/app/models/page.rb +53 -0
  45. data/app/models/project.rb +10 -0
  46. data/app/models/reference.rb +18 -0
  47. data/app/models/relation.rb +18 -0
  48. data/app/models/relation_proxy.rb +379 -0
  49. data/app/models/section.rb +5 -0
  50. data/app/models/site.rb +355 -0
  51. data/app/models/skin.rb +20 -0
  52. data/app/models/template.rb +134 -0
  53. data/app/models/template_content.rb +112 -0
  54. data/app/models/template_version.rb +37 -0
  55. data/app/models/text_document.rb +162 -0
  56. data/app/models/text_document_content.rb +46 -0
  57. data/app/models/text_document_version.rb +21 -0
  58. data/app/models/user.rb +412 -0
  59. data/app/models/version.rb +328 -0
  60. data/app/models/virtual_class.rb +134 -0
  61. data/app/models/zip.rb +6 -0
  62. data/app/views/comments/_add.rhtml +6 -0
  63. data/app/views/comments/_bin.rhtml +5 -0
  64. data/app/views/comments/_form.rhtml +26 -0
  65. data/app/views/comments/_li.rhtml +13 -0
  66. data/app/views/comments/_li_simple.rhtml +3 -0
  67. data/app/views/comments/_list.rhtml +13 -0
  68. data/app/views/comments/create.rjs +32 -0
  69. data/app/views/comments/edit.rjs +2 -0
  70. data/app/views/comments/empty_bin.rjs +1 -0
  71. data/app/views/comments/index.rhtml +12 -0
  72. data/app/views/comments/publish.rjs +7 -0
  73. data/app/views/comments/remove.rjs +9 -0
  74. data/app/views/comments/reply_to.rjs +2 -0
  75. data/app/views/comments/update.rjs +1 -0
  76. data/app/views/data_entries/_li.html.erb +9 -0
  77. data/app/views/data_entries/create.rjs +1 -0
  78. data/app/views/data_entries/destroy.rjs +1 -0
  79. data/app/views/data_entries/edit.rjs +1 -0
  80. data/app/views/data_entries/index.html.erb +5 -0
  81. data/app/views/data_entries/show.html.erb +5 -0
  82. data/app/views/data_entries/show.rjs +1 -0
  83. data/app/views/data_entries/update.rjs +1 -0
  84. data/app/views/discussions/_add.rhtml +6 -0
  85. data/app/views/discussions/_form.rhtml +21 -0
  86. data/app/views/discussions/_li.rhtml +9 -0
  87. data/app/views/discussions/_list.rhtml +4 -0
  88. data/app/views/discussions/create.rjs +10 -0
  89. data/app/views/discussions/remove.rjs +7 -0
  90. data/app/views/discussions/show.rjs +1 -0
  91. data/app/views/discussions/update.rjs +2 -0
  92. data/app/views/documents/_crop.rhtml +10 -0
  93. data/app/views/documents/crop_form.rjs +4 -0
  94. data/app/views/documents/new.rhtml +18 -0
  95. data/app/views/documents/show.rhtml +17 -0
  96. data/app/views/groups/_add.rhtml +6 -0
  97. data/app/views/groups/_form.rhtml +44 -0
  98. data/app/views/groups/_li.rhtml +13 -0
  99. data/app/views/groups/create.rjs +8 -0
  100. data/app/views/groups/destroy.rjs +2 -0
  101. data/app/views/groups/edit.html.erb +5 -0
  102. data/app/views/groups/index.rhtml +6 -0
  103. data/app/views/groups/show.html.erb +5 -0
  104. data/app/views/groups/show.rjs +1 -0
  105. data/app/views/iformats/_add.rhtml +6 -0
  106. data/app/views/iformats/_form.rhtml +29 -0
  107. data/app/views/iformats/_li.rhtml +15 -0
  108. data/app/views/iformats/create.rjs +8 -0
  109. data/app/views/iformats/destroy.rjs +11 -0
  110. data/app/views/iformats/edit.html.erb +5 -0
  111. data/app/views/iformats/index.rhtml +7 -0
  112. data/app/views/iformats/show.html.erb +5 -0
  113. data/app/views/iformats/show.rjs +1 -0
  114. data/app/views/iformats/update.rjs +5 -0
  115. data/app/views/image/_title.rhtml +8 -0
  116. data/app/views/links/_add.rhtml +6 -0
  117. data/app/views/links/_form.rhtml +34 -0
  118. data/app/views/links/_li.rhtml +7 -0
  119. data/app/views/links/_list.rhtml +9 -0
  120. data/app/views/links/create.rjs +5 -0
  121. data/app/views/links/destroy.rjs +11 -0
  122. data/app/views/links/show.rjs +5 -0
  123. data/app/views/nodes/404.html +15 -0
  124. data/app/views/nodes/500.html +15 -0
  125. data/app/views/nodes/_dates.rhtml +13 -0
  126. data/app/views/nodes/_edit_attribute.rhtml +32 -0
  127. data/app/views/nodes/_gallery.rhtml +16 -0
  128. data/app/views/nodes/_groups.rhtml +25 -0
  129. data/app/views/nodes/_import_results.rhtml +20 -0
  130. data/app/views/nodes/_list_nodes.rhtml +9 -0
  131. data/app/views/nodes/_parent.rhtml +15 -0
  132. data/app/views/nodes/_position.rhtml +22 -0
  133. data/app/views/nodes/_results.rhtml +29 -0
  134. data/app/views/nodes/_show_attr.rhtml +6 -0
  135. data/app/views/nodes/_table.rhtml +14 -0
  136. data/app/views/nodes/clear_order.rjs +7 -0
  137. data/app/views/nodes/create.rjs +17 -0
  138. data/app/views/nodes/drive.rjs +2 -0
  139. data/app/views/nodes/drop.rjs +1 -0
  140. data/app/views/nodes/edit.html.erb +17 -0
  141. data/app/views/nodes/edit.rjs +7 -0
  142. data/app/views/nodes/import.rhtml +10 -0
  143. data/app/views/nodes/save_text.rjs +13 -0
  144. data/app/views/nodes/search.rjs +3 -0
  145. data/app/views/nodes/show.rjs +1 -0
  146. data/app/views/nodes/table_update.rjs +8 -0
  147. data/app/views/nodes/update.rjs +29 -0
  148. data/app/views/nodes/zafu.rjs +1 -0
  149. data/app/views/relations/_add.erb +6 -0
  150. data/app/views/relations/_form.erb +43 -0
  151. data/app/views/relations/_li.erb +16 -0
  152. data/app/views/relations/create.rjs +8 -0
  153. data/app/views/relations/destroy.rjs +6 -0
  154. data/app/views/relations/edit.erb +2 -0
  155. data/app/views/relations/index.erb +6 -0
  156. data/app/views/relations/new.erb +2 -0
  157. data/app/views/relations/show.rjs +1 -0
  158. data/app/views/relations/update.rjs +5 -0
  159. data/app/views/search/_form.rhtml +13 -0
  160. data/app/views/sites/_form.erb +37 -0
  161. data/app/views/sites/_li.erb +13 -0
  162. data/app/views/sites/clear_cache.rjs +2 -0
  163. data/app/views/sites/edit.erb +2 -0
  164. data/app/views/sites/index.erb +6 -0
  165. data/app/views/sites/show.rjs +1 -0
  166. data/app/views/sites/update.rjs +5 -0
  167. data/app/views/sites/zena_up.html.erb +11 -0
  168. data/app/views/templates/defaults/+adminLayout.zafu +69 -0
  169. data/app/views/templates/defaults/+login.zafu +32 -0
  170. data/app/views/templates/document_create_tabs/_file.rhtml +13 -0
  171. data/app/views/templates/document_create_tabs/_import.rhtml +9 -0
  172. data/app/views/templates/document_create_tabs/_template.rhtml +22 -0
  173. data/app/views/templates/document_create_tabs/_text_doc.rhtml +14 -0
  174. data/app/views/templates/drive_tabs/_drive.rhtml +11 -0
  175. data/app/views/templates/drive_tabs/_help.rhtml +0 -0
  176. data/app/views/templates/drive_tabs/_links.rhtml +8 -0
  177. data/app/views/templates/edit_tabs/_contact.rhtml +8 -0
  178. data/app/views/templates/edit_tabs/_custom.rhtml +6 -0
  179. data/app/views/templates/edit_tabs/_document.rhtml +8 -0
  180. data/app/views/templates/edit_tabs/_help.rhtml +7 -0
  181. data/app/views/templates/edit_tabs/_image.rhtml +19 -0
  182. data/app/views/templates/edit_tabs/_template.rhtml +8 -0
  183. data/app/views/templates/edit_tabs/_text.rhtml +1 -0
  184. data/app/views/templates/edit_tabs/_textdocument.rhtml +16 -0
  185. data/app/views/templates/edit_tabs/_title.rhtml +27 -0
  186. data/app/views/users/_add.rhtml +6 -0
  187. data/app/views/users/_form.rhtml +49 -0
  188. data/app/views/users/_li.rhtml +18 -0
  189. data/app/views/users/change_info.rjs +7 -0
  190. data/app/views/users/change_password.rjs +7 -0
  191. data/app/views/users/create.rjs +8 -0
  192. data/app/views/users/index.rhtml +7 -0
  193. data/app/views/users/preferences.html.erb +40 -0
  194. data/app/views/users/show.rjs +1 -0
  195. data/app/views/users/update.rjs +16 -0
  196. data/app/views/versions/_li.rhtml +3 -0
  197. data/app/views/versions/_list.rhtml +5 -0
  198. data/app/views/versions/_tr.rhtml +10 -0
  199. data/app/views/versions/backup.rjs +16 -0
  200. data/app/views/versions/css_preview.rjs +2 -0
  201. data/app/views/versions/destroy.rjs +6 -0
  202. data/app/views/versions/diff.rjs +3 -0
  203. data/app/views/versions/edit.rhtml +55 -0
  204. data/app/views/versions/preview.rjs +9 -0
  205. data/app/views/versions/show.rjs +5 -0
  206. data/app/views/versions/update.rjs +9 -0
  207. data/app/views/virtual_classes/_add.erb +6 -0
  208. data/app/views/virtual_classes/_form.erb +30 -0
  209. data/app/views/virtual_classes/_li.erb +12 -0
  210. data/app/views/virtual_classes/create.rjs +8 -0
  211. data/app/views/virtual_classes/destroy.rjs +6 -0
  212. data/app/views/virtual_classes/index.erb +7 -0
  213. data/app/views/virtual_classes/new.erb +2 -0
  214. data/app/views/virtual_classes/show.rjs +1 -0
  215. data/app/views/virtual_classes/update.rjs +5 -0
  216. data/bin/zena +5 -0
  217. data/bricks/captcha/MIT-LICENSE +19 -0
  218. data/bricks/captcha/README +11 -0
  219. data/bricks/captcha/patch/application_controller.rb +10 -0
  220. data/bricks/captcha/patch/application_helper.rb +32 -0
  221. data/bricks/captcha/patch/site.rb +2 -0
  222. data/bricks/captcha/zafu/captcha.rb +29 -0
  223. data/bricks/math/patch/application_helper.rb +95 -0
  224. data/bricks/tags/README +31 -0
  225. data/bricks/tags/lib/has_tags.rb +164 -0
  226. data/bricks/tags/patch/node.rb +15 -0
  227. data/bricks/tags/test/sites/zena/links.yml +11 -0
  228. data/bricks/tags/test/unit/tags_test.rb +103 -0
  229. data/bricks/tags/test/zafu/tags.yml +28 -0
  230. data/bricks/toto.zip +0 -0
  231. data/config/awstats.conf.rhtml +1497 -0
  232. data/config/boot.rb +109 -0
  233. data/config/database.rhtml +25 -0
  234. data/config/database.yml +40 -0
  235. data/config/database_example.yml +27 -0
  236. data/config/deploy.rb +382 -0
  237. data/config/deploy_config_example.rb +7 -0
  238. data/config/environment.rb +13 -0
  239. data/config/environments/development.rb +21 -0
  240. data/config/environments/production.rb +27 -0
  241. data/config/environments/test.rb +22 -0
  242. data/config/gems.yml +46 -0
  243. data/config/httpd.rhtml +18 -0
  244. data/config/initializers/mime_types.rb +10 -0
  245. data/config/initializers/zena.rb +1 -0
  246. data/config/locales/de.yml +120 -0
  247. data/config/locales/fr-CH.yml +123 -0
  248. data/config/locales/fr.yml +123 -0
  249. data/config/mongrel_upload_progress.conf +7 -0
  250. data/config/routes.rb +3 -0
  251. data/config/start.html +44 -0
  252. data/config/stats.vhost.rhtml +40 -0
  253. data/config/vhost.rhtml +84 -0
  254. data/config/vhost_www.rhtml +10 -0
  255. data/config/zena.rb +39 -0
  256. data/db/init/base/help.en.zml +94 -0
  257. data/db/init/base/help.fr.zml +88 -0
  258. data/db/init/base/skins.zml +3 -0
  259. data/db/init/base/skins/default.zml +10 -0
  260. data/db/init/base/skins/default/Node-+adminLayout.zafu +45 -0
  261. data/db/init/base/skins/default/Node-+index.zafu +1 -0
  262. data/db/init/base/skins/default/Node-+login.zafu +25 -0
  263. data/db/init/base/skins/default/Node-+notFound.zafu +14 -0
  264. data/db/init/base/skins/default/Node-+popupLayout.zafu +39 -0
  265. data/db/init/base/skins/default/Node-+search.zafu +20 -0
  266. data/db/init/base/skins/default/Node-tree.zafu +19 -0
  267. data/db/init/base/skins/default/Node.zafu +95 -0
  268. data/db/init/base/skins/default/Project.zafu +8 -0
  269. data/db/init/base/skins/default/favicon.png +0 -0
  270. data/db/init/base/skins/default/notes.zafu +22 -0
  271. data/db/init/base/skins/default/style.css +80 -0
  272. data/db/migrate/001_create_base.rb +156 -0
  273. data/db/migrate/002_add_time_zone_to_users.rb +9 -0
  274. data/db/migrate/003_add_custom_base_flag.rb +11 -0
  275. data/db/migrate/004_rename_template_skin.rb +9 -0
  276. data/db/migrate/005_create_cached_pages.rb +20 -0
  277. data/db/migrate/006_create_sites.rb +60 -0
  278. data/db/migrate/007_replace_id_by_zip.rb +17 -0
  279. data/db/migrate/008_user_status.rb +10 -0
  280. data/db/migrate/009_fulltext.rb +13 -0
  281. data/db/migrate/010_create_template_content.rb +17 -0
  282. data/db/migrate/011_project_to_section.rb +9 -0
  283. data/db/migrate/012_add_project_id.rb +12 -0
  284. data/db/migrate/013_remove_defaults.rb +29 -0
  285. data/db/migrate/014_add_sort_field.rb +10 -0
  286. data/db/migrate/015_add_dyn_attributes.rb +18 -0
  287. data/db/migrate/016_remove_translations.rb +20 -0
  288. data/db/migrate/017_rename_authorize.rb +9 -0
  289. data/db/migrate/018_add_auth_option.rb +9 -0
  290. data/db/migrate/019_remove_user_status.rb +25 -0
  291. data/db/migrate/020_create_participation.rb +30 -0
  292. data/db/migrate/021_create_relations.rb +23 -0
  293. data/db/migrate/022_create_virtual_classes.rb +20 -0
  294. data/db/migrate/023_ip_on_anonymous_comment.rb +9 -0
  295. data/db/migrate/024_correct_vclass_kpath.rb +11 -0
  296. data/db/migrate/025_move_tag_into_vclass.rb +13 -0
  297. data/db/migrate/026_rename_templates.rb +47 -0
  298. data/db/migrate/027_add_country_to_contacts.rb +9 -0
  299. data/db/migrate/028_change_size_of_conten_type_field.rb +9 -0
  300. data/db/migrate/029_create_data_entries.rb +21 -0
  301. data/db/migrate/030_redit_auto_publish_site_settings.rb +13 -0
  302. data/db/migrate/031_create_iformats.rb +21 -0
  303. data/db/migrate/032_caches_context_as_hash.rb +10 -0
  304. data/db/migrate/033_documents_kpath_change.rb +17 -0
  305. data/db/migrate/034_change_file_storage.rb +38 -0
  306. data/db/migrate/035_add_status_to_link.rb +13 -0
  307. data/db/migrate/036_add_flag_fields_on_nodes.rb +11 -0
  308. data/db/migrate/037_add_auto_create_discussion_to_v_class.rb +11 -0
  309. data/db/migrate/038_create_site_attributes.rb +15 -0
  310. data/db/migrate/039_default_position.rb +10 -0
  311. data/db/migrate/040_second_value_for_data_entry.rb +11 -0
  312. data/db/migrate/041_add_attributes_to_v_class.rb +9 -0
  313. data/db/migrate/042_fix_position_should_be_float.rb +8 -0
  314. data/db/migrate/043_move_user_lang_into_participation.rb +15 -0
  315. data/db/migrate/044_remove_monolingual_site_option.rb +9 -0
  316. data/db/migrate/045_avoid_star_in_templates.rb +13 -0
  317. data/db/migrate/046_fix_zazen_image_tag.rb +47 -0
  318. data/db/migrate/047_change_default_link_id_to_zero.rb +12 -0
  319. data/db/migrate/048_link_source_target_can_be_null.rb +11 -0
  320. data/db/migrate/049_fix_publish_from_is_null.rb +9 -0
  321. data/db/migrate/050_date_in_links.rb +9 -0
  322. data/db/migrate/051_add_exif_tags_to_images.rb +9 -0
  323. data/db/migrate/20090825201159_insert_zero_link.rb +8 -0
  324. data/db/migrate/20090825201200_merge_bricks_migrations_with_std_migrations.rb +19 -0
  325. data/db/migrate/20090924141459_zafu_fix_sept09.rb +19 -0
  326. data/db/migrate/20090927125912_allow_null_in_text_fields.rb +17 -0
  327. data/db/migrate/20090928133440_no_more_private_nodes.rb +25 -0
  328. data/db/migrate/20090928143754_version_status_change.rb +24 -0
  329. data/db/migrate/20091001084025_change_status_values_for_comments.rb +22 -0
  330. data/db/migrate/20091009084057_add_vhash_in_node.rb +13 -0
  331. data/db/migrate/20091013100351_rename_publish_group_to_drive_group.rb +12 -0
  332. data/db/migrate/20091014130833_fix_template_title.rb +16 -0
  333. data/db/migrate/20091014183726_merge_participation_into_users.rb +21 -0
  334. data/db/production.sqlite3 +0 -0
  335. data/db/schema.rb +281 -0
  336. data/lib/base_additions.rb +7 -0
  337. data/lib/bricks/patcher.rb +68 -0
  338. data/lib/comment_query.rb +92 -0
  339. data/lib/core_ext/date_time.rb +5 -0
  340. data/lib/core_ext/dir.rb +12 -0
  341. data/lib/core_ext/fixnum.rb +20 -0
  342. data/lib/core_ext/string.rb +74 -0
  343. data/lib/exif_data.rb +54 -0
  344. data/lib/fix_rails_layouts.rb +9 -0
  345. data/lib/gettext_strings.rb +160 -0
  346. data/lib/image_builder.rb +325 -0
  347. data/lib/log_recorder/lib/log_recorder.rb +138 -0
  348. data/lib/log_recorder/test/log_recorder_test.rb +0 -0
  349. data/lib/parser.rb +1 -0
  350. data/lib/tasks/capistrano.rake +99 -0
  351. data/lib/tasks/zena.rake +358 -0
  352. data/lib/tasks/zena.rb +2 -0
  353. data/lib/upload_progress_server.rb +24 -0
  354. data/lib/webdav_adapter.rb +172 -0
  355. data/lib/zafu_parser.rb +3 -0
  356. data/lib/zazen_parser.rb +1 -0
  357. data/lib/zena.rb +398 -0
  358. data/lib/zena/acts/multiversion.rb +755 -0
  359. data/lib/zena/acts/secure.rb +774 -0
  360. data/lib/zena/app.rb +39 -0
  361. data/lib/zena/code_syntax.rb +275 -0
  362. data/lib/zena/controller/test_case.rb +32 -0
  363. data/lib/zena/db.rb +252 -0
  364. data/lib/zena/fix/mysql_connection.rb +17 -0
  365. data/lib/zena/foxy_parser.rb +845 -0
  366. data/lib/zena/migrator.rb +109 -0
  367. data/lib/zena/parser.rb +601 -0
  368. data/lib/zena/parser/zafu_rules.rb +232 -0
  369. data/lib/zena/parser/zafu_tags.rb +197 -0
  370. data/lib/zena/parser/zazen_rules.rb +427 -0
  371. data/lib/zena/parser/zazen_tags.rb +44 -0
  372. data/lib/zena/parser/zena_rules.rb +29 -0
  373. data/lib/zena/parser/zena_tags.rb +3559 -0
  374. data/lib/zena/root.rb +3 -0
  375. data/lib/zena/routes.rb +73 -0
  376. data/lib/zena/test_controller.rb +74 -0
  377. data/lib/zena/unit/test_case.rb +24 -0
  378. data/lib/zena/use/ajax.rb +119 -0
  379. data/lib/zena/use/authentification.rb +120 -0
  380. data/lib/zena/use/calendar.rb +130 -0
  381. data/lib/zena/use/custom_queries/complex.host.yml +173 -0
  382. data/lib/zena/use/dates.rb +230 -0
  383. data/lib/zena/use/dyn_attributes.rb +256 -0
  384. data/lib/zena/use/error_rendering.rb +52 -0
  385. data/lib/zena/use/fixtures.rb +133 -0
  386. data/lib/zena/use/grid.rb +148 -0
  387. data/lib/zena/use/html_tags.rb +603 -0
  388. data/lib/zena/use/i18n.rb +247 -0
  389. data/lib/zena/use/nested_attributes_alias.rb +201 -0
  390. data/lib/zena/use/node_query_finders.rb +491 -0
  391. data/lib/zena/use/refactor.rb +231 -0
  392. data/lib/zena/use/relations.rb +360 -0
  393. data/lib/zena/use/rendering.rb +248 -0
  394. data/lib/zena/use/test_helper.rb +151 -0
  395. data/lib/zena/use/urls.rb +180 -0
  396. data/lib/zena/use/zafu.rb +549 -0
  397. data/lib/zena/use/zazen.rb +230 -0
  398. data/lib/zena/view/test_case.rb +23 -0
  399. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  400. data/locale/en/zena.po +2116 -0
  401. data/locale/fr/LC_MESSAGES/zena.mo +0 -0
  402. data/locale/fr/zena.po +2172 -0
  403. data/locale/zena.pot +1915 -0
  404. data/public/calendar/calendar-brown.css +225 -0
  405. data/public/calendar/calendar-setup.js +153 -0
  406. data/public/calendar/calendar.js +1817 -0
  407. data/public/calendar/iconCalendar.gif +0 -0
  408. data/public/calendar/lang/calendar-en-utf8.js +128 -0
  409. data/public/calendar/lang/calendar-fr-utf8.js +120 -0
  410. data/public/calendar/lang/lang.zip +0 -0
  411. data/public/dispatch.cgi +10 -0
  412. data/public/dispatch.fcgi +24 -0
  413. data/public/dispatch.rb +10 -0
  414. data/public/favicon.ico +0 -0
  415. data/public/images/accept.png +0 -0
  416. data/public/images/action.png +0 -0
  417. data/public/images/add.png +0 -0
  418. data/public/images/ajax-loader.gif +0 -0
  419. data/public/images/anchor.png +0 -0
  420. data/public/images/application.png +0 -0
  421. data/public/images/application_add.png +0 -0
  422. data/public/images/application_cascade.png +0 -0
  423. data/public/images/application_delete.png +0 -0
  424. data/public/images/application_double.png +0 -0
  425. data/public/images/application_edit.png +0 -0
  426. data/public/images/application_error.png +0 -0
  427. data/public/images/application_form.png +0 -0
  428. data/public/images/application_form_add.png +0 -0
  429. data/public/images/application_form_delete.png +0 -0
  430. data/public/images/application_form_edit.png +0 -0
  431. data/public/images/application_form_magnify.png +0 -0
  432. data/public/images/application_get.png +0 -0
  433. data/public/images/application_go.png +0 -0
  434. data/public/images/application_home.png +0 -0
  435. data/public/images/application_key.png +0 -0
  436. data/public/images/application_lightning.png +0 -0
  437. data/public/images/application_link.png +0 -0
  438. data/public/images/application_osx.png +0 -0
  439. data/public/images/application_osx_terminal.png +0 -0
  440. data/public/images/application_put.png +0 -0
  441. data/public/images/application_side_boxes.png +0 -0
  442. data/public/images/application_side_contract.png +0 -0
  443. data/public/images/application_side_expand.png +0 -0
  444. data/public/images/application_side_list.png +0 -0
  445. data/public/images/application_side_tree.png +0 -0
  446. data/public/images/application_split.png +0 -0
  447. data/public/images/application_tile_horizontal.png +0 -0
  448. data/public/images/application_tile_vertical.png +0 -0
  449. data/public/images/application_view_columns.png +0 -0
  450. data/public/images/application_view_detail.png +0 -0
  451. data/public/images/application_view_gallery.png +0 -0
  452. data/public/images/application_view_icons.png +0 -0
  453. data/public/images/application_view_list.png +0 -0
  454. data/public/images/application_view_tile.png +0 -0
  455. data/public/images/application_xp.png +0 -0
  456. data/public/images/application_xp_terminal.png +0 -0
  457. data/public/images/arrow_branch.png +0 -0
  458. data/public/images/arrow_divide.png +0 -0
  459. data/public/images/arrow_down.png +0 -0
  460. data/public/images/arrow_in.png +0 -0
  461. data/public/images/arrow_inout.png +0 -0
  462. data/public/images/arrow_join.png +0 -0
  463. data/public/images/arrow_left.png +0 -0
  464. data/public/images/arrow_merge.png +0 -0
  465. data/public/images/arrow_out.png +0 -0
  466. data/public/images/arrow_redo.png +0 -0
  467. data/public/images/arrow_refresh.png +0 -0
  468. data/public/images/arrow_refresh_small.png +0 -0
  469. data/public/images/arrow_right.png +0 -0
  470. data/public/images/arrow_rotate_anticlockwise.png +0 -0
  471. data/public/images/arrow_rotate_clockwise.png +0 -0
  472. data/public/images/arrow_switch.png +0 -0
  473. data/public/images/arrow_turn_left.png +0 -0
  474. data/public/images/arrow_turn_right.png +0 -0
  475. data/public/images/arrow_undo.png +0 -0
  476. data/public/images/arrow_up.png +0 -0
  477. data/public/images/asterisk_orange.png +0 -0
  478. data/public/images/asterisk_yellow.png +0 -0
  479. data/public/images/attach.png +0 -0
  480. data/public/images/award_star_add.png +0 -0
  481. data/public/images/award_star_bronze_1.png +0 -0
  482. data/public/images/award_star_bronze_2.png +0 -0
  483. data/public/images/award_star_bronze_3.png +0 -0
  484. data/public/images/award_star_delete.png +0 -0
  485. data/public/images/award_star_gold_1.png +0 -0
  486. data/public/images/award_star_gold_2.png +0 -0
  487. data/public/images/award_star_gold_3.png +0 -0
  488. data/public/images/award_star_silver_1.png +0 -0
  489. data/public/images/award_star_silver_2.png +0 -0
  490. data/public/images/award_star_silver_3.png +0 -0
  491. data/public/images/basket.png +0 -0
  492. data/public/images/basket_add.png +0 -0
  493. data/public/images/basket_delete.png +0 -0
  494. data/public/images/basket_edit.png +0 -0
  495. data/public/images/basket_error.png +0 -0
  496. data/public/images/basket_go.png +0 -0
  497. data/public/images/basket_put.png +0 -0
  498. data/public/images/basket_remove.png +0 -0
  499. data/public/images/bell.png +0 -0
  500. data/public/images/bell_add.png +0 -0
  501. data/public/images/bell_delete.png +0 -0
  502. data/public/images/bell_error.png +0 -0
  503. data/public/images/bell_go.png +0 -0
  504. data/public/images/bell_link.png +0 -0
  505. data/public/images/bin.png +0 -0
  506. data/public/images/bin_closed.png +0 -0
  507. data/public/images/bin_empty.gif +0 -0
  508. data/public/images/bin_empty.png +0 -0
  509. data/public/images/bin_full.gif +0 -0
  510. data/public/images/bomb.png +0 -0
  511. data/public/images/book.png +0 -0
  512. data/public/images/book_add.png +0 -0
  513. data/public/images/book_addresses.png +0 -0
  514. data/public/images/book_delete.png +0 -0
  515. data/public/images/book_edit.png +0 -0
  516. data/public/images/book_error.png +0 -0
  517. data/public/images/book_go.png +0 -0
  518. data/public/images/book_key.png +0 -0
  519. data/public/images/book_link.png +0 -0
  520. data/public/images/book_next.png +0 -0
  521. data/public/images/book_open.png +0 -0
  522. data/public/images/book_previous.png +0 -0
  523. data/public/images/box.png +0 -0
  524. data/public/images/brick.png +0 -0
  525. data/public/images/brick_add.png +0 -0
  526. data/public/images/brick_delete.png +0 -0
  527. data/public/images/brick_edit.png +0 -0
  528. data/public/images/brick_error.png +0 -0
  529. data/public/images/brick_go.png +0 -0
  530. data/public/images/brick_link.png +0 -0
  531. data/public/images/bricks.png +0 -0
  532. data/public/images/briefcase.png +0 -0
  533. data/public/images/bug.png +0 -0
  534. data/public/images/bug_add.png +0 -0
  535. data/public/images/bug_delete.png +0 -0
  536. data/public/images/bug_edit.png +0 -0
  537. data/public/images/bug_error.png +0 -0
  538. data/public/images/bug_go.png +0 -0
  539. data/public/images/bug_link.png +0 -0
  540. data/public/images/building.png +0 -0
  541. data/public/images/building_add.png +0 -0
  542. data/public/images/building_delete.png +0 -0
  543. data/public/images/building_edit.png +0 -0
  544. data/public/images/building_error.png +0 -0
  545. data/public/images/building_go.png +0 -0
  546. data/public/images/building_key.png +0 -0
  547. data/public/images/building_link.png +0 -0
  548. data/public/images/bullet_add.png +0 -0
  549. data/public/images/bullet_arrow_bottom.png +0 -0
  550. data/public/images/bullet_arrow_down.png +0 -0
  551. data/public/images/bullet_arrow_top.png +0 -0
  552. data/public/images/bullet_arrow_up.png +0 -0
  553. data/public/images/bullet_black.png +0 -0
  554. data/public/images/bullet_blue.png +0 -0
  555. data/public/images/bullet_delete.png +0 -0
  556. data/public/images/bullet_disk.png +0 -0
  557. data/public/images/bullet_error.png +0 -0
  558. data/public/images/bullet_feed.png +0 -0
  559. data/public/images/bullet_go.png +0 -0
  560. data/public/images/bullet_green.png +0 -0
  561. data/public/images/bullet_key.png +0 -0
  562. data/public/images/bullet_orange.png +0 -0
  563. data/public/images/bullet_picture.png +0 -0
  564. data/public/images/bullet_pink.png +0 -0
  565. data/public/images/bullet_purple.png +0 -0
  566. data/public/images/bullet_red.png +0 -0
  567. data/public/images/bullet_star.png +0 -0
  568. data/public/images/bullet_toggle_minus.png +0 -0
  569. data/public/images/bullet_toggle_plus.png +0 -0
  570. data/public/images/bullet_white.png +0 -0
  571. data/public/images/bullet_wrench.png +0 -0
  572. data/public/images/bullet_yellow.png +0 -0
  573. data/public/images/cake.png +0 -0
  574. data/public/images/calculator.png +0 -0
  575. data/public/images/calculator_add.png +0 -0
  576. data/public/images/calculator_delete.png +0 -0
  577. data/public/images/calculator_edit.png +0 -0
  578. data/public/images/calculator_error.png +0 -0
  579. data/public/images/calculator_link.png +0 -0
  580. data/public/images/calendar.png +0 -0
  581. data/public/images/calendar_add.png +0 -0
  582. data/public/images/calendar_delete.png +0 -0
  583. data/public/images/calendar_edit.png +0 -0
  584. data/public/images/calendar_link.png +0 -0
  585. data/public/images/calendar_view_day.png +0 -0
  586. data/public/images/calendar_view_month.png +0 -0
  587. data/public/images/calendar_view_week.png +0 -0
  588. data/public/images/camera.png +0 -0
  589. data/public/images/camera_add.png +0 -0
  590. data/public/images/camera_delete.png +0 -0
  591. data/public/images/camera_edit.png +0 -0
  592. data/public/images/camera_error.png +0 -0
  593. data/public/images/camera_go.png +0 -0
  594. data/public/images/camera_link.png +0 -0
  595. data/public/images/camera_small.png +0 -0
  596. data/public/images/cancel.png +0 -0
  597. data/public/images/car.png +0 -0
  598. data/public/images/car_add.png +0 -0
  599. data/public/images/car_delete.png +0 -0
  600. data/public/images/cart.png +0 -0
  601. data/public/images/cart_add.png +0 -0
  602. data/public/images/cart_delete.png +0 -0
  603. data/public/images/cart_edit.png +0 -0
  604. data/public/images/cart_error.png +0 -0
  605. data/public/images/cart_go.png +0 -0
  606. data/public/images/cart_put.png +0 -0
  607. data/public/images/cart_remove.png +0 -0
  608. data/public/images/cd.png +0 -0
  609. data/public/images/cd_add.png +0 -0
  610. data/public/images/cd_burn.png +0 -0
  611. data/public/images/cd_delete.png +0 -0
  612. data/public/images/cd_edit.png +0 -0
  613. data/public/images/cd_eject.png +0 -0
  614. data/public/images/cd_go.png +0 -0
  615. data/public/images/chart_bar.png +0 -0
  616. data/public/images/chart_bar_add.png +0 -0
  617. data/public/images/chart_bar_delete.png +0 -0
  618. data/public/images/chart_bar_edit.png +0 -0
  619. data/public/images/chart_bar_error.png +0 -0
  620. data/public/images/chart_bar_link.png +0 -0
  621. data/public/images/chart_curve.png +0 -0
  622. data/public/images/chart_curve_add.png +0 -0
  623. data/public/images/chart_curve_delete.png +0 -0
  624. data/public/images/chart_curve_edit.png +0 -0
  625. data/public/images/chart_curve_error.png +0 -0
  626. data/public/images/chart_curve_go.png +0 -0
  627. data/public/images/chart_curve_link.png +0 -0
  628. data/public/images/chart_line.png +0 -0
  629. data/public/images/chart_line_add.png +0 -0
  630. data/public/images/chart_line_delete.png +0 -0
  631. data/public/images/chart_line_edit.png +0 -0
  632. data/public/images/chart_line_error.png +0 -0
  633. data/public/images/chart_line_link.png +0 -0
  634. data/public/images/chart_organisation.png +0 -0
  635. data/public/images/chart_organisation_add.png +0 -0
  636. data/public/images/chart_organisation_delete.png +0 -0
  637. data/public/images/chart_pie.png +0 -0
  638. data/public/images/chart_pie_add.png +0 -0
  639. data/public/images/chart_pie_delete.png +0 -0
  640. data/public/images/chart_pie_edit.png +0 -0
  641. data/public/images/chart_pie_error.png +0 -0
  642. data/public/images/chart_pie_link.png +0 -0
  643. data/public/images/clock.png +0 -0
  644. data/public/images/clock_add.png +0 -0
  645. data/public/images/clock_delete.png +0 -0
  646. data/public/images/clock_edit.png +0 -0
  647. data/public/images/clock_error.png +0 -0
  648. data/public/images/clock_go.png +0 -0
  649. data/public/images/clock_link.png +0 -0
  650. data/public/images/clock_pause.png +0 -0
  651. data/public/images/clock_play.png +0 -0
  652. data/public/images/clock_red.png +0 -0
  653. data/public/images/clock_stop.png +0 -0
  654. data/public/images/cog.png +0 -0
  655. data/public/images/cog_add.png +0 -0
  656. data/public/images/cog_delete.png +0 -0
  657. data/public/images/cog_edit.png +0 -0
  658. data/public/images/cog_error.png +0 -0
  659. data/public/images/cog_go.png +0 -0
  660. data/public/images/coins.png +0 -0
  661. data/public/images/coins_add.png +0 -0
  662. data/public/images/coins_delete.png +0 -0
  663. data/public/images/collection.png +0 -0
  664. data/public/images/color_swatch.png +0 -0
  665. data/public/images/color_wheel.png +0 -0
  666. data/public/images/column_add.png +0 -0
  667. data/public/images/column_delete.png +0 -0
  668. data/public/images/comment.png +0 -0
  669. data/public/images/comment_add.png +0 -0
  670. data/public/images/comment_delete.png +0 -0
  671. data/public/images/comment_edit.png +0 -0
  672. data/public/images/comments.png +0 -0
  673. data/public/images/comments_add.png +0 -0
  674. data/public/images/comments_delete.png +0 -0
  675. data/public/images/comments_red.png +0 -0
  676. data/public/images/compress.png +0 -0
  677. data/public/images/computer.png +0 -0
  678. data/public/images/computer_add.png +0 -0
  679. data/public/images/computer_delete.png +0 -0
  680. data/public/images/computer_edit.png +0 -0
  681. data/public/images/computer_error.png +0 -0
  682. data/public/images/computer_go.png +0 -0
  683. data/public/images/computer_key.png +0 -0
  684. data/public/images/computer_link.png +0 -0
  685. data/public/images/connect.png +0 -0
  686. data/public/images/contrast.png +0 -0
  687. data/public/images/contrast_decrease.png +0 -0
  688. data/public/images/contrast_high.png +0 -0
  689. data/public/images/contrast_increase.png +0 -0
  690. data/public/images/contrast_low.png +0 -0
  691. data/public/images/control_eject.png +0 -0
  692. data/public/images/control_eject_blue.png +0 -0
  693. data/public/images/control_end.png +0 -0
  694. data/public/images/control_end_blue.png +0 -0
  695. data/public/images/control_equalizer.png +0 -0
  696. data/public/images/control_equalizer_blue.png +0 -0
  697. data/public/images/control_fastforward.png +0 -0
  698. data/public/images/control_fastforward_blue.png +0 -0
  699. data/public/images/control_pause.png +0 -0
  700. data/public/images/control_pause_blue.png +0 -0
  701. data/public/images/control_play.png +0 -0
  702. data/public/images/control_play_blue.png +0 -0
  703. data/public/images/control_repeat.png +0 -0
  704. data/public/images/control_repeat_blue.png +0 -0
  705. data/public/images/control_rewind.png +0 -0
  706. data/public/images/control_rewind_blue.png +0 -0
  707. data/public/images/control_start.png +0 -0
  708. data/public/images/control_start_blue.png +0 -0
  709. data/public/images/control_stop.png +0 -0
  710. data/public/images/control_stop_blue.png +0 -0
  711. data/public/images/controller.png +0 -0
  712. data/public/images/controller_add.png +0 -0
  713. data/public/images/controller_delete.png +0 -0
  714. data/public/images/controller_error.png +0 -0
  715. data/public/images/creditcards.png +0 -0
  716. data/public/images/cross.png +0 -0
  717. data/public/images/css.png +0 -0
  718. data/public/images/css_add.png +0 -0
  719. data/public/images/css_delete.png +0 -0
  720. data/public/images/css_go.png +0 -0
  721. data/public/images/css_valid.png +0 -0
  722. data/public/images/cup.png +0 -0
  723. data/public/images/cup_add.png +0 -0
  724. data/public/images/cup_delete.png +0 -0
  725. data/public/images/cup_edit.png +0 -0
  726. data/public/images/cup_error.png +0 -0
  727. data/public/images/cup_go.png +0 -0
  728. data/public/images/cup_key.png +0 -0
  729. data/public/images/cup_link.png +0 -0
  730. data/public/images/cursor.png +0 -0
  731. data/public/images/cut.png +0 -0
  732. data/public/images/cut_red.png +0 -0
  733. data/public/images/database.png +0 -0
  734. data/public/images/database_add.png +0 -0
  735. data/public/images/database_connect.png +0 -0
  736. data/public/images/database_delete.png +0 -0
  737. data/public/images/database_edit.png +0 -0
  738. data/public/images/database_error.png +0 -0
  739. data/public/images/database_gear.png +0 -0
  740. data/public/images/database_go.png +0 -0
  741. data/public/images/database_key.png +0 -0
  742. data/public/images/database_lightning.png +0 -0
  743. data/public/images/database_link.png +0 -0
  744. data/public/images/database_refresh.png +0 -0
  745. data/public/images/database_save.png +0 -0
  746. data/public/images/database_table.png +0 -0
  747. data/public/images/date.png +0 -0
  748. data/public/images/date_add.png +0 -0
  749. data/public/images/date_delete.png +0 -0
  750. data/public/images/date_edit.png +0 -0
  751. data/public/images/date_error.png +0 -0
  752. data/public/images/date_go.png +0 -0
  753. data/public/images/date_link.png +0 -0
  754. data/public/images/date_magnify.png +0 -0
  755. data/public/images/date_next.png +0 -0
  756. data/public/images/date_previous.png +0 -0
  757. data/public/images/delete.png +0 -0
  758. data/public/images/disconnect.png +0 -0
  759. data/public/images/disk.png +0 -0
  760. data/public/images/disk_multiple.png +0 -0
  761. data/public/images/door.png +0 -0
  762. data/public/images/door_in.png +0 -0
  763. data/public/images/door_open.png +0 -0
  764. data/public/images/door_out.png +0 -0
  765. data/public/images/drink.png +0 -0
  766. data/public/images/drink_empty.png +0 -0
  767. data/public/images/drive.png +0 -0
  768. data/public/images/drive_add.png +0 -0
  769. data/public/images/drive_burn.png +0 -0
  770. data/public/images/drive_cd.png +0 -0
  771. data/public/images/drive_cd_empty.png +0 -0
  772. data/public/images/drive_delete.png +0 -0
  773. data/public/images/drive_disk.png +0 -0
  774. data/public/images/drive_edit.png +0 -0
  775. data/public/images/drive_error.png +0 -0
  776. data/public/images/drive_go.png +0 -0
  777. data/public/images/drive_key.png +0 -0
  778. data/public/images/drive_link.png +0 -0
  779. data/public/images/drive_magnify.png +0 -0
  780. data/public/images/drive_network.png +0 -0
  781. data/public/images/drive_rename.png +0 -0
  782. data/public/images/drive_user.png +0 -0
  783. data/public/images/drive_web.png +0 -0
  784. data/public/images/dvd.png +0 -0
  785. data/public/images/dvd_add.png +0 -0
  786. data/public/images/dvd_delete.png +0 -0
  787. data/public/images/dvd_edit.png +0 -0
  788. data/public/images/dvd_error.png +0 -0
  789. data/public/images/dvd_go.png +0 -0
  790. data/public/images/dvd_key.png +0 -0
  791. data/public/images/dvd_link.png +0 -0
  792. data/public/images/email.png +0 -0
  793. data/public/images/email_add.png +0 -0
  794. data/public/images/email_attach.png +0 -0
  795. data/public/images/email_delete.png +0 -0
  796. data/public/images/email_edit.png +0 -0
  797. data/public/images/email_error.png +0 -0
  798. data/public/images/email_go.png +0 -0
  799. data/public/images/email_link.png +0 -0
  800. data/public/images/email_open.png +0 -0
  801. data/public/images/email_open_image.png +0 -0
  802. data/public/images/emoticon_evilgrin.png +0 -0
  803. data/public/images/emoticon_grin.png +0 -0
  804. data/public/images/emoticon_happy.png +0 -0
  805. data/public/images/emoticon_smile.png +0 -0
  806. data/public/images/emoticon_surprised.png +0 -0
  807. data/public/images/emoticon_tongue.png +0 -0
  808. data/public/images/emoticon_unhappy.png +0 -0
  809. data/public/images/emoticon_waii.png +0 -0
  810. data/public/images/emoticon_wink.png +0 -0
  811. data/public/images/error.png +0 -0
  812. data/public/images/error_add.png +0 -0
  813. data/public/images/error_delete.png +0 -0
  814. data/public/images/error_go.png +0 -0
  815. data/public/images/exclamation.png +0 -0
  816. data/public/images/ext/contact.png +0 -0
  817. data/public/images/ext/contact_pv.png +0 -0
  818. data/public/images/ext/doc.png +0 -0
  819. data/public/images/ext/doc_tiny.png +0 -0
  820. data/public/images/ext/jpg.png +0 -0
  821. data/public/images/ext/jpg_tiny.png +0 -0
  822. data/public/images/ext/other.png +0 -0
  823. data/public/images/ext/other_pv.png +0 -0
  824. data/public/images/ext/other_tiny.png +0 -0
  825. data/public/images/ext/page.png +0 -0
  826. data/public/images/ext/page_pv.png +0 -0
  827. data/public/images/ext/page_tiny.png +0 -0
  828. data/public/images/ext/pdf.png +0 -0
  829. data/public/images/ext/pdf_pv.png +0 -0
  830. data/public/images/ext/pdf_tiny.png +0 -0
  831. data/public/images/ext/png.png +0 -0
  832. data/public/images/ext/png_tiny.png +0 -0
  833. data/public/images/ext/post.png +0 -0
  834. data/public/images/ext/post_pv.png +0 -0
  835. data/public/images/ext/post_tiny.png +0 -0
  836. data/public/images/ext/project.png +0 -0
  837. data/public/images/ext/project_pv.png +0 -0
  838. data/public/images/ext/project_tiny.png +0 -0
  839. data/public/images/ext/rtf.png +0 -0
  840. data/public/images/ext/rtf_tiny.png +0 -0
  841. data/public/images/ext/tag.png +0 -0
  842. data/public/images/ext/tag_pv.png +0 -0
  843. data/public/images/ext/xls.png +0 -0
  844. data/public/images/ext/xls_tiny.png +0 -0
  845. data/public/images/ext/zip.png +0 -0
  846. data/public/images/ext/zip_pv.png +0 -0
  847. data/public/images/ext/zip_tiny.png +0 -0
  848. data/public/images/eye.png +0 -0
  849. data/public/images/feed.png +0 -0
  850. data/public/images/feed_add.png +0 -0
  851. data/public/images/feed_delete.png +0 -0
  852. data/public/images/feed_disk.png +0 -0
  853. data/public/images/feed_edit.png +0 -0
  854. data/public/images/feed_error.png +0 -0
  855. data/public/images/feed_go.png +0 -0
  856. data/public/images/feed_key.png +0 -0
  857. data/public/images/feed_link.png +0 -0
  858. data/public/images/feed_magnify.png +0 -0
  859. data/public/images/female.png +0 -0
  860. data/public/images/film.png +0 -0
  861. data/public/images/film_add.png +0 -0
  862. data/public/images/film_delete.png +0 -0
  863. data/public/images/film_edit.png +0 -0
  864. data/public/images/film_error.png +0 -0
  865. data/public/images/film_go.png +0 -0
  866. data/public/images/film_key.png +0 -0
  867. data/public/images/film_link.png +0 -0
  868. data/public/images/film_save.png +0 -0
  869. data/public/images/find.png +0 -0
  870. data/public/images/flag_blue.png +0 -0
  871. data/public/images/flag_green.png +0 -0
  872. data/public/images/flag_orange.png +0 -0
  873. data/public/images/flag_pink.png +0 -0
  874. data/public/images/flag_purple.png +0 -0
  875. data/public/images/flag_red.png +0 -0
  876. data/public/images/flag_yellow.png +0 -0
  877. data/public/images/folder.png +0 -0
  878. data/public/images/folder_add.png +0 -0
  879. data/public/images/folder_bell.png +0 -0
  880. data/public/images/folder_brick.png +0 -0
  881. data/public/images/folder_bug.png +0 -0
  882. data/public/images/folder_camera.png +0 -0
  883. data/public/images/folder_database.png +0 -0
  884. data/public/images/folder_delete.png +0 -0
  885. data/public/images/folder_edit.png +0 -0
  886. data/public/images/folder_error.png +0 -0
  887. data/public/images/folder_explore.png +0 -0
  888. data/public/images/folder_feed.png +0 -0
  889. data/public/images/folder_find.png +0 -0
  890. data/public/images/folder_go.png +0 -0
  891. data/public/images/folder_heart.png +0 -0
  892. data/public/images/folder_image.png +0 -0
  893. data/public/images/folder_key.png +0 -0
  894. data/public/images/folder_lightbulb.png +0 -0
  895. data/public/images/folder_link.png +0 -0
  896. data/public/images/folder_magnify.png +0 -0
  897. data/public/images/folder_page.png +0 -0
  898. data/public/images/folder_page_white.png +0 -0
  899. data/public/images/folder_palette.png +0 -0
  900. data/public/images/folder_picture.png +0 -0
  901. data/public/images/folder_star.png +0 -0
  902. data/public/images/folder_table.png +0 -0
  903. data/public/images/folder_user.png +0 -0
  904. data/public/images/folder_wrench.png +0 -0
  905. data/public/images/font.png +0 -0
  906. data/public/images/font_add.png +0 -0
  907. data/public/images/font_delete.png +0 -0
  908. data/public/images/font_go.png +0 -0
  909. data/public/images/group.png +0 -0
  910. data/public/images/group_add.png +0 -0
  911. data/public/images/group_admin.png +0 -0
  912. data/public/images/group_delete.png +0 -0
  913. data/public/images/group_edit.png +0 -0
  914. data/public/images/group_error.png +0 -0
  915. data/public/images/group_gear.png +0 -0
  916. data/public/images/group_go.png +0 -0
  917. data/public/images/group_key.png +0 -0
  918. data/public/images/group_link.png +0 -0
  919. data/public/images/group_pub.png +0 -0
  920. data/public/images/group_site.png +0 -0
  921. data/public/images/heart.png +0 -0
  922. data/public/images/heart_add.png +0 -0
  923. data/public/images/heart_delete.png +0 -0
  924. data/public/images/help.png +0 -0
  925. data/public/images/home.png +0 -0
  926. data/public/images/hourglass.png +0 -0
  927. data/public/images/hourglass_add.png +0 -0
  928. data/public/images/hourglass_delete.png +0 -0
  929. data/public/images/hourglass_go.png +0 -0
  930. data/public/images/hourglass_link.png +0 -0
  931. data/public/images/house.png +0 -0
  932. data/public/images/house_go.png +0 -0
  933. data/public/images/house_link.png +0 -0
  934. data/public/images/html.png +0 -0
  935. data/public/images/html_add.png +0 -0
  936. data/public/images/html_delete.png +0 -0
  937. data/public/images/html_go.png +0 -0
  938. data/public/images/html_valid.png +0 -0
  939. data/public/images/image.png +0 -0
  940. data/public/images/image_add.png +0 -0
  941. data/public/images/image_delete.png +0 -0
  942. data/public/images/image_edit.png +0 -0
  943. data/public/images/image_link.png +0 -0
  944. data/public/images/images.png +0 -0
  945. data/public/images/img_not_found.png +0 -0
  946. data/public/images/information.png +0 -0
  947. data/public/images/ipod.png +0 -0
  948. data/public/images/ipod_cast.png +0 -0
  949. data/public/images/ipod_cast_add.png +0 -0
  950. data/public/images/ipod_cast_delete.png +0 -0
  951. data/public/images/ipod_sound.png +0 -0
  952. data/public/images/joystick.png +0 -0
  953. data/public/images/joystick_add.png +0 -0
  954. data/public/images/joystick_delete.png +0 -0
  955. data/public/images/joystick_error.png +0 -0
  956. data/public/images/key.png +0 -0
  957. data/public/images/key_add.png +0 -0
  958. data/public/images/key_delete.png +0 -0
  959. data/public/images/key_go.png +0 -0
  960. data/public/images/keyboard.png +0 -0
  961. data/public/images/keyboard_add.png +0 -0
  962. data/public/images/keyboard_delete.png +0 -0
  963. data/public/images/keyboard_magnify.png +0 -0
  964. data/public/images/latex_error.png +0 -0
  965. data/public/images/layers.png +0 -0
  966. data/public/images/layout.png +0 -0
  967. data/public/images/layout_add.png +0 -0
  968. data/public/images/layout_content.png +0 -0
  969. data/public/images/layout_delete.png +0 -0
  970. data/public/images/layout_edit.png +0 -0
  971. data/public/images/layout_error.png +0 -0
  972. data/public/images/layout_header.png +0 -0
  973. data/public/images/layout_link.png +0 -0
  974. data/public/images/layout_sidebar.png +0 -0
  975. data/public/images/lightbulb.png +0 -0
  976. data/public/images/lightbulb_add.png +0 -0
  977. data/public/images/lightbulb_delete.png +0 -0
  978. data/public/images/lightbulb_off.png +0 -0
  979. data/public/images/lightning.png +0 -0
  980. data/public/images/lightning_add.png +0 -0
  981. data/public/images/lightning_delete.png +0 -0
  982. data/public/images/lightning_go.png +0 -0
  983. data/public/images/link.png +0 -0
  984. data/public/images/link_add.png +0 -0
  985. data/public/images/link_break.png +0 -0
  986. data/public/images/link_delete.png +0 -0
  987. data/public/images/link_edit.png +0 -0
  988. data/public/images/link_error.png +0 -0
  989. data/public/images/link_go.png +0 -0
  990. data/public/images/lock.png +0 -0
  991. data/public/images/lock_add.png +0 -0
  992. data/public/images/lock_break.png +0 -0
  993. data/public/images/lock_delete.png +0 -0
  994. data/public/images/lock_edit.png +0 -0
  995. data/public/images/lock_go.png +0 -0
  996. data/public/images/lock_open.png +0 -0
  997. data/public/images/lorry.png +0 -0
  998. data/public/images/lorry_add.png +0 -0
  999. data/public/images/lorry_delete.png +0 -0
  1000. data/public/images/lorry_error.png +0 -0
  1001. data/public/images/lorry_flatbed.png +0 -0
  1002. data/public/images/lorry_go.png +0 -0
  1003. data/public/images/lorry_link.png +0 -0
  1004. data/public/images/magifier_zoom_out.png +0 -0
  1005. data/public/images/magnifier.png +0 -0
  1006. data/public/images/magnifier_zoom_in.png +0 -0
  1007. data/public/images/male.png +0 -0
  1008. data/public/images/map.png +0 -0
  1009. data/public/images/map_add.png +0 -0
  1010. data/public/images/map_delete.png +0 -0
  1011. data/public/images/map_edit.png +0 -0
  1012. data/public/images/map_go.png +0 -0
  1013. data/public/images/map_magnify.png +0 -0
  1014. data/public/images/medal_bronze_1.png +0 -0
  1015. data/public/images/medal_bronze_2.png +0 -0
  1016. data/public/images/medal_bronze_3.png +0 -0
  1017. data/public/images/medal_bronze_add.png +0 -0
  1018. data/public/images/medal_bronze_delete.png +0 -0
  1019. data/public/images/medal_gold_1.png +0 -0
  1020. data/public/images/medal_gold_2.png +0 -0
  1021. data/public/images/medal_gold_3.png +0 -0
  1022. data/public/images/medal_gold_add.png +0 -0
  1023. data/public/images/medal_gold_delete.png +0 -0
  1024. data/public/images/medal_silver_1.png +0 -0
  1025. data/public/images/medal_silver_2.png +0 -0
  1026. data/public/images/medal_silver_3.png +0 -0
  1027. data/public/images/medal_silver_add.png +0 -0
  1028. data/public/images/medal_silver_delete.png +0 -0
  1029. data/public/images/money.png +0 -0
  1030. data/public/images/money_add.png +0 -0
  1031. data/public/images/money_delete.png +0 -0
  1032. data/public/images/money_dollar.png +0 -0
  1033. data/public/images/money_euro.png +0 -0
  1034. data/public/images/money_pound.png +0 -0
  1035. data/public/images/money_yen.png +0 -0
  1036. data/public/images/monitor.png +0 -0
  1037. data/public/images/monitor_add.png +0 -0
  1038. data/public/images/monitor_delete.png +0 -0
  1039. data/public/images/monitor_edit.png +0 -0
  1040. data/public/images/monitor_error.png +0 -0
  1041. data/public/images/monitor_go.png +0 -0
  1042. data/public/images/monitor_lightning.png +0 -0
  1043. data/public/images/monitor_link.png +0 -0
  1044. data/public/images/mouse.png +0 -0
  1045. data/public/images/mouse_add.png +0 -0
  1046. data/public/images/mouse_delete.png +0 -0
  1047. data/public/images/mouse_error.png +0 -0
  1048. data/public/images/music.png +0 -0
  1049. data/public/images/new.png +0 -0
  1050. data/public/images/newspaper.png +0 -0
  1051. data/public/images/newspaper_add.png +0 -0
  1052. data/public/images/newspaper_delete.png +0 -0
  1053. data/public/images/newspaper_go.png +0 -0
  1054. data/public/images/newspaper_link.png +0 -0
  1055. data/public/images/note.png +0 -0
  1056. data/public/images/note_add.png +0 -0
  1057. data/public/images/note_delete.png +0 -0
  1058. data/public/images/note_edit.png +0 -0
  1059. data/public/images/note_error.png +0 -0
  1060. data/public/images/note_go.png +0 -0
  1061. data/public/images/overlays.png +0 -0
  1062. data/public/images/package.png +0 -0
  1063. data/public/images/package_add.png +0 -0
  1064. data/public/images/package_delete.png +0 -0
  1065. data/public/images/package_go.png +0 -0
  1066. data/public/images/package_green.png +0 -0
  1067. data/public/images/package_link.png +0 -0
  1068. data/public/images/page.png +0 -0
  1069. data/public/images/page_add.png +0 -0
  1070. data/public/images/page_attach.png +0 -0
  1071. data/public/images/page_code.png +0 -0
  1072. data/public/images/page_copy.png +0 -0
  1073. data/public/images/page_delete.png +0 -0
  1074. data/public/images/page_edit.png +0 -0
  1075. data/public/images/page_error.png +0 -0
  1076. data/public/images/page_excel.png +0 -0
  1077. data/public/images/page_find.png +0 -0
  1078. data/public/images/page_gear.png +0 -0
  1079. data/public/images/page_go.png +0 -0
  1080. data/public/images/page_green.png +0 -0
  1081. data/public/images/page_key.png +0 -0
  1082. data/public/images/page_lightning.png +0 -0
  1083. data/public/images/page_link.png +0 -0
  1084. data/public/images/page_paintbrush.png +0 -0
  1085. data/public/images/page_paste.png +0 -0
  1086. data/public/images/page_red.png +0 -0
  1087. data/public/images/page_refresh.png +0 -0
  1088. data/public/images/page_save.png +0 -0
  1089. data/public/images/page_white.png +0 -0
  1090. data/public/images/page_white_acrobat.png +0 -0
  1091. data/public/images/page_white_actionscript.png +0 -0
  1092. data/public/images/page_white_add.png +0 -0
  1093. data/public/images/page_white_c.png +0 -0
  1094. data/public/images/page_white_camera.png +0 -0
  1095. data/public/images/page_white_cd.png +0 -0
  1096. data/public/images/page_white_code.png +0 -0
  1097. data/public/images/page_white_code_red.png +0 -0
  1098. data/public/images/page_white_coldfusion.png +0 -0
  1099. data/public/images/page_white_compressed.png +0 -0
  1100. data/public/images/page_white_copy.png +0 -0
  1101. data/public/images/page_white_cplusplus.png +0 -0
  1102. data/public/images/page_white_csharp.png +0 -0
  1103. data/public/images/page_white_cup.png +0 -0
  1104. data/public/images/page_white_database.png +0 -0
  1105. data/public/images/page_white_delete.png +0 -0
  1106. data/public/images/page_white_dvd.png +0 -0
  1107. data/public/images/page_white_edit.png +0 -0
  1108. data/public/images/page_white_error.png +0 -0
  1109. data/public/images/page_white_excel.png +0 -0
  1110. data/public/images/page_white_find.png +0 -0
  1111. data/public/images/page_white_flash.png +0 -0
  1112. data/public/images/page_white_freehand.png +0 -0
  1113. data/public/images/page_white_gear.png +0 -0
  1114. data/public/images/page_white_get.png +0 -0
  1115. data/public/images/page_white_go.png +0 -0
  1116. data/public/images/page_white_h.png +0 -0
  1117. data/public/images/page_white_horizontal.png +0 -0
  1118. data/public/images/page_white_key.png +0 -0
  1119. data/public/images/page_white_lightning.png +0 -0
  1120. data/public/images/page_white_link.png +0 -0
  1121. data/public/images/page_white_magnify.png +0 -0
  1122. data/public/images/page_white_medal.png +0 -0
  1123. data/public/images/page_white_office.png +0 -0
  1124. data/public/images/page_white_paint.png +0 -0
  1125. data/public/images/page_white_paintbrush.png +0 -0
  1126. data/public/images/page_white_paste.png +0 -0
  1127. data/public/images/page_white_php.png +0 -0
  1128. data/public/images/page_white_picture.png +0 -0
  1129. data/public/images/page_white_powerpoint.png +0 -0
  1130. data/public/images/page_white_put.png +0 -0
  1131. data/public/images/page_white_ruby.png +0 -0
  1132. data/public/images/page_white_stack.png +0 -0
  1133. data/public/images/page_white_star.png +0 -0
  1134. data/public/images/page_white_swoosh.png +0 -0
  1135. data/public/images/page_white_text.png +0 -0
  1136. data/public/images/page_white_text_width.png +0 -0
  1137. data/public/images/page_white_tux.png +0 -0
  1138. data/public/images/page_white_vector.png +0 -0
  1139. data/public/images/page_white_visualstudio.png +0 -0
  1140. data/public/images/page_white_width.png +0 -0
  1141. data/public/images/page_white_word.png +0 -0
  1142. data/public/images/page_white_world.png +0 -0
  1143. data/public/images/page_white_wrench.png +0 -0
  1144. data/public/images/page_white_zip.png +0 -0
  1145. data/public/images/page_word.png +0 -0
  1146. data/public/images/page_world.png +0 -0
  1147. data/public/images/paintbrush.png +0 -0
  1148. data/public/images/paintcan.png +0 -0
  1149. data/public/images/palette.png +0 -0
  1150. data/public/images/paste_plain.png +0 -0
  1151. data/public/images/paste_word.png +0 -0
  1152. data/public/images/pencil.png +0 -0
  1153. data/public/images/pencil_add.png +0 -0
  1154. data/public/images/pencil_delete.png +0 -0
  1155. data/public/images/pencil_go.png +0 -0
  1156. data/public/images/phone.png +0 -0
  1157. data/public/images/phone_add.png +0 -0
  1158. data/public/images/phone_delete.png +0 -0
  1159. data/public/images/phone_sound.png +0 -0
  1160. data/public/images/photo.png +0 -0
  1161. data/public/images/photo_add.png +0 -0
  1162. data/public/images/photo_blue.png +0 -0
  1163. data/public/images/photo_delete.png +0 -0
  1164. data/public/images/photo_grey.png +0 -0
  1165. data/public/images/photo_link.png +0 -0
  1166. data/public/images/photos.png +0 -0
  1167. data/public/images/picture.png +0 -0
  1168. data/public/images/picture_add.png +0 -0
  1169. data/public/images/picture_delete.png +0 -0
  1170. data/public/images/picture_edit.png +0 -0
  1171. data/public/images/picture_empty.png +0 -0
  1172. data/public/images/picture_error.png +0 -0
  1173. data/public/images/picture_go.png +0 -0
  1174. data/public/images/picture_key.png +0 -0
  1175. data/public/images/picture_link.png +0 -0
  1176. data/public/images/picture_save.png +0 -0
  1177. data/public/images/pictures.png +0 -0
  1178. data/public/images/pilcrow.png +0 -0
  1179. data/public/images/pill.png +0 -0
  1180. data/public/images/pill_add.png +0 -0
  1181. data/public/images/pill_delete.png +0 -0
  1182. data/public/images/pill_go.png +0 -0
  1183. data/public/images/plugin.png +0 -0
  1184. data/public/images/plugin_add.png +0 -0
  1185. data/public/images/plugin_delete.png +0 -0
  1186. data/public/images/plugin_disabled.png +0 -0
  1187. data/public/images/plugin_edit.png +0 -0
  1188. data/public/images/plugin_error.png +0 -0
  1189. data/public/images/plugin_go.png +0 -0
  1190. data/public/images/plugin_link.png +0 -0
  1191. data/public/images/printer.png +0 -0
  1192. data/public/images/printer_add.png +0 -0
  1193. data/public/images/printer_delete.png +0 -0
  1194. data/public/images/printer_empty.png +0 -0
  1195. data/public/images/printer_error.png +0 -0
  1196. data/public/images/project.png +0 -0
  1197. data/public/images/rails.png +0 -0
  1198. data/public/images/rainbow.png +0 -0
  1199. data/public/images/report.png +0 -0
  1200. data/public/images/report_add.png +0 -0
  1201. data/public/images/report_delete.png +0 -0
  1202. data/public/images/report_disk.png +0 -0
  1203. data/public/images/report_edit.png +0 -0
  1204. data/public/images/report_go.png +0 -0
  1205. data/public/images/report_key.png +0 -0
  1206. data/public/images/report_link.png +0 -0
  1207. data/public/images/report_magnify.png +0 -0
  1208. data/public/images/report_picture.png +0 -0
  1209. data/public/images/report_user.png +0 -0
  1210. data/public/images/report_word.png +0 -0
  1211. data/public/images/resultset_first.png +0 -0
  1212. data/public/images/resultset_last.png +0 -0
  1213. data/public/images/resultset_next.png +0 -0
  1214. data/public/images/resultset_previous.png +0 -0
  1215. data/public/images/rosette.png +0 -0
  1216. data/public/images/row_add.png +0 -0
  1217. data/public/images/row_delete.png +0 -0
  1218. data/public/images/rss.png +0 -0
  1219. data/public/images/rss_add.png +0 -0
  1220. data/public/images/rss_delete.png +0 -0
  1221. data/public/images/rss_go.png +0 -0
  1222. data/public/images/rss_valid.png +0 -0
  1223. data/public/images/ruby.png +0 -0
  1224. data/public/images/ruby_add.png +0 -0
  1225. data/public/images/ruby_delete.png +0 -0
  1226. data/public/images/ruby_gear.png +0 -0
  1227. data/public/images/ruby_get.png +0 -0
  1228. data/public/images/ruby_go.png +0 -0
  1229. data/public/images/ruby_key.png +0 -0
  1230. data/public/images/ruby_link.png +0 -0
  1231. data/public/images/ruby_put.png +0 -0
  1232. data/public/images/script.png +0 -0
  1233. data/public/images/script_add.png +0 -0
  1234. data/public/images/script_code.png +0 -0
  1235. data/public/images/script_code_red.png +0 -0
  1236. data/public/images/script_delete.png +0 -0
  1237. data/public/images/script_edit.png +0 -0
  1238. data/public/images/script_error.png +0 -0
  1239. data/public/images/script_gear.png +0 -0
  1240. data/public/images/script_go.png +0 -0
  1241. data/public/images/script_key.png +0 -0
  1242. data/public/images/script_lightning.png +0 -0
  1243. data/public/images/script_link.png +0 -0
  1244. data/public/images/script_palette.png +0 -0
  1245. data/public/images/script_save.png +0 -0
  1246. data/public/images/server.png +0 -0
  1247. data/public/images/server_add.png +0 -0
  1248. data/public/images/server_chart.png +0 -0
  1249. data/public/images/server_compressed.png +0 -0
  1250. data/public/images/server_connect.png +0 -0
  1251. data/public/images/server_database.png +0 -0
  1252. data/public/images/server_delete.png +0 -0
  1253. data/public/images/server_edit.png +0 -0
  1254. data/public/images/server_error.png +0 -0
  1255. data/public/images/server_go.png +0 -0
  1256. data/public/images/server_key.png +0 -0
  1257. data/public/images/server_lightning.png +0 -0
  1258. data/public/images/server_link.png +0 -0
  1259. data/public/images/server_uncompressed.png +0 -0
  1260. data/public/images/shading.png +0 -0
  1261. data/public/images/shape_align_bottom.png +0 -0
  1262. data/public/images/shape_align_center.png +0 -0
  1263. data/public/images/shape_align_left.png +0 -0
  1264. data/public/images/shape_align_middle.png +0 -0
  1265. data/public/images/shape_align_right.png +0 -0
  1266. data/public/images/shape_align_top.png +0 -0
  1267. data/public/images/shape_flip_horizontal.png +0 -0
  1268. data/public/images/shape_flip_vertical.png +0 -0
  1269. data/public/images/shape_group.png +0 -0
  1270. data/public/images/shape_handles.png +0 -0
  1271. data/public/images/shape_move_back.png +0 -0
  1272. data/public/images/shape_move_backwards.png +0 -0
  1273. data/public/images/shape_move_forwards.png +0 -0
  1274. data/public/images/shape_move_front.png +0 -0
  1275. data/public/images/shape_rotate_anticlockwise.png +0 -0
  1276. data/public/images/shape_rotate_clockwise.png +0 -0
  1277. data/public/images/shape_square.png +0 -0
  1278. data/public/images/shape_square_add.png +0 -0
  1279. data/public/images/shape_square_delete.png +0 -0
  1280. data/public/images/shape_square_edit.png +0 -0
  1281. data/public/images/shape_square_error.png +0 -0
  1282. data/public/images/shape_square_go.png +0 -0
  1283. data/public/images/shape_square_key.png +0 -0
  1284. data/public/images/shape_square_link.png +0 -0
  1285. data/public/images/shape_ungroup.png +0 -0
  1286. data/public/images/shield.png +0 -0
  1287. data/public/images/shield_add.png +0 -0
  1288. data/public/images/shield_delete.png +0 -0
  1289. data/public/images/shield_go.png +0 -0
  1290. data/public/images/silk.html +1495 -0
  1291. data/public/images/sitemap.png +0 -0
  1292. data/public/images/sitemap_color.png +0 -0
  1293. data/public/images/sound.png +0 -0
  1294. data/public/images/sound_add.png +0 -0
  1295. data/public/images/sound_delete.png +0 -0
  1296. data/public/images/sound_low.png +0 -0
  1297. data/public/images/sound_mute.png +0 -0
  1298. data/public/images/sound_none.png +0 -0
  1299. data/public/images/spellcheck.png +0 -0
  1300. data/public/images/sport_8ball.png +0 -0
  1301. data/public/images/sport_basketball.png +0 -0
  1302. data/public/images/sport_football.png +0 -0
  1303. data/public/images/sport_golf.png +0 -0
  1304. data/public/images/sport_raquet.png +0 -0
  1305. data/public/images/sport_shuttlecock.png +0 -0
  1306. data/public/images/sport_soccer.png +0 -0
  1307. data/public/images/sport_tennis.png +0 -0
  1308. data/public/images/star.png +0 -0
  1309. data/public/images/status_away.png +0 -0
  1310. data/public/images/status_busy.png +0 -0
  1311. data/public/images/status_offline.png +0 -0
  1312. data/public/images/status_online.png +0 -0
  1313. data/public/images/stop.png +0 -0
  1314. data/public/images/style.png +0 -0
  1315. data/public/images/style_add.png +0 -0
  1316. data/public/images/style_delete.png +0 -0
  1317. data/public/images/style_edit.png +0 -0
  1318. data/public/images/style_go.png +0 -0
  1319. data/public/images/sum.png +0 -0
  1320. data/public/images/swf/xspf/Main.as +55 -0
  1321. data/public/images/swf/xspf/com/zuardi/musicplayer/MusicButton.as +557 -0
  1322. data/public/images/swf/xspf/com/zuardi/musicplayer/MusicPlayer.as +118 -0
  1323. data/public/images/swf/xspf/com/zuardi/musicplayer/Playlist.as +127 -0
  1324. data/public/images/swf/xspf/com/zuardi/musicplayer/ProgressiveSlider.as +66 -0
  1325. data/public/images/swf/xspf/license.txt +10 -0
  1326. data/public/images/swf/xspf/musicplayer.swf +0 -0
  1327. data/public/images/swf/xspf/musicplayer_f6.swf +0 -0
  1328. data/public/images/swf/xspf/musicplayerbtn.fla +0 -0
  1329. data/public/images/swf/xspf/parameters.as +39 -0
  1330. data/public/images/tab.png +0 -0
  1331. data/public/images/tab_add.png +0 -0
  1332. data/public/images/tab_delete.png +0 -0
  1333. data/public/images/tab_edit.png +0 -0
  1334. data/public/images/tab_go.png +0 -0
  1335. data/public/images/table.png +0 -0
  1336. data/public/images/table_add.png +0 -0
  1337. data/public/images/table_delete.png +0 -0
  1338. data/public/images/table_edit.png +0 -0
  1339. data/public/images/table_error.png +0 -0
  1340. data/public/images/table_gear.png +0 -0
  1341. data/public/images/table_go.png +0 -0
  1342. data/public/images/table_key.png +0 -0
  1343. data/public/images/table_lightning.png +0 -0
  1344. data/public/images/table_link.png +0 -0
  1345. data/public/images/table_multiple.png +0 -0
  1346. data/public/images/table_refresh.png +0 -0
  1347. data/public/images/table_relationship.png +0 -0
  1348. data/public/images/table_row_delete.png +0 -0
  1349. data/public/images/table_row_insert.png +0 -0
  1350. data/public/images/table_save.png +0 -0
  1351. data/public/images/table_sort.png +0 -0
  1352. data/public/images/tag.png +0 -0
  1353. data/public/images/tag_blue.png +0 -0
  1354. data/public/images/tag_blue_add.png +0 -0
  1355. data/public/images/tag_blue_delete.png +0 -0
  1356. data/public/images/tag_blue_edit.png +0 -0
  1357. data/public/images/tag_green.png +0 -0
  1358. data/public/images/tag_orange.png +0 -0
  1359. data/public/images/tag_pink.png +0 -0
  1360. data/public/images/tag_purple.png +0 -0
  1361. data/public/images/tag_red.png +0 -0
  1362. data/public/images/tag_yellow.png +0 -0
  1363. data/public/images/target.png +0 -0
  1364. data/public/images/telephone.png +0 -0
  1365. data/public/images/telephone_add.png +0 -0
  1366. data/public/images/telephone_delete.png +0 -0
  1367. data/public/images/telephone_edit.png +0 -0
  1368. data/public/images/telephone_error.png +0 -0
  1369. data/public/images/telephone_go.png +0 -0
  1370. data/public/images/telephone_key.png +0 -0
  1371. data/public/images/telephone_link.png +0 -0
  1372. data/public/images/television.png +0 -0
  1373. data/public/images/television_add.png +0 -0
  1374. data/public/images/television_delete.png +0 -0
  1375. data/public/images/text_align_center.png +0 -0
  1376. data/public/images/text_align_justify.png +0 -0
  1377. data/public/images/text_align_left.png +0 -0
  1378. data/public/images/text_align_right.png +0 -0
  1379. data/public/images/text_allcaps.png +0 -0
  1380. data/public/images/text_bold.png +0 -0
  1381. data/public/images/text_columns.png +0 -0
  1382. data/public/images/text_dropcaps.png +0 -0
  1383. data/public/images/text_heading_1.png +0 -0
  1384. data/public/images/text_heading_2.png +0 -0
  1385. data/public/images/text_heading_3.png +0 -0
  1386. data/public/images/text_heading_4.png +0 -0
  1387. data/public/images/text_heading_5.png +0 -0
  1388. data/public/images/text_heading_6.png +0 -0
  1389. data/public/images/text_horizontalrule.png +0 -0
  1390. data/public/images/text_indent.png +0 -0
  1391. data/public/images/text_indent_remove.png +0 -0
  1392. data/public/images/text_italic.png +0 -0
  1393. data/public/images/text_kerning.png +0 -0
  1394. data/public/images/text_letter_omega.png +0 -0
  1395. data/public/images/text_letterspacing.png +0 -0
  1396. data/public/images/text_linespacing.png +0 -0
  1397. data/public/images/text_list_bullets.png +0 -0
  1398. data/public/images/text_list_numbers.png +0 -0
  1399. data/public/images/text_lowercase.png +0 -0
  1400. data/public/images/text_padding_bottom.png +0 -0
  1401. data/public/images/text_padding_left.png +0 -0
  1402. data/public/images/text_padding_right.png +0 -0
  1403. data/public/images/text_padding_top.png +0 -0
  1404. data/public/images/text_replace.png +0 -0
  1405. data/public/images/text_signature.png +0 -0
  1406. data/public/images/text_smallcaps.png +0 -0
  1407. data/public/images/text_strikethrough.png +0 -0
  1408. data/public/images/text_subscript.png +0 -0
  1409. data/public/images/text_superscript.png +0 -0
  1410. data/public/images/text_underline.png +0 -0
  1411. data/public/images/text_uppercase.png +0 -0
  1412. data/public/images/textfield.png +0 -0
  1413. data/public/images/textfield_add.png +0 -0
  1414. data/public/images/textfield_delete.png +0 -0
  1415. data/public/images/textfield_key.png +0 -0
  1416. data/public/images/textfield_rename.png +0 -0
  1417. data/public/images/thumb_down.png +0 -0
  1418. data/public/images/thumb_up.png +0 -0
  1419. data/public/images/tick.png +0 -0
  1420. data/public/images/time.png +0 -0
  1421. data/public/images/time_add.png +0 -0
  1422. data/public/images/time_delete.png +0 -0
  1423. data/public/images/time_go.png +0 -0
  1424. data/public/images/timeline_marker.png +0 -0
  1425. data/public/images/transmit.png +0 -0
  1426. data/public/images/transmit_add.png +0 -0
  1427. data/public/images/transmit_blue.png +0 -0
  1428. data/public/images/transmit_delete.png +0 -0
  1429. data/public/images/transmit_edit.png +0 -0
  1430. data/public/images/transmit_error.png +0 -0
  1431. data/public/images/transmit_go.png +0 -0
  1432. data/public/images/tux.png +0 -0
  1433. data/public/images/user.png +0 -0
  1434. data/public/images/user_add.png +0 -0
  1435. data/public/images/user_admin.png +0 -0
  1436. data/public/images/user_comment.png +0 -0
  1437. data/public/images/user_delete.png +0 -0
  1438. data/public/images/user_edit.png +0 -0
  1439. data/public/images/user_female.png +0 -0
  1440. data/public/images/user_go.png +0 -0
  1441. data/public/images/user_gray.png +0 -0
  1442. data/public/images/user_green.png +0 -0
  1443. data/public/images/user_orange.png +0 -0
  1444. data/public/images/user_pub.png +0 -0
  1445. data/public/images/user_red.png +0 -0
  1446. data/public/images/user_su.png +0 -0
  1447. data/public/images/user_suit.png +0 -0
  1448. data/public/images/validate.png +0 -0
  1449. data/public/images/valider.png +0 -0
  1450. data/public/images/vcard.png +0 -0
  1451. data/public/images/vcard_add.png +0 -0
  1452. data/public/images/vcard_delete.png +0 -0
  1453. data/public/images/vcard_edit.png +0 -0
  1454. data/public/images/vector.png +0 -0
  1455. data/public/images/vector_add.png +0 -0
  1456. data/public/images/vector_delete.png +0 -0
  1457. data/public/images/wand.png +0 -0
  1458. data/public/images/weather_clouds.png +0 -0
  1459. data/public/images/weather_cloudy.png +0 -0
  1460. data/public/images/weather_lightning.png +0 -0
  1461. data/public/images/weather_rain.png +0 -0
  1462. data/public/images/weather_snow.png +0 -0
  1463. data/public/images/weather_sun.png +0 -0
  1464. data/public/images/webcam.png +0 -0
  1465. data/public/images/webcam_add.png +0 -0
  1466. data/public/images/webcam_delete.png +0 -0
  1467. data/public/images/webcam_error.png +0 -0
  1468. data/public/images/world.png +0 -0
  1469. data/public/images/world_add.png +0 -0
  1470. data/public/images/world_delete.png +0 -0
  1471. data/public/images/world_edit.png +0 -0
  1472. data/public/images/world_go.png +0 -0
  1473. data/public/images/world_link.png +0 -0
  1474. data/public/images/wrench.png +0 -0
  1475. data/public/images/wrench_orange.png +0 -0
  1476. data/public/images/xhtml.png +0 -0
  1477. data/public/images/xhtml_add.png +0 -0
  1478. data/public/images/xhtml_delete.png +0 -0
  1479. data/public/images/xhtml_go.png +0 -0
  1480. data/public/images/xhtml_valid.png +0 -0
  1481. data/public/images/zoom.png +0 -0
  1482. data/public/images/zoom_in.png +0 -0
  1483. data/public/images/zoom_out.png +0 -0
  1484. data/public/img/logo.png +0 -0
  1485. data/public/javascripts/application.js +2 -0
  1486. data/public/javascripts/builder.js +136 -0
  1487. data/public/javascripts/controls.js +965 -0
  1488. data/public/javascripts/dragdrop.js +975 -0
  1489. data/public/javascripts/effects.js +1130 -0
  1490. data/public/javascripts/prototype.js +4320 -0
  1491. data/public/javascripts/scriptaculous.js +60 -0
  1492. data/public/javascripts/slider.js +275 -0
  1493. data/public/javascripts/sound.js +55 -0
  1494. data/public/javascripts/tablekit.js +965 -0
  1495. data/public/javascripts/unittest.js +568 -0
  1496. data/public/javascripts/upload-progress.js +133 -0
  1497. data/public/javascripts/zena.js +501 -0
  1498. data/public/robots.txt +1 -0
  1499. data/public/stylesheets/admin.css +77 -0
  1500. data/public/stylesheets/calendar.css +55 -0
  1501. data/public/stylesheets/code.css +67 -0
  1502. data/public/stylesheets/comment.css +43 -0
  1503. data/public/stylesheets/csshover2.htc +121 -0
  1504. data/public/stylesheets/default.css +85 -0
  1505. data/public/stylesheets/popup.css +200 -0
  1506. data/public/stylesheets/reset.css +33 -0
  1507. data/public/stylesheets/search.css +19 -0
  1508. data/public/stylesheets/upload-progress.css +4 -0
  1509. data/public/stylesheets/wiki.css +100 -0
  1510. data/public/stylesheets/zen.css +230 -0
  1511. data/public/stylesheets/zena.css +78 -0
  1512. data/rails/init.rb +2 -0
  1513. data/tasks/ann.rake +80 -0
  1514. data/tasks/bones.rake +20 -0
  1515. data/tasks/gem.rake +201 -0
  1516. data/tasks/git.rake +40 -0
  1517. data/tasks/notes.rake +27 -0
  1518. data/tasks/post_load.rake +34 -0
  1519. data/tasks/rdoc.rake +51 -0
  1520. data/tasks/rubyforge.rake +55 -0
  1521. data/tasks/setup.rb +292 -0
  1522. data/tasks/spec.rake +54 -0
  1523. data/tasks/svn.rake +47 -0
  1524. data/tasks/test.rake +40 -0
  1525. data/tasks/zentest.rake +36 -0
  1526. data/test/fixtures/comments.yml +126 -0
  1527. data/test/fixtures/contact_contents.yml +132 -0
  1528. data/test/fixtures/data_entries.yml +65 -0
  1529. data/test/fixtures/discussions.yml +48 -0
  1530. data/test/fixtures/document_contents.yml +108 -0
  1531. data/test/fixtures/dyn_attributes.yml +66 -0
  1532. data/test/fixtures/files/Node-test.zafu +307 -0
  1533. data/test/fixtures/files/bird.jpg +0 -0
  1534. data/test/fixtures/files/bomb.png +0 -0
  1535. data/test/fixtures/files/exif_sample.jpg +0 -0
  1536. data/test/fixtures/files/flower.jpg +0 -0
  1537. data/test/fixtures/files/forest.pdf +0 -0
  1538. data/test/fixtures/files/import.tgz +0 -0
  1539. data/test/fixtures/files/jet_30.zip +0 -0
  1540. data/test/fixtures/files/lake.jpg +0 -0
  1541. data/test/fixtures/files/letter.zip +0 -0
  1542. data/test/fixtures/files/other.txt +1 -0
  1543. data/test/fixtures/files/simple.zml.gz +0 -0
  1544. data/test/fixtures/files/some.txt +1 -0
  1545. data/test/fixtures/files/translations_de.yml +4 -0
  1546. data/test/fixtures/files/translations_fr.yml +4 -0
  1547. data/test/fixtures/files/tree.jpg +0 -0
  1548. data/test/fixtures/files/water.pdf +0 -0
  1549. data/test/fixtures/groups.yml +86 -0
  1550. data/test/fixtures/groups_users.yml +81 -0
  1551. data/test/fixtures/iformats.yml +28 -0
  1552. data/test/fixtures/import/photos.en.zml +11 -0
  1553. data/test/fixtures/import/photos/bird.jpg +0 -0
  1554. data/test/fixtures/import/photos/bird.jpg.en.zml +1 -0
  1555. data/test/fixtures/import/photos/bird.jpg.fr.zml +1 -0
  1556. data/test/fixtures/import/photos/document.yml.en +4 -0
  1557. data/test/fixtures/import/photos/document.yml.fr +4 -0
  1558. data/test/fixtures/import/simple.zml +8 -0
  1559. data/test/fixtures/links.yml +313 -0
  1560. data/test/fixtures/nodes.yml +2592 -0
  1561. data/test/fixtures/relations.yml +126 -0
  1562. data/test/fixtures/sites.yml +58 -0
  1563. data/test/fixtures/template_contents.yml +172 -0
  1564. data/test/fixtures/users.yml +167 -0
  1565. data/test/fixtures/versions.yml +1909 -0
  1566. data/test/fixtures/virtual_classes.yml +87 -0
  1567. data/test/fixtures/zips.yml +15 -0
  1568. data/test/functional/application_controller_test.rb +136 -0
  1569. data/test/functional/calendar_controller_test.rb +25 -0
  1570. data/test/functional/comments_controller_test.rb +59 -0
  1571. data/test/functional/data_entries_controller_test.rb +22 -0
  1572. data/test/functional/discussion_controller_test.rb +20 -0
  1573. data/test/functional/documents_controller_test.rb +155 -0
  1574. data/test/functional/groups_controller_test.rb +109 -0
  1575. data/test/functional/iformats_controller_test.rb +115 -0
  1576. data/test/functional/links_controller_test.rb +26 -0
  1577. data/test/functional/nodes_controller_test.rb +448 -0
  1578. data/test/functional/note_controller_test.rb +53 -0
  1579. data/test/functional/preferences_controller_test.rb +11 -0
  1580. data/test/functional/relations_controller_test.rb +55 -0
  1581. data/test/functional/search_controller_test.rb +41 -0
  1582. data/test/functional/sessions_controller_test.rb +73 -0
  1583. data/test/functional/sites_controller_test.rb +102 -0
  1584. data/test/functional/users_controller_test.rb +28 -0
  1585. data/test/functional/versions_controller_test.rb +99 -0
  1586. data/test/functional/virtual_classes_controller_test.rb +62 -0
  1587. data/test/helpers/node_query/basic.yml +149 -0
  1588. data/test/helpers/node_query/comments.yml +18 -0
  1589. data/test/helpers/node_query/complex.yml +98 -0
  1590. data/test/helpers/node_query/filters.yml +105 -0
  1591. data/test/helpers/node_query/relations.yml +43 -0
  1592. data/test/helpers/node_query_test.rb +117 -0
  1593. data/test/integration/multiple_hosts_test.rb +98 -0
  1594. data/test/integration/multiversion_test.rb +164 -0
  1595. data/test/integration/navigation_test.rb +283 -0
  1596. data/test/sites/README +2 -0
  1597. data/test/sites/complex/complex.png +0 -0
  1598. data/test/sites/complex/groups.yml +9 -0
  1599. data/test/sites/complex/links.yml +75 -0
  1600. data/test/sites/complex/nodes.yml +253 -0
  1601. data/test/sites/complex/relations.yml +11 -0
  1602. data/test/sites/complex/sites.yml +13 -0
  1603. data/test/sites/complex/users.yml +20 -0
  1604. data/test/sites/complex/versions.yml +1 -0
  1605. data/test/sites/complex/virtual_classes.yml +19 -0
  1606. data/test/sites/ocean/contact_contents.yml +19 -0
  1607. data/test/sites/ocean/groups.yml +9 -0
  1608. data/test/sites/ocean/iformats.yml +7 -0
  1609. data/test/sites/ocean/nodes.yml +36 -0
  1610. data/test/sites/ocean/sites.yml +14 -0
  1611. data/test/sites/ocean/template_contents.yml +8 -0
  1612. data/test/sites/ocean/users.yml +33 -0
  1613. data/test/sites/ocean/versions.yml +48 -0
  1614. data/test/sites/zena/comments.yml +82 -0
  1615. data/test/sites/zena/contact_contents.yml +55 -0
  1616. data/test/sites/zena/data_entries.yml +42 -0
  1617. data/test/sites/zena/discussions.yml +30 -0
  1618. data/test/sites/zena/document_contents.yml +76 -0
  1619. data/test/sites/zena/dyn_attributes.yml +43 -0
  1620. data/test/sites/zena/groups.yml +11 -0
  1621. data/test/sites/zena/iformats.yml +6 -0
  1622. data/test/sites/zena/links.yml +49 -0
  1623. data/test/sites/zena/nodes.yml +338 -0
  1624. data/test/sites/zena/relations.yml +66 -0
  1625. data/test/sites/zena/sites.yml +13 -0
  1626. data/test/sites/zena/template_contents.yml +103 -0
  1627. data/test/sites/zena/users.yml +48 -0
  1628. data/test/sites/zena/versions.yml +558 -0
  1629. data/test/sites/zena/virtual_classes.yml +23 -0
  1630. data/test/test_helper.rb +62 -0
  1631. data/test/test_zena.rb +138 -0
  1632. data/test/unit/cache_test.rb +62 -0
  1633. data/test/unit/cached_page_test.rb +165 -0
  1634. data/test/unit/comment_test.rb +185 -0
  1635. data/test/unit/contact_content_test.rb +33 -0
  1636. data/test/unit/contact_test.rb +39 -0
  1637. data/test/unit/contact_version_test.rb +48 -0
  1638. data/test/unit/core_ext_test.rb +48 -0
  1639. data/test/unit/data_entry_test.rb +92 -0
  1640. data/test/unit/discussion_test.rb +59 -0
  1641. data/test/unit/document_content_test.rb +110 -0
  1642. data/test/unit/document_test.rb +234 -0
  1643. data/test/unit/document_version_test.rb +11 -0
  1644. data/test/unit/dyn_attributes_test.rb +229 -0
  1645. data/test/unit/exif_data_test.rb +66 -0
  1646. data/test/unit/group_test.rb +142 -0
  1647. data/test/unit/iformat_test.rb +190 -0
  1648. data/test/unit/image_builder_test.rb +214 -0
  1649. data/test/unit/image_content_test.rb +154 -0
  1650. data/test/unit/image_test.rb +311 -0
  1651. data/test/unit/image_version_test.rb +18 -0
  1652. data/test/unit/letter_test.rb +9 -0
  1653. data/test/unit/link_test.rb +32 -0
  1654. data/test/unit/multiversion_test.rb +1008 -0
  1655. data/test/unit/node_test.rb +1578 -0
  1656. data/test/unit/note_test.rb +85 -0
  1657. data/test/unit/page_test.rb +79 -0
  1658. data/test/unit/project_test.rb +32 -0
  1659. data/test/unit/reference_test.rb +9 -0
  1660. data/test/unit/relation_proxy_test.rb +409 -0
  1661. data/test/unit/relation_test.rb +48 -0
  1662. data/test/unit/section_test.rb +32 -0
  1663. data/test/unit/secure_test.rb +939 -0
  1664. data/test/unit/site_test.rb +236 -0
  1665. data/test/unit/skin_test.rb +18 -0
  1666. data/test/unit/template_content_test.rb +9 -0
  1667. data/test/unit/template_test.rb +357 -0
  1668. data/test/unit/template_version_test.rb +7 -0
  1669. data/test/unit/text_document_content_test.rb +8 -0
  1670. data/test/unit/text_document_test.rb +139 -0
  1671. data/test/unit/text_document_version_test.rb +37 -0
  1672. data/test/unit/user_test.rb +295 -0
  1673. data/test/unit/version_test.rb +312 -0
  1674. data/test/unit/virtual_class_test.rb +242 -0
  1675. data/test/unit/zena/db_test.rb +94 -0
  1676. data/test/unit/zena/parser/latex.yml +14 -0
  1677. data/test/unit/zena/parser/zafu.yml +391 -0
  1678. data/test/unit/zena/parser/zafu_asset.yml +43 -0
  1679. data/test/unit/zena/parser/zafu_insight.yml +3 -0
  1680. data/test/unit/zena/parser/zazen.yml +211 -0
  1681. data/test/unit/zena/parser_test.rb +184 -0
  1682. data/test/unit/zena/unit/test_case_test.rb +12 -0
  1683. data/test/unit/zena/use/calendar_test.rb +49 -0
  1684. data/test/unit/zena/use/dates_model_methods_test.rb +41 -0
  1685. data/test/unit/zena/use/dates_string_methods_test.rb +94 -0
  1686. data/test/unit/zena/use/dates_view_methods_test.rb +158 -0
  1687. data/test/unit/zena/use/html_tags_test.rb +244 -0
  1688. data/test/unit/zena/use/i18n_test.rb +34 -0
  1689. data/test/unit/zena/use/nested_attributes_alias_model_test.rb +104 -0
  1690. data/test/unit/zena/use/nested_attributes_alias_view_test.rb +99 -0
  1691. data/test/unit/zena/use/refactor_test.rb +52 -0
  1692. data/test/unit/zena/use/rendering_test.rb +23 -0
  1693. data/test/unit/zena/use/urls_test.rb +119 -0
  1694. data/test/unit/zena/use/zafu_test.rb +21 -0
  1695. data/test/unit/zena/use/zazen_test.rb +230 -0
  1696. data/test/unit/zena/zena_tags/ajax.yml +233 -0
  1697. data/test/unit/zena/zena_tags/apphelper.yml +85 -0
  1698. data/test/unit/zena/zena_tags/basic.yml +1295 -0
  1699. data/test/unit/zena/zena_tags/complex.yml +249 -0
  1700. data/test/unit/zena/zena_tags/data.yml +73 -0
  1701. data/test/unit/zena/zena_tags/errors.yml +71 -0
  1702. data/test/unit/zena/zena_tags/eval.yml +51 -0
  1703. data/test/unit/zena/zena_tags/relations.yml +411 -0
  1704. data/test/unit/zena/zena_tags/zazen.yml +84 -0
  1705. data/test/unit/zena/zena_tags_test.rb +235 -0
  1706. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run 2.tmCommand +24 -0
  1707. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Context.tmCommand +58 -0
  1708. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Focused Should.tmCommand +88 -0
  1709. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run.tmCommand +27 -0
  1710. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/YAML to Shoulda.tmCommand +23 -0
  1711. data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Context.tmPreferences +19 -0
  1712. data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Should.tmPreferences +19 -0
  1713. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory attributes for.tmSnippet +16 -0
  1714. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory build.tmSnippet +16 -0
  1715. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory.tmSnippet +16 -0
  1716. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define with class.tmSnippet +18 -0
  1717. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define.tmSnippet +18 -0
  1718. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_next.tmSnippet +16 -0
  1719. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_sequence.tmSnippet +18 -0
  1720. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_bad_value.tmSnippet +16 -0
  1721. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_contains.tmSnippet +16 -0
  1722. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_does_not_contain.tmSnippet +16 -0
  1723. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_good_value.tmSnippet +16 -0
  1724. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_same_elements.tmSnippet +16 -0
  1725. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_save.tmSnippet +16 -0
  1726. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_sent_email.tmSnippet +18 -0
  1727. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_valid.tmSnippet +16 -0
  1728. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/association.tmSnippet +17 -0
  1729. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/attribute.tmSnippet +17 -0
  1730. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/before_should block.tmSnippet +18 -0
  1731. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block get.tmSnippet +22 -0
  1732. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block post.tmSnippet +23 -0
  1733. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block with setup.tmSnippet +25 -0
  1734. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/setup.tmSnippet +18 -0
  1735. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block with before proc.tmSnippet +18 -0
  1736. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block.tmSnippet +18 -0
  1737. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_allow_values_for.tmSnippet +16 -0
  1738. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_assign_to.tmSnippet +16 -0
  1739. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful denied.tmSnippet +20 -0
  1740. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful.tmSnippet +20 -0
  1741. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_belong_to.tmSnippet +16 -0
  1742. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change by.tmSnippet +16 -0
  1743. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change from to.tmSnippet +16 -0
  1744. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_at_least.tmSnippet +16 -0
  1745. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_in_range.tmSnippet +16 -0
  1746. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_is.tmSnippet +16 -0
  1747. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_value_in_range.tmSnippet +16 -0
  1748. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_eventually.tmSnippet +18 -0
  1749. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_filter_params.tmSnippet +16 -0
  1750. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_and_belong_to_many.tmSnippet +16 -0
  1751. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_class_methods.tmSnippet +16 -0
  1752. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_column.tmSnippet +16 -0
  1753. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_columns.tmSnippet +16 -0
  1754. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_index.tmSnippet +16 -0
  1755. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_indices.tmSnippet +16 -0
  1756. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_instance_methods.tmSnippet +16 -0
  1757. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_many.tmSnippet +16 -0
  1758. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_named_scope.tmSnippet +16 -0
  1759. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_one.tmSnippet +16 -0
  1760. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_readonly_attributes.tmSnippet +16 -0
  1761. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_mass_assignment_of.tmSnippet +16 -0
  1762. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_values_for.tmSnippet +16 -0
  1763. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_assign_to.tmSnippet +16 -0
  1764. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_change.tmSnippet +16 -0
  1765. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_set_the_flash.tmSnippet +16 -0
  1766. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_redirect_to.tmSnippet +16 -0
  1767. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_a_form.tmSnippet +16 -0
  1768. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_template.tmSnippet +16 -0
  1769. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_with_layout.tmSnippet +16 -0
  1770. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_without_layout.tmSnippet +16 -0
  1771. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with.tmSnippet +16 -0
  1772. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with_content_type.tmSnippet +16 -0
  1773. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_return_from_session.tmSnippet +16 -0
  1774. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_route.tmSnippet +16 -0
  1775. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_set_the_flash_to.tmSnippet +16 -0
  1776. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_acceptance_of.tmSnippet +16 -0
  1777. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_numericality_of.tmSnippet +16 -0
  1778. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_presence_of.tmSnippet +16 -0
  1779. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of with scope.tmSnippet +16 -0
  1780. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of.tmSnippet +16 -0
  1781. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/catch_exception.rb +39 -0
  1782. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/run_script.rb +104 -0
  1783. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/stdin_dialog.rb +14 -0
  1784. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/test.rb +17 -0
  1785. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/todo.txt +13 -0
  1786. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/bin/yaml_to_shoulda.rb +25 -0
  1787. data/vendor/TextMate/Ruby Shoulda.tmbundle/Syntaxes/Ruby on Rails (Shoulda).tmLanguage +166 -0
  1788. data/vendor/TextMate/Ruby Shoulda.tmbundle/info.plist +304 -0
  1789. data/vendor/TextMate/Zena.tmbundle/Commands/Run all yaml tests.tmCommand +37 -0
  1790. data/vendor/TextMate/Zena.tmbundle/Commands/Run focused yaml test.tmCommand +53 -0
  1791. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/run_script.rb +74 -0
  1792. data/vendor/TextMate/Zena.tmbundle/info.plist +15 -0
  1793. data/vendor/apache_upload/mod_upload_progress.c +813 -0
  1794. data/vendor/bricks/20070122-172926.txt +282 -0
  1795. data/vendor/plugins/ar_mysql_full_text/README +15 -0
  1796. data/vendor/plugins/ar_mysql_full_text/init.rb +1 -0
  1797. data/vendor/plugins/ar_mysql_full_text/lib/ar_mysql_full_text.rb +69 -0
  1798. data/vendor/plugins/gettext_i18n_rails/README.markdown +139 -0
  1799. data/vendor/plugins/gettext_i18n_rails/Rakefile +6 -0
  1800. data/vendor/plugins/gettext_i18n_rails/init.rb +10 -0
  1801. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails.rb +21 -0
  1802. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/action_controller.rb +6 -0
  1803. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/active_record.rb +17 -0
  1804. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/backend.rb +47 -0
  1805. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/haml_parser.rb +43 -0
  1806. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb +10 -0
  1807. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/model_attributes_finder.rb +46 -0
  1808. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/ruby_gettext_extractor.rb +136 -0
  1809. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/action_controller_spec.rb +36 -0
  1810. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/active_record_spec.rb +50 -0
  1811. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/backend_spec.rb +41 -0
  1812. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails_spec.rb +43 -0
  1813. data/vendor/plugins/gettext_i18n_rails/spec/spec_helper.rb +15 -0
  1814. data/vendor/plugins/gettext_i18n_rails/tasks/gettext_rails_i18n.rake +73 -0
  1815. data/vendor/plugins/responds_to_parent/MIT-LICENSE +20 -0
  1816. data/vendor/plugins/responds_to_parent/README +42 -0
  1817. data/vendor/plugins/responds_to_parent/Rakefile +22 -0
  1818. data/vendor/plugins/responds_to_parent/init.rb +1 -0
  1819. data/vendor/plugins/responds_to_parent/lib/responds_to_parent.rb +46 -0
  1820. data/vendor/plugins/responds_to_parent/test/responds_to_parent_test.rb +115 -0
  1821. data/vendor/plugins/rjs-assertions/MIT-LICENSE +20 -0
  1822. data/vendor/plugins/rjs-assertions/README +64 -0
  1823. data/vendor/plugins/rjs-assertions/init.rb +1 -0
  1824. data/vendor/plugins/rjs-assertions/lib/rjs-assertions.rb +99 -0
  1825. data/vendor/rails_patches/support_for_inverse_relationships_on_active_record_objects.diff +739 -0
  1826. metadata +2075 -0
@@ -0,0 +1,44 @@
1
+ require 'redcloth'
2
+
3
+ module Zena
4
+ module Parser
5
+ module ZazenTags
6
+ # This is not exactly how compile/render is meant to work with Parser, but there is no real need for a two step
7
+ # rendering, so we compile here (enter(:void)) instead of doing this whith 'start'. This also lets us have the
8
+ # context during compilation which makes it easier to manage the callbacks to the helper.
9
+ def r_void
10
+ @context = {:images => true, :pretty_code=>true, :output => 'html'}.merge(@context)
11
+ @translate_ids = @context[:translate_ids]
12
+ @text = @text.gsub("\r\n","\n") # this also creates our own 'working' copy of the text
13
+ @blocks = "" # same reason as why we rewrite 'store'
14
+
15
+ extract_code(@text)
16
+
17
+ # set whether the first paragraphe is spaced preserved.
18
+ @in_space_pre = (@text[0..0] == ' ')
19
+
20
+ enter(:void) # <== parse here
21
+
22
+ unless @translate_ids
23
+ store '</pre>' if @in_space_pre
24
+
25
+ case @context[:output]
26
+ when 'html'
27
+ # TODO: we should write our own parser for textile with rendering formats...
28
+ @text = RedCloth.new(@blocks).to_html
29
+ when 'latex'
30
+ # replace RedCloth markup by latex equivalent
31
+ @text = RedCloth.new(@blocks).to_latex
32
+ end
33
+
34
+ # Replace placeholders by their real values
35
+ @helper.replace_placeholders(@text) if @helper.respond_to?('replace_placeholders')
36
+ @blocks = ""
37
+ enter(:wiki)
38
+ end
39
+ render_code(@blocks)
40
+ @blocks
41
+ end
42
+ end # ZazenTags
43
+ end # Parser
44
+ end # Zena
@@ -0,0 +1,29 @@
1
+ module Zena
2
+ module Parser
3
+ module ZenaRules
4
+ def start(mode)
5
+ super
6
+ if @method =~ /^\[(.*)\]$/
7
+ # do='[text]
8
+ @method = 'show'
9
+ @params[:attr_or_date] = $1
10
+ elsif @method =~ /^\{(.*)\}$/
11
+ # do='{v_text}'
12
+ @method = 'zazen'
13
+ @params[:attr] = $1
14
+ elsif @method =~ /\A(\w+)\s+(\w+)\s+(.+)$/
15
+ # 'pages where name ...'
16
+ @params[:select] = @method
17
+ @method = 'context'
18
+ end
19
+
20
+ if @method == 'with' || self.respond_to?("r_#{@method}")
21
+ # ok
22
+ else
23
+ @params[:select] = @method
24
+ @method = 'context'
25
+ end
26
+ end
27
+ end # ZenaRules
28
+ end # Parser
29
+ end # Zena
@@ -0,0 +1,3559 @@
1
+ =begin
2
+ Thoughts for ajax related stuff cleanup (dom_id, erb_dom_id, ...)
3
+
4
+ When we open a list context:
5
+ - we change the context_dom_id => unique name => "page"
6
+
7
+ When we open a single context (do_var, each, block):
8
+ - we change the context_dom_id => unique name with id => "page_{parent_id}"
9
+
10
+ Any 'id' is set with:
11
+ - "{context_dom_id}_{id}" => 'page_34' (if not in list) or 'page_12_34' if in list.
12
+
13
+
14
+ List in list (initial node zip = 12):
15
+ context_dom_id dom_id (context_erb_dom_id, erb_dom_id)
16
+ <ul> page_12 page_12 [pages in='site'] new unique name
17
+ <li id='page_12_13'> page_12 page_12_13 [each] expand_with(:context_dom_id => 'page_13')
18
+ <ul> page_13
19
+ <li id='page_13_23'/> page_13 page_13_23 [each]
20
+ <li id='page_13_24'/> page_13 page_13_24 [each]
21
+ <li id='page_13_25'/> page_13 page_13_25 [each]
22
+ </ul>
23
+ </li>
24
+ <li id='page_12_14'> page_12 page_12_14 [each] expand_with(:context_dom_id => 'page_14')
25
+ <ul>
26
+ <li id='page_14_23'/> page_14 page_14_23 [each] expand_with(:context_dom_id => 'page_23')
27
+ <li id='page_14_27'/> page_14 page_14_27 [each] ...
28
+ </ul>
29
+ </li>
30
+ </ul>
31
+
32
+ <div id='page1_12'> page1_12 page1_12 [block] new unique name
33
+ <ul>
34
+ <li id='page1_12_24'/> page1_12 page1_12_24 [each]
35
+ <li id='page1_12_32'/> page1_12 page1_12_32 [each]
36
+ </ul>
37
+ </div>
38
+ =end
39
+
40
+ require 'yaml'
41
+
42
+ module Zena
43
+ module Parser
44
+ # Zafu tags used to display / edit nodes and versions
45
+ module ZenaTags
46
+ PSEUDO_ATTRIBUTES = {
47
+ 'now' => 'Time.now',
48
+ 'start.id' => '(params[:s] || @node[:zip])',
49
+ 'nil' => 'nil',
50
+ }
51
+
52
+ class << self
53
+ def inline_methods(*args)
54
+ args.each do |name|
55
+ class_eval <<-END
56
+ def r_#{name}
57
+ "<%= #{name}(:node=>\#{node}\#{params_to_erb(@params)}) %>"
58
+ end
59
+ END
60
+ end
61
+ end
62
+
63
+ def direct_methods(*args)
64
+ args.each do |name|
65
+ class_eval <<-END
66
+ def r_#{name}
67
+ helper.#{name}
68
+ end
69
+ END
70
+ end
71
+ end
72
+ end
73
+ inline_methods :login_link, :visitor_link, :search_box, :show_menu, :show_path, :lang_links
74
+ direct_methods :uses_datebox
75
+
76
+ def before_render
77
+ return unless super
78
+
79
+ @var = nil # reset var counter
80
+
81
+ if key = @params[:store]
82
+ set_stored(Node, key, node)
83
+ end
84
+
85
+ if key = @params[:store_date]
86
+ set_stored(Date, key, current_date)
87
+ end
88
+ @anchor_param = @params[:anchor]
89
+
90
+ true
91
+ end
92
+
93
+ def do_method(sym)
94
+ method = sym
95
+ pre, post = '', ''
96
+
97
+ # do we need recursion ?
98
+ inc = descendant('include')
99
+ if inc && inc.params[:part] == @name
100
+ @context["#{@name}_method".to_sym] = method_name = template_url[1..-1].gsub(/[\/-]/,'_')
101
+ pre << "<% def #{method_name}(depth, node, list); return '' if depth > #{inc.params[:depth] ? [inc.params[:depth].to_i,30].min : 5}; _erbout = '' -%>"
102
+ post << "<% _erbout; end -%><%= #{method_name}(0,#{node},#{list || "[#{node}]"}) %>"
103
+ @context[:node] = 'node'
104
+ @context[:list] = 'list'
105
+ end
106
+
107
+ if @context[:make_form]
108
+ res = case method
109
+ when :r_title
110
+ make_input(:name => 'v_title')
111
+ when :r_link
112
+ make_input(:name => (@params[:attr] || 'v_title'))
113
+ when :r_show
114
+ make_input(:name => (@params[:attr] || @params[:tattr]), :date => @params[:date])
115
+ when :r_text
116
+ make_textarea(:name => 'v_text')
117
+ when :r_summary
118
+ make_textarea(:name => 'v_summary')
119
+ when :r_zazen
120
+ make_textarea(:name => @params[:attr])
121
+ else
122
+ if node_kind_of?(DataEntry) && @method.to_s =~ /node_/
123
+ # select node_id
124
+ "<%= select_id('#{base_class.to_s.underscore}', '#{@method}_id') %>"
125
+ end
126
+ end
127
+ res = "<#{@html_tag || 'div'} class='zazen'>#{res}</#{@html_tag || 'div'}>" if [:r_summary, :r_text].include?(sym)
128
+ end
129
+
130
+
131
+ res ||= super(method)
132
+ "#{pre}#{res}#{post}"
133
+ end
134
+
135
+
136
+ def after_render(text)
137
+ if @anchor_param
138
+ @params[:anchor] = @anchor_param # set back in case of double rendering so it is computed again
139
+ res = r_anchor + super
140
+ else
141
+ res = super
142
+ end
143
+ res
144
+ end
145
+
146
+ # Our special version of r_expand_with tag with "set_" parsing.
147
+ def r_expand_with
148
+ hash = {}
149
+ @params.each do |k,v|
150
+ if k.to_s =~ /^set_(.+)$/
151
+ # TODO: DRY with render_html_tag
152
+ k = $1
153
+ value, static = parse_attributes_in_value(v, :erb => false)
154
+ hash["exp_#{k}"] = static ? value.inspect : "\"#{value}\""
155
+ else
156
+ hash["exp_#{k}"] = v.inspect
157
+ end
158
+ end
159
+ @params = {}
160
+ expand_with(hash)
161
+ end
162
+
163
+ def r_show
164
+ if attr_or_date = @params[:attr_or_date]
165
+ # using [var] shortcut. Can be either a date or an attribute/var
166
+ if attr_or_date == 'current_date' || attr_or_date =~ /_at$/
167
+ @params[:date] = attr_or_date
168
+ else
169
+ @params[:attr] = attr_or_date
170
+ end
171
+ end
172
+
173
+ if var_name = @params[:var]
174
+ return parser_error("var #{@params[:var].inspect} not set") unless @context[:vars] && @context[:vars].include?(var_name)
175
+ attribute_method = "set_#{var_name}"
176
+ elsif @params[:eval]
177
+ return unless attribute_method = parse_eval_parameter(@params[:eval])
178
+ elsif @params[:tattr]
179
+ attribute_method = "_(#{node_attribute(@params[:tattr], :else=>@params[:else], :default=>@params[:default])})"
180
+ elsif @params[:attr]
181
+ attribute_method = node_attribute(@params[:attr], :else=>@params[:else], :default=>@params[:default])
182
+ elsif p = @params[:param]
183
+ return "<%= params[#{p.to_sym.inspect}] %>"
184
+ elsif @params[:date]
185
+ # date can be any attribute v_created_at or updated_at etc.
186
+ # TODO format with @params[:format] and @params[:tformat] << translated format
187
+ # TODO: test
188
+ if @params[:tformat]
189
+ format = _(@params[:tformat])
190
+ elsif @params[:format]
191
+ format = @params[:format]
192
+ else
193
+ format = "%Y-%m-%d"
194
+ end
195
+
196
+ tz = ''
197
+ lang = ''
198
+ if tz_name = @params[:time_zone]
199
+ tz_list = @params.reject {|k,v| !(k.to_s =~ /^time_zone\d*$/)}.to_a.sort {|a,b| a[0].to_s <=> b[0].to_s }.map do |k,tz_name|
200
+ if tz_name =~ /^\[(\w+)\]$/
201
+ node_attribute($1)
202
+ else
203
+ begin
204
+ TZInfo::Timezone.get(tz_name)
205
+ rescue TZInfo::InvalidTimezoneIdentifier
206
+ return parser_error("invalid timezone #{tz_name.inspect}")
207
+ end
208
+ tz_name.inspect
209
+ end
210
+ end
211
+ tz = ", #{tz_list.join(' || ')}"
212
+ end
213
+ if lang = @params[:lang]
214
+ tz = ', nil' if tz == ''
215
+ lang = ", #{lang.inspect}"
216
+ end
217
+ attribute_method = "format_date(#{node_attribute(@params[:date])}, #{format.inspect}#{tz}#{lang})"
218
+ elsif @context[:trans]
219
+ # error
220
+ return "no attribute for 'show'".inspect
221
+ else
222
+ return parser_error("missing attribute")
223
+ end
224
+
225
+ if !@params[:date] && fmt = @params[:format]
226
+ begin
227
+ # test argument
228
+ sprintf(fmt, 123.45)
229
+ rescue ArgumentError
230
+ return parser_error("incorect format #{fmt.inspect}")
231
+ end
232
+ if fmt =~ /%[\d\.]*f/
233
+ modifier = ".to_f"
234
+ elsif fmt =~ /%[\d\.]*i/
235
+ modifier = ".to_i"
236
+ else
237
+ modifier = ''
238
+ end
239
+
240
+ if @params[:zero] == 'hide'
241
+ attribute_method = "sprintf_unless_zero(#{fmt.inspect}, #{attribute_method}#{modifier})"
242
+ else
243
+ attribute_method = "sprintf(#{fmt.inspect}, #{attribute_method}#{modifier})"
244
+ end
245
+ end
246
+
247
+
248
+ if @context[:trans]
249
+ # TODO: what do we do here with gsubs, url ?
250
+ return attribute_method
251
+ end
252
+
253
+ if gsub = @params[:gsub]
254
+ if gsub =~ /\A\/(.+)\/(.+)\/\Z/
255
+ value = $2
256
+ key = $1.gsub(/\#([\{\$\@])/,'# \1') # FIXME: SECURITY.
257
+ # Please note that .gsub(/#([\{\$\@])/,'\#\1') won't work, since '\#{blah}' will become '\\#{blah}' and 'blah' will be evaluated.
258
+ regexp_ok = begin
259
+ output = StringIO.open('','w')
260
+ $stderr = output
261
+ re = /#{key}/
262
+ output.string !~ /warning:/
263
+ rescue
264
+ false
265
+ ensure
266
+ $stderr = STDERR
267
+ false
268
+ end
269
+
270
+ if regexp_ok
271
+ attribute_method = "#{attribute_method}.to_s.gsub(/#{key}/,#{value.inspect})"
272
+ else
273
+ # invalid regexp
274
+ return parser_error("invalid gsub #{gsub.inspect}")
275
+ end
276
+ else
277
+ # error
278
+ return parser_error("invalid gsub #{gsub.inspect}")
279
+ end
280
+ end
281
+
282
+ if @params[:actions]
283
+ actions = "<%= node_actions(:node=>#{node}#{params_to_erb(:actions=>@params[:actions], :publish_after_save=>auto_publish_param)}) %>"
284
+ else
285
+ actions = ''
286
+ end
287
+
288
+ attribute = @params[:attr] || @params[:tattr] || @params[:date]
289
+
290
+ if (@params[:edit_preview] || @params[:ep]) == 'true'
291
+ @html_tag_params[:id] = "#{attribute}#{erb_node_id}"
292
+ @html_tag ||= 'span'
293
+ end
294
+
295
+ if @params[:edit] == 'true' && !['url','path'].include?(attribute)
296
+ "<% if #{node}.can_write? -%><span class='show_edit' id='#{erb_dom_id("_#{attribute}")}'>#{actions}<%= link_to_remote(#{attribute_method}, :url => edit_node_path(#{node_id}) + \"?attribute=#{attribute}&dom_id=#{dom_id("_#{attribute}")}#{auto_publish_param(true)}\", :method => :get) %></span><% else -%>#{actions}<%= #{attribute_method} %><% end -%>"
297
+ else
298
+ "#{actions}<%= #{attribute_method} %>"
299
+ end
300
+ end
301
+
302
+ def r_zazen
303
+ attribute = @params[:attr] || @params[:tattr]
304
+ limit = @params[:limit] ? ", :limit=>#{@params[:limit].to_i}" : ""
305
+ if @context[:trans]
306
+ # TODO: what do we do here with dates ?
307
+ return "#{node_attribute(attribute)}"
308
+ elsif @params[:tattr]
309
+ return "<%= zazen(_(#{node_attribute(attribute)})#{limit}, :node=>#{node(Node)}) %>"
310
+ elsif @params[:attr]
311
+ if output_format == 'html'
312
+ res = "<%= zazen(#{node_attribute(attribute)}#{limit}, :node=>#{node(Node)}) %>"
313
+ else
314
+ return "<%= zazen(#{node_attribute(attribute)}#{limit}, :node=>#{node(Node)}, :output=>#{output_format.inspect}) %>"
315
+ end
316
+ elsif @params[:date]
317
+ # date can be any attribute v_created_at or updated_at etc.
318
+ # TODO format with @params[:format] and @params[:tformat] << translated format
319
+ else
320
+ # error
321
+ end
322
+
323
+ @html_tag ||= 'div'
324
+
325
+ add_html_class('zazen')
326
+
327
+ if (@params[:edit_preview] || @params[:ep]) == 'true'
328
+ @html_tag_params[:id] = "#{attribute}#{erb_node_id}"
329
+ end
330
+
331
+ if @params[:edit] == 'true' && !['url','path'].include?(attribute)
332
+ edit_text = _('edit')
333
+ @html_tag_params[:id] = erb_dom_id("_#{attribute}")
334
+ res = "<% if #{node}.can_write? -%><span class='zazen_edit'><%= link_to_remote(#{edit_text.inspect}, :url => edit_node_path(#{node_id}) + \"?attribute=#{attribute}&dom_id=#{dom_id("_#{attribute}")}#{auto_publish_param(true)}&zazen=true\", :method => :get) %></span><% end -%>#{res}"
335
+ else
336
+ res
337
+ end
338
+ end
339
+
340
+ # TODO: test, rename ?
341
+ def r_search_results
342
+ do_list("@nodes")
343
+ end
344
+
345
+
346
+ def r_set
347
+ return parser_error("'var' missing") unless var_name = @params[:var]
348
+ return parser_error("bad value for 'var' (#{var_name.inspect})") unless var_name =~ /^[a-zA-Z_]+$/
349
+ return '' unless @context[:set]
350
+ if @params[:value]
351
+ out "<% set_#{var_name} = #{@params[:value].inspect} -%>"
352
+ # TODO: isn't @context[:vars] = @params[:value].inspect missing here ?
353
+ elsif @params[:eval]
354
+ return unless eval_string = parse_eval_parameter(@params[:eval])
355
+ out "<% set_#{var_name} = #{eval_string} -%>"
356
+ else
357
+ out "<% set_#{var_name} = capture do %>"
358
+ out expand_with(:set => false) # do not propagate
359
+ out "<% end -%>"
360
+ end
361
+ end
362
+
363
+
364
+ # TODO: write a test (please)
365
+ # FIXME: we should use a single way to change a whole context into a template (applies to 'each', 'form', 'block'). Then 'swap' could use the 'each' block.
366
+ # Define a block of elements to be used by ajax calls (edit/filter)
367
+ def r_block
368
+ if @context[:block] == self
369
+ # called from self (storing template)
370
+ @context.reject! do |k,v|
371
+ # FIXME: reject all stored elements in a better way then this
372
+ k.kind_of?(String) && k =~ /\ANode_\w/
373
+ end
374
+ @html_tag_done = false
375
+ @html_tag_params.merge!(:id=>erb_dom_id)
376
+ @context[:scope_node] = node if @context[:scope_node]
377
+ out expand_with(:node => node)
378
+ if @method == 'drop' && !@context[:make_form]
379
+ out drop_javascript
380
+ end
381
+ else
382
+ if parent.method == 'each' && @method == parent.single_child_method
383
+ # use parent as block
384
+ # FIXME: will not work with block as distant target...
385
+ # do nothing
386
+ else
387
+ @html_tag ||= 'div'
388
+ new_dom_scope
389
+
390
+ unless @context[:make_form]
391
+ # STORE TEMPLATE ========
392
+
393
+ context_bak = @context.dup # avoid side effects when rendering the same block
394
+ ignore_list = @method == 'block' ? ['form'] : [] # do not show the form in the normal template of a block
395
+ template = expand_block(self, :block=>self, :list=>false, :saved_template=>true, :ignore => ignore_list)
396
+ @context = context_bak
397
+ @result = ''
398
+ out helper.save_erb_to_url(template, template_url)
399
+
400
+ # STORE FORM ============
401
+ if edit = descendant('edit')
402
+ publish_after_save = (edit.params[:publish] == 'true')
403
+ if form = descendant('form')
404
+ # USE BLOCK FORM ========
405
+ form_text = expand_block(form, :saved_template=>true, :publish_after_save => publish_after_save)
406
+ else
407
+ # MAKE A FORM FROM BLOCK ========
408
+ form = self.dup
409
+ form.method = 'form'
410
+ form_text = expand_block(form, :make_form => true, :list => false, :saved_template => true, :publish_after_save => publish_after_save)
411
+ end
412
+ out helper.save_erb_to_url(form_text, form_url)
413
+ end
414
+ end
415
+
416
+ # RENDER
417
+ @html_tag_done = false
418
+ @html_tag_params.merge!(:id=>erb_dom_id)
419
+ end
420
+
421
+ out expand_with
422
+ if @method == 'drop' && !@context[:make_form]
423
+ out drop_javascript
424
+ end
425
+ end
426
+ end
427
+
428
+ # TODO: test
429
+ def r_filter
430
+ if upd = @params[:update]
431
+ return unless block = find_target(upd)
432
+ else
433
+ return parser_error("missing 'block' in same parent") unless parent && block = parent.descendant('block')
434
+ end
435
+ return parser_error("cannot use 's' as key (used by start_node)") if @params[:key] == 's'
436
+ out "<%= form_remote_tag(:url => zafu_node_path(#{node_id}), :method => :get, :html => {:id => \"#{dom_id}_f\"}) %><div class='hidden'><input type='hidden' name='t_url' value='#{block.template_url}'/><input type='hidden' name='dom_id' value='#{block.erb_dom_id}'/>#{start_node_s_param(:input)}</div><div class='wrapper'>"
437
+ if @blocks == []
438
+ out "<input type='text' name='#{@params[:key] || 'f'}' value='<%= params[#{(@params[:key] || 'f').to_sym.inspect}] %>'/>"
439
+ else
440
+ out expand_with(:in_filter => true)
441
+ end
442
+ out "</div></form>"
443
+ if @params[:live] || @params[:update]
444
+ out "<%= observe_form( \"#{dom_id}_f\" , :method => :get, :frequency => 1, :submit =>\"#{dom_id}_f\", :url => zafu_node_path(#{node_id})) %>"
445
+ end
446
+ end
447
+
448
+ # swap an attribute
449
+ # TODO: test
450
+ def r_swap
451
+ if upd = @params[:update]
452
+ if upd == '_page'
453
+ block = nil
454
+ elsif block = find_target(upd)
455
+ # ok
456
+ if ancestor('block') || ancestor('each')
457
+ upd_both = '&upd_both=true'
458
+ else
459
+ upd_both = ''
460
+ end
461
+ else
462
+ return
463
+ end
464
+ elsif ancestor('block') || ancestor('each')
465
+ # ancestor: ok
466
+ block = self
467
+ elsif parent && block = parent.descendant('block')
468
+ # sibling: ok
469
+ upd_both = ''
470
+ else
471
+ return parser_error("missing 'block' in same parent")
472
+ end
473
+
474
+ states = ((@params[:states] || 'todo, done') + ' ').split(',').map(&:strip)
475
+
476
+ query_params = "node[#{@params[:attr]}]=\#{#{states.inspect}[ ((#{states.inspect}.index(#{node_attribute(@params[:attr])}.to_s) || 0)+1) % #{states.size}]}#{upd_both}"
477
+ out link_to_update(block, :query_params => query_params, :method => :put, :html_params => get_html_params(@params, :link))
478
+ end
479
+
480
+ def r_load
481
+ if dict = @params[:dictionary]
482
+ dict_content, absolute_url, doc = self.class.get_template_text(dict, @options[:helper], @options[:current_folder])
483
+ return parser_error("dictionary #{dict.inspect} not found") unless doc
484
+ @context[:dict] ||= {}
485
+ begin
486
+ definitions = YAML::load(dict_content)
487
+ definitions['translations'].each do |elem|
488
+ @context[:dict][elem[0]] = elem[1]
489
+ end
490
+ rescue
491
+ return parser_error("invalid dictionary content #{dict.inspect}")
492
+ end
493
+ else
494
+ return parser_error("missing 'dictionary'")
495
+ end
496
+ expand_with
497
+ end
498
+
499
+ def r_trans
500
+ static = true
501
+ if @params[:text]
502
+ text = @params[:text]
503
+ elsif @params[:attr]
504
+ text = "#{node_attribute(@params[:attr])}"
505
+ static = false
506
+ else
507
+ res = []
508
+ text = ""
509
+ @blocks.each do |b|
510
+ if b.kind_of?(String)
511
+ res << b.inspect
512
+ text << b
513
+ elsif ['show', 'current_date'].include?(b.method)
514
+ res << expand_block(b, :trans=>true)
515
+ static = false
516
+ else
517
+ # ignore
518
+ end
519
+ end
520
+ unless static
521
+ text = res.join(' + ')
522
+ end
523
+ end
524
+ if static
525
+ _(text)
526
+ else
527
+ "<%= _(#{text}) %>"
528
+ end
529
+ end
530
+
531
+ alias r_t r_trans
532
+
533
+ def r_anchor(obj=node)
534
+ "<a name='#{anchor_name(@anchor_param, obj)}'></a>"
535
+ end
536
+
537
+ def anchor_name(p, obj=node)
538
+ if p =~ /\[(.+)\]/
539
+ "<%= #{node_attribute($1)} %>"
540
+ else
541
+ "#{base_class.to_s.underscore}#{erb_node_id(obj)}"
542
+ end
543
+ end
544
+
545
+ def r_content_for_layout
546
+ "<% if content_for_layout = yield -%><%= content_for_layout %><% else -%>" +
547
+ expand_with +
548
+ "<% end -%>"
549
+ end
550
+
551
+ def r_title_for_layout
552
+ "<% if @title_for_layout -%><%= @title_for_layout %><% elsif @node && !@node.new_record? -%><%= @node.rootpath %><% elsif @node.parent -%><%= @node.parent.rootpath %><% else -%>" +
553
+ expand_with +
554
+ "<% end -%>"
555
+ end
556
+
557
+ def r_check_lang
558
+ text = @params[:text] || expand_with
559
+ klass = @params[:class] || @html_tag_params[:class]
560
+ text = nil if text.blank?
561
+ klas = nil if klass.blank?
562
+ @html_tag_done = true
563
+ "#{@space_before}<%= check_lang(#{node},:text=>#{text.inspect},:class=>#{klass.inspect},:wrap=>#{@html_tag.inspect}) %>"
564
+ end
565
+
566
+ def r_title
567
+ if node_kind_of?(Version)
568
+ node = "#{self.node}.node"
569
+ elsif node_kind_of?(Node)
570
+ node = self.node
571
+ else
572
+ return parser_error('title','only works with nodes')
573
+ end
574
+ title_params = {}
575
+
576
+ title_params[:check_lang] = @params[:check_lang] if @params.include?(:check_lang)
577
+
578
+ if @params[:link]
579
+ value, static = parse_attributes_in_value(@params[:link], :erb => false)
580
+ link_param = ", :link=>\"#{value}\""
581
+ else
582
+ link_param = ''
583
+ end
584
+
585
+ res = "<%= show_title(:node=>#{node}#{link_param}#{params_to_erb(title_params)}"
586
+ if @params[:text]
587
+ res << ", :text=>#{@params[:text].inspect}"
588
+ elsif @params[:attr]
589
+ res << ", :text=>#{node_attribute(@params[:attr])}"
590
+ end
591
+
592
+ if @params.include?(:project)
593
+ res << ", :project=>#{@params[:project] == 'true'}"
594
+ end
595
+ res << ")"
596
+ if @params[:actions]
597
+ res << " + node_actions(:node=>#{node}#{params_to_erb(:actions=>@params[:actions], :publish_after_save=>auto_publish_param)})"
598
+ end
599
+ res << "%>"
600
+ if @params[:status] == 'true' || (@params[:status].nil? && @params[:actions])
601
+ @html_tag ||= 'span'
602
+ add_html_class("s<%= #{node}.version.status %>")
603
+ end
604
+ res
605
+ end
606
+
607
+ # TODO: test
608
+ def r_actions
609
+ out expand_with
610
+ out "<%= node_actions(:node=>#{node}#{params_to_erb(:actions=>@params[:select], :publish_after_save=>auto_publish_param)}) %>"
611
+ end
612
+
613
+ # TODO: test
614
+ def r_admin_links
615
+ "<%= show_link(:admin_links).join('</#{@html_tag}><#{@html_tag}>') %>"
616
+ end
617
+
618
+ def r_text
619
+ text = @params[:text] ? @params[:text].inspect : "#{node_attribute('v_text')}"
620
+ limit = @params[:limit] ? ", :limit=>#{@params[:limit].to_i}" : ""
621
+
622
+ @html_tag ||= 'div'
623
+
624
+ if @html_tag_params[:id]
625
+ # add a sub-div
626
+ pre = "<div id='v_text#{erb_node_id}'>"
627
+ post = "</div>"
628
+ else
629
+ pre = post = ''
630
+ @html_tag_params[:id] = "v_text#{erb_node_id}"
631
+ end
632
+
633
+ add_html_class('zazen')
634
+
635
+ unless @params[:empty] == 'true'
636
+ out "#{pre}<% if #{node}.kind_of?(TextDocument); l = #{node}.content_lang -%>"
637
+ out "<%= zazen(\"<code\#{l ? \" lang='\#{l}'\" : ''} class=\\'full\\'>\#{#{text}}</code>\") %>"
638
+ out "<% else -%>"
639
+ out "<%= zazen(#{text}#{limit}, :node=>#{node(Node)}) %>"
640
+ out "<% end -%>#{post}"
641
+ else
642
+ out "#{pre}#{post}"
643
+ end
644
+ end
645
+
646
+ def r_inspect
647
+ out ["params: #{@params.inspect}",
648
+ "name: #{@context[:name]}",
649
+ "node: #{node}",
650
+ "list: #{list}"].join("<br/>")
651
+ end
652
+
653
+ # TODO: replace with a more general 'zazen' or 'show' with id ?
654
+ def r_summary
655
+ limit = @params[:limit] ? ", :limit=>#{@params[:limit].to_i}" : ""
656
+ @html_tag ||= 'div'
657
+ if @html_tag_params[:id]
658
+ # add a sub-div
659
+ pre = "<div id='v_summary#{erb_node_id}'>"
660
+ post = "</div>"
661
+ else
662
+ pre = post = ''
663
+ @html_tag_params[:id] = "v_summary#{erb_node_id}"
664
+ end
665
+
666
+ add_html_class('zazen')
667
+
668
+ unless @params[:or]
669
+ text = @params[:text] ? @params[:text].inspect : node_attribute('v_summary')
670
+ out "#{pre}<%= zazen(#{text}#{limit}, :node=>#{node(Node)}) %>#{post}"
671
+ else
672
+ limit ||= ', :limit => 2'
673
+ first_name = 'v_summary'
674
+ first = node_attribute(first_name)
675
+
676
+ second_name = @params[:or].gsub(/[^a-z_]/,'') # FIXME: ist this still needed ? (ERB injection)
677
+ second = node_attribute(second_name)
678
+ out "#{pre}<% if #{first} != '' %>"
679
+ out "<%= zazen(#{first}, :node=>#{node(Node)}) %>"
680
+ out "<% else %>"
681
+ out "<%= zazen(#{second}#{limit}, :node=>#{node(Node)}) %>"
682
+ out "<% end %>#{post}"
683
+ end
684
+ end
685
+
686
+ def r_show_author
687
+ if @params[:size] == 'large'
688
+ out "#{_("posted by")} <b><%= #{node}.author.fullname %></b>"
689
+ out "<% if #{node}[:user_id] != #{node}.version[:user_id] -%>"
690
+ out "<% if #{node}[:ref_lang] != #{node}.version[:lang] -%>"
691
+ out "#{_("traduction by")} <b><%= #{node}.version.author.fullname %></b>"
692
+ out "<% else -%>"
693
+ out "#{_("modified by")} <b><%= #{node}.version.author.fullname %></b>"
694
+ out "<% end"
695
+ out " end -%>"
696
+ out " #{_("on")} <%= format_date(#{node}.version.updated_at, #{_('short_date').inspect}) %>."
697
+ if @params[:traductions] == 'true'
698
+ out " #{_("Traductions")} : <span class='traductions'><%= helper.traductions(:node=>#{node}).join(', ') %></span>"
699
+ end
700
+ else
701
+ out "<b><%= #{node}.version.author.initials %></b> - <%= format_date(#{node}.version.updated_at, #{_('short_date').inspect}) %>"
702
+ if @params[:traductions] == 'true'
703
+ out " <span class='traductions'>(<%= helper.traductions(:node=>#{node}).join(', ') %>)</span>"
704
+ end
705
+ end
706
+ end
707
+
708
+ def r_comments_to_publish
709
+ open_context("visitor.comments_to_publish", :node_class => [Comment])
710
+ end
711
+
712
+ def r_to_publish
713
+ open_context("visitor.to_publish", :node_class => [Version])
714
+ end
715
+
716
+ def r_proposed
717
+ open_context("visitor.proposed", :node_class => [Version])
718
+ end
719
+
720
+ def r_redactions
721
+ open_context("visitor.redactions", :node_class => [Version])
722
+ end
723
+
724
+ def r_edit
725
+
726
+ if @context[:dom_prefix]
727
+ # ajax
728
+ if @context[:in_form]
729
+ # cancel button
730
+ @context[:form_cancel] || ''
731
+ else
732
+ # edit button
733
+
734
+ # TODO: show 'reply' instead of 'edit' in comments if visitor != author
735
+ out link_to_update(self, :default_text => _('edit'), :url => "\#{edit_#{base_class.to_s.underscore}_path(#{node_id})}", :html_params => get_html_params(@params, :link), :method => :get, :cond => "#{node}.can_write?", :else => :void)
736
+ end
737
+ else
738
+ # FIXME: we could link to some html page to edit the item.
739
+ ""
740
+ end
741
+ end
742
+
743
+ alias r_cancel r_edit
744
+
745
+ def r_textarea
746
+ out make_textarea(@html_tag_params.merge(@params))
747
+ @html_tag_done = true
748
+ end
749
+
750
+
751
+ # <r:select name='klass' root_class='...'/>
752
+ # <r:select name='parent_id' values='projects in site'/>
753
+ # TODO: optimization (avoid loading full AR to only use [id, name])
754
+ def r_select
755
+ html_attributes, attribute = get_input_params()
756
+ return parser_error("missing name") unless attribute
757
+ if value = @params[:selected]
758
+ # FIXME: DRY with html_attributes
759
+ value = value.gsub(/\[([^\]]+)\]/) do
760
+ node_attr = $1
761
+ res = node_attribute(node_attr)
762
+ "\#{#{res}}"
763
+ end
764
+ selected = value.inspect
765
+ elsif @context[:in_filter]
766
+ selected = "params[#{attribute.to_sym.inspect}].to_s"
767
+ else
768
+ selected = "#{node_attribute(attribute)}.to_s"
769
+ end
770
+ html_id = html_attributes[:id] ? " id='#{html_attributes[:id]}'" : ''
771
+ if @context[:in_filter]
772
+ select_tag = "<select#{html_id} name='#{attribute}'>"
773
+ else
774
+ select_tag = "<select#{html_id} name='#{base_class.to_s.underscore}[#{attribute}]'>"
775
+ end
776
+
777
+ if klass = @params[:root_class]
778
+ class_opts = {}
779
+ class_opts[:without] = @params[:without] if @params[:without]
780
+ # do not use 'selected' if the node is not new
781
+ "#{select_tag}<%= options_for_select(Node.classes_for_form(:class => #{klass.inspect}#{params_to_erb(class_opts)}), (#{node}.new_record? ? #{selected} : #{node}.klass)) %></select>"
782
+ elsif @params[:type] == 'time_zone'
783
+ # <r:select name='d_tz' type='time_zone'/>
784
+ "#{select_tag}<%= options_for_select(TZInfo::Timezone.all_identifiers, #{selected}) %></select>"
785
+ elsif options_list = get_options_for_select
786
+ "#{select_tag}<%= options_for_select(#{options_list}, #{selected}) %></select>"
787
+ else
788
+ parser_error("missing 'nodes', 'root_class' or 'values'")
789
+ end
790
+ end
791
+
792
+
793
+ def r_input
794
+ html_attributes, attribute = get_input_params()
795
+ case @params[:type]
796
+ when 'select' # FIXME: why is this only for classes ?
797
+ out parser_error("please use [select] here")
798
+ r_select
799
+ when 'date_box', 'date'
800
+ return parser_error("date_box without name") unless attribute
801
+ input_id = @context[:dom_prefix] ? ", :id=>\"#{dom_id}_#{attribute}\"" : ''
802
+ "<%= date_box '#{base_class.to_s.underscore}', #{attribute.inspect}, :size=>15#{@context[:in_add] ? ", :value=>''" : ''}#{input_id} %>"
803
+ when 'id'
804
+ return parser_error("select id without name") unless attribute
805
+ name = "#{attribute}_id" unless attribute[-3..-1] == '_id'
806
+ input_id = @context[:erb_dom_id] ? ", :input_id =>\"#{erb_dom_id}_#{attribute}\"" : ''
807
+ "<%= select_id('#{base_class.to_s.underscore}', #{attribute.inspect}#{input_id}) %>"
808
+ when 'time_zone'
809
+ out parser_error("please use [select] here")
810
+ r_select
811
+ when 'submit'
812
+ @html_tag = 'input'
813
+ @html_tag_params[:type] = @params[:type]
814
+ @html_tag_params[:text] = @params[:text] if @params[:text]
815
+ @html_tag_params.merge!(html_attributes)
816
+ render_html_tag(nil)
817
+ else
818
+ # 'text', 'hidden', ...
819
+ @html_tag = 'input'
820
+ @html_tag_params[:type] = @params[:type] || 'text'
821
+ if checked = html_attributes.delete(:checked)
822
+ @html_tag_params.merge!(html_attributes)
823
+ render_html_tag(nil, checked)
824
+ else
825
+ @html_tag_params.merge!(html_attributes)
826
+ render_html_tag(nil)
827
+ end
828
+ end
829
+ end
830
+
831
+ def r_form_tag
832
+ # replace <form> with constructed form
833
+ "#{@context[:form_tag]}#{expand_with(:form_tag => nil)}</form>"
834
+ end
835
+
836
+ # TODO: add parent_id into the form !
837
+ # TODO: add <div style="margin:0;padding:0"><input name="_method" type="hidden" value="put" /></div> if method == put
838
+ # FIXME: use <r:form href='self'> or <r:form action='...'>
839
+ def r_form
840
+ hidden_fields = {}
841
+ set_fields = []
842
+ id_hash = {:class => @html_tag_params[:class] || @params[:class] || 'form'}
843
+ var_name = base_class.to_s.underscore
844
+ (descendants('input') + descendants('select')).each do |tag|
845
+ set_fields << "#{var_name}[#{tag.params[:name]}]"
846
+ end
847
+
848
+ if @context[:dom_prefix] || @params[:update]
849
+ # ajax
850
+ if @context[:in_add]
851
+ # inline form used to create new elements: set values to '' and 'parent_id' from context
852
+ id_hash[:id] = "#{erb_dom_id}_form"
853
+ id_hash[:style] = "display:none;"
854
+
855
+ cancel = "<p class='btn_x'><a href='#' onclick='[\"#{erb_dom_id}_add\", \"#{erb_dom_id}_form\"].each(Element.toggle);return false;'>#{_('btn_x')}</a></p>\n"
856
+ form = "<%= form_remote_tag(:url => #{base_class.to_s.underscore.pluralize}_path, :html => {:id => \"#{dom_id}_form_t\"}) %>\n"
857
+ else
858
+ # saved form
859
+
860
+ id_hash[:id] = erb_dom_id
861
+
862
+ cancel = !@context[:dom_prefix] ? "" : <<-END_TXT
863
+ <% if #{node}.new_record? -%>
864
+ <p class='btn_x'><a href='#' onclick='[\"<%= params[:dom_id] %>_add\", \"<%= params[:dom_id] %>_form\"].each(Element.toggle);return false;'>#{_('btn_x')}</a></p>
865
+ <% else -%>
866
+ <p class='btn_x'><%= link_to_remote(#{_('btn_x').inspect}, :url => #{base_class.to_s.underscore}_path(#{node_id}) + \"/zafu?t_url=#{CGI.escape(template_url)}&dom_id=\#{params[:dom_id]}#{@context[:need_link_id] ? "&link_id=\#{#{node}.link_id}" : ''}\", :method => :get) %></p>
867
+ <% end -%>
868
+ END_TXT
869
+ form =<<-END_TXT
870
+ <% if #{node}.new_record? -%>
871
+ <%= form_remote_tag(:url => #{base_class.to_s.underscore.pluralize}_path, :html => {:id => \"\#{params[:dom_id]}_form_t\"}) %>
872
+ <% else -%>
873
+ <%= form_remote_tag(:url => #{base_class.to_s.underscore}_path(#{node_id}), :method => :put, :html => {:id => \"#{dom_id}_form_t\"}) %>
874
+ <% end -%>
875
+ END_TXT
876
+ end
877
+
878
+ if (descendants('input') || []).select{|elem| elem.params[:type] == 'submit'} != []
879
+ # has submit
880
+ else
881
+ hidden_submit = "<input type='submit'/>" # hidden submit for Firefox compatibility
882
+ end
883
+
884
+ hidden_fields['link_id'] = "<%= #{node}.link_id %>" if @context[:need_link_id]
885
+
886
+ if @params[:update] || (@context[:add] && @context[:add].params[:update])
887
+ upd = @params[:update] || @context[:add].params[:update]
888
+ if target = find_target(upd)
889
+ hidden_fields['u_url'] = target.template_url
890
+ hidden_fields['udom_id'] = target.erb_dom_id
891
+ hidden_fields['u_id'] = "<%= #{@context[:parent_node]}.zip %>" if @context[:in_add]
892
+ hidden_fields['s'] = start_node_s_param(:value)
893
+ end
894
+ elsif (block = ancestor('block')) && node_kind_of?(DataEntry)
895
+ # updates template url
896
+ hidden_fields['u_url'] = block.template_url
897
+ hidden_fields['udom_id'] = block.erb_dom_id
898
+ end
899
+
900
+ hidden_fields['t_url'] = template_url
901
+ if t_id = @params[:t_id]
902
+ hidden_fields['t_id'] = parse_attributes_in_value(t_id)
903
+ end
904
+
905
+ erb_dom_id = @context[:saved_template] ? '<%= params[:dom_id] %>' : self.erb_dom_id
906
+
907
+ hidden_fields['dom_id'] = erb_dom_id
908
+
909
+ if node_kind_of?(Node)
910
+ hidden_fields['node[parent_id]'] = "<%= #{@context[:in_add] ? "#{@context[:parent_node]}.zip" : "#{node}.parent_zip"} %>"
911
+ elsif node_kind_of?(Comment)
912
+ # FIXME: the "... || '@node'" is a hack and I don't understand why it's needed...
913
+ hidden_fields['node_id'] = "<%= #{@context[:parent_node] || '@node'}.zip %>"
914
+ elsif node_kind_of?(DataEntry)
915
+ hidden_fields["data_entry[#{@context[:data_root]}_id]"] = "<%= #{@context[:in_add] ? @context[:parent_node] : "#{node}.#{@context[:data_root]}"}.zip %>"
916
+ end
917
+
918
+ if add_block = @context[:add]
919
+ params = add_block.params
920
+ [:after, :before, :top, :bottom].each do |sym|
921
+ if params[sym]
922
+ hidden_fields['position'] = sym.to_s
923
+ if params[sym] == 'self'
924
+ if sym == :before
925
+ hidden_fields['reference'] = "#{erb_dom_id}_add"
926
+ else
927
+ hidden_fields['reference'] = "#{erb_dom_id}_form"
928
+ end
929
+ else
930
+ hidden_fields['reference'] = params[sym]
931
+ end
932
+ break
933
+ end
934
+ end
935
+ if params[:done] == 'focus'
936
+ if params[:focus]
937
+ hidden_fields['done'] = "'$(\"#{erb_dom_id}_#{@params[:focus]}\").focus();'"
938
+ else
939
+ hidden_fields['done'] = "'$(\"#{erb_dom_id}_form_t\").focusFirstElement();'"
940
+ end
941
+ elsif params[:done]
942
+ hidden_fields['done'] = CGI.escape(params[:done]) # .gsub("NODE_ID", @node.zip).gsub("PARENT_ID", @node.parent_zip)
943
+ end
944
+ else
945
+ # ajax form, not in 'add'
946
+ hidden_fields['done'] = CGI.escape(@params[:done]) if @params[:done]
947
+ end
948
+ else
949
+ # no ajax
950
+ # FIXME
951
+ cancel = "" # link to normal node ?
952
+ form = "<form method='post' action='/nodes/#{erb_node_id}'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div>"
953
+ end
954
+
955
+ if node_kind_of?(Node) && (@params[:klass] || @context[:klass])
956
+ hidden_fields['node[klass]'] = @params[:klass] || @context[:klass]
957
+ end
958
+
959
+ if node_kind_of?(Node) && @params[:mode]
960
+ hidden_fields['mode'] = @params[:mode]
961
+ end
962
+
963
+ hidden_fields['node[v_status]'] = Zena::Status[:pub] if @context[:publish_after_save] || auto_publish_param
964
+
965
+ form << "<div class='hidden'>"
966
+ hidden_fields.each do |k,v|
967
+ next if set_fields.include?(k)
968
+ v = "'#{v}'" unless v.kind_of?(String) && ['"', "'"].include?(v[0..0])
969
+ form << "<input type='hidden' name='#{k}' value=#{v}/>\n"
970
+ end
971
+ form << hidden_submit << "\n" if hidden_submit
972
+ form << "</div>"
973
+
974
+ form << "<%= error_messages_for(#{node}) %>"
975
+
976
+ if !descendant('cancel') && !descendant('edit')
977
+ if !descendant('form_tag')
978
+ # add a descendant before blocks.
979
+ blocks_bak = @blocks
980
+ @blocks = @blocks.dup
981
+ @blocks = [make(:void, :method=>'void', :text=>cancel)] + blocks_bak
982
+ else
983
+ form = cancel + form
984
+ cancel = ''
985
+ end
986
+ end
987
+
988
+ if descendant('form_tag')
989
+ res = expand_with(:form_tag => form, :in_form => true, :form_cancel => cancel, :erb_dom_id => erb_dom_id, :dom_id => dom_id)
990
+ else
991
+ res = form + expand_with(:in_form => true, :form_cancel => cancel, :erb_dom_id => erb_dom_id, :dom_id => dom_id) + '</form>'
992
+ end
993
+
994
+ @blocks = blocks_bak if blocks_bak
995
+
996
+ @html_tag_done = false
997
+ @html_tag_params.merge!(id_hash)
998
+ out render_html_tag(res)
999
+ end
1000
+
1001
+ # <r:checkbox role='collaborator_for' values='projects' in='site'/>"
1002
+ # TODO: implement checkbox in the same spirit as 'r_select'
1003
+ def r_checkbox
1004
+ return parser_error("missing 'nodes'") unless values = @params[:values] || @params[:nodes]
1005
+ return parser_error("missing 'role'") unless role = (@params[:role] || @params[:name])
1006
+ attribute = @params[:attr] || 'name'
1007
+ if role =~ /(.*)_ids?\Z/
1008
+ role = $1
1009
+ end
1010
+ meth = role.singularize
1011
+
1012
+ if values =~ /^\d+\s*($|,)/
1013
+ # ids
1014
+ # TODO generate the full query instead of using secure.
1015
+ values = values.split(',').map{|v| v.to_i}
1016
+ list_finder = "(secure(Node) { Node.find(:all, :conditions => 'zip IN (#{values.join(',')})') })"
1017
+ else
1018
+ # relation
1019
+ list_finder, klass = build_finder_for(:all, values)
1020
+ return unless list_finder
1021
+ return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
1022
+ end
1023
+ out "<% if (#{list_var} = #{list_finder}) && (#{list_var}_relation = #{node}.relation_proxy(#{role.inspect})) -%>"
1024
+ out "<% if #{list_var}_relation.unique? -%>"
1025
+
1026
+ out "<% #{list_var}_id = #{list_var}_relation.other_id -%>"
1027
+ out "<div class='input_radio'><% #{list_var}.each do |#{var}| -%>"
1028
+ out "<span><input type='radio' name='node[#{meth}_id]' value='#{erb_node_id(var)}'<%= #{list_var}_id == #{var}[:id] ? \" checked='checked'\" : '' %>/> <%= #{node_attribute(attribute, :node=>var)} %></span> "
1029
+ out "<% end -%></div>"
1030
+ out "<input type='radio' name='node[#{meth}_id]' value=''/> #{_('none')}"
1031
+
1032
+ out "<% else -%>"
1033
+
1034
+ out "<% #{list_var}_ids = #{list_var}_relation.other_ids -%>"
1035
+ out "<div class='input_checkbox'><% #{list_var}.each do |#{var}| -%>"
1036
+ out "<span><input type='checkbox' name='node[#{meth}_ids][]' value='#{erb_node_id(var)}'<%= #{list_var}_ids.include?(#{var}[:id]) ? \" checked='checked'\" : '' %>/> <%= #{node_attribute(attribute, :node=>var)} %></span> "
1037
+ out "<% end -%></div>"
1038
+ out "<input type='hidden' name='node[#{meth}_ids][]' value=''/>"
1039
+
1040
+ out "<% end -%><% end -%>"
1041
+ end
1042
+
1043
+ alias r_radio r_checkbox
1044
+
1045
+ # TODO: test
1046
+ def r_add
1047
+ return parser_error("should not be called from within 'each'") if parent.method == 'each'
1048
+ return '' if @context[:make_form]
1049
+
1050
+ # why is node = @node (which we need) but we are supposed to have Comments ?
1051
+ # FIXME: during rewrite, replace 'node' by 'node(klass = node_class)' so the ugly lines below would be
1052
+ # if node_kind_of?(Comment)
1053
+ # out "<% if #{node(Node)}.can_comment? -%>"
1054
+ # Refs #198.
1055
+ if node_kind_of?(Comment)
1056
+ out "<% if #{node}.can_comment? -%>"
1057
+ else
1058
+ out "<% if #{node}.can_write? -%>"
1059
+ end
1060
+
1061
+ unless descendant('add_btn')
1062
+ # add a descendant between self and blocks.
1063
+ blocks = @blocks.dup
1064
+ @blocks = []
1065
+ add_btn = make(:void, :method=>'add_btn', :params=>@params.dup, :text=>'')
1066
+ add_btn.blocks = blocks
1067
+ remove_instance_variable(:@all_descendants)
1068
+ end
1069
+
1070
+ if @context[:form] && @context[:dom_prefix]
1071
+ # ajax add
1072
+
1073
+ @html_tag_params.merge!(:id => "#{erb_dom_id}_add")
1074
+ @html_tag_params[:class] ||= 'btn_add'
1075
+ if @params[:focus]
1076
+ focus = "$(\"#{erb_dom_id}_#{@params[:focus]}\").focus();"
1077
+ else
1078
+ focus = "$(\"#{erb_dom_id}_form_t\").focusFirstElement();"
1079
+ end
1080
+
1081
+ out render_html_tag("#{expand_with(:onclick=>"[\"#{erb_dom_id}_add\", \"#{erb_dom_id}_form\"].each(Element.toggle);#{focus}return false;")}")
1082
+
1083
+ if node_kind_of?(Node)
1084
+ # FIXME: BUG if we set <r:form klass='Post'/> the user cannot select class with menu...
1085
+ klass = @context[:klass] || 'Node'
1086
+ # FIXME: inspect '@context[:form]' to see if it contains v_klass ?
1087
+ out "<% if #{var}_new = secure(Node) { Node.new_from_class(#{klass.inspect}) } -%>"
1088
+ else
1089
+ out "<% if #{var}_new = #{node_class}.new -%>"
1090
+ end
1091
+
1092
+ if @context[:form].method == 'form'
1093
+ out expand_block(@context[:form], :in_add => true, :no_ignore => ['form'], :add=>self, :node => "#{var}_new", :parent_node => node, :klass => klass, :publish_after_save => auto_publish_param)
1094
+ else
1095
+ # build form from 'each'
1096
+ out expand_block(@context[:form], :in_add => true, :no_ignore => ['form'], :add=>self, :make_form => true, :node => "#{var}_new", :parent_node => node, :klass => klass, :publish_after_save => auto_publish_param)
1097
+ end
1098
+ out "<% end -%>"
1099
+ else
1100
+ # no ajax
1101
+ @html_tag_params[:class] ||= 'btn_add' if @html_tag
1102
+ out render_html_tag(expand_with)
1103
+ end
1104
+ out "<% end -%>"
1105
+ @html_tag_done = true
1106
+ end
1107
+
1108
+ def r_add_btn
1109
+ if @params[:text]
1110
+ text = @params[:text]
1111
+ text = "<div>#{text}</div>" unless @html_tag
1112
+ elsif @params[:trans]
1113
+ text = _(@params[:trans])
1114
+ text = "<div>#{text}</div>" unless @html_tag
1115
+ elsif @blocks != []
1116
+ text = expand_with
1117
+ else
1118
+ text = node_class == Comment ? _("btn_add_comment") : _("btn_add")
1119
+ end
1120
+
1121
+ out "<a href='#' onclick='#{@context[:onclick]}'>#{text}</a>"
1122
+ end
1123
+
1124
+ # Show html to add open a popup window to add a document.
1125
+ # TODO: inline ajax for upload ?
1126
+ def r_add_document
1127
+ return parser_error("only works with nodes (not with #{node_class})") unless node_kind_of?(Node)
1128
+ @html_tag_params[:class] ||= 'btn_add'
1129
+ res = "<a href='/documents/new?parent_id=#{erb_node_id}' onclick='uploader=window.open(\"/documents/new?parent_id=#{erb_node_id}\", \"upload\", \"width=400,height=300\");return false;'>#{_('btn_add_doc')}</a>"
1130
+ "<% if #{node}.can_write? -%>#{render_html_tag(res)}<% end -%>"
1131
+ end
1132
+
1133
+ #if RAILS_ENV == 'test'
1134
+ # def r_test
1135
+ # inspect
1136
+ # end
1137
+ #end
1138
+
1139
+ def r_drop
1140
+ if parent.method == 'each' && @method == parent.single_child_method
1141
+ parent.add_html_class('drop')
1142
+ else
1143
+ @html_tag_params[:class] ||= 'drop'
1144
+ end
1145
+ r_block
1146
+ end
1147
+
1148
+ def drop_javascript
1149
+ hover = @params[:hover]
1150
+ change = @params[:change]
1151
+
1152
+ if role = @params[:set] || @params[:add]
1153
+ query_params = ["node[#{role}_id]=[id]"]
1154
+ else
1155
+ query_params = []
1156
+ # set='icon_for=[id], v_status='50', v_title='[v_title]'
1157
+ @params.each do |k, v|
1158
+ next if [:hover, :change, :done].include?(k)
1159
+ value, static = parse_attributes_in_value(v, :erb => false, :skip_node_attributes => true)
1160
+ key = change == 'params' ? "params[#{k}]" : "node[#{k}]"
1161
+ query_params << "#{key}=#{CGI.escape(value)}"
1162
+ end
1163
+ return parser_error("missing parameters to set values") if query_params == []
1164
+ end
1165
+
1166
+ query_params << "change=#{change}" if change == 'receiver'
1167
+ query_params << "t_url=#{CGI.escape(template_url)}"
1168
+ query_params << "dom_id=#{erb_dom_id}"
1169
+ query_params << start_node_s_param(:erb)
1170
+ query_params << "done=#{CGI.escape(@params[:done])}" if @params[:done]
1171
+
1172
+ "<script type='text/javascript'>
1173
+ //<![CDATA[
1174
+ Droppables.add('#{erb_dom_id}', {hoverclass:'#{hover || 'drop_hover'}', onDrop:function(element){new Ajax.Request('/nodes/#{erb_node_id}/drop?#{query_params.join('&')}', {asynchronous:true, evalScripts:true, method:'put', parameters:'drop=' + encodeURIComponent(element.id)})}})
1175
+ //]]>
1176
+ </script>"
1177
+ end
1178
+
1179
+ def r_draggable
1180
+ new_dom_scope
1181
+ @html_tag ||= 'div'
1182
+ case @params[:revert]
1183
+ when 'move'
1184
+ revert_effect = 'Element.move'
1185
+ when 'remove'
1186
+ revert_effect = 'Element.remove'
1187
+ else
1188
+ revert_effect = 'Element.move'
1189
+ end
1190
+
1191
+ res, drag_handle = set_drag_handle_and_id(expand_with, @params, :id => erb_dom_id)
1192
+
1193
+ out render_html_tag(res)
1194
+
1195
+ if drag_handle
1196
+ out "<script type='text/javascript'>\n//<![CDATA[\n
1197
+ new Draggable('#{erb_dom_id}', {ghosting:true, revert:true, revertEffect:#{revert_effect}, handle:$('#{erb_dom_id}').select('.#{drag_handle}')[0]});\n//]]>\n</script>"
1198
+ else
1199
+ out "<script type='text/javascript'>\n//<![CDATA[\nZena.draggable('#{erb_dom_id}',0,true,true,#{revert_effect})\n//]]>\n</script>"
1200
+ end
1201
+ end
1202
+
1203
+ def r_unlink
1204
+ return "" if @context[:make_form]
1205
+ opts = {}
1206
+
1207
+ if upd = @params[:update]
1208
+ if upd == '_page'
1209
+ target = nil
1210
+ elsif target = find_target(upd)
1211
+ # ok
1212
+ else
1213
+ return
1214
+ end
1215
+ elsif target = ancestor('block')
1216
+ # ok
1217
+ else
1218
+ target = self
1219
+ end
1220
+
1221
+ if node_kind_of?(Node)
1222
+ opts[:cond] = "#{node}.can_write? && #{node}.link_id"
1223
+ opts[:url] = "/nodes/\#{#{node_id}}/links/\#{#{node}.link_id}"
1224
+ elsif node_kind_of?(Link)
1225
+ opts[:url] = "/nodes/\#{#{node}.this_zip}/links/\#{#{node}.zip}"
1226
+ end
1227
+
1228
+ opts[:method] = :delete
1229
+ opts[:default_text] = _('btn_tiny_del')
1230
+ opts[:html_params] = get_html_params({:class => 'unlink'}.merge(@params), :link)
1231
+
1232
+ out link_to_update(target, opts)
1233
+
1234
+ #tag_to_remote
1235
+ #"<%= tag_to_remote({:url => node_path(#{node_id}) + \"#{opts[:method] != :put ? '/zafu' : ''}?#{action.join('&')}\", :method => #{opts[:method].inspect}}) %>"
1236
+ # out "<a class='#{@params[:class] || 'unlink'}' href='/nodes/#{erb_node_id}/links/<%= #{node}.link_id %>?#{action}' onclick=\"new Ajax.Request('/nodes/#{erb_node_id}/links/<%= #{node}.link_id %>?#{action}', {asynchronous:true, evalScripts:true, method:'delete'}); return false;\">"
1237
+ # if !@blocks.empty?
1238
+ # inner = expand_with
1239
+ # else
1240
+ # inner = _('btn_tiny_del')
1241
+ # end
1242
+ # out "#{inner}</a><% else -%>#{inner}<% end -%>"
1243
+ #elsif node_kind_of?(DataEntry)
1244
+ # text = get_text_for_erb
1245
+ # if text.blank?
1246
+ # text = _('btn_tiny_del')
1247
+ # end
1248
+ # out "<%= link_to_remote(#{text.inspect}, {:url => \"/data_entries/\#{#{node}[:id]}?dom_id=#{dom_id}#{upd_url}\", :method => :delete}, :class=>#{(@params[:class] || 'unlink').inspect}) %>"
1249
+ #end
1250
+ end
1251
+
1252
+ # Group elements in a list. Use :order to specify order.
1253
+ def r_group
1254
+ return parser_error("cannot be used outside of a list") unless list_var = @context[:list]
1255
+ return parser_error("missing 'by' clause") unless key = @params[:by]
1256
+
1257
+ sort_key = @params[:sort] || 'name'
1258
+ if node_kind_of?(DataEntry) && DataEntry::NodeLinkSymbols.include?(key.to_sym)
1259
+ key = "#{key}_id"
1260
+ sort_block = "{|e| (e.#{key} || {})[#{sort_key.to_sym.inspect}]}"
1261
+ group_array = "group_array(#{list_var}) {|e| e.#{key}}"
1262
+ elsif node_kind_of?(Node)
1263
+ if ['project', 'parent', 'section'].include?(key)
1264
+ sort_block = "{|e| (e.#{key} || {})[#{sort_key.to_sym.inspect}]}"
1265
+ group_array = "group_array(#{list_var}) {|e| e.#{key}_id}"
1266
+ end
1267
+ end
1268
+
1269
+ group_array ||= "group_array(#{list_var}) {|e| #{node_attribute(key, :node => 'e')}}"
1270
+
1271
+ if sort_block
1272
+ out "<% grp_#{list_var} = sort_array(#{group_array}) #{sort_block} -%>"
1273
+ else
1274
+ out "<% grp_#{list_var} = #{group_array} -%>"
1275
+ end
1276
+
1277
+ if descendant('each_group')
1278
+ out expand_with(:group => "grp_#{list_var}")
1279
+ else
1280
+ @context[:group] = "grp_#{list_var}"
1281
+ r_each_group
1282
+ end
1283
+ end
1284
+
1285
+
1286
+ # Compute statistics on elements in the current list context.
1287
+ def r_stat
1288
+ return parser_error("must be used inside a list context") unless list
1289
+ find = @params[:find] || @params[:date] || 'count'
1290
+ key = @params[:of] || @params[:from] || 'value'
1291
+ case find
1292
+ when 'sum'
1293
+ value = "#{list}.flatten.inject(0) {|#{var}_sum,#{var}| #{var}_sum + #{node_attribute(key, :node => var)}.to_f}"
1294
+ when 'min'
1295
+ value = "#{node_attribute(key, :node => "min_array(#{list}) {|e| #{node_attribute(key, :node => 'e')}}")}"
1296
+ when 'max'
1297
+ value = "#{node_attribute(key, :node => "max_array(#{list}) {|e| #{node_attribute(key, :node => 'e')}}")}"
1298
+ when 'count'
1299
+ return "<%= #{list}.size %>"
1300
+ end
1301
+ if @params[:date]
1302
+ # FIXME: DRY (r_show)
1303
+ if @params[:tformat]
1304
+ format = _(@params[:tformat])
1305
+ elsif @params[:format]
1306
+ format = @params[:format]
1307
+ else
1308
+ format = "%Y-%m-%d"
1309
+ end
1310
+ "<%= #{list}==[] ? '' : format_date(#{value}, #{format.inspect}) %>"
1311
+ elsif format = @params[:format]
1312
+
1313
+ if @params[:zero] == 'hide'
1314
+ "<%= #{list}==[] ? '' : sprintf_unless_zero(#{@params[:format].inspect}, #{value}) %>"
1315
+ else
1316
+ "<%= #{list}==[] ? '' : sprintf(#{@params[:format].inspect}, #{value}) %>"
1317
+ end
1318
+ else
1319
+ "<%= #{list}==[] ? '' : #{value} %>"
1320
+ end
1321
+ end
1322
+
1323
+ def r_each_group
1324
+ return parser_error("must be used inside a group context") unless group = @context[:group]
1325
+ if join = @params[:join]
1326
+ join = join.gsub(/&lt;([^%])/, '<\1').gsub(/([^%])&gt;/, '\1>')
1327
+ out "<% #{group}.each_index do |#{list_var}_index| -%>"
1328
+ out "<%= #{list_var}=#{group}[#{list_var}_index]; #{var} = #{list_var}[0]; #{list_var}_index > 0 ? #{join.inspect} : '' %>"
1329
+ else
1330
+ out "<% #{group}.each do |#{list_var}|; #{var} = #{list_var}[0]; -%>"
1331
+ end
1332
+ out render_html_tag(expand_with(:group => nil, :list => list_var, :node => var, :scope_node => var))
1333
+ out "<% end -%>"
1334
+ end
1335
+
1336
+ def r_each
1337
+ is_draggable = @params[:draggable] == 'true' || @params[:drag_handle]
1338
+
1339
+ if descendant('edit') || descendant('unlink') || descendant('swap') || ['block', 'drop'].include?(single_child_method) || is_draggable
1340
+ id_hash = {:id => erb_dom_id}
1341
+ else
1342
+ id_hash = nil
1343
+ end
1344
+
1345
+
1346
+ if @context[:make_form]
1347
+ # use the elements inside 'each' loop to produce the edit form
1348
+ r_form
1349
+ elsif @context[:list]
1350
+ # normal rendering: not the start of a saved template
1351
+ if is_draggable || descendant('unlink')
1352
+ out "<% #{var}_dom_ids = [] -%>"
1353
+ end
1354
+
1355
+ @params[:alt_class] ||= @html_tag_params.delete(:alt_class)
1356
+ # FIXME: add alt_reverse='true' to start counting from bottom (if order last on top...)
1357
+ if @params[:alt_class] || @params[:join]
1358
+ join = @params[:join] || ''
1359
+ join = join.gsub(/&lt;([^%])/, '<\1').gsub(/([^%])&gt;/, '\1>')
1360
+ out "<% #{var}_max_index = #{list}.size - 1 -%>" if @params[:alt_reverse]
1361
+ out "<% #{list}.each_with_index do |#{var},#{var}_index| -%>"
1362
+
1363
+ if join_clause = @params[:join_if]
1364
+ set_stored(Node, 'prev', "#{var}_prev")
1365
+ cond = get_test_condition(var, :test=>join_clause)
1366
+ out "<%= #{var}_prev = #{list}[#{var}_index - 1]; (#{var}_index > 0 && #{cond}) ? #{join.inspect} : '' %>"
1367
+ else
1368
+ out "<%= #{var}_index > 0 ? #{join.inspect} : '' %>"
1369
+ end
1370
+
1371
+ if alt_class = @params[:alt_class]
1372
+ alt_test = @params[:alt_reverse] == 'true' ? "(#{var}_max_index - #{var}_index) % 2 != 0" : "#{var}_index % 2 != 0"
1373
+ if html_class = @html_tag_params.delete(:class)
1374
+ html_append = " class='#{html_class}<%= #{alt_test} ? #{(' ' + alt_class).inspect} : '' %>'"
1375
+ else
1376
+ html_append = "<%= #{alt_test} ? ' class=#{alt_class.inspect}' : '' %>"
1377
+ end
1378
+ else
1379
+ html_append = nil
1380
+ end
1381
+ else
1382
+ out "<% #{list}.each do |#{var}| -%>"
1383
+ html_append = nil
1384
+ end
1385
+
1386
+ if is_draggable
1387
+ out "<% #{var}_dom_ids << \"#{dom_id}\" -%>"
1388
+ end
1389
+
1390
+ out r_anchor(var) if @anchor_param # insert anchor inside the each loop
1391
+ @params[:anchor] = @anchor_param # set back in case we double render
1392
+ @anchor_param = nil
1393
+
1394
+ res, drag_handle = set_drag_handle_and_id(expand_with(:node => var, :scope_node => var), @params, id_hash)
1395
+
1396
+ out render_html_tag(res, html_append)
1397
+
1398
+ out "<% end -%>"
1399
+
1400
+ if is_draggable
1401
+ if drag_handle
1402
+ out "<script type='text/javascript'>\n//<![CDATA[\n<%= #{var}_dom_ids.inspect %>.each(function(dom_id, index) {
1403
+ new Draggable(dom_id, {ghosting:true, revert:true, handle:$(dom_id).select('.#{drag_handle}')[0]});
1404
+ });\n//]]>\n</script>"
1405
+ else
1406
+ out "<script type='text/javascript'>\n//<![CDATA[\n<%= #{var}_dom_ids.inspect %>.each(Zena.draggable)\n//]]>\n</script>"
1407
+ end
1408
+ end
1409
+
1410
+ elsif @context[:saved_template]
1411
+ # render to start a saved template
1412
+ res, drag_handle = set_drag_handle_and_id(expand_with(:scope_node => node), @params, id_hash)
1413
+
1414
+ out render_html_tag(res)
1415
+
1416
+ if is_draggable
1417
+ if drag_handle
1418
+ out "<script type='text/javascript'>\n//<![CDATA[\nnew Draggable('#{erb_dom_id}', {ghosting:true, revert:true, handle:$('#{erb_dom_id}').select('.#{drag_handle}')[0]});\n//]]>\n</script>"
1419
+ else
1420
+ out "<script type='text/javascript'>\n//<![CDATA[\nZena.draggable('#{erb_dom_id}')\n//]]>\n</script>"
1421
+ end
1422
+ end
1423
+ else
1424
+ # TODO: make a single list ?
1425
+ @context[:list] = "[#{node}]"
1426
+ r_each
1427
+ end
1428
+ end
1429
+
1430
+ def r_case
1431
+ out "<% if false -%>"
1432
+ out expand_with(:in_if=>true, :only=>['when', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
1433
+ @html_tag_done = true
1434
+ out "<% end -%>"
1435
+ end
1436
+
1437
+ # TODO: test
1438
+ def r_if
1439
+ cond = get_test_condition
1440
+ return parser_error("condition error") unless cond
1441
+
1442
+ if cond == 'true'
1443
+ return expand_with(:in_if => false)
1444
+ elsif cond == 'false'
1445
+ if descendant('else') || descendant('elsif')
1446
+ return expand_with(:in_if=>true, :only=>['elsif', 'else'])
1447
+ else
1448
+ @html_tag_done = true
1449
+ return ''
1450
+ end
1451
+ end
1452
+
1453
+ out "<% if #{cond} -%>"
1454
+ out render_html_tag(expand_with(:in_if=>false))
1455
+ out expand_with(:in_if=>true, :only=>['elsif', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
1456
+ out "<% end -%>"
1457
+ end
1458
+
1459
+ def r_else
1460
+ if @context[:in_if]
1461
+ @html_tag = @context[:html_tag]
1462
+ @html_tag_params = @context[:html_tag_params] || {}
1463
+ out "<% elsif true -%>"
1464
+ if @params[:text]
1465
+ out render_html_tag(@params[:text])
1466
+ else
1467
+ out render_html_tag(expand_with(:in_if=>false, :only => nil)) # do not propagate :only from ancestor 'if' clause
1468
+ end
1469
+ else
1470
+ ""
1471
+ end
1472
+ end
1473
+
1474
+ def r_elsif
1475
+ return '' unless @context[:in_if]
1476
+ @html_tag = @context[:html_tag]
1477
+ @html_tag_params = @context[:html_tag_params] || {}
1478
+ cond = get_test_condition
1479
+ return parser_error("condition error") unless cond
1480
+ out "<% elsif #{cond} -%>"
1481
+ out render_html_tag(expand_with(:in_if=>false, :only => nil)) # do not propagate :only from ancestor 'if' clause
1482
+ end
1483
+
1484
+ def r_when
1485
+ r_elsif
1486
+ end
1487
+
1488
+ # be carefull, this gives a list of 'versions', not 'nodes'
1489
+ def r_traductions
1490
+ if @params[:except]
1491
+ case @params[:except]
1492
+ when 'current'
1493
+ opts = "(:conditions=>\"lang != '#{helper.lang}'\")"
1494
+ else
1495
+ # list of lang
1496
+ # TODO: test
1497
+ langs = @params[:except].split(',').map{|l| l.gsub(/[^a-z]/,'').strip }
1498
+ opts = "(:conditions=>\"lang NOT IN ('#{langs.join("','")}')\")"
1499
+ end
1500
+ elsif @params[:only]
1501
+ # TODO: test
1502
+ case @params[:only]
1503
+ when 'current'
1504
+ opts = "(:conditions=>\"lang = '#{helper.lang}'\")"
1505
+ else
1506
+ # list of lang
1507
+ # TODO: test
1508
+ langs = @params[:only].split(',').map{|l| l.gsub(/[^a-z]/,'').strip }
1509
+ opts = "(:conditions=>\"lang IN ('#{langs.join("','")}')\")"
1510
+ end
1511
+ else
1512
+ opts = ""
1513
+ end
1514
+ out "<% if #{list_var} = #{node}.traductions#{opts} -%>"
1515
+ out expand_with(:list=>list_var, :node_class => Version)
1516
+ out "<% end -%>"
1517
+ end
1518
+
1519
+ # TODO: test
1520
+ def r_show_traductions
1521
+ "<% if #{list_var} = #{node}.traductions -%>"
1522
+ "#{_("Traductions:")} <span class='traductions'><%= #{list_var}.join(', ') %></span>"
1523
+ "<%= traductions(:node=>#{node}).join(', ') %>"
1524
+ end
1525
+
1526
+ def r_node
1527
+ @method = @params[:select] || 'node' # 'node' is for version.node
1528
+ r_unknown
1529
+ end
1530
+
1531
+ # icon or first image (defined using build_finder_for instead of zafu_known_context for performance reasons).
1532
+ def r_icon
1533
+ if !@params[:in] && !@params[:where] && !@params[:from] && !@params[:find]
1534
+ finder, klass = build_finder_for(:first, 'icon', @params.merge(:or => 'image', :order => 'l_id desc, position asc, name asc', :group => 'id,l_id'))
1535
+ return unless finder
1536
+ return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
1537
+ do_var(finder, :node_class => klass)
1538
+ else
1539
+ r_unknown
1540
+ end
1541
+ end
1542
+
1543
+ def r_date
1544
+ select = @params[:select]
1545
+ case select
1546
+ when 'main'
1547
+ expand_with(:date=>'main_date')
1548
+ when 'now'
1549
+ expand_with(:date=>'Time.now')
1550
+ else
1551
+ if select =~ /^\d{4}-\d{1,2}-\d{1,2}$/
1552
+ begin
1553
+ d = Date.parse(select)
1554
+ expand_with(:date=>select.inspect)
1555
+ rescue
1556
+ parser_error("invalid date '#{select}' should be 'YYYY-MM-DD'")
1557
+ end
1558
+ elsif date = find_stored(Date, select)
1559
+ if date[0..0] == '"'
1560
+ begin
1561
+ d = Date.parse(date[1..-2])
1562
+ expand_with(:date=>date)
1563
+ rescue
1564
+ parser_error("invalid date #{select} (#{date}) should be 'YYYY-MM-DD'")
1565
+ end
1566
+ else
1567
+ expand_with(:date=>select)
1568
+ end
1569
+ elsif select =~ /\[(.*)\]/
1570
+ date, static = parse_attributes_in_value(select, :erb => false)
1571
+ expand_with(:date => "\"#{date}\"")
1572
+ else
1573
+ parser_error("bad parameter '#{select}'")
1574
+ end
1575
+ end
1576
+ end
1577
+
1578
+ def r_javascripts
1579
+ if @params[:list].nil?
1580
+ list = %w{ prototype effects tablekit zena }
1581
+ elsif @params[:list] == 'all'
1582
+ list = %w{ prototype effects dragdrop tablekit zena }
1583
+ else
1584
+ list = @params[:list].split(',').map{|e| e.strip}
1585
+ end
1586
+ helper.javascript_include_tag(*list)
1587
+ end
1588
+
1589
+ def r_stylesheets
1590
+ if @params[:list] == 'all' || @params[:list].nil?
1591
+ list = %w{ zena code }
1592
+ else
1593
+ list = @params[:list].split(',').map{|e| e.strip}
1594
+ end
1595
+ list << {:media => @params[:media]} if @params[:media]
1596
+ helper.stylesheet_link_tag(*list)
1597
+ end
1598
+
1599
+ def r_flash_messages
1600
+ type = @params[:show] || 'both'
1601
+ "<div id='messages'>" +
1602
+ if (type == 'notice' || type == 'both')
1603
+ "<% if flash[:notice] -%><div id='notice' class='flash' onclick='new Effect.Fade(\"error\")'><%= flash[:notice] %></div><% end -%>"
1604
+ else
1605
+ ''
1606
+ end +
1607
+ if (type == 'error' || type == 'both')
1608
+ "<% if flash[:error] -%><div id='error' class='flash' onclick='new Effect.Fade(\"error\")'><%= flash[:error] %></div><% end -%>"
1609
+ else
1610
+ ''
1611
+ end +
1612
+ "</div>"
1613
+ end
1614
+
1615
+ # Shows a 'made with zena' link or logo. ;-) Thanks for using this !
1616
+ # TODO: test and add translation.
1617
+ # <r:zena show='logo'/> or <r:zena show='text'/> == <r:zena/>
1618
+ def r_zena
1619
+ if logo = @params[:logo]
1620
+ # FIXME
1621
+ case logo
1622
+ when 'tiny'
1623
+ else
1624
+ end
1625
+ else
1626
+ text = case @params[:type]
1627
+ when 'riding'
1628
+ _("riding zena")
1629
+ when 'peace'
1630
+ _("in peace with zena")
1631
+ when 'garden'
1632
+ _("a zen garden")
1633
+ else
1634
+ _("made with zena")
1635
+ end
1636
+ "<a class='zena' href='http://zenadmin.org' title='zena <%= Zena::VERSION %>'>#{text}</a>"
1637
+ end
1638
+ end
1639
+
1640
+ def r_design
1641
+ if @params[:by]
1642
+ by = "<a href='#{@params[:href]}'>#{@params[:by]}</a>"
1643
+ else
1644
+ by = expand_with(:trans => true)
1645
+ end
1646
+ unless skin = @params[:skin]
1647
+ skin = helper.instance_variable_get(:@controller).instance_variable_get(:@skin_name)
1648
+ end
1649
+ skin = "<i>#{skin}</i>" unless skin.blank?
1650
+ _("%{skin}, design by %{name}") % {:name => by, :skin => skin}
1651
+ end
1652
+
1653
+ # creates a link. Options are:
1654
+ # :href (node, parent, project, root)
1655
+ # :tattr (translated attribute used as text link)
1656
+ # :attr (attribute used as text link)
1657
+ # <r:link href='node'><r:trans attr='lang'/></r:link>
1658
+ # <r:link href='node' tattr='lang'/>
1659
+ # <r:link update='dom_id'/>
1660
+ # <r:link page='next'/> <r:link page='previous'/> <r:link page='list'/>
1661
+ def r_link
1662
+ if @params[:page]
1663
+ pagination_links
1664
+ else
1665
+ make_link
1666
+ end
1667
+ end
1668
+
1669
+ def make_link(options = {})
1670
+ query_params = options[:query_params] || {}
1671
+ default_text = options[:default_text]
1672
+ params = @params.dup
1673
+
1674
+ opts = {}
1675
+ if upd = params.delete(:update)
1676
+ return unless remote_target = find_target(upd)
1677
+ end
1678
+
1679
+ if href = params.delete(:href)
1680
+ if lnode = find_stored(Node, href)
1681
+ # using stored node
1682
+ else
1683
+ lnode, klass = build_finder_for(:first, href, {})
1684
+ return unless lnode
1685
+ return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
1686
+ end
1687
+ else
1688
+ # obj
1689
+ if node_class == Version
1690
+ lnode = "#{node}.node"
1691
+ opts[:lang] = "#{node}.lang"
1692
+ elsif node_kind_of?(Node)
1693
+ lnode = node
1694
+ else
1695
+ lnode = @context[:previous_node]
1696
+ end
1697
+ end
1698
+
1699
+ if fmt = params.delete(:format)
1700
+ if fmt == 'data'
1701
+ opts[:format] = "#{node}.c_ext"
1702
+ else
1703
+ opts[:format] = fmt.inspect
1704
+ end
1705
+ end
1706
+
1707
+ if mode = params.delete(:mode)
1708
+ opts[:mode] = mode.inspect
1709
+ end
1710
+
1711
+ if sharp = params.delete(:sharp)
1712
+ opts[:sharp] = sharp.inspect
1713
+ end
1714
+
1715
+ if sharp_in = params.delete(:in)
1716
+ finder, klass = build_finder_for(:first, sharp_in, {})
1717
+ return unless finder
1718
+ return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
1719
+ opts[:sharp_in] = finder
1720
+ end
1721
+
1722
+ if @html_tag && @html_tag != 'a'
1723
+ # FIXME: can we remove this ?
1724
+ # html attributes do not belong to anchor
1725
+ pre_space = ''
1726
+ html_params = {}
1727
+ else
1728
+ html_params = get_html_params(params.merge(@html_tag_params), :link)
1729
+ pre_space = @space_before || ''
1730
+ @html_tag_done = true
1731
+ end
1732
+
1733
+ (params.keys - [:style, :class, :id, :rel, :name, :anchor, :attr, :tattr, :trans, :text, :page]).each do |k|
1734
+ next if k.to_s =~ /if_|set_/
1735
+ query_params[k] = params[k]
1736
+ end
1737
+
1738
+ # TODO: merge these two query_params cleanup things into something cleaner.
1739
+ if remote_target
1740
+ # ajax
1741
+ query_params_list = []
1742
+ query_params.each do |k,v|
1743
+ if k == :date
1744
+ if v == 'current_date'
1745
+ str = "\#{#{current_date}}"
1746
+ elsif v =~ /\A\d/
1747
+ str = CGI.escape(v.gsub('"',''))
1748
+ elsif v =~ /\[/
1749
+ attribute, static = parse_attributes_in_value(v.gsub('"',''), :erb => false)
1750
+ str = static ? CGI.escape(attribute) : "\#{CGI.escape(\"#{attribute}\")}"
1751
+ else
1752
+ str = "\#{CGI.escape(#{node_attribute(v)})}"
1753
+ end
1754
+ else
1755
+ attribute, static = parse_attributes_in_value(v.gsub('"',''), :erb => false)
1756
+ str = static ? CGI.escape(attribute) : "\#{CGI.escape(\"#{attribute}\")}"
1757
+ end
1758
+ query_params_list << "#{k.to_s.gsub('"','')}=#{str}"
1759
+ end
1760
+ pre_space + link_to_update(remote_target, :node_id => "#{lnode}.zip", :query_params => query_params_list, :default_text => default_text, :html_params => html_params)
1761
+ else
1762
+ # direct link
1763
+ query_params.each do |k,v|
1764
+ if k == :date
1765
+ if v == 'current_date'
1766
+ query_params[k] = current_date
1767
+ elsif v =~ /\A\d/
1768
+ query_params[k] = v.inspect
1769
+ elsif v =~ /\[/
1770
+ attribute, static = parse_attributes_in_value(v.gsub('"',''), :erb => false)
1771
+ query_params[k] = "\"#{attribute}\""
1772
+ else
1773
+ query_params[k] = node_attribute(v)
1774
+ end
1775
+ else
1776
+ attribute, static = parse_attributes_in_value(v.gsub('"',''), :erb => false)
1777
+ query_params[k] = "\"#{attribute}\""
1778
+ end
1779
+ end
1780
+
1781
+ query_params.merge!(opts)
1782
+
1783
+ opts_str = ''
1784
+ query_params.keys.sort {|a,b| a.to_s <=> b.to_s }.each do |k|
1785
+ opts_str << ",:#{k.to_s.gsub(/[^a-z_A-Z_]/,'')}=>#{query_params[k]}"
1786
+ end
1787
+
1788
+ opts_str += ", :host => #{@context["exp_host"]}" if @context["exp_host"]
1789
+
1790
+ pre_space + "<a#{params_to_html(html_params)} href='<%= zen_path(#{lnode}#{opts_str}) %>'>#{text_for_link(default_text)}</a>"
1791
+ end
1792
+ end
1793
+
1794
+ # <r:link page='next'/> <r:link page='previous'/> <r:link page='list'/>
1795
+ def pagination_links
1796
+ return parser_error("not in pagination scope") unless pagination_key = @context[:paginate]
1797
+ case @params[:page]
1798
+ when 'previous'
1799
+ out "<% if set_#{pagination_key}_previous = (set_#{pagination_key} > 1 ? set_#{pagination_key} - 1 : nil) -%>"
1800
+ @context[:vars] ||= []
1801
+ @context[:vars] << "#{pagination_key}_previous"
1802
+ out make_link(:default_text => "<%= set_#{pagination_key}_previous %>", :query_params => {pagination_key => "[#{pagination_key}_previous]"})
1803
+ if descendant('else')
1804
+ out expand_with(:in_if => true, :only => ['else', 'elsif'])
1805
+ end
1806
+ out "<% end -%>"
1807
+ when 'next'
1808
+ out "<% if set_#{pagination_key}_next = (set_#{pagination_key}_count - set_#{pagination_key} > 0 ? set_#{pagination_key} + 1 : nil) -%>"
1809
+ @context[:vars] ||= []
1810
+ @context[:vars] << "#{pagination_key}_next"
1811
+ out make_link(:default_text => "<%= set_#{pagination_key}_next %>", :query_params => {pagination_key => "[#{pagination_key}_next]"})
1812
+ if descendant('else')
1813
+ out expand_with(:in_if => true, :only => ['else', 'elsif'])
1814
+ end
1815
+ out "<% end -%>"
1816
+ when 'list'
1817
+ @context[:vars] ||= []
1818
+ @context[:vars] << "#{pagination_key}_page"
1819
+ if @blocks == [] || (@blocks.size == 1 && !@blocks.first.kind_of?(String) && @blocks.first.method == 'else')
1820
+ # add a default block
1821
+ if tag = @params[:tag]
1822
+ open_tag = "<#{tag}>"
1823
+ close_tag = "</#{tag}>"
1824
+ else
1825
+ open_tag = close_tag = ''
1826
+ end
1827
+ link_params = {}
1828
+ @params.each do |k,v|
1829
+ next if [:tag, :page, :join, :page_count].include?(k)
1830
+ link_params[k] = v
1831
+ end
1832
+ text = "#{open_tag}<r:link #{params_to_html(link_params)} #{pagination_key}='[#{pagination_key}_page]' do='[#{pagination_key}_page]'/>#{close_tag}"
1833
+ @blocks = [make(:void, :method=>'void', :text=>text)]
1834
+ remove_instance_variable(:@all_descendants)
1835
+ end
1836
+
1837
+ if !descendant('else')
1838
+ @blocks += [make(:void, :method=>'void', :text=>"<r:else>#{open_tag}<r:show var='#{pagination_key}_page'/>#{close_tag}</r:else>")]
1839
+ remove_instance_variable(:@all_descendants)
1840
+ end
1841
+
1842
+ out "<% page_numbers(set_#{pagination_key}, set_#{pagination_key}_count, #{(@params[:join] || ' ').inspect}, #{@params[:page_count] ? @params[:page_count].to_i : 'nil'}) do |set_#{pagination_key}_page, #{pagination_key}_page_join| %>"
1843
+ out "<%= #{pagination_key}_page_join %>"
1844
+ out "<% if set_#{pagination_key}_page != set_#{pagination_key} -%>"
1845
+ out expand_with(:in_if => true)
1846
+ out "<% end; end -%>"
1847
+ else
1848
+ parser_error("unkown 'page' option #{@params[:page].inspect} should be ('previous', 'next' or 'list')")
1849
+ end
1850
+ end
1851
+
1852
+ def r_img
1853
+ return unless node_kind_of?(Node)
1854
+ if @params[:src]
1855
+ finder, klass = build_finder_for(:first, @params[:src])
1856
+ return unless finder
1857
+ return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
1858
+ img = finder
1859
+ else
1860
+ img = node
1861
+ end
1862
+ mode = @params[:mode] || 'std'
1863
+ # FIXME: replace this call by something that integrates better with html_tag_params and such.
1864
+ res = "img_tag(#{img}, :mode=>#{mode.inspect}"
1865
+ [:class, :alt_src, :id, :border, :style].each do |k|
1866
+ res += ", :#{k}=>#{@params[k].inspect}" if @params[k]
1867
+ end
1868
+ res += ", :host => #{@context["exp_host"]}" if @context["exp_host"]
1869
+ res += ")"
1870
+ if @params[:link]
1871
+ finder, klass = build_finder_for(:first, @params[:link])
1872
+ return unless finder
1873
+ return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
1874
+
1875
+ opts_str = @context["exp_host"] ? ", :host => #{@context["exp_host"]}" : ""
1876
+
1877
+ "<a href='<%= zen_path(#{finder}#{opts_str}) %>'><%= #{res} %></a>"
1878
+ else
1879
+ "<%= #{res} %>"
1880
+ end
1881
+ end
1882
+
1883
+ def r_calendar
1884
+ if @context[:block] == self
1885
+ # called from self (storing template / rendering)
1886
+ if role = @params[:assign_as]
1887
+ assign_calendar(role)
1888
+ else
1889
+ display_calendar
1890
+ end
1891
+ else
1892
+ # This is called first to prepare calendar
1893
+ if @params[:assign_as]
1894
+ fld = 'date'
1895
+ table_name = 'links'
1896
+ else
1897
+ fld = @params[:date] || 'event_at'
1898
+ if ['log_at', 'created_at', 'updated_at', 'event_at'].include?(fld) # TODO: use rubyless to learn type
1899
+ table_name = 'nodes'
1900
+ elsif fld == 'l_date'
1901
+ fld = 'date'
1902
+ table_name = 'links'
1903
+ else
1904
+ return parser_error("Invalid 'date' value for calendar (#{fld.inspect}).")
1905
+ end
1906
+ end
1907
+
1908
+ @date_scope = "TABLE_NAME[#{table_name}].#{fld} >= '\#{start_date.strftime('%Y-%m-%d')}' AND TABLE_NAME[#{table_name}].#{fld} <= '\#{end_date.strftime('%Y-%m-%d')}'"
1909
+
1910
+ new_dom_scope
1911
+
1912
+ # SAVED TEMPLATE
1913
+ template = expand_block(self, :block => self, :saved_template => true)
1914
+ out helper.save_erb_to_url(template, template_url)
1915
+
1916
+ # INLINE
1917
+ out expand_block(self, :block => self, :saved_template => false)
1918
+ end
1919
+ end
1920
+
1921
+ def display_calendar
1922
+ size = (params[:size] || 'large').to_sym
1923
+ finder = params[:select] || 'notes in project'
1924
+
1925
+ if @blocks == []
1926
+ # add a default <r:link/> block
1927
+ if size == :tiny
1928
+ @blocks = [make(:void, :method=>'void', :text=>"<em do='link' date='current_date' do='[current_date]' format='%d'/><r:else do='[current_date]' format='%d'/>")]
1929
+ else
1930
+ @blocks = [make(:void, :method=>'void', :text=>"<span do='show' date='current_date' format='%d'/><ul><li do='each' do='link' attr='name'/></ul><r:else do='[current_date]' format='%d'/>")]
1931
+ end
1932
+ remove_instance_variable(:@all_descendants)
1933
+ elsif !descendant('else')
1934
+ @blocks += [make(:void, :method=>'void', :text=>"<r:else do='[current_date]' format='%d'/>")]
1935
+ remove_instance_variable(:@all_descendants)
1936
+ end
1937
+
1938
+ @html_tag_done = false
1939
+ @html_tag_params[:id] = erb_dom_id
1940
+ @html_tag_params[:class] ||= "#{size}cal"
1941
+ @html_tag ||= 'div'
1942
+
1943
+ finder, klass = build_finder_for(:all, finder, @params, [@date_scope])
1944
+ return unless finder
1945
+ return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
1946
+
1947
+ cell_code = "<% if #{list_var} = nodes_#{list_var}[cal_#{list_var}.strftime('%Y-%m-%d %H')] -%>#{expand_with(:in_if => true, :list => list_var, :date => "cal_#{list_var}", :saved_template => nil, :dom_prefix => nil, :in_calendar => true)}<% end -%>"
1948
+
1949
+ render_html_tag(calendar_code(finder, "", cell_code, "", params))
1950
+ end
1951
+
1952
+ # manage links from @node ---- reference ----> ...
1953
+ # <div do='calendar' assign='reference' to='main' split_hours='12' />
1954
+ def assign_calendar(as_role)
1955
+ size = (params[:size] || 'large').to_sym
1956
+ @html_tag_done = false
1957
+ @html_tag_params[:id] = erb_dom_id
1958
+ @html_tag_params[:class] ||= "#{size}cal"
1959
+ @html_tag ||= 'div'
1960
+ if rel = RelationProxy.find_by_role(as_role.singularize)
1961
+ role = rel.this_role
1962
+ else
1963
+ return parser_error("Invalid role #{as_role.inspect}.")
1964
+ end
1965
+ finder, klass = build_finder_for(:all, role, @params, [@date_scope])
1966
+ return unless finder
1967
+ return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
1968
+
1969
+ # SAVED TEMPLATE ========
1970
+ template_url = self.template_url + 'cell'
1971
+ template = "<%= cal_assign_cell(@node, #{role.inspect}, #{@params[:used].inspect}) %>"
1972
+ out helper.save_erb_to_url(template, template_url)
1973
+
1974
+ # we call update on node 'B'
1975
+ # A (main)
1976
+ # ... B (other node)
1977
+ # calendar (in B context) ---- role --->
1978
+
1979
+ cell_prefix_code = "<span><%= day_#{list_var}.strftime('%d').to_i -%></span><ul>"
1980
+ cell_code = "<%= #{list_var} = nodes_#{list_var}[cal_#{list_var}.strftime('%Y-%m-%d %H')]; #{node}.linked_node = #{list_var} ? #{list_var}.first : nil; cal_assign_cell(#{node}, #{role.inspect}, #{@params[:used].inspect}, params[:s] || @node.zip, cal_#{list_var}, #{template_url.inspect}) %>"
1981
+ cell_postfix_code = "</ul>"
1982
+ render_html_tag(calendar_code(finder, cell_prefix_code, cell_code, cell_postfix_code, params))
1983
+ end
1984
+
1985
+ def calendar_code(finder, cell_prefix_code, cell_code, cell_postfix_code, params)
1986
+ type = params[:type] ? params[:type].to_sym : :month
1987
+ size = (params[:size] || 'large').to_sym
1988
+ ref_date = params[:assign_as] ? 'l_date' : (params[:date] || 'event_at')
1989
+
1990
+ case type
1991
+ when :month
1992
+ title = "\"\#{_(Date::MONTHNAMES[main_date.mon])} \#{main_date.year}\""
1993
+ prev_date = "\#{main_date.advance(:months => -1).strftime(\"%Y-%m-%d\")}"
1994
+ next_date = "\#{main_date.advance(:months => 1).strftime(\"%Y-%m-%d\")}"
1995
+ when :week
1996
+ title = "\"\#{_(Date::MONTHNAMES[main_date.mon])} \#{main_date.year}\""
1997
+ prev_date = "\#{main_date.advance(:days => -7).strftime(\"%Y-%m-%d\")}"
1998
+ next_date = "\#{main_date.advance(:days => +7).strftime(\"%Y-%m-%d\")}"
1999
+ else
2000
+ return parser_error("invalid type (should be 'month' or 'week')")
2001
+ end
2002
+
2003
+ if hours = @params[:split_hours]
2004
+ hours = hours.split(',').map{|l| l.to_i}
2005
+ hours << 0
2006
+ hours = hours.uniq.sort
2007
+ # I feel all this would be much better if we could use "each_group" but then how do we access hours ?
2008
+ week_code = "<% week.step(week+6,1) do |day_#{list_var}| -%>
2009
+ <td<%= cal_class(day_#{list_var},#{current_date}) %>>#{cell_prefix_code}<% #{hours.inspect}.each do |set_hour|; cal_#{list_var} = Time.utc(day_#{list_var}.year,day_#{list_var}.month,day_#{list_var}.day,set_hour) -%>#{cell_code}<% end -%>#{cell_postfix_code}</td>
2010
+ <% end -%>"
2011
+ (@context[:vars] ||= []) << "hour"
2012
+ else
2013
+ hours = nil
2014
+ week_code = "<% week.step(week+6,1) do |day_#{list_var}| -%>
2015
+ <td<%= cal_class(day_#{list_var},#{current_date}) %>><% cal_#{list_var} = Time.utc(day_#{list_var}.year,day_#{list_var}.month,day_#{list_var}.day) -%>#{cell_prefix_code}#{cell_code}#{cell_postfix_code}</td>
2016
+ <% end -%>"
2017
+ end
2018
+
2019
+ res = <<-END_TXT
2020
+ <h3 class='title'>
2021
+ <span><%= link_to_remote(#{_('img_prev_page').inspect}, :url => #{base_class.to_s.underscore}_path(#{node_id}) + \"/zafu?t_url=#{CGI.escape(template_url)}&dom_id=#{dom_id}&date=#{prev_date}&#{start_node_s_param(:string)}\", :method => :get) %></span>
2022
+ <span class='date'><%= link_to_remote(#{title}, :url => #{base_class.to_s.underscore}_path(#{node_id}) + \"/zafu?t_url=#{CGI.escape(template_url)}&dom_id=#{dom_id}&#{start_node_s_param(:string)}\", :method => :get) %></span>
2023
+ <span><%= link_to_remote(#{_('img_next_page').inspect}, :url => #{base_class.to_s.underscore}_path(#{node_id}) + \"/zafu?t_url=#{CGI.escape(template_url)}&dom_id=#{dom_id}&date=#{next_date}&#{start_node_s_param(:string)}\", :method => :get) %></span>
2024
+ </h3>
2025
+ <table cellspacing='0' class='#{size}cal#{@params[:assign_as] ? " assign" : ''}'>
2026
+ <tr class='head'><%= cal_day_names(#{size.inspect}) %></tr>
2027
+ <% start_date, end_date = cal_start_end(#{current_date}, #{type.inspect}) -%>
2028
+ <% cal_weeks(#{ref_date.to_sym.inspect}, #{finder}, start_date, end_date, #{hours.inspect}) do |week, nodes_#{list_var}| -%>
2029
+ <tr class='body'>
2030
+ #{week_code}
2031
+ </tr>
2032
+ <% end -%>
2033
+ </table>
2034
+ END_TXT
2035
+ end
2036
+
2037
+ # part caching
2038
+ def r_cache
2039
+ kpath = @params[:kpath] || Page.kpath
2040
+ out "<% #{cache} = Cache.with(visitor.id, visitor.group_ids, #{kpath.inspect}, #{helper.send(:lang).inspect}, #{template_url.inspect}) do capture do %>"
2041
+ out expand_with
2042
+ out "<% end; end %><%= #{cache} %>"
2043
+ end
2044
+
2045
+ # recursion
2046
+ def r_include
2047
+ return '' if @context[:saved_template]
2048
+ return super if @params[:template] || !@params[:part]
2049
+ part = @params[:part].gsub(/[^a-zA-Z_]/,'')
2050
+ method_name = @context["#{part}_method".to_sym]
2051
+ return parser_error("no parent named '#{part}'") unless method_name
2052
+ "<%= #{method_name}(depth+1,#{node},#{list}) %>"
2053
+ end
2054
+
2055
+ # use all other tags as relations
2056
+ def r_unknown
2057
+ @params[:select] = @method
2058
+ r_context
2059
+ end
2060
+
2061
+ # Enter a new context (<r:context find='all' method='pages'>). This is the same as '<r:pages>...</r:pages>'). It is
2062
+ # considered better style to use '<r:pages>...</r:pages>' instead of the more general '<r:context>' because the tags
2063
+ # give a clue on the context at start and end. Another way to open a context is the 'do' syntax: "<div do='pages'>...</div>".
2064
+ # FIXME: 'else' clause has been removed, find a solution to put it back.
2065
+ def r_context
2066
+ # DRY ! (build_finder_for, block)
2067
+ return parser_error("missing 'method' parameter") unless method = @params[:select]
2068
+
2069
+ context = node_class.zafu_known_contexts[method]
2070
+ if context && @params.keys == [:select]
2071
+ open_context("#{node}.#{method}", context)
2072
+ elsif node_kind_of?(Node)
2073
+ count = ['first','all','count'].include?(@params[:find]) ? @params[:find].to_sym : nil
2074
+ count ||= Node.plural_relation?(method) ? :all : :first
2075
+ finder, klass, query = build_finder_for(count, method, @params)
2076
+ return unless finder
2077
+ if node_kind_of?(Node) && !klass.ancestors.include?(Node)
2078
+ # moving out of node: store last Node
2079
+ @context[:previous_node] = node
2080
+ end
2081
+ if count == :all
2082
+ # plural
2083
+ do_list( finder, query, :node_class => klass)
2084
+ # elsif count == :count
2085
+ # "<%= #{build_finder_for(count, method, @params)} %>"
2086
+ else
2087
+ # singular
2088
+ do_var( finder, :node_class => klass)
2089
+ end
2090
+ else
2091
+ "unknown relation (#{method}) for #{node_class} class"
2092
+ end
2093
+ end
2094
+
2095
+ def open_context(finder, context)
2096
+ klass = context[:node_class]
2097
+ # hack to store last 'Node' context until we fix node(Node) stuff:
2098
+ previous_node = node_kind_of?(Node) ? node : @context[:previous_node]
2099
+ if klass.kind_of?(Array)
2100
+ # plural
2101
+ do_list( finder, nil, context.merge(:node_class => klass[0], :previous_node => previous_node) )
2102
+ else
2103
+ # singular
2104
+ do_var( finder, context.merge(:previous_node => previous_node) )
2105
+ end
2106
+ end
2107
+
2108
+ # Prepare stylesheet and xml content for xsl-fo post-processor
2109
+ def r_fop
2110
+ return parser_error("missing 'stylesheet' argument") unless @params[:stylesheet]
2111
+ # get stylesheet text
2112
+ xsl_content, absolute_url, doc = self.class.get_template_text(@params[:stylesheet], @options[:helper], @options[:current_folder])
2113
+ return parser_error("stylesheet #{@params[:stylesheet].inspect} not found") unless doc
2114
+
2115
+ template_url = (self.template_url.split('/')[0..-2] + ['_main.xsl']).join('/')
2116
+ helper.save_erb_to_url(xsl_content, template_url)
2117
+ out "<?xml version='1.0' encoding='utf-8'?>\n"
2118
+ out "<!-- xsl_id:#{doc[:id] } -->\n" if doc
2119
+ out expand_with
2120
+ end
2121
+
2122
+ # Prepare content for LateX post-processor
2123
+ def r_latex
2124
+ out "% latex\n"
2125
+ # all content inside this will be informed to render for Latex output
2126
+ out expand_with(:output_format => 'latex')
2127
+ end
2128
+
2129
+ def r_debug
2130
+ return '' unless @context[:dev]
2131
+ add_html_class('debug')
2132
+ out "<p>#{@params[:title]}</p>" if @params[:title]
2133
+ (@params[:show] || '').split(',').map(&:strip).each do |what|
2134
+ case what
2135
+ when 'params'
2136
+ out "<pre><%= params.inspect %></pre>"
2137
+ else
2138
+ parser_error("invalid element to show. Options are ['params'].")
2139
+ end
2140
+ end
2141
+ out expand_with
2142
+ end
2143
+
2144
+ # ================== HELPER METHODS ================
2145
+
2146
+ # Create an sql query to open a new context (passes its arguments to HasRelations#build_find)
2147
+ def build_finder_for(count, rel, params=@params, raw_filters = [])
2148
+ if (context = node_class.zafu_known_contexts[rel]) && !params[:in] && !params[:where] && !params[:from] && !params[:order] && raw_filters == []
2149
+ klass = context[:node_class]
2150
+
2151
+ if klass.kind_of?(Array) && count == :all
2152
+ return ["#{node}.#{rel}", klass[0]]
2153
+ else
2154
+ return [(count == :all ? "[#{node}.#{rel}]" : "#{node}.#{rel}"), klass]
2155
+ end
2156
+ end
2157
+
2158
+ rel ||= 'self'
2159
+ if (count == :first)
2160
+ if rel == 'self'
2161
+ return [node, node_class]
2162
+ elsif rel == 'main'
2163
+ return ["@node", Node]
2164
+ elsif rel == 'root'
2165
+ return ["(secure(Node) { Node.find(#{current_site[:root_id]})})", Node]
2166
+ elsif rel == 'start'
2167
+ return ["start_node", Node]
2168
+ elsif rel == 'visitor'
2169
+ return ["visitor.contact", Node]
2170
+ elsif rel =~ /^\d+$/
2171
+ return ["(secure(Node) { Node.find_by_zip(#{rel.inspect})})", Node]
2172
+ elsif node_name = find_stored(Node, rel)
2173
+ return [node_name, Node]
2174
+ elsif rel[0..0] == '/'
2175
+ rel = rel[1..-1]
2176
+ return ["(secure(Node) { Node.find_by_path(#{rel.inspect})})", Node]
2177
+ end
2178
+ end
2179
+
2180
+ pseudo_sql, add_raw_filters = make_pseudo_sql(rel, params)
2181
+ raw_filters += add_raw_filters if add_raw_filters
2182
+
2183
+ # FIXME: stored should be clarified and managed in a single way through links and contexts.
2184
+ # <r:void store='foo'>...
2185
+ # <r:link href='foo'/>
2186
+ # <r:pages from='foo'/> <-- this is just a matter of changing node parameter
2187
+ # <r:pages from='site' project='foo'/>
2188
+ # <r:img link='foo'/>
2189
+ # ...
2190
+
2191
+ if node_kind_of?(Node)
2192
+ node_name = @context[:parent_node] || node
2193
+ else
2194
+ node_name = @context[:previous_node]
2195
+ end
2196
+
2197
+ # make sure we do not use a new record in a find query:
2198
+ query = Node.build_find(count, pseudo_sql, :node_name => node_name, :raw_filters => raw_filters, :ref_date => "\#{#{current_date}}")
2199
+
2200
+ unless query.valid?
2201
+ out parser_error(query.errors.join(' '), pseudo_sql.join(', '))
2202
+ return nil
2203
+ end
2204
+
2205
+
2206
+ if count == :count
2207
+ out "<%= #{query.finder(:count)} %>"
2208
+ return nil
2209
+ end
2210
+
2211
+ klass = query.main_class
2212
+
2213
+ if params[:else]
2214
+ # FIXME: else not working with zafu_known_contexts
2215
+ finder, else_class, else_query = build_finder_for(count, params[:else], {})
2216
+ if finder && (else_query.nil? || else_query.valid?) && (else_class == klass || klass.ancestors.include?(else_class) || else_class.ancestors.include?(klass))
2217
+ ["(#{query.finder(count)} || #{finder})", klass, query]
2218
+ else
2219
+ [query.finder(count), query.main_class, query]
2220
+ end
2221
+ else
2222
+ [query.finder(count), query.main_class, query]
2223
+ end
2224
+ end
2225
+
2226
+ # Build pseudo sql from the parameters
2227
+ # comments where ... from ... in ... order ... limit
2228
+ def make_pseudo_sql(rel, params=@params)
2229
+ parts = [rel.dup]
2230
+ filters = []
2231
+
2232
+ if params[:from]
2233
+ parts << params[:from]
2234
+
2235
+ key_counter = 1
2236
+ while sub_part = params["from#{key_counter}".to_sym]
2237
+ key_counter += 1
2238
+ parts << sub_part
2239
+ end
2240
+ end
2241
+
2242
+ if params[:where]
2243
+ parts[0] << " where #{params[:where]}"
2244
+ end
2245
+
2246
+ if params[:in]
2247
+ parts[-1] << " in #{params[:in]}"
2248
+ end
2249
+
2250
+ if group = params[:group]
2251
+ parts[-1] << " group by #{group}" unless parts[0] =~ /group by/
2252
+ end
2253
+
2254
+ if order = params[:order]
2255
+ parts[-1] << " order by #{order}" unless parts[0] =~ /order by/
2256
+ end
2257
+
2258
+ if paginate = params[:paginate]
2259
+ page_size = params[:limit].to_i
2260
+ page_size = 20 if page_size < 1
2261
+ parts[-1] << " limit #{page_size} paginate #{paginate.gsub(/[^a-z_A-Z]/,'')}"
2262
+ else
2263
+ [:limit, :offset].each do |k|
2264
+ next unless params[k]
2265
+ parts[-1] << " #{k} #{params[k]}" unless parts[0] =~ / #{k} /
2266
+ end
2267
+ end
2268
+
2269
+ finders = [parts.join(' from ')]
2270
+ if params[:or]
2271
+ finders << params[:or]
2272
+
2273
+ key_counter = 1
2274
+ while sub_or = params["or#{key_counter}".to_sym]
2275
+ key_counter += 1
2276
+ finders << sub_or
2277
+ end
2278
+ else
2279
+ or_clause = nil
2280
+ end
2281
+
2282
+ return [finders, parse_raw_filters(params)]
2283
+ end
2284
+
2285
+ # Parse special filters
2286
+ def parse_raw_filters(params)
2287
+ filters = []
2288
+
2289
+ if value = params[:author]
2290
+ if stored = find_stored(User, value)
2291
+ filters << "TABLE_NAME.user_id = '\#{#{stored}.id}'"
2292
+ elsif value == 'current'
2293
+ filters << "TABLE_NAME.user_id = '\#{#{node}[:user_id]}'"
2294
+ elsif value == 'visitor'
2295
+ filters << "TABLE_NAME.user_id = '\#{visitor[:id]}'"
2296
+ elsif value =~ /\A\d+\Z/
2297
+ filters << "TABLE_NAME.user_id = '#{value.to_i}'"
2298
+ elsif value =~ /\A[\w\/]+\Z/
2299
+ # TODO: path, not implemented yet
2300
+ end
2301
+ end
2302
+
2303
+ if value = params[:project]
2304
+ if stored = find_stored(Node, value)
2305
+ filters << "TABLE_NAME.project_id = '\#{#{stored}.get_project_id}'"
2306
+ elsif value == 'current'
2307
+ filters << "TABLE_NAME.project_id = '\#{#{node}.get_project_id}'"
2308
+ elsif value =~ /\A\d+\Z/
2309
+ filters << "TABLE_NAME.project_id = '#{value.to_i}'"
2310
+ elsif value =~ /\A[\w\/]+\Z/
2311
+ # TODO: path, not implemented yet
2312
+ end
2313
+ end
2314
+
2315
+ if value = params[:section]
2316
+ if stored = find_stored(Node, value)
2317
+ filters << "TABLE_NAME.section_id = '\#{#{stored}.get_section_id}'"
2318
+ elsif value == 'current'
2319
+ filters << "TABLE_NAME.section_id = '\#{#{node}.get_section_id}'"
2320
+ elsif value =~ /\A\d+\Z/
2321
+ filters << "TABLE_NAME.section_id = '#{value.to_i}'"
2322
+ elsif value =~ /\A[\w\/]+\Z/
2323
+ # not implemented yet
2324
+ end
2325
+ end
2326
+
2327
+ [:updated, :created, :event, :log].each do |k|
2328
+ if value = params[k]
2329
+ # current, same are synonym for 'today'
2330
+ filters << date_condition(value,"TABLE_NAME.#{k}_at",current_date)
2331
+ end
2332
+ end
2333
+
2334
+ filters == [] ? nil : filters
2335
+ end
2336
+
2337
+ # helpers
2338
+ # get current output format
2339
+ def output_format
2340
+ @context[:output_format] || 'html'
2341
+ end
2342
+
2343
+ # find the current node name in the context
2344
+ def node(klass = self.node_class)
2345
+ if klass == self.node_class
2346
+ (@context[:saved_template] && @context[:main_node]) ? "@#{base_class.to_s.underscore}" : (@context[:node] || '@node')
2347
+ elsif klass == Node
2348
+ @context[:previous_node] || '@node'
2349
+ else
2350
+ # ?
2351
+ out parser_error("could not find node_name for #{klass} (current class is #{node_class})")
2352
+ '@node'
2353
+ end
2354
+ end
2355
+
2356
+ def erb_node_id(obj = node)
2357
+ if node_kind_of?(Version)
2358
+ "<%= #{obj}.node.zip %>.<%= #{obj}.number %>"
2359
+ else
2360
+ "<%= #{node_id(obj)} %>"
2361
+ end
2362
+ end
2363
+
2364
+ def node_id(obj = node)
2365
+ "#{obj}.zip"
2366
+ end
2367
+
2368
+ def current_date
2369
+ @context[:date] || 'main_date'
2370
+ end
2371
+
2372
+ def var
2373
+ return @var if @var
2374
+ if node =~ /^var(\d+)$/
2375
+ @var = "var#{$1.to_i + 1}"
2376
+ else
2377
+ @var = "var1"
2378
+ end
2379
+ end
2380
+
2381
+ def cache
2382
+ return @cache if @cache
2383
+ if @context[:cache] =~ /^cache(\d+)$/
2384
+ @cache = "cache#{$1.to_i + 1}"
2385
+ else
2386
+ @cache = "cache1"
2387
+ end
2388
+ end
2389
+
2390
+ def list_var
2391
+ return @list_var if @list_var
2392
+ if (list || "") =~ /^list(\d+)$/
2393
+ @list_var = "list#{$1.to_i + 1}"
2394
+ else
2395
+ @list_var = "list1"
2396
+ end
2397
+ end
2398
+
2399
+ # Class of the current 'node' object (can be Version, Comment, Node, DataEntry, etc)
2400
+ def node_class
2401
+ @context[:node_class] || Node
2402
+ end
2403
+
2404
+ def base_class
2405
+ if node_kind_of?(Node)
2406
+ Node
2407
+ elsif node_kind_of?(Version)
2408
+ Version
2409
+ else
2410
+ node_class
2411
+ end
2412
+ end
2413
+
2414
+ def node_kind_of?(ancestor)
2415
+ node_class.ancestors.include?(ancestor)
2416
+ end
2417
+
2418
+ def list
2419
+ @context[:list]
2420
+ end
2421
+
2422
+ def helper
2423
+ @options[:helper]
2424
+ end
2425
+
2426
+ def params_to_erb(params, initial_comma = true)
2427
+ res = initial_comma ? [""] : []
2428
+ params.each do |k,v|
2429
+ if v =~ /<%=/ && !(v =~ /"/)
2430
+ # replace by #{}
2431
+ val = v.gsub('#{', '# {').gsub(/<%=(.*?)%>/,'#{\1}')
2432
+ res << "#{k.inspect}=>\"#{val}\""
2433
+ else
2434
+ res << "#{k.inspect}=>#{v.inspect}"
2435
+ end
2436
+ end
2437
+ res.join(', ')
2438
+ end
2439
+
2440
+ def do_var(var_finder=nil, opts={})
2441
+ clear_dom_scope
2442
+ if var_finder == 'nil'
2443
+ out "<% if nil -%>"
2444
+ elsif var_finder
2445
+ out "<% if #{var} = #{var_finder} -%>"
2446
+ end
2447
+
2448
+ if descendant('unlink')
2449
+ @html_tag ||= 'div'
2450
+ new_dom_scope
2451
+ @html_tag_params[:id] = erb_dom_id
2452
+ end
2453
+
2454
+ res = expand_with(opts.merge(:node=>var, :in_if => false))
2455
+
2456
+ if var_finder
2457
+ res += expand_with(opts.merge(:in_if => true, :only => ['else', 'elsif'], :html_tag_params => @html_tag_params, :html_tag => @html_tag))
2458
+ end
2459
+ out render_html_tag(res)
2460
+ out "<% end -%>" if var_finder
2461
+ end
2462
+
2463
+ def do_list(list_finder, query = nil, opts={})
2464
+ clear_dom_scope
2465
+
2466
+ @context.merge!(opts) # pass options from 'zafu_known_contexts' to @context
2467
+
2468
+ if (each_block = descendant('each')) && (each_block.descendant('edit') || descendant('add') || descendant('add_document') || (descendant('swap') && descendant('swap').parent.method != 'block') || ['block', 'drop'].include?(each_block.single_child_method))
2469
+ new_dom_scope
2470
+ # ajax, build template. We could merge the following code with 'r_block'.
2471
+ add_block = descendant('add')
2472
+ form_block = descendant('form') || each_block
2473
+
2474
+ @context[:need_link_id] = form_block.need_link_id
2475
+
2476
+ out "<% if (#{list_var} = #{list_finder}) || (#{node}.#{node_kind_of?(Comment) ? "can_comment?" : "can_write?"} && #{list_var}=[]) -%>"
2477
+ if query && (pagination_key = query.pagination_key)
2478
+ out "<% set_#{pagination_key}_nodes = #{query.finder(:count)}; set_#{pagination_key}_count = (set_#{pagination_key}_nodes / #{query.page_size.to_f}).ceil; set_#{pagination_key} = [1,params[:#{pagination_key}].to_i].max -%>"
2479
+ @context[:paginate] = pagination_key
2480
+ @context[:vars] ||= []
2481
+ @context[:vars] << "#{pagination_key}_nodes"
2482
+ @context[:vars] << "#{pagination_key}_count"
2483
+ @context[:vars] << "#{pagination_key}"
2484
+ end
2485
+
2486
+ # should we publish ?
2487
+ publish_after_save ||= form_block ? form_block.params[:publish] : nil
2488
+ publish_after_save ||= descendant('edit') ? descendant('edit').params[:publish] : nil
2489
+
2490
+ # class name for create form
2491
+ klass = add_block ? add_block.params[:klass] : nil
2492
+ klass ||= form_block ? form_block.params[:klass] : nil
2493
+
2494
+ # INLINE ==========
2495
+ # 'r_add' needs the form when rendering. Send with :form.
2496
+ out render_html_tag(expand_with(:list=>list_var, :in_if => false, :form=>form_block, :publish_after_save => publish_after_save, :ignore => ['form'], :klass => klass))
2497
+ out expand_with(:in_if=>true, :only=>['elsif', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
2498
+ out "<% end -%>"
2499
+
2500
+ # SAVED TEMPLATE ========
2501
+ template = expand_block(each_block, :list=>false, :klass => klass, :saved_template => true)
2502
+ out helper.save_erb_to_url(template, template_url)
2503
+
2504
+ # FORM ============
2505
+ if each_block != form_block
2506
+ form = expand_block(form_block, :klass => klass, :add=>add_block, :publish_after_save => publish_after_save, :saved_template => true)
2507
+ else
2508
+ form = expand_block(form_block, :klass => klass, :add=>add_block, :make_form=>true, :publish_after_save => publish_after_save, :saved_template => true)
2509
+ end
2510
+ out helper.save_erb_to_url(form, form_url)
2511
+ else
2512
+ # no form, render, edit and add are not ajax
2513
+ if descendant('add') || descendant('add_document')
2514
+ out "<% if (#{list_var} = #{list_finder}) || (#{node}.#{node_kind_of?(Comment) ? "can_comment?" : "can_write?"} && #{list_var}=[]) -%>"
2515
+ elsif list_finder != 'nil'
2516
+ out "<% if #{list_var} = #{list_finder} -%>"
2517
+ else
2518
+ out "<% if nil -%>"
2519
+ end
2520
+
2521
+ if query && (pagination_key = query.pagination_key)
2522
+ out "<% set_#{pagination_key}_nodes = #{query.finder(:count)}; set_#{pagination_key}_count = (set_#{pagination_key}_nodes / #{query.page_size.to_f}).ceil; set_#{pagination_key} = [1,params[:#{pagination_key}].to_i].max -%>"
2523
+ @context[:paginate] = pagination_key
2524
+ @context[:vars] ||= []
2525
+ @context[:vars] << "#{pagination_key}_nodes"
2526
+ @context[:vars] << "#{pagination_key}_count"
2527
+ @context[:vars] << "#{pagination_key}"
2528
+ end
2529
+
2530
+ out render_html_tag(expand_with(:list=>list_var, :in_if => false))
2531
+ out expand_with(:in_if=>true, :only=>['elsif', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
2532
+ out "<% end -%>"
2533
+ end
2534
+ end
2535
+
2536
+ def _(text)
2537
+ if @context[:dict]
2538
+ @context[:dict][text] || helper.send(:_,text)
2539
+ else
2540
+ helper.send(:_,text)
2541
+ end
2542
+ end
2543
+
2544
+ # Find a block to update on the page
2545
+ def find_target(name)
2546
+ # find dom_id / template_url
2547
+ target = nil
2548
+ root.descendants('block').each do |b|
2549
+ if b.name == name
2550
+ target = b
2551
+ break
2552
+ end
2553
+ end
2554
+ out parser_error("could not find a block named '#{name}'") if target.nil?
2555
+ target
2556
+ end
2557
+
2558
+ # DOM id for the current context
2559
+ def dom_id(suffix='')
2560
+ return "\#{dom_id(#{node})}" if @context && (@context[:saved_template] && @context[:main_node])
2561
+ if @context && scope_node = @context[:scope_node]
2562
+ res = "#{dom_prefix}_\#{#{scope_node}.zip}"
2563
+ else
2564
+ res = dom_prefix
2565
+ end
2566
+ if (method == 'each' || method == 'each_group') && !@context[:make_form]
2567
+ "#{res}_\#{#{var}.zip}"
2568
+ elsif @context && @context[:in_calendar]
2569
+ "#{res}_\#{#{current_date}.to_i}"
2570
+ elsif method == 'unlink' || method == 'edit'
2571
+ target = nil
2572
+ parent = self.parent
2573
+ while parent
2574
+ if ['block', 'each', 'context', 'icon'].include?(parent.method)
2575
+ target = parent
2576
+ break
2577
+ end
2578
+ parent = parent.parent
2579
+ end
2580
+ target ? target.dom_id(suffix) : (res + suffix)
2581
+ else
2582
+ res + suffix
2583
+ end
2584
+ end
2585
+
2586
+ def erb_dom_id(suffix='')
2587
+ return "<%= dom_id(#{node}) %>" if @context && (@context[:saved_template] && @context[:main_node])
2588
+ if @context && scope_node = @context[:scope_node]
2589
+ res = "#{dom_prefix}_<%= #{scope_node}.zip %>"
2590
+ else
2591
+ res = dom_prefix
2592
+ end
2593
+ if (method == 'each' || method == 'each_group') && !@context[:make_form]
2594
+ "#{res}_<%= #{var}.zip %>"
2595
+ elsif method == 'draggable'
2596
+ "#{res}_<%= #{node}.zip %>"
2597
+ elsif @context && @context[:in_calendar]
2598
+ "#{res}_<%= #{current_date}.to_i %>"
2599
+ elsif method == 'unlink'
2600
+ target = nil
2601
+ parent = self.parent
2602
+ while parent
2603
+ if ['block', 'each', 'context', 'icon'].include?(parent.method)
2604
+ target = parent
2605
+ break
2606
+ end
2607
+ parent = parent.parent
2608
+ end
2609
+ target ? target.erb_dom_id(suffix) : (res + suffix)
2610
+ else
2611
+ res + suffix
2612
+ end
2613
+ end
2614
+
2615
+ # Unique template_url, ending with dom_id
2616
+ def template_url
2617
+ "#{@options[:root]}/#{dom_prefix}"
2618
+ end
2619
+
2620
+ def form_url
2621
+ template_url + '_form'
2622
+ end
2623
+
2624
+ # Return parameter value accessor
2625
+ def get_param(key)
2626
+ "params[:#{key}]"
2627
+ end
2628
+
2629
+ def context
2630
+ return @context if @context
2631
+ # not rendered yet, find first parent with context
2632
+ @context = parent ? parent.context : {}
2633
+ end
2634
+
2635
+ # prefix for DOM id
2636
+ def dom_prefix
2637
+ (@context ? @context[:dom_prefix] : nil) || (@dom_prefix ||= unique_name)
2638
+ end
2639
+
2640
+ # use our own scope
2641
+ def clear_dom_scope
2642
+ @context.delete(:make_form) # should not propagate
2643
+ @context.delete(:main_node) # should not propagate
2644
+ end
2645
+
2646
+ # create our own ajax DOM scope
2647
+ def new_dom_scope
2648
+ clear_dom_scope
2649
+ @context.delete(:saved_template) # should not propagate on fresh template
2650
+ @context.delete(:dom_prefix) # should not propagate on fresh template
2651
+ @context[:main_node] = true # the current context will be rendered with a fresh '@node'
2652
+ @context[:dom_prefix] = self.dom_prefix
2653
+ end
2654
+
2655
+ # Return a different name on each call
2656
+ def unique_name(base = context_name)
2657
+ root.next_name_index(base, base == @name).gsub(/[^\d\w\/]/,'_')
2658
+ end
2659
+
2660
+ def context_name
2661
+ @name || if @context
2662
+ @context[:name] || 'list'
2663
+ elsif parent
2664
+ parent.context_name
2665
+ else
2666
+ 'root'
2667
+ end
2668
+ end
2669
+
2670
+ def next_name_index(key, own_id = false)
2671
+ @next_name_index ||= {}
2672
+ if @next_name_index[key]
2673
+ @next_name_index[key] += 1
2674
+ key + @next_name_index[key].to_s
2675
+ elsif own_id
2676
+ @next_name_index[key] = 0
2677
+ key
2678
+ else
2679
+ @next_name_index[key] = 1
2680
+ key + '1'
2681
+ end
2682
+ end
2683
+
2684
+ def add_params(text, opts={}, inner = '')
2685
+ text.sub(/\A([^<]*)<(\w+)(( .*?)[^%]|)>/) do
2686
+ # we must set the first tag id
2687
+ before = $1
2688
+ tag = $2
2689
+ params = parse_params($3)
2690
+ opts.each do |k,v|
2691
+ next unless v
2692
+ params[k] = v
2693
+ end
2694
+ "#{before}<#{tag}#{params_to_html(params)}>#{inner}"
2695
+ end
2696
+ end
2697
+
2698
+ # TODO: RUBYLESS
2699
+ def get_test_condition(node = self.node, params = @params)
2700
+ tests = []
2701
+ params.each do |k,v|
2702
+ if k.to_s =~ /^(or_|)([a-zA-Z_]+)(\d*)$/
2703
+ k = $2.to_sym
2704
+ end #tagged undocumented
2705
+ if [:kind_of, :klass, :status, :lang, :can, :tagged, :node, :in, :visitor, :has].include?(k)
2706
+ tests << [k, v]
2707
+ elsif k == :test
2708
+ if v =~ /\s/
2709
+ tests << [:test, v]
2710
+ else
2711
+ tests << [:attribute, v]
2712
+ end
2713
+ end
2714
+ end
2715
+
2716
+
2717
+ tests.map! do |type,value|
2718
+ case type
2719
+ when :kind_of
2720
+ "#{node}.vkind_of?(#{value.inspect})"
2721
+ when :klass
2722
+ klass = begin Module::const_get(value) rescue "NilClass" end
2723
+ "#{node}.klass == #{value.inspect}"
2724
+ when :status
2725
+ "#{node}.version.status == #{Zena::Status[value.to_sym]}"
2726
+ when :tagged
2727
+ # TODO: undocumented: remove and use rubyless !
2728
+ "#{node}.tagged[#{value.inspect}]"
2729
+ when :lang
2730
+ "#{node}.version.lang == #{value.inspect}"
2731
+ when :can
2732
+ # TODO: test
2733
+ case value
2734
+ when 'write', 'edit'
2735
+ "#{node}.can_write?"
2736
+ when 'drive', 'publish'
2737
+ "#{node}.can_drive?"
2738
+ else
2739
+ nil
2740
+ end
2741
+ when :has
2742
+ case value
2743
+ when 'discussion'
2744
+ "#{node}.discussion"
2745
+ else
2746
+ nil
2747
+ end
2748
+ when :test
2749
+ parse_condition(value, node)
2750
+ when :attribute
2751
+ '!' + node_attribute(value, :node => node) + '.blank?'
2752
+ when :node
2753
+ if node_kind_of?(Node)
2754
+ value, node_name = get_attribute_and_node(value)
2755
+ node_name ||= '@node'
2756
+ if value
2757
+ case value
2758
+ when 'main'
2759
+ "#{node}[:id] == #{node_name}[:id]"
2760
+ when 'start'
2761
+ "#{node}[:zip] == (params[:s] || @node[:zip]).to_i"
2762
+ when 'parent'
2763
+ "#{node}[:id] == #{node_name}[:parent_id]"
2764
+ when 'project'
2765
+ "#{node}[:id] == #{node_name}[:project_id]"
2766
+ when 'section'
2767
+ "#{node}[:id] == #{node_name}[:section_id]"
2768
+ when 'ancestor'
2769
+ "#{node_name}.fullpath =~ /\\A\#{#{node}.fullpath}/"
2770
+ else
2771
+ if stored = find_stored(Node, value)
2772
+ "#{node}[:id] == #{stored}[:id]"
2773
+ else
2774
+ nil
2775
+ end
2776
+ end
2777
+ else
2778
+ # bad node_name
2779
+ nil
2780
+ end
2781
+ else
2782
+ nil
2783
+ end
2784
+ when :in
2785
+ if @context["in_#{value}".to_sym] # FIXME: || ancestors.include?(value) ==> ancestors is a list of zafu tags, not a list of names !
2786
+ 'true'
2787
+ else
2788
+ 'false'
2789
+ end
2790
+ when :visitor
2791
+ if value == 'anon'
2792
+ "visitor.is_anon?"
2793
+ else
2794
+ nil
2795
+ end
2796
+ else
2797
+ nil
2798
+ end
2799
+ end.compact!
2800
+ tests == [] ? nil : tests.join(' || ')
2801
+ end
2802
+
2803
+ def parse_condition_error(clause, rest, res)
2804
+ out parser_error("invalid clause #{clause.inspect} near \"#{res[-2..-1]}#{rest[0..1]}\"")
2805
+ end
2806
+
2807
+ def parse_condition(clause, node_name)
2808
+ rest = clause.strip
2809
+ types = [:par_open, :value, :bool_op, :op, :par_close]
2810
+ allowed = [:par_open, :value]
2811
+ par_count = 0
2812
+ uses_bool_op = false
2813
+ segment = [] # value op value
2814
+ after_value = lambda { segment.size == 3 ? [:bool_op, :par_close] : [:op, :bool_op, :par_close]}
2815
+ res = ""
2816
+ while rest != ''
2817
+ # puts rest.inspect
2818
+ if rest =~ /\A\s+/
2819
+ rest = rest[$&.size..-1]
2820
+ elsif rest[0..0] == '('
2821
+ unless allowed.include?(:par_open)
2822
+ parse_condition_error(clause, rest, res)
2823
+ return nil
2824
+ end
2825
+ res << '('
2826
+ rest = rest[1..-1]
2827
+ par_count += 1
2828
+ elsif rest[0..0] == ')'
2829
+ unless allowed.include?(:par_close)
2830
+ parse_condition_error(clause, rest, res)
2831
+ return nil
2832
+ end
2833
+ res << ')'
2834
+ rest = rest[1..-1]
2835
+ par_count -= 1
2836
+ if par_count < 0
2837
+ parse_condition_error(clause, rest, res)
2838
+ return nil
2839
+ end
2840
+ allowed = [:bool_op]
2841
+ elsif rest =~ /\A(lt|le|eq|ne|ge|gt)\s+/
2842
+ unless allowed.include?(:op)
2843
+ parse_condition_error(clause, rest, res)
2844
+ return nil
2845
+ end
2846
+ op = $1.strip
2847
+ rest = rest[op.size..-1]
2848
+ op = {'lt' => '<', 'le' => '<=', 'eq' => '==', 'ne' => '!=', 'ge' => '>=', 'gt' => '>'}[op]
2849
+ segment << [op, :op]
2850
+ allowed = [:value]
2851
+ elsif rest =~ /\A("|')([^\1]*?)\1/
2852
+ # string
2853
+ unless allowed.include?(:value)
2854
+ parse_condition_error(clause, rest, res)
2855
+ return nil
2856
+ end
2857
+ rest = rest[$&.size..-1]
2858
+ segment << [$2.inspect, :string]
2859
+ allowed = after_value.call
2860
+ elsif rest =~ /\A(-?\d+)/
2861
+ # number
2862
+ unless allowed.include?(:value)
2863
+ parse_condition_error(clause, rest, res)
2864
+ return nil
2865
+ end
2866
+ rest = rest[$&.size..-1]
2867
+ segment << [$1, :number]
2868
+ allowed = after_value.call
2869
+ elsif rest =~ /\A(and|or)/
2870
+ unless allowed.include?(:bool_op)
2871
+ parse_condition_error(clause, rest, res)
2872
+ return nil
2873
+ end
2874
+ uses_bool_op = true
2875
+ rest = rest[$&.size..-1]
2876
+ res << " #{$1} "
2877
+ allowed = [:par_open, :value]
2878
+ elsif rest =~ /\A([\w:\.\-]+)/
2879
+ # variable
2880
+ unless allowed.include?(:value)
2881
+ parse_condition_error(clause, rest, res)
2882
+ return nil
2883
+ end
2884
+ rest = rest[$&.size..-1]
2885
+ fld = $1
2886
+ unless node_attr = node_attribute(fld, :node => node_name)
2887
+ parser_error("invalid field #{fld.inspect}")
2888
+ return nil
2889
+ end
2890
+ segment << [node_attr, :var]
2891
+ allowed = after_value.call
2892
+ else
2893
+ parse_condition_error(clause, rest, res)
2894
+ return nil
2895
+ end
2896
+ if segment.size == 3
2897
+ toi = (segment[1][0] =~ /(>|<)/ || (segment[0][1] == :number || segment[2][1] == :number))
2898
+ segment.map! do |part, type|
2899
+ if type == :var
2900
+ toi ? "#{part}.to_i" : part
2901
+ elsif type == :string
2902
+ toi ? part[1..-2].to_i : part
2903
+ else
2904
+ part
2905
+ end
2906
+ end
2907
+ res << segment.join(" ")
2908
+ segment = []
2909
+ end
2910
+ end
2911
+
2912
+ if par_count > 0
2913
+ parser_error("invalid clause #{clause.inspect}: missing closing ')'")
2914
+ return nil
2915
+ elsif allowed.include?(:value)
2916
+ parser_error("invalid clause #{clause.inspect}")
2917
+ return nil
2918
+ else
2919
+ return uses_bool_op ? "(#{res})" : res
2920
+ end
2921
+ end
2922
+
2923
+ # Block visibility of descendance with 'do_list'.
2924
+ def public_descendants
2925
+ all = super
2926
+ if ['context', 'each', 'block'].include?(self.method)
2927
+ # do not propagate 'form',etc up
2928
+ all.reject do |k,v|
2929
+ ['form','unlink'].include?(k)
2930
+ end
2931
+ elsif ['if', 'case'].include?(self.method)
2932
+ all.reject do |k,v|
2933
+ ['else', 'elsif', 'when'].include?(k)
2934
+ end
2935
+ else
2936
+ all
2937
+ end
2938
+ end
2939
+
2940
+ def single_child_method
2941
+ return @single_child_method if defined?(@single_child_method)
2942
+ @single_child_method = if @blocks.size == 1
2943
+ single_child = @blocks[0]
2944
+ return nil if single_child.kind_of?(String)
2945
+ single_child.html_tag ? nil : single_child.method
2946
+ else
2947
+ nil
2948
+ end
2949
+ end
2950
+
2951
+ def get_attribute_and_node(str)
2952
+ if str =~ /([^\.]+)\.(.+)/
2953
+ node_name = $1
2954
+ node_attr = $2
2955
+ if att_node = find_stored(Node, node_name)
2956
+ return [node_attr, att_node, Node]
2957
+ elsif node_name == 'main'
2958
+ return [node_attr, '@node', Node]
2959
+ elsif node_name == 'visitor'
2960
+ return [node_attr, 'visitor.contact', Contact]
2961
+ elsif node_name == 'site'
2962
+ return [node_attr, 'current_site', Site]
2963
+ else
2964
+ out parser_error("invalid node name #{node_name.inspect} in attribute #{str.inspect}")
2965
+ return [nil]
2966
+ end
2967
+ else
2968
+ return [str]
2969
+ end
2970
+ end
2971
+
2972
+ def parse_attributes_in_value(v, opts = {})
2973
+ opts = {:erb => true}.merge(opts)
2974
+ static = true
2975
+
2976
+ use_node = @var || node
2977
+ res = v.gsub(/\[([^\]]+)\]/) do
2978
+ static = false
2979
+ res = nil
2980
+ attribute = $1
2981
+
2982
+ if opts[:skip_node_attributes]
2983
+ if attribute =~ /^param:(\w+)$/
2984
+ attribute = get_param($1)
2985
+ elsif attribute == 'current_date'
2986
+ attribute = current_date
2987
+ else
2988
+ res = "[#{attribute}]"
2989
+ end
2990
+ else
2991
+ attribute = node_attribute(attribute, :node => use_node )
2992
+ end
2993
+
2994
+ res ||= if opts[:erb]
2995
+ "<%= #{attribute} %>"
2996
+ else
2997
+ "\#{#{attribute}}"
2998
+ end
2999
+ res
3000
+ end
3001
+ [res, static]
3002
+ end
3003
+
3004
+ def node_attribute(str, opts={})
3005
+
3006
+ if @context[:vars] && @context[:vars].include?(str)
3007
+ return "set_#{str}"
3008
+ end
3009
+
3010
+ res = PSEUDO_ATTRIBUTES[str]
3011
+ return res if res
3012
+ return current_date if str == 'current_date'
3013
+ return get_param($1) if str =~ /^param:(\w+)$/
3014
+
3015
+ attribute, att_node, klass = get_attribute_and_node(str)
3016
+
3017
+ return 'nil' unless attribute
3018
+
3019
+
3020
+ att_node ||= opts[:node] || node
3021
+ klass ||= opts[:node_class] || node_class
3022
+
3023
+ real_attribute = attribute =~ /\Ad_/ ? attribute : attribute.gsub(/\A(|[\w_]+)id(s?)\Z/, '\1zip\2')
3024
+
3025
+ res = if klass.ancestors.include?(Node)
3026
+ if ['url','path'].include?(real_attribute)
3027
+ # pseudo attribute 'url'
3028
+ params = {}
3029
+ params[:mode] = @params[:mode] if @params[:mode]
3030
+ params[:format] = @params[:format] if @params[:format]
3031
+ "zen_#{real_attribute}(#{node}#{params_to_erb(params)})"
3032
+ elsif type = klass.safe_method_type([real_attribute])
3033
+ "#{att_node}.#{type[:method]}"
3034
+ else
3035
+ "#{att_node}.safe_read(#{real_attribute.inspect})"
3036
+ end
3037
+ elsif type = klass.safe_method_type([real_attribute])
3038
+ "#{att_node}.#{type[:method]}"
3039
+ else
3040
+ # unknown class, resolve at runtime
3041
+ "#{att_node}.safe_read(#{real_attribute.inspect})"
3042
+ end
3043
+
3044
+ res = "(#{res} || #{node_attribute(opts[:else])})" if opts[:else]
3045
+ res = "(#{res} || #{opts[:default].inspect})" if opts[:default]
3046
+ res
3047
+ end
3048
+
3049
+ # Add a class name to the html_tag
3050
+ def add_html_class(class_name)
3051
+ if klass = @html_tag_params[:class]
3052
+ @html_tag_params[:class] = "#{class_name} #{klass}"
3053
+ else
3054
+ @html_tag_params[:class] = class_name
3055
+ end
3056
+ end
3057
+
3058
+ def render_html_tag(text,*append)
3059
+ append ||= []
3060
+ return text if @html_tag_done
3061
+ set_params = {}
3062
+ if_params = {}
3063
+ @params.each do |k,v|
3064
+ if k.to_s =~ /^t?set_/
3065
+ set_params[k] = v
3066
+ end
3067
+ end
3068
+ tag_class = @html_tag_params[:class] || @params[:class]
3069
+ if node_kind_of?(Node)
3070
+
3071
+ if @context[:make_form]
3072
+ node_name = node
3073
+ elsif (@method == 'each' || @method == 'each_group') && @context[:list]
3074
+ node_name = var
3075
+ elsif @method == 'context'
3076
+ node_name = @var || node
3077
+ else
3078
+ node_name = node
3079
+ end
3080
+
3081
+ class_cond = nil
3082
+ @params.each do |k,v|
3083
+ if k.to_s =~ /^(.+)_if$/
3084
+ klass = $1
3085
+ cond = get_test_condition(node_name, :test => v)
3086
+ elsif k.to_s =~ /^(.+)_if_(test|node|kind_of|klass|status|lang|can|in)$/
3087
+ klass = $1
3088
+ cond = get_test_condition(node_name, $2.to_sym => v)
3089
+ end
3090
+ if cond
3091
+ class_cond = "#{cond} ? \" class='#{klass}'\" : #{class_cond}" # (x = 3) ? "class='foo'" :
3092
+ end
3093
+ end
3094
+
3095
+ if class_cond
3096
+ append << "<%= #{class_cond}\"#{tag_class ? " class='#{tag_class}'" : ""}\" %>"
3097
+ @html_tag_params.delete(:class)
3098
+ end
3099
+ end
3100
+
3101
+ @html_tag = 'div' if !@html_tag && (set_params != {} || @html_tag_params != {})
3102
+
3103
+ bak = @html_tag_params.dup
3104
+ @html_tag_params = get_html_params(set_params.merge(@html_tag_params), @html_tag)
3105
+ res = super(text,*append)
3106
+ @html_tag_params = bak
3107
+ res
3108
+ end
3109
+
3110
+ def link_to_update(target, opts = {})
3111
+ method = opts[:method] || :get
3112
+
3113
+ html_params = opts[:html_params] || {}
3114
+ node_id = opts[:node_id] || self.node_id
3115
+
3116
+ url = opts[:url] || "/#{base_class.to_s.pluralize.underscore}/\#{#{node_id}}#{method == :get ? '/zafu' : ''}"
3117
+ opts[:cond] ||= "#{node}.can_write?" if method != :get
3118
+
3119
+ query_params = [opts[:query_params]].flatten.compact
3120
+
3121
+ if method == :get
3122
+ if target
3123
+ query_params << "t_url=#{CGI.escape(target.template_url)}"
3124
+ query_params << "dom_id=#{target.dom_id}"
3125
+ else
3126
+ query_params << "dom_id=_page"
3127
+ end
3128
+ else
3129
+ query_params << "t_url=#{CGI.escape(template_url)}" if method != :delete
3130
+
3131
+ query_params << "dom_id=#{dom_id}"
3132
+ if target != self
3133
+ if target
3134
+ query_params << "u_url=#{CGI.escape(target.template_url)}"
3135
+ query_params << "udom_id=#{target.dom_id}"
3136
+ else
3137
+ query_params << "udom_id=_page"
3138
+ end
3139
+ end
3140
+ end
3141
+
3142
+ query_params << "link_id=\#{#{node}.link_id}" if @context[:need_link_id] && node_kind_of?(Node)
3143
+ query_params << "node[v_status]=#{Zena::Status[:pub]}" if @params[:publish] # FIXME: this acts like publish = 'force'
3144
+ query_params << start_node_s_param(:string)
3145
+
3146
+ res = ''
3147
+ res += "<% if #{opts[:cond]} -%>" if opts[:cond]
3148
+ res += "<%= tag_to_remote({:url => \"#{url}?#{query_params.join('&')}\", :method => #{method.inspect}}#{params_to_erb(html_params)}) %>"
3149
+ res += text_for_link(opts[:default_text])
3150
+ res += "</a>"
3151
+ if opts[:cond]
3152
+ if opts[:else] != :void
3153
+ res += "<% else -%>"
3154
+ res += text_for_link(opts[:default_text])
3155
+ end
3156
+ res += "<% end -%>"
3157
+ end
3158
+ res
3159
+ end
3160
+
3161
+ def text_for_link(default = nil)
3162
+ if @blocks.size > 1 || (@blocks.size == 1 && !(@blocks.first.kind_of?(String) || ['else','elsif'].include?(@blocks.first.method)))
3163
+ expand_with
3164
+ elsif default
3165
+ default
3166
+ elsif erb_text = get_text_for_erb(@params, false, :string)
3167
+ erb_text
3168
+ elsif node_kind_of?(Node)
3169
+ "<%= #{node}.version.title %>"
3170
+ elsif node_kind_of?(Version)
3171
+ "<%= #{node}.title %>"
3172
+ elsif node_kind_of?(Link)
3173
+ "<%= #{node}.name %>"
3174
+ else
3175
+ _('edit')
3176
+ end
3177
+ end
3178
+
3179
+ def get_text_for_erb(params = @params, use_blocks = true, context = :erb)
3180
+ string_context = context == :string
3181
+ if params[:attr]
3182
+ string_context ? "<%= #{node_attribute(params[:attr])} %>" : node_attribute(params[:attr])
3183
+ elsif params[:tattr]
3184
+ string_context ? "<%= _(#{node_attribute(params[:tattr])}) %>" : "_(#{node_attribute(params[:tattr])})"
3185
+ elsif params[:trans]
3186
+ string_context ? _(params[:trans]) : _(params[:trans]).inspect
3187
+ elsif params[:text]
3188
+ string_context ? params[:text] : params[:text].inspect
3189
+ elsif use_blocks && @blocks != []
3190
+ res = []
3191
+ text = ""
3192
+ static = true
3193
+ @blocks.each do |b|
3194
+ # FIXME: this is a little too hacky
3195
+ if b.kind_of?(String)
3196
+ res << b.inspect
3197
+ text << b
3198
+ elsif ['show', 'img'].include?(b.method)
3199
+ res << expand_block(b, :trans=>true)
3200
+ static = false
3201
+ elsif ['rename_asset', 'trans'].include?(b.method)
3202
+ # FIXME: if a trans contains non-static: static should become false
3203
+ res << expand_block(b).inspect
3204
+ text << expand_block(b)
3205
+ else
3206
+ # ignore
3207
+ end
3208
+ end
3209
+ if static
3210
+ # "just plain text"
3211
+ string_context ? text : text.inspect
3212
+ else
3213
+ # function(...) + "blah" + function()
3214
+ string_context ? "<%= #{res.join(' + ')} %>" : res.join(' + ')
3215
+ end
3216
+ else
3217
+ nil
3218
+ end
3219
+ end
3220
+
3221
+ def get_input_params(params = @params)
3222
+ res = {}
3223
+ if res[:name] = (params[:name] || params[:date])
3224
+ if res[:name] =~ /\A([\w_]+)\[(.*?)\]/
3225
+ attribute, sub_attr = $1, $2
3226
+ else
3227
+ attribute = res[:name]
3228
+ end
3229
+
3230
+ unless @context[:in_filter] || attribute == 's'
3231
+ if sub_attr
3232
+ res[:name] = "#{base_class.to_s.underscore}[#{attribute}][#{sub_attr}]"
3233
+ else
3234
+ res[:name] = "#{base_class.to_s.underscore}[#{attribute}]"
3235
+ end
3236
+ end
3237
+
3238
+ if sub_attr
3239
+ if (nattr = node_attribute(attribute)) != 'nil'
3240
+ nattr = "#{nattr}[#{sub_attr.inspect}]"
3241
+ end
3242
+ else
3243
+ nattr = node_attribute(attribute)
3244
+ end
3245
+
3246
+ if sub_attr && params[:type] == 'checkbox' && !params[:value]
3247
+ # Special case when we have a sub_attribute: default value for "tagged[foobar]" is "foobar"
3248
+ params[:value] = sub_attr
3249
+ end
3250
+
3251
+ if @context[:in_add]
3252
+ res[:value] = (params[:value] || params[:set_value]) ? ["'#{ helper.fquote(params[:value])}'"] : ["''"]
3253
+ elsif @context[:in_filter]
3254
+ res[:value] = attribute ? ["'<%= fquote params[#{attribute.to_sym.inspect}] %>'"] : ["''"]
3255
+ elsif params[:value]
3256
+ res[:value] = ["'#{ helper.fquote(params[:value])}'"]
3257
+ else
3258
+ if nattr != 'nil'
3259
+ res[:value] = ["'<%= fquote #{nattr} %>'"]
3260
+ else
3261
+ res[:value] = ["''"]
3262
+ end
3263
+ end
3264
+ end
3265
+
3266
+ if @context[:dom_prefix]
3267
+ res[:id] = "#{erb_dom_id}_#{attribute}"
3268
+ else
3269
+ res[:id] = params[:id] if params[:id]
3270
+ end
3271
+
3272
+ if params[:type] == 'checkbox' && nattr
3273
+ if value = params[:value]
3274
+ res[:checked] = "<%= #{nattr} == #{value.inspect} ? \" checked='checked'\" : '' %>"
3275
+ else
3276
+ res[:checked] = "<%= #{nattr}.blank? ? '' : \" checked='checked'\" %>"
3277
+ end
3278
+ end
3279
+
3280
+ [:size, :style, :class].each do |k|
3281
+ res[k] = params[k] if params[k]
3282
+ end
3283
+
3284
+ return [res, attribute]
3285
+ end
3286
+
3287
+ def get_html_params(params, tag_type)
3288
+ res = {}
3289
+ params.each do |k,v|
3290
+ next unless v
3291
+ if k.to_s =~ /\A(t?)set_(.+)$/
3292
+ key = $2
3293
+ trans = $1 == 't'
3294
+ value, static = parse_attributes_in_value(v, :erb => !trans)
3295
+
3296
+ if trans
3297
+ if static
3298
+ value = ["'#{_(value)}'"] # array so it is not escaped on render
3299
+ else
3300
+ value = ["'<%= _(\"#{value}\") %>'"] # FIXME: use dict ! array so it is not escaped on render
3301
+ end
3302
+ end
3303
+ res[key.to_sym] = value
3304
+ elsif tag_type == :link && ![:style, :class, :id, :title].include?(k)
3305
+ # bad html parameter for links (some keys for link tags are used as query parameters)
3306
+ # filter out
3307
+ else
3308
+ res[k] ||= v
3309
+ end
3310
+ end
3311
+
3312
+ if params[:anchor]
3313
+ @anchor_param = nil
3314
+ res[:name] = anchor_name(params[:anchor], node)
3315
+ end
3316
+
3317
+ res
3318
+ end
3319
+
3320
+ def get_options_for_select
3321
+ if nodes = @params[:nodes]
3322
+ # TODO: dry with r_checkbox
3323
+ if nodes =~ /^\d+\s*($|,)/
3324
+ # ids
3325
+ # TODO: optimization generate the full query instead of using secure.
3326
+ nodes = nodes.split(',').map{|v| v.to_i}
3327
+ nodes = "(secure(Node) { Node.find(:all, :conditions => 'zip IN (#{nodes.join(',')})') })"
3328
+ else
3329
+ # relation
3330
+ nodes, klass = build_finder_for(:all, nodes)
3331
+ return unless nodes
3332
+ return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
3333
+ end
3334
+ set_attr = @params[:attr] || 'id'
3335
+ show_attr = @params[:show] || 'name'
3336
+ options_list = "[['','']] + (#{nodes} || []).map{|r| [#{node_attribute(show_attr, :node => 'r', :node_class => Node)}, #{node_attribute(set_attr, :node => 'r', :node_class => Node)}.to_s]}"
3337
+ elsif values = @params[:values]
3338
+ options_list = values.split(',').map(&:strip)
3339
+
3340
+ if show = @params[:show]
3341
+ show_values = show.split(',').map(&:strip)
3342
+ elsif show = @params[:tshow]
3343
+ show_values = show.split(',').map do |s|
3344
+ _(s.strip)
3345
+ end
3346
+ end
3347
+
3348
+ if show_values
3349
+ options_list.each_index do |i|
3350
+ options_list[i] = [show_values[i], options_list[i]]
3351
+ end
3352
+ end
3353
+ options_list.inspect
3354
+ end
3355
+ end
3356
+
3357
+ def parse_eval_parameter(str)
3358
+ # evaluate an expression. Can only contain vars, '(', ')', '*', '+', '/', '-', '[attr]'
3359
+ # FIXME: SECURITY (audit this)
3360
+ vars = @context[:vars] || []
3361
+ parts = str.split(/\s+/)
3362
+ res = []
3363
+ test = []
3364
+ parts.each do |p|
3365
+ if p =~ /\[([\w_]+)\]/
3366
+ test << 1
3367
+ res << (node_attribute($1) + '.to_f')
3368
+ elsif p =~ /^[a-zA-Z_]+$/
3369
+ unless vars.include?(p)
3370
+ out parser_error("var #{p.inspect} not set in eval")
3371
+ return nil
3372
+ end
3373
+ test << 1
3374
+ res << "set_#{p}.to_f"
3375
+ elsif ['(', ')', '*', '+', '/', '-'].include?(p)
3376
+ res << p
3377
+ test << p
3378
+ elsif p =~ /^[0-9\.]+$/
3379
+ res << p
3380
+ test << p
3381
+ else
3382
+ out parser_error("bad argument #{p.inspect} in eval")
3383
+ return nil
3384
+ end
3385
+ end
3386
+ begin
3387
+ begin
3388
+ eval test.join(' ')
3389
+ rescue
3390
+ # rescue evaluation error
3391
+ out parser_error("error in eval")
3392
+ return nil
3393
+ end
3394
+ "(#{res.join(' ')})"
3395
+ rescue SyntaxError => err
3396
+ # rescue compilation error
3397
+ out parser_error("compilation error in eval")
3398
+ return nil
3399
+ end
3400
+ end
3401
+
3402
+ def find_stored(klass, key)
3403
+ if "#{klass}_#{key}" == "Node_start_node"
3404
+ # main node before ajax stuff (the one in browser url)
3405
+ "start_node"
3406
+ else
3407
+ @context["#{klass}_#{key}"]
3408
+ end
3409
+ end
3410
+
3411
+ def set_stored(klass, key, obj)
3412
+ @context["#{klass}_#{key}"] = obj
3413
+ end
3414
+
3415
+ # transform a 'show' tag into an input field.
3416
+ def make_input(params = @params)
3417
+ input, attribute = get_input_params(params)
3418
+ return parser_error("missing 'name'") unless attribute
3419
+ return '' if attribute == 'parent_id' # set with 'r_form'
3420
+ return '' if ['url','path'].include?(attribute) # cannot be set with a form
3421
+ if params[:date]
3422
+ input_id = @context[:dom_prefix] ? ", :id=>\"#{dom_id}_#{attribute}\"" : ''
3423
+ return "<%= date_box('#{base_class.to_s.underscore}', #{params[:date].inspect}#{input_id}) %>"
3424
+ end
3425
+ input_id = @context[:dom_prefix] ? " id='#{erb_dom_id}_#{attribute}'" : ''
3426
+ "<input type='#{params[:type] || 'text'}'#{input_id} name='#{input[:name]}' value=#{input[:value]}/>"
3427
+ end
3428
+
3429
+ # transform a 'zazen' tag into a textarea input field.
3430
+ def make_textarea(params)
3431
+ return parser_error("missing 'name'") unless name = params[:name]
3432
+ if name =~ /\A([\w_]+)\[(.*?)\]/
3433
+ attribute = $2
3434
+ else
3435
+ attribute = name
3436
+ name = "#{base_class.to_s.underscore}[#{attribute}]"
3437
+ end
3438
+ return '' if attribute == 'parent_id' # set with 'r_form'
3439
+
3440
+ if @blocks == [] || @blocks == ['']
3441
+ if @context[:in_add]
3442
+ value = ''
3443
+ else
3444
+ value = attribute ? "<%= #{node_attribute(attribute)} %>" : ""
3445
+ end
3446
+ else
3447
+ value = expand_with
3448
+ end
3449
+ html_id = @context[:dom_prefix] ? " id='#{erb_dom_id}_#{attribute}'" : ''
3450
+ "<textarea#{html_id} name='#{name}'>#{value}</textarea>"
3451
+ end
3452
+
3453
+ def default_focus_field
3454
+ if (input_fields = descendants('input')) != []
3455
+ field = input_fields.first.params[:name]
3456
+ elsif (show_fields = descendants('show')) != []
3457
+ field = show_fields.first.params[:attr]
3458
+ elsif node_kind_of?(Node)
3459
+ field = 'v_title'
3460
+ else
3461
+ field = 'text'
3462
+ end
3463
+ end
3464
+
3465
+ # Returns true if a form/edit needs to keep track of link_id (l_status or l_comment used).
3466
+ def need_link_id
3467
+ if (input_fields = (descendants('input') + descendants('select'))) != []
3468
+ input_fields.each do |f|
3469
+ return true if f.params[:name] =~ /\Al_/
3470
+ end
3471
+ elsif (show_fields = descendants('show')) != []
3472
+ show_fields.each do |f|
3473
+ return true if f.params[:attr] =~ /\Al_/
3474
+ end
3475
+ end
3476
+ return false
3477
+ end
3478
+
3479
+ def start_node_s_param(type = :input)
3480
+ if type == :input
3481
+ "<input type='hidden' name='s' value='<%= params[:s] || @node[:zip] %>'/>"
3482
+ elsif type == :erb
3483
+ "s=<%= params[:s] || @node[:zip] %>"
3484
+ elsif type == :value
3485
+ "<%= params[:s] || @node[:zip] %>"
3486
+ else
3487
+ "s=\#{params[:s] || @node[:zip]}"
3488
+ end
3489
+ end
3490
+
3491
+ def parser_error(message, tag=@method)
3492
+ "<span class='parser_error'>[#{tag}] #{message}</span>"
3493
+ end
3494
+
3495
+ # Used by [each] and [draggable] to insert 'id' and drag handle span
3496
+ def set_drag_handle_and_id(text, params, id_hash)
3497
+ res, drag_handle = text, nil
3498
+ if params[:drag_handle]
3499
+ drag_handle = params[:drag_handle] == 'true' ? 'drag_handle' : params[:drag_handle]
3500
+ if text =~ /class\s*=\s*['"]#{drag_handle}/
3501
+ # nothing to do
3502
+ insert = ''
3503
+ else
3504
+ insert = "<span class='#{drag_handle}'>&nbsp;</span>"
3505
+ end
3506
+ else
3507
+ insert = ''
3508
+ end
3509
+
3510
+ res = insert + text
3511
+
3512
+ if id_hash
3513
+ @html_tag ||= 'div'
3514
+ @html_tag_params.merge!(id_hash)
3515
+ end
3516
+
3517
+ [res, drag_handle]
3518
+ end
3519
+
3520
+ def expand_with(acontext={})
3521
+ # set variables
3522
+ context = nil
3523
+ pre = ''
3524
+ @blocks.each do |block|
3525
+ next if block.kind_of?(String) || block.method != 'set'
3526
+ @context[:vars] ||= []
3527
+ context ||= @context.merge(acontext).merge(:set => true)
3528
+ pre << expand_block(block, context)
3529
+ @context[:vars] << block.params[:var]
3530
+ end
3531
+
3532
+ pre + super
3533
+ end
3534
+
3535
+ def auto_publish_param(in_string = false)
3536
+ if in_string
3537
+ ['true','force'].include?(@params[:publish]) ? "&publish=#{@params[:publish]}" : ''
3538
+ else
3539
+ @params[:publish]
3540
+ end
3541
+ end
3542
+
3543
+ # This is used by zafu and it's a mess.
3544
+ # ref_date can be a string ('2005-05-03') or ruby ('Time.now'). It should not come uncleaned from evil web.
3545
+ def date_condition(date_cond, field, ref_date='today')
3546
+ if date_cond == 'today' || ref_date == 'today'
3547
+ ref_date = Zena::Db::NOW
3548
+ elsif ref_date =~ /(\d{4}-\d{1,2}-\d{1,2}( \d{1,2}:\d{1,2}(:\d{1,2})?)?)/
3549
+ ref_date = "'#{$1}'"
3550
+ elsif ref_date =~ /\A"/
3551
+ ref_date = "'\#{format_date(#{ref_date})}'"
3552
+ else
3553
+ ref_date = "'\#{#{ref_date}.strftime('%Y-%m-%d %H:%M:%S')}'"
3554
+ end
3555
+ Zena::Db.date_condition(date_cond, field, ref_date)
3556
+ end
3557
+ end # ZenaTags
3558
+ end # Parser
3559
+ end # Zena