zena 1.2.1 → 1.2.2

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 (202) hide show
  1. data/History.txt +38 -1
  2. data/app/controllers/documents_controller.rb +7 -5
  3. data/app/controllers/nodes_controller.rb +47 -6
  4. data/app/controllers/user_sessions_controller.rb +12 -3
  5. data/app/controllers/virtual_classes_controller.rb +8 -2
  6. data/app/models/acl.rb +5 -2
  7. data/app/models/cached_page.rb +5 -5
  8. data/app/models/column.rb +27 -4
  9. data/app/models/group.rb +1 -1
  10. data/app/models/node.rb +106 -24
  11. data/app/models/note.rb +2 -1
  12. data/app/models/relation.rb +9 -4
  13. data/app/models/relation_proxy.rb +2 -2
  14. data/app/models/role.rb +12 -5
  15. data/app/models/site.rb +10 -9
  16. data/app/models/skin.rb +8 -0
  17. data/app/models/string_hash.rb +65 -0
  18. data/app/models/text_document.rb +1 -1
  19. data/app/models/user.rb +2 -0
  20. data/app/models/virtual_class.rb +43 -10
  21. data/app/views/comments/create.rjs +1 -32
  22. data/app/views/comments/edit.rjs +1 -1
  23. data/app/views/comments/update.rjs +1 -1
  24. data/app/views/documents/show.rhtml +1 -1
  25. data/app/views/groups/_form.rhtml +7 -0
  26. data/app/views/groups/_li.rhtml +1 -1
  27. data/app/views/nodes/500.html +2 -1
  28. data/app/views/nodes/destroy.rjs +2 -0
  29. data/app/views/sites/jobs.erb +2 -3
  30. data/app/views/templates/document_create_tabs/_file.rhtml +1 -1
  31. data/app/views/templates/document_create_tabs/_import.rhtml +4 -1
  32. data/app/views/templates/document_create_tabs/_template.rhtml +3 -0
  33. data/app/views/templates/document_create_tabs/_text_document.rhtml +3 -0
  34. data/app/views/versions/custom_tab.rhtml +1 -1
  35. data/app/views/versions/edit.rhtml +1 -1
  36. data/bricks/acls/lib/bricks/acls.rb +3 -3
  37. data/bricks/acls/zena/test/unit/acl_test.rb +15 -0
  38. data/bricks/fs_skin/lib/bricks/fs_skin.rb +190 -0
  39. data/bricks/fs_skin/zena/init.rb +1 -0
  40. data/bricks/fs_skin/zena/migrate/20110702010330_add_fs_skin_to_idx_templates.rb +12 -0
  41. data/bricks/{static → fs_skin}/zena/skins/blog/Image-edit.zafu +0 -0
  42. data/bricks/{static → fs_skin}/zena/skins/blog/Image.zafu +0 -0
  43. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+index.zafu +0 -0
  44. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+notFound.zafu +0 -0
  45. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+search.zafu +0 -0
  46. data/bricks/{static → fs_skin}/zena/skins/blog/Node.zafu +1 -1
  47. data/bricks/{static → fs_skin}/zena/skins/blog/Post.zafu +0 -0
  48. data/bricks/{static → fs_skin}/zena/skins/blog/Project--kml.zafu +0 -0
  49. data/bricks/{static → fs_skin}/zena/skins/blog/Project.zafu +0 -0
  50. data/bricks/{static → fs_skin}/zena/skins/blog/comments.zafu +0 -0
  51. data/bricks/{static → fs_skin}/zena/skins/blog/dict.yml +0 -0
  52. data/bricks/{static → fs_skin}/zena/skins/blog/img/dateBg.jpg +0 -0
  53. data/bricks/{static → fs_skin}/zena/skins/blog/img/header.png +0 -0
  54. data/bricks/{static → fs_skin}/zena/skins/blog/img/mapPin.png +0 -0
  55. data/bricks/{static → fs_skin}/zena/skins/blog/img/menu.gif +0 -0
  56. data/bricks/{static → fs_skin}/zena/skins/blog/img/menuover.gif +0 -0
  57. data/bricks/{static → fs_skin}/zena/skins/blog/img/style.css +0 -0
  58. data/bricks/fs_skin/zena/tasks.rb +26 -0
  59. data/bricks/{static/zena/test/integration/static_integration_test.rb → fs_skin/zena/test/integration/fs_skin_integration_test.rb} +6 -6
  60. data/bricks/fs_skin/zena/test/unit/fs_skin_test.rb +33 -0
  61. data/bricks/grid/lib/bricks/grid.rb +4 -3
  62. data/bricks/tags/lib/bricks/tags.rb +1 -7
  63. data/bricks/zena/zena/migrate/20120605091558_add_ssl_login_to_site.rb +7 -0
  64. data/bricks/zena/zena/migrate/20120630123551_add_auto_publish_to_group.rb +9 -0
  65. data/config/bricks.yml +3 -3
  66. data/config/gems.yml +2 -3
  67. data/lib/tasks/zena.rake +7 -3
  68. data/lib/zafu.rb +7 -0
  69. data/lib/zafu/all.rb +21 -0
  70. data/lib/zafu/compiler.rb +7 -0
  71. data/lib/zafu/controller_methods.rb +58 -0
  72. data/lib/zafu/handler.rb +57 -0
  73. data/lib/zafu/info.rb +4 -0
  74. data/lib/zafu/markup.rb +309 -0
  75. data/lib/zafu/mock_helper.rb +42 -0
  76. data/lib/zafu/node_context.rb +203 -0
  77. data/lib/zafu/ordered_hash.rb +53 -0
  78. data/lib/zafu/parser.rb +676 -0
  79. data/lib/zafu/parsing_rules.rb +382 -0
  80. data/lib/zafu/process/ajax.rb +530 -0
  81. data/lib/zafu/process/conditional.rb +92 -0
  82. data/lib/zafu/process/context.rb +186 -0
  83. data/lib/zafu/process/forms.rb +143 -0
  84. data/lib/zafu/process/html.rb +186 -0
  85. data/lib/zafu/process/ruby_less_processing.rb +321 -0
  86. data/lib/zafu/security.rb +15 -0
  87. data/lib/zafu/template.rb +25 -0
  88. data/lib/zafu/test_helper.rb +19 -0
  89. data/lib/zafu/view_methods.rb +6 -0
  90. data/lib/zena.rb +1 -1
  91. data/lib/zena/acts/enrollable.rb +1 -1
  92. data/lib/zena/app.rb +4 -17
  93. data/lib/zena/console.rb +18 -1
  94. data/lib/zena/core_ext/file_utils.rb +13 -1
  95. data/lib/zena/core_ext/fixnum.rb +4 -0
  96. data/lib/zena/core_ext/float.rb +7 -0
  97. data/lib/zena/deploy.rb +4 -2
  98. data/lib/zena/deploy/app_init.rhtml +2 -1
  99. data/lib/zena/deploy/database.rhtml +1 -1
  100. data/lib/zena/info.rb +1 -1
  101. data/lib/zena/parser/zazen_rules.rb +4 -4
  102. data/lib/zena/routes.rb +1 -1
  103. data/lib/zena/test_controller.rb +1 -1
  104. data/lib/zena/use.rb +14 -1
  105. data/lib/zena/use/action.rb +4 -2
  106. data/lib/zena/use/ajax.rb +86 -38
  107. data/lib/zena/use/authlogic.rb +16 -1
  108. data/lib/zena/use/calendar.rb +37 -17
  109. data/lib/zena/use/conditional.rb +2 -2
  110. data/lib/zena/use/context.rb +30 -9
  111. data/lib/zena/use/dates.rb +39 -3
  112. data/lib/zena/use/display.rb +6 -19
  113. data/lib/zena/use/forms.rb +100 -79
  114. data/lib/zena/use/i18n.rb +40 -16
  115. data/lib/zena/use/query_builder.rb +0 -6
  116. data/lib/zena/use/query_node.rb +17 -4
  117. data/lib/zena/use/relations.rb +1 -3
  118. data/lib/zena/use/rendering.rb +10 -8
  119. data/lib/zena/use/scope_index.rb +5 -1
  120. data/lib/zena/use/search.rb +2 -1
  121. data/lib/zena/use/urls.rb +82 -77
  122. data/lib/zena/use/workflow.rb +12 -4
  123. data/lib/zena/use/zafu_safe_definitions.rb +37 -9
  124. data/lib/zena/use/zafu_templates.rb +49 -20
  125. data/lib/zena/use/zazen.rb +6 -2
  126. data/locale/it/LC_MESSAGES/zena.mo +0 -0
  127. data/locale/it/zena.mo +0 -0
  128. data/locale/it/zena.po +1982 -0
  129. data/public/images/arrow_back.png +0 -0
  130. data/public/images/remove_tag.png +0 -0
  131. data/public/javascripts/grid.js +800 -199
  132. data/public/javascripts/window.js +1 -1
  133. data/public/javascripts/zena.js +130 -21
  134. data/public/stylesheets/grid.css +11 -2
  135. data/public/stylesheets/zena.css +2 -1
  136. data/test/custom_queries/complex.host.yml +5 -0
  137. data/test/fixtures/files/TestNode.zafu +36 -0
  138. data/test/functional/nodes_controller_test.rb +18 -1
  139. data/test/integration/zafu_compiler/action.yml +2 -2
  140. data/test/integration/zafu_compiler/ajax.yml +44 -26
  141. data/test/integration/zafu_compiler/asset.yml +12 -2
  142. data/test/integration/zafu_compiler/basic.yml +0 -16
  143. data/test/integration/zafu_compiler/calendar.yml +6 -6
  144. data/test/integration/zafu_compiler/complex_ok.yml +23 -1
  145. data/test/integration/zafu_compiler/conditional.yml +5 -5
  146. data/test/integration/zafu_compiler/context.yml +6 -5
  147. data/test/integration/zafu_compiler/dates.yml +23 -2
  148. data/test/integration/zafu_compiler/display.yml +46 -2
  149. data/test/integration/zafu_compiler/errors.yml +2 -2
  150. data/test/integration/zafu_compiler/eval.yml +35 -7
  151. data/test/integration/zafu_compiler/forms.yml +47 -13
  152. data/test/integration/zafu_compiler/i18n.yml +2 -2
  153. data/test/integration/zafu_compiler/meta.yml +35 -1
  154. data/test/integration/zafu_compiler/query.yml +23 -4
  155. data/test/integration/zafu_compiler/relations.yml +10 -6
  156. data/test/integration/zafu_compiler/roles.yml +4 -4
  157. data/test/integration/zafu_compiler/rubyless.yml +11 -1
  158. data/test/integration/zafu_compiler/safe_definitions.yml +23 -5
  159. data/test/integration/zafu_compiler/security.yml +10 -6
  160. data/test/integration/zafu_compiler/urls.yml +23 -6
  161. data/test/integration/zafu_compiler/zafu_attributes.yml +1 -1
  162. data/test/integration/zafu_compiler/zazen.yml +14 -0
  163. data/test/selenium/Add/add3.rsel +8 -8
  164. data/test/selenium/Destroy/0setup.rsel +12 -0
  165. data/test/selenium/Destroy/destroy1.rsel +16 -0
  166. data/test/selenium/Edit/edit2.rsel +9 -9
  167. data/test/selenium/Edit/edit5.rsel +9 -9
  168. data/test/selenium/Edit/edit6.rsel +9 -9
  169. data/test/selenium/Form/form4.rsel +17 -0
  170. data/test/selenium/Toggle/toggle1.rsel +2 -0
  171. data/test/selenium/Toggle/toggle2.rsel +18 -0
  172. data/test/sites/zena/columns.yml +3 -0
  173. data/test/sites/zena/versions.yml +7 -0
  174. data/test/unit/cached_page_test.rb +13 -13
  175. data/test/unit/column_test.rb +26 -0
  176. data/test/unit/node_test.rb +16 -1
  177. data/test/unit/project_test.rb +6 -1
  178. data/test/unit/relation_test.rb +1 -1
  179. data/test/unit/role_test.rb +1 -1
  180. data/test/unit/string_hash_test.rb +30 -0
  181. data/test/unit/virtual_class_test.rb +31 -17
  182. data/test/unit/zafu_markup_test.rb +414 -0
  183. data/test/unit/zafu_node_context_test.rb +375 -0
  184. data/test/unit/zafu_ordered_hash_test.rb +69 -0
  185. data/test/unit/zena/acts/enrollable_test.rb +1 -1
  186. data/test/unit/zena/parser/zafu_asset.yml +0 -10
  187. data/test/unit/zena/parser/zazen.yml +1 -1
  188. data/test/unit/zena/parser_test.rb +1 -72
  189. data/test/unit/zena/use/dates_test.rb +1 -1
  190. data/test/unit/zena/use/rendering_test.rb +24 -7
  191. data/test/unit/zena/use/scope_index_test.rb +17 -0
  192. data/test/unit/zena/use/zazen_test.rb +2 -1
  193. data/zena.gemspec +71 -37
  194. metadata +104 -83
  195. data/app/views/nodes/destroy.erb +0 -0
  196. data/bricks/static/lib/bricks/static.rb +0 -151
  197. data/bricks/static/zena/init.rb +0 -1
  198. data/bricks/static/zena/migrate/20110702010330_add_static_to_idx_templates.rb +0 -12
  199. data/bricks/static/zena/test/unit/static_test.rb +0 -33
  200. data/lib/zena/parser/zafu_rules.rb +0 -244
  201. data/lib/zena/parser/zafu_tags.rb +0 -198
  202. data/lib/zena/parser/zena_rules.rb +0 -23
