zena 1.0.0.beta2 → 1.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +12 -0
  3. data/app/controllers/application_controller.rb +0 -1
  4. data/app/controllers/columns_controller.rb +11 -1
  5. data/app/controllers/nodes_controller.rb +79 -19
  6. data/app/controllers/versions_controller.rb +0 -2
  7. data/app/controllers/virtual_classes_controller.rb +19 -6
  8. data/app/models/column.rb +5 -1
  9. data/app/models/comment.rb +1 -6
  10. data/app/models/node.rb +21 -3
  11. data/app/models/role.rb +21 -0
  12. data/app/models/site.rb +7 -2
  13. data/app/models/template.rb +3 -3
  14. data/app/models/text_document.rb +4 -4
  15. data/app/models/user.rb +21 -8
  16. data/app/views/columns/_li.html.erb +1 -0
  17. data/app/views/nodes/_groups.rhtml +1 -1
  18. data/app/views/sites/_form.erb +3 -1
  19. data/app/views/sites/_li.erb +1 -0
  20. data/app/views/sites/index.erb +1 -1
  21. data/app/views/virtual_classes/_form.erb +11 -2
  22. data/app/views/virtual_classes/_li.erb +5 -2
  23. data/bin/zena +1 -1
  24. data/bricks/math/lib/bricks/math.rb +1 -1
  25. data/bricks/mongrel/README +3 -0
  26. data/bricks/mongrel/zena/deploy.rb +56 -0
  27. data/bricks/passenger/README +3 -0
  28. data/bricks/passenger/zena/deploy.rb +49 -0
  29. data/config/bricks.yml +6 -0
  30. data/config/deploy.rb +24 -18
  31. data/config/gems.yml +3 -3
  32. data/db/migrate/20100915062903_add_api_group_id_to_site.rb +9 -0
  33. data/lib/tasks/zena.rake +39 -35
  34. data/lib/zena.rb +5 -6
  35. data/lib/zena/acts/enrollable.rb +37 -6
  36. data/lib/zena/app.rb +4 -2
  37. data/lib/zena/deploy.rb +110 -150
  38. data/lib/zena/deploy/awstats.conf.rhtml +4 -4
  39. data/lib/zena/deploy/httpd.rhtml +2 -1
  40. data/lib/zena/deploy/stats.vhost.rhtml +7 -7
  41. data/lib/zena/deploy/vhost.rhtml +1 -1
  42. data/lib/zena/deploy/vhost_www.rhtml +4 -4
  43. data/lib/zena/foxy_parser.rb +6 -5
  44. data/lib/zena/info.rb +1 -1
  45. data/lib/zena/integration/test_case.rb +8 -3
  46. data/lib/zena/parser.rb +11 -11
  47. data/lib/zena/parser/zafu_tags.rb +2 -2
  48. data/lib/zena/remote.rb +16 -0
  49. data/lib/zena/remote/connection.rb +67 -0
  50. data/lib/zena/remote/interface.rb +405 -0
  51. data/lib/zena/remote/klass.rb +14 -0
  52. data/lib/zena/remote/mock.rb +58 -0
  53. data/lib/zena/remote/node.rb +76 -0
  54. data/lib/zena/routes.rb +2 -1
  55. data/lib/zena/use.rb +9 -4
  56. data/lib/zena/use/ajax.rb +3 -3
  57. data/lib/zena/use/authlogic.rb +8 -1
  58. data/lib/zena/use/context.rb +22 -21
  59. data/lib/zena/use/dates.rb +26 -3
  60. data/lib/zena/use/display.rb +33 -5
  61. data/lib/zena/use/forms.rb +90 -12
  62. data/lib/zena/use/fulltext.rb +1 -1
  63. data/lib/zena/use/i18n.rb +118 -31
  64. data/lib/zena/use/query_builder.rb +7 -5
  65. data/lib/zena/use/query_node.rb +30 -4
  66. data/lib/zena/use/rendering.rb +1 -1
  67. data/lib/zena/use/search.rb +10 -7
  68. data/lib/zena/use/urls.rb +3 -3
  69. data/lib/zena/use/zafu_attributes.rb +2 -2
  70. data/lib/zena/use/zafu_eval.rb +1 -1
  71. data/lib/zena/use/zafu_safe_definitions.rb +1 -0
  72. data/lib/zena/use/zafu_templates.rb +1 -1
  73. data/lib/zena/zafu_compiler.rb +5 -1
  74. data/public/javascripts/zena.js +4 -4
  75. data/public/stylesheets/admin.css +1 -0
  76. data/test/custom_queries/complex.host.yml +3 -3
  77. data/test/fixtures/files/translations_fr.yml +4 -1
  78. data/test/functional/application_controller_test.rb +2 -2
  79. data/test/functional/nodes_controller_test.rb +57 -5
  80. data/test/functional/users_controller_test.rb +10 -9
  81. data/test/functional/virtual_classes_controller_test.rb +48 -0
  82. data/test/integration/navigation_test.rb +13 -1
  83. data/test/integration/query_node/filters.yml +5 -0
  84. data/test/integration/query_node_test.rb +1 -1
  85. data/test/integration/zafu_compiler/ajax.yml +13 -19
  86. data/test/integration/zafu_compiler/basic.yml +0 -72
  87. data/test/integration/zafu_compiler/complex.yml +1 -1
  88. data/test/integration/zafu_compiler/complex_ok.yml +19 -0
  89. data/test/integration/zafu_compiler/dates.yml +62 -1
  90. data/test/integration/zafu_compiler/display.yml +4 -4
  91. data/test/integration/zafu_compiler/forms.yml +19 -7
  92. data/test/integration/zafu_compiler/i18n.yml +56 -1
  93. data/test/integration/zafu_compiler/later.yml +23 -1
  94. data/test/integration/zafu_compiler/relations.yml +1 -1
  95. data/test/integration/zafu_compiler/roles.yml +29 -1
  96. data/test/integration/zafu_compiler/safe_definitions.yml +1 -1
  97. data/test/integration/zafu_compiler/zafu_attributes.yml +2 -1
  98. data/test/integration/zafu_compiler_test.rb +5 -3
  99. data/test/sites/zena/columns.yml +3 -0
  100. data/test/sites/zena/roles.yml +0 -1
  101. data/test/sites/zena/sites.yml +1 -0
  102. data/test/sites/zena/versions.yml +2 -0
  103. data/test/unit/node_test.rb +27 -9
  104. data/test/unit/relation_proxy_test.rb +7 -4
  105. data/test/unit/remote_test.rb +379 -0
  106. data/test/unit/user_test.rb +47 -0
  107. data/test/unit/zena/acts/enrollable_test.rb +36 -7
  108. data/test/unit/zena/acts/serializable_test.rb +14 -2
  109. data/test/unit/zena/use/i18n_test.rb +32 -5
  110. data/test/unit/zena/use/query_node_test.rb +13 -1
  111. data/zena.gemspec +25 -11
  112. metadata +24 -10
