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.



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

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

#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



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

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

#createElement(name, attributes) ⇒ Object

Create an element but don’t insert it anywhere



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

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



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

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



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

def elementInScope(target, tableVariant=false)
  # Exit early when possible.
  return true if @open_elements[-1].name == target

  # 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



302
303
304
305
306
307
308
309
310
311
312
# File 'lib/html5/treebuilders/base.rb', line 302

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



314
315
316
# File 'lib/html5/treebuilders/base.rb', line 314

def get_document
  @document
end

#get_fragmentObject



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

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



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/html5/treebuilders/base.rb', line 274

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



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

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

#insert_element(name, attributes) ⇒ Object



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

def insert_element(name, attributes)
  send(@insert_element, name, attributes)
end

#insert_elementNormal(name, attributes) ⇒ Object



231
232
233
234
235
236
237
# File 'lib/html5/treebuilders/base.rb', line 231

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

#insert_elementTable(name, attributes) ⇒ Object

Create an element and insert it into the tree



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/html5/treebuilders/base.rb', line 240

def insert_elementTable(name, attributes)
  element = @elementClass.new(name)
  element.attributes = attributes
  if TABLE_INSERT_MODE_ELEMENTS.include?(@open_elements.last.name)
    #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)
  else
    return insert_elementNormal(name, attributes)
  end
  return element
end

#insert_from_table=(value) ⇒ Object

Switch the function used to insert an element from the normal one to the misnested table one and back again



222
223
224
225
# File 'lib/html5/treebuilders/base.rb', line 222

def insert_from_table=(value)
  @insert_from_table = value
  @insert_element = value ? :insert_elementTable : :insert_elementNormal
end

#insertDoctype(name, public_id, system_id) ⇒ Object



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

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



259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/html5/treebuilders/base.rb', line 259

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



141
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
# File 'lib/html5/treebuilders/base.rb', line 141

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



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

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)


327
328
329
# File 'lib/html5/treebuilders/base.rb', line 327

def testSerializer(node)
  raise NotImplementedError
end