PureHTML.TreeBuilder.Helpers (PureHTML v0.5.0)

View Source

Shared helpers for the tree builder's insertion modes.

The stack of open elements holds refs; the elements map holds the data (ref => %{tag, attrs, children, parent_ref}). A child joins its parent's children at push time, and popping only removes the ref: the stack top is the insertion parent.

The modes import this module whole. Delegations between modes ("process the token using the rules for ...") are plain calls that leave the insertion mode to the rules invoked.

Summary

Functions

Adds a child (text, comment, or tuple element) to the current element. Updates children in elements map.

Inserts a comment or PI as a child of the Document, before the html element.

Adds text to the current element, merging with previous text if present.

True when every character is ASCII whitespace: U+0009, U+000A, U+000C, U+000D, U+0020. String.trim/1 also strips U+00A0 and other Unicode whitespace, which the parser treats as characters.

Clears active formatting elements up to and including the last marker.

Pops elements from the stack of open elements until an HTML template element has been popped.

Corrects certain tag names (e.g., "image" -> "img").

Returns the current element (top of stack).

Returns the tag of the current element (top of stack).

Disables foster parenting. Called by the tree builder after each token.

Enables foster parenting for the token being processed. The tree builder disables it again once the token (and any reprocessing) is done.

Generic raw text and RCDATA element parsing, after the element is inserted: switch the tokenizer, keep the current insertion mode as the original one, then switch to "text".

Extracts only whitespace characters from text. Returns the whitespace portion of the string.

Finds the foster parent for foster parenting. Returns {foster_parent_ref, insert_before_ref}.

Finds the ref of an element with the given tag in the stack. Returns the ref or nil if not found.

Foster parents content and returns only the state.

Unified foster parenting function. Inserts content before the table element per HTML5 spec. Always returns {state, ref} where ref is nil for text/element insertions.

Generates implied end tags per the HTML5 spec.

Generates implied end tags, except for elements with the given tag name.

Generates implied end tags thoroughly (used at EOF per spec).

Gets an attribute value from an attribute list.

"If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move on to the next one." The tree builder clears the flag on the next token.

Checks if an element with the given tag (or any tag in a list) is in the specified scope. Scope types: :default, :table, :button

Merges new attrs into existing attrs, preserving existing values. New attrs are only added if the key doesn't already exist.

Merges new attributes into the html element, preserving existing attrs. Used when processing <html> start tags in various modes.

Moves an existing element to the appropriate place for inserting a node with target_ref as the override target: the foster parent location when foster parenting is enabled and the target is a table, tbody, tfoot, thead, or tr element, otherwise the end of the target.

Checks if the current element requires foster parenting. Returns true if current node is a table structure element.

Creates a new HTML element with the given tag and attributes.

Creates a new foreign (SVG/MathML) element with namespace.

Checks if the element with the given ref is in the default scope, per the spec's "the stack of open elements does not have node in scope".

Parse error unless the current node is an HTML element with this tag name.

Points the form element pointer at the current node, the form element just inserted, unless the parser is parsing template contents (a template is on the stack of open elements).

Pops the current element from the stack. Just removes the ref; the new stack top is the insertion parent. Children are already in elements map (added at push time).

Pops elements from the stack of open elements until an HTML element with the given tag name has been popped.

Pops elements from the stack of open elements until ref has been popped.

Pops elements from the stack until a tag in the given list is at the top.

Pops elements from the stack until an element with the given tag is found. Returns {:ok, state} if found, {:not_found, state} otherwise.

Processes the token with the "in body" rules from inside a state pipe.

Processes a head element start tag with the "in head" rules on behalf of a mode that inserts it where it stands (in body, in template): the token is consumed there, never reprocessed.

Processes the token with the "in table" rules (in table body, in row): a delegation for one token that leaves the insertion mode to those rules.

Pushes a marker onto the active formatting elements list.

Pushes a new element onto the stack.

Pushes a new foreign element onto the stack.

"Reset the insertion mode appropriately": walk the stack of open elements from the current node. The first node in the stack is the last step of the walk, and in the fragment case that step uses the context element instead.

Records the document's doctype; initial calls this once.