@@ -0,0 +1,14 @@
1
+ module Zena
2
+ module Remote
3
+ class Klass
4
+ attr_accessor :connection, :name
5
+
6
+ include Zena::Remote::Interface::ClassMethods
7
+
8
+ def initialize(connection, name)
9
+ @connection = connection
10
+ @name = name
11
+ end
12
+ end
13
+ end # Remote
14
+ end # Zena
@@ -0,0 +1,58 @@
1
+ module Zena
2
+ module Remote
3
+ module Mock
4
+ # Redirect actual request to the integration test.
5
+ class Request < HTTParty::Request
6
+ def perform_actual_request
7
+ # body should contain xml data for post and put (@raw_request.body ?)
8
+ method = @raw_request.method.downcase
9
+ path = @raw_request.path
10
+ body = @raw_request.body
11
+
12
+ response = $test_connection.test_request(method, path, body, options[:headers], false)
13
+ transform_response(response)
14
+ end
15
+
16
+
17
+ # Transform an ActionController::Response into a Net::HTTP response.
18
+ # Based on code from fakeweb (thanks Chrisk !)
19
+ def transform_response(ac_res)
20
+ code, msg = 200, 'OK'
21
+ response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, msg)
22
+ response.instance_variable_set(:@body, ac_res.body)
23
+ ac_res.headers.each do |name, value|
24
+ if value.respond_to?(:each)
25
+ value.each { |v| response.add_field(name, v) }
26
+ else
27
+ response[name] = value
28
+ end
29
+ end
30
+
31
+ response.instance_variable_set(:@read, true)
32
+
33
+ class << response
34
+ def read_body(*args, &block)
35
+ yield @body if block_given?
36
+ @body
37
+ end
38
+ end
39
+
40
+ response
41
+ end
42
+ end
43
+
44
+ # Include this module to mock the connection and use the integration test to execute
45
+ # the actual request operations.
46
+ module Connection
47
+
48
+ def self.included(base)
49
+ def base.perform_request(http_method, path, options) #:nodoc:
50
+ options = default_options.dup.merge(options)
51
+ process_cookies(options)
52
+ request = Zena::Remote::Mock::Request.new(http_method, path, options).perform
53
+ end
54
+ end
55
+ end # Connection
56
+ end # Mock
57
+ end # Remote
58
+ end # Zena
@@ -0,0 +1,76 @@
1
+ module Zena
2
+ module Remote
3
+ class Node
4
+ include Zena::Remote::Interface::InstanceMethods
5
+ attr_accessor :connection, :attributes, :errors
6
+
7
+ def initialize(connection, hash)
8
+ @connection = connection
9
+ @attributes = {}
10
+ self.attributes = hash
11
+ end
12
+
13
+ def attributes=(new_attributes)
14
+ raise Exception.new("Invalid attributes. Expecting a hash, found #{new_attributes.inspect}") unless new_attributes.kind_of?(Hash)
15
+ new_attributes.stringify_keys.each do |key, value|
16
+ if value.kind_of?(Array)
17
+ # setting multiple ids
18
+ key = "#{key}_ids" unless key =~ /_ids$/
19
+ @attributes[key] = value.map do |elem|
20
+ if elem.kind_of?(Remote::Node)
21
+ elem.id
22
+ else
23
+ elem
24
+ end
25
+ end
26
+ elsif value.kind_of?(Remote::Node)
27
+ key = "#{key}_id" unless key =~ /_id$/
28
+ @attributes[key] = value.id
29
+ elsif key =~ /_ids$/ && value.kind_of?(String)
30
+ @attributes[key] = value.split(',').map(&:to_i)
31
+ else
32
+ @attributes[key] = value
33
+ end
34
+ end
35
+ end
36
+
37
+ def id
38
+ @attributes['id']
39
+ end
40
+
41
+ def method_missing(method, *args)
42
+ method = method.to_s
43
+ if args.size == 1 && method =~ /(.*)=$/
44
+ key = $1
45
+ elem = args.first
46
+ if elem.kind_of?(Remote::Node)
47
+ key = "#{key}_id" unless key =~ /_ids?$/
48
+ @attributes[key] = elem.id
49
+ elsif elem.kind_of?(Array)
50
+ key = "#{key}_ids" unless key =~ /_ids?$/
51
+ @attributes[key] = elem.map do |value|
52
+ value.kind_of?(Remote::Node) ? value.id : value
53
+ end
54
+ else
55
+ @attributes[$1] = elem
56
+ end
57
+ elsif args.size == 0
58
+ if @attributes.has_key?(method)
59
+ @attributes[method]
60
+ elsif method =~ /_ids?$/
61
+ @attributes[method] ||= []
62
+ else
63
+ # build query
64
+ if method.pluralize == method
65
+ res = all(method)
66
+ else
67
+ res = first(method)
68
+ end
69
+ end
70
+ else
71
+ super
72
+ end
73
+ end
74
+ end
75
+ end # Remote
76
+ end # Zena
data/lib/zena/routes.rb CHANGED
@@ -25,7 +25,8 @@ module Zena
25
25
  :collection => { :asearch => :get, :search => :get },
