///|
fn Parser::is_special_text_element(self : Parser, name : StringView) -> Bool {
if name == "noscript" {
self.scripting_enabled
} else {
is_special_text_element(name)
}
}
///|
fn is_special_text_element(name : StringView) -> Bool {
match name {
"iframe"
| "noembed"
| "noframes"
| "noscript"
| "plaintext"
| "script"
| "style"
| "title"
| "textarea"
| "xmp" => true
_ => false
}
}
///|
fn special_text_eof_error_code(name : StringView) -> String {
match name {
"noframes" | "script" | "style" | "title" | "xmp" =>
"expected-named-closing-tag-but-got-eof"
_ => "expected-closing-tag-but-got-eof"
}
}
///|
fn Parser::error_at_special_text_eof(self : Parser, name : StringView) -> Unit {
self.error_at(special_text_eof_error_code(name), self.eof_error_pos())
}
///|
fn Parser::decoded_special_text(
self : Parser,
name : StringView,
raw : StringView,
start : Int,
error_pos : Int,
) -> String {
let (raw, offset) = if name == "textarea" {
strip_one_initial_lf_with_offset(raw)
} else {
(raw, 0)
}
let raw = self.replace_null_characters(raw, start + offset)
let data = if @tok.special_text_decodes_entities(name) {
let decoded = @tok.decode_entities_with_errors(raw, in_attribute=false)
for error in decoded.errors {
self.error_at(error.code, error_pos)
}
decoded.data
} else {
normalize_newlines(raw)
}
let data = normalize_tree_builder_text(data)
if self.xml_coercion {
coerce_text_for_xml(data)
} else {
data
}
}
///|
fn strip_one_initial_lf_with_offset(input : StringView) -> (StringView, Int) {
match input.get_char(0) {
Some('\r') =>
if input.get_char(1) is Some('\n') {
(input[2:], 2)
} else {
(input[1:], 1)
}
Some('\n') => (input[1:], 1)
_ => (input, 0)
}
}
///|
fn Parser::skip_one_initial_lf(self : Parser) -> Unit {
match self.current() {
Some('\r') => {
self.pos += 1
if self.current() == Some('\n') {
self.pos += 1
}
}
Some('\n') => self.pos += 1
_ => ()
}
}
///|
fn start_tag_ignores_initial_lf(name : StringView) -> Bool {
match name {
"pre" | "listing" => true
_ => false
}
}
///|
fn Parser::skip_matching_end_tag(self : Parser) -> Unit {
self.pos += 2
while !self.is_eof() {
if self.current().unwrap() == '>' {
break
} else {
ignore(self.advance_char())
}
}
if self.current() == Some('>') {
ignore(self.advance_char())
}
}
///|
fn Parser::consume_matching_special_end_tag(self : Parser) -> Bool {
self.pos += 2
while !self.is_eof() {
guard self.current() is Some(ch) else { break }
match ch {
'>' | '/' => break
ch if ch.is_ascii_whitespace() => break
_ => ignore(self.advance_char())
}
}
let attrs : Map[String, String?] = {}
let mut closed = false
while !self.is_eof() {
self.skip_ascii_whitespace()
guard self.current() is Some(ch) else { break }
match ch {
'>' => {
ignore(self.advance_char())
closed = true
break
}
'/' => {
ignore(self.advance_char())
if self.current() == Some('>') {
ignore(self.advance_char())
closed = true
break
} else {
self.error_at("unexpected-character-after-solidus-in-tag", self.pos)
}
}
_ => self.parse_attribute(attrs)
}
}
if !closed {
self.error_at_eof("eof-in-tag")
}
closed
}
///|
fn Parser::consume_special_element_content(
self : Parser,
parent : @dom.Node,
name : String,
) -> Unit {
let content_start = self.pos
if name == "plaintext" {
let view = self.input[content_start:self.input.length()]
parent.append_child(
self.text_at(
self.decoded_special_text(
name,
view,
content_start,
eof_error_pos(self.input),
),
content_start,
),
)
self.error_at_special_text_eof(name)
self.pos = self.input.length()
return
}
if name == "script" {
let scan = @tok.scan_script_text(self.input, self.pos)
for error in scan.errors {
self.error_at(error.code, error.offset)
}
if !scan.data.is_empty() {
let scan_data = normalize_tree_builder_text(scan.data)
let data = if self.xml_coercion {
coerce_text_for_xml(scan_data)
} else {
scan_data
}
parent.append_child(self.text_at(data, content_start))
}
match scan.end_start {
Some(end_start) => {
self.pos = end_start
if !self.consume_matching_special_end_tag() {
self.error_at_special_text_eof(name)
}
}
None => {
self.error_at_special_text_eof(name)
self.pos = self.input.length()
}
}
return
}
match @tok.find_matching_end_tag(self.input, self.pos, name) {
Some(end_start) => {
let error_pos = @tok.matching_end_tag_error_pos(self.input, end_start)
let view = self.input[content_start:end_start]
parent.append_child(
self.text_at(
self.decoded_special_text(name, view, content_start, error_pos),
content_start,
),
)
self.pos = end_start
if !self.consume_matching_special_end_tag() {
self.error_at_special_text_eof(name)
}
}
None => {
let error_pos = eof_error_pos(self.input)
let view = self.input[content_start:self.input.length()]
parent.append_child(
self.text_at(
self.decoded_special_text(name, view, content_start, error_pos),
content_start,
),
)
self.error_at_special_text_eof(name)
self.pos = self.input.length()
}
}
}