zafu 0.5.0 → 0.6.0

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.
@@ -1,90 +1,368 @@
1
1
  module Zafu
2
2
  module Process
3
3
  module Ajax
4
+ def save_state
5
+ super.merge(:@markup => @markup.dup)
6
+ end
7
+
8
+
9
+ # This method process a list and handles building the necessary templates for ajax 'add'.
10
+ def expand_with_finder(finder)
11
+ return super unless finder[:class].kind_of?(Array)
12
+
13
+ # Get the block responsible for rendering each elements in the list
14
+ each_block = descendant('each')
15
+ add_block = descendant('add')
16
+ form_block = descendant('form') || each_block
17
+ edit_block = descendant('edit')
18
+
19
+
20
+ # Should 'edit' and 'add' auto-publish ?
21
+ publish_after_save = (form_block && form_block.params[:publish]) ||
22
+ (edit_block && edit_block.params[:publish])
23
+
24
+ # class name for create form
25
+ klass = (add_block && add_block.params[:klass]) ||
26
+ (form_block && form_block.params[:klass])
27
+
28
+ if need_ajax?(each_block)
29
+ # We need to build the templates for ajax rendering.
30
+
31
+ # 1. Render inline
32
+ # assign [] to var
33
+ out "<% if (#{var} = #{finder[:method]}) || (#{node}.#{node.will_be?(Comment) ? "can_comment?" : "can_write?"} && #{var}=[]) -%>"
34
+ # The list is not empty or we have enough rights to add new elements.
35
+ set_dom_prefix
36
+
37
+ # New node context.
38
+ open_node_context(finder, :node => self.node.move_to(var, finder[:class])) do #, :need_link_id => form_block.need_link_id) do
39
+ # Pagination count and other contextual variables exist here.
40
+
41
+ # INLINE ==========
42
+ # 'r_add' needs the form when rendering. Send with :form.
43
+ out @markup.wrap(
44
+ expand_with(
45
+ :in_if => false,
46
+ :form => form_block,
47
+ :publish_after_save => publish_after_save,
48
+ # Do not render the form block directly: let [add] do this.
49
+ :ignore => ['form'],
50
+ :klass => klass
51
+ )
52
+ )
53
+
54
+ # Render 'else' clauses
55
+ @markup.done = false
56
+ out @markup.wrap(
57
+ expand_with(
58
+ :in_if => true,
59
+ :only => ['elsif', 'else']
60
+ )
61
+ )
62
+ end
63
+ out "<% end -%>"
64
+
65
+ # 2. Save 'each' template
66
+ store_block(each_block) #, :klass => klass) # do we need klass here ?
67
+
68
+ # 3. Save 'form' template
69
+ cont = {
70
+ :saved_template => form_url(node),
71
+ :klass => klass,
72
+ :make_form => each_block == form_block,
73
+ :publish_after_save => publish_after_save,
74
+ }
75
+
76
+ store_block(form_block, cont)
77
+ else
78
+ super
79
+ end
80
+
81
+ # out @markup.wrap(expand_with(:node => node.move_to(var, finder[:class]), :in_if => true))
82
+
83
+
84
+ #query = opts[:query]
85
+ #
86
+ #
87
+ #if need_ajax?
88
+ # new_dom_scope
89
+ # # ajax, build template. We could merge the following code with 'r_block'.
90
+ #
91
+ # # FORM ============
92
+ # if each_block != form_block
93
+ # form = expand_block(form_block, :klass => klass, :add=>add_block, :publish_after_save => publish_after_save, :saved_template => true)
94
+ # else
95
+ # form = expand_block(form_block, :klass => klass, :add=>add_block, :make_form=>true, :publish_after_save => publish_after_save, :saved_template => true)
96
+ # end
97
+ # out helper.save_erb_to_url(form, form_url)
98
+ #else
99
+ # # no form, render, edit and add are not ajax
100
+ # if descendant('add') || descendant('add_document')
101
+ # out "<% if (#{list_var} = #{list_finder}) || (#{node}.#{node.will_be?(Comment) ? "can_comment?" : "can_write?"} && #{list_var}=[]) -%>"
102
+ # elsif list_finder != 'nil'
103
+ # out "<% if #{list_var} = #{list_finder} -%>"
104
+ # else
105
+ # out "<% if nil -%>"
106
+ # end
107
+ #
108
+ #
109
+ # out render_html_tag(expand_with(:list=>list_var, :in_if => false))
110
+ # out expand_with(:in_if=>true, :only=>['elsif', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
111
+ # out "<% end -%>"
112
+ #end
113
+ end
4
114
 