@@ -0,0 +1,92 @@
1
+ module Zafu
2
+ module Process
3
+ # This module manages conditional rendering (if, else, elsif, case, when).
4
+ module Conditional
5
+ def r_if(cond = nil)
6
+ cond ||= get_condition
7
+ return unless cond
8
+ expand_if(cond)
9
+ end
10
+
11
+ def r_case
12
+ r_if('false')
13
+ end
14
+
15
+ def r_else
16
+ r_elsif('true')
17
+ end
18
+
19
+ def r_when
20
+ r_elsif
21
+ end
22
+
23
+ def r_elsif(cond = nil)
24
+ return '' unless @context[:in_if]
25
+ cond ||= get_condition
26
+ return unless cond
27
+
28
+ res = expand_with(:in_if => false, :markup => nil)
29
+
30
+ # We use 'elsif' just in case there are more then one 'else' clause
31
+ if markup = @context[:markup]
32
+ if @markup.tag.blank?
33
+ # Copy markup tag
34
+ @markup.tag = markup.tag
35
+ @markup.steal_html_params_from(@params)
36
+ markup.params.each do |k, v|
37
+ next if @markup.params[k]
38
+ @markup.set_param(k, v)
39
+ end
40
+
41
+ markup.dyn_params.each do |k, v|
42
+ next if @markup.params[k] || @markup.dyn_params[k]
43
+ @markup.set_dyn_param(k, v)
44
+ end
45
+ inner = wrap(res)
46
+ else
47
+ markup.done = false
48
+ # Wrap with both markup (ours and the else/elsif clause).
49
+ inner = markup.wrap(wrap(res))
50
+ end
51
+ out "<% elsif #{cond} %>#{inner}" # do not propagate
52
+ else
53
+ #@markup.done = true # never wrap else/elsif clause
54
+ out "<% elsif #{cond} %>#{res}" # do not propagate
55
+ end
56
+ end
57
+
58
+ # Expand blocks with conditional processing enabled (else, elsif, etc).
59
+ #
60
+ # ==== Parameters
61
+ #
62
+ # * +condition+ - ruby condition for the conditional execution.
63
+ # * +new_node_context+ - (optional) new node context to enter if the clause succeeds.
64
+ # * +alt_markup+ - (optional) alternative markup to use for the 'else', 'elsif' clauses.
65
+ def expand_if(condition, new_node_context = self.node, alt_markup = @markup)
66
+ res = ""
67
+ res << "<% if #{condition} %>"
68
+ with_context(:node => new_node_context) do
69
+ res << wrap(expand_with)
70
+ end
71
+
72
+ only = method == 'case' ? %r{^[A-Z]|else|elsif|when} : %w{else elsif when}
73
+ res << expand_with(:in_if => true, :only => only, :markup => alt_markup)
74
+ res << "<% end %>"
75
+ res
76
+ end
77
+
78
+ private
79
+ def get_condition
80
+ if in_tag = @params[:in]
81
+ if in_tag == 'form' && @context[:make_form]
82
+ 'true'
83
+ else
84
+ ancestor(in_tag) ? 'true' : 'false'
85
+ end
86
+ else
87
+ get_attribute_or_eval(false)
88
+ end
89
+ end
90
+ end # Context
91
+ end # Process
92
+ end # Zafu
@@ -0,0 +1,186 @@
1
+ module Zafu
2
+ module Process
3
+ # This module manages the change of contexts by opening (each) or moving into the NodeContext.
4
+ # The '@context' holds many information on the current compilation environment. Inside this
5
+ # context, the "node" context holds information on the type of "this" (first responder).
6
+ module Context
7
+ def r_each
8
+ if node.list_context?
9
+ if @params[:alt_class] || @params[:join]
10
+ out "<% #{var}_max_index = #{node}.size - 1 %>" if @params[:alt_reverse]
11
+ out "<% #{node}.each_with_index do |#{var},#{var}_index| %>"
12
+
13
+ if join = @params[:join]
14
+ join = RubyLess.translate_string(self, join)
15
+ out "<%= #{var}_index > 0 ? #{join} : '' %>"
16
+ end
17
+
18
+ if alt_class = @params[:alt_class]
19
+ alt_class = RubyLess.translate_string(self, alt_class)
20
+ alt_test = @params[:alt_reverse] == 'true' ? "(#{var}_max_index - #{var}_index) % 2 != 0" : "#{var}_index % 2 != 0"
21
+
22
+ alt_var = get_var_name('set_var', 'alt_class')
23
+ set_context_var('set_var', 'alt_class', RubyLess::TypedString.new(alt_var, :class => String))
24
+ out "<% #{alt_var} = #{alt_test} ? #{alt_class} : '' %>"
25
+
26
+ if @markup.tag
27
+ @markup.append_dyn_param(:class, "<%= #{alt_var} %>")
28
+ else
29
+ # Just declare 'alt_class'
30
+ end
31
+ end
32
+ else
33
+ out "<% #{node}.each do |#{var}| %>"
34
+ end
35
+
36
+ raw_dom_prefix = node.raw_dom_prefix
37
+
38
+ with_context(:node => node.move_to(var, node.klass.first, :query => node.opts[:query])) do
39
+ # We pass the :query option for RubyLess resolution by using the QueryBuilder finder
40
+
41
+ steal_and_eval_html_params_for(@markup, @params)
42
+ # The id set here should be used as prefix for sub-nodes to ensure uniqueness of generated DOM ids
43
+ if node.list_context?
44
+ # we are still in a list (example: previous context was [[Node]], current is [Node])
45
+ else
46
+ # Change dom_prefix if it isn't our own (inherited).
47
+ node.dom_prefix = dom_name unless raw_dom_prefix
48
+ node.propagate_dom_scope!
49
+
50
+ if need_dom_id?
51
+ @markup.set_id(node.dom_id)
52
+ end
53
+ end
54
+
55
+ out wrap(expand_with)
56
+ end
57
+ out "<% end %>"
58
+ else
59
+ out expand_with
60
+ end
61
+
62
+ # We need to return true for Ajax 'make_form'
63
+ true
64
+ end
65
+
66
+ def helper
67
+ @context[:helper]
68
+ end
69
+
70
+ # Return true if we need to insert the dom id for this element. This method is overwritten in Ajax.
71
+ def need_dom_id?
72
+ false
73
+ end
74
+
75
+ # Return the node context for a given class (looks up into the hierarchy) or the
76
+ # current node context if klass is nil.
77
+ def node(klass = nil)
78
+ return @context[:node] if !klass
79
+ @context[:node].get(klass)
80
+ end
81
+
82
+ # Store some contextual value / variable inside a named group. This should be
83
+ # used to avoid key clashes between different types of elements to store.
84
+ def set_context_var(group, key, obj, context = @context)
85
+ context["#{group}::#{key}"] = obj
86
+ end
87
+
88
+ # Retrieve a value from a given contextual group. The value must have been
89
+ # previously set with 'set_context_var' somewhere in the hierarchy.
90
+ def get_context_var(group, key, context = @context)
91
+ context["#{group}::#{key}"]
92
+ end
93
+
94
+ # Return a new context without contextual variables.
95
+ def context_without_vars
96
+ context = @context.dup
97
+ context.keys.each do |k|
98
+ context.delete(k) if k.kind_of?(String)
99
+ end
100
+ context
101
+ end
102
+
103
+ # Expand blocks in a new context.
104
+ # This method is partly overwriten in Ajax
105
+ def expand_with_finder(finder)
106
+ if finder[:nil]
107
+ open_node_context(finder, :form => nil) do # do not propagate :form
108
+ expand_if("#{var} = #{finder[:method]}", node.move_to(var, finder[:class], finder.merge(:nil => false)))
109
+ end
110
+ else
111
+ res = ''
112
+ res << "<% #{var} = #{finder[:method]} %>"
113
+ open_node_context(finder, :node => node.move_to(var, finder[:class], finder), :form => nil) do
114
+ res << wrap(expand_with)
115
+ end
116
+ res
117
+ end
118
+ end
119
+
120
+ # def context_with_node(name, klass)
121
+ # context = @context.dup
122
+ # context[:node] = context[:node].move_to(name, klass)
123
+ # end
124
+
125
+ def var
126
+ return @var if @var
127
+ if node.name =~ /^var(\d+)$/
128
+ @var = "var#{$1.to_i + 1}"
129
+ else
130
+ @var = "var1"
131
+ end
132
+ end
133
+
134
+ # This method is called when we enter a new node context
135
+ def node_context_vars(finder)
136
+ # do nothing (this is a hook for other modules like QueryBuilder and RubyLess)
137
+ {}
138
+ end
139
+
140
+ # Get a variable name and store the name in context variables for the given group.
141
+ #
142
+ # ==== Parameters
143
+ #
144
+ # * +group_name+ - name of the variable context group
145
+ # * +wanted_name+ - wanted variable name (used as key to get real var back later with #get_context_var)
146
+ # * +context+ - (optional) can be used if we do not want to store the variable definition in the current context
147
+ #
148
+ def get_var_name(group_name, wanted_name, context = @context)
149
+ secure_name = wanted_name.gsub(/[^a-zA-Z0-9]/,'')
150
+ name = "_z#{secure_name}"
151
+ i = 0
152
+ while get_context_var('var', name, context)
153
+ i += 1
154
+ name = "_z#{secure_name}#{i}"
155
+ end
156
+ set_context_var('var', name, true)
157
+ set_context_var(group_name, wanted_name, name)
158
+ name
159
+ end
160
+
161
+ # Change context for a given scope.
162
+ def with_context(cont, merge = true)
163
+ raise "Block missing" unless block_given?
164
+ cont_bak = @context
165
+ if merge
166
+ @context = @context.merge(cont)
167
+ else
168
+ @context = cont
169
+ end
170
+ res = yield
171
+ @context = cont_bak
172
+ res
173
+ end
174
+
175
+ # This should be called when we enter a new node context so that the proper hooks are
176
+ # triggered (insertion of contextual variables).
177
+ def open_node_context(finder, cont = {})
178
+ sub_context = node_context_vars(finder).merge(cont)
179
+
180
+ with_context(sub_context) do
181
+ yield
182
+ end
183
+ end
184
+ end # Context
185
+ end # Process
186
+ end # Zafu
@@ -0,0 +1,143 @@
1
+ module Zafu
2
+ module Process
3
+ module Forms
4
+ def self.included(base)
5
+ base.expander :make_form
6
+ end
7
+
8
+ def r_form
9
+ if node.dom_prefix
10
+ fnode = node
11
+ else
12
+ fnode = node.dup
13
+ fnode.dom_prefix = dom_name
14
+ end
15
+ with_context(:node => fnode) do
16
+
17
+ unless @params[:on].nil? || @params[:on].split(',').include?(@context[:ajax_action])
18
+ return ''
19
+ end
20
+
21
+ return parser_error('Cannot render update form in list context.') if node.list_context?
22
+
23
+ options = form_options
24
+
25
+ @markup.set_id(options[:id]) if options[:id]
26
+ @markup.set_param(:style, options[:style]) if options[:style]
27
+
28
+ if descendant('form_tag')
29
+ # We have a specific place to insert our form
30
+ out expand_with(:form_options => options, :form => self)
31
+ else
32
+ r_form_tag(options)
33
+ end
34
+ end
35
+ end
36
+
37
+ def r_form_tag(options = @context[:form_options])
38
+ form_tag(options) do |opts|
39
+ # Render error messages tag
40
+ form_error_messages(opts[:form_helper])
41
+
42
+ # Render form elements
43
+ out expand_with(opts)
44
+
45
+ # Render hidden fields (these must go after normal elements so that focusFirstElement works)
46
+ hidden_fields = form_hidden_fields(options)
47
+
48
+ out "<div class='hidden'>"
49
+ hidden_fields.each do |k,v|
50
+ if v.kind_of?(String)
51
+ v = "'#{v}'" unless v.kind_of?(String) && ['"', "'"].include?(v[0..0])
52
+ out "<input type='hidden' name='#{k}' value=#{v}/>"
53
+ elsif v.kind_of?(Array)
54
+ # We use ['ffff'] to indicate that the content is already escaped and ready for ERB.
55
+ out v.first
56
+ end
57
+ end
58
+ out '</div>'
59
+ end
60
+ end
61
+
62
+ private
63
+ def make_form
64
+ return nil unless @context[:make_form]
65
+
66
+ if method == 'each' || method == 'block'
67
+ r_form
68
+ else
69
+ nil
70
+ end
71
+ end
72
+
73
+ # Return id, style, form and cancel parts of the form.
74
+ def form_options
75
+ opts = {}
76
+
77
+ # Do we need this ?
78
+ # opts[:klass] = node.master_class(ActiveRecord::Base).to_s
79
+
80
+ if @context[:in_add]
81
+ opts[:id] = "#{node.dom_prefix}_add"
82
+ opts[:style] = 'display:none;'
83
+ elsif @markup.tag == 'table'
84
+ # the normal id goes to the form wrapping the table
85
+ opts[:id] = "#{node.dom_prefix}_tbl"
86
+ form_id = node.dom_prefix
87
+ end
88
+
89
+ form_id ||= "#{node.dom_prefix}_form_t"
90
+ if @context[:template_url]
91
+ opts[:form_tag] = "<% remote_form_for(:#{node.form_name}, #{node}, :html => {:id => #{form_id.inspect}}) do |f| %>"
92
+ opts[:form_helper] = 'f'
93
+ else
94
+ opts[:form_tag] = "<% form_for(:#{node.form_name}, #{node}, :html => {:id => #{form_id.inspect}}) do |f| %>"
95
+ opts[:form_helper] = 'f'
96
+ end
97
+ opts[:form_prefix] = node.dom_prefix || dom_name
98
+ opts
99
+ end
100
+
101
+ # Return hidden fields that need to be inserted in the form.
102
+ def form_hidden_fields(opts)
103
+ if t_url = @context[:template_url]
104
+ {'t_url' => t_url}
105
+ else
106
+ {}
107
+ end
108
+ end
109
+
110
+ # Render the 'form' tag and set expansion context.
111
+ def form_tag(options)
112
+ opts = options.dup
113
+
114
+ if descendant('cancel') || descendant('edit')
115
+ # Pass 'form_cancel' content to expand_with (already in options).
116
+ else
117
+ # Insert cancel before form
118
+ out opts.delete(:form_cancel).to_s
119
+ end
120
+
121
+ # form_for ... do |f|
122
+ out opts.delete(:form_tag)
123
+ # f.xxx
124
+ if markup.tag == 'table'
125
+ # Avoid <table><form> (invalid HTML)
126
+ bak = @result
127
+ @result = ''
128
+ yield(opts.merge(:in_form => true))
129
+ @result = bak + markup.wrap(@result)
130
+ else
131
+ yield(opts.merge(:in_form => true))
132
+ end
133
+ # close form
134
+ out opts[:form_helper] ? "<% end %>" : '</form>'
135
+ end
136
+
137
+ def form_error_messages(f)
138
+ out "<%= #{f}.error_messages %>"
139
+ end
140
+
141
+ end # Forms
142
+ end # Process
143
+ end # Zafu
@@ -0,0 +1,186 @@
1
+ module Zafu
2
+ module Process
3
+ module HTML
4
+ SAFE_SRC_REGEX = %r{\A/[^\.]+\.[a-zA-Z]+\Z}
5
+ def self.included(base)
6
+ base.wrap :wrap_html
7
+ end
8
+
9
+ # Replace the 'original' element in the included template with our new version.
10
+ def replace_with(new_obj)
11
+ super
12
+ # [self = original_element]. Replace @markup with content of the new_obj (<ul do='with'>...)
13
+ if new_obj.markup.tag
14
+ @markup.tag = new_obj.markup.tag
15
+ else
16
+ # Steal 'class' param
17
+ @markup.steal_html_params_from(new_obj.params)
18
+ end
19
+
20
+ @markup.params.merge!(new_obj.markup.params)
21
+
22
+ # We do not have to merge dyn_params since these are compiled before processing (and we are in
23
+ # the pre-processor)
24
+
25
+ if new_obj.params[:method]
26
+ @method = new_obj.params[:method]
27
+ elsif new_obj.sub_do
28
+ @method = 'void'
29
+ end
30
+ end
31
+
32
+ # Pass the caller's 'markup' to the included part.
33
+ def include_part(obj)
34
+ if @markup.tag
35
+ obj.markup = @markup.dup
36
+ end
37
+ @markup.tag = nil
38
+
39
+ if sub_do
40
+ obj.method = @blocks.first.method
41
+ obj.params = @blocks.first.params
42
+ elsif params[:method]
43
+ obj.method = params[:method]
44
+ end
45
+ super(obj)
46
+ end
47
+
48
+ def empty?
49
+ super && @markup.params == {} && @markup.tag.nil?
50
+ end
51
+
52
+ def compile_html_params
53
+ return if @markup.done
54
+ unless @markup.tag
55
+ if @markup.tag = @params.delete(:tag)
56
+ @markup.steal_html_params_from(@params)
57
+ end
58
+ end
59
+
60
+ # Translate dynamic params such as <tt>class='#{visitor.lang}'</tt> in the context
61
+ # of the current parser
62
+ @markup.compile_params(self)
63
+ end
64
+
65
+ def wrap_html(text)
66
+ compile_html_params
67
+ @markup.wrap(text)
68
+ end
69
+
70
+ #def restore_markup
71
+ # # restore @markup
72
+ # @markup = @markup_bak
73
+ #end
74
+
75
+ def inspect
76
+ @markup.done = false
77
+ res = super
78
+ if @markup.tag
79
+ if res =~ /\A\[(\w+)(.*)\/\]\Z/m
80
+ res = "[#{$1}#{$2}]<#{@markup.tag}/>[/#{$1}]"
81
+ elsif res =~ /\A\[([^\]]+)\](.*)\[\/(\w+)\]\Z/m
82
+ res = "[#{$1}]#{@markup.wrap($2)}[/#{$3}]"
83
+ end
84
+ end
85
+ res
86
+ end
87
+
88
+ def r_ignore
89
+ @markup.done = true
90
+ ''
91
+ end
92
+
93
+ def r_rename_asset
94
+ return expand_with unless @markup.tag
95
+ case @markup.tag
96
+ when 'link'
97
+ key = :href
98
+ return parser_error("Missing 'rel' parameter.") unless rel = @params[:rel]
99
+ return parser_error("Missing 'href' parameter.") unless @params[:href]
100
+ if rel.downcase == 'stylesheet'
101
+ type = :stylesheet
102
+ else
103
+ type = :link
104
+ end
105
+ when 'style'
106
+ return expand_with.gsub(/url\(('|")(.*?)\1\)/) do
107
+ if $2[0..6] == 'http://'
108
+ $&
109
+ else
110
+ quote = $1
111
+ new_src = helper.send(:template_url_for_asset, :base_path=>@options[:base_path], :src => $2)
112
+ "url(#{quote}#{new_src}#{quote})"
113
+ end
114
+ end
115
+ else
116
+ key = :src
117
+ type = @markup.tag.to_sym
118
+ end
119
+
120
+ src = @params.delete(key)
121
+ if src && src[0..7] != 'http://'
122
+ if new_value = helper.send(:template_url_for_asset, :src => src, :base_path => @options[:base_path], :type => type)
123
+ elsif src =~ SAFE_SRC_REGEX
124
+ fullpath = "#{SITES_ROOT}#{current_site.public_path}#{src}"
125
+ if File.exist?(fullpath) && File.stat(fullpath)
126
+ src = "#{src}?#{File.mtime(fullpath).to_i}"
127
+ end
128
+ end
129
+ @markup.params[key] = new_value.blank? ? src : new_value
130
+ end
131
+
132
+ expand_with
133
+ end
134
+
135
+ def steal_and_eval_html_params_for(markup, params)
136
+ markup.steal_keys.each do |key|
137
+ next unless value = params.delete(key)
138
+ append_markup_attr(markup, key, value)
139
+ end
140
+ end
141
+ #def r_form
142
+ # res = "<#{@markup.tag}#{params_to_html(@params)}"
143
+ # @markup.done = true
144
+ # inner = expand_with
145
+ # if inner == ''
146
+ # res + "/>"
147
+ # else
148
+ # res + ">#{inner}"
149
+ # end
150
+ #end
151
+ #
152
+ #def r_select
153
+ # res = "<#{@markup.tag}#{params_to_html(@params)}"
154
+ # @markup.done = true
155
+ # inner = expand_with
156
+ # if inner == ''
157
+ # res + "></#{@markup.tag}>"
158
+ # else
159
+ # res + ">#{inner}"
160
+ # end
161
+ #end
162
+ #
163
+ #def r_input
164
+ # res = "<#{@markup.tag}#{params_to_html(@params)}"
165
+ # @markup.done = true
166
+ # inner = expand_with
167
+ # if inner == ''
168
+ # res + "/>"
169
+ # else
170
+ # res + ">#{inner}"
171
+ # end
172
+ #end
173
+ #
174
+ #def r_textarea
175
+ # res = "<#{@markup.tag}#{params_to_html(@params)}"
176
+ # @markup.done = true
177
+ # inner = expand_with
178
+ # if inner == ''
179
+ # res + "/>"
180
+ # else
181
+ # res + ">#{inner}"
182
+ # end
183
+ #end
184
+ end # HTML
185
+ end # Process
186
+ end # Zafu