mullet 0.0.0 → 0.0.1
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/lib/mullet/container.rb +8 -4
- data/lib/mullet/default_model.rb +9 -9
- data/lib/mullet/default_nested_model.rb +7 -6
- data/lib/mullet/html/attribute_command.rb +8 -4
- data/lib/mullet/html/attributes.rb +22 -0
- data/lib/mullet/html/command.rb +4 -3
- data/lib/mullet/html/command_element_renderer.rb +19 -0
- data/lib/mullet/html/element.rb +41 -0
- data/lib/mullet/html/element_renderer.rb +261 -0
- data/lib/mullet/html/filtered_element_handler.rb +87 -0
- data/lib/mullet/html/for_element_renderer.rb +47 -0
- data/lib/mullet/html/if_element_renderer.rb +46 -0
- data/lib/mullet/html/layout.rb +48 -0
- data/lib/mullet/html/message.rb +55 -0
- data/lib/mullet/html/message_attribute_command.rb +30 -0
- data/lib/mullet/html/model_attribute_command.rb +30 -0
- data/lib/mullet/html/page_builder.rb +152 -0
- data/lib/mullet/html/parser/attribute.rb +8 -0
- data/lib/mullet/html/parser/constants.rb +1061 -0
- data/lib/mullet/html/parser/default_handler.rb +27 -0
- data/lib/mullet/html/parser/input_stream.rb +711 -0
- data/lib/mullet/html/parser/open_element.rb +77 -0
- data/lib/mullet/html/parser/simple_parser.rb +128 -0
- data/lib/mullet/html/parser/tokenizer.rb +1085 -0
- data/lib/mullet/html/remove_mode.rb +30 -0
- data/lib/mullet/html/static_text_renderer.rb +20 -0
- data/lib/mullet/html/template.rb +44 -0
- data/lib/mullet/html/template_builder.rb +208 -63
- data/lib/mullet/html/template_loader.rb +77 -39
- data/lib/mullet/html/template_parser.rb +48 -0
- data/lib/mullet/html/unless_element_renderer.rb +24 -0
- data/lib/mullet/model.rb +2 -5
- data/lib/mullet/render_context.rb +24 -18
- data/lib/mullet/tilt.rb +37 -0
- data/lib/mullet/version.rb +2 -1
- data/lib/mullet.rb +1 -0
- metadata +58 -11
data/lib/mullet/container.rb
CHANGED
@@ -8,24 +8,28 @@ module Mullet
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def add_child(child)
|
11
|
-
@children
|
11
|
+
@children.push(child)
|
12
12
|
end
|
13
13
|
|
14
14
|
def delete_child(child)
|
15
15
|
@children.delete(child);
|
16
16
|
end
|
17
17
|
|
18
|
+
def children()
|
19
|
+
return @children
|
20
|
+
end
|
21
|
+
|
18
22
|
def clear_children()
|
19
23
|
@children.clear()
|
20
24
|
end
|
21
25
|
|
22
26
|
# Renders children in order they were added.
|
23
27
|
#
|
24
|
-
# @param [RenderContext]
|
28
|
+
# @param [RenderContext] render_context
|
25
29
|
# render context
|
26
|
-
def render_children(
|
30
|
+
def render_children(render_context)
|
27
31
|
@children.each do |child|
|
28
|
-
child.render(
|
32
|
+
child.render(render_context)
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
data/lib/mullet/default_model.rb
CHANGED
@@ -22,27 +22,27 @@ module Mullet
|
|
22
22
|
@data = data
|
23
23
|
end
|
24
24
|
|
25
|
-
def fetch_impl(
|
26
|
-
if
|
25
|
+
def fetch_impl(name)
|
26
|
+
if name == :this
|
27
27
|
return @data
|
28
28
|
end
|
29
29
|
|
30
30
|
# Is the variable name a key in a Hash?
|
31
31
|
if @data.respond_to?(:fetch)
|
32
32
|
# Call the block if the key is not found.
|
33
|
-
return @data.fetch(
|
33
|
+
return @data.fetch(name) {|k| @data.fetch(k.to_s(), NOT_FOUND) }
|
34
34
|
end
|
35
35
|
|
36
36
|
# Does the variable name match a method name in the object?
|
37
|
-
if @data.respond_to?(
|
38
|
-
method = @data.method(
|
37
|
+
if @data.respond_to?(name)
|
38
|
+
method = @data.method(name)
|
39
39
|
if method.arity == 0
|
40
40
|
return method.call()
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
# Does the variable name match an instance variable name in the object?
|
45
|
-
variable = :"@#{
|
45
|
+
variable = :"@#{name}"
|
46
46
|
if @data.instance_variable_defined?(variable)
|
47
47
|
return @data.instance_variable_get(variable)
|
48
48
|
end
|
@@ -52,11 +52,11 @@ module Mullet
|
|
52
52
|
|
53
53
|
# Resolves variable name to value.
|
54
54
|
#
|
55
|
-
# @param [Symbol]
|
55
|
+
# @param [Symbol] name
|
56
56
|
# variable name
|
57
57
|
# @return variable value
|
58
|
-
def
|
59
|
-
value = fetch_impl(
|
58
|
+
def get_variable_value(name)
|
59
|
+
value = fetch_impl(name)
|
60
60
|
if value.is_a?(Proc)
|
61
61
|
value = value.call()
|
62
62
|
end
|
@@ -18,18 +18,18 @@ module Mullet
|
|
18
18
|
|
19
19
|
# Resolves variable name to value.
|
20
20
|
#
|
21
|
-
# @param [Symbol]
|
21
|
+
# @param [Symbol] name
|
22
22
|
# variable name
|
23
23
|
# @return variable value
|
24
|
-
def
|
24
|
+
def get_variable_value(name)
|
25
25
|
@scopes.reverse_each do |scope|
|
26
|
-
value = scope.
|
27
|
-
if value !=
|
26
|
+
value = scope.get_variable_value(name)
|
27
|
+
if value != NOT_FOUND
|
28
28
|
return value
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
return
|
32
|
+
return NOT_FOUND
|
33
33
|
end
|
34
34
|
|
35
35
|
# Adds a nested scope to search in subsequent lookups.
|
@@ -37,7 +37,8 @@ module Mullet
|
|
37
37
|
# @param data
|
38
38
|
# data object
|
39
39
|
def push_scope(data)
|
40
|
-
@scopes.push(
|
40
|
+
@scopes.push(
|
41
|
+
data.respond_to?(:get_variable_value) ? data : DefaultModel.new(data))
|
41
42
|
end
|
42
43
|
|
43
44
|
# Removes innermost nested scope.
|
@@ -1,6 +1,10 @@
|
|
1
|
-
|
1
|
+
require 'mullet/model'
|
2
2
|
|
3
|
-
|
3
|
+
module Mullet; module HTML
|
4
|
+
|
5
|
+
# Operation to set attribute value. Classes including this module are
|
6
|
+
# expected to respond to the get_value method returning the attribute value
|
7
|
+
# to set.
|
4
8
|
module AttributeCommand
|
5
9
|
|
6
10
|
# Constructor
|
@@ -11,7 +15,7 @@ module Mullet
|
|
11
15
|
@attribute_name = attribute_name
|
12
16
|
end
|
13
17
|
|
14
|
-
# Sets attribute in the
|
18
|
+
# Sets attribute in the _attributes_ collection.
|
15
19
|
#
|
16
20
|
# @param [RenderContext] render_context
|
17
21
|
# render context
|
@@ -29,4 +33,4 @@ module Mullet
|
|
29
33
|
end
|
30
34
|
end
|
31
35
|
|
32
|
-
end
|
36
|
+
end; end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Mullet; module HTML
|
2
|
+
|
3
|
+
# Maps attribute names to values. Also renders attributes to HTML.
|
4
|
+
class Attributes < Hash
|
5
|
+
|
6
|
+
def escape_quote(value)
|
7
|
+
return value.include?('"') ? value.gsub(/"/, '"') : value
|
8
|
+
end
|
9
|
+
|
10
|
+
# Renders attributes to HTML syntax.
|
11
|
+
#
|
12
|
+
# @return rendered HTML
|
13
|
+
def render()
|
14
|
+
output = ''
|
15
|
+
each do |key, value|
|
16
|
+
output << %( #{key}="#{escape_quote(value)}")
|
17
|
+
end
|
18
|
+
return output
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end; end
|
data/lib/mullet/html/command.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
module Mullet
|
1
|
+
module Mullet; module HTML
|
2
2
|
|
3
3
|
# Recognized template commands
|
4
4
|
module Command
|
5
|
-
|
5
|
+
DATA_PREFIX = 'data-'
|
6
|
+
NAMESPACE_PREFIX = 'mullet'
|
6
7
|
NAMESPACE_URI = 'http://pukkaone.github.com/mullet/1'
|
7
8
|
|
8
9
|
ACTION = 'action'
|
@@ -26,4 +27,4 @@ module Mullet
|
|
26
27
|
VALUE_MESSAGE = 'value-message'
|
27
28
|
end
|
28
29
|
|
29
|
-
end
|
30
|
+
end; end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Mullet; module HTML
|
2
|
+
|
3
|
+
# Answers true when asked if it has any command.
|
4
|
+
class CommandElementRenderer < ElementRenderer
|
5
|
+
|
6
|
+
# Constructor
|
7
|
+
#
|
8
|
+
# @param [Element] element
|
9
|
+
# element to render
|
10
|
+
def initialize(element)
|
11
|
+
super(element)
|
12
|
+
end
|
13
|
+
|
14
|
+
def has_command()
|
15
|
+
return true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end; end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Mullet; module HTML
|
2
|
+
|
3
|
+
# HTML element
|
4
|
+
class Element
|
5
|
+
|
6
|
+
# attributes from template
|
7
|
+
attr_reader :attributes
|
8
|
+
|
9
|
+
# true if element has any child element or text content
|
10
|
+
attr_accessor :has_content
|
11
|
+
|
12
|
+
# true if element has any template command
|
13
|
+
attr_accessor :has_command
|
14
|
+
|
15
|
+
# Constructor
|
16
|
+
#
|
17
|
+
# @param [String] qualified_name
|
18
|
+
# tag name with namespace prefix
|
19
|
+
# @param [Attributes] attributes
|
20
|
+
# attributes from template
|
21
|
+
def initialize(qualified_name, attributes)
|
22
|
+
@name = qualified_name
|
23
|
+
@attributes = attributes
|
24
|
+
@has_content = false
|
25
|
+
@has_command = false
|
26
|
+
end
|
27
|
+
|
28
|
+
# Renders start tag
|
29
|
+
#
|
30
|
+
# @param [Attributes] attributes
|
31
|
+
# attributes to render
|
32
|
+
def render_start_tag(attributes)
|
33
|
+
return "<#{@name}#{attributes.render()}>"
|
34
|
+
end
|
35
|
+
|
36
|
+
def render_end_tag()
|
37
|
+
return "</#{@name}>"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end; end
|
@@ -0,0 +1,261 @@
|
|
1
|
+
require 'mullet/container'
|
2
|
+
require 'mullet/template_error'
|
3
|
+
require 'mullet/html/command'
|
4
|
+
require 'mullet/html/message'
|
5
|
+
require 'mullet/html/message_attribute_command'
|
6
|
+
require 'mullet/html/model_attribute_command'
|
7
|
+
|
8
|
+
module Mullet; module HTML
|
9
|
+
|
10
|
+
# Renders an HTML element.
|
11
|
+
class ElementRenderer
|
12
|
+
include Container
|
13
|
+
|
14
|
+
ATTRIBUTE_SEPARATOR = ';'
|
15
|
+
ATTRIBUTE_NAME_SEPARATOR = '='
|
16
|
+
ATTRIBUTE_SYNTAX_ERROR = "expected '%s' in '%s'"
|
17
|
+
ATTRIBUTE_NAME_MISSING_ERROR = "attribute name missing in '%s'"
|
18
|
+
CONVENIENT_ATTRIBUTE_COMMANDS = [
|
19
|
+
Command::ACTION,
|
20
|
+
Command::ALT,
|
21
|
+
Command::HREF,
|
22
|
+
Command::SRC,
|
23
|
+
Command::TITLE,
|
24
|
+
Command::VALUE ]
|
25
|
+
|
26
|
+
attr_reader :remove_mode
|
27
|
+
|
28
|
+
# Constructor
|
29
|
+
#
|
30
|
+
# @param [Element] element
|
31
|
+
# element to render
|
32
|
+
def initialize(element)
|
33
|
+
super()
|
34
|
+
|
35
|
+
@element = element
|
36
|
+
@attribute_commands = []
|
37
|
+
@remove_mode = nil
|
38
|
+
@text_variable_name = nil
|
39
|
+
@text_message = nil
|
40
|
+
@template = nil
|
41
|
+
@escape_xml = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_attribute_command(attribute_name, variable_name)
|
45
|
+
@attribute_commands <<
|
46
|
+
ModelAttributeCommand.new(attribute_name, variable_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_attribute_commands(attribute_variable_pairs)
|
50
|
+
attribute_variable_pairs.split(ATTRIBUTE_SEPARATOR).each do |command_text|
|
51
|
+
command_parts = command_text.split(ATTRIBUTE_NAME_SEPARATOR, 2)
|
52
|
+
if command_parts.length() < 2
|
53
|
+
raise TemplateError.new(
|
54
|
+
ATTRIBUTE_SYNTAX_ERROR % [ATTRIBUTE_NAME_SEPARATOR, command_text])
|
55
|
+
end
|
56
|
+
|
57
|
+
attribute_name = command_parts[0].strip()
|
58
|
+
if attribute_name.empty?()
|
59
|
+
raise TemplateError.new(ATTRIBUTE_NAME_MISSING_ERROR % command_text)
|
60
|
+
end
|
61
|
+
|
62
|
+
variable_name = command_parts[1].strip()
|
63
|
+
if variable_name.empty?()
|
64
|
+
raise TemplateError.new("variable name missing in '#{command_text}'")
|
65
|
+
end
|
66
|
+
|
67
|
+
add_attribute_command(attribute_name, variable_name)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def configure_attribute_commands(command_attributes)
|
72
|
+
value = command_attributes.fetch(Command::ATTR, nil)
|
73
|
+
if value != nil
|
74
|
+
add_attribute_commands(value)
|
75
|
+
end
|
76
|
+
|
77
|
+
CONVENIENT_ATTRIBUTE_COMMANDS.each do |attribute_name|
|
78
|
+
value = command_attributes.fetch(attribute_name, nil)
|
79
|
+
if value != nil
|
80
|
+
add_attribute_command(attribute_name, value)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
value = command_attributes.fetch(Command::REMOVE, nil)
|
85
|
+
if value != nil
|
86
|
+
value.strip!();
|
87
|
+
value.downcase!()
|
88
|
+
@remove_mode = RemoveMode.value_of(value)
|
89
|
+
if @remove_mode == nil
|
90
|
+
raise TemplateError.new("invalid remove argument '#{value}'")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def add_attribute_message_command(attribute_name, message_arguments)
|
96
|
+
@attribute_commands << MessageAttributeCommand.new(
|
97
|
+
attribute_name, Message.new(message_arguments))
|
98
|
+
end
|
99
|
+
|
100
|
+
def add_attribute_message_commands(attribute_message_pairs)
|
101
|
+
attribute_message_pairs.split(ATTRIBUTE_SEPARATOR).each do |command_text|
|
102
|
+
command_parts = command_text.split(ATTRIBUTE_NAME_SEPARATOR, 2)
|
103
|
+
if command_parts.length() < 2
|
104
|
+
raise TemplateError.new(
|
105
|
+
ATTRIBUTE_SYNTAX_ERROR % [ATTRIBUTE_NAME_SEPARATOR, command_text])
|
106
|
+
end
|
107
|
+
|
108
|
+
attribute_name = command_parts[0].strip()
|
109
|
+
if attribute_name.empty?()
|
110
|
+
raise TemplateError.new(ATTRIBUTE_NAME_MISSING_ERROR % command_text)
|
111
|
+
end
|
112
|
+
|
113
|
+
message_arguments = command_parts[1].strip()
|
114
|
+
if message_arguments.empty?()
|
115
|
+
raise TemplateError.new(
|
116
|
+
"message arguments missing in '#{command_text}'")
|
117
|
+
end
|
118
|
+
|
119
|
+
add_attribute_message_command(attribute_name, message_arguments)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def configure_attribute_message_commands(command_attributes)
|
124
|
+
value = command_attributes.fetch(Command::ALT_MESSAGE, nil)
|
125
|
+
if value != nil
|
126
|
+
add_attribute_message_command(Command::ALT, value)
|
127
|
+
end
|
128
|
+
|
129
|
+
value = command_attributes.fetch(Command::ATTR_MESSAGE, nil)
|
130
|
+
if value != nil
|
131
|
+
add_attribute_message_commands(value)
|
132
|
+
end
|
133
|
+
|
134
|
+
value = command_attributes.fetch(Command::TITLE_MESSAGE, nil)
|
135
|
+
if value != nil
|
136
|
+
add_attribute_message_command(Command::TITLE, value)
|
137
|
+
end
|
138
|
+
|
139
|
+
value = command_attributes.fetch(Command::VALUE_MESSAGE, nil)
|
140
|
+
if value != nil
|
141
|
+
add_attribute_message_command(Command::VALUE, value)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def configure_content(command_attributes, template_loader)
|
146
|
+
@text_variable_name = command_attributes.fetch(Command::TEXT, nil)
|
147
|
+
if @text_variable_name != nil
|
148
|
+
@text_variable_name = @text_variable_name.to_sym()
|
149
|
+
return
|
150
|
+
end
|
151
|
+
|
152
|
+
text_message_arguments =
|
153
|
+
command_attributes.fetch(Command::TEXT_MESSAGE, nil)
|
154
|
+
if text_message_arguments != nil
|
155
|
+
@text_message = Message.new(text_message_arguments)
|
156
|
+
return
|
157
|
+
end
|
158
|
+
|
159
|
+
uri = command_attributes.fetch(Command::INCLUDE, nil)
|
160
|
+
if uri != nil
|
161
|
+
@template = template_loader.load(uri)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def configure_commands(command_attributes, template_loader)
|
166
|
+
configure_attribute_commands(command_attributes)
|
167
|
+
configure_attribute_message_commands(command_attributes)
|
168
|
+
|
169
|
+
configure_content(command_attributes, template_loader)
|
170
|
+
|
171
|
+
escape_xml_value = command_attributes.fetch(Command::ESCAPE_XML, nil)
|
172
|
+
if escape_xml_value != nil
|
173
|
+
@escape_xml = escape_xml_value != 'false'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Checks if this renderer has a command. If it has a command, then the
|
178
|
+
# template builder should not discard it.
|
179
|
+
def has_command()
|
180
|
+
return !@attribute_commands.empty?()
|
181
|
+
end
|
182
|
+
|
183
|
+
# Checks if the element content will be rendered by a command.
|
184
|
+
def has_dynamic_content()
|
185
|
+
return @text_variable_name != nil ||
|
186
|
+
@text_message != nil ||
|
187
|
+
@template != nil
|
188
|
+
end
|
189
|
+
|
190
|
+
def execute_attribute_commands(render_context)
|
191
|
+
if @attribute_commands.empty?()
|
192
|
+
return @element.attributes()
|
193
|
+
end
|
194
|
+
|
195
|
+
# Copy the original attributes. The commands modify the copy to
|
196
|
+
# produce the attributes to render.
|
197
|
+
render_attributes = @element.attributes().dup()
|
198
|
+
@attribute_commands.each do |command|
|
199
|
+
command.execute(render_context, render_attributes)
|
200
|
+
end
|
201
|
+
return render_attributes
|
202
|
+
end
|
203
|
+
|
204
|
+
def should_render_tag()
|
205
|
+
return @remove_mode == nil || @remove_mode == RemoveMode::CONTENT
|
206
|
+
end
|
207
|
+
|
208
|
+
def render_start_tag(render_context)
|
209
|
+
if should_render_tag()
|
210
|
+
attributes = execute_attribute_commands(render_context)
|
211
|
+
render_context << @element.render_start_tag(attributes)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def render_end_tag(render_context)
|
216
|
+
if should_render_tag()
|
217
|
+
render_context << @element.render_end_tag()
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def should_render_content()
|
222
|
+
return @remove_mode != RemoveMode::CONTENT
|
223
|
+
end
|
224
|
+
|
225
|
+
def render_content(render_context)
|
226
|
+
if should_render_content()
|
227
|
+
if @text_variable_name != nil
|
228
|
+
value = render_context.get_display_value(@text_variable_name)
|
229
|
+
text = render_context.escape_xml(value.to_s())
|
230
|
+
render_context << text
|
231
|
+
elsif @text_message != nil
|
232
|
+
text = @text_message.translate(render_context)
|
233
|
+
text = render_context.escape_xml(text)
|
234
|
+
render_context << text
|
235
|
+
elsif @template != nil
|
236
|
+
@template.render(render_context)
|
237
|
+
else
|
238
|
+
render_children(render_context)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def render(render_context)
|
244
|
+
# Process the command to change the escaping mode.
|
245
|
+
original_escape_xml_enabled = render_context.escape_xml_enabled()
|
246
|
+
if @escape_xml != nil
|
247
|
+
render_context.escape_xml_enabled = @escape_xml
|
248
|
+
end
|
249
|
+
|
250
|
+
render_start_tag(render_context)
|
251
|
+
render_content(render_context)
|
252
|
+
render_end_tag(render_context)
|
253
|
+
|
254
|
+
# Restore the original escaping mode.
|
255
|
+
if @escape_xml != nil
|
256
|
+
render_context.escape_xml_enabled = original_escape_xml_enabled
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
end; end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'mullet/html/command'
|
2
|
+
require 'mullet/template_error'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
module Mullet; module HTML
|
7
|
+
|
8
|
+
# Proxy for a SAX event handler that forwards events only while the
|
9
|
+
# parser is within an element identified by an `id` attribute.
|
10
|
+
class FilteredElementHandler < Nokogiri::XML::SAX::Document
|
11
|
+
ID = 'id'
|
12
|
+
|
13
|
+
# Constructor
|
14
|
+
#
|
15
|
+
# @param [Document] handler
|
16
|
+
# event handler to forward events to
|
17
|
+
# @param [String] id
|
18
|
+
# id attribute value
|
19
|
+
def initialize(handler, id)
|
20
|
+
@handler = handler
|
21
|
+
@id = id
|
22
|
+
@depth = 0
|
23
|
+
@found_id = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def should_forward()
|
27
|
+
return @depth > 0
|
28
|
+
end
|
29
|
+
|
30
|
+
def start_document()
|
31
|
+
@handler.start_document()
|
32
|
+
end
|
33
|
+
|
34
|
+
def end_document()
|
35
|
+
@handler.end_document()
|
36
|
+
|
37
|
+
if !@found_id
|
38
|
+
raise TemplateError.new("element with attribute id='#{@id}' not found")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def start_element_namespace(name, attributes, prefix, uri, namespaces)
|
43
|
+
if should_forward()
|
44
|
+
@depth += 1
|
45
|
+
return @handler.start_element_namespace(
|
46
|
+
name, attributes, prefix, uri, namespaces)
|
47
|
+
end
|
48
|
+
|
49
|
+
value = attributes.each do |attr|
|
50
|
+
qualified_name = [attr.prefix, attr.localname].compact.join(':')
|
51
|
+
if qualified_name == ID && attr.value == @id
|
52
|
+
# Enable event forwarding.
|
53
|
+
@depth = 1
|
54
|
+
@found_id = true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def end_element_namespace(name, prefix, uri)
|
60
|
+
if should_forward()
|
61
|
+
@depth -= 1
|
62
|
+
if @depth > 0
|
63
|
+
@handler.end_element_namespace(name, prefix, uri)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def characters(data)
|
69
|
+
if should_forward()
|
70
|
+
@handler.characters(data)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def cdata_block(data)
|
75
|
+
if should_forward()
|
76
|
+
@handler.cdata_block(data)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def comment(data)
|
81
|
+
if should_forward()
|
82
|
+
@handler.comment(data)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end; end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'mullet/html/command_element_renderer'
|
2
|
+
require 'mullet/model'
|
3
|
+
|
4
|
+
module Mullet; module HTML
|
5
|
+
|
6
|
+
# Renders an element for each item in a collection.
|
7
|
+
class ForElementRenderer < CommandElementRenderer
|
8
|
+
|
9
|
+
# Constructor
|
10
|
+
#
|
11
|
+
# @param [Element] element
|
12
|
+
# element to render
|
13
|
+
# @param [String] variable_name
|
14
|
+
# name of variable containing collection
|
15
|
+
def initialize(element, variable_name)
|
16
|
+
super(element)
|
17
|
+
@variable_name = variable_name.to_sym()
|
18
|
+
end
|
19
|
+
|
20
|
+
alias :super_render :render
|
21
|
+
|
22
|
+
def render_nested_model(data, render_context)
|
23
|
+
render_context.push_scope(data)
|
24
|
+
super_render(render_context)
|
25
|
+
render_context.pop_scope()
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(render_context)
|
29
|
+
value = render_context.get_variable_value(@variable_name)
|
30
|
+
if value == Model::NOT_FOUND || value == nil || value == false
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
if value.respond_to?(:empty?) && value.empty?()
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
if value.respond_to?(:each)
|
39
|
+
value.each {|item| render_nested_model(item, render_context) }
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
render_nested_model(value, render_context)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end; end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'mullet/html/command_element_renderer'
|
2
|
+
require 'mullet/model'
|
3
|
+
|
4
|
+
module Mullet; module HTML
|
5
|
+
|
6
|
+
# Renders an element if variable is true.
|
7
|
+
class IfElementRenderer < CommandElementRenderer
|
8
|
+
|
9
|
+
# Constructor
|
10
|
+
#
|
11
|
+
# @param [Element] element
|
12
|
+
# element to render
|
13
|
+
# @param [String] variable_name
|
14
|
+
# name of variable containing condition
|
15
|
+
def initialize(element, variable_name)
|
16
|
+
super(element)
|
17
|
+
@variable_name = variable_name.to_sym()
|
18
|
+
end
|
19
|
+
|
20
|
+
def should_render_element(render_context)
|
21
|
+
value = render_context.get_variable_value(@variable_name)
|
22
|
+
if value == Model::NOT_FOUND || value == nil
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
|
26
|
+
if value.is_a?(FalseClass) || value.is_a?(TrueClass)
|
27
|
+
return value
|
28
|
+
end
|
29
|
+
|
30
|
+
if value.respond_to?(:empty?)
|
31
|
+
return !value.empty?()
|
32
|
+
end
|
33
|
+
|
34
|
+
return true
|
35
|
+
end
|
36
|
+
|
37
|
+
alias :super_render :render
|
38
|
+
|
39
|
+
def render(render_context)
|
40
|
+
if should_render_element(render_context)
|
41
|
+
super_render(render_context)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end; end
|