std1.0.0-beta-7 SafeC docs

Module wasm::dom

#include <std/wasm/dom.h> source

wasm32 DOM and browser-API interop.

A wasm32-unknown-unknown module has no access to the page itself, so every browser operation here is an 'extern' js_* function that becomes a WebAssembly import (an undefined extern in a module linked with --allow-undefined is imported from "env"), implemented by the JS glue that ships beside this header: std/wasm/safec_dom.js. Load a module through it —

import { loadSafeC } from "./safec_dom.js";
const app = await loadSafeC(fetch("/app.wasm"));   // instantiates, wires every import
app.exports.start();

— and every dom_* function below works; see safec_dom.js's header for running under Node with a fake document (that is how the tests run it).

ABI. Strings go to JS as (pointer, length) into the module's linear memory and are read synchronously. Strings come back through a caller buffer: the import copies at most 'cap' bytes and returns the full length (-1 for "absent"), and the wrappers here retry with a buffer of that size, so the dom_* API hands out ordinary owned Strings. Elements are integer handles into a JS-side table (-1: none); DOM_DOCUMENT and DOM_WINDOW name the document and window. A handle stays valid until dom_release() — release elements you looked up or created in a loop, or the table grows for the page's lifetime.

Callbacks (events, timers, animation frames, fetch completions) are slots in one table of DOM_MAX_CALLBACKS entries; JS invokes them by id through the exported std_dom_dispatch_* functions. A handler receives its userdata (the generic ?&T it was registered with) and, for events, a DomEvent whose accessors read the event being dispatched — valid only during the handler. Every wrapper pairs fn void(?&T, ...) with ?&T, so the type-erased storage is always called correctly.

