Class: Mullet::HTML::TemplateBuilder

Inherits:
Parser::DefaultHandler show all
Includes:
Command
Defined in:
lib/mullet/html/template_builder.rb

Overview

Handles SAX events to build a template.

Constant Summary collapse

COMMANDS =
Set[
ACTION,
ALT,
ALT_MESSAGE,
ATTR,
ATTR_MESSAGE,
ESCAPE_XML,
FOR,
HREF,
IF,
INCLUDE,
REMOVE,
SRC,
TEXT,
TEXT_MESSAGE,
TITLE,
TITLE_MESSAGE,
UNLESS,
VALUE,
VALUE_MESSAGE]
START_CDATA =
'<![CDATA['
END_CDATA =
']]>'

Constants included from Command

Command::ACTION, Command::ALT, Command::ALT_MESSAGE, Command::ATTR, Command::ATTR_MESSAGE, Command::DATA_PREFIX, Command::ESCAPE_XML, Command::FOR, Command::HREF, Command::IF, Command::INCLUDE, Command::NAMESPACE_PREFIX, Command::NAMESPACE_URI, Command::REMOVE, Command::SRC, Command::TEXT, Command::TEXT_MESSAGE, Command::TITLE, Command::TITLE_MESSAGE, Command::UNLESS, Command::VALUE, Command::VALUE_MESSAGE

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(loader) ⇒ TemplateBuilder

Constructor

Parameters:

  • loader (TemplateLoader)

    template loader to use to load included template files



51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/mullet/html/template_builder.rb', line 51

def initialize(loader)
  @loader = loader

  # Stack of elements where this handler has seen the start tag and not yet
  # seen the end tag.
  @open_elements = []

  # stack of current containers to add renderers to
  @containers = []

  @static_text = ''
  @template = nil
end

Instance Attribute Details

#templateObject (readonly)

Returns the value of attribute template.



45
46
47
# File 'lib/mullet/html/template_builder.rb', line 45

def template
  @template
end

Instance Method Details

#add_child(renderer) ⇒ Object

Adds renderer to current container.

