zena 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
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