Memory: the strings these wrappers return are heap Strings; free them. (std/wasm/wasm_rt.sc's allocator is a bump allocator whose free() is a no-op — a long-running page should keep per-event allocation small.)

Structs

DomEventThe event being dispatched. Accessors call into JS for the live event: only valid inside the handler that received it.
DomFetchResponseA completed fetch, as its handler sees it. 'status' is 0 (and ok 0) on a network error; text() etc. are only valid inside the handler.

Type aliases

DomEventHandlerStored type-erased (the table holds handlers with unrelated context types); the generic wrappers below are the only writers and always pair a handler with userdata of the matching type. A callback id is slot + DOM_MAX_CALLBACKS * generation, so an id whose slot was freed and reused (a timer that already fired, say) is recognized as stale.

Functions

js_get_elementOriginal surface (kept for existing glue).
js_queryElements and tree.
js_get_textContent, attributes, classes, style, properties.
js_add_listenerEvents.
js_set_timerTimers and time.
js_fetchfetch().
js_storage_getlocalStorage / sessionStorage.
js_locationlocation / history / console.
wasm_strlenLength of a NUL-terminated string. No libc 'strlen' on a freestanding wasm32 build — this is the whole reason dom.sc carries its own copy.
wasm_itoaMinimal signed-decimal integer formatter — no snprintf on wasm32. 'buf' should hold 24 bytes (any 64-bit value's sign + digits + NUL); a shorter buf gets a truncated number. Always NUL-terminates.
dom_get_elementFirst element matching the CSS selector (document.querySelector); -1 if none. dom_query is the same; dom_query_in searches under 'parent'.
dom_query
dom_query_in
dom_get_by_iddocument.getElementById.
dom_query_allEvery match (querySelectorAll), appended to 'out' as handles; returns the count.
dom_query_all_in
dom_bodydocument.body / document.head.
dom_head
dom_create_elementdocument.createElement / createTextNode.
dom_create_text
dom_appendparent.appendChild(child); parent.insertBefore(child, ref) (ref -1: append); node.remove().
dom_insert_before
dom_remove
dom_clearRemoves every child (textContent = "").
dom_releaseDrops the handle (the element itself is untouched).
dom_parentparentElement / firstElementChild / nextElementSibling / previousElementSibling / lastElementChild, or -1.
dom_first_child
dom_next_sibling
dom_prev_sibling
dom_last_child
dom_childrenThe element children (handles appended to 'out'); returns the count.
dom_set_texttextContent
dom_get_text
dom_set_htmlinnerHTML (trusted markup only)
dom_get_html
dom_set_attr
dom_get_attrThe attribute's value; empty if absent (dom_has_attr tells the two apart).
dom_has_attr
dom_remove_attr
dom_class_addclassList.add / remove / toggle (returns the new state) / contains.
dom_class_remove
dom_class_toggle
dom_class_contains
dom_set_stylestyle.setProperty(prop, value) ("" removes it); CSS property names ("background-color"), not camelCase.
dom_set_visibleShows/hides via style.display ("" / "none").
dom_get_valueForm controls: .value, .checked, .disabled.
dom_set_value
dom_get_checked
dom_set_checked
dom_set_disabled
dom_get_propAny property: String(el[name]) (empty for undefined/null), el[name] = value; the numeric forms convert with Number() / assign a number (0/1 works for boolean properties). DOM_DOCUMENT and DOM_WINDOW work too: dom_set_prop(DOM_DOCUMENT, "title", "...").
dom_get_prop_bufThe same into a caller buffer: copies up to buf.len - 1 bytes, NUL- terminates, returns the full length (-1 if undefined/null).
dom_set_prop
dom_get_prop_num
dom_set_prop_num
dom_callelmethod with no arguments: "focus", "blur", "click", "select", "scrollIntoView", "reset", "submit", ...
dom_focus
dom_console_log
dom_consoleconsole.debug/info/log/warn/error by DOM_LOG_* level.
dom_unregister_callbackFrees a callback slot (dom_off / dom_clear_timer / ... do this).
dom_register_callback
dom_on_click
dom_add_listener
dom_on
dom_on_selector
dom_offremoveEventListener + frees the callback slot.
dom_set_timeout
dom_set_interval
dom_clear_timer
dom_request_animation_frame
dom_cancel_animation_frame
dom_nowperformance.now(), in milliseconds.
dom_fetch
dom_fetch_get
dom_storage_getlocalStorage (DOM_STORAGE_LOCAL) / sessionStorage (DOM_STORAGE_SESSION). get: 1 and the value appended to 'out', or 0 if the key is absent.
dom_storage_set1 on success, 0 if the browser refused (quota, storage disabled).
dom_storage_remove
dom_storage_clear
dom_storage_length
dom_storage_keyThe i-th key (empty past the end).
dom_locationA location field (DOM_LOC_*): href, pathname, search ("?a=1"), hash ("#x"), host, origin.
dom_location_path
dom_history_pushhistory.pushState(null, "", url) / replaceState / back() / forward(). Listen for DOM_WINDOW "popstate" to react to back/forward.
dom_history_replace
dom_history_back
dom_history_forward
dom_navigatelocation.assign(url): a real navigation.
dom_dispatch_eventExported for the JS glue, never called by SafeC code. Names are fixed (std_dom_dispatch_event is the original export existing glue uses).
dom_dispatch_frame
dom_dispatch_fetch

Macros

DOM_NONE
DOM_DOCUMENThandle of 'document'
DOM_WINDOWhandle of 'window' (popstate, resize, keydown, ...)
DOM_LOG_DEBUG
DOM_LOG_INFO
DOM_LOG_LOG
DOM_LOG_WARN
DOM_LOG_ERROR
DOM_STORAGE_LOCAL
DOM_STORAGE_SESSION
DOM_LOC_HREFdom_location() fields.
DOM_LOC_PATHNAME
DOM_LOC_SEARCH
DOM_LOC_HASH
DOM_LOC_HOST
DOM_LOC_ORIGIN
DOM_LISTEN_CAPTUREdom_add_listener flags.
DOM_LISTEN_ONCE
DOM_LISTEN_PASSIVE
DOM_EV_TARGETDomEvent fields (js_event_num / js_event_str).
DOM_EV_CLIENT_X
DOM_EV_CLIENT_Y
DOM_EV_BUTTON
DOM_EV_BUTTONS
DOM_EV_MODIFIERSbit 0 alt, 1 ctrl, 2 shift, 3 meta
DOM_EV_DELTA_X
DOM_EV_DELTA_Y
DOM_EV_REPEAT
DOM_EV_TIMESTAMP
DOM_EV_OFFSET_X
DOM_EV_OFFSET_Y
DOM_EV_TARGET_CHECKED
DOM_EV_CURRENT_TARGET
DOM_EV_STR_TYPE
DOM_EV_STR_KEY
DOM_EV_STR_CODE
DOM_EV_STR_VALUEevent.target.value
DOM_EV_STR_DATAInputEvent.data / MessageEvent.data
DOM_EV_STR_STATEpopstate: JSON.stringify(event.state)
DOM_MOD_ALT
DOM_MOD_CTRL
DOM_MOD_SHIFT
DOM_MOD_META
DOM_MAX_CALLBACKS