///|
fn html_data_attributes(
value : String,
) -> Map[String, String] raise ParseFailure {
let attributes : Map[String, String] = Map([])
for item in value.split(",") {
guard item.split_once("=") is Some((key, data_value)) else {
raise InvalidArgument(
message="\\htmlData key/value '\{item}' missing equals sign",
loc=None,
)
}
let key = key.trim(chars=" \t\n\r")
attributes["data-\{key}"] = data_value.to_owned()
}
attributes
}
///|
fn html_spec() -> FunctionSpec {
FunctionSpec::make(
["\\htmlClass", "\\htmlId", "\\htmlStyle", "\\htmlData"],
2,
arg_types=[RawArg, OriginalArg],
allowed_in_text=true,
handler=html_handler,
)
}
///|
fn html_handler(
context : FunctionContext,
args : Array[ParseNode],
_ : Array[ParseNode?],
) -> ParseNode raise ParseFailure {
guard require_function_arg(args, 0, context.func_name)
is Raw(string=value, ..) else {
raise InternalInvariant(
message="Expected raw argument for \{context.func_name}",
)
}
(context.report_nonstrict)(
"htmlExtension", "HTML extension is disabled on strict mode",
)
let attributes : Map[String, String] = Map([])
let trust_context = match context.func_name {
"\\htmlClass" => {
attributes["class"] = value
HtmlClass(class=value)
}
"\\htmlId" => {
attributes["id"] = value
HtmlId(id=value)
}
"\\htmlStyle" => {
attributes["style"] = value
HtmlStyle(style=value)
}
"\\htmlData" => {
let parsed = html_data_attributes(value)
for key, item in parsed {
attributes[key] = item
}
HtmlData(attributes~)
}
_ => raise InternalInvariant(message="Unrecognized html command")
}
let body = ord_argument(require_function_arg(args, 1, context.func_name))
if (context.is_trusted)(trust_context) {
Html(mode=context.mode, attributes~, body~)
} else {
OrdGroup(mode=context.mode, loc=None, body~, semisimple=false)
}
}