Sets the frameset-ok flag.

Sets the current insertion mode.

Sets the quirks mode flag, decided in initial from the doctype or its absence.

Whether an element with this tag is in the special category.

Splits U+0000 out of a character token's text: the text without them and how many there were. In body and in table text each one is a parse error and is ignored; foreign content replaces each with U+FFFD.

Splits text into leading whitespace and remaining content. Returns {whitespace, rest}.

Switches the current template insertion mode. Replaces the top of template_mode_stack with new_mode (or pushes if empty).

Asks the tree builder to switch the tokenizer to tokenizer_state before the next token.

Updates an entry in the active formatting elements list by ref.

Functions

add_child_to_stack(state, child)

Adds a child (text, comment, or tuple element) to the current element. Updates children in elements map.

add_document_child(state, node)

Inserts a comment or PI as a child of the Document, before the html element.

add_text_to_stack(state, text)

Adds text to the current element, merging with previous text if present.

ascii_whitespace_only?(arg1)

True when every character is ASCII whitespace: U+0009, U+000A, U+000C, U+000D, U+0020. String.trim/1 also strips U+00A0 and other Unicode whitespace, which the parser treats as characters.

clear_af_to_marker(state)

Clears active formatting elements up to and including the last marker.

close_html_template(state)

Pops elements from the stack of open elements until an HTML template element has been popped.

correct_tag(tag)

Corrects certain tag names (e.g., "image" -> "img").

current_element(map)

Returns the current element (top of stack).

current_tag(map)

Returns the tag of the current element (top of stack).

disable_foster_parenting(state)

Disables foster parenting. Called by the tree builder after each token.

enable_foster_parenting(state)

Enables foster parenting for the token being processed. The tree builder disables it again once the token (and any reprocessing) is done.

enter_text_mode(state, tokenizer_state)

Generic raw text and RCDATA element parsing, after the element is inserted: switch the tokenizer, keep the current insertion mode as the original one, then switch to "text".

extract_whitespace(text)

Extracts only whitespace characters from text. Returns the whitespace portion of the string.

find_foster_parent(map)

Finds the foster parent for foster parenting. Returns {foster_parent_ref, insert_before_ref}.

Per HTML5 spec:

  1. Let last table be the last table element in the stack
  2. Let last template be the last template element in the stack
  3. If there is a template AND (no table OR template is closer to stack top than table), then foster parent is the template element itself (no insert_before)
  4. Otherwise if there is a table, foster parent is table's parent, insert before table
  5. Otherwise foster parent is the first element (html)

find_ref(map, tag)

Finds the ref of an element with the given tag in the stack. Returns the ref or nil if not found.

foster_insert(state, content)

Foster parents content and returns only the state.

foster_parent(state, content)

Unified foster parenting function. Inserts content before the table element per HTML5 spec. Always returns {state, ref} where ref is nil for text/element insertions.

Content types:

  • {:text, text} - insert text, returns {state, nil}
  • {:element, {tag, attrs, children}} - insert complete element, returns {state, nil}
  • {:push, tag, attrs} - create element, push to stack, returns {state, ref}
  • {:push_foreign, ns, tag, attrs, self_closing} - create foreign element, returns {state, nil} for self-closing, {state, ref} otherwise

generate_implied_end_tags(state)

Generates implied end tags per the HTML5 spec.

generate_implied_end_tags_except(state, except_tag)

Generates implied end tags, except for elements with the given tag name.

generate_implied_end_tags_thoroughly(state)

Generates implied end tags thoroughly (used at EOF per spec).

get_attr(attrs, key, default \\ nil)

Gets an attribute value from an attribute list.

Returns the value if the attribute is found, or the default if not.

Examples

iex> get_attr([{"type", "hidden"}, {"name", "foo"}], "type")
"hidden"

iex> get_attr([{"name", "foo"}], "type")
nil

iex> get_attr([{"name", "foo"}], "type", "text")
"text"

has_template_on_stack?(state)

ignore_next_lf(state)

"If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move on to the next one." The tree builder clears the flag on the next token.

in_scope?(state, tag, scope_type)

