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
@@ -51,7 +51,7 @@ module Zena
51
51
  end
52
52
 
53
53
  # Get day class. The first parameter is an UTC Date. The second is a local Time.
54
- def cal_class(utc_date, local_ref, tz)
54
+ def cal_class(utc_date, local_ref, tz, events=nil)
55
55
  date = tz.utc_to_local(utc_date.to_time)
56
56
  @cal_today ||= tz.utc_to_local(Time.now).strftime(DAY_FORMAT)
57
57
  case date.wday
@@ -64,9 +64,10 @@ module Zena
64
64
  end
65
65
  s += 'other' if date.mon != local_ref.mon
66
66
  s = s == '' ? [] : [s]
67
- s << 'today' if date.strftime(DAY_FORMAT) == @today
67
+ s << 'today' if date.strftime(DAY_FORMAT) == @cal_today
68
68
  s << 'ref' if date.strftime(DAY_FORMAT) == local_ref.strftime(DAY_FORMAT)
69
- s == [] ? '' : " class='#{s.join(' ')}'"
69
+ s << 'events' if events
70
+ s.join(' ')
70
71
  end
71
72
 
72
73
  # Yield block for every week between 'start_date' and 'end_date' with a hash of days => events.
@@ -197,16 +198,16 @@ module Zena
197
198
  if header_block = descendant('header')
198
199
  elsif @params[:type] == 'week'
199
200
  add_block(%q{<h3 do='header'>
200
- <r:link date='date.advance(:days =&gt; -1)' t='img_prev_page'/>
201
+ <r:link date='date.advance(:days => -1)' t='img_prev_page'/>
201
202
  <r:date format='%B'/>
202
- <r:link date='date.advance(:days =&gt; 1)' t='img_next_page'/>
203
+ <r:link date='date.advance(:days => 1)' t='img_next_page'/>
203
204
  </h3>}, true)
204
205
  header_block = descendant('header')
205
206
  else
206
207
  add_block(%q{<h3 do='header'>
207
- <r:link date='date.advance(:months =&gt; -1)' t='img_prev_page'/>
208
+ <r:link date='date.advance(:months => -1)' t='img_prev_page'/>
208
209
  <r:date format='%B'/>
209
- <r:link date='date.advance(:months =&gt; 1)' t='img_next_page'/>
210
+ <r:link date='date.advance(:months => 1)' t='img_next_page'/>
210
211
  </h3>}, true)
211
212
  header_block = descendant('header')
212
213
  end
@@ -231,7 +232,7 @@ module Zena
231
232
  opts[:current_date] = get_var_name('calendar', 'c_date')
232
233
  make_calendar(opts)
233
234
  end
234
-
235
+
235
236
  def make_calendar(opts)
236
237
  current_date = opts[:current_date]
237
238
  type = params[:type] ? params[:type].to_sym : :month
@@ -257,9 +258,10 @@ module Zena
257
258
  set_tz = "<% #{tz_var} = visitor.tz %>"
258
259
  end
259
260
 
260
- cell_date = get_var_name('calendar', 'date')
261
- cal_start = get_var_name('calendar', 'cal_start')
262
- cal_end = get_var_name('calendar', 'cal_end')
261
+ cell_date = get_var_name('calendar', 'date')
262
+ cal_start = get_var_name('calendar', 'cal_start')
263
+ cal_end = get_var_name('calendar', 'cal_end')
264
+ day_class = get_var_name('calendar', 'class')
263
265
 
264
266
  # To avoid wrapping in each cell
265
267
  markup = @markup
@@ -305,15 +307,16 @@ module Zena
305
307
  klass = finder[:query].main_class
306
308
  return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)
307
309
 
308
- if type = klass.safe_method_type([date_attr])
309
- if type[:class] <= Time
310
+ if safe_type = klass.safe_method_type([date_attr])
311
+ if safe_type[:class] <= Time
310
312
  # OK
311
313
  else
312
- return parser_error("Invalid attribute '#{date_attr}': type is '#{type[:class]}' should be Time")
314
+ return parser_error("Invalid attribute '#{date_attr}': '#{safe_type[:class]}' is not a Time")
313
315
  end
314
316
  else
315
317
  return parser_error("Invalid attribute '#{date_attr}' for #{klass}")
316
318
  end
