Class: HTML5::TreeBuilders::Base::TreeBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/html5/treebuilders/base.rb

Overview

Base treebuilder implementation

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeTreeBuilder

Returns a new instance of TreeBuilder.



105
106
107
# File 'lib/html5/treebuilders/base.rb', line 105

def initialize
  reset
end

Instance Attribute Details

#activeFormattingElementsObject

Returns the value of attribute activeFormattingElements.



81
82
83
# File 'lib/html5/treebuilders/base.rb', line 81

def activeFormattingElements
  @activeFormattingElements
end

#documentObject

Returns the value of attribute document.



83
84
85
# File 'lib/html5/treebuilders/base.rb', line 83

def document
  @document
end

#formPointerObject

Returns the value of attribute formPointer.



87
88
89
# File 'lib/html5/treebuilders/base.rb', line 87

def formPointer
  @formPointer
end

#head_pointerObject

Returns the value of attribute head_pointer.



85
86
87
# File 'lib/html5/treebuilders/base.rb', line 85

def head_pointer
  @head_pointer
end

#insert_from_tableObject

Returns the value of attribute insert_from_table.



89
90
91
# File 'lib/html5/treebuilders/base.rb', line 89

def insert_from_table
  @insert_from_table
end

#open_elementsObject

Returns the value of attribute open_elements.



79
80
81
# File 'lib/html5/treebuilders/base.rb', line 79

def open_elements
  @open_elements
end

Instance Method Details

#clearActiveFormattingElementsObject



185
186
187
# File 'lib/html5/treebuilders/base.rb', line 185

def clearActiveFormattingElements
  {} until @activeFormattingElements.empty? || @activeFormattingElements.pop == Marker
end

#createElement(name, attributes) ⇒ Object

Create an element but don’t insert it anywhere



215
216
217
218
219
# File 'lib/html5/treebuilders/base.rb', line 215

def createElement(name, attributes)
  element = @elementClass.new(name)
  element.attributes = attributes
  return element
end

#elementInActiveFormattingElements(name) ⇒ Object

Check if an element exists between the end of the active formatting elements and the last marker. If it does, return it, else return false



192
193
194
195
196
197
198
199
200
# File 'lib/html5/treebuilders/base.rb', line 192

def elementInActiveFormattingElements(name)
  @activeFormattingElements.reverse.each do |element|
    # Check for Marker first because if it's a Marker it doesn't have a
    # name attribute.
    break if element == Marker
    return element if element.name == name
  end
  return false
end

#elementInScope(target, tableVariant = false) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/html5/treebuilders/base.rb', line 122

def elementInScope(target, tableVariant=false)
  # Exit early when possible.
  return true if @open_elements[-1] && @open_elements[-1].name == target
  return false if @open_elements.length == 0
  # AT How about while true and simply set node to [-1] and set it to
  # [-2] at the end...
  @open_elements.reverse.each do |element|
    if element.name == target
      return true
    elsif element.name == 'table'
      return false
    elsif not tableVariant and SCOPING_ELEMENTS.include?(element.name)
      return false
    elsif element.name == 'html'
      return false
    end
  end
  assert false # We should never reach this point
end

#generateImpliedEndTags(exclude = nil) ⇒ Object



307
308
309
310
311
312
313
314
315
316
317
# File 'lib/html5/treebuilders/base.rb', line 307

def generateImpliedEndTags(exclude=nil)
  name = @open_elements[-1].name

  # XXX td, th and tr are not actually needed
  if (%w[dd dt li p td th tr].include?(name) and name != exclude)
    @open_elements.pop
    # XXX This is not entirely what the specification says. We should
    # investigate it more closely.
    generateImpliedEndTags(exclude)
  end
end

#get_documentObject



319
320
321
# File 'lib/html5/treebuilders/base.rb', line 319

def get_document
  @document
end

#get_fragmentObject



323
324
325
326
327
328
# File 'lib/html5/treebuilders/base.rb', line 323

def get_fragment
  #assert @inner_html
  fragment = @fragmentClass.new
  @open_elements[0].reparentChildren(fragment)
  return fragment
end

#getTableMisnestedNodePositionObject

Get the foster parent element, and sibling to insert before (or nil) when inserting a misnested table node



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/html5/treebuilders/base.rb', line 279

def getTableMisnestedNodePosition
  #The foster parent element is the one which comes before the most
  #recently opened table element
  #XXX - this is really inelegant
  lastTable = nil
  fosterParent = nil
  insertBefore = nil
  @open_elements.reverse.each do |element|
    if element.name == "table"
      lastTable = element
      break
    end
  end
  if lastTable
    #XXX - we should really check that this parent is actually a
    #node here
    if lastTable.parent
      fosterParent = lastTable.parent
      insertBefore = lastTable
    else
      fosterParent = @open_elements[@open_elements.index(lastTable) - 1]
    end
  else
    fosterParent = @open_elements[0]
  end
  return fosterParent, insertBefore
