2026-01-26 05:12:14 +01:00
{# retoor < retoor @ molodetz . nl > #}
{% extends 'page.html' %}
2026-01-25 02:47:47 +01:00
2026-01-26 05:12:14 +01:00
{% set page_title = "html" %}
{% set breadcrumb = [{"url": "api/index.html", "title": "API Reference"}, {"title": "html"}] %}
{% set prev_page = {"url": "api/fswatch.html", "title": "fswatch"} %}
{% set next_page = {"url": "api/http.html", "title": "http"} %}
{% block article %}
2026-01-25 02:47:47 +01:00
< h1 > html</ h1 >
2026-01-26 16:28:49 +01:00
< p > The < code > html</ code > module provides HTML/URL utilities and a complete DOM implementation for parsing, querying, manipulating, and serializing HTML documents.</ p >
2026-01-25 02:47:47 +01:00
2026-01-26 16:28:49 +01:00
< pre >< code > import "html" for Html, Document, Element, TextNode, NodeList</ code ></ pre >
2026-01-25 02:47:47 +01:00
< h2 > Html Class</ h2 >
< div class = "class-header" >
< h3 > Html</ h3 >
< p > HTML and URL encoding utilities</ p >
</ div >
< h3 > Static Methods</ h3 >
< div class = "method-signature" >
2026-01-26 16:28:49 +01:00
< span class = "method-name" > Html.urlencode</ span > (< span class = "param" > string</ span > ) → < span class = "type" > String</ span >
2026-01-25 02:47:47 +01:00
</ div >
2026-01-26 16:28:49 +01:00
< p > URL-encodes a string for use in URLs and query parameters.</ p >
2026-01-25 02:47:47 +01:00
< ul class = "param-list" >
< li >< span class = "param-name" > string</ span > < span class = "param-type" > (String)</ span > - The string to encode</ li >
< li >< span class = "returns" > Returns:</ span > URL-encoded string</ li >
</ ul >
2026-01-26 16:28:49 +01:00
< pre >< code > System.print(Html.urlencode("hello world")) // hello+world</ code ></ pre >
2026-01-25 02:47:47 +01:00
< div class = "method-signature" >
2026-01-26 16:28:49 +01:00
< span class = "method-name" > Html.urldecode</ span > (< span class = "param" > string</ span > ) → < span class = "type" > String</ span >
2026-01-25 02:47:47 +01:00
</ div >
2026-01-26 16:28:49 +01:00
< p > Decodes a URL-encoded string.</ p >
2026-01-25 02:47:47 +01:00
< ul class = "param-list" >
< li >< span class = "param-name" > string</ span > < span class = "param-type" > (String)</ span > - The URL-encoded string</ li >
< li >< span class = "returns" > Returns:</ span > Decoded string</ li >
</ ul >
2026-01-26 16:28:49 +01:00
< pre >< code > System.print(Html.urldecode("hello+world")) // hello world</ code ></ pre >
2026-01-25 02:47:47 +01:00
< div class = "method-signature" >
2026-01-26 16:28:49 +01:00
< span class = "method-name" > Html.slugify</ span > (< span class = "param" > string</ span > ) → < span class = "type" > String</ span >
2026-01-25 02:47:47 +01:00
</ div >
2026-01-26 16:28:49 +01:00
< p > Converts a string to a URL-friendly slug.</ p >
2026-01-25 02:47:47 +01:00
< ul class = "param-list" >
< li >< span class = "param-name" > string</ span > < span class = "param-type" > (String)</ span > - The string to slugify</ li >
< li >< span class = "returns" > Returns:</ span > URL-friendly slug</ li >
</ ul >
2026-01-26 16:28:49 +01:00
< pre >< code > System.print(Html.slugify("Hello World!")) // hello-world</ code ></ pre >
2026-01-25 02:47:47 +01:00
< div class = "method-signature" >
2026-01-26 16:28:49 +01:00
< span class = "method-name" > Html.quote</ span > (< span class = "param" > string</ span > ) → < span class = "type" > String</ span >
2026-01-25 02:47:47 +01:00
</ div >
< p > Escapes HTML special characters to prevent XSS attacks.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > string</ span > < span class = "param-type" > (String)</ span > - The string to escape</ li >
< li >< span class = "returns" > Returns:</ span > HTML-escaped string</ li >
</ ul >
2026-01-26 16:28:49 +01:00
< pre >< code > System.print(Html.quote("< script> ")) // & lt;script& gt;</ code ></ pre >
2026-01-25 02:47:47 +01:00
< div class = "method-signature" >
2026-01-26 16:28:49 +01:00
< span class = "method-name" > Html.unquote</ span > (< span class = "param" > string</ span > ) → < span class = "type" > String</ span >
2026-01-25 02:47:47 +01:00
</ div >
< p > Unescapes HTML entities back to their original characters.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > string</ span > < span class = "param-type" > (String)</ span > - The HTML-escaped string</ li >
< li >< span class = "returns" > Returns:</ span > Unescaped string</ li >
</ ul >
2026-01-26 16:28:49 +01:00
< pre >< code > System.print(Html.unquote("& lt;div& gt;")) // < div> </ code ></ pre >
2026-01-25 02:47:47 +01:00
< div class = "method-signature" >
2026-01-26 16:28:49 +01:00
< span class = "method-name" > Html.encodeParams</ span > (< span class = "param" > params</ span > ) → < span class = "type" > String</ span >
2026-01-25 02:47:47 +01:00
</ div >
< p > Encodes a map of key-value pairs into a URL query string.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > params</ span > < span class = "param-type" > (Map)</ span > - Map of parameters to encode</ li >
< li >< span class = "returns" > Returns:</ span > URL-encoded query string</ li >
</ ul >
2026-01-26 16:28:49 +01:00
< pre >< code > System.print(Html.encodeParams({"name": "John", "age": 30})) // name=John& age=30</ code ></ pre >
2026-01-25 02:47:47 +01:00
< div class = "method-signature" >
2026-01-26 16:28:49 +01:00
< span class = "method-name" > Html.decodeParams</ span > (< span class = "param" > string</ span > ) → < span class = "type" > Map</ span >
2026-01-25 02:47:47 +01:00
</ div >
< p > Decodes a URL query string into a map of key-value pairs.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > string</ span > < span class = "param-type" > (String)</ span > - URL-encoded query string</ li >
< li >< span class = "returns" > Returns:</ span > Map of decoded parameters</ li >
</ ul >
2026-01-26 16:28:49 +01:00
< pre >< code > var params = Html.decodeParams("name=John& age=30")
System.print(params["name"]) // John</ code ></ pre >
2026-01-25 02:47:47 +01:00
2026-01-26 16:28:49 +01:00
< hr >
< h2 > Document Class</ h2 >
< div class = "class-header" >
< h3 > Document</ h3 >
< p > Represents a parsed HTML document. Provides methods to query and manipulate the DOM tree.</ p >
</ div >
< h3 > Constructor</ h3 >
< div class = "method-signature" >
< span class = "method-name" > Document.parse</ span > (< span class = "param" > html</ span > ) → < span class = "type" > Document</ span >
</ div >
< p > Parses an HTML string and returns a Document object.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > html</ span > < span class = "param-type" > (String)</ span > - HTML string to parse</ li >
< li >< span class = "returns" > Returns:</ span > Document object representing the parsed HTML</ li >
</ ul >
< pre >< code > var doc = Document.parse("< div>< p> Hello< /p>< /div> ")
System.print(doc.body) // Element</ code ></ pre >
< h3 > Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > document.documentElement</ span > → < span class = "type" > Element</ span >
</ div >
< p > Returns the root element of the document (typically the html element).</ p >
< div class = "method-signature" >
< span class = "method-name" > document.head</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the head element of the document, or null if not present.</ p >
< div class = "method-signature" >
< span class = "method-name" > document.body</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the body element of the document, or null if not present.</ p >
< div class = "method-signature" >
< span class = "method-name" > document.title</ span > → < span class = "type" > String</ span >
</ div >
< p > Gets the document title (content of the title element).</ p >
< pre >< code > var doc = Document.parse("< title> My Page< /title> ")
System.print(doc.title) // My Page</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > document.title=</ span > (< span class = "param" > value</ span > )
</ div >
< p > Sets the document title.</ p >
< pre >< code > doc.title = "New Title"</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > document.innerHTML</ span > → < span class = "type" > String</ span >
</ div >
< p > Returns the inner HTML content of the document element.</ p >
< div class = "method-signature" >
< span class = "method-name" > document.outerHTML</ span > → < span class = "type" > String</ span >
</ div >
< p > Returns the complete HTML serialization of the document.</ p >
< pre >< code > var doc = Document.parse("< div> Hello< /div> ")
System.print(doc.outerHTML) // < html>< div> Hello< /div>< /html> </ code ></ pre >
< h3 > Query Methods</ h3 >
< div class = "method-signature" >
< span class = "method-name" > document.querySelector</ span > (< span class = "param" > selector</ span > ) → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the first element matching the CSS selector, or null if not found.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > selector</ span > < span class = "param-type" > (String)</ span > - CSS selector string</ li >
< li >< span class = "returns" > Returns:</ span > First matching Element or null</ li >
</ ul >
< pre >< code > var doc = Document.parse("< div class='box'> Content< /div> ")
var elem = doc.querySelector(".box")
System.print(elem.textContent) // Content</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > document.querySelectorAll</ span > (< span class = "param" > selector</ span > ) → < span class = "type" > NodeList</ span >
</ div >
< p > Returns all elements matching the CSS selector.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > selector</ span > < span class = "param-type" > (String)</ span > - CSS selector string</ li >
< li >< span class = "returns" > Returns:</ span > NodeList of matching elements</ li >
</ ul >
< pre >< code > var doc = Document.parse("< p> One< /p>< p> Two< /p> ")
var elems = doc.querySelectorAll("p")
System.print(elems.count) // 2</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > document.getElementById</ span > (< span class = "param" > id</ span > ) → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the element with the specified ID, or null if not found.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > id</ span > < span class = "param-type" > (String)</ span > - The element ID to search for</ li >
< li >< span class = "returns" > Returns:</ span > Element with matching ID or null</ li >
</ ul >
< pre >< code > var doc = Document.parse("< div id='main'> Content< /div> ")
var elem = doc.getElementById("main")
System.print(elem.tagName) // DIV</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > document.getElementsByClassName</ span > (< span class = "param" > className</ span > ) → < span class = "type" > NodeList</ span >
</ div >
< p > Returns all elements with the specified class name.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > className</ span > < span class = "param-type" > (String)</ span > - The class name to search for</ li >
< li >< span class = "returns" > Returns:</ span > NodeList of matching elements</ li >
</ ul >
< pre >< code > var doc = Document.parse("< div class='item'> A< /div>< div class='item'> B< /div> ")
var elems = doc.getElementsByClassName("item")
System.print(elems.count) // 2</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > document.getElementsByTagName</ span > (< span class = "param" > tagName</ span > ) → < span class = "type" > NodeList</ span >
</ div >
< p > Returns all elements with the specified tag name.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > tagName</ span > < span class = "param-type" > (String)</ span > - The tag name to search for (case-insensitive)</ li >
< li >< span class = "returns" > Returns:</ span > NodeList of matching elements</ li >
</ ul >
< pre >< code > var doc = Document.parse("< p> One< /p>< p> Two< /p>< span> Three< /span> ")
var elems = doc.getElementsByTagName("p")
System.print(elems.count) // 2</ code ></ pre >
< h3 > Element Creation</ h3 >
< div class = "method-signature" >
< span class = "method-name" > document.createElement</ span > (< span class = "param" > tagName</ span > ) → < span class = "type" > Element</ span >
</ div >
< p > Creates a new element with the specified tag name.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > tagName</ span > < span class = "param-type" > (String)</ span > - The tag name for the new element</ li >
< li >< span class = "returns" > Returns:</ span > New Element object</ li >
</ ul >
< pre >< code > var doc = Document.parse("< div>< /div> ")
var p = doc.createElement("p")
p.textContent = "Hello"
doc.querySelector("div").appendChild(p)</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > document.createTextNode</ span > (< span class = "param" > text</ span > ) → < span class = "type" > TextNode</ span >
</ div >
< p > Creates a new text node with the specified content.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > text</ span > < span class = "param-type" > (String)</ span > - The text content</ li >
< li >< span class = "returns" > Returns:</ span > New TextNode object</ li >
</ ul >
< pre >< code > var doc = Document.parse("< div>< /div> ")
var text = doc.createTextNode("Hello World")
doc.querySelector("div").appendChild(text)</ code ></ pre >
< hr >
< h2 > Element Class</ h2 >
< div class = "class-header" >
< h3 > Element</ h3 >
< p > Represents an HTML element in the DOM tree. Provides methods for traversal, manipulation, and querying.</ p >
</ div >
< h3 > Identity Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > element.tagName</ span > → < span class = "type" > String</ span >
</ div >
< p > Returns the tag name of the element in uppercase.</ p >
< pre >< code > var div = doc.querySelector("div")
System.print(div.tagName) // DIV</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.id</ span > → < span class = "type" > String</ span >
</ div >
< p > Gets the ID attribute of the element.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.id=</ span > (< span class = "param" > value</ span > )
</ div >
< p > Sets the ID attribute of the element.</ p >
< pre >< code > elem.id = "newId"
System.print(elem.id) // newId</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.className</ span > → < span class = "type" > String</ span >
</ div >
< p > Gets the class attribute as a string.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.className=</ span > (< span class = "param" > value</ span > )
</ div >
< p > Sets the class attribute.</ p >
< pre >< code > elem.className = "foo bar"
System.print(elem.className) // foo bar</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.classList</ span > → < span class = "type" > List</ span >
</ div >
< p > Returns the class names as a list of strings.</ p >
< pre >< code > elem.className = "foo bar baz"
var classes = elem.classList
System.print(classes[0]) // foo
System.print(classes.count) // 3</ code ></ pre >
< h3 > Node Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > element.nodeType</ span > → < span class = "type" > Num</ span >
</ div >
< p > Returns the node type (1 for Element).</ p >
< div class = "method-signature" >
< span class = "method-name" > element.nodeName</ span > → < span class = "type" > String</ span >
</ div >
< p > Returns the node name (same as tagName for elements).</ p >
< div class = "method-signature" >
< span class = "method-name" > element.nodeValue</ span > → < span class = "type" > Null</ span >
</ div >
< p > Returns null for elements (nodeValue is only meaningful for text nodes).</ p >
< h3 > Content Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > element.textContent</ span > → < span class = "type" > String</ span >
</ div >
< p > Gets the text content of the element and all descendants.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.textContent=</ span > (< span class = "param" > value</ span > )
</ div >
< p > Sets the text content, replacing all children with a single text node.</ p >
< pre >< code > elem.textContent = "New text"</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.innerHTML</ span > → < span class = "type" > String</ span >
</ div >
< p > Gets the HTML content inside the element.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.innerHTML=</ span > (< span class = "param" > html</ span > )
</ div >
< p > Sets the inner HTML, parsing and replacing all children.</ p >
< pre >< code > elem.innerHTML = "< p> New content< /p> "</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.outerHTML</ span > → < span class = "type" > String</ span >
</ div >
< p > Gets the HTML serialization of the element including itself.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.outerHTML=</ span > (< span class = "param" > html</ span > )
</ div >
< p > Replaces the element with the parsed HTML.</ p >
< h3 > Attribute Methods</ h3 >
< div class = "method-signature" >
< span class = "method-name" > element.getAttribute</ span > (< span class = "param" > name</ span > ) → < span class = "type" > String|Null</ span >
</ div >
< p > Gets the value of the specified attribute, or null if not present.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > name</ span > < span class = "param-type" > (String)</ span > - Attribute name</ li >
< li >< span class = "returns" > Returns:</ span > Attribute value or null</ li >
</ ul >
< pre >< code > var href = elem.getAttribute("href")
System.print(href)</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.setAttribute</ span > (< span class = "param" > name</ span > , < span class = "param" > value</ span > )
</ div >
< p > Sets the value of the specified attribute.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > name</ span > < span class = "param-type" > (String)</ span > - Attribute name</ li >
< li >< span class = "param-name" > value</ span > < span class = "param-type" > (String)</ span > - Attribute value</ li >
</ ul >
< pre >< code > elem.setAttribute("data-id", "123")</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.removeAttribute</ span > (< span class = "param" > name</ span > )
</ div >
< p > Removes the specified attribute.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > name</ span > < span class = "param-type" > (String)</ span > - Attribute name to remove</ li >
</ ul >
< pre >< code > elem.removeAttribute("disabled")</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.hasAttribute</ span > (< span class = "param" > name</ span > ) → < span class = "type" > Bool</ span >
</ div >
< p > Returns true if the element has the specified attribute.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > name</ span > < span class = "param-type" > (String)</ span > - Attribute name</ li >
< li >< span class = "returns" > Returns:</ span > Boolean indicating presence</ li >
</ ul >
< pre >< code > if (elem.hasAttribute("disabled")) {
System.print("Element is disabled")
}</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.attributes</ span > → < span class = "type" > Map</ span >
</ div >
< p > Returns a map of all attributes (name to value).</ p >
< pre >< code > var attrs = elem.attributes
for (name in attrs.keys) {
System.print("%(name)=%(attrs[name])")
}</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.dataset</ span > → < span class = "type" > Map</ span >
</ div >
< p > Returns a map of all data-* attributes with camelCase keys.</ p >
< pre >< code > // < div data-user-id="123" data-active="true">
var data = elem.dataset
System.print(data["userId"]) // 123
System.print(data["active"]) // true</ code ></ pre >
< h3 > Traversal Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > element.parentNode</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the parent node (element or document).</ p >
< div class = "method-signature" >
< span class = "method-name" > element.parentElement</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the parent element, or null if parent is not an element.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.children</ span > → < span class = "type" > NodeList</ span >
</ div >
< p > Returns all child elements (excludes text nodes).</ p >
< div class = "method-signature" >
< span class = "method-name" > element.childNodes</ span > → < span class = "type" > NodeList</ span >
</ div >
< p > Returns all child nodes including text nodes.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.firstChild</ span > → < span class = "type" > Element|TextNode|Null</ span >
</ div >
< p > Returns the first child node.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.lastChild</ span > → < span class = "type" > Element|TextNode|Null</ span >
</ div >
< p > Returns the last child node.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.firstElementChild</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the first child that is an element.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.lastElementChild</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the last child that is an element.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.nextSibling</ span > → < span class = "type" > Element|TextNode|Null</ span >
</ div >
< p > Returns the next sibling node.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.previousSibling</ span > → < span class = "type" > Element|TextNode|Null</ span >
</ div >
< p > Returns the previous sibling node.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.nextElementSibling</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the next sibling that is an element.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.previousElementSibling</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the previous sibling that is an element.</ p >
< h3 > Manipulation Methods</ h3 >
< div class = "method-signature" >
< span class = "method-name" > element.appendChild</ span > (< span class = "param" > child</ span > ) → < span class = "type" > Element|TextNode</ span >
</ div >
< p > Appends a child node to the end of the element's children.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > child</ span > < span class = "param-type" > (Element|TextNode)</ span > - Node to append</ li >
< li >< span class = "returns" > Returns:</ span > The appended node</ li >
</ ul >
< pre >< code > var p = doc.createElement("p")
p.textContent = "New paragraph"
container.appendChild(p)</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.insertBefore</ span > (< span class = "param" > newNode</ span > , < span class = "param" > refNode</ span > ) → < span class = "type" > Element|TextNode</ span >
</ div >
< p > Inserts a node before the reference node.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > newNode</ span > < span class = "param-type" > (Element|TextNode)</ span > - Node to insert</ li >
< li >< span class = "param-name" > refNode</ span > < span class = "param-type" > (Element|TextNode|Null)</ span > - Reference node (null appends)</ li >
< li >< span class = "returns" > Returns:</ span > The inserted node</ li >
</ ul >
< pre >< code > var newP = doc.createElement("p")
container.insertBefore(newP, existingP)</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.removeChild</ span > (< span class = "param" > child</ span > ) → < span class = "type" > Element|TextNode</ span >
</ div >
< p > Removes a child node from the element.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > child</ span > < span class = "param-type" > (Element|TextNode)</ span > - Node to remove</ li >
< li >< span class = "returns" > Returns:</ span > The removed node</ li >
</ ul >
< pre >< code > var removed = container.removeChild(child)
System.print(removed.textContent)</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.replaceChild</ span > (< span class = "param" > newChild</ span > , < span class = "param" > oldChild</ span > ) → < span class = "type" > Element|TextNode</ span >
</ div >
< p > Replaces a child node with a new node.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > newChild</ span > < span class = "param-type" > (Element|TextNode)</ span > - Replacement node</ li >
< li >< span class = "param-name" > oldChild</ span > < span class = "param-type" > (Element|TextNode)</ span > - Node to replace</ li >
< li >< span class = "returns" > Returns:</ span > The replaced (old) node</ li >
</ ul >
< pre >< code > var newP = doc.createElement("p")
container.replaceChild(newP, oldP)</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.cloneNode</ span > (< span class = "param" > deep</ span > ) → < span class = "type" > Element</ span >
</ div >
< p > Creates a copy of the element.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > deep</ span > < span class = "param-type" > (Bool)</ span > - If true, clones all descendants</ li >
< li >< span class = "returns" > Returns:</ span > Cloned element</ li >
</ ul >
< pre >< code > var shallow = elem.cloneNode(false) // Just the element
var deep = elem.cloneNode(true) // Element and all children</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.remove</ span > ()
</ div >
< p > Removes the element from its parent.</ p >
< pre >< code > elem.remove() // Element is now detached</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.normalize</ span > ()
</ div >
< p > Merges adjacent text nodes and removes empty text nodes.</ p >
< h3 > Query Methods</ h3 >
< div class = "method-signature" >
< span class = "method-name" > element.querySelector</ span > (< span class = "param" > selector</ span > ) → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the first descendant matching the CSS selector.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.querySelectorAll</ span > (< span class = "param" > selector</ span > ) → < span class = "type" > NodeList</ span >
</ div >
< p > Returns all descendants matching the CSS selector.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.getElementsByClassName</ span > (< span class = "param" > className</ span > ) → < span class = "type" > NodeList</ span >
</ div >
< p > Returns all descendants with the specified class.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.getElementsByTagName</ span > (< span class = "param" > tagName</ span > ) → < span class = "type" > NodeList</ span >
</ div >
< p > Returns all descendants with the specified tag.</ p >
< div class = "method-signature" >
< span class = "method-name" > element.matches</ span > (< span class = "param" > selector</ span > ) → < span class = "type" > Bool</ span >
</ div >
< p > Returns true if the element matches the CSS selector.</ p >
< pre >< code > if (elem.matches(".active")) {
System.print("Element is active")
}</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.closest</ span > (< span class = "param" > selector</ span > ) → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the closest ancestor (or self) matching the selector.</ p >
< pre >< code > var container = elem.closest(".container")
if (container) {
System.print("Found container: %(container.id)")
}</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.contains</ span > (< span class = "param" > node</ span > ) → < span class = "type" > Bool</ span >
</ div >
< p > Returns true if the node is a descendant of this element.</ p >
< pre >< code > if (container.contains(child)) {
System.print("Child is inside container")
}</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > element.hasChildNodes</ span > () → < span class = "type" > Bool</ span >
</ div >
< p > Returns true if the element has any child nodes.</ p >
< pre >< code > if (elem.hasChildNodes()) {
System.print("Element has children")
}</ code ></ pre >
< hr >
< h2 > TextNode Class</ h2 >
< div class = "class-header" >
< h3 > TextNode</ h3 >
< p > Represents a text node in the DOM tree.</ p >
</ div >
< h3 > Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > textNode.textContent</ span > → < span class = "type" > String</ span >
</ div >
< p > Gets the text content.</ p >
< div class = "method-signature" >
< span class = "method-name" > textNode.textContent=</ span > (< span class = "param" > value</ span > )
</ div >
< p > Sets the text content.</ p >
< div class = "method-signature" >
< span class = "method-name" > textNode.nodeType</ span > → < span class = "type" > Num</ span >
</ div >
< p > Returns 3 (TEXT_NODE).</ p >
< div class = "method-signature" >
< span class = "method-name" > textNode.nodeName</ span > → < span class = "type" > String</ span >
</ div >
< p > Returns "#text".</ p >
< div class = "method-signature" >
< span class = "method-name" > textNode.nodeValue</ span > → < span class = "type" > String</ span >
</ div >
< p > Gets the text content (same as textContent).</ p >
< div class = "method-signature" >
< span class = "method-name" > textNode.nodeValue=</ span > (< span class = "param" > value</ span > )
</ div >
< p > Sets the text content.</ p >
< h3 > Traversal Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > textNode.parentNode</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the parent node.</ p >
< div class = "method-signature" >
< span class = "method-name" > textNode.parentElement</ span > → < span class = "type" > Element|Null</ span >
</ div >
< p > Returns the parent element.</ p >
< div class = "method-signature" >
< span class = "method-name" > textNode.nextSibling</ span > → < span class = "type" > Element|TextNode|Null</ span >
</ div >
< p > Returns the next sibling node.</ p >
< div class = "method-signature" >
< span class = "method-name" > textNode.previousSibling</ span > → < span class = "type" > Element|TextNode|Null</ span >
</ div >
< p > Returns the previous sibling node.</ p >
< h3 > Methods</ h3 >
< div class = "method-signature" >
< span class = "method-name" > textNode.cloneNode</ span > (< span class = "param" > deep</ span > ) → < span class = "type" > TextNode</ span >
</ div >
< p > Creates a copy of the text node (deep parameter is ignored).</ p >
< div class = "method-signature" >
< span class = "method-name" > textNode.remove</ span > ()
</ div >
< p > Removes the text node from its parent.</ p >
< hr >
< h2 > NodeList Class</ h2 >
< div class = "class-header" >
< h3 > NodeList</ h3 >
< p > An iterable collection of DOM nodes returned by query methods.</ p >
</ div >
< h3 > Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > nodeList.count</ span > → < span class = "type" > Num</ span >
</ div >
< p > Returns the number of nodes in the list.</ p >
< h3 > Access Methods</ h3 >
< div class = "method-signature" >
< span class = "method-name" > nodeList[index]</ span > → < span class = "type" > Element|TextNode|Null</ span >
</ div >
< p > Returns the node at the specified index, or null if out of bounds.</ p >
< pre >< code > var first = list[0]
var last = list[list.count - 1]</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > nodeList.item</ span > (< span class = "param" > index</ span > ) → < span class = "type" > Element|TextNode|Null</ span >
</ div >
< p > Same as subscript access.</ p >
< div class = "method-signature" >
< span class = "method-name" > nodeList.toList</ span > → < span class = "type" > List</ span >
</ div >
< p > Converts the NodeList to a standard Wren List.</ p >
< pre >< code > var list = nodeList.toList
for (elem in list) {
System.print(elem.tagName)
}</ code ></ pre >
< h3 > Iteration</ h3 >
< p > NodeList supports iteration with for-in loops:</ p >
< pre >< code > for (elem in doc.querySelectorAll("p")) {
System.print(elem.textContent)
}</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > nodeList.forEach</ span > (< span class = "param" > fn</ span > )
</ div >
< p > Calls the function for each node in the list.</ p >
< pre >< code > nodeList.forEach {|elem|
System.print(elem.tagName)
}</ code ></ pre >
< hr >
< h2 > CSS Selectors</ h2 >
< p > The DOM implementation supports the following CSS selector syntax:</ p >
2026-01-25 02:47:47 +01:00
< table >
< tr >
2026-01-26 16:28:49 +01:00
< th > Selector</ th >
< th > Example</ th >
< th > Description</ th >
2026-01-25 02:47:47 +01:00
</ tr >
< tr >
2026-01-26 16:28:49 +01:00
< td > Tag</ td >
< td >< code > div</ code > , < code > p</ code ></ td >
< td > Matches elements by tag name</ td >
2026-01-25 02:47:47 +01:00
</ tr >
< tr >
2026-01-26 16:28:49 +01:00
< td > Universal</ td >
< td >< code > *</ code ></ td >
< td > Matches all elements</ td >
2026-01-25 02:47:47 +01:00
</ tr >
< tr >
2026-01-26 16:28:49 +01:00
< td > ID</ td >
< td >< code > #myId</ code ></ td >
< td > Matches element with id="myId"</ td >
2026-01-25 02:47:47 +01:00
</ tr >
< tr >
2026-01-26 16:28:49 +01:00
< td > Class</ td >
< td >< code > .myClass</ code ></ td >
< td > Matches elements with class="myClass"</ td >
2026-01-25 02:47:47 +01:00
</ tr >
< tr >
2026-01-26 16:28:49 +01:00
< td > Attribute</ td >
< td >< code > [href]</ code ></ td >
< td > Matches elements with href attribute</ td >
</ tr >
< tr >
< td > Attribute equals</ td >
< td >< code > [type="text"]</ code ></ td >
< td > Matches elements with type="text"</ td >
</ tr >
< tr >
< td > Attribute contains word</ td >
< td >< code > [class~="item"]</ code ></ td >
< td > Matches if class contains "item" as a word</ td >
</ tr >
< tr >
< td > Attribute starts with</ td >
< td >< code > [href^="https"]</ code ></ td >
< td > Matches if href starts with "https"</ td >
</ tr >
< tr >
< td > Attribute ends with</ td >
< td >< code > [src$=".png"]</ code ></ td >
< td > Matches if src ends with ".png"</ td >
</ tr >
< tr >
< td > Attribute contains</ td >
< td >< code > [title*="hello"]</ code ></ td >
< td > Matches if title contains "hello"</ td >
</ tr >
< tr >
< td > Descendant</ td >
< td >< code > div p</ code ></ td >
< td > Matches p anywhere inside div</ td >
</ tr >
< tr >
< td > Child</ td >
< td >< code > div > p</ code ></ td >
< td > Matches p that is direct child of div</ td >
</ tr >
< tr >
< td > Adjacent sibling</ td >
< td >< code > h1 + p</ code ></ td >
< td > Matches p immediately after h1</ td >
</ tr >
< tr >
< td > General sibling</ td >
< td >< code > h1 ~ p</ code ></ td >
< td > Matches any p after h1</ td >
</ tr >
< tr >
< td > :first-child</ td >
< td >< code > p:first-child</ code ></ td >
< td > Matches first child element</ td >
</ tr >
< tr >
< td > :last-child</ td >
< td >< code > p:last-child</ code ></ td >
< td > Matches last child element</ td >
</ tr >
< tr >
< td > :nth-child(n)</ td >
< td >< code > li:nth-child(2)</ code ></ td >
< td > Matches 2nd child</ td >
</ tr >
< tr >
< td > :nth-child(odd/even)</ td >
< td >< code > tr:nth-child(odd)</ code ></ td >
< td > Matches odd rows</ td >
</ tr >
< tr >
< td > :first-of-type</ td >
< td >< code > p:first-of-type</ code ></ td >
< td > First p among siblings</ td >
</ tr >
< tr >
< td > :last-of-type</ td >
< td >< code > p:last-of-type</ code ></ td >
< td > Last p among siblings</ td >
</ tr >
< tr >
< td > :only-child</ td >
< td >< code > p:only-child</ code ></ td >
< td > Matches if only child</ td >
</ tr >
< tr >
< td > :empty</ td >
< td >< code > div:empty</ code ></ td >
< td > Matches elements with no children</ td >
2026-01-25 02:47:47 +01:00
</ tr >
</ table >
2026-01-26 16:28:49 +01:00
< h3 > Compound Selectors</ h3 >
< pre >< code > doc.querySelector("div.container#main") // Tag + class + ID
doc.querySelector("input[type='text'].large") // Tag + attribute + class
doc.querySelector("ul > li:first-child") // Combinator + pseudo-class</ code ></ pre >
< hr >
2026-01-25 02:47:47 +01:00
< h2 > Examples</ h2 >
2026-01-26 16:28:49 +01:00
< h3 > Web Scraping</ h3 >
< pre >< code > import "html" for Document
2026-01-25 02:47:47 +01:00
2026-01-26 16:28:49 +01:00
var html = """
< div class="products">
< div class="product">
< h2> Widget< /h2>
< span class="price"> $9.99< /span>
< /div>
< div class="product">
< h2> Gadget< /h2>
< span class="price"> $19.99< /span>
< /div>
< /div>
"""
2026-01-25 02:47:47 +01:00
2026-01-26 16:28:49 +01:00
var doc = Document.parse(html)
for (product in doc.querySelectorAll(".product")) {
var name = product.querySelector("h2").textContent
var price = product.querySelector(".price").textContent
System.print("%(name): %(price)")
2026-01-25 02:47:47 +01:00
}</ code ></ pre >
2026-01-26 16:28:49 +01:00
< h3 > HTML Generation</ h3 >
< pre >< code > import "html" for Document
var doc = Document.parse("< div id='root'>< /div> ")
var root = doc.getElementById("root")
var items = ["Apple", "Banana", "Cherry"]
var ul = doc.createElement("ul")
for (item in items) {
var li = doc.createElement("li")
li.textContent = item
ul.appendChild(li)
}
root.appendChild(ul)
System.print(doc.outerHTML)</ code ></ pre >
< h3 > DOM Transformation</ h3 >
< pre >< code > import "html" for Document
var doc = Document.parse("< p> Hello < b> World< /b>< /p> ")
// Replace all < b> with < strong>
for (b in doc.querySelectorAll("b").toList) {
var strong = doc.createElement("strong")
strong.innerHTML = b.innerHTML
b.parentNode.replaceChild(strong, b)
}
System.print(doc.outerHTML)</ code ></ pre >
< div class = "admonition note" >
< div class = "admonition-title" > Note</ div >
< p > The DOM implementation automatically decodes HTML entities when parsing and encodes them when serializing.</ p >
2026-01-25 02:47:47 +01:00
</ div >
2026-01-26 05:12:14 +01:00
{% endblock %}