319
+
317
320
  # HACK to overwrite 'header' method...
318
321
  h = opts[:header]
319
322
  h.method = 'void'
@@ -325,6 +328,12 @@ module Zena
325
328
  cell_date,
326
329
  :class => Time
327
330
  ))
331
+
332
+ # Date for the cell
333
+ set_context_var('set_var', 'day_class', RubyLess::TypedString.new(
334
+ day_class,
335
+ :class => String
336
+ ))
328
337
 
329
338
 
330
339
  # HACK to render sub-elements...
@@ -333,7 +342,18 @@ module Zena
333
342
  # reset saved scope
334
343
  @context[:saved_template] = nil
335
344
  @blocks = opts[:cell].blocks
336
- cell_code = expand_if(var, node.move_to(var, [klass]))
345
+
346
+ cell_code = expand_if(var, node.move_to(var, [klass]))
347
+ unless @params[:split_hours]
348
+ markup = opts[:cell].markup
349
+ markup.tag = 'td'
350
+
351
+ markup.params[:class] ||= '#{day_class}'
352
+ markup.compile_params(self)
353
+ markup.done = false
354
+ cell_code = markup.wrap(cell_code)
355
+ end
356
+
337
357
  @context[:saved_template] = saved_template
338
358
  @blocks = bak
339
359
  @markup = markup
@@ -360,13 +380,13 @@ module Zena
360
380
  hour_var = get_var_name('calendar', 'hour')
361
381
 
362
382
  week_code = "<% #{week_var}.step(#{week_var}+6,1) do |#{day_var}| %>
