zena 0.15.2 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (284) hide show
  1. data/.gitignore +20 -0
  2. data/CREDITS +27 -0
  3. data/Capfile +3 -0
  4. data/DEVELOPERS +46 -0
  5. data/History.txt +15 -0
  6. data/MIT-LICENSE +19 -0
  7. data/Rakefile +44 -0
  8. data/TODO +24 -0
  9. data/TODO_ZENA_1_0 +23 -0
  10. data/app/controllers/application_controller.rb +3 -0
  11. data/app/controllers/documents_controller.rb +22 -56
  12. data/app/controllers/nodes_controller.rb +42 -27
  13. data/app/controllers/pings_controller.rb +19 -0
  14. data/app/controllers/relations_controller.rb +5 -1
  15. data/app/controllers/sites_controller.rb +1 -46
  16. data/app/controllers/user_sessions_controller.rb +47 -0
  17. data/app/controllers/users_controller.rb +1 -0
  18. data/app/controllers/versions_controller.rb +25 -7
  19. data/app/controllers/virtual_classes_controller.rb +1 -1
  20. data/app/helpers/application_helper.rb +1 -1
  21. data/app/models/comment.rb +2 -1
  22. data/app/models/contact_content.rb +2 -2
  23. data/app/models/data_entry.rb +5 -6
  24. data/app/models/document.rb +14 -10
  25. data/app/models/document_content.rb +4 -6
  26. data/app/models/iformat.rb +2 -2
  27. data/app/models/image_content.rb +6 -9
  28. data/app/models/node.rb +106 -164
  29. data/app/models/page.rb +0 -20
  30. data/app/models/site.rb +42 -12
  31. data/app/models/template.rb +3 -8
  32. data/app/models/template_content.rb +2 -0
  33. data/app/models/text_document.rb +13 -8
  34. data/app/models/user.rb +47 -100
  35. data/app/models/user_session.rb +4 -0
  36. data/app/models/version.rb +1 -1
  37. data/app/views/comments/create.rjs +3 -3
  38. data/app/views/comments/edit.rjs +1 -1
  39. data/app/views/comments/update.rjs +1 -1
  40. data/app/views/nodes/_import_results.rhtml +1 -1
  41. data/app/views/nodes/create.rjs +3 -3
  42. data/app/views/templates/document_create_tabs/_file.rhtml +1 -2
  43. data/app/views/templates/document_create_tabs/_import.rhtml +7 -2
  44. data/app/views/templates/edit_tabs/_document.rhtml +1 -3
  45. data/app/views/templates/edit_tabs/_image.rhtml +1 -3
  46. data/app/views/versions/_tr.rhtml +1 -1
  47. data/app/views/versions/edit.rhtml +2 -26
  48. data/bin/zena +6 -1
  49. data/bricks/delayed_job/README +18 -0
  50. data/bricks/delayed_job/migrate/20091104191643_create_delayed_jobs_table.rb +19 -0
  51. data/bricks/delayed_job/misc/init.rb +8 -0
  52. data/bricks/delayed_job/misc/tasks.rb +2 -0
  53. data/bricks/math/patch/application_helper.rb +1 -1
  54. data/bricks/sphinx/MIT-LICENSE +19 -0
  55. data/bricks/sphinx/README +19 -0
  56. data/bricks/sphinx/lib/use_sphinx.rb +78 -0
  57. data/bricks/sphinx/migrate/20091102171258_add_delta_for_sphinx.rb +9 -0
  58. data/bricks/sphinx/misc/deploy.rb +20 -0
  59. data/bricks/sphinx/misc/sphinx.yml +12 -0
  60. data/bricks/sphinx/misc/tasks.rb +21 -0
  61. data/bricks/sphinx/patch/node.rb +8 -0
  62. data/bricks/tags/lib/has_tags.rb +5 -3
  63. data/bricks/tags/test/zafu/tags.yml +13 -1
  64. data/config/bricks.yml +35 -0
  65. data/config/deploy.rb +8 -1
  66. data/config/environment.rb +1 -1
  67. data/config/environments/production.rb +1 -1
  68. data/config/gems.yml +28 -5
  69. data/config/sphinx.yml +12 -0
  70. data/db/init/base/skins/default/Node-+popupLayout.zafu +1 -16
  71. data/db/migrate/20091026161708_add_persistence_token.rb +13 -0
  72. data/db/migrate/20091101184952_add_session_table.rb +16 -0
  73. data/db/migrate/20091123175137_add_single_access_token.rb +9 -0
  74. data/db/migrate/20091124161608_rebuild_fullpath.rb +11 -0
  75. data/db/schema.rb +21 -8
  76. data/doc/README_FOR_APP +24 -0
  77. data/doc/fixtures.graffle +19568 -0
  78. data/doc/fixtures.pdf +0 -0
  79. data/doc/template/LICENSE +184 -0
  80. data/doc/template/README +37 -0
  81. data/doc/template/allison.css +283 -0
  82. data/doc/template/allison.js +307 -0
  83. data/doc/template/allison.rb +260 -0
  84. data/doc/template/cache/BODY +588 -0
  85. data/doc/template/cache/CLASS_INDEX +4 -0
  86. data/doc/template/cache/CLASS_PAGE +1 -0
  87. data/doc/template/cache/FILE_INDEX +4 -0
  88. data/doc/template/cache/FILE_PAGE +1 -0
  89. data/doc/template/cache/FONTS +1 -0
  90. data/doc/template/cache/FR_INDEX_BODY +1 -0
  91. data/doc/template/cache/IMGPATH +1 -0
  92. data/doc/template/cache/INDEX +1 -0
  93. data/doc/template/cache/JAVASCRIPT +307 -0
  94. data/doc/template/cache/METHOD_INDEX +4 -0
  95. data/doc/template/cache/METHOD_LIST +1 -0
  96. data/doc/template/cache/SRC_PAGE +1 -0
  97. data/doc/template/cache/STYLE +283 -0
  98. data/doc/template/cache/URL +1 -0
  99. data/doc/zafu_changes.yml +29 -0
  100. data/lib/base_additions.rb +1 -1
  101. data/lib/bricks.rb +9 -0
  102. data/lib/bricks/loader.rb +86 -0
  103. data/lib/bricks/requirements_validation.rb +71 -0
  104. data/lib/tasks/zena.rake +42 -4
  105. data/lib/zafu/action.rb +285 -0
  106. data/lib/zafu/ajax.rb +93 -0
  107. data/lib/zafu/attributes.rb +117 -0
  108. data/lib/zafu/calendar.rb +159 -0
  109. data/lib/zafu/context.rb +330 -0
  110. data/lib/zafu/core/html.rb +102 -0
  111. data/lib/zafu/core/move_to_parser.rb +167 -0
  112. data/lib/zafu/dates.rb +58 -0
  113. data/lib/zafu/display.rb +502 -0
  114. data/lib/zafu/eval.rb +66 -0
  115. data/lib/zafu/experimental.rb +66 -0
  116. data/lib/zafu/i18n.rb +64 -0
  117. data/lib/zafu/meta.rb +25 -0
  118. data/lib/zafu/refactor.rb +73 -0
  119. data/lib/zafu/support/context.rb +265 -0
  120. data/lib/zafu/support/dom.rb +145 -0
  121. data/lib/zafu/support/erb.rb +62 -0
  122. data/lib/zafu/support/flow.rb +401 -0
  123. data/lib/zafu/support/forms.rb +461 -0
  124. data/lib/zafu/support/links.rb +306 -0
  125. data/lib/zafu_parser.rb +26 -2
  126. data/lib/zena.rb +34 -15
  127. data/lib/zena/acts/multiversion.rb +2 -2
  128. data/lib/zena/acts/secure.rb +41 -30
  129. data/lib/zena/app.rb +7 -10
  130. data/lib/zena/controller/test_case.rb +12 -7
  131. data/lib/zena/crypto_provider/initial.rb +15 -0
  132. data/lib/zena/db.rb +6 -1
  133. data/lib/zena/deploy.rb +34 -6
  134. data/lib/zena/deploy/logrotate_app.rhtml +9 -0
  135. data/lib/zena/deploy/logrotate_host.rhtml +34 -0
  136. data/lib/zena/deploy/template.rb +1 -9
  137. data/lib/zena/foxy_parser.rb +1 -1
  138. data/lib/zena/info.rb +3 -1
  139. data/lib/zena/migrator.rb +1 -1
  140. data/lib/zena/parser.rb +12 -4
  141. data/lib/zena/parser/zazen_rules.rb +6 -6
  142. data/lib/zena/parser/zena_rules.rb +1 -7
  143. data/lib/zena/routes.rb +5 -5
  144. data/lib/zena/test_controller.rb +7 -2
  145. data/lib/zena/unit/test_case.rb +6 -8
  146. data/lib/zena/use/ajax.rb +10 -10
  147. data/lib/zena/use/authlogic.rb +93 -0
  148. data/lib/zena/use/dyn_attributes.rb +5 -0
  149. data/lib/zena/use/html_tags.rb +16 -34
  150. data/lib/zena/use/i18n.rb +4 -1
  151. data/lib/zena/use/node_query_finders.rb +8 -4
  152. data/lib/zena/use/refactor.rb +8 -20
  153. data/lib/zena/use/relations.rb +1 -0
  154. data/lib/zena/use/rendering.rb +4 -2
  155. data/lib/zena/use/search.rb +52 -0
  156. data/lib/zena/use/test_helper.rb +27 -28
  157. data/lib/zena/use/upload.rb +188 -0
  158. data/lib/zena/use/urls.rb +16 -14
  159. data/lib/zena/use/zafu.rb +16 -63
  160. data/lib/zena/use/zazen.rb +8 -8
  161. data/lib/zena/view/test_case.rb +8 -4
  162. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  163. data/locale/en/zena.po +3 -3
  164. data/public/.htaccess +40 -0
  165. data/public/javascripts/upload-progress.js +17 -8
  166. data/public/javascripts/zena.js +8 -2
  167. data/public/stylesheets/popup.css +1 -0
  168. data/script/about +3 -0
  169. data/script/apache_logging +25 -0
  170. data/script/breakpointer +3 -0
  171. data/script/console +3 -0
  172. data/script/dbconsole +3 -0
  173. data/script/destroy +3 -0
  174. data/script/generate +3 -0
  175. data/script/performance/benchmarker +3 -0
  176. data/script/performance/profiler +3 -0
  177. data/script/plugin +3 -0
  178. data/script/process/inspector +3 -0
  179. data/script/process/reaper +3 -0
  180. data/script/process/spawner +3 -0
  181. data/script/runner +3 -0
  182. data/script/server +3 -0
  183. data/script/set_revision +29 -0
  184. data/spec/controllers/versions_controller_spec.rb +11 -0
  185. data/test/fixtures/files/Node-test.zafu +1 -1
  186. data/test/functional/nodes_controller_test.rb +25 -0
  187. data/test/functional/pings_controller_test.rb +8 -0
  188. data/test/functional/user_sessions_controller_test.rb +59 -0
  189. data/test/functional/users_controller_test.rb +81 -19
  190. data/test/helpers/node_query/filters.yml +5 -0
  191. data/test/helpers/node_query_test.rb +3 -3
  192. data/test/integration/multiple_hosts_test.rb +1 -1
  193. data/test/integration/navigation_test.rb +1 -1
  194. data/test/sites/complex/users.yml +1 -1
  195. data/test/sites/ocean/users.yml +3 -3
  196. data/test/sites/zena/users.yml +5 -4
  197. data/test/test_zena.rb +38 -38
  198. data/test/unit/cached_page_test.rb +2 -2
  199. data/test/unit/comment_test.rb +0 -1
  200. data/test/unit/document_test.rb +23 -11
  201. data/test/unit/helpers/ping_helper_test.rb +4 -0
  202. data/test/unit/multiversion_test.rb +24 -16
  203. data/test/unit/node_test.rb +32 -93
  204. data/test/unit/note_test.rb +9 -0
  205. data/test/unit/page_test.rb +2 -2
  206. data/test/unit/secure_test.rb +2 -12
  207. data/test/unit/site_test.rb +43 -24
  208. data/test/unit/template_test.rb +45 -3
  209. data/test/unit/text_document_test.rb +4 -3
  210. data/test/unit/user_test.rb +13 -33
  211. data/test/unit/zena/db_test.rb +8 -0
  212. data/test/unit/zena/parser/zazen.yml +4 -4
  213. data/test/unit/zena/use/dates_view_methods_test.rb +2 -1
  214. data/test/unit/zena/use/html_tags_test.rb +12 -4
  215. data/test/unit/zena/use/refactor_test.rb +4 -3
  216. data/test/unit/zena/use/rendering_test.rb +1 -0
  217. data/test/unit/zena/use/upload_test.rb +76 -0
  218. data/test/unit/zena/use/urls_test.rb +4 -0
  219. data/test/unit/zena/use/zafu_test.rb +8 -0
  220. data/test/unit/zena/workflow/status_version_test.rb +6 -0
  221. data/test/unit/zena/zena_tags/ajax.yml +4 -4
  222. data/test/unit/zena/zena_tags/basic.yml +21 -10
  223. data/test/unit/zena/zena_tags/relations.yml +0 -6
  224. data/test/unit/zena/zena_tags/rubyless.yml +35 -0
  225. data/test/unit/zena/zena_tags/zazen.yml +4 -4
  226. data/test/unit/zena/zena_tags_test.rb +36 -4
  227. data/vendor/TextMate/Zena.tmbundle/Commands/Run all yaml tests.tmCommand +1 -1
  228. data/vendor/TextMate/Zena.tmbundle/Commands/Run focused yaml test.tmCommand +2 -3
  229. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/catch_exception.rb +39 -0
  230. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/run_script.rb +102 -58
  231. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/stdin_dialog.rb +14 -0
  232. data/vendor/TextMate/Zena.tmbundle/info.plist +2 -0
  233. data/zena.gemspec +2085 -0
  234. metadata +265 -90
  235. data/app/controllers/sessions_controller.rb +0 -41
  236. data/app/views/sites/zena_up.html.erb +0 -11
  237. data/config/database.yml +0 -40
  238. data/db/production.sqlite3 +0 -0
  239. data/lib/bricks/patcher.rb +0 -68
  240. data/lib/zena/parser/zena_tags.rb +0 -3562
  241. data/lib/zena/use/authentification.rb +0 -120
  242. data/public/images/ext/contact_pv.png +0 -0
  243. data/public/images/ext/other_pv.png +0 -0
  244. data/public/images/ext/page_pv.png +0 -0
  245. data/public/images/ext/page_tiny.png +0 -0
  246. data/public/images/ext/pdf_pv.png +0 -0
  247. data/public/images/ext/post_pv.png +0 -0
  248. data/public/images/ext/post_tiny.png +0 -0
  249. data/public/images/ext/project_pv.png +0 -0
  250. data/public/images/ext/project_tiny.png +0 -0
  251. data/public/images/ext/tag_pv.png +0 -0
  252. data/public/images/ext/zip_pv.png +0 -0
  253. data/tasks/ann.rake +0 -80
  254. data/tasks/bones.rake +0 -20
  255. data/tasks/gem.rake +0 -201
  256. data/tasks/git.rake +0 -40
  257. data/tasks/notes.rake +0 -27
  258. data/tasks/post_load.rake +0 -34
  259. data/tasks/rdoc.rake +0 -51
  260. data/tasks/rubyforge.rake +0 -55
  261. data/tasks/setup.rb +0 -292
  262. data/tasks/spec.rake +0 -54
  263. data/tasks/svn.rake +0 -47
  264. data/tasks/test.rake +0 -40
  265. data/tasks/zentest.rake +0 -36
  266. data/test/fixtures/comments.yml +0 -126
  267. data/test/fixtures/contact_contents.yml +0 -132
  268. data/test/fixtures/data_entries.yml +0 -65
  269. data/test/fixtures/discussions.yml +0 -48
  270. data/test/fixtures/document_contents.yml +0 -108
  271. data/test/fixtures/dyn_attributes.yml +0 -66
  272. data/test/fixtures/groups.yml +0 -86
  273. data/test/fixtures/groups_users.yml +0 -81
  274. data/test/fixtures/iformats.yml +0 -29
  275. data/test/fixtures/links.yml +0 -313
  276. data/test/fixtures/nodes.yml +0 -2592
  277. data/test/fixtures/relations.yml +0 -126
  278. data/test/fixtures/sites.yml +0 -58
  279. data/test/fixtures/template_contents.yml +0 -172
  280. data/test/fixtures/users.yml +0 -167
  281. data/test/fixtures/versions.yml +0 -1911
  282. data/test/fixtures/virtual_classes.yml +0 -87
  283. data/test/fixtures/zips.yml +0 -15
  284. data/test/functional/sessions_controller_test.rb +0 -73