5
115
  # Store a context as a sub-template that can be used in ajax calls
6
116
  def r_block
117
+ # Since we are using ajax, we will need this object to have an ID set.
118
+ set_dom_prefix
7
119
 
8
- # 1. store template
9
- store_block(self)
10
- out expand_with
11
- end
120
+ if @context[:block] == self
121
+ # Storing template (called from within store_block)
122
+ # Set id with the template's node context (<%= @node.zip %>)
123
+ @markup.set_id(node.dom_id)
124
+ expand_with
125
+ else
126
+ # 1. store template
127
+ # will wrap with @markup
128
+ store_block(self)
12
129
 
130
+ # 2. render
131
+ # Set id with the current node context (<%= var1.zip %>)
132
+ @markup.set_id(node.dom_id)
133
+ out expand_with
134
+ end
135
+ end
13
136
 
14
- private
15
- def store_block(block)
16
- # Save current rendering information (id, html_tag_done, html_tag_params)
17
- markup_bak = block.markup.dup
137
+ def r_add
138
+ return parser_error("Should not be called from within 'each'") if parent.method == 'each'
139
+ return '' if @context[:make_form]
18
140
 
19
- # Creatae new node context
20
- node_context = node.as_main
141
+ if node.will_be?(Comment)
142
+ out "<% if #{node.up(Node)}.can_comment? -%>"
143
+ else
144
+ out "<% if #{node.up(Node)}.can_write? -%>"
145
+ end
21
146
 
22
- # Change rendering context
23
- block.markup.done = false
24
- block.markup.set_id(node.dom_id) # "<%= dom_id(#{node}) %>"
147
+ unless descendant('add_btn')
148
+ # Add a descendant between self and blocks. ==> add( add_btn(blocks) )
149
+ blocks = @blocks.dup
150
+ @blocks = []
151
+ add_btn = make(:void, :method => 'add_btn', :params => @params.dup, :text => '')
152
+ add_btn.blocks = blocks
153
+ remove_instance_variable(:@all_descendants)
25
154
  end
26
155
 
27
- template = expand_block(self, :)
156
+ if @context[:form]
157
+ # ajax add
158
+ @markup.set_id("#{node.dom_prefix}_add")
159
+ @markup.append_param(:class, 'btn_add')
28
160
 
29
- if @context[:block] == self
30
- # called from self (storing template)
31
- @context.reject! do |k,v|
32
- # FIXME: reject all stored elements in a better way then this
33
- k.kind_of?(String) && k =~ /\ANode_\w/
161
+ if @params[:focus]
162
+ focus = "$(\"#{node.dom_prefix}_#{@params[:focus]}\").focus();"
163
+ else
164
+ focus = "$(\"#{node.dom_prefix}_form_t\").focusFirstElement();"
34
165
  end
35
- @markup.done = false
36
- @markup.params.merge!(:id=>erb_dom_id)
37
- @context[:scope_node] = node if @context[:scope_node]
38
- out expand_with(:node => node)
39
- if @method == 'drop' && !@context[:make_form]
40
- out drop_javascript
166
+
167
+ # Expand 'add' block
168
+ out @markup.wrap("#{expand_with(:onclick=>"[\"#{node.dom_prefix}_add\", \"#{node.dom_prefix}_form\"].each(Element.toggle);#{focus}return false;")}")
169
+
170
+ # New object to render form.
171
+ # FIXME: use 'klass' param in r_add or r_form instead of current list content.
172
+ new_node = node.move_to("#{var}_new", [node.klass].flatten.first)
173
+
174
+ if new_node.will_be?(Node)
175
+ # FIXME: BUG if we set <r:form klass='Post'/> the user cannot select class with menu...
176
+
177
+ # FIXME: inspect '@context[:form]' to see if it contains v_klass ?
178
+ out "<% if #{new_node} = secure(Node) { Node.new_from_class('#{new_node.class_name}') } -%>"
179
+ else
180
+ out "<% if #{new_node} = #{new_node.class_name}.new -%>"
41
181
  end