363
- <td<%= cal_class(#{day_var},#{local_ref}, #{tz_var}) %>>#{opts[:cell_prefix_code]}<% #{hours.inspect}.each do |#{hour_var}|; #{cell_date} = #{day_var}.to_time.advance(:hours => #{hour_var}); #{var} = #{events_hash}[#{cell_date}).strftime_tz('%Y-%m-%d %H',#{tz_var})] %>#{cell_code}<% end %>#{opts[:cell_postfix_code]}</td>
383
+ <td class='<%= cal_class(#{day_var},#{local_ref},#{tz_var}) %>'><% #{hours.inspect}.each do |#{hour_var}|; #{cell_date} = #{day_var}.to_time.advance(:hours => #{hour_var}); #{var} = #{events_hash}[#{cell_date}).strftime_tz('%Y-%m-%d %H',#{tz_var})] %>#{cell_code}<% end %></td>
364
384
  <% end %>"
365
385
  (@context[:vars] ||= []) << "hour"
366
386
  else
367
387
  hours = nil
368
388
  week_code = "<% #{week_var}.step(#{week_var}+6,1) do |#{day_var}| %>
369
- <td<%= cal_class(#{day_var},#{local_ref}, #{tz_var}) %>><% #{cell_date} = #{day_var}.to_time; #{var} = #{events_hash}[#{cell_date}.strftime_tz('%Y-%m-%d 00',#{tz_var})] %>#{opts[:cell_prefix_code]}#{cell_code}#{opts[:cell_postfix_code]}</td>
389
+ <% #{cell_date} = #{day_var}.to_time; #{var} = #{events_hash}[#{cell_date}.strftime_tz('%Y-%m-%d 00',#{tz_var})]; #{day_class} = cal_class(#{day_var},#{local_ref},#{tz_var},#{var}) %>#{cell_code}
370
390
  <% end %>"
371
391
  end
372
392
 
@@ -10,7 +10,7 @@ module Zena::Use::Conditional
10
10
  return parser_error("Cannot scope class in list (use each before filtering).") if node.list_context?
11
11
  # capital letter ==> class conditional
12
12
  if klass = VirtualClass[class_name]
13
- if klass.kpath =~ %r{^#{node.klass.kpath}} || @context[:saved_template]
13
+ if node.klass.kpath =~ %r{^#{klass.kpath}} || klass.kpath =~ %r{^#{node.klass.kpath}} || @context[:saved_template]
14
14
  # Saved templates can be rendered with anything...
15
15
  # FIXME: Make sure saved templates from 'block' start with the proper node type ?
16
16
  cond = "#{node}.kpath_match?('#{klass.kpath}')"
@@ -21,7 +21,7 @@ module Zena::Use::Conditional
21
21
  new_node = node.move_to(node.name, klass)
22
22
  end
23
23
  elsif role = Node.get_role(class_name)
24
- if node.klass.kpath =~ %r{^#{role.kpath}} || @context[:saved_template]
24
+ if node.klass.kpath =~ %r{^#{role.kpath}} || role.kpath =~ %r{^#{node.klass.kpath}} || @context[:saved_template]
25
25
  # Saved templates can be rendered with anything...
26
26
  # FIXME: Make sure saved templates from 'block' start with the proper node type ?
27
27
  cond = "#{node}.has_role?(#{role.id})"
@@ -189,16 +189,29 @@ module Zena
189
189
  var = var.to_s
190
190
  begin
191
191
  typed_string = ::RubyLess.translate(self, code)
192
- name = get_var_name('set_var', var)
193
- out "<% #{name} = #{typed_string} %>"
194
- var_setting = {}
195
- set_context_var('set_var', var, RubyLess::TypedString.new(name, typed_string.opts), var_setting)
196
- # Leak into following siblings
197
- self.pass(var_setting)
198
- # Set inside
199
- @context.merge!(var_setting)
192
+
193
+ # Do we have this variable already ?
194
+ if up_var = get_context_var('set_var', var)
195
+ if up_var.klass != typed_string.klass
196
+ return parser_error("Type mismatch for var #{var}=#{code}: #{typed_string.klass} != #{up_var.klass}")
197
+ end
198
+
199
+ if typed_string.could_be_nil?
200
+ if !up_var.could_be_nil?
201
+ out "<% #{up_var} = #{typed_string} || #{up_var} %>"
202
+ else
203
+ out "<% #{up_var} = #{typed_string} %>"
204
+ end
205
+ else
206
+ out "<% #{up_var} = #{typed_string} %>"
207
+ end
208
+ else
209
+ name = get_var_name('set_var', var)
210
+ out "<% #{name} = #{typed_string} %>"
211
+ set_context_var('set_var', var, RubyLess::TypedString.new(name, typed_string.opts))
212
+ end
200
213
  rescue RubyLess::NoMethodError => err
201
- parser_error(err.message, code)
214
+ out parser_error(err.message, "set #{var}=#{code}")
202
215
  end
203
216
  end
204
217
  expand_with
@@ -255,6 +268,14 @@ module Zena
255
268
  def r_each_group
256
269
  r_each
257
270
  end
271
+
272
+ def r_master_template
273
+ if template = @context[:master_template]
274
+ expand_if("#{var} = secure(Node) { Node.find_by_zip(#{template.zip}) }", node.move_to(var, template.vclass))
275
+ else
276
+ out ''
277
+ end
278
+ end
258
279
  end # ZafuMethods
259
280
  end # Context
260
281
  end # Use
@@ -134,9 +134,9 @@ module Zena
134
134
  # fld = Zafu::Markup.new('input')
135
135
  # fld.params = (opts[:html] || {}).merge(:name => "node[#{name}]", :id => opts[:id], :type => 'text', :value => value)
136
136
  if opts[:size]
137
- fld = "<input id='#{opts[:id]}' name='node[#{name}]' type='text' size='#{opts[:size]}' value='#{value}' class='#{opts[:class]}'/>"
137
+ fld = "<input id='#{opts[:id]}' name='#{name}' type='text' size='#{opts[:size]}' value='#{value}' class='#{opts[:class]}'/>"
138
138
  else
139
- fld = "<input id='#{opts[:id]}' name='node[#{name}]' type='text' value='#{value}' class='#{opts[:class]}'/>"
139
+ fld = "<input id='#{opts[:id]}' name='#{name}' type='text' value='#{value}' class='#{opts[:class]}'/>"
140
140
  end
141
141
 
142
142
  js_data << %Q{Calendar.setup({
@@ -153,6 +153,10 @@ module Zena
153
153
  EOL
154
154
  end
155
155
  end
156
+
157
+ module ModelMethods
158
+ include Common
159
+ end
156
160
 
157
161
  module ViewMethods
158
162
  include Common
@@ -306,6 +310,32 @@ module Zena
306
310
  rescue TZInfo::AmbiguousTime
307
311
  0
308
312
  end
313
+
314
+ def advance_tz(opts, tz = nil)
315
+ if tz.blank?
316
+ tz = visitor.tz
317
+ elsif tz.kind_of?(String)
318
+ tz = TZInfo::Timezone.get(tz)
319
+ end
320
+ tz.local_to_utc(tz.utc_to_local(self).advance(opts))
321
+ rescue TZInfo::InvalidTimezoneIdentifier
322
+ self
323
+ rescue TZInfo::AmbiguousTime
324
+ self
325
+ end
326
+
327
+ def wday_tz(tz = nil)
328
+ if tz.blank?
329
+ tz = visitor.tz
330
+ elsif tz.kind_of?(String)
331
+ tz = TZInfo::Timezone.get(tz)
332
+ end
333
+ tz.utc_to_local(self).wday
334
+ rescue TZInfo::InvalidTimezoneIdentifier
335
+ 0
336
+ rescue TZInfo::AmbiguousTime
337
+ 0
338
+ end
309
339
 
310
340
  def to_date_tz(tz = nil)
311
341
  if tz.blank?
@@ -330,11 +360,17 @@ module Zena
330
360
  :days => Number,
331
361
  :hours => Number,
332
362
  :minutes => Number,
333
- :seconds => Number}] => Time
363
+ :seconds => Number}] => {:class => Time, :pre_processor => true, :method => 'advance_tz'}
364
+
334
365
  safe_method_for Time, :to_i => {:class => Number, :pre_processor => true}
335
366
  safe_method_for Time, :year => {:class => Number, :pre_processor => true, :method => 'year_tz'}
336
367
  safe_method_for Time, [:year, String] => {:class => Number, :pre_processor => true, :method => 'year_tz'}
337
368
  safe_method_for Time, [:year, TZInfo::Timezone] => {:class => Number, :pre_processor => true, :method => 'year_tz'}
369
+
370
+ safe_method_for Time, :wday => {:class => Number, :pre_processor => true, :method => 'wday_tz'}
371
+ safe_method_for Time, [:wday, String] => {:class => Number, :pre_processor => true, :method => 'wday_tz'}
372
+ safe_method_for Time, [:wday, TZInfo::Timezone] => {:class => Number, :pre_processor => true, :method => 'wday_tz'}
373
+
338
374
  safe_method_for Time, [:strftime, String] => {:class => String, :pre_processor => true, :method => 'strftime_tz'}
339
375
  safe_method_for Time, [:strftime, String, String] => {:class => String, :pre_processor => true, :method => 'strftime_tz'}
340
376
  safe_method_for Time, [:strftime, String, TZInfo::Timezone] => {:class => String, :pre_processor => true, :method => 'strftime_tz'}
@@ -4,11 +4,10 @@ module Zena
4
4
  module Common
5
5
  def icon_finder
6
6
  if rel = RelationProxy.find_by_role('icon')
7
- finder = 'icon or image'
7
+ "icon or image group by id,l_id order by l_id desc, position asc"
8
8
  else
9
- finder = 'image'
9
+ "image order by position asc"
10
10
  end
11
- "#{finder} group by id,l_id order by l_id desc, position asc"
12
11
  end
13
12
  end # Common
14
13
 
@@ -442,7 +441,7 @@ module Zena
442
441
  node = node(Node) || '@node'
443
442
  return nil unless attribute = get_attribute_or_eval
444
443
 
445
- hash_arguments = extract_from_params(:code, :host, :line_numbers, :theme) || []
444
+ hash_arguments = extract_from_params(:code, :host, :line_numbers, :theme, :target) || []
446
445
 
447
446
  hash_arguments.insert(0, ":node => #{node}")
448
447
 
@@ -489,6 +488,7 @@ module Zena
489
488
  end
490
489
 
491
490
  def extract_label(res, attribute)
491
+ attribute ||= @params[:param]
492
492
  if (label = param(:label) || param(:tlabel)) && attribute
493
493
  case label
494
494
  when 'true'
@@ -602,7 +602,7 @@ module Zena
602
602
 
603
603
  params = {}
604
604
  @params.each do |k,v|
605
- next if [:attr, :eval, :text, :t, :update].include?(k)
605
+ next if [:attr, :eval, :text, :t].include?(k)
606
606
  v = RubyLess.translate_string(self, v)
607
607
  if v.literal
608
608
  params[k] = CGI.escape(v.literal)
@@ -611,21 +611,8 @@ module Zena
611
611
  end
612
612
  end
613
613
 
614
- if upd = @params[:update]
615
- js = ""
616
- with_context(:node => node(Node)) do
617
- href = make_href(upd)
618
- name = get_var_name('add_document', 'update')
619
-
620
- txt = "%Q{#{name}\#{#{node}.zip} = function() {new Ajax.Request(\"\#{#{href}}\", {asynchronous:true, evalScripts:true, method:\"get\"})}}"
621
- js = "<% js_data << #{txt} %>"
622
- # Evaluated before the add_document page is opened.
623
- params[:js] = "<%= CGI.escape(\"Zena.t().#{name}\#{#{node}.zip}();\") %>"
624
- end
625
- end
626
-
627
614
  res = node_action_link('add_doc', "<%= #{node}.zip %>", :text => text_for_link(''), :params => params)
628
- "<% if #{node}.can_write? %>#{js}#{wrap(res)}<% end %>"
615
+ "<% if #{node}.can_write? %>#{wrap(res)}<% end %>"
629
616
  end
630
617
 
631
618
  # Find icon through a relation named 'icon' or use first image child
@@ -123,7 +123,8 @@ module Zena
123
123
 
124
124
  def make_input(form_helper, name, type, textarea = false)
125
125
  if type == Time
126
- "<%= date_box(#{node}, :#{name}) %>"
126
+ code = RubyLess.translate(self, "this.#{name}")
127
+ "<%= date_box(#{node}, 'node[#{name}]', :value => #{code}) %>"
127
128
  elsif textarea
128
129
  "<%= #{form_helper}.text_area :#{name}, :id => '#{node.dom_prefix}_#{name}' %>"
129
130
  else
@@ -223,7 +224,7 @@ module Zena
223
224
 
224
225
  opts[:form_cancel] = %Q{
225
226
  <% if #{node}.new_record? %>
226
- #{cancel_pre}<a href='javascript:void(0)' onclick='[\"<%= params[:dom_id] %>_add\", \"<%= params[:dom_id] %>\"].each(Element.toggle);return false;'>#{cancel_text}</a>#{cancel_post}
227
+ #{cancel_pre}<a href='javascript:void(0)' onclick='[\"<%= params[:dom_id] %>_add\", \"<%= params[:dom_id] %>_0\"].each(Element.toggle);return false;'>#{cancel_text}</a>#{cancel_post}
227
228
  <% else %>
228
229
  #{cancel_pre}<%= link_to_remote(#{cancel_text_ruby}, :url => #{node.form_name}_path(#{node}.zip) + \"/zafu?t_url=#{CGI.escape(template_url)}&dom_id=\#{params[:dom_id]}#{@context[:has_link_id] ? "&link_id=\#{#{node}.link_id}" : ''}\", :method => :get) %>#{cancel_post}
229
230
  <% end %>
@@ -266,7 +267,8 @@ module Zena
266
267
  # Ajax
267
268
  hidden_fields['link_id'] = "<%= #{node}.link_id %>" if @context[:has_link_id] && node.will_be?(Node)
268
269
 
269
- if upd = @params[:update]
270
+ f = @method == 'form_tag' ? ancestor('form') : self
271
+ if upd = f && f.params[:update]
270
272
  if target = find_target(upd)
271
273
  hidden_fields['u_url'] = target.template_url
272
274
  hidden_fields['udom_id'] = upd # target.node.dom_prefix ? (but target.node is not set yet...)
@@ -453,24 +455,37 @@ module Zena
453
455
  selected = "#{node}.prop[#{attribute.inspect}].to_s"
454
456
  end
455
457
  end
456
-
457
- html_id = html_attributes[:id] ? " id='#{html_attributes[:id]}'" : ''
458
+
458
459
  if @context[:in_filter] || @params[:param]
459
- select_tag = "<select#{html_id} name='#{attribute}'>"
460
+ html_attributes[:name] = attribute
460
461
  else
461
- select_tag = "<select#{html_id} name='#{node.form_name}[#{attribute}]'>"
462
+ html_attributes[:name] = "#{node.form_name}[#{attribute}]"
462
463
  end
464
+ html_attributes.delete(:value)
465
+ select_tag = Zafu::Markup.new('select', html_attributes)
463
466
 
464
467
  res = if klass = @params[:root_class]
465
468
  class_opts = ''
466
469
  class_opts << ", :without => #{@params[:without].inspect}" if @params[:without]
470
+ tprefix = @params[:tprefix] || @params[:name] || @params[:param]
467
471
  # do not use 'selected' if the node is not new
468
- "#{select_tag}<%= options_for_select(Node.classes_for_form(:class => #{klass.inspect}#{class_opts}, :class_attr => #{(@params[:attr] || 'name').inspect}), (#{node}.new_record? ? #{selected} : #{node}.klass)) %></select>"
472
+ options_list = Node.classes_for_form(:class => klass, :without => @params[:without], :class_attr => @params[:attr] || 'name')
473
+
474
+ if !tprefix.blank? && tprefix != 'false'
475
+ options_list.map! do |e|
476
+ if e[0] =~ /^([^a-zA-Z]*)(.*)$/
477
+ [$1 + trans("#{tprefix}_#{$2}"), e[1]]
478
+ else
479
+ e
480
+ end
481
+ end
482
+ end
483
+ select_tag.wrap "<%= options_for_select(#{options_list.inspect}, (#{node}.new_record? ? #{selected} : #{node}.klass)) %>"
469
484
  elsif @params[:type] == 'time_zone'
470
485
  # <r:select name='d_tz' type='time_zone'/>
471
- "#{select_tag}<%= options_for_select(TZInfo::Timezone.all_identifiers, #{selected}) %></select>"
486
+ select_tag.wrap "<%= options_for_select(TZInfo::Timezone.all_identifiers, #{selected}) %>"
472
487
  elsif options_list = get_options_for_select
473
- "#{select_tag}<%= options_for_select(#{options_list}, #{selected}) %></select>"
488
+ select_tag.wrap "<%= options_for_select(#{options_list}, #{selected}) %>"
474
489
  else
475
490
  parser_error("missing 'nodes', 'root_class' or 'values'")
476
491
  end
@@ -481,6 +496,7 @@ module Zena
481
496
 
482
497
  def r_input(skip_col = false)
483
498
  html_attributes, attribute = get_input_params()
499
+
484
500
  erb_attr = html_attributes.delete(:erb_attr)
485
501
  # TODO: get attribute type from get_input_params
486
502
 
@@ -489,7 +505,7 @@ module Zena
489
505
  out "<% if #{node}.ptype == :string -%>"
490
506
  out r_textarea
491
507
  out "<% elsif #{node}.ptype == :datetime -%>"
492
- res = "<%= date_box(#{node(Node)}, #{node}.name, :value => #{node(Node)}.prop[#{node}.name]) %>"
508
+ res = "<%= date_box(#{node(Node)}, %Q{node[\#{#{node}.name}]}, :value => #{node(Node)}.prop[#{node}.name]) %>"
493
509
  out extract_label(res, erb_attr)
494
510
  out "<% else -%>"
495
511
  out r_input(true)
@@ -503,8 +519,15 @@ module Zena
503
519
  r_select
504
520
  when 'date_box', 'date'
505
521
  return parser_error("date_box without name") unless attribute
506
- if value = @params[:value]
507
- code = ::RubyLess.translate(self, value)
522
+ if code = @params[:value]
523
+ code = ::RubyLess.translate(self, code)
524
+ elsif code = html_attributes[:value]
525
+ if code =~ /\A<%= .*?\((.+)\)\s*%>/
526
+ # remove <%= %>
527
+ code = $1
528
+ else
529
+ code = code.inspect
530
+ end
508
531
  else
509
532
  code = ::RubyLess.translate(self, "this.#{attribute}")
510
533
  end
@@ -514,7 +537,7 @@ module Zena
514
537
  html_params << ":#{key} => #{@params[key].inspect}" if @params[key]
515
538
  end
516
539
  html_params << ":id=>\"#{node.dom_id(:erb => false)}_#{attribute}\"" if node.dom_prefix
517
- "<%= date_box(#{node}, #{attribute.inspect}, :value => #{value}, #{html_params.join(', ')}) %>"
540
+ "<%= date_box(#{node}, #{html_attributes[:name].inspect}, :value => #{value}, #{html_params.join(', ')}) %>"
518
541
  when 'id'
519
542
  return parser_error("select id without name") unless attribute
520
543
  name = "#{attribute}_id" unless attribute[-3..-1] == '_id'
@@ -532,7 +555,7 @@ module Zena
532
555
  @markup.done = false
533
556
  wrap('')
534
557
  else
535
- # 'text', 'hidden', ...
558
+ # 'text', 'hidden', 'checkbox', ...
536
559
  return parser_error('Missing name.') unless attribute || html_attributes[:name]
537
560
  @markup.tag = 'input'
538
561
  @markup.set_param(:type, @params[:type] || 'text')
@@ -601,21 +624,6 @@ module Zena
601
624
 
602
625
  alias r_radio r_checkbox
603
626
 
604
- # transform a 'show' tag into an input field.
605
- #def make_input(params = @params)
606
- # input, attribute = get_input_params(params)
607
- # return parser_error("missing 'name'") unless attribute
608
- # return '' if attribute == 'parent_id' # set with 'r_form'
609
- # return '' if ['url','path'].include?(attribute) # cannot be set with a form
610
- # if params[:date]
611
- # input_id = @context[:dom_prefix] ? ", :id=>\"#{dom_id}_#{attribute}\"" : ''
612
- # return "<%= date_box(#{node}, #{params[:date].inspect}#{input_id}) %>"
613
- # end
614
- # input_id = node.dom_prefix ? " id='#{node.dom_prefix}_#{attribute}'" : ''
615
- # "<input type='#{params[:type] || 'text'}'#{input_id} name='#{input[:name]}' value='#{input[:value]}'/>"
616
- #end
617
- #
618
-
619
627
  # Parse params to extract everything that is relevant to building input fields.
620
628
  # TODO: refactor and pass the @markup so that attributes are added directly
621
629
  # TODO: get attribute type in get_input_params (safe_method_type)
@@ -646,26 +654,26 @@ module Zena
646
654
  end
647
655
  end
648
656
 
657
+ if value = params[:value]
658
+ # On refactor, use append_markup_attr(markup, key, value)
659
+ value = RubyLess.translate_string(self, value)
660
+
661
+ if value.literal
662
+ res[:value] = form_quote(value.literal.to_s)
663
+ else
664
+ res[:value] = "<%= fquote(#{value}) %>"
665
+ end
666
+ elsif params[:param]
667
+ res[:value] = "<%= fquote(#{sub_attr_ruby}) %>"
668
+ end
669
+
649
670
  if sub_attr
650
- type = node.klass.safe_method_type([attribute])
671
+ type = node.klass.safe_method_type([attribute], node)
651
672
  if sub_attr_ruby = RubyLess.translate(self, %Q{this.#{attribute}[#{sub_attr.inspect}]})
652
- res[:value] = "<%= fquote #{sub_attr_ruby} %>"
653
- end
654
- else
655
- if value = params[:value]
656
- # On refactor, use append_markup_attr(markup, key, value)
657
- value = RubyLess.translate_string(self, value)
658
-
659
- if value.literal
660
- res[:value] = form_quote(value.literal.to_s)
661
- else
662
- res[:value] = "<%= fquote #{value} %>"
663
- end
664
- elsif params[:param]
665
- res[:value] = "<%= fquote #{sub_attr_ruby} %>"
666
- elsif attribute && type = node.klass.safe_method_type([attribute])
667
- res[:value] = "<%= fquote #{node}.#{type[:method]} %>"
673
+ res[:value] ||= "<%= fquote(#{sub_attr_ruby}) %>"
668
674
  end
675
+ elsif attribute && type = node.klass.safe_method_type([attribute], node)
676
+ res[:value] ||= "<%= fquote(#{node}.#{type[:method]}) %>"
669
677
  end
670
678
 
671
679
  if sub_attr && params[:type] == 'checkbox' && !params[:value]
@@ -673,29 +681,16 @@ module Zena
673
681
  res[:value] = sub_attr
674
682
  end
675
683
 
676
- #if @context[:in_add]
677
- # res[:value] = (params[:value] || params[:set_value]) ? ["'#{ helper.fquote(params[:value])}'"] : ["''"]
678
- #elsif @context[:in_filter]
679
- # res[:value] = attribute ? ["'<%= fquote params[#{attribute.to_sym.inspect}] %>'"] : ["''"]
680
- #elsif params[:value]
681
- # res[:value] = ["'#{ helper.fquote(params[:value])}'"]
682
- #else
683
- # if nattr != 'nil'
684
- # res[:value] = ["'<%= fquote #{nattr} %>'"]
685
- # else
686
- # res[:value] = ["''"]
687
- # end
688
- #end
689
684
  elsif node.will_be?(Column)
690
685
  res[:erb_attr] = "<%= #{node}.name %>"
691
686
  res[:name] = "node[<%= #{node}.name %>]"
692
687
  res[:value] = "<%= fquote #{node(Node)}.prop[#{node}.name] %>"
693
688
  end
694
-
695
- if node.dom_prefix && !params[:param]
696
- res[:id] = params[:id] || "#{@context[:form_prefix]}_#{attribute}"
697
- else
698
- res[:id] = params[:id] if params[:id]
689
+
690
+ if params[:id]
691
+ res[:id] = params[:id]
692
+ elsif base = @context[:form_prefix]
693
+ res[:id] = "#{base}_#{attribute}"
699
694
  end
700
695
 
701
696
  if params[:type] == 'checkbox' && sub_attr_ruby
@@ -707,11 +702,16 @@ module Zena
707
702
  end
708
703
 
709
704
  params.each do |k, v|
710
- next unless [:size, :style, :class].include?(k)
711
- res[k] = params[k]
705
+ if [:size, :style, :class].include?(k) || k.to_s =~ /^data-/
706
+ res[k] = params[k]
707
+ end
708
+ end
709
+
710
+ if sub_attr
711
+ return [res, "#{attribute}_#{sub_attr}"]
712
+ else
713
+ return [res, attribute]
712
714
  end
713
-
714
- return [res, attribute]
715
715
  end
716
716
 
717
717
  # TODO: add parent_id into the form !
@@ -801,10 +801,15 @@ module Zena
801
801
  elsif show = @params[:tshow]
802
802
  show_values = translate_list(show)
803
803
  else
804
- tprefix = @params[:tprefix] || @params[:name]
804
+ tprefix = @params[:tprefix] || @params[:name] || @params[:param]
805
+ if tprefix == 'false'
806
+ tprefix = ''
807
+ else
808
+ tprefix = "#{tprefix}_"
809
+ end
805
810
  show_values = options_list.map do |v|
806
- t = trans("#{tprefix}_#{v}")
807
- if t == "#{tprefix}_"
811
+ t = trans("#{tprefix}#{v}")
812
+ if t == tprefix
808
813
  ''
809
814
  else
810
815
  t
@@ -820,16 +825,32 @@ module Zena
820
825
  options_list.inspect
821
826
  elsif code = @params[:eval]
822
827
  ruby = ::RubyLess.translate(self, code)
823
- if !ruby.klass.kind_of?(Array)
824
- return parser_error("invalid eval: should return an Array (found #{ruby.klass})")
825
- end
828
+ if ruby.klass.kind_of?(Array)
829
+ if ruby.klass.first <= String
830
+ ruby
831
+ else
832
+ return parser_error("cannot extract values from eval (not a String list: [#{ruby.klass.first}])")
833
+ end
834
+ elsif ruby.klass <= String
835
+ if ruby.could_be_nil?
836
+ ruby = "(#{ruby} || '')"
837
+ else
838
+ ruby = "(#{ruby})"
839
+ end
840
+
841
+ dict = get_context_var('set_var', 'dictionary')
826
842
 
827
- if ruby.klass.first <= String
828
- # ok
829
- ruby
843
+ if dict && dict.klass <= ::Zena::Use::I18n::TranslationDict
844
+ trans = "#{dict}.get"
845
+ else
846
+ trans = "trans"
847
+ end
848
+
849
+ ruby = "#{ruby}.split(',').map(&:strip).map {|e| [#{trans}(e), e]}"
830
850
  else
831
- return parser_error("cannot extract values from eval (not a String list: [#{ruby.klass.first}])")
851
+ return parser_error("invalid eval: should return an Array or String (found #{ruby.klass})")
832
852
  end
853
+
833
854
  end
834
855
  end
835
856