zena 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/History.txt +29 -1
  2. data/Rakefile +0 -1
  3. data/app/controllers/documents_controller.rb +1 -1
  4. data/app/controllers/nodes_controller.rb +34 -8
  5. data/app/controllers/sites_controller.rb +8 -1
  6. data/app/controllers/user_sessions_controller.rb +13 -3
  7. data/app/models/acl.rb +16 -0
  8. data/app/models/document.rb +33 -14
  9. data/app/models/idx_nodes_integer.rb +5 -0
  10. data/app/models/image.rb +16 -4
  11. data/app/models/node.rb +16 -3
  12. data/app/models/relation_proxy.rb +3 -3
  13. data/app/models/site.rb +11 -1
  14. data/app/models/string_hash.rb +1 -1
  15. data/app/models/template.rb +1 -1
  16. data/app/models/user.rb +6 -1
  17. data/app/models/virtual_class.rb +36 -1
  18. data/app/views/acls/_form.rhtml +5 -1
  19. data/app/views/acls/_li.rhtml +1 -1
  20. data/app/views/templates/document_create_tabs/_file.rhtml +1 -0
  21. data/app/views/templates/document_create_tabs/_template.rhtml +1 -1
  22. data/app/views/users/_form.rhtml +1 -0
  23. data/app/views/virtual_classes/_form.erb +8 -7
  24. data/bricks/acls/lib/bricks/acls.rb +43 -15
  25. data/bricks/acls/zena/migrate/20130313110443_add_create_kpath_to_acl.rb +13 -0
  26. data/bricks/acls/zena/migrate/20130429073432_fix_create_kpath_default.rb +8 -0
  27. data/bricks/acls/zena/test/integration/acl_integration_test.rb +53 -1
  28. data/bricks/acls/zena/test/sites/erebus/acls.yml +21 -0
  29. data/bricks/acls/zena/test/unit/acl_test.rb +35 -2
  30. data/bricks/math/lib/bricks/math.rb +1 -1
  31. data/bricks/sphinx/zena/tasks.rb +1 -1
  32. data/bricks/spreadsheet/lib/bricks/spreadsheet.rb +1 -1
  33. data/bricks/worker/zena/worker +25 -0
  34. data/config/environment.rb +1 -1
  35. data/config/environments/production.rb +1 -1
  36. data/config/gems.yml +6 -5
  37. data/lib/bricks/requirements_validation.rb +1 -1
  38. data/lib/log_recorder/lib/log_recorder.rb +1 -1
  39. data/lib/tasks/zena.rake +10 -2
  40. data/lib/zena.rb +4 -3
  41. data/lib/zena/app.rb +1 -0
  42. data/lib/zena/deploy/httpd.rhtml +2 -2
  43. data/lib/zena/deploy/template.rb +15 -5
  44. data/lib/zena/info.rb +1 -1
  45. data/lib/zena/parser/zazen_rules.rb +9 -2
  46. data/lib/zena/remote/connection.rb +2 -2
  47. data/lib/zena/remote/interface.rb +8 -2
  48. data/lib/zena/remote/node.rb +1 -1
  49. data/lib/zena/routes.rb +2 -1
  50. data/lib/zena/use/action.rb +8 -2
  51. data/lib/zena/use/ajax.rb +31 -20
  52. data/lib/zena/use/calendar.rb +2 -0
  53. data/lib/zena/use/conditional.rb +15 -14
  54. data/lib/zena/use/dates.rb +5 -2
  55. data/lib/zena/use/display.rb +3 -2
  56. data/lib/zena/use/forms.rb +36 -9
  57. data/lib/zena/use/i18n.rb +8 -2
  58. data/lib/zena/use/image_builder.rb +7 -0
  59. data/lib/zena/use/query_node.rb +24 -8
  60. data/lib/zena/use/relations.rb +2 -6
  61. data/lib/zena/use/rendering.rb +10 -6
  62. data/lib/zena/use/upload.rb +6 -4
  63. data/lib/zena/use/urls.rb +13 -5
  64. data/lib/zena/use/zafu_safe_definitions.rb +1 -1
  65. data/public/javascripts/grid.js +11 -2
  66. data/public/javascripts/upload-progress.js +5 -3
  67. data/public/javascripts/zena.js +6 -2
  68. data/public/stylesheets/upload-progress.css +1 -0
  69. data/test/fixtures/files/TestNode.zafu +2 -2
  70. data/test/fixtures/files/translations_fr.yml +2 -1
  71. data/test/functional/acls_controller_test.rb +6 -0
  72. data/test/functional/nodes_controller_test.rb +1 -1
  73. data/test/functional/sites_controller_test.rb +19 -0
  74. data/test/integration/navigation_test.rb +7 -0
  75. data/test/integration/query_node/filters.yml +10 -0
  76. data/test/integration/zafu_compiler/action.yml +8 -4
  77. data/test/integration/zafu_compiler/ajax.yml +4 -4
  78. data/test/integration/zafu_compiler/calendar.yml +8 -15
  79. data/test/integration/zafu_compiler/context.yml +1 -1
  80. data/test/integration/zafu_compiler/dates.yml +5 -1
  81. data/test/integration/zafu_compiler/display.yml +1 -2
  82. data/test/integration/zafu_compiler/forms.yml +37 -10
  83. data/test/integration/zafu_compiler/query.yml +5 -5
  84. data/test/integration/zafu_compiler/relations.yml +8 -8
  85. data/test/integration/zafu_compiler/safe_definitions.yml +7 -2
  86. data/test/integration/zafu_compiler/urls.yml +24 -3
  87. data/test/integration/zafu_compiler/zazen.yml +9 -1
  88. data/test/selenium/Destroy/destroy1.rsel +2 -1
  89. data/test/selenium/Destroy/destroy2.rsel +17 -0
  90. data/test/unit/document_test.rb +17 -4
  91. data/test/unit/relation_proxy_test.rb +19 -8
  92. data/test/unit/string_hash_test.rb +1 -1
  93. data/test/unit/template_test.rb +3 -3
  94. data/test/unit/virtual_class_test.rb +77 -0
  95. data/test/unit/zena/use/urls_test.rb +9 -1
  96. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails_config.rb +1 -1
  97. data/zena.gemspec +60 -53
  98. metadata +145 -125