Parameters:

  • renderer (#render)

    renderer to add



69
70
71
# File 'lib/mullet/html/template_builder.rb', line 69

def add_child(renderer)
  @containers.last().add_child(renderer)
end

#append_static_text(data) ⇒ Object



124
125
126
# File 'lib/mullet/html/template_builder.rb', line 124

def append_static_text(data)
  @static_text << data
end

#cdata_block(data) ⇒ Object



268
269
270
271
272
# File 'lib/mullet/html/template_builder.rb', line 268

def cdata_block(data)
  append_static_text(START_CDATA)
  characters(data)
  append_static_text(END_CDATA)
end

#characters(data) ⇒ Object



263
264
265
266
# File 'lib/mullet/html/template_builder.rb', line 263

def characters(data)
  set_has_content()
  append_static_text(data)
end

#comment(data) ⇒ Object



274
275
276
277
278
# File 'lib/mullet/html/template_builder.rb', line 274

def comment(data)
  append_static_text('<!--')
  characters(data)
  append_static_text('-->')
end

#configure_remove_command(element, renderer) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/mullet/html/template_builder.rb', line 221

def configure_remove_command(element, renderer)
  case renderer.remove_mode
  when RemoveMode::TAG
    if !renderer.has_command && !renderer.has_dynamic_content
      # Discard tag, but preserve the children.
      delete_child(renderer)
      renderer.children.each do |child|
        add_child(child)
      end
    end
  when RemoveMode::CONTENT
    if !renderer.has_command
      # Discard children. Statically render the tag.
      delete_child(renderer)

      append_static_text(element.render_start_tag(element.attributes))
      append_static_text(element.render_end_tag())
    end
  when RemoveMode::ELEMENT
    # Discard element and all its content.
    delete_child(renderer)
  end
end

#create_element_renderer(element, command_attributes) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/mullet/html/template_builder.rb', line 166

def create_element_renderer(element, command_attributes)
  renderer = nil

  variable_name = command_attributes.fetch(IF, nil)
  if variable_name != nil
    renderer = IfElementRenderer.new(element, variable_name)
  end

  if renderer == nil
    variable_name = command_attributes.fetch(UNLESS, nil)
    if variable_name != nil
      renderer = UnlessElementRenderer.new(element, variable_name)
    end
  end

  if renderer == nil
    variable_name = command_attributes.fetch(FOR, nil)
    if variable_name != nil
      renderer = ForElementRenderer.new(element, variable_name)
    end
  end

  if renderer == nil
    renderer = ElementRenderer.new(element)
  end

  renderer.configure_commands(command_attributes, @loader)
  return renderer
end

#delete_child(renderer) ⇒ Object

Deletes renderer from current container.

Parameters:

  • renderer (#render)

    renderer to delete



77
78
79
# File 'lib/mullet/html/template_builder.rb', line 77

def delete_child(renderer)
  @containers.last().delete_child(renderer)
end

#doctype(name, public_id, system_id) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/mullet/html/template_builder.rb', line 151

def doctype(name, public_id, system_id)
  text = "<!DOCTYPE #{name}"

  if public_id
    text << %( PUBLIC "#{public_id}")
  end

  if system_id
    text << %( "#{system_id}")
  end

  text << '>'
  append_static_text(text)
end

#end_documentObject



147
148
149
# File 'lib/mullet/html/template_builder.rb', line 147

def end_document()
  end_static_text()
end

#end_element_namespace(name, prefix, uri) ⇒ Object



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/mullet/html/template_builder.rb', line 245

def end_element_namespace(name, prefix, uri)
  element = @open_elements.pop()
  if element.has_command
    end_static_text()

    renderer = @containers.pop()
    if renderer.has_dynamic_content
      # Discard children because the content will be replaced at render
      # time.
      renderer.clear_children()
    end

    configure_remove_command(element, renderer)
  elsif uri != Parser::SimpleParser::IMPLICIT_END_TAG_NS_URI
    append_static_text(element.render_end_tag())
  end
end

#end_static_textObject



128
129
130
131
132
133
# File 'lib/mullet/html/template_builder.rb', line 128

def end_static_text()
  if !@static_text.empty?()
    add_child(StaticTextRenderer.new(@static_text))
    @static_text = ''
  end
end

#find_commands(attributes, ns, ordinary_attributes, command_attributes) ⇒ Boolean

Partitions the attributes into ordinary and command attributes.

Parameters:

  • attributes (Array)

    input attributes

  • ns (Hash)

    hash of namespace prefix to uri mappings

  • ordinary_attributes (#store)

    hash will receive name to value mappings for ordinary attributes

  • command_attributes (#store)

    hash will receive name to value mappings for command attributes

Returns:

  • (Boolean)

    true if any command attribute found



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/mullet/html/template_builder.rb', line 92

def find_commands(attributes, ns, ordinary_attributes, command_attributes)
  found_command = false
  attributes.each do |attr|
    if attr.localname.start_with?(DATA_PREFIX)
      command_name = attr.localname.slice(DATA_PREFIX.length()..-1)
      if COMMANDS.include?(command_name)
        command_attributes.store(command_name, attr.value)
        found_command = true
      end
    elsif attr.uri == NAMESPACE_URI || attr.prefix == NAMESPACE_PREFIX
      command_name = attr.localname
      if !COMMANDS.include?(command_name)
        raise TemplateError("invalid command '#{command_name}'")
      end
      command_attributes.store(command_name, attr.value)
      found_command = true
    else
      attribute_name = [attr.prefix, attr.localname].compact().join(':')
      ordinary_attributes.store(attribute_name, attr.value)
    end
  end

  ns.each do |prefix, uri|
    if uri != NAMESPACE_URI
      attribute_name = ['xmlns', prefix].compact().join(':')
      ordinary_attributes.store(attribute_name, uri)
    end
  end

  return found_command
end

#processing_instruction(data) ⇒ Object



280
281
282
283
284
# File 'lib/mullet/html/template_builder.rb', line 280

def processing_instruction(data)
  append_static_text('<?')
  characters(data)
  append_static_text('?>')
end

#set_has_contentObject

Marks the most deeply nested open element as having content.



136
137
138
139
140
# File 'lib/mullet/html/template_builder.rb', line 136

def set_has_content()
  if !@open_elements.empty?()
    @open_elements.last().has_content = true
  end
end

#start_documentObject



142
143
144
145
# File 'lib/mullet/html/template_builder.rb', line 142

def start_document()
  @template = Template.new()
  @containers.push(@template)
end

#start_element_namespace(name, attributes, prefix, uri, ns) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/mullet/html/template_builder.rb', line 196

def start_element_namespace(name, attributes, prefix, uri, ns)
  set_has_content()

  ordinary_attributes = Attributes.new()
  command_attributes = Attributes.new()
  found_command = find_commands(
      attributes, ns, ordinary_attributes, command_attributes)

  qualified_name = [prefix, name].compact().join(':')
  element = Element.new(qualified_name, ordinary_attributes)
  @open_elements.push(element)

  if found_command
    end_static_text()

    element.has_command = true
    renderer = create_element_renderer(element, command_attributes)
    add_child(renderer)

    @containers.push(renderer)
  else
    append_static_text(element.render_start_tag(element.attributes))
  end
end