182
+
183
+ form_block = @context[:form]
184
+
185
+ # Expand (inline) 'form' block
186
+ out expand_block(form_block,
187
+ # Needed in form to be able to return the result
188
+ :template_url => template_url(node),
189
+ # ??
190
+ :in_add => true,
191
+ # ??
192
+ :add => self,
193
+ # Transform 'each' block into a form
194
+ :make_form => form_block.method == 'each',
195
+ # Node context = new node
196
+ :node => new_node
197
+ )
198
+ out "<% end -%>"
42
199
  else
43
- if parent.method == 'each' && @method == parent.single_child_method
44
- # use parent as block
45
- # FIXME: will not work with block as distant target...
46
- # do nothing
47
- else
48
- @markup.tag ||= 'div'
49
- new_dom_scope
50
-
51
- unless @context[:make_form]
52
- # STORE TEMPLATE ========
53
-
54
- context_bak = @context.dup # avoid side effects when rendering the same block
55
- ignore_list = @method == 'block' ? ['form'] : [] # do not show the form in the normal template of a block
56
- template = expand_block(self, :block=>self, :list=>false, :saved_template=>true, :ignore => ignore_list)
57
- @context = context_bak
58
- @result = ''
59
- out helper.save_erb_to_url(template, template_url)
60
-
61
- # STORE FORM ============
62
- if edit = descendant('edit')
63
- publish_after_save = (edit.params[:publish] == 'true')
64
- if form = descendant('form')
65
- # USE BLOCK FORM ========
66
- form_text = expand_block(form, :saved_template=>true, :publish_after_save => publish_after_save)
67
- else
68
- # MAKE A FORM FROM BLOCK ========
69
- form = self.dup
70
- form.method = 'form'
71
- form_text = expand_block(form, :make_form => true, :list => false, :saved_template => true, :publish_after_save => publish_after_save)
72
- end
73
- out helper.save_erb_to_url(form_text, form_url)
74
- end
75
- end
200
+ # no ajax
201
+ @markup.append_param(:class, 'btn_add') if @markup.tag
202
+ out @markup.wrap(expand_with)
203
+ end
204
+ out "<% end -%>"
205
+ end
76
206
 
77
- # RENDER
78
- @markup.done = false
79
- @markup.params.merge!(:id=>erb_dom_id)
80
- end
207
+ def r_add_btn
208
+ default = node.will_be?(Comment) ? _("btn_add_comment") : _("btn_add")
81
209
 
82
- out expand_with
83
- if @method == 'drop' && !@context[:make_form]
84
- out drop_javascript
85
- end
210
+ out "<a href='#' onclick='#{@context[:onclick]}'>#{text_for_link(default)}</a>"
211
+ end
212
+
213
+ def r_each
214
+ if @context[:saved_template]
215
+ # render to start a saved template
216
+ options = form_options
217
+ @markup.set_id(options[:id]) if options[:id]
218
+ @markup.set_param(:style, options[:style]) if options[:style]
219
+
220
+ out @markup.wrap(expand_with)
221
+ else
222
+ super
86
223
  end
87
224
  end