end

#insert_comment(data, parent = nil) ⇒ Object



209
210
211
212
# File 'lib/html5/treebuilders/base.rb', line 209

def insert_comment(data, parent=nil)
  parent = @open_elements[-1] if parent.nil?
  parent.appendChild(@commentClass.new(data))
end

#insert_element(name, attributes, namespace = nil) ⇒ Object



228
229
230
# File 'lib/html5/treebuilders/base.rb', line 228

def insert_element(name, attributes, namespace = nil)
  send(@insert_element, name, attributes, namespace)
end

#insert_elementNormal(name, attributes, namespace = nil) ⇒ Object



236
237
238
239
240
241
242
# File 'lib/html5/treebuilders/base.rb', line 236

def insert_elementNormal(name, attributes, namespace=nil)
  element = @elementClass.new(name, namespace)
  element.attributes = attributes
  @open_elements.last.appendChild(element)
  @open_elements.push(element)
  element
end

#insert_elementTable(name, attributes, namespace = nil) ⇒ Object

Create an element and insert it into the tree



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/html5/treebuilders/base.rb', line 245

def insert_elementTable(name, attributes, namespace=nil)
  element = @elementClass.new(name, namespace)
  element.attributes = attributes
  if !TABLE_INSERT_MODE_ELEMENTS.include?(@open_elements.last.name)
    return insert_elementNormal(name, attributes)
  else
    #We should be in the InTable mode. This means we want to do
    #special magic element rearranging
    parent, insertBefore = getTableMisnestedNodePosition
    if insertBefore.nil?
      parent.appendChild(element)
    else
      parent.insertBefore(element, insertBefore)
    end
    @open_elements.push(element)
  end
  return element
end

#insert_foreign_element(name, attributes, namespace) ⇒ Object



232
233
234
# File 'lib/html5/treebuilders/base.rb', line 232

def insert_foreign_element(name, attributes, namespace)
  insert_element(name, attributes, namespace)
end

#insertDoctype(name, public_id, system_id) ⇒ Object



202
203
204
205
206
207
# File 'lib/html5/treebuilders/base.rb', line 202

def insertDoctype(name, public_id, system_id)
  doctype = @doctypeClass.new(name)
  doctype.public_id = public_id
  doctype.system_id = system_id
  @document.appendChild(doctype)
end

#insertText(data, parent = nil) ⇒ Object



264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/html5/treebuilders/base.rb', line 264

def insertText(data, parent=nil)
  parent = @open_elements[-1] if parent.nil?

  if (not(@insert_from_table) or (@insert_from_table and not TABLE_INSERT_MODE_ELEMENTS.include?(@open_elements[-1].name)))
    parent.insertText(data)
  else
    #We should be in the InTable mode. This means we want to do
    #special magic element rearranging
    parent, insertBefore = getTableMisnestedNodePosition
    parent.insertText(data, insertBefore)
  end
end

#reconstructActiveFormattingElementsObject



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/html5/treebuilders/base.rb', line 142

def reconstructActiveFormattingElements
  # Within this algorithm the order of steps described in the
  # specification is not quite the same as the order of steps in the
  # code. It should still do the same though.

  # Step 1: stop the algorithm when there's nothing to do.
  return if @activeFormattingElements.empty?

  # Step 2 and step 3: we start with the last element. So i is -1.
  i = -1
  entry = @activeFormattingElements[i]
  return if entry == Marker or @open_elements.include?(entry)

  # Step 6
  until entry == Marker or @open_elements.include?(entry)
    # Step 5: let entry be one earlier in the list.
    i -= 1
    begin
      entry = @activeFormattingElements[i]
    rescue
      # Step 4: at this point we need to jump to step 8. By not doing
      # i += 1 which is also done in step 7 we achieve that.
      break
    end
  end
  while true
    # Step 7
    i += 1

    # Step 8
    clone = @activeFormattingElements[i].cloneNode

    # Step 9
    element = insert_element(clone.name, clone.attributes)

    # Step 10
    @activeFormattingElements[i] = element

    # Step 11
    break if element == @activeFormattingElements[-1]
  end
end

#resetObject



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/html5/treebuilders/base.rb', line 109

def reset
  @open_elements = []
  @activeFormattingElements = []

  #XXX - rename these to headElement, formElement
  @head_pointer = nil
  @formPointer = nil

  self.insert_from_table = false

  @document = @documentClass.new
end

#testSerializer(node) ⇒ Object

Serialize the subtree of node in the format required by unit tests node - the node from which to start serializing

Raises:

  • (NotImplementedError)


332
333
334
# File 'lib/html5/treebuilders/base.rb', line 332

def testSerializer(node)
  raise NotImplementedError
end