@@ -0,0 +1,145 @@
1
+ module Zafu
2
+ module Support
3
+ module Dom
4
+
5
+ def start_node_s_param(type = :input)
6
+ if type == :input
7
+ "<input type='hidden' name='s' value='<%= params[:s] || @node[:zip] %>'/>"
8
+ elsif type == :erb
9
+ "s=<%= params[:s] || @node[:zip] %>"
10
+ elsif type == :value
11
+ "<%= params[:s] || @node[:zip] %>"
12
+ else
13
+ "s=\#{params[:s] || @node[:zip]}"
14
+ end
15
+ end
16
+
17
+ def erb_node_id(obj = node)
18
+ if node_kind_of?(Version)
19
+ "<%= #{obj}.node.zip %>.<%= #{obj}.number %>"
20
+ else
21
+ "<%= #{node_id(obj)} %>"
22
+ end
23
+ end
24
+
25
+ def node_id(obj = node)
26
+ "#{obj}.zip"
27
+ end
28
+
29
+ # DOM id for the current context
30
+ def dom_id(suffix='')
31
+ return "\#{dom_id(#{node})}" if @context && (@context[:saved_template] && @context[:main_node])
32
+ if @context && scope_node = @context[:scope_node]
33
+ res = "#{dom_prefix}_\#{#{scope_node}.zip}"
34
+ else
35
+ res = dom_prefix
36
+ end
37
+ if (method == 'each' || method == 'each_group') && !@context[:make_form]
38
+ "#{res}_\#{#{var}.zip}"
39
+ elsif @context && @context[:in_calendar]
40
+ "#{res}_\#{#{current_date}.to_i}"
41
+ elsif method == 'unlink' || method == 'edit'
42
+ target = nil
43
+ parent = self.parent
44
+ while parent
45
+ if ['block', 'each', 'context', 'icon'].include?(parent.method)
46
+ target = parent
47
+ break
48
+ end
49
+ parent = parent.parent
50
+ end
51
+ target ? target.dom_id(suffix) : (res + suffix)
52
+ else
53
+ res + suffix
54
+ end
55
+ end
56
+
57
+ def erb_dom_id(suffix='')
58
+ return "<%= dom_id(#{node}) %>" if @context && (@context[:saved_template] && @context[:main_node])
59
+ if @context && scope_node = @context[:scope_node]
60
+ res = "#{dom_prefix}_<%= #{scope_node}.zip %>"
61
+ else
62
+ res = dom_prefix
63
+ end
64
+ if (method == 'each' || method == 'each_group') && !@context[:make_form]
65
+ "#{res}_<%= #{var}.zip %>"
66
+ elsif method == 'draggable'
67
+ "#{res}_<%= #{node}.zip %>"
68
+ elsif @context && @context[:in_calendar]
69
+ "#{res}_<%= #{current_date}.to_i %>"
70
+ elsif method == 'unlink'
71
+ target = nil
72
+ parent = self.parent
73
+ while parent
74
+ if ['block', 'each', 'context', 'icon'].include?(parent.method)
75
+ target = parent
76
+ break
77
+ end
78
+ parent = parent.parent
79
+ end
80
+ target ? target.erb_dom_id(suffix) : (res + suffix)
81
+ else
82
+ res + suffix
83
+ end
84
+ end
85
+
86
+ # Unique template_url, ending with dom_id
87
+ def template_url
88
+ "#{@options[:root]}/#{dom_prefix}"
89
+ end
90
+
91
+ def form_url
92
+ template_url + '_form'
93
+ end
94
+
95
+ # prefix for DOM id
96
+ def dom_prefix
97
+ (@context ? @context[:dom_prefix] : nil) || (@dom_prefix ||= unique_name)
98
+ end
99
+
100
+ # use our own scope
101
+ def clear_dom_scope
102
+ @context.delete(:make_form) # should not propagate
103
+ @context.delete(:main_node) # should not propagate
104
+ end
105
+
106
+ # create our own ajax DOM scope
107
+ def new_dom_scope
108
+ clear_dom_scope
109
+ @context.delete(:saved_template) # should not propagate on fresh template
110
+ @context.delete(:dom_prefix) # should not propagate on fresh template
111
+ @context[:main_node] = true # the current context will be rendered with a fresh '@node'
112
+ @context[:dom_prefix] = self.dom_prefix
113
+ end
114
+
115
+ # Return a different name on each call
116
+ def unique_name(base = context_name)
117
+ root.next_name_index(base, base == @name).gsub(/[^\d\w\/]/,'_')
118
+ end
119
+
120
+ def context_name
121
+ @name || if @context
122
+ @context[:name] || 'list'
123
+ elsif parent
124
+ parent.context_name
125
+ else
126
+ 'root'
127
+ end
128
+ end
129
+
130
+ def next_name_index(key, own_id = false)
131
+ @next_name_index ||= {}
132
+ if @next_name_index[key]
133
+ @next_name_index[key] += 1
134
+ key + @next_name_index[key].to_s
135
+ elsif own_id
136
+ @next_name_index[key] = 0
137
+ key
138
+ else
139
+ @next_name_index[key] = 1
140
+ key + '1'
141
+ end
142
+ end
143
+ end # Dom
144
+ end # Support
145
+ end # Zafu
@@ -0,0 +1,62 @@
1
+ module Zafu
2
+ module Support
3
+ module Erb
4
+
5
+ def params_to_erb(params, initial_comma = true)
6
+ res = initial_comma ? [""] : []
7
+ params.each do |k,v|
8
+ if v =~ /<%=/ && !(v =~ /"/)
9
+ # replace by #{}
10
+ val = v.gsub('#{', '# {').gsub(/<%=(.*?)%>/,'#{\1}')
11
+ res << "#{k.inspect}=>\"#{val}\""
12
+ else
13
+ res << "#{k.inspect}=>#{v.inspect}"
14
+ end
15
+ end
16
+ res.join(', ')
17
+ end
18
+
19
+ def get_text_for_erb(params = @params, use_blocks = true, context = :erb)
20
+ string_context = context == :string
21
+ if params[:attr]
22
+ string_context ? "<%= #{node_attribute(params[:attr])} %>" : node_attribute(params[:attr])
23
+ elsif params[:tattr]
24
+ string_context ? "<%= _(#{node_attribute(params[:tattr])}) %>" : "_(#{node_attribute(params[:tattr])})"
25
+ elsif params[:trans]
26
+ string_context ? _(params[:trans]) : _(params[:trans]).inspect
27
+ elsif params[:text]
28
+ string_context ? params[:text] : params[:text].inspect
29
+ elsif use_blocks && @blocks != []
30
+ res = []
31
+ text = ""
32
+ static = true
33
+ @blocks.each do |b|
34
+ # FIXME: this is a little too hacky
35
+ if b.kind_of?(String)
36
+ res << b.inspect
37
+ text << b
38
+ elsif ['show', 'img'].include?(b.method)
39
+ res << expand_block(b, :trans=>true)
40
+ static = false
41
+ elsif ['rename_asset', 'trans'].include?(b.method)
42
+ # FIXME: if a trans contains non-static: static should become false
43
+ res << expand_block(b).inspect
44
+ text << expand_block(b)
45
+ else
46
+ # ignore
47
+ end
48
+ end
49
+ if static
50
+ # "just plain text"
51
+ string_context ? text : text.inspect
52
+ else
53
+ # function(...) + "blah" + function()
54
+ string_context ? "<%= #{res.join(' + ')} %>" : res.join(' + ')
55
+ end
56
+ else
57
+ nil
58
+ end
59
+ end
60
+ end # Erb
61
+ end # Support
62
+ end # Zafu
@@ -0,0 +1,401 @@
1
+ module Zafu
2
+ module Support
3
+ module Flow
4
+
5
+ def r_each_group
6
+ return parser_error("must be used inside a group context") unless group = @context[:group]
7
+ if join = @params[:join]
8
+ join = join.gsub(/&lt;([^%])/, '<\1').gsub(/([^%])&gt;/, '\1>')
9
+ out "<% #{group}.each_index do |#{list_var}_index| -%>"
10
+ out "<%= #{list_var}=#{group}[#{list_var}_index]; #{var} = #{list_var}[0]; #{list_var}_index > 0 ? #{join.inspect} : '' %>"
11
+ else
12
+ out "<% #{group}.each do |#{list_var}|; #{var} = #{list_var}[0]; -%>"
13
+ end
14
+ out render_html_tag(expand_with(:group => nil, :list => list_var, :node => var, :scope_node => var))
15
+ out "<% end -%>"
16
+ end
17
+
18
+ def r_each
19
+ is_draggable = @params[:draggable] == 'true' || @params[:drag_handle]
20
+
21
+ if descendant('edit') || descendant('unlink') || descendant('swap') || ['block', 'drop'].include?(single_child_method) || is_draggable
22
+ id_hash = {:id => erb_dom_id}
23
+ else
24
+ id_hash = nil
25
+ end
26
+
27
+
28
+ if @context[:make_form]
29
+ # use the elements inside 'each' loop to produce the edit form
30
+ r_form
31
+ elsif @context[:list]
32
+ # normal rendering: not the start of a saved template
33
+ if is_draggable || descendant('unlink')
34
+ out "<% #{var}_dom_ids = [] -%>"
35
+ end
36
+
37
+ @params[:alt_class] ||= @html_tag_params.delete(:alt_class)
38
+ # FIXME: add alt_reverse='true' to start counting from bottom (if order last on top...)
39
+ if @params[:alt_class] || @params[:join]
40
+ join = @params[:join] || ''
41
+ join = join.gsub(/&lt;([^%])/, '<\1').gsub(/([^%])&gt;/, '\1>')
42
+ out "<% #{var}_max_index = #{list}.size - 1 -%>" if @params[:alt_reverse]
43
+ out "<% #{list}.each_with_index do |#{var},#{var}_index| -%>"
44
+
45
+ if join_clause = @params[:join_if]
46
+ set_stored(Node, 'prev', "#{var}_prev")
47
+ cond = get_test_condition(var, :test=>join_clause)
48
+ out "<%= #{var}_prev = #{list}[#{var}_index - 1]; (#{var}_index > 0 && #{cond}) ? #{join.inspect} : '' %>"
49
+ else
50
+ out "<%= #{var}_index > 0 ? #{join.inspect} : '' %>"
51
+ end
52
+
53
+ if alt_class = @params[:alt_class]
54
+ alt_test = @params[:alt_reverse] == 'true' ? "(#{var}_max_index - #{var}_index) % 2 != 0" : "#{var}_index % 2 != 0"
55
+ if html_class = @html_tag_params.delete(:class)
56
+ html_append = " class='#{html_class}<%= #{alt_test} ? #{(' ' + alt_class).inspect} : '' %>'"
57
+ else
58
+ html_append = "<%= #{alt_test} ? ' class=#{alt_class.inspect}' : '' %>"
59
+ end
60
+ else
61
+ html_append = nil
62
+ end
63
+ else
64
+ out "<% #{list}.each do |#{var}| -%>"
65
+ html_append = nil
66
+ end
67
+
68
+ if is_draggable
69
+ out "<% #{var}_dom_ids << \"#{dom_id}\" -%>"
70
+ end
71
+
72
+ out r_anchor(var) if @anchor_param # insert anchor inside the each loop
73
+ @params[:anchor] = @anchor_param # set back in case we double render
74
+ @anchor_param = nil
75
+
76
+ res, drag_handle = set_drag_handle_and_id(expand_with(:node => var, :scope_node => var), @params, id_hash)
77
+
78
+ out render_html_tag(res, html_append)
79
+
80
+ out "<% end -%>"
81
+
82
+ if is_draggable
83
+ if drag_handle
84
+ out "<script type='text/javascript'>\n//<![CDATA[\n<%= #{var}_dom_ids.inspect %>.each(function(dom_id, index) {
85
+ new Draggable(dom_id, {ghosting:true, revert:true, handle:$(dom_id).select('.#{drag_handle}')[0]});
86
+ });\n//]]>\n</script>"
87
+ else
88
+ out "<script type='text/javascript'>\n//<![CDATA[\n<%= #{var}_dom_ids.inspect %>.each(Zena.draggable)\n//]]>\n</script>"
89
+ end
90
+ end
91
+
92
+ elsif @context[:saved_template]
93
+ # render to start a saved template
94
+ res, drag_handle = set_drag_handle_and_id(expand_with(:scope_node => node), @params, id_hash)
95
+
96
+ out render_html_tag(res)
97
+
98
+ if is_draggable
99
+ if drag_handle
100
+ 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>"
101
+ else
102
+ out "<script type='text/javascript'>\n//<![CDATA[\nZena.draggable('#{erb_dom_id}')\n//]]>\n</script>"
103
+ end
104
+ end
105
+ else
106
+ # TODO: make a single list ?
107
+ @context[:list] = "[#{node}]"
108
+ r_each
109
+ end
110
+ end
111
+
112
+ def r_case
113
+ out "<% if false -%>"
114
+ out expand_with(:in_if=>true, :only=>['when', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
115
+ @html_tag_done = true
116
+ out "<% end -%>"
117
+ end
118
+
119
+ # TODO: test
120
+ def r_if
121
+ cond = get_test_condition
122
+ return parser_error("condition error") unless cond
123
+
124
+ if cond == 'true'
125
+ return expand_with(:in_if => false)
126
+ elsif cond == 'false'
127
+ if descendant('else') || descendant('elsif')
128
+ out "<% if false -%>"
129
+ out expand_with(:in_if=>true, :only=>['elsif', 'else'])
130
+ out "<% end -%>"
131
+ return
132
+ else
133
+ @html_tag_done = true
134
+ return ''
135
+ end
136
+ end
137
+
138
+ out "<% if #{cond} -%>"
139
+ out render_html_tag(expand_with(:in_if=>false))
140
+ out expand_with(:in_if=>true, :only=>['elsif', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
141
+ out "<% end -%>"
142
+ end
143
+
144
+ def r_else
145
+ if @context[:in_if]
146
+ @html_tag = @context[:html_tag]
147
+ @html_tag_params = @context[:html_tag_params] || {}
148
+ out "<% elsif true -%>"
149
+ if @params[:text]
150
+ out render_html_tag(@params[:text])
151
+ else
152
+ out render_html_tag(expand_with(:in_if=>false, :only => nil)) # do not propagate :only from ancestor 'if' clause
153
+ end
154
+ else
155
+ ""
156
+ end
157
+ end
158
+
159
+ def r_elsif
160
+ return '' unless @context[:in_if]
161
+ @html_tag = @context[:html_tag]
162
+ @html_tag_params = @context[:html_tag_params] || {}
163
+ cond = get_test_condition
164
+ return parser_error("condition error") unless cond
165
+ out "<% elsif #{cond} -%>"
166
+ out render_html_tag(expand_with(:in_if=>false, :only => nil)) # do not propagate :only from ancestor 'if' clause
167
+ end
168
+
169
+ def r_when
170
+ r_elsif
171
+ end
172
+
173
+ protected
174
+
175
+ # TODO: RUBYLESS
176
+ def get_test_condition(node = self.node, params = @params)
177
+ tests = []
178
+ params.each do |k,v|
179
+ if k.to_s =~ /^(or_|)([a-zA-Z_]+)(\d*)$/
180
+ k = $2.to_sym
181
+ end #tagged undocumented
182
+ if [:kind_of, :klass, :status, :lang, :can, :tagged, :node, :in, :visitor, :has].include?(k)
183
+ tests << [k, v]
184
+ elsif k == :test
185
+ if v =~ /\s/
186
+ tests << [:test, v]
187
+ else
188
+ tests << [:attribute, v]
189
+ end
190
+ end
191
+ end
192
+
193
+
194
+ tests.map! do |type,value|
195
+ case type
196
+ when :kind_of
197
+ "#{node}.vkind_of?(#{value.inspect})"
198
+ when :klass
199
+ klass = begin Module::const_get(value) rescue "NilClass" end
200
+ "#{node}.klass == #{value.inspect}"
201
+ when :status
202
+ "#{node}.version.status == #{Zena::Status[value.to_sym]}"
203
+ when :tagged
204
+ # TODO: undocumented: remove and use rubyless !
205
+ "#{node}.tagged[#{value.inspect}]"
206
+ when :lang
207
+ "#{node}.version.lang == #{value.inspect}"
208
+ when :can
209
+ # TODO: test
210
+ case value
211
+ when 'write', 'edit'
212
+ "#{node}.can_write?"
213
+ when 'drive', 'publish'
214
+ "#{node}.can_drive?"
215
+ else
216
+ nil
217
+ end
218
+ when :has
219
+ case value
220
+ when 'discussion'
221
+ "#{node}.discussion"
222
+ else
223
+ nil
224
+ end
225
+ when :test
226
+ parse_condition(value, node)
227
+ when :attribute
228
+ '!' + node_attribute(value, :node => node) + '.blank?'
229
+ when :node
230
+ if node_kind_of?(Node)
231
+ value, node_name = get_attribute_and_node(value)
232
+ node_name ||= '@node'
233
+ if value
234
+ case value
235
+ when 'main'
236
+ "#{node}[:id] == #{node_name}[:id]"
237
+ when 'start'
238
+ "#{node}[:zip] == (params[:s] || @node[:zip]).to_i"
239
+ when 'parent'
240
+ "#{node}[:id] == #{node_name}[:parent_id]"
241
+ when 'project'
242
+ "#{node}[:id] == #{node_name}[:project_id]"
243
+ when 'section'
244
+ "#{node}[:id] == #{node_name}[:section_id]"
245
+ when 'ancestor'
246
+ "#{node_name}.fullpath =~ /\\A\#{#{node}.fullpath}/"
247
+ else
248
+ if stored = find_stored(Node, value)
249
+ "#{node}[:id] == #{stored}[:id]"
250
+ else
251
+ nil
252
+ end
253
+ end
254
+ else
255
+ # bad node_name
256
+ nil
257
+ end
258
+ else
259
+ nil
260
+ end
261
+ when :in
262
+ if @context["in_#{value}".to_sym] # FIXME: || ancestors.include?(value) ==> ancestors is a list of zafu tags, not a list of names !
263
+ 'true'
264
+ else
265
+ 'false'
266
+ end
267
+ when :visitor
268
+ if value == 'anon'
269
+ "visitor.is_anon?"
270
+ else
271
+ nil
272
+ end
273
+ else
274
+ nil
275
+ end
276
+ end.compact!
277
+ tests == [] ? nil : tests.join(' || ')
278
+ end
279
+
280
+ def parse_condition_error(clause, rest, res)
281
+ out parser_error("invalid clause #{clause.inspect} near \"#{res[-2..-1]}#{rest[0..1]}\"")
282
+ end
283
+
284
+ def parse_condition(clause, node_name)
285
+ rest = clause.strip
286
+ types = [:par_open, :value, :bool_op, :op, :par_close]
287
+ allowed = [:par_open, :value]
288
+ par_count = 0
289
+ uses_bool_op = false
290
+ segment = [] # value op value
291
+ after_value = lambda { segment.size == 3 ? [:bool_op, :par_close] : [:op, :bool_op, :par_close]}
292
+ res = ""
293
+ while rest != ''
294
+ # puts rest.inspect
295
+ if rest =~ /\A\s+/
296
+ rest = rest[$&.size..-1]
297
+ elsif rest[0..0] == '('
298
+ unless allowed.include?(:par_open)
299
+ parse_condition_error(clause, rest, res)
300
+ return nil
301
+ end
302
+ res << '('
303
+ rest = rest[1..-1]
304
+ par_count += 1
305
+ elsif rest[0..0] == ')'
306
+ unless allowed.include?(:par_close)
307
+ parse_condition_error(clause, rest, res)
308
+ return nil
309
+ end
310
+ res << ')'
311
+ rest = rest[1..-1]
312
+ par_count -= 1
313
+ if par_count < 0
314
+ parse_condition_error(clause, rest, res)
315
+ return nil
316
+ end
317
+ allowed = [:bool_op]
318
+ elsif rest =~ /\A(lt|le|eq|ne|ge|gt)\s+/
319
+ unless allowed.include?(:op)
320
+ parse_condition_error(clause, rest, res)
321
+ return nil
322
+ end
323
+ op = $1.strip
324
+ rest = rest[op.size..-1]
325
+ op = {'lt' => '<', 'le' => '<=', 'eq' => '==', 'ne' => '!=', 'ge' => '>=', 'gt' => '>'}[op]
326
+ segment << [op, :op]
327
+ allowed = [:value]
328
+ elsif rest =~ /\A("|')([^\1]*?)\1/
329
+ # string
330
+ unless allowed.include?(:value)
331
+ parse_condition_error(clause, rest, res)
332
+ return nil
333
+ end
334
+ rest = rest[$&.size..-1]
335
+ segment << [$2.inspect, :string]
336
+ allowed = after_value.call
337
+ elsif rest =~ /\A(-?\d+)/
338
+ # number
339
+ unless allowed.include?(:value)
340
+ parse_condition_error(clause, rest, res)
341
+ return nil
342
+ end
343
+ rest = rest[$&.size..-1]
344
+ segment << [$1, :number]
345
+ allowed = after_value.call
346
+ elsif rest =~ /\A(and|or)/
347
+ unless allowed.include?(:bool_op)
348
+ parse_condition_error(clause, rest, res)
349
+ return nil
350
+ end
351
+ uses_bool_op = true
352
+ rest = rest[$&.size..-1]
353
+ res << " #{$1} "
354
+ allowed = [:par_open, :value]
355
+ elsif rest =~ /\A([\w:\.\-]+)/
356
+ # variable
357
+ unless allowed.include?(:value)
358
+ parse_condition_error(clause, rest, res)
359
+ return nil
360
+ end
361
+ rest = rest[$&.size..-1]
362
+ fld = $1
363
+ unless node_attr = node_attribute(fld, :node => node_name)
364
+ parser_error("invalid field #{fld.inspect}")
365
+ return nil
366
+ end
367
+ segment << [node_attr, :var]
368
+ allowed = after_value.call
369
+ else
370
+ parse_condition_error(clause, rest, res)
371
+ return nil
372
+ end
373
+ if segment.size == 3
374
+ toi = (segment[1][0] =~ /(>|<)/ || (segment[0][1] == :number || segment[2][1] == :number))
375
+ segment.map! do |part, type|
376
+ if type == :var
377
+ toi ? "#{part}.to_i" : part
378
+ elsif type == :string
379
+ toi ? part[1..-2].to_i : part
380
+ else
381
+ part
382
+ end
383
+ end
384
+ res << segment.join(" ")
385
+ segment = []
386
+ end
387
+ end
388
+
389
+ if par_count > 0
390
+ parser_error("invalid clause #{clause.inspect}: missing closing ')'")
391
+ return nil
392
+ elsif allowed.include?(:value)
393
+ parser_error("invalid clause #{clause.inspect}")
394
+ return nil
395
+ else
396
+ return uses_bool_op ? "(#{res})" : res
397
+ end
398
+ end
399
+ end # Flow
400
+ end # Support
401
+ end # Zafu