225
+
226
+ # Return true if we need to insert the dom id for this element. This method is overwritten in Ajax.
227
+ def need_dom_id?
228
+ @context[:form]
229
+ end
230
+
231
+ # Set a unique DOM prefix to build unique ids in the page.
232
+ def set_dom_prefix
233
+ @name ||= unique_name
234
+ node.dom_prefix = @name
235
+ end
236
+
237
+ # Unique template_url, ending with dom_id
238
+ def template_url(node)
239
+ "#{root.options[:root]}/#{node.dom_prefix}"
240
+ end
241
+
242
+ def form_url(node)
243
+ template_url(node) + '_form'
244
+ end
245
+
246
+ # Return a different name on each call
247
+ def unique_name
248
+ base = @name || @context[:name] || 'list'
249
+ root.get_unique_name(base, base == @name).gsub(/[^\d\w\/]/,'_')
250
+ end
251
+
252
+ def get_unique_name(key, own_id = false)
253
+ @next_name_index ||= {}
254
+ if @next_name_index[key]
255
+ @next_name_index[key] += 1
256
+ key + @next_name_index[key].to_s
257
+ elsif own_id
258
+ @next_name_index[key] = 0
259
+ key
260
+ else
261
+ @next_name_index[key] = 1
262
+ key + '1'
263
+ end
264
+ end
265
+
266
+
267
+
268
+ private
269
+ def store_block(block, cont = {})
270
+ cont = @context.merge(cont)
271
+
272
+ # Create new node context
273
+ node = cont[:node].as_main(ActiveRecord::Base)
274
+ node.dom_prefix = @name
275
+
276
+ cont[:template_url] = template_url(node)
277
+ cont[:node] = node
278
+ cont[:block] = block
279
+ cont[:saved_template] ||= cont[:template_url]
280
+ @context.each do |k, v|
281
+ if k.kind_of?(String)
282
+ cont[k] = nil
283
+ end
284
+ end
285
+
286
+ template = expand_block(block, cont)
287
+
288
+ out helper.save_erb_to_url(template, cont[:saved_template])
289
+ end
290
+
291
+ def need_ajax?(each_block)
292
+ return false unless each_block
293
+ # Inline editable
294
+ each_block.descendant('edit') ||
295
+ # Ajax add
296
+ descendant('add') ||
297
+ # List is reloaded from the 'add_document' popup
298
+ descendant('add_document') ||
299
+ # We use 'each' as block to render swap
300
+ (descendant('swap') && descendant('swap').parent.method != 'block') ||
301
+ # We use 'each' as block instead of the declared 'block' or 'drop'
302
+ ['block', 'drop'].include?(each_block.single_child_method)
303
+ end
304
+
305
+ #template = expand_block(self, :)
306
+ #
307
+ #if @context[:block] == self
308
+ # # called from self (storing template)
309
+ # @context.reject! do |k,v|
310
+ # # FIXME: reject all stored elements in a better way then this
311
+ # k.kind_of?(String) && k =~ /\ANode_\w/
312
+ # end
313
+ # @markup.done = false
314
+ # @markup.params.merge!(:id=>node.dom_id)
315
+ # @context[:scope_node] = node if @context[:scope_node]
316
+ # out expand_with(:node => node)
317
+ # if @method == 'drop' && !@context[:make_form]
318
+ # out drop_javascript
319
+ # end
320
+ #else
321
+ # if parent.method == 'each' && @method == parent.single_child_method
322
+ # # use parent as block
323
+ # # FIXME: will not work with block as distant target...
324
+ # # do nothing
325
+ # else
326
+ # @markup.tag ||= 'div'
327
+ # new_dom_scope
328
+ #
329
+ # unless @context[:make_form]
330
+ # # STORE TEMPLATE ========
331
+ #
332
+ # context_bak = @context.dup # avoid side effects when rendering the same block
333
+ # ignore_list = @method == 'block' ? ['form'] : [] # do not show the form in the normal template of a block
334
+ # template = expand_block(self, :block=>self, :list=>false, :saved_template=>true, :ignore => ignore_list)
335
+ # @context = context_bak
336
+ # @result = ''
337
+ # out helper.save_erb_to_url(template, template_url)
338
+ #
339
+ # # STORE FORM ============
340
+ # if edit = descendant('edit')
341
+ # publish_after_save = (edit.params[:publish] == 'true')
342
+ # if form = descendant('form')
343
+ # # USE BLOCK FORM ========
344
+ # form_text = expand_block(form, :saved_template=>true, :publish_after_save => publish_after_save)
345
+ # else
346
+ # # MAKE A FORM FROM BLOCK ========
347
+ # form = self.dup
348
+ # form.method = 'form'
349
+ # form_text = expand_block(form, :make_form => true, :list => false, :saved_template => true, :publish_after_save => publish_after_save)
350
+ # end
351
+ # out helper.save_erb_to_url(form_text, form_url)
352
+ # end
353
+ # end
354
+ #
355
+ # # RENDER
356
+ # @markup.done = false
357
+ # @markup.params.merge!(:id=>node.dom_id)
358
+ # end
359
+ #
360
+ # out expand_with
361
+ # if @method == 'drop' && !@context[:make_form]
362
+ # out drop_javascript
363
+ # end
364
+ #end
365
+
88
366
  end
