@namespace = args.namespace ? NS_HTML
@parent = args.parent ? null
@token = args.token ? null
+ @flags = args.flags ? {}
if args.id?
@id = "#{args.id}+"
else
@token.flag 'did_self_close'
else
@flag 'did_self_close', true
- flag: ->
- # fixfull
+ flag: (key, value = null) ->
+ if value?
+ @flags[key] = value
+ else
+ return @flags[key]
serialize: (shallow = false, show_ids = false) -> # for unit tests
ret = ''
switch @type
h1:NS_HTML, h2:NS_HTML, h3:NS_HTML, h4:NS_HTML, h5:NS_HTML, h6:NS_HTML
}
+# FIXME namespacify
foster_parenting_targets = {
table: true
tbody: true
tr: true
}
+# FIXME namespacify
# all html I presume
end_tag_implied = {
dd: true
el_is_special_not_adp = (el) ->
return special_elements[el.name] is el.namespace and adp_els[el.name] isnt el.namespace
+svg_attribute_fixes = {
+ attributename: 'attributeName'
+ attributetype: 'attributeType'
+ basefrequency: 'baseFrequency'
+ baseprofile: 'baseProfile'
+ calcmode: 'calcMode'
+ clippathunits: 'clipPathUnits'
+ contentscripttype: 'contentScriptType'
+ contentstyletype: 'contentStyleType'
+ diffuseconstant: 'diffuseConstant'
+ edgemode: 'edgeMode'
+ externalresourcesrequired: 'externalResourcesRequired'
+ filterres: 'filterRes'
+ filterunits: 'filterUnits'
+ glyphref: 'glyphRef'
+ gradienttransform: 'gradientTransform'
+ gradientunits: 'gradientUnits'
+ kernelmatrix: 'kernelMatrix'
+ kernelunitlength: 'kernelUnitLength'
+ keypoints: 'keyPoints'
+ keysplines: 'keySplines'
+ keytimes: 'keyTimes'
+ lengthadjust: 'lengthAdjust'
+ limitingconeangle: 'limitingConeAngle'
+ markerheight: 'markerHeight'
+ markerunits: 'markerUnits'
+ markerwidth: 'markerWidth'
+ maskcontentunits: 'maskContentUnits'
+ maskunits: 'maskUnits'
+ numoctaves: 'numOctaves'
+ pathlength: 'pathLength'
+ patterncontentunits: 'patternContentUnits'
+ patterntransform: 'patternTransform'
+ patternunits: 'patternUnits'
+ pointsatx: 'pointsAtX'
+ pointsaty: 'pointsAtY'
+ pointsatz: 'pointsAtZ'
+ preservealpha: 'preserveAlpha'
+ preserveaspectratio: 'preserveAspectRatio'
+ primitiveunits: 'primitiveUnits'
+ refx: 'refX'
+ refy: 'refY'
+ repeatcount: 'repeatCount'
+ repeatdur: 'repeatDur'
+ requiredextensions: 'requiredExtensions'
+ requiredfeatures: 'requiredFeatures'
+ specularconstant: 'specularConstant'
+ specularexponent: 'specularExponent'
+ spreadmethod: 'spreadMethod'
+ startoffset: 'startOffset'
+ stddeviation: 'stdDeviation'
+ stitchtiles: 'stitchTiles'
+ surfacescale: 'surfaceScale'
+ systemlanguage: 'systemLanguage'
+ tablevalues: 'tableValues'
+ targetx: 'targetX'
+ targety: 'targetY'
+ textlength: 'textLength'
+ viewbox: 'viewBox'
+ viewtarget: 'viewTarget'
+ xchannelselector: 'xChannelSelector'
+ ychannelselector: 'yChannelSelector'
+ zoomandpan: 'zoomAndPan'
+}
+adjust_mathml_attributes = (t) ->
+ for a in t.attrs_a
+ if a[0] is 'definitionurl'
+ a[0] = 'definitionURL'
+ return
+adjust_svg_attributes = (t) ->
+ for a in t.attrs_a
+ if svg_attribute_fixes[a[0]]?
+ a[0] = svg_attribute_fixes[a[0]]
+ return
+adjust_foreign_attributes = (t) ->
+ # fixfull
+ return
+
# decode_named_char_ref()
#
# The list of named character references is _huge_ so ask the browser to decode
return is_in_scope_x_y tag_name, standard_scopers, button_scopers, namespace
is_in_table_scope = (tag_name, namespace = null) ->
return is_in_scope_x tag_name, table_scopers, namespace
+ # aka is_in_list_item_scope
+ is_in_li_scope = (tag_name, namespace = null) ->
+ return is_in_scope_x_y tag_name, standard_scopers, li_scopers, namespace
is_in_select_scope = (tag_name, namespace = null) ->
for t in open_els
if t.name is tag_name and (namespace is null or namespace is t.namespace)
# http://www.w3.org/TR/html5/syntax.html#reconstruct-the-active-formatting-elements
# this implementation is structured (mostly) as described at the link above.
# capitalized comments are the "labels" described at the link above.
- reconstruct_active_formatting_elements = ->
+ reconstruct_afe = ->
return if afe.length is 0
if afe[0].type is TYPE_AFE_MARKER or afe[0] in open_els
return
open_els.unshift el
return el
# http://www.w3.org/TR/html5/syntax.html#insert-an-html-element
- insert_html_element = insert_foreign_element # (token, namespace) ->
+ insert_html_element = (token) ->
+ insert_foreign_element token, NS_HTML
# http://www.w3.org/TR/html5/syntax.html#insert-a-comment
# position should be [node, index_within_children]
parse_error()
return
if is_space_tok t
- reconstruct_active_formatting_elements()
+ reconstruct_afe()
insert_character t
return
if t.type is TYPE_TEXT
- reconstruct_active_formatting_elements()
+ reconstruct_afe()
insert_character t
flag_frameset_ok = false
return
# spec: If the next token is a "LF" (U+000A) character token, then
# ignore that token and move on to the next one. (Newlines at the
# start of pre blocks are ignored as an authoring convenience.)
- if txt.charAt(cur) is "\u000a"
+ if txt.charAt(cur) is "\u000a" # FIXME check for crlf?
cur += 1
flag_frameset_ok = false
return
close_p_if_in_button_scope()
insert_html_element t
return
- # FIXME CONTINUE
-
+ if t.type is TYPE_START_TAG and t.name is 'plaintext'
+ close_p_if_in_button_scope()
+ insert_html_element t
+ tok_state = tok_state_plaintext
+ return
+ if t.type is TYPE_START_TAG and t.name is 'button'
+ if is_in_scope 'button', NS_HTML
+ parse_error()
+ generate_implied_end_tags()
+ loop
+ el = open_els.shift()
+ if el.name is 'button' and el.namespace is NS_HTML
+ break
+ reconstruct_afe()
+ insert_html_element t
+ flag_frameset_ok = false
+ return
+ if t.type is TYPE_END_TAG and (t.name is 'address' or t.name is 'article' or t.name is 'aside' or t.name is 'blockquote' or t.name is 'button' or t.name is 'center' or t.name is 'details' or t.name is 'dialog' or t.name is 'dir' or t.name is 'div' or t.name is 'dl' or t.name is 'fieldset' or t.name is 'figcaption' or t.name is 'figure' or t.name is 'footer' or t.name is 'header' or t.name is 'hgroup' or t.name is 'listing' or t.name is 'main' or t.name is 'nav' or t.name is 'ol' or t.name is 'pre' or t.name is 'section' or t.name is 'summary' or t.name is 'ul')
+ unless is_in_scope t.name, NS_HTML
+ parse_error()
+ return
+ generate_implied_end_tags()
+ unless open_els[0].name is t.name and open_els[0].namespace is NS_HTML
+ parse_error()
+ loop
+ el = open_els.shift()
+ if el.name is t.name and el.namespace is NS_HTML
+ return
+ return
+ if t.type is TYPE_END_TAG and t.name is 'form'
+ unless template_tag_is_open()
+ node = form_element_pointer
+ form_element_pointer = null
+ if node is null or not el_is_in_scope node
+ parse_error()
+ return
+ generate_implied_end_tags()
+ if open_els[0] isnt node
+ parse_error()
+ for el, i in open_els
+ if el is node
+ open_els.splice i, 1
+ break
+ else
+ unless is_in_scope 'form', NS_HTML
+ parse_error()
+ return
+ generate_implied_end_tags()
+ if open_els[0].name isnt 'form' or open_els[0].namespace isnt NS_HTML
+ parse_error()
+ loop
+ el = open_els.shift()
+ if el.name is 'form' and el.namespace is NS_HTML
+ break
+ return
+ if t.type is TYPE_END_TAG and t.name is 'p'
+ unless is_in_button_scope 'p', NS_HTML
+ parse_error()
+ insert_html_element new_open_tag 'p'
+ close_p_element()
+ return
+ if t.type is TYPE_END_TAG and t.name is 'li'
+ unless is_in_li_scope 'li', NS_HTML
+ parse_error()
+ return
+ generate_implied_end_tags 'li' # arg is exception
+ if open_els[0].name isnt 'li' or open_els[0].namespace isnt NS_HTML
+ parse_error()
+ loop
+ el = open_els.shift()
+ if el.name is 'li' and el.namespace is NS_HTML
+ break
+ return
+ if t.type is TYPE_END_TAG and (t.name is 'dd' or t.name is 'dt')
+ unless is_in_scope t.name, NS_HTML
+ parse_error()
+ return
+ generate_implied_end_tags t.name # arg is exception
+ if open_els[0].name isnt t.name or open_els[0].namespace isnt NS_HTML
+ parse_error()
+ loop
+ el = open_els.shift()
+ if el.name is t.name and el.namespace is NS_HTML
+ break
+ return
+ if t.type is TYPE_END_TAG and h_tags[t.name]?
+ h_in_scope = false
+ for el in open_els
+ if h_tags[el.name] is el.namespace
+ h_in_scope = true
+ break
+ if standard_scopers[el.name] is el.namespace
+ break
+ unless h_in_scope
+ parse_error()
+ return
+ generate_implied_end_tags()
+ if open_els[0].name isnt t.name or open_els[0].namespace isnt NS_HTML
+ parse_error()
+ loop
+ el = open_els.shift()
+ if h_tags[el.name] is el.namespace
+ break
+ return
+ # deep breath!
if t.type is TYPE_START_TAG and t.name is 'a'
# If the list of active formatting elements contains an a element
# between the end of the list and the last marker on the list (or
for el in afe
if el.type is TYPE_AFE_MARKER
break
- if el.name is 'a'
+ if el.name is 'a' and el.namespace is NS_HTML
found = el
if found?
parse_error()
for el, i in open_els
if el is found
open_els.splice i, 1
- reconstruct_active_formatting_elements()
+ reconstruct_afe()
el = insert_html_element t
afe_push el
return
if t.type is TYPE_START_TAG and (t.name is 'b' or t.name is 'big' or t.name is 'code' or t.name is 'em' or t.name is 'font' or t.name is 'i' or t.name is 's' or t.name is 'small' or t.name is 'strike' or t.name is 'strong' or t.name is 'tt' or t.name is 'u')
- reconstruct_active_formatting_elements()
+ reconstruct_afe()
el = insert_html_element t
afe_push el
return
- if t.type is TYPE_START_TAG and t.name is 'table'
- # fixfull quirksmode thing
- close_p_if_in_button_scope()
+ if t.type is TYPE_START_TAG and t.name is 'nobr'
+ reconstruct_afe()
+ el = insert_html_element t
+ afe_push el
+ return
+ if t.type is TYPE_END_TAG and (t.name is 'a' or t.name is 'b' or t.name is 'big' or t.name is 'code' or t.name is 'em' or t.name is 'font' or t.name is 'i' or t.name is 'nobr' or t.name is 's' or t.name is 'small' or t.name is 'strike' or t.name is 'strong' or t.name is 'tt' or t.name is 'u')
+ adoption_agency t.name
+ return
+ if t.type is TYPE_START_TAG and (t.name is 'applet' or t.name is 'marquee' or t.name is 'object')
+ reconstruct_afe()
insert_html_element t
- ins_mode = ins_mode_in_table
+ afe_push_marker()
+ flag_frameset_ok = false
return
- if t.type is TYPE_END_TAG and (t.name is 'address' or t.name is 'article' or t.name is 'aside' or t.name is 'blockquote' or t.name is 'button' or t.name is 'center' or t.name is 'details' or t.name is 'dialog' or t.name is 'dir' or t.name is 'div' or t.name is 'dl' or t.name is 'fieldset' or t.name is 'figcaption' or t.name is 'figure' or t.name is 'footer' or t.name is 'header' or t.name is 'hgroup' or t.name is 'listing' or t.name is 'main' or t.name is 'nav' or t.name is 'ol' or t.name is 'pre' or t.name is 'section' or t.name is 'summary' or t.name is 'ul')
+ if t.type is TYPE_END_TAG and (t.name is 'applet' or t.name is 'marquee' or t.name is 'object')
unless is_in_scope t.name, NS_HTML
parse_error()
return
generate_implied_end_tags()
- unless open_els[0].name is t.name and open_els[0].namespace is NS_HTML
+ if open_els[0].name isnt t.name or open_els[0].namespace isnt NS_HTML
parse_error()
loop
el = open_els.shift()
if el.name is t.name and el.namespace is NS_HTML
- return
+ break
+ clear_afe_to_marker()
return
- if t.type is TYPE_END_TAG and t.name is 'p'
- unless is_in_button_scope 'p'
- parse_error()
- insert_html_element new_open_tag 'p'
- close_p_element()
+ if t.type is TYPE_START_TAG and t.name is 'table'
+ close_p_if_in_button_scope() # fixfull quirksmode thing
+ insert_html_element t
+ flag_frameset_ok = false
+ ins_mode = ins_mode_in_table
return
- if t.type is TYPE_END_TAG and (t.name is 'a' or t.name is 'b' or t.name is 'big' or t.name is 'code' or t.name is 'em' or t.name is 'font' or t.name is 'i' or t.name is 'nobr' or t.name is 's' or t.name is 'small' or t.name is 'strike' or t.name is 'strong' or t.name is 'tt' or t.name is 'u')
- adoption_agency t.name
+ if t.type is TYPE_END_TAG and t.name is 'br'
+ parse_error()
+ t.type is TYPE_START_TAG
+ # fall through
+ if t.type is TYPE_START_TAG and (t.name is 'area' or t.name is 'br' or t.name is 'embed' or t.name is 'img' or t.name is 'keygen' or t.name is 'wbr')
+ reconstruct_afe()
+ insert_html_element t
+ open_els.shift()
+ t.acknowledge_self_closing()
+ flag_frameset_ok = false
+ return
+ if t.type is TYPE_START_TAG and t.name is 'input'
+ reconstruct_afe()
+ insert_html_element t
+ open_els.shift()
+ t.acknowledge_self_closing()
+ unless is_input_hidden_tok t
+ flag_frameset_ok = false
+ return
+ if t.type is TYPE_START_TAG and (t.name is 'param' or t.name is 'source' or t.name is 'track')
+ insert_html_element t
+ open_els.shift()
+ t.acknowledge_self_closing()
+ return
+ if t.type is TYPE_START_TAG and t.name is 'hr'
+ close_p_if_in_button_scope()
+ insert_html_element t
+ open_els.shift()
+ t.acknowledge_self_closing()
+ flag_frameset_ok = false
+ return
+ if t.type is TYPE_START_TAG and t.name is 'image'
+ parse_error()
+ t.name = 'img'
+ ins_mode t
+ return
+ if t.type is TYPE_START_TAG and t.name is 'isindex'
+ parse_error()
+ if template_tag_is_open() is false and form_element_pointer isnt null
+ return
+ t.acknowledge_self_closing()
+ flag_frameset_ok = false
+ close_p_if_in_button_scope()
+ el = insert_html_element new_open_tag 'form'
+ unless template_tag_is_open()
+ form_element_pointer = el
+ for a in t.attrs_a
+ if a[0] is 'action'
+ el.attrs['action'] = a[1]
+ break
+ insert_html_element new_open_tag 'hr'
+ open_els.shift()
+ reconstruct_afe()
+ insert_html_element new_open_tag 'label'
+ # note: this is a little out-of-spec-order so we only have to scan t.attrs_a once
+ input_el = new_open_tag 'input'
+ prompt = null
+ for a in t.attrs_a
+ if a[0] is 'prompt'
+ prompt = a[1]
+ if a[0] isnt 'name' and a[0] isnt 'action' and a[0] isnt 'prompt'
+ input_el.attrs_a.push [a[0], a[1]]
+ input_el.attrs_a.push ['name', 'isindex']
+ # fixfull this next bit is in english... internationalize?
+ prompt ?= "This is a searchable index. Enter search keywords: "
+ insert_character prompt # fixfull split
+ # TODO submit typo "balue" in spec
+ insert_html_element input_el
+ open_els.shift()
+ # insert_character '' # you can put chars here if promt attr missing
+ open_els.shift()
+ insert_html_element new_open_tag 'hr'
+ open_els.shift()
+ open_els.shift()
+ unless template_tag_is_open()
+ form_element_pointer = null
+ return
+ if t.type is TYPE_START_TAG and t.name is 'textarea'
+ insert_html_element t
+ if txt.charAt(cur) is "\u000a" # FIXME check for crlf?
+ cur += 1
+ tok_state = tok_state_rcdata
+ original_ins_mode = ins_mode
+ flag_frameset_ok = false
+ ins_mode = ins_mode_text
+ return
+ if t.type is TYPE_START_TAG and t.name is 'xmp'
+ close_p_if_in_button_scope()
+ reconstruct_afe()
+ flag_frameset_ok = false
+ parse_generic_raw_text t
+ return
+ if t.type is TYPE_START_TAG and t.name is 'iframe'
+ flag_frameset_ok = false
+ parse_generic_raw_text t
+ return
+ if t.type is TYPE_START_TAG and (t.name is 'noembed' or (t.name is 'noscript' and flag_scripting))
+ parse_generic_raw_text t
+ return
+ if t.type is TYPE_START_TAG and t.name is 'select'
+ reconstruct_afe()
+ insert_html_element t
+ flag_frameset_ok = false
+ if ins_mode is ins_mode_in_table or ins_mode is ins_mode_in_caption or ins_mode is ins_mode_in_table_body or ins_mode is ins_mode_in_row or ins_mode is ins_mode_in_cell
+ ins_mode = ins_mode_in_select_in_table
+ else
+ ins_mode = ins_mode_in_select
+ return
+ if t.type is TYPE_START_TAG and (t.name is 'optgroup' or t.name is 'option')
+ if open_els[0].name is 'option' and open_els[0].namespace is NS_HTML
+ open_els.shift()
+ reconstruct_afe()
+ insert_html_element t
+ return
+ if t.type is TYPE_START_TAG and (t.name is 'rb' or t.name is 'rp' or t.name is 'rtc')
+ if is_in_scope 'ruby', NS_HTML
+ generate_implied_end_tags()
+ unless open_els[0].name is 'ruby' and open_els[0].namespace is NS_HTML
+ parse_error()
+ insert_html_element t
+ return
+ if t.type is TYPE_START_TAG and t.name is 'rt'
+ if is_in_scope 'ruby', NS_HTML
+ generate_implied_end_tags 'rtc' # arg is exception
+ unless (open_els[0].name is 'ruby' or open_els[0].name is 'rtc') and open_els[0].namespace is NS_HTML
+ parse_error()
+ insert_html_element t
+ return
+ if t.type is TYPE_START_TAG and t.name is 'math'
+ reconstruct_afe()
+ adjust_mathml_attributes t
+ adjust_foreign_attributes t
+ insert_foreign_element t, NS_MATHML
+ if t.flag 'self-closing'
+ open_els.shift()
+ t.acknowledge_self_closing()
+ return
+ if t.type is TYPE_START_TAG and t.name is 'svg'
+ reconstruct_afe()
+ adjust_svg_attributes t
+ adjust_foreign_attributes t
+ insert_foreign_element t, NS_SVG
+ if t.flag 'self-closing'
+ open_els.shift()
+ t.acknowledge_self_closing()
+ return
+ if t.type is TYPE_START_TAG and (t.name is 'caption' or t.name is 'col' or t.name is 'colgroup' or t.name is 'frame' or t.name is 'head' or t.name is 'tbody' or t.name is 'td' or t.name is 'tfoot' or t.name is 'th' or t.name is 'thead' or t.name is 'tr')
+ parse_error()
return
if t.type is TYPE_START_TAG # any other start tag
- reconstruct_active_formatting_elements()
+ reconstruct_afe()
insert_html_element t
return
if t.type is TYPE_END_TAG # any other end tag
in_body_any_other_end_tag t.name
+ return
return
ins_mode_in_table_else = (t) ->
# Anything else
return null
+ # 8.2.4.68 http://www.w3.org/TR/html5/syntax.html#cdata-section-state
+ tok_state_cdata_section = ->
+ tok_state = tok_state_data
+ next_gt = txt.indexOf ']]>', cur
+ if next_gt is -1
+ val = txt.substr cur
+ cur = txt.length
+ else
+ val = txt.substr cur, (next_gt - cur)
+ cur = next_gt + 3
+ val = val.replace "\u0000", "\ufffd" # fixfull spec doesn't say this
+ return new_character_token val # fixfull split
# 8.2.4.69 http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference
# Don't set this as a state, just call it
module.exports.TYPE_TEXT = TYPE_TEXT
module.exports.TYPE_COMMENT = TYPE_COMMENT
module.exports.TYPE_DOCTYPE = TYPE_DOCTYPE
+module.exports.NS_HTML = NS_HTML
+module.exports.NS_MATHML = NS_MATHML
+module.exports.NS_SVG = NS_SVG