26
26
  :member => { :import => :post, :export => :get, :save_text => :put,
27
27
  :order => :any, :clear_order => :any,
28
- :zafu => :get, :drop => :put, :attribute => :get
28
+ :zafu => :get, :drop => :put, :attribute => :get,
29
+ :find => :get # same as search but starting on current node instead of root
29
30
  }.merge(Zena::Use::Grid::Routes) do |nodes|
30
31
  nodes.resources :versions,
31
32
  :member => { :edit => :get,
data/lib/zena/use.rb CHANGED
@@ -9,16 +9,16 @@ module Zena
9
9
  class << self
10
10
  attr_accessor :modules
11
11
 
12
- # Delcare a module (or list of modules) that should be used in Zena. The module should implement
12
+ # Declare a module (or list of modules) that should be used in Zena. The module should implement
13
13
  # sub-modules named ControllerMethods, ViewMethods or ZafuMethods in order to add features to
14
14
  # the controller, view or zafu compiler respectively.
15
15
  def module(*modules)
16
16
  create_module_hash
17
17
 
18
18
  modules.flatten.each do |mod|
19
- MODULE_NAME.each do |key, module_name|
19
+ MODULE_NAME.each do |key, sub_module_name|
20
20
  begin
21
- self.modules[key] << mod.const_get(module_name)
21
+ self.modules[key] << mod.const_get(sub_module_name)
22
22
  rescue NameError
23
23
  # ignore
24
24
  end
@@ -28,11 +28,16 @@ module Zena
28
28
 
29
29
  def each_module_for(name)
30
30
  create_module_hash
31
- (self.modules[name] || []).each do |mod|
31
+ modules_for(name).each do |mod|
32
32
  yield(mod)
33
33
  end
34
34
  end
35
35
 
36
+ def modules_for(name)
37
+ create_module_hash
38
+ self.modules[name] || []
39
+ end
40
+
36
41
  private
37
42
  def create_module_hash
38
43
  if self.modules.nil?
data/lib/zena/use/ajax.rb CHANGED
@@ -232,7 +232,7 @@ module Zena
232
232
 
233
233
  dom_id = node.dom_id(:erb => false)
234
234
 
235
- out %Q{<%= form_remote_tag(:url => zafu_node_path(#{node}), :method => :get, :html => {:id => \"#{dom_id}_f\"}) %>
235
+ out %Q{<%= form_remote_tag(:url => zafu_node_path(#{node}.zip), :method => :get, :html => {:id => \"#{dom_id}_f\"}) %>
236
236
  <div class='hidden'>
237
237
  <input type='hidden' name='t_url' value='#{template_url(upd)}'/>
238
238
  <input type='hidden' name='dom_id' value='#{upd}'/>
@@ -297,7 +297,7 @@ module Zena
297
297
  return parser_error("missing 'set' or 'add' parameter") unless role = @params.delete(:set) || @params.delete(:add)
298
298
  return parser_error("missing 'for' parameter") unless finder = @params.delete(:for)
299
299
 
300
- finder = RubyLess.translate(finder, self)
300
+ finder = RubyLess.translate(self, finder)
301
301
  return parser_error("Invalid class 'for' parameter: #{finder.klass}") unless finder.klass <= Node
302
302
 
303
303
  set_dom_prefix
@@ -315,7 +315,7 @@ module Zena
315
315
  return
316
316
  end
317
317
 
318
- finder = RubyLess.translate(finder, self)
318
+ finder = RubyLess.translate(self, finder)
319
319
  unless finder.klass <= Node
320
320
  out parser_error("Invalid class 'for' parameter: #{finder.klass}")
321
321
  return
@@ -20,6 +20,13 @@ module Zena
20
20
  private
21
21
 
22
22
  def save_after_login_url
23
+ # prevent redirect to favicon or css
24
+ return unless request.format == Mime::HTML
25
+ path = params[:path]
26
+ if path && path.last =~ /\.(.+)\Z/
27
+ return if $1 != 'html'
28
+ end
29
+
23
30
  session[:after_login_url] = request.parameters
24
31
  end
25
32
 
@@ -92,7 +99,7 @@ module Zena
92
99
  # Allow xml without :prefix in NodesController because it is rendered with zafu.
93
100
 
94
101
  # Authentication token required for xml.
95
- render :xml => 'Authentication token needed.', :status => 401
102
+ render :xml => [{:message => 'Authentication token needed.'}].to_xml(:root => 'errors'), :status => 401
96
103
  end
97
104
  end
98
105
  end
@@ -12,6 +12,7 @@ module Zena
12
12
 
13
13
  # Group an array of records by key.
14
14
  def group_array(list)
15
+ return nil if list.empty?
15
16
  groups = []
16
17
  h = {}
17
18
  list.each do |e|
@@ -148,38 +149,38 @@ module Zena
148
149
  # end
149
150
 
150
151
  if %w{parent project section}.include?(key)
151
- key = "e.#{key}"
152
+ key = "e.#{key}_id"
152
153
  else
153
- key = "e.#{RubyLess.translate(key, node.klass.first)}"
154
+ receiver = RubyLess::TypedString.new('e', :class => node.klass.first, :query => node.opts[:query])
155
+ key = RubyLess.translate(receiver, key)
154
156
  end
155
157
 
156
158
  #if sort_block
157
159
  # out "<% grp_#{list_var} = sort_array(#{group_array}) #{sort_block} -%>"
158
160
  #else
159
- out "<% #{var} = group_array(#{node}) {|e| #{key}} -%>"
160
161
  #end
162
+ method = "group_array(#{node}) {|e| #{key}}"
163
+ out "<% if #{var} = #{method} -%>"
164
+ open_node_context({:method => method}, :node => node.move_to(var, [node.klass], :query => node.opts[:query])) do
165
+ if child['each_group']
166
+ out expand_with
167
+ else
168
+ @var = nil
169
+ r_each
170
+ end
171
+ end
172
+ out "<% end -%>"
161
173
 
162
- if descendant('each_group')
163
- out expand_with(:group => var)
164
- else
165
- @context[:group] = var
166
- r_each_group
167
- end
174
+ #if descendant('each_group')
175
+ # out expand_with(:group => var)
176
+ #else
177
+ # @context[:group] = var
178
+ # r_each_group
179
+ #end
168
180
  end
169
181
 
170
-
171
182
  def r_each_group
172
- return parser_error("must be used inside a group context") unless group = @context[:group]
173
- if join = @params[:join]
174
- join = join.gsub(/&lt;([^%])/, '<\1').gsub(/([^%])&gt;/, '\1>')
175
- out "<% #{group}.each_with_index do |#{var}, #{var}_i| -%>"
176
- out "<%= #{var}_i > 0 ? #{join.inspect} : '' %>"
177
- else
178
- out "<% #{group}.each do |#{var}| -%>"
179
- end
180
-
181
- out wrap(expand_with(:group => nil, :node => node.move_to(var, node.klass)))
182
- out "<% end -%>"
183
+ r_each
183
184
  end
184
185
  end # ZafuMethods
185
186
  end # Context
@@ -279,9 +279,32 @@ EOL
279
279
  end
280
280
 
281
281
  # Select a date for the current context
282
- # def r_date
283
- # set_context_var('set_var', 'date', get_attribute_or_eval)
284
- # end
282
+ def r_date
283
+ return nil unless code = get_attribute_or_eval
284
+
285
+ if format = @params[:format]
286
+ format = RubyLess.translate_string(self, format)
287
+ else
288
+ format = "'%Y-%m-%d %H:%M:%S'"
289
+ end
290
+
291
+ if code.klass <= String
292
+ if code.could_be_nil?
293
+ code = "(#{code} || '').to_utc(#{format})"
294
+ else
295
+ code = "#{code}.to_utc(#{format})"
296
+ end
297
+ could_be_nil = true
298
+ elsif code.klass <= Time
299
+ could_be_nil = code.could_be_nil?
300
+ else
301
+ return parser_error("should evaluate to a String or Time (found #{code.klass})")
302
+ end
303
+ v = get_var_name('set_var', 'date')
304
+ out "<% #{v} = #{code} -%>"
305
+ set_context_var('set_var', 'date', RubyLess::TypedString.new(v, :class => Time, :nil => could_be_nil))
306
+ out expand_with
307
+ end
285
308
 
286
309
  end
287
310
  end # Dates
@@ -387,11 +387,32 @@ module Zena
387
387
  end # ViewMethods
388
388
 
389
389
  module ZafuMethods
390
+ SHOW_KEYS = [:tz, :tformat, :format, :lang, :zero]
391
+
390
392
  include Common
391
393
  include RubyLess
392
394
 
393
395
  safe_method [:zazen, String] => :r_zazen
394
396
 
397
+ # As a last resort, if the method cannot be compilated, use <r:show eval='...'/>
398
+ def self.included(base)
399
+ base.process_unknown :show_eval
400
+ end
401
+
402
+ # Transform <p do='created_at' format='%d'/> into
403
+ # <p do='show' eval='created_at' format='%d'/>
404
+ def show_eval
405
+ if !@params.empty? && !(@method =~ /. ./) && (@params.keys - SHOW_KEYS == [])
406
+ # try to use r_show without using params as arguments
407
+ code = RubyLess.translate(self, @method)
408
+ r_show(code)
409
+ else
410
+ nil
411
+ end
412
+ rescue RubyLess::Error
413
+ nil
414
+ end
415
+
395
416
  # Parse text with zazen helper
396
417
  def r_zazen(signature = nil)
397
418
  @markup.prepend_param(:class, 'zazen')
@@ -421,15 +442,15 @@ module Zena
421
442
  end
422
443
 
423
444
  # Display an attribute or RubyLess code
424
- def r_show
445
+ def r_show(code = nil)
425
446
  if node.list_context?
426
- @context[:node] = node.move_to("#{node}.first", node.klass.first)
447
+ @context[:node] = node.move_to("#{node}.first", node.klass.first, :query => node.opts[:query])
427
448
  return r_show
428
449
  elsif node.will_be?(String)
429
450
  return "<%= #{node} %>"
430
451
  end
431
452
 
432
- return nil unless method = get_attribute_or_eval
453
+ return nil unless method = code || get_attribute_or_eval
433
454
 
434
455
  klass = method.klass
435
456
 
@@ -505,7 +526,7 @@ module Zena
505
526
  return unless node.will_be?(Node)
506
527
 
507
528
  if src = @params[:src]
508
- finder = ::RubyLess.translate(@params[:src], self) #build_finder(:first, @params[:src])
529
+ finder = ::RubyLess.translate(self, @params[:src]) #build_finder(:first, @params[:src])
509
530
  return parser_error("invalid class (#{finder.klass})") unless finder.klass <= Node
510
531
 
511
532
  img = finder
@@ -522,7 +543,7 @@ module Zena
522
543
  res += ", :host => #{@context["exp_host"]}" if @context["exp_host"]
523
544
  res += ")"
524
545
  if finder = @params[:link]
525
- finder = ::RubyLess.translate(finder, self)
546
+ finder = ::RubyLess.translate(self, finder)
526
547
 
527
548
  return parser_error("Invalid class (#{finder.klass})") unless finder.klass <= Node
528
549
 
@@ -586,8 +607,15 @@ module Zena
586
607
  end
587
608
 
588
609
  def show_time(method)
610
+ if tformat = @params.delete(:tformat)
611
+ tformat = RubyLess.translate(self, "t(%Q{#{tformat}})")
612
+ method = "#{method}, :format => #{tformat}"
613
+ end
614
+
589
615
  if hash_arguments = extract_from_params(:tz, :lang, :format)
590
616
  "<%= format_date(#{method}, #{hash_arguments.join(', ')}) %>"
617
+ elsif tformat
618
+ "<%= format_date(#{method}) %>"
591
619
  else
592
620
  "<%= #{method} %>"
593
621
  end
@@ -2,6 +2,13 @@ module Zena
2
2
  module Use
3
3
  module Forms
4
4
  module ViewMethods
5
+
6
+ # Create a new instance of the given class name
7
+ def new_instance(class_name, params = {})
8
+ return nil unless klass = Node.get_class(class_name, :create => true)
9
+ klass.new_instance(Node.transform_attributes(params))
10
+ end
11
+
5
12
  def make_checkbox(node, values, relation_name, attribute)
6
13
  relation_proxy = node.relation_proxy(relation_name)
7
14
  return nil unless values && relation_proxy
@@ -39,6 +46,43 @@ module Zena
39
46
  end # ViewMethods
40
47
 
41
48
  module ZafuMethods
49
+
50
+ # Enter the context of a newly created object
51
+ def r_new
52
+ return parser_error("missing 'klass' parameter") unless class_name = @params[:klass]
53
+ return parser_error("invalid 'klass' parameter (not a Node)") unless klass = get_class(class_name)
54
+
55
+ res = []
56
+ keys = {:klass => 'klass'}
57
+ @params.each do |key, value|
58
+ next if key == :klass
59
+ # TODO: maybe it would be safer to check with [:"key="] and change safe_property to
60
+ # authorize both ?
61
+ next unless type = klass.safe_method_type([key.to_s])
62
+ # Store how to access current value to show hidden field in form.
63
+ keys[key] = type[:method]
64
+ res << ":#{key} => #{RubyLess.translate_string(self, value)}"
65
+ end
66
+
67
+ if res == []
68
+ method = "new_instance(#{class_name.inspect})"
69
+ else
70
+ method = "new_instance(#{class_name.inspect}, #{res.join(', ')})"
71
+ end
72
+
73
+ expand_with_finder(
74
+ :method => method,
75
+ :class => klass,
76
+ :nil => true,
77
+ :new_keys => keys
78
+ )
79
+ end
80
+
81
+ def r_errors
82
+ # Very basic for the moment
83
+ "<%= error_messages_for(#{node.form_name}, :object => #{node}) %>"
84
+ end
85
+
42
86
  def make_input(form_helper, name, type, textarea = false)
43
87
  if type == Time
44
88
  "<%= date_box(#{node}, :#{name}) %>"
@@ -112,19 +156,31 @@ module Zena
112
156
  # Saved form
113
157
  opts[:id] = "<%= ndom_id(#{node}) %>"
114
158
 
115
- opts[:form_tag] = <<-END_TXT
116
- <% remote_form_for(:#{node.form_name}, #{node}, :url => #{node}.new_record? ? #{node.form_name.pluralize}_path : #{node.form_name}_path(#{node}), :method => #{node}.new_record? ? :post : :put, :html => {:id => \"\#{ndom_id(#{node})}_form_t\"}) do |f| %>
117
- END_TXT
159
+ opts[:form_tag] = %Q{
160
+ <% remote_form_for(:#{node.form_name}, #{node}, :url => #{node}.new_record? ? #{node.form_name.pluralize}_path : #{node.form_name}_path(#{node}.zip), :html => {:method => #{node}.new_record? ? :post : :put, :id => \"\#{ndom_id(#{node})}_form_t\"}) do |f| %>
161
+ }
118
162
 
119
- opts[:form_cancel] = <<-END_TXT
163
+ opts[:form_cancel] = %Q{
120
164
  <% if #{node}.new_record? -%>
121
165
  <p class='btn_x'><a href='#' onclick='[\"<%= params[:dom_id] %>_add\", \"<%= params[:dom_id] %>_form\"].each(Element.toggle);return false;'>#{_('btn_x')}</a></p>
122
166
  <% else -%>
123
- <p class='btn_x'><%= link_to_remote(#{_('btn_x').inspect}, :url => #{node.form_name}_path(#{node}.id) + \"/zafu?t_url=#{CGI.escape(template_url)}&dom_id=\#{params[:dom_id]}#{@context[:has_link_id] ? "&link_id=\#{#{node}.link_id}" : ''}\", :method => :get) %></p>
167
+ <p class='btn_x'><%= link_to_remote(#{_('btn_x').inspect}, :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) %></p>
124
168
  <% end -%>
125
- END_TXT
169
+ }
126
170
  end
171
+ else
172
+ # no ajax
173
+ if descendants('errors')
174
+ error_messages = ''
175
+ else
176
+ error_messages = r_errors + "\n"
177
+ end
178
+
179
+ opts[:form_tag] = %Q{
180
+ <% form_for(:#{node.form_name}, #{node}, :url => #{node}.new_record? ? #{node.form_name.pluralize}_path : #{node.form_name}_path(#{node}.zip), :html => {:method => #{node}.new_record? ? :post : :put, :id => \"\#{ndom_id(#{node})}_form_t\"}) do |f| %>
181
+ #{error_messages}}
127
182
  end
183
+
128
184
  opts
129
185
  end
130
186
 
@@ -234,8 +290,27 @@ END_TXT
234
290
 
235
291
  hidden_fields['node[v_status]'] = Zena::Status[:pub].to_s if add_params[:publish] || auto_publish_param
236
292
 
293
+ # All default values set in the <r:new> field should at least appear as hidden fields
294
+ if new_keys = node.opts[:new_keys]
295
+ input_keys = (
296
+ (descendants('input') || []).map {|e| e.params[:name]} +
297
+ hidden_fields.keys.map do |e|
298
+ if e =~ /.*\[(.*)\]/
299
+ $1.to_sym
300
+ else
301
+ nil
302
+ end
303
+ end
304
+ ).compact.uniq
305
+
306
+ new_keys.each do |key, value|
307
+ next if input_keys.include?(key)
308
+ hidden_fields["node[#{key}]"] = "<%= #{node}.#{value} %>"
309
+ end
310
+ end
237
311
  # ===
238
312
  # TODO: reject set_fields from hidden_fields
313
+ # ? what is this ?
239
314
  # ===
240
315
 
241
316
  hidden_fields.reject! do |k,v|
@@ -257,7 +332,7 @@ END_TXT
257
332
  return parser_error("missing name") unless attribute
258
333
 
259
334
  if value = @params[:selected]
260
- selected = ::RubyLess.translate_string(value, self)
335
+ selected = ::RubyLess.translate_string(self, value)
261
336
  elsif @context[:in_filter]
262
337
  selected = "params[#{attribute.to_sym.inspect}].to_s"
263
338
  elsif %w{parent_id}.include?(attribute)
@@ -396,13 +471,13 @@ END_TXT
396
471
 
397
472
  if sub_attr
398
473
  type = node.klass.safe_method_type([attribute])
399
- if sub_attr_ruby = RubyLess.translate(%Q{this.#{attribute}[#{sub_attr.inspect}]}, self)
474
+ if sub_attr_ruby = RubyLess.translate(self, %Q{this.#{attribute}[#{sub_attr.inspect}]})
400
475
  res[:value] = "<%= fquote #{sub_attr_ruby} %>"
401
476
  end
402
477
  else
403
478
  if value = params[:value]
404
479
  # On refactor, use append_markup_attr(markup, key, value)
405
- value = RubyLess.translate_string(value, self)
480
+ value = RubyLess.translate_string(self, value)
406
481
 
407
482
  if value.literal
408
483
  res[:value] = value.literal.to_s.gsub("'",'&apos;')
@@ -432,6 +507,9 @@ END_TXT
432
507
  # res[:value] = ["''"]
433
508
  # end
434
509
  #end
510
+ elsif node.will_be?(Column)
511
+ res[:name] = "node[<%= #{node}.name %>]"
512
+ res[:value] = "<%= fquote #{node(Node)}.prop[#{node}.name] %>"
435
513
  end
436
514
 
437
515
  if node.dom_prefix
@@ -474,7 +552,7 @@ END_TXT
474
552
 
475
553
  # Get current attribute in forms
476
554
  def node_attribute(attribute)
477
- node_attribute = ::RubyLess.translate(attribute, node.klass)
555
+ node_attribute = ::RubyLess.translate(node.klass, attribute)
478
556
  "#{node}.#{node_attribute}"
479
557
  rescue ::RubyLess::NoMethodError
480
558
  if node.will_be?(Node)
@@ -517,8 +595,8 @@ END_TXT
517
595
  nodes = finder[:method]
518
596
  end
519
597
 
520
- set_attr = ::RubyLess.translate(@params[:attr] || 'id', klass)
521
- show_attr = ::RubyLess.translate(@params[:show] || 'title', klass)
598
+ set_attr = ::RubyLess.translate(klass, @params[:attr] || 'id')
599
+ show_attr = ::RubyLess.translate(klass, @params[:show] || 'title')
522
600
 
523
601
  options_list = "[['','']] + (#{nodes} || []).map{|r| [r.#{show_attr}, r.#{set_attr}.to_s]}"
524
602
  elsif values = @params[:values]