89
367
  end
90
368
  end
@@ -2,44 +2,55 @@ module Zafu
2
2
  module Process
3
3
  # This module manages conditional rendering (if, else, elsif, case, when).
4
4
  module Conditional
5
- def r_if
6
- "<% if true -%>#{expand_with(:in_if => true)}<% end -%>"
5
+ def r_if(cond = nil)
6
+ cond ||= get_attribute_or_eval(false)
7
+ return parser_error("condition error") unless cond
8
+ expand_if(cond)
7
9
  end
8
10
 
9
- def r_else
10
- return nil unless @context[:in_if]
11
- # We use 'elsif' just in case there are more then one 'else' clause
12
- out "<% elsif true -%>#{expand_with(:in_if => false)}" # do not propagate
11
+ def r_case
12
+ r_if('false')
13
13
  end
14
14
 
15
- def helper
16
- @context[:helper]
15
+ def r_else
16
+ r_elsif('true')
17
17
  end
18
18
 
19
- # Return the node context for a given class (looks up into the hierarchy) or the
20
- # current node context if klass is nil.
21
- def node(klass = nil)
22
- return @context[:node] if !klass
23
- @context[:node].get(klass)
19
+ def r_when
20
+ r_elsif
24
21
  end
25
22
 
26
- def expand_with_node(name, klass)
27
- expand_with(:node => @context[:node].move_to(name, klass))
28
- end
23
+ def r_elsif(cond = nil)
24
+ return '' unless @context[:in_if]
25
+ cond ||= get_attribute_or_eval(false)
26
+ return parser_error("condition error") unless cond
29
27
 
30
- # def context_with_node(name, klass)
31
- # context = @context.dup
32
- # context[:node] = context[:node].move_to(name, klass)
33
- # end
28
+ res = expand_with(:in_if => false, :markup => nil)
34
29
 
35
- def var
36
- return @var if @var
37
- if node.name =~ /^var(\d+)$/
38
- @var = "var#{$1.to_i + 1}"
30
+ # We use 'elsif' just in case there are more then one 'else' clause
31
+ if markup = @context[:markup]
32
+ @markup.tag ||= markup.tag
33
+ @markup.steal_html_params_from(@params)
34
+ markup.params.each do |k, v|
35
+ next if @markup.param[k]
36
+ @markup.set_param(k, v)
37
+ end
38
+ out "<% elsif #{cond} -%>#{@markup.wrap(res)}" # do not propagate
39
39
  else
40
- @var = "var1"
40
+ @markup.done = true # never wrap else/elsif clause
41
+ out "<% elsif #{cond} -%>#{res}" # do not propagate
41
42
  end
42
43
  end
44
+
45
+ # Expand blocks with conditional enabled (else, elsif, etc).
46
+ def expand_if(condition, new_node_context = self.node)
47
+ res = ""
48
+ res << "<% if #{condition} -%>"
49
+ res << @markup.wrap(expand_with(:node => new_node_context))
50
+ res << expand_with(:in_if => true, :only => %w{else elsif when}, :markup => @markup)
51
+ res << "<% end -%>"
52
+ res
53
+ end
43
54
  end # Context
44
55
  end # Process
45
56
  end # Zafu