zena 1.2.3 → 1.2.4

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 (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}