zena 0.15.2 → 0.16.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 (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