@@ -289,6 +289,8 @@ module Zena
289
289
  if !c_date_code.klass <= Time
290
290
  return parser_error("Invalid 'date' parameter. Should be a Time (found #{current_date.klass})")
291
291
  end
292
+ elsif dvar = get_context_var('set_var', 'date')
293
+ c_date_code = dvar
292
294
  else
293
295
  # Get current date from url for the current time_zone
294
296
  c_date_code = RubyLess.translate(self, 'date(tz)')
@@ -10,27 +10,28 @@ 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 node.klass.kpath =~ %r{^#{klass.kpath}} || klass.kpath =~ %r{^#{node.klass.kpath}} || @context[:saved_template]
13
+ # FIXME: This does not always work... (block inside block resets class scoping...). We should always render blocks with 'Node' class...
14
+ #if node.klass.kpath =~ %r{^#{klass.kpath}} || klass.kpath =~ %r{^#{node.klass.kpath}} || @context[:saved_template]
14
15
  # Saved templates can be rendered with anything...
15
16
  # FIXME: Make sure saved templates from 'block' start with the proper node type ?
16
17
  cond = "#{node}.kpath_match?('#{klass.kpath}')"
17
18
  new_node = node.move_to(node.name, klass)
18
- else
19
- # render nothing: incompatible classes
20
- cond = 'false'
21
- new_node = node.move_to(node.name, klass)
22
- end
19
+ #else
20
+ # # render nothing: incompatible classes
21
+ # cond = 'false'
22
+ # new_node = node.move_to(node.name, klass)
23
+ #end
23
24
  elsif role = Node.get_role(class_name)
24
- if node.klass.kpath =~ %r{^#{role.kpath}} || role.kpath =~ %r{^#{node.klass.kpath}} || @context[:saved_template]
25
- # Saved templates can be rendered with anything...
26
- # FIXME: Make sure saved templates from 'block' start with the proper node type ?
25
+ #if node.klass.kpath =~ %r{^#{role.kpath}} || role.kpath =~ %r{^#{node.klass.kpath}} || @context[:saved_template]
26
+ # # Saved templates can be rendered with anything...
27
+ # # FIXME: Make sure saved templates from 'block' start with the proper node type ?
27
28
  cond = "#{node}.has_role?(#{role.id})"
28
29
  new_node = node.move_to(node.name, node.klass)
29
- else
30
- # render nothing: incompatible classes
31
- cond = 'false'
32
- new_node = node.move_to(node.name, node.klass)
33
- end
30
+ #else
31
+ # # render nothing: incompatible classes
32
+ # cond = 'false'
33
+ # new_node = node.move_to(node.name, node.klass)
34
+ #end
34
35
  else
35
36
  return parser_error("Invalid role or class '#{class_name}'")
36
37
  end
@@ -138,11 +138,14 @@ module Zena
138
138
  else
139
139
  fld = "<input id='#{opts[:id]}' name='#{name}' type='text' value='#{value}' class='#{opts[:class]}'/>"
140
140
  end
141
-
141
+
142
+ if onUpdate = opts[:onUpdate]
143
+ onUpdate = "onUpdate : #{onUpdate},"
144
+ end
142
145
  js_data << %Q{Calendar.setup({
143
146
  inputField : "#{opts[:id]}", // id of the input field
144
147
  button : "#{opts[:button]}", // trigger for the calendar (button ID)
145
- singleClick : true,
148
+ singleClick : true,#{onUpdate}
146
149
  showsTime : #{showsTime},
147
150
  ifFormat : '#{dateFormat}'
148
151
  });}
@@ -453,12 +453,13 @@ module Zena
453
453
  end
454
454
 
455
455
  if signature
456
+ # TODO: Get 'notextile' param from rubyless.
456
457
  if node = node(Node)
457
458
  {
458
459
  :class => String,
459
460
  :method => 'zazen',
460
461
  :accept_nil => true,
461
- :html_safe => true,
462
+ :html_safe => true,
462
463
  :append_hash => {:node => ::RubyLess::TypedString.new(node.to_s, :class => node.klass)}
463
464
  }
464
465
  else
@@ -468,7 +469,7 @@ module Zena
468
469
  node = node(Node) || '@node'
469
470
  return nil unless attribute = get_attribute_or_eval
470
471
 
471
- hash_arguments = extract_from_params(:code, :host, :line_numbers, :theme, :target) || []
472
+ hash_arguments = extract_from_params(:code, :notextile, :host, :line_numbers, :theme, :target) || []
472
473
 
473
474
  hash_arguments.insert(0, ":node => #{node}")
474
475
 
@@ -48,9 +48,15 @@ module Zena
48
48
  name = "node[#{name}]"
49
49
  end
50
50
  res = []
51
- res << "<input type='hidden' name='#{name}' value=''/>"
51
+ if default = opts[:default]
52
+ default = fquote default.to_s
53
+ else
54
+ default = ''
55
+ end
56
+ res << "<input type='hidden' name='#{name}' value='#{default}'/>"
57
+ type = opts[:type] || 'checkbox'
52
58
  list.each_with_index do |value, i|
53
- res << ("<input type='checkbox' name='#{name}' value='#{value}'" +
59
+ res << ("<input type='#{type}' name='#{name}' value='#{value}'" +
54
60
  (selected.include?(value.to_s) ? " checked='checked'/> " : '/> ') +
55
61
  "<span>#{show[i]}</span>")
56
62
  end
@@ -337,7 +343,6 @@ module Zena
337
343
  elsif params[:focus]
338
344
  hidden_fields['done'] = "'$(\"#{erb_dom_id}_#{params[:focus]}\").focus();'"
339
345
  end
340
-
341
346
  else
342
347
  # ajax form, not in 'add'
343
348
  done = RubyLess.translate_string(self, @params[:done])
@@ -506,7 +511,10 @@ module Zena
506
511
  if !tprefix.blank? && tprefix != 'false'
507
512
  options_list.map! do |e|
508
513
  if e[0] =~ /^([^a-zA-Z]*)(.*)$/
509
- [$1 + trans("#{tprefix}_#{$2}"), e[1]]
514
+ name = "#{tprefix}_#{$2}"
515
+ t = trans(name)
516
+ t = $2 if t == name
517
+ [$1 + t, e[1]]
510
518
  else
511
519
  e
512
520
  end
@@ -565,10 +573,12 @@ module Zena
565
573
  end
566
574
  value = code # @context[:in_add] ? "''" : code
567
575
  html_params = [':size => 15']
568
- [:style, :class, :onclick, :size, :time].each do |key|
576
+ [:style, :class, :onclick, :size, :time, :id, :onUpdate].each do |key|
569
577
  html_params << ":#{key} => #{@params[key].inspect}" if @params[key]
570
578
  end
571
- html_params << ":id=>\"#{node.dom_id(:erb => false)}_#{attribute}\"" if node.dom_prefix
579
+ if !@params[:id] and node.dom_prefix
580
+ html_params << ":id=>\"#{node.dom_id(:erb => false)}_#{attribute}\""
581
+ end
572
582
  "<%= date_box(#{node}, #{html_attributes[:name].inspect}, :value => #{value}, #{html_params.join(', ')}) %>"
573
583
  when 'id'
574
584
  return parser_error("select id without name") unless attribute
@@ -619,9 +629,18 @@ module Zena
619
629
  opts << ":show => #{show_values.split(',').map(&:strip).inspect}"
620
630
  elsif show_values = @params[:tshow]
621
631
  opts << ":show => #{translate_list(show_values).inspect}"
632
+ else
633
+ opts << ":show => #{translate_list(values, @params[:tprefix] || name).inspect}"
622
634
  end
623
635
  meth = RubyLess.translate(self, "this.#{name}")
624
636
  opts << ":selected => #{meth}"
637
+ if default = @params[:default]
638
+ opts << ":default => #{default.inspect}"
639
+ end
640
+
641
+ if type = @params[:type]
642
+ opts << ":type => #{type.inspect}"
643
+ end
625
644
  attribute = name
626
645
  res = "<%= make_checkbox(#{node}, #{opts.join(', ')}) %>"
627
646
  else
@@ -654,7 +673,10 @@ module Zena
654
673
  extract_label(res, attribute)
655
674
  end
656
675
 
657
- alias r_radio r_checkbox
676
+ def r_radio
677
+ @params[:type] = 'radio'
678
+ r_checkbox
679
+ end
658
680
 
659
681
  # Parse params to extract everything that is relevant to building input fields.
660
682
  # TODO: refactor and pass the @markup so that attributes are added directly
@@ -823,8 +845,13 @@ module Zena
823
845
  set_attr = ::RubyLess.translate(self, @params[:attr] || 'id')
824
846
  show_attr = ::RubyLess.translate(self, @params[:show] || 'title')
825
847
  end
826
-
827
- options_list = "[['','']] + (#{nodes} || []).map{|r| [#{show_attr}, #{set_attr}.to_s]}"
848
+
849
+ if @params[:blank] != 'false'
850
+ options_list = "[['', '']] + "
851
+ else
852
+ options_list = ""
853
+ end
854
+ options_list = "#{options_list}(#{nodes} || []).map{|r| [#{show_attr}, #{set_attr}.to_s]}"
828
855
  elsif values = @params[:values]
829
856
  options_list = values.split(',').map(&:strip)
830
857
 
@@ -251,7 +251,7 @@ module Zena
251
251
  end
252
252
  else
253
253
  if params[:controller] == 'nodes'
254
- res << tag_in + "<a href='#{zen_path(@node, :lang => l)}'>#{l}</a>"
254
+ res << tag_in + "<a href='#{zen_path(@node, :lang => l)}'>#{l}</a>" + tag_out
255
255
  else
256
256
  res << tag_in + link_to(l, params.merge(:lang => l)) + tag_out
257
257
  end
@@ -384,9 +384,15 @@ module Zena
384
384
 
385
385
  # Translate a string representing a list of values separated with a comma ('dog,cat,house')
386
386
  # to a list of strings.
387
- def translate_list(str)
387
+ def translate_list(str, prefix = nil)
388
388
  if trad = trans(str, false)
389
389
  trad.split(',').map(&:strip)
390
+ elsif prefix
391
+ str.split(',').map(&:strip).map do |v|
392
+ k = "#{prefix}_#{v}"
393
+ d = trans(k)
394
+ d == k ? v : d
395
+ end
390
396
  else
391
397
  str.split(',').map(&:strip).map{|v| trans(v)}
392
398
  end
@@ -80,6 +80,7 @@ module Zena
80
80
 
81
81
  def initialize(h)
82
82
  params = {:height=>nil, :width=>nil, :path=>nil, :file=>nil, :actions=>[]}.merge(h)
83
+ node = params.delete(:node)
83
84
 
84
85
  params.each do |k,v|
85
86
  case k
@@ -105,6 +106,10 @@ module Zena
105
106
  if @img = build_image_from_file_or_path
106
107
  @width = @img.columns
107
108
  @height = @img.rows
109
+ if node && node.respond_to?(:fix_sizes)
110
+ # Fix property
111
+ node.fix_sizes(@width, @height)
112
+ end
108
113
  end
109
114
  end
110
115
  end
@@ -331,6 +336,8 @@ module Zena
331
336
  img
332
337
  end
333
338
  end
339
+ rescue
340
+ nil
334
341
  end
335
342
  end # ImageBuilder
336
343
  end # Use
@@ -286,12 +286,19 @@ module Zena
286
286
  "params[#{pagination_key.to_sym.inspect}]"
287
287
  end
288
288
 
289
+ def process_not_equal(left, right)
290
+ if (left == [:field, 'class'] || left == [:field, 'klass']) && (right[0] == :field || right[0] == :string)
291
+ process_equal(left, right, true)
292
+ else
293
+ process_op(:'<>', left, right)
294
+ end
295
+ end
296
+
289
297
  # Handle special case for 'class = ' and 'role = ' and 'foo.date ='
290
- def process_equal(left, right)
291
- if (left == [:field, 'class'] || left == [:field, 'klass']) &&
292
- (right[0] == :field || right[0] == :string)
298
+ def process_equal(left, right, is_not = nil)
299
+ if (left == [:field, 'class'] || left == [:field, 'klass']) && (right[0] == :field || right[0] == :string)
293
300
  if klass = Node.get_class(right.last)
294
- "#{field_or_attr('kpath')} = #{quote(klass.kpath)}"
301
+ "#{field_or_attr('kpath')} #{is_not ? '<>' : '='} #{quote(klass.kpath)}"
295
302
  else
296
303
  raise ::QueryBuilder::Error.new("Unknown class #{right.last.inspect}.")
297
304
  end
@@ -311,15 +318,15 @@ module Zena
311
318
  b = right
312
319
  process([:and, [:<=, b, a], [:<, a, [:+, b, [:interval, [:integer, '1'], 'day']]]])
313
320
  else
314
- super
321
+ process_op(:'=', left, right)
315
322
  end
316
323
  end
317
324
 
318
325
  # Handle special case for 'class like '
319
- def process_like(left, right)
320
- if left == [:field, 'class'] && right[0] == :field
326
+ def process_like(left, right, is_not = nil)
327
+ if (left == [:field, 'class'] || left == [:field, 'klass']) && right[0] == :field
321
328
  if klass = Node.get_class(right[1])
322
- "#{field_or_attr('kpath')} LIKE #{quote(klass.kpath + '%')}"
329
+ "#{field_or_attr('kpath')} #{is_not ? 'NOT ' : ''}LIKE #{quote(klass.kpath + '%')}"
323
330
  else
324
331
  raise QueryBuilder::QueryException.new("Unknown class #{right.last.inspect}.")
325
332
  end
@@ -327,6 +334,15 @@ module Zena
327
334
  process_op(:like, left, right)
328
335
  end
329
336
  end
337
+
338
+ # [:like, [:field, "class"], [:field, "Image"]]
339
+ def process_not(arg)
340
+ if (arg[1] == [:field, 'class'] || arg[1] == [:field, 'klass']) && arg[0] == :like
341
+ process_like(arg[1], arg[2], true)
342
+ else
343
+ super
344
+ end
345
+ end
330
346
 
331
347
  def resolve_scope_idx_fields(arg1, arg2)
332
348
  if arg1.first == :function
@@ -59,11 +59,7 @@ module Zena
59
59
 
60
60
  # Class path hierarchy. Example for (Post) : N, NN, NNP
61
61
  def split_kpath
62
- @split_kpath ||= begin
63
- klasses = []
64
- kpath.split(//).each_index { |i| klasses << kpath[0..i] }
65
- klasses
66
- end
62
+ @split_kpath ||= VirtualClass.split_kpath(kpath)
67
63
  end
68
64
  end
69
65
 
@@ -270,7 +266,7 @@ module Zena
270
266
  #if relation.record_count > 5
271
267
  # # FIXME: show message ?
272
268
  #end
273
- links = rel.records(:limit => 5, :order => "link_id DESC")
269
+ links = rel.records(:limit => 25, :order => "link_id DESC")
274
270
  res << [rel, links] if links
275
271
  end
276
272
  res
@@ -81,13 +81,16 @@ module Zena
81
81
  zafu_node('@node', Project)
82
82
 
83
83
  respond_to do |format|
84
- format.xml { render :nothing => true, :status => "404 Not Found" }
85
84
  format.all do
86
- not_found = "#{SITES_ROOT}/#{current_site.host}/public/#{prefix}/404.html"
87
- if File.exists?(not_found)
88
- render :text => File.read(not_found), :status => '404 Not Found'
85
+ if request.format == Mime::XML
86
+ render :nothing => true, :status => "404 Not Found"
89
87
  else
90
- render_and_cache :mode => '+notFound', :format => 'html', :cache_url => "/#{prefix}/404.html", :status => '404 Not Found'
88
+ not_found = "#{SITES_ROOT}/#{current_site.host}/public/#{prefix}/404.html"
89
+ if File.exists?(not_found)
90
+ render :text => File.read(not_found), :status => '404 Not Found'
91
+ else
92
+ render_and_cache :mode => '+notFound', :format => 'html', :cache_url => "/#{prefix}/404.html", :status => '404 Not Found'
93
+ end
91
94
  end
92
95
  end
93
96
  end
@@ -130,7 +133,8 @@ module Zena
130
133
  opts[:format] ||= params[:format].blank? ? 'html' : params[:format]
131
134
  #
132
135
  # cleanup before rendering
133
- params.delete(:mode)
136
+ # params.delete(:mode)
137
+
134
138
  if opts[:format] != 'html'
135
139
 
136
140
  method = "render_to_#{opts[:format]}"
@@ -149,8 +149,9 @@ module Zena
149
149
  responds_to_parent do # execute the redirect in the iframe's parent window
150
150
  render :update do |page|
151
151
  if @node.new_record?
152
+ page << "UploadProgress.setAsError(#{error_messages_for(:node, :object => @node).inspect})"
153
+ Node.logger.warn "ERROR #{error_messages_for(:node, :object => @node)}"
152
154
  page.replace_html 'form_errors', error_messages_for(:node, :object => @node)
153
- page.call 'UploadProgress.setAsError'
154
155
  else
155
156
  page.call 'UploadProgress.setAsFinished'
156
157
  page.delay(1) do # allow the progress bar fade to complete
@@ -160,10 +161,11 @@ module Zena
160
161
  if params[:reload]
161
162
  page << "Zena.t().Zena.reload(#{params[:reload].inspect})"
162
163
  end
163
- if params[:redir]
164
- page << "Zena.reload_and_close(#{params[:redir].inspect})"
165
- else
164
+ if params[:redir] == 'more'
165
+ # This is used when we want "upload more" in popup window.
166
166
  page.redirect_to document_url(@node[:zip], :reload => params[:reload], :js => params[:js])
167
+ elsif params[:redir]
168
+ page << "Zena.t().window.location = #{params[:redir].gsub('NODE_ID', @node.zip.to_s).inspect}"
167
169
  end
168
170
  end
169
171
  end
@@ -88,6 +88,13 @@ module Zena
88
88
 
89
89
  pre = opts.delete(:prefix) || (visitor.is_anon? && opts.delete(:lang)) || prefix
90
90
  mode = opts.delete(:mode)
91
+ if ep = opts[:encode_params]
92
+ ep = ep.split(',').map(&:strip)
93
+ if ep.delete('mode')
94
+ mode ||= params[:mode]
95
+ end
96
+ opts['encode_params'] = ep
97
+ end
91
98
 
92
99
  if host = opts.delete(:host)
93
100
  if ssl = opts.delete(:ssl)
@@ -155,10 +162,12 @@ module Zena
155
162
  list = opts.keys.map do |k|
156
163
  # FIXME: DOC
157
164
  if k.to_s == 'encode_params'
158
- opts[k].split(',').map(&:strip).map do |key|
165
+ opts[k].map do |key|
159
166
  value = params[key]
160
167
  if value.kind_of?(Hash)
161
168
  {key => value}.to_query
169
+ elsif value.kind_of?(Array)
170
+ {key => value.map{|v| v.blank? ? nil : v}.compact}.to_query
162
171
  elsif !value.blank?
163
172
  "#{key}=#{CGI.escape(value)}"
164
173
  else
@@ -405,7 +414,7 @@ module Zena
405
414
  http_method = http_method_from_action(options[:action])
406
415
 
407
416
  if http_method == 'delete' && method != 'unlink'
408
- confirm ||= '#{t("Destroy")} #{h title} ?'
417
+ confirm ||= '#{t("Destroy")} "#{h title}" ?'
409
418
  end
410
419
 
411
420
  if confirm
@@ -414,7 +423,7 @@ module Zena
414
423
  if confirm.literal
415
424
  markup.set_param(:"data-confirm", confirm.literal)
416
425
  else
417
- markup.set_dyn_param(:"data-confirm", "<%= #{confirm} %>")
426
+ markup.set_dyn_param(:"data-confirm", "<%= fquote(#{confirm}) %>")
418
427
  end
419
428
  end
420
429
 
@@ -427,7 +436,7 @@ module Zena
427
436
  if true
428
437
  # Use onclick with Ajax.
429
438
  if confirm
430
- markup.set_dyn_param(:onclick, "if(confirm(\"<%= #{confirm} %>\")) {new Ajax.Request(\"<%= #{href} %>\", {asynchronous:true, evalScripts:true, method:\"#{http_method}\"});} return false;")
439
+ markup.set_dyn_param(:onclick, "if(confirm(this.getAttribute(\"data-confirm\"))) {new Ajax.Request(\"<%= #{href} %>\", {asynchronous:true, evalScripts:true, method:\"#{http_method}\"});} return false;")
431
440
  else
432
441
  markup.set_dyn_param(:onclick, "new Ajax.Request(\"<%= #{href} %>\", {asynchronous:true, evalScripts:true, method:\"#{http_method}\"}); return false;")
433
442
  end
@@ -732,7 +741,6 @@ module Zena
732
741
 
733
742
  # <r:link page='next'/> <r:link page='previous'/> <r:link page='list'/>
734
743
  def pagination_links
735
-
736
744
  return parser_error("not in pagination scope") unless pagination_key = get_context_var('paginate', 'key')
737
745
  page_direction = @params.delete(:page)
738
746
  case page_direction
@@ -179,7 +179,7 @@ module Zena
179
179
  safe_method_for Number, :fmt => {:class => String, :pre_processor => true}
180
180
  safe_method_for Number, [:fmt, Number] => {:class => String, :pre_processor => true}
181
181
 
182
- safe_method_for Range, :to_a => {:class => [Number], :pre_processor => true}
182
+ safe_method_for Range, :to_a => {:class => [Number]}
183
183
 
184
184
  safe_method_for NilClass, :to_f => {:class => Number, :pre_processor => true}
185
185
  safe_method_for NilClass, :to_i => {:class => Number, :pre_processor => true}