Checks if an element with the given tag (or any tag in a list) is in the specified scope. Scope types: :default, :table, :button

insert_pi(state, target, data)

merge_attr_lists(new_attrs, existing_attrs)

Merges new attrs into existing attrs, preserving existing values. New attrs are only added if the key doesn't already exist.

merge_html_attrs(state, new_attrs)

Merges new attributes into the html element, preserving existing attrs. Used when processing <html> start tags in various modes.

move_node_to_appropriate_place(state, ref, target_ref)

Moves an existing element to the appropriate place for inserting a node with target_ref as the override target: the foster parent location when foster parenting is enabled and the target is a table, tbody, tfoot, thead, or tr element, otherwise the end of the target.

needs_foster_parenting?(arg1)

Checks if the current element requires foster parenting. Returns true if current node is a table structure element.

new_element(tag, attrs \\ [], parent_ref \\ nil)

Creates a new HTML element with the given tag and attributes.

new_foreign_element(ns, tag, attrs, parent_ref \\ nil)

Creates a new foreign (SVG/MathML) element with namespace.

node_in_scope?(state, ref)

Checks if the element with the given ref is in the default scope, per the spec's "the stack of open elements does not have node in scope".

parse_error_unless_current(state, tag)

Parse error unless the current node is an HTML element with this tag name.

point_form_element(state)

Points the form element pointer at the current node, the form element just inserted, unless the parser is parsing template contents (a template is on the stack of open elements).

pop_element(state)

Pops the current element from the stack. Just removes the ref; the new stack top is the insertion parent. Children are already in elements map (added at push time).

pop_template_mode(state)

pop_through(state, tag)

Pops elements from the stack of open elements until an HTML element with the given tag name has been popped.

pop_through_ref(state, ref)

Pops elements from the stack of open elements until ref has been popped.

pop_until_one_of(state, tags)

Pops elements from the stack until a tag in the given list is at the top.

pop_until_tag(state, tag)

Pops elements from the stack until an element with the given tag is found. Returns {:ok, state} if found, {:not_found, state} otherwise.

process_in_body(state, token)

Processes the token with the "in body" rules from inside a state pipe.

process_in_head(state, token)

Processes a head element start tag with the "in head" rules on behalf of a mode that inserts it where it stands (in body, in template): the token is consumed there, never reprocessed.

process_in_table(state, token)

Processes the token with the "in table" rules (in table body, in row): a delegation for one token that leaves the insertion mode to those rules.

push_af_marker(state)

Pushes a marker onto the active formatting elements list.

push_element(state, tag, attrs)

Pushes a new element onto the stack.

  • Creates element in elements map
  • Adds element's ref to parent's children (at push time)
  • Pushes ref to stack

push_foreign_element(state, ns, tag, attrs)

Pushes a new foreign element onto the stack.

push_template_mode(state, mode)

reset_insertion_mode(state)

"Reset the insertion mode appropriately": walk the stack of open elements from the current node. The first node in the stack is the last step of the walk, and in the fragment case that step uses the context element instead.

set_doctype(state, name, public_id, system_id)

Records the document's doctype; initial calls this once.

set_frameset_not_ok(state)

set_frameset_ok(state, value)

Sets the frameset-ok flag.

set_mode(state, mode)

Sets the current insertion mode.

set_quirks_mode(state, quirks?)

Sets the quirks mode flag, decided in initial from the doctype or its absence.

special_element?(tag)

Whether an element with this tag is in the special category.

special_elements()

split_null_characters(text)

Splits U+0000 out of a character token's text: the text without them and how many there were. In body and in table text each one is a parse error and is ignored; foreign content replaces each with U+FFFD.

split_whitespace(text)

Splits text into leading whitespace and remaining content. Returns {whitespace, rest}.

switch_template_mode(state, new_mode)

Switches the current template insertion mode. Replaces the top of template_mode_stack with new_mode (or pushes if empty).

switch_tokenizer(state, tokenizer_state)

Asks the tree builder to switch the tokenizer to tokenizer_state before the next token.

update_af_entry(af, old_ref, new_entry)

Updates an entry in the active formatting elements list by ref.