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.
- data/History.txt +38 -1
- data/app/controllers/documents_controller.rb +7 -5
- data/app/controllers/nodes_controller.rb +47 -6
- data/app/controllers/user_sessions_controller.rb +12 -3
- data/app/controllers/virtual_classes_controller.rb +8 -2
- data/app/models/acl.rb +5 -2
- data/app/models/cached_page.rb +5 -5
- data/app/models/column.rb +27 -4
- data/app/models/group.rb +1 -1
- data/app/models/node.rb +106 -24
- data/app/models/note.rb +2 -1
- data/app/models/relation.rb +9 -4
- data/app/models/relation_proxy.rb +2 -2
- data/app/models/role.rb +12 -5
- data/app/models/site.rb +10 -9
- data/app/models/skin.rb +8 -0
- data/app/models/string_hash.rb +65 -0
- data/app/models/text_document.rb +1 -1
- data/app/models/user.rb +2 -0
- data/app/models/virtual_class.rb +43 -10
- data/app/views/comments/create.rjs +1 -32
- data/app/views/comments/edit.rjs +1 -1
- data/app/views/comments/update.rjs +1 -1
- data/app/views/documents/show.rhtml +1 -1
- data/app/views/groups/_form.rhtml +7 -0
- data/app/views/groups/_li.rhtml +1 -1
- data/app/views/nodes/500.html +2 -1
- data/app/views/nodes/destroy.rjs +2 -0
- data/app/views/sites/jobs.erb +2 -3
- data/app/views/templates/document_create_tabs/_file.rhtml +1 -1
- data/app/views/templates/document_create_tabs/_import.rhtml +4 -1
- data/app/views/templates/document_create_tabs/_template.rhtml +3 -0
- data/app/views/templates/document_create_tabs/_text_document.rhtml +3 -0
- data/app/views/versions/custom_tab.rhtml +1 -1
- data/app/views/versions/edit.rhtml +1 -1
- data/bricks/acls/lib/bricks/acls.rb +3 -3
- data/bricks/acls/zena/test/unit/acl_test.rb +15 -0
- data/bricks/fs_skin/lib/bricks/fs_skin.rb +190 -0
- data/bricks/fs_skin/zena/init.rb +1 -0
- data/bricks/fs_skin/zena/migrate/20110702010330_add_fs_skin_to_idx_templates.rb +12 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Image-edit.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Image.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Node-+index.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Node-+notFound.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Node-+search.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Node.zafu +1 -1
- data/bricks/{static → fs_skin}/zena/skins/blog/Post.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Project--kml.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Project.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/comments.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/dict.yml +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/dateBg.jpg +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/header.png +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/mapPin.png +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/menu.gif +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/menuover.gif +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/style.css +0 -0
- data/bricks/fs_skin/zena/tasks.rb +26 -0
- data/bricks/{static/zena/test/integration/static_integration_test.rb → fs_skin/zena/test/integration/fs_skin_integration_test.rb} +6 -6
- data/bricks/fs_skin/zena/test/unit/fs_skin_test.rb +33 -0
- data/bricks/grid/lib/bricks/grid.rb +4 -3
- data/bricks/tags/lib/bricks/tags.rb +1 -7
- data/bricks/zena/zena/migrate/20120605091558_add_ssl_login_to_site.rb +7 -0
- data/bricks/zena/zena/migrate/20120630123551_add_auto_publish_to_group.rb +9 -0
- data/config/bricks.yml +3 -3
- data/config/gems.yml +2 -3
- data/lib/tasks/zena.rake +7 -3
- data/lib/zafu.rb +7 -0
- data/lib/zafu/all.rb +21 -0
- data/lib/zafu/compiler.rb +7 -0
- data/lib/zafu/controller_methods.rb +58 -0
- data/lib/zafu/handler.rb +57 -0
- data/lib/zafu/info.rb +4 -0
- data/lib/zafu/markup.rb +309 -0
- data/lib/zafu/mock_helper.rb +42 -0
- data/lib/zafu/node_context.rb +203 -0
- data/lib/zafu/ordered_hash.rb +53 -0
- data/lib/zafu/parser.rb +676 -0
- data/lib/zafu/parsing_rules.rb +382 -0
- data/lib/zafu/process/ajax.rb +530 -0
- data/lib/zafu/process/conditional.rb +92 -0
- data/lib/zafu/process/context.rb +186 -0
- data/lib/zafu/process/forms.rb +143 -0
- data/lib/zafu/process/html.rb +186 -0
- data/lib/zafu/process/ruby_less_processing.rb +321 -0
- data/lib/zafu/security.rb +15 -0
- data/lib/zafu/template.rb +25 -0
- data/lib/zafu/test_helper.rb +19 -0
- data/lib/zafu/view_methods.rb +6 -0
- data/lib/zena.rb +1 -1
- data/lib/zena/acts/enrollable.rb +1 -1
- data/lib/zena/app.rb +4 -17
- data/lib/zena/console.rb +18 -1
- data/lib/zena/core_ext/file_utils.rb +13 -1
- data/lib/zena/core_ext/fixnum.rb +4 -0
- data/lib/zena/core_ext/float.rb +7 -0
- data/lib/zena/deploy.rb +4 -2
- data/lib/zena/deploy/app_init.rhtml +2 -1
- data/lib/zena/deploy/database.rhtml +1 -1
- data/lib/zena/info.rb +1 -1
- data/lib/zena/parser/zazen_rules.rb +4 -4
- data/lib/zena/routes.rb +1 -1
- data/lib/zena/test_controller.rb +1 -1
- data/lib/zena/use.rb +14 -1
- data/lib/zena/use/action.rb +4 -2
- data/lib/zena/use/ajax.rb +86 -38
- data/lib/zena/use/authlogic.rb +16 -1
- data/lib/zena/use/calendar.rb +37 -17
- data/lib/zena/use/conditional.rb +2 -2
- data/lib/zena/use/context.rb +30 -9
- data/lib/zena/use/dates.rb +39 -3
- data/lib/zena/use/display.rb +6 -19
- data/lib/zena/use/forms.rb +100 -79
- data/lib/zena/use/i18n.rb +40 -16
- data/lib/zena/use/query_builder.rb +0 -6
- data/lib/zena/use/query_node.rb +17 -4
- data/lib/zena/use/relations.rb +1 -3
- data/lib/zena/use/rendering.rb +10 -8
- data/lib/zena/use/scope_index.rb +5 -1
- data/lib/zena/use/search.rb +2 -1
- data/lib/zena/use/urls.rb +82 -77
- data/lib/zena/use/workflow.rb +12 -4
- data/lib/zena/use/zafu_safe_definitions.rb +37 -9
- data/lib/zena/use/zafu_templates.rb +49 -20
- data/lib/zena/use/zazen.rb +6 -2
- data/locale/it/LC_MESSAGES/zena.mo +0 -0
- data/locale/it/zena.mo +0 -0
- data/locale/it/zena.po +1982 -0
- data/public/images/arrow_back.png +0 -0
- data/public/images/remove_tag.png +0 -0
- data/public/javascripts/grid.js +800 -199
- data/public/javascripts/window.js +1 -1
- data/public/javascripts/zena.js +130 -21
- data/public/stylesheets/grid.css +11 -2
- data/public/stylesheets/zena.css +2 -1
- data/test/custom_queries/complex.host.yml +5 -0
- data/test/fixtures/files/TestNode.zafu +36 -0
- data/test/functional/nodes_controller_test.rb +18 -1
- data/test/integration/zafu_compiler/action.yml +2 -2
- data/test/integration/zafu_compiler/ajax.yml +44 -26
- data/test/integration/zafu_compiler/asset.yml +12 -2
- data/test/integration/zafu_compiler/basic.yml +0 -16
- data/test/integration/zafu_compiler/calendar.yml +6 -6
- data/test/integration/zafu_compiler/complex_ok.yml +23 -1
- data/test/integration/zafu_compiler/conditional.yml +5 -5
- data/test/integration/zafu_compiler/context.yml +6 -5
- data/test/integration/zafu_compiler/dates.yml +23 -2
- data/test/integration/zafu_compiler/display.yml +46 -2
- data/test/integration/zafu_compiler/errors.yml +2 -2
- data/test/integration/zafu_compiler/eval.yml +35 -7
- data/test/integration/zafu_compiler/forms.yml +47 -13
- data/test/integration/zafu_compiler/i18n.yml +2 -2
- data/test/integration/zafu_compiler/meta.yml +35 -1
- data/test/integration/zafu_compiler/query.yml +23 -4
- data/test/integration/zafu_compiler/relations.yml +10 -6
- data/test/integration/zafu_compiler/roles.yml +4 -4
- data/test/integration/zafu_compiler/rubyless.yml +11 -1
- data/test/integration/zafu_compiler/safe_definitions.yml +23 -5
- data/test/integration/zafu_compiler/security.yml +10 -6
- data/test/integration/zafu_compiler/urls.yml +23 -6
- data/test/integration/zafu_compiler/zafu_attributes.yml +1 -1
- data/test/integration/zafu_compiler/zazen.yml +14 -0
- data/test/selenium/Add/add3.rsel +8 -8
- data/test/selenium/Destroy/0setup.rsel +12 -0
- data/test/selenium/Destroy/destroy1.rsel +16 -0
- data/test/selenium/Edit/edit2.rsel +9 -9
- data/test/selenium/Edit/edit5.rsel +9 -9
- data/test/selenium/Edit/edit6.rsel +9 -9
- data/test/selenium/Form/form4.rsel +17 -0
- data/test/selenium/Toggle/toggle1.rsel +2 -0
- data/test/selenium/Toggle/toggle2.rsel +18 -0
- data/test/sites/zena/columns.yml +3 -0
- data/test/sites/zena/versions.yml +7 -0
- data/test/unit/cached_page_test.rb +13 -13
- data/test/unit/column_test.rb +26 -0
- data/test/unit/node_test.rb +16 -1
- data/test/unit/project_test.rb +6 -1
- data/test/unit/relation_test.rb +1 -1
- data/test/unit/role_test.rb +1 -1
- data/test/unit/string_hash_test.rb +30 -0
- data/test/unit/virtual_class_test.rb +31 -17
- data/test/unit/zafu_markup_test.rb +414 -0
- data/test/unit/zafu_node_context_test.rb +375 -0
- data/test/unit/zafu_ordered_hash_test.rb +69 -0
- data/test/unit/zena/acts/enrollable_test.rb +1 -1
- data/test/unit/zena/parser/zafu_asset.yml +0 -10
- data/test/unit/zena/parser/zazen.yml +1 -1
- data/test/unit/zena/parser_test.rb +1 -72
- data/test/unit/zena/use/dates_test.rb +1 -1
- data/test/unit/zena/use/rendering_test.rb +24 -7
- data/test/unit/zena/use/scope_index_test.rb +17 -0
- data/test/unit/zena/use/zazen_test.rb +2 -1
- data/zena.gemspec +71 -37
- metadata +104 -83
- data/app/views/nodes/destroy.erb +0 -0
- data/bricks/static/lib/bricks/static.rb +0 -151
- data/bricks/static/zena/init.rb +0 -1
- data/bricks/static/zena/migrate/20110702010330_add_static_to_idx_templates.rb +0 -12
- data/bricks/static/zena/test/unit/static_test.rb +0 -33
- data/lib/zena/parser/zafu_rules.rb +0 -244
- data/lib/zena/parser/zafu_tags.rb +0 -198
- data/lib/zena/parser/zena_rules.rb +0 -23
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
require 'zafu/markup'
|
|
2
|
+
|
|
3
|
+
module Zafu
|
|
4
|
+
PARAM_KEY_REGEXP = %r{^\s+([\w_\-\[\]:]+)=}m
|
|
5
|
+
PARAM_VALUE_REGEXP = %r{('|")(|[^\1]*?[^\\])\1}m
|
|
6
|
+
module ParsingRules
|
|
7
|
+
# The context informs the rendering element about the current Node, node class, existing ids, etc. The
|
|
8
|
+
# context is inherited by sub-elements.
|
|
9
|
+
attr_reader :context
|
|
10
|
+
|
|
11
|
+
# The helper is used to connect the compiler to the world of the application (read/write templates, access traductions, etc)
|
|
12
|
+
attr_reader :helper
|
|
13
|
+
|
|
14
|
+
# The markup (of class Markup) holds information on the tag (<li>), tag attributes (.. class='foo') and
|
|
15
|
+
# indentation information that should be used when rendered. This context is not inherited.
|
|
16
|
+
attr_accessor :markup
|
|
17
|
+
|
|
18
|
+
# We need this flag to detect cases like <r:with part='list' do='other list finder'/>
|
|
19
|
+
attr_reader :sub_do
|
|
20
|
+
|
|
21
|
+
def self.included(base)
|
|
22
|
+
base.before_parse :remove_erb
|
|
23
|
+
base.before_process :unescape_ruby
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# This callback is run just after the block is initialized (Parser#initialize).
|
|
27
|
+
def start(mode)
|
|
28
|
+
# tag_context
|
|
29
|
+
@markup = Markup.new(@options.delete(:html_tag))
|
|
30
|
+
|
|
31
|
+
# html_tag
|
|
32
|
+
if html_params = @options.delete(:html_tag_params)
|
|
33
|
+
@markup.params = html_params
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# end_tag is used to know when to close parsing in sub-do
|
|
37
|
+
# Example:
|
|
38
|
+
# <li do='each' do='images'>
|
|
39
|
+
# <ul>
|
|
40
|
+
# <li><r:link/></li> <!-- do not close outer LI now: @end_tag_count != 0 -->
|
|
41
|
+
# </ul>
|
|
42
|
+
# </li> <!-- close outer LI now: @end_tag_count == 0 -->
|
|
43
|
+
#
|
|
44
|
+
@end_tag = @markup.tag || @options.delete(:end_tag) || "r:#{@method}"
|
|
45
|
+
@end_tag_count = 1
|
|
46
|
+
|
|
47
|
+
# code indentation
|
|
48
|
+
@markup.space_before = @options.delete(:space_before)
|
|
49
|
+
|
|
50
|
+
if sub = @params.delete(:do)
|
|
51
|
+
# we have a sub 'do'
|
|
52
|
+
sub_method = sub.delete(:method)
|
|
53
|
+
|
|
54
|
+
# We need this flag to detect cases cases like <r:with part='list' do='other list finder'/>
|
|
55
|
+
@sub_do = true
|
|
56
|
+
|
|
57
|
+
opts = {:method => sub_method, :params => sub}
|
|
58
|
+
|
|
59
|
+
# the matching zafu tag will be parsed by the last 'do', we must inform it to halt properly :
|
|
60
|
+
opts[:end_tag] = @end_tag
|
|
61
|
+
|
|
62
|
+
sub = make(:void, opts)
|
|
63
|
+
@markup.space_after = sub.markup.space_after
|
|
64
|
+
sub.markup.space_after = ""
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# set name used for include/replace from html_tag if not already set by superclass
|
|
68
|
+
@name = extract_name
|
|
69
|
+
|
|
70
|
+
if !@markup.tag && (@markup.tag = @params.delete(:tag))
|
|
71
|
+
# Extract html tag parameters from @params
|
|
72
|
+
@markup.steal_html_params_from(@params)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
if @method == 'include' && @params[:template]
|
|
76
|
+
include_template
|
|
77
|
+
elsif mode == :tag && !sub
|
|
78
|
+
scan_tag
|
|
79
|
+
elsif !sub
|
|
80
|
+
enter(mode)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Used to debug parser.
|
|
85
|
+
def to_s
|
|
86
|
+
"[#{@method}#{@name.blank? ? '' : " '#{@name}'"}#{@params.empty? ? '' : " #{@params.map{|k,v| ":#{k}=>#{v.inspect}"}.join(', ')}"}]" + (@blocks||[]).join('') + "[/#{@method}]"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def extract_name
|
|
90
|
+
@options[:name] ||
|
|
91
|
+
(%w{input select textarea}.include?(@method) ? nil : @params[:name]) ||
|
|
92
|
+
@markup.params[:id] ||
|
|
93
|
+
@params[:id]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def remove_erb(text)
|
|
97
|
+
text.gsub('<%', '<%').gsub('%>', '%>').gsub(/<\Z/, '<')
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def unescape_ruby
|
|
101
|
+
@params.each do |k,v|
|
|
102
|
+
v.gsub!('>', '>')
|
|
103
|
+
v.gsub!('<', '<')
|
|
104
|
+
end
|
|
105
|
+
@method.gsub!('>', '>')
|
|
106
|
+
@method.gsub!('<', '<')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def single_child_method
|
|
110
|
+
return @single_child_method if defined?(@single_child_method)
|
|
111
|
+
@single_child_method = if @blocks.size == 1
|
|
112
|
+
single_child = @blocks[0]
|
|
113
|
+
return nil if single_child.kind_of?(String)
|
|
114
|
+
single_child.markup.tag ? nil : single_child.method
|
|
115
|
+
else
|
|
116
|
+
nil
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# scan rules
|
|
121
|
+
def scan
|
|
122
|
+
#puts "SCAN(#{@method}): [#{@text[0..20]}]"
|
|
123
|
+
if @text =~ %r{\A([^<]*?)(\s*)//!}m
|
|
124
|
+
# comment
|
|
125
|
+
found = $1
|
|
126
|
+
flush found
|
|
127
|
+
eat $2
|
|
128
|
+
scan_comment
|
|
129
|
+
elsif @text =~ /\A(([^<]*?)(^ *|))</m
|
|
130
|
+
# Warning: this regexp looks too complicated but it's the only one that
|
|
131
|
+
# works without capturing too much or not enough space in "space_before".
|
|
132
|
+
flush $2
|
|
133
|
+
space = $3
|
|
134
|
+
eat space
|
|
135
|
+
|
|
136
|
+
if @text[1..1] == '/'
|
|
137
|
+
store space
|
|
138
|
+
scan_close_tag
|
|
139
|
+
elsif %w{! ?}.include?(@text[1..1])
|
|
140
|
+
if @text[2..3] == '--'
|
|
141
|
+
store space
|
|
142
|
+
scan_html_comment
|
|
143
|
+
elsif @text[2..8] == '[CDATA['
|
|
144
|
+
# We do not flush because space has been eaten
|
|
145
|
+
store space
|
|
146
|
+
flush '<![CDATA['
|
|
147
|
+
elsif @text =~ /\A\s*<([^>]+)>/m
|
|
148
|
+
# Doctype/xml
|
|
149
|
+
flush $&
|
|
150
|
+
end
|
|
151
|
+
elsif $1.last == ' ' && @text[0..1] == '< '
|
|
152
|
+
# solitary ' < '
|
|
153
|
+
store space
|
|
154
|
+
flush '< '
|
|
155
|
+
scan
|
|
156
|
+
else
|
|
157
|
+
scan_tag(:space_before => space)
|
|
158
|
+
end
|
|
159
|
+
else
|
|
160
|
+
# no more tags
|
|
161
|
+
flush
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def scan_close_tag
|
|
166
|
+
if @text =~ /\A<\/([^>]+)>( *\n+|)/m
|
|
167
|
+
# puts "CLOSE:[#{$&}]}" # ztag
|
|
168
|
+
# closing tag
|
|
169
|
+
if $1 == @end_tag
|
|
170
|
+
@end_tag_count -= 1
|
|
171
|
+
if @end_tag_count == 0
|
|
172
|
+
eat $&
|
|
173
|
+
|
|
174
|
+
@markup.space_after = $2
|
|
175
|
+
leave
|
|
176
|
+
else
|
|
177
|
+
# keep the tag (false alert)
|
|
178
|
+
flush $&
|
|
179
|
+
end
|
|
180
|
+
elsif $1[0..1] == 'r:'
|
|
181
|
+
# /rtag
|
|
182
|
+
eat $&
|
|
183
|
+
if $1 != @end_tag
|
|
184
|
+
# error bad closing rtag
|
|
185
|
+
store "<span class='parser_error'>#{$&.gsub('<', '<').gsub('>','>')} should be </#{@end_tag}></span>"
|
|
186
|
+
end
|
|
187
|
+
leave
|
|
188
|
+
else
|
|
189
|
+
# other html tag closing
|
|
190
|
+
flush $&
|
|
191
|
+
end
|
|
192
|
+
else
|
|
193
|
+
# error
|
|
194
|
+
flush
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def scan_html_comment(opts={})
|
|
199
|
+
if @text =~ /\A<!--\|(.*?)-->/m
|
|
200
|
+
# zafu html escaped
|
|
201
|
+
#puts "ZAFU_HTML_ESCAPED[#{$&}]"
|
|
202
|
+
eat $&
|
|
203
|
+
@text = opts[:space_before] + $1 + @text
|
|
204
|
+
elsif @text =~ /\A<!--.*?-->/m
|
|
205
|
+
# html comment
|
|
206
|
+
#puts "HTML_COMMENT[#{$&}]"
|
|
207
|
+
flush $&
|
|
208
|
+
else
|
|
209
|
+
# error
|
|
210
|
+
flush
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def scan_comment
|
|
215
|
+
if @text =~ %r{\A//!.*(\n|\Z)}
|
|
216
|
+
# zafu html escaped
|
|
217
|
+
eat $&
|
|
218
|
+
else
|
|
219
|
+
# error
|
|
220
|
+
flush
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def get_params
|
|
225
|
+
params = Zafu::OrderedHash.new
|
|
226
|
+
raw = ''
|
|
227
|
+
while @text =~ PARAM_KEY_REGEXP
|
|
228
|
+
raw << $&
|
|
229
|
+
eat $&
|
|
230
|
+
key = $1
|
|
231
|
+
|
|
232
|
+
if @text =~ PARAM_VALUE_REGEXP
|
|
233
|
+
raw_t = $&
|
|
234
|
+
quote = $1
|
|
235
|
+
eat $&
|
|
236
|
+
value = $2.gsub("\\#{quote}", quote)
|
|
237
|
+
if key == 'do'
|
|
238
|
+
# Sub do
|
|
239
|
+
sub, raw = get_params
|
|
240
|
+
sub[:method] = value
|
|
241
|
+
params[:do] = sub
|
|
242
|
+
return params
|
|
243
|
+
else
|
|
244
|
+
raw << raw_t
|
|
245
|
+
params[key.to_sym] = value
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
return params, raw
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def scan_tag(opts={})
|
|
253
|
+
#puts "TAG(#{@method}): [#{@text[0..20]}]"
|
|
254
|
+
# FIXME: Better parameters parsing could avoid the > hack. Create a "scan_params" method.
|
|
255
|
+
if @text =~ /\A<r:([\w_]+\??)/
|
|
256
|
+
#puts "RTAG:#{$~.to_a.inspect}" # ztag
|
|
257
|
+
method = $1
|
|
258
|
+
eat $&
|
|
259
|
+
params, raw = get_params
|
|
260
|
+
#puts "AFTER(#{@method}): [#{@text[0..20]}]"
|
|
261
|
+
if @text =~ /\A\s*(\/?)>/
|
|
262
|
+
eat $&
|
|
263
|
+
opts.merge!(:method=>method, :params=>params)
|
|
264
|
+
opts.merge!(:text=>'') if $1 != ''
|
|
265
|
+
make(:void, opts)
|
|
266
|
+
else
|
|
267
|
+
# ERROR
|
|
268
|
+
flush
|
|
269
|
+
end
|
|
270
|
+
#elsif @text =~ /\A<(\w+)([^>]*?)do\s*=('([^>]*?[^\\]|)'|"([^>]*?[^\\]|)")([^>]*?)(\/?)>/
|
|
271
|
+
elsif @text =~ /\A<([\w:]+)/
|
|
272
|
+
html_tag = $1
|
|
273
|
+
eat $&
|
|
274
|
+
params, raw = get_params
|
|
275
|
+
|
|
276
|
+
#puts "HTML(#{html_tag}):[#{@text}]" # html tag
|
|
277
|
+
if @text =~ /\A\s*(\/?)>/
|
|
278
|
+
eat $&
|
|
279
|
+
is_end_tag = !$1.blank?
|
|
280
|
+
|
|
281
|
+
if sub = params.delete(:do)
|
|
282
|
+
# puts "SUB_DO:#{params.inspect}"
|
|
283
|
+
# do tag
|
|
284
|
+
method = sub.delete(:method)
|
|
285
|
+
opts.merge!(:text=>'') if is_end_tag
|
|
286
|
+
opts.merge!(
|
|
287
|
+
:html_tag => html_tag,
|
|
288
|
+
:html_tag_params => params,
|
|
289
|
+
:method => method,
|
|
290
|
+
:params => sub
|
|
291
|
+
)
|
|
292
|
+
make(:void, opts)
|
|
293
|
+
elsif raw =~ /\#\{/ || params[:id]
|
|
294
|
+
# puts "HTML_DYN|ID:#{@params.inspect}"
|
|
295
|
+
# If we have an :id, we need to store this as a block in case it is replaced
|
|
296
|
+
# html tag with dynamic params
|
|
297
|
+
opts.merge!(:text=>'') if is_end_tag
|
|
298
|
+
opts.merge!(:method => 'void', :html_tag => html_tag, :html_tag_params => params)
|
|
299
|
+
make(:void, opts)
|
|
300
|
+
elsif @end_tag && html_tag == @end_tag
|
|
301
|
+
#puts "PLAIN(END):#{@params.inspect}"
|
|
302
|
+
# plain html tag
|
|
303
|
+
store "#{opts[:space_before]}<#{html_tag}#{raw}#{is_end_tag ? '/' : ''}>"
|
|
304
|
+
@end_tag_count += 1 unless is_end_tag
|
|
305
|
+
elsif %w{link img script}.include?(html_tag)
|
|
306
|
+
#puts "ASSET: [#{@text}]"
|
|
307
|
+
opts.merge!(:text=>'') if is_end_tag
|
|
308
|
+
opts.merge!(:method => 'rename_asset', :html_tag_params => params, :params => params, :html_tag => html_tag)
|
|
309
|
+
make(:asset, opts)
|
|
310
|
+
else
|
|
311
|
+
#puts "PLAIN:<#{html_tag}#{raw}#{is_end_tag ? '/' : ''}>"
|
|
312
|
+
# plain html tag
|
|
313
|
+
store "#{opts[:space_before]}<#{html_tag}#{raw}#{is_end_tag ? '/' : ''}>"
|
|
314
|
+
end
|
|
315
|
+
else
|
|
316
|
+
# ERROR
|
|
317
|
+
flush
|
|
318
|
+
end
|
|
319
|
+
else
|
|
320
|
+
# unknown tag type
|
|
321
|
+
store %Q{<span class='parser_error'>Invalid tag near '#{@text[0..10].gsub('>','>').gsub('<','<')}'</span>}
|
|
322
|
+
@text = ''
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def scan_asset
|
|
327
|
+
@end_tag = @markup.tag
|
|
328
|
+
if @markup.tag == 'script'
|
|
329
|
+
enter(:void)
|
|
330
|
+
else
|
|
331
|
+
enter(:inside_asset)
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def scan_inside_asset
|
|
336
|
+
if @text =~ /\A(.*?)<\/#{@end_tag.gsub('?', '\\?')}>/m
|
|
337
|
+
eat $&
|
|
338
|
+
store $1
|
|
339
|
+
leave(:asset)
|
|
340
|
+
else
|
|
341
|
+
# never ending asset
|
|
342
|
+
flush
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# Helper during compilation to make a block
|
|
347
|
+
def add_block(text_or_opts, at_start = false)
|
|
348
|
+
# avoid wrapping objects in [void][/void]
|
|
349
|
+
bak = @blocks
|
|
350
|
+
@blocks = []
|
|
351
|
+
if text_or_opts.kind_of?(String)
|
|
352
|
+
new_blocks = make(:void, :method => 'void', :text => text_or_opts).blocks
|
|
353
|
+
else
|
|
354
|
+
new_blocks = [make(:void, text_or_opts)]
|
|
355
|
+
end
|
|
356
|
+
if at_start
|
|
357
|
+
bak = new_blocks + bak
|
|
358
|
+
else
|
|
359
|
+
bak += new_blocks
|
|
360
|
+
end
|
|
361
|
+
@blocks = bak
|
|
362
|
+
# Force descendants rebuild
|
|
363
|
+
@all_descendants = nil
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Helper during compilation to wrap current content in a new block
|
|
367
|
+
def wrap_in_block(text_or_opts)
|
|
368
|
+
# avoid wrapping objects in [void][/void]
|
|
369
|
+
bak = @blocks
|
|
370
|
+
@blocks = []
|
|
371
|
+
if text_or_opts.kind_of?(String)
|
|
372
|
+
wrapper = make(:void, :method => 'void', :text => text_or_opts)
|
|
373
|
+
else
|
|
374
|
+
wrapper = make(:void, text_or_opts)
|
|
375
|
+
end
|
|
376
|
+
wrapper.blocks = bak
|
|
377
|
+
@blocks = [wrapper]
|
|
378
|
+
# Force descendants rebuild
|
|
379
|
+
@all_descendants = nil
|
|
380
|
+
end
|
|
381
|
+
end # ParsingRules
|
|
382
|
+
end # Zafu
|
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
module Zafu
|
|
2
|
+
module Process
|
|
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
|
+
@context.delete(:make_form) # Do not propagate.
|
|
12
|
+
return super unless finder[:class].kind_of?(Array)
|
|
13
|
+
|
|
14
|
+
# reset scope
|
|
15
|
+
@context[:saved_template] = nil
|
|
16
|
+
|
|
17
|
+
# Get the block responsible for rendering each elements in the list
|
|
18
|
+
each_block = descendant('each')
|
|
19
|
+
add_block = descendant('add')
|
|
20
|
+
form_block = descendant('form') || each_block
|
|
21
|
+
edit_block = descendant('edit')
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Should 'edit' and 'add' auto-publish ?
|
|
25
|
+
publish_after_save = (form_block && form_block.params[:publish]) ||
|
|
26
|
+
(edit_block && edit_block.params[:publish])
|
|
27
|
+
|
|
28
|
+
# class name for create form
|
|
29
|
+
if class_name = (add_block && add_block.params[:klass]) ||
|
|
30
|
+
(form_block && form_block.params[:klass])
|
|
31
|
+
unless klass = get_class(class_name)
|
|
32
|
+
return parser_error("Invalid class '#{class_name}'")
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
klass = finder[:class].first
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if need_ajax?(each_block)
|
|
39
|
+
# 1. Render inline
|
|
40
|
+
# assign [] to var
|
|
41
|
+
out "<% if (#{var} = #{finder[:method]}) || (#{node}.#{finder[:class].first <= Comment ? "can_comment?" : "can_write?"} && #{var}=[]) %>"
|
|
42
|
+
# The list is not empty or we have enough rights to add new elements.
|
|
43
|
+
|
|
44
|
+
# New node context.
|
|
45
|
+
open_node_context(finder, :node => self.node.move_to(var, finder[:class])) do
|
|
46
|
+
# Pagination count and other contextual variables exist here.
|
|
47
|
+
|
|
48
|
+
tmplt_node = self.node.move_to(var, finder[:class])
|
|
49
|
+
# Own scope
|
|
50
|
+
node.dom_prefix = dom_name
|
|
51
|
+
tmplt_node.dom_prefix = dom_name
|
|
52
|
+
|
|
53
|
+
# INLINE ==========
|
|
54
|
+
out wrap(
|
|
55
|
+
expand_with(
|
|
56
|
+
:in_if => false,
|
|
57
|
+
# 'r_add' needs the form when rendering. Send with :form.
|
|
58
|
+
:form => form_block,
|
|
59
|
+
:publish_after_save => publish_after_save,
|
|
60
|
+
# Do not render the form block directly: let [add] do this.
|
|
61
|
+
:ignore => ['form'],
|
|
62
|
+
:klass => klass
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Render 'else' clauses
|
|
67
|
+
else_clauses = expand_with(
|
|
68
|
+
:in_if => true,
|
|
69
|
+
:only => ['elsif', 'else'],
|
|
70
|
+
:markup => @markup
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# 2. Save 'each' template
|
|
74
|
+
store_block(each_block, :node => tmplt_node)
|
|
75
|
+
|
|
76
|
+
# 3. Save 'form' template
|
|
77
|
+
cont = {
|
|
78
|
+
:saved_template => form_url(tmplt_node.dom_prefix),
|
|
79
|
+
:klass => klass,
|
|
80
|
+
:make_form => each_block == form_block,
|
|
81
|
+
# Used to get parameters like 'publish', 'done', 'after'
|
|
82
|
+
:add => add_block,
|
|
83
|
+
:publish_after_save => publish_after_save,
|
|
84
|
+
:new_keys => {:parent_id => '@node.parent_zip'}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
store_block(form_block, cont)
|
|
88
|
+
end
|
|
89
|
+
out "<% end %>"
|
|
90
|
+
else
|
|
91
|
+
super
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# out wrap(expand_with(:node => node.move_to(var, finder[:class]), :in_if => true))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
#query = opts[:query]
|
|
98
|
+
#
|
|
99
|
+
#
|
|
100
|
+
#if need_ajax?
|
|
101
|
+
# new_dom_scope
|
|
102
|
+
# # ajax, build template. We could merge the following code with 'r_block'.
|
|
103
|
+
#
|
|
104
|
+
# # FORM ============
|
|
105
|
+
# if each_block != form_block
|
|
106
|
+
# form = expand_block(form_block, :klass => klass, :add=>add_block, :publish_after_save => publish_after_save, :saved_template => true)
|
|
107
|
+
# else
|
|
108
|
+
# form = expand_block(form_block, :klass => klass, :add=>add_block, :make_form=>true, :publish_after_save => publish_after_save, :saved_template => true)
|
|
109
|
+
# end
|
|
110
|
+
# out helper.save_erb_to_url(form, form_url)
|
|
111
|
+
#else
|
|
112
|
+
# # no form, render, edit and add are not ajax
|
|
113
|
+
# if descendant('add') || descendant('add_document')
|
|
114
|
+
# out "<% if (#{list_var} = #{list_finder}) || (#{node}.#{node.will_be?(Comment) ? "can_comment?" : "can_write?"} && #{list_var}=[]) %>"
|
|
115
|
+
# elsif list_finder != 'nil'
|
|
116
|
+
# out "<% if #{list_var} = #{list_finder} %>"
|
|
117
|
+
# else
|
|
118
|
+
# out "<% if nil %>"
|
|
119
|
+
# end
|
|
120
|
+
#
|
|
121
|
+
#
|
|
122
|
+
# out render_html_tag(expand_with(:list=>list_var, :in_if => false))
|
|
123
|
+
# out expand_with(:in_if=>true, :only=>['elsif', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
|
|
124
|
+
# out "<% end %>"
|
|
125
|
+
#end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Store a context as a sub-template that can be used in ajax calls
|
|
129
|
+
def r_block
|
|
130
|
+
if parent.method == 'each' && @method == parent.single_child_method
|
|
131
|
+
# Block stored in 'each', do nothing
|
|
132
|
+
# What happens when this is used as remote target ?
|
|
133
|
+
return expand_with
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
@markup.done = false
|
|
137
|
+
|
|
138
|
+
if @context[:block] == self
|
|
139
|
+
# Storing our block template
|
|
140
|
+
#node.dom_prefix = dom_name
|
|
141
|
+
@markup.set_id(node.dom_id(:list => false))
|
|
142
|
+
@markup.set_dyn_param(:"data-z", "<%= #{node}.zip %>")
|
|
143
|
+
expand_with
|
|
144
|
+
elsif @context[:saved_template]
|
|
145
|
+
# already in a parent's store operation. Reset scope and simply render inline elements
|
|
146
|
+
# reset scope
|
|
147
|
+
with_context(:node => node.dup, :saved_template => nil) do
|
|
148
|
+
node.saved_dom_id = nil
|
|
149
|
+
node.dom_prefix = dom_name
|
|
150
|
+
@markup.set_id(node.dom_id(:list => false))
|
|
151
|
+
expand_with
|
|
152
|
+
end
|
|
153
|
+
else
|
|
154
|
+
# Since we are using ajax, we will need this object to have an ID set and
|
|
155
|
+
# have its own template_url and such.
|
|
156
|
+
with_context(:node => node.dup, :saved_template => nil) do
|
|
157
|
+
# reset scope. We only keep current id when we are called from
|
|
158
|
+
# r_drop.
|
|
159
|
+
@markup = @markup.dup
|
|
160
|
+
@markup.set_id(nil)
|
|
161
|
+
node.saved_dom_id = nil
|
|
162
|
+
# our own domain
|
|
163
|
+
node.dom_prefix = dom_name
|
|
164
|
+
|
|
165
|
+
# 1. inline
|
|
166
|
+
# Set id with the current node context (<%= var1.zip %>).
|
|
167
|
+
@markup.set_id(node.dom_id(:list => false))
|
|
168
|
+
if node.dom_id(:list => false) != node.dom_prefix
|
|
169
|
+
@markup.set_param(:"data-t", node.dom_prefix)
|
|
170
|
+
end
|
|
171
|
+
@markup.set_dyn_param(:"data-z", "<%= #{node}.zip %>")
|
|
172
|
+
|
|
173
|
+
out expand_with
|
|
174
|
+
# 2. store template
|
|
175
|
+
# will wrap with @markup
|
|
176
|
+
store_block(self, :ajax_action => 'show')
|
|
177
|
+
|
|
178
|
+
if edit_block = descendant('edit')
|
|
179
|
+
form_block = descendant('form') || self
|
|
180
|
+
|
|
181
|
+
publish_after_save = form_block.params[:publish] ||
|
|
182
|
+
(edit_block && edit_block.params[:publish])
|
|
183
|
+
|
|
184
|
+
# 3. store form
|
|
185
|
+
cont = {
|
|
186
|
+
:saved_template => form_url(node.dom_prefix),
|
|
187
|
+
:make_form => self == form_block,
|
|
188
|
+
:publish_after_save => publish_after_save,
|
|
189
|
+
:ajax_action => 'edit',
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
store_block(form_block, cont)
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def r_edit
|
|
200
|
+
# ajax
|
|
201
|
+
if cancel = @context[:form_cancel]
|
|
202
|
+
# cancel button
|
|
203
|
+
out cancel
|
|
204
|
+
else
|
|
205
|
+
# edit button
|
|
206
|
+
|
|
207
|
+
# TODO: show 'reply' instead of 'edit' in comments if visitor != author
|
|
208
|
+
block = ancestor(%w{each block})
|
|
209
|
+
|
|
210
|
+
# These parameters are detected by r_block and set in form.
|
|
211
|
+
# removed so they do not polute link
|
|
212
|
+
@params.delete(:publish)
|
|
213
|
+
@params.delete(:cancel)
|
|
214
|
+
@params.delete(:tcancel)
|
|
215
|
+
|
|
216
|
+
link = wrap(make_link(:default_text => _('edit'), :update => block, :action => 'edit'))
|
|
217
|
+
|
|
218
|
+
out "<% if #{node}.can_write? %>#{link}<% end %>"
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def r_cancel
|
|
223
|
+
r_edit
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def r_add
|
|
227
|
+
return parser_error("Should not be called from within 'each'") if parent.method == 'each'
|
|
228
|
+
return parser_error("Should not be called outside list context") unless node.list_context?
|
|
229
|
+
return '' if @context[:make_form]
|
|
230
|
+
|
|
231
|
+
if node.will_be?(Comment)
|
|
232
|
+
out "<% if #{node.up(Node)}.can_comment? %>"
|
|
233
|
+
else
|
|
234
|
+
out "<% if #{node.up(Node)}.can_write? %>"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
unless descendant('add_btn')
|
|
238
|
+
# Add a descendant between self and blocks. ==> add( add_btn(blocks) )
|
|
239
|
+
blocks = @blocks.dup
|
|
240
|
+
@blocks = []
|
|
241
|
+
add_btn = make(:void, :method => 'add_btn', :params => @params.dup, :text => '')
|
|
242
|
+
add_btn.blocks = blocks
|
|
243
|
+
@all_descendants = nil
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
if @context[:form]
|
|
247
|
+
# ajax add
|
|
248
|
+
@markup.set_id("#{node.dom_prefix}_add")
|
|
249
|
+
@markup.append_param(:class, 'btn_add')
|
|
250
|
+
|
|
251
|
+
if @params[:focus]
|
|
252
|
+
focus = "$(\"#{node.dom_prefix}_#{@params[:focus]}\").focus();"
|
|
253
|
+
else
|
|
254
|
+
focus = "$(\"#{node.dom_prefix}_form_t\").focusFirstElement();"
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Expand 'add' block
|
|
258
|
+
out wrap("#{expand_with(:onclick=>"[\"#{node.dom_prefix}_add\", \"#{node.dom_prefix}_0\"].each(Element.toggle);#{focus}return false;")}")
|
|
259
|
+
|
|
260
|
+
klass = @context[:klass] || node.single_class
|
|
261
|
+
|
|
262
|
+
# New object to render form.
|
|
263
|
+
new_node = node.move_to("#{var}_new", klass, :new_keys => {})
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
if new_node.will_be?(Node)
|
|
267
|
+
# FIXME: BUG if we set <r:form klass='Post'/> the user cannot select class with menu...
|
|
268
|
+
|
|
269
|
+
if @context[:saved_template]
|
|
270
|
+
parent_id = "#{node}.parent_zip"
|
|
271
|
+
else
|
|
272
|
+
parent_id = "#{node(Node)}.zip"
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
new_node.opts[:new_keys]['parent_id'] = parent_id
|
|
276
|
+
|
|
277
|
+
# FIXME: inspect '@context[:form]' to see if it contains v_klass ?
|
|
278
|
+
out "<% if #{new_node} = secure(Node) { Node.new_node('class' => '#{new_node.klass}', 'parent_id' => #{parent_id}) } %>"
|
|
279
|
+
# if node.will_be?(Node)
|
|
280
|
+
# # Nested contexts:
|
|
281
|
+
# # 1. @node
|
|
282
|
+
# # 2. var1 = @node.children
|
|
283
|
+
# # 3. var1_new = Node.new
|
|
284
|
+
# if node.opts[:new_record] || @context[:saved_template]
|
|
285
|
+
# if @context[:saved_template] || !@context[:in_add]
|
|
286
|
+
# # TODO: we should not add parent_id on every saved_template. Why is this needed ?
|
|
287
|
+
# parent_id = "#{node}.parent_zip"
|
|
288
|
+
# else
|
|
289
|
+
# # We are in var2_new
|
|
290
|
+
# parent_id = "#{node.up(Node)}.zip"
|
|
291
|
+
# end
|
|
292
|
+
#
|
|
293
|
+
# hidden_fields['node[parent_id]'] = "<%= #{parent_id} %>"
|
|
294
|
+
# end
|
|
295
|
+
# els
|
|
296
|
+
else
|
|
297
|
+
out "<% if #{new_node} = #{new_node.class_name}.new %>"
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
form_block = @context[:form]
|
|
301
|
+
|
|
302
|
+
# Expand (inline) 'form' block
|
|
303
|
+
out expand_block(form_block,
|
|
304
|
+
# Needed in form to be able to return the result
|
|
305
|
+
:template_url => template_url(node.dom_prefix),
|
|
306
|
+
# Used to avoid wrong dom_id in hidden form. Should not be
|
|
307
|
+
# necessary but it's hard to fix when node changes a lot (drop in add).
|
|
308
|
+
:dom_prefix => node.dom_prefix,
|
|
309
|
+
# Used to add needed hidden fields in form
|
|
310
|
+
:in_add => true,
|
|
311
|
+
# Used to get parameters like 'publish' or 'klass'
|
|
312
|
+
:add => self,
|
|
313
|
+
# Transform 'each' block into a form
|
|
314
|
+
:make_form => form_block.method == 'each',
|
|
315
|
+
# Node context = new node
|
|
316
|
+
:node => new_node
|
|
317
|
+
)
|
|
318
|
+
out "<% end %>"
|
|
319
|
+
else
|
|
320
|
+
# no ajax
|
|
321
|
+
@markup.append_param(:class, 'btn_add') if @markup.tag
|
|
322
|
+
out wrap(expand_with)
|
|
323
|
+
end
|
|
324
|
+
out "<% end %>"
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def r_add_btn
|
|
328
|
+
default = node.will_be?(Comment) ? _("btn_add_comment") : _("btn_add")
|
|
329
|
+
|
|
330
|
+
out "<a href='javascript:void(0)' onclick='#{@context[:onclick]}'>#{text_for_link(default)}</a>"
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def r_each
|
|
334
|
+
if @context[:saved_template]
|
|
335
|
+
# render to start a saved template
|
|
336
|
+
node.saved_dom_id = "\#{ndom_id(#{node})}"
|
|
337
|
+
node.dom_prefix = dom_name unless node.raw_dom_prefix
|
|
338
|
+
node.propagate_dom_scope!
|
|
339
|
+
@markup.set_id(node.dom_id)
|
|
340
|
+
|
|
341
|
+
options = form_options
|
|
342
|
+
@markup.set_param(:style, options[:style]) if options[:style]
|
|
343
|
+
|
|
344
|
+
out wrap(expand_with)
|
|
345
|
+
else
|
|
346
|
+
super
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Block visibility of descendance with 'do_list'.
|
|
351
|
+
def public_descendants
|
|
352
|
+
all = super
|
|
353
|
+
if ['context', 'each', 'block'].include?(method)
|
|
354
|
+
# do not propagate 'form',etc up
|
|
355
|
+
all.reject do |k,v|
|
|
356
|
+
# FIXME: Zena leakage
|
|
357
|
+
['form','unlink', 'count'].include?(k)
|
|
358
|
+
end
|
|
359
|
+
elsif ['if', 'case'].include?(method) || (method =~ /^[A-Z]/)
|
|
360
|
+
# conditional
|
|
361
|
+
all.reject do |k,v|
|
|
362
|
+
['else', 'elsif', 'when'].include?(k)
|
|
363
|
+
end
|
|
364
|
+
else
|
|
365
|
+
all
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# Return true if we need to insert the dom id for this element.
|
|
370
|
+
def need_dom_id?
|
|
371
|
+
@context[:form] || child['unlink'] || (single_child_method && single_child_method == child['drop'])
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Unique template_url, ending with dom_id
|
|
375
|
+
def template_url(dom_prefix = node.dom_prefix)
|
|
376
|
+
"#{root.options[:root]}/#{dom_prefix}"
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def form_url(dom_prefix = node.dom_prefix)
|
|
380
|
+
template_url(dom_prefix) + '_form'
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# Return object id (or name). Sets name when needed.
|
|
384
|
+
# Context is passed when the parent needs to set dom_name on a child
|
|
385
|
+
# before @context is passed down.
|
|
386
|
+
def dom_name(context = @context)
|
|
387
|
+
@dom_name ||= unique_name(context)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# Return a different name on each call
|
|
391
|
+
def unique_name(context = @context)
|
|
392
|
+
base = @name || context[:name] || 'list'
|
|
393
|
+
root.get_unique_name(base, base == @name).gsub(/[^\d\w\/]/,'_')
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def get_unique_name(key, own_id = false)
|
|
397
|
+
@next_name_index ||= {}
|
|
398
|
+
if @next_name_index[key]
|
|
399
|
+
@next_name_index[key] += 1
|
|
400
|
+
key + @next_name_index[key].to_s
|
|
401
|
+
elsif own_id
|
|
402
|
+
@next_name_index[key] = 0
|
|
403
|
+
key
|
|
404
|
+
else
|
|
405
|
+
@next_name_index[key] = 1
|
|
406
|
+
key + '1'
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
protected
|
|
411
|
+
|
|
412
|
+
def need_ajax?(each_block)
|
|
413
|
+
return false unless each_block
|
|
414
|
+
# Inline editable
|
|
415
|
+
each_block.descendant('edit') ||
|
|
416
|
+
# Ajax add
|
|
417
|
+
descendant('add') ||
|
|
418
|
+
# List is reloaded from the 'add_document' popup
|
|
419
|
+
descendant('add_document') ||
|
|
420
|
+
# We use 'each' as block instead of the declared 'block' or 'drop'
|
|
421
|
+
['block', 'drop'].include?(each_block.single_child_method)
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def context_for_partial(cont)
|
|
425
|
+
context_without_vars.merge(cont)
|
|
426
|
+
end
|
|
427
|
+
private
|
|
428
|
+
|
|
429
|
+
# Find a block to update on the page
|
|
430
|
+
def find_target(name)
|
|
431
|
+
# Hack for drop until descendants is rebuilt on set_dom_prefix
|
|
432
|
+
return self if name == self.name
|
|
433
|
+
|
|
434
|
+
root.descendants('block').each do |block|
|
|
435
|
+
return block if block.name == name
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
out parser_error("could not find a block named '#{name}'")
|
|
439
|
+
return nil
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def store_block(block, cont = {})
|
|
443
|
+
cont, prefix = context_for_partial(cont)
|
|
444
|
+
|
|
445
|
+
# Create new node context
|
|
446
|
+
node = cont[:node].as_main(ActiveRecord::Base)
|
|
447
|
+
node.opts[:new_keys] = cont.delete(:new_keys)
|
|
448
|
+
|
|
449
|
+
# The dom_id will be calculated from the Ajax params in the view.
|
|
450
|
+
node.saved_dom_id = "\#{ndom_id(#{node})}"
|
|
451
|
+
|
|
452
|
+
cont[:template_url] = template_url(node.dom_prefix)
|
|
453
|
+
cont[:node] = node
|
|
454
|
+
cont[:block] = block
|
|
455
|
+
cont[:saved_template] ||= cont[:template_url]
|
|
456
|
+
|
|
457
|
+
template = nil
|
|
458
|
+
|
|
459
|
+
# We overwrite all context: no merge.
|
|
460
|
+
with_context(cont, false) do
|
|
461
|
+
template = prefix.to_s + expand_block(block)
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
out helper.save_erb_to_url(template, cont[:saved_template])
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
#template = expand_block(self, :)
|
|
468
|
+
#
|
|
469
|
+
#if @context[:block] == self
|
|
470
|
+
# # called from self (storing template)
|
|
471
|
+
# @context.reject! do |k,v|
|
|
472
|
+
# # FIXME: reject all stored elements in a better way then this
|
|
473
|
+
# k.kind_of?(String) && k =~ /\ANode_\w/
|
|
474
|
+
# end
|
|
475
|
+
# @markup.done = false
|
|
476
|
+
# @markup.params.merge!(:id=>node.dom_id)
|
|
477
|
+
# @context[:scope_node] = node if @context[:scope_node]
|
|
478
|
+
# out expand_with(:node => node)
|
|
479
|
+
# if @method == 'drop' && !@context[:make_form]
|
|
480
|
+
# out drop_javascript
|
|
481
|
+
# end
|
|
482
|
+
#else
|
|
483
|
+
# if parent.method == 'each' && @method == parent.single_child_method
|
|
484
|
+
# # use parent as block
|
|
485
|
+
# # FIXME: will not work with block as distant target...
|
|
486
|
+
# # do nothing
|
|
487
|
+
# else
|
|
488
|
+
# @markup.tag ||= 'div'
|
|
489
|
+
# new_dom_scope
|
|
490
|
+
#
|
|
491
|
+
# unless @context[:make_form]
|
|
492
|
+
# # STORE TEMPLATE ========
|
|
493
|
+
#
|
|
494
|
+
# context_bak = @context.dup # avoid side effects when rendering the same block
|
|
495
|
+
# ignore_list = @method == 'block' ? ['form'] : [] # do not show the form in the normal template of a block
|
|
496
|
+
# template = expand_block(self, :block=>self, :list=>false, :saved_template=>true, :ignore => ignore_list)
|
|
497
|
+
# @context = context_bak
|
|
498
|
+
# @result = ''
|
|
499
|
+
# out helper.save_erb_to_url(template, template_url)
|
|
500
|
+
#
|
|
501
|
+
# # STORE FORM ============
|
|
502
|
+
# if edit = descendant('edit')
|
|
503
|
+
# publish_after_save = (edit.params[:publish] == 'true')
|
|
504
|
+
# if form = descendant('form')
|
|
505
|
+
# # USE BLOCK FORM ========
|
|
506
|
+
# form_text = expand_block(form, :saved_template=>true, :publish_after_save => publish_after_save)
|
|
507
|
+
# else
|
|
508
|
+
# # MAKE A FORM FROM BLOCK ========
|
|
509
|
+
# form = self.dup
|
|
510
|
+
# form.method = 'form'
|
|
511
|
+
# form_text = expand_block(form, :make_form => true, :list => false, :saved_template => true, :publish_after_save => publish_after_save)
|
|
512
|
+
# end
|
|
513
|
+
# out helper.save_erb_to_url(form_text, form_url)
|
|
514
|
+
# end
|
|
515
|
+
# end
|
|
516
|
+
#
|
|
517
|
+
# # RENDER
|
|
518
|
+
# @markup.done = false
|
|
519
|
+
# @markup.params.merge!(:id=>node.dom_id)
|
|
520
|
+
# end
|
|
521
|
+
#
|
|
522
|
+
# out expand_with
|
|
523
|
+
# if @method == 'drop' && !@context[:make_form]
|
|
524
|
+
# out drop_javascript
|
|
525
|
+
# end
|
|
526
|
+
#end
|
|
527
|
+
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
end
|