JavaScript DSL

JWeb provides type-safe JavaScript generation. Write JS in Java with full IDE support, compile-time checks, and no context switching.

Import Statements

// Core JS DSL
import static com.osmig.Jweb.framework.js.JS.*;

// High-level UI actions
import static com.osmig.Jweb.framework.js.Actions.*;

// Event handling patterns
import static com.osmig.Jweb.framework.js.Events.*;

// Async/await and fetch
import static com.osmig.Jweb.framework.js.Async.*;

Two Approaches

Use Actions DSL for common UI patterns, or JS DSL for custom logic.

Actions DSL (High-Level)

Declarative builders for common interactions.

// Form submission with loading state
onSubmit("login-form")
    .loading("Signing in...")
    .post("/api/login").withFormData()
    .ok(navigateTo("/dashboard"))
    .fail(showMessage("error").text("Invalid credentials"))

// Button click with confirmation
onClick("delete-btn")
    .confirm("Delete this item?")
    .post("/api/delete/" + id)
    .ok(reload())

// Input change handler
onChange("search-input")
    .then(fetch("/api/search?q=" + variable("this").dot("value"))
        .get()
        .ok(setHtml("results")))

JS DSL (Low-Level)

Full control over generated JavaScript.

// Variables and values
script()
    .var_("count", 0)
    .let_("name", str("John"))
    .const_("PI", 3.14159)

// Variable references
variable("count")      // count
str("hello")          // 'hello'
array(1, 2, 3)        // [1,2,3]
obj("a", 1, "b", 2)   // {a:1,b:2}

// Functions
func("greet", "name")
    .var_("msg", str("Hello, ").plus(variable("name")))
    .ret(variable("msg"))

// Callbacks (anonymous functions)
callback("item")
    .ret(variable("item").times(2))

Core JS DSL

Fundamental JavaScript generation with type-safe methods.

DOM Access

// Get element by ID
getElem("myId")           // document.getElementById('myId')
$("myId")                 // Shorthand

// Query selectors
query(".my-class")        // document.querySelector('.my-class')
queryAll(".items")        // document.querySelectorAll('.items')

// Element manipulation
getElem("btn")
    .addClass("active")
    .removeClass("disabled")
    .setAttribute("data-id", "123")
    .setStyle("color", "red")

// Content
getElem("output").setText(variable("result"))
getElem("container").setHtml(variable("template"))

// Visibility
getElem("modal").show()
getElem("tooltip").hide()

Control Flow

// If/else
func("checkAge", "age")
    .if_(variable("age").gte(18))
        .then_(ret(str("adult")))
    .else_(ret(str("minor")))

// For loop
func("sum", "items")
    .let_("total", 0)
    .forOf("item", variable("items"))
        .body(variable("total").addAssign(variable("item")))
    .endFor()
    .ret(variable("total"))

// While loop
func("countdown", "n")
    .while_(variable("n").gt(0))
        .body("n--", call("console.log", variable("n")))
    .endWhile()

// Switch
func("handleAction", "action")
    .switch_(variable("action"))
        .case_("add").then_(call("add"), "break")
        .case_("remove").then_(call("remove"), "break")
        .default_().then_(call("noop"))
    .endSwitch()

Array Methods

30+ fluent array operations.

// Filter and map
variable("items")
    .filter(callback("x").ret(variable("x").gt(5)))
    .map(callback("x").ret(variable("x").times(2)))
    .join(", ")

// Find
variable("users")
    .find(callback("u").ret(variable("u").dot("id").eq(userId)))

// Reduce
variable("numbers").reduce(
    callback("acc", "n").ret(variable("acc").plus(variable("n"))),
    0
)

// Other methods
.forEach(callback)    // Iterate
.some(predicate)      // Any match?
.every(predicate)     // All match?
.includes(value)      // Contains?
.indexOf(value)       // Find index
.slice(start, end)    // Get slice
.concat(other)        // Combine
.reverse()            // Reverse
.sort(comparator)     // Sort
.flat()               // Flatten
.first()              // First element
.last()               // Last element

String Methods

20+ string operations.

variable("text")
    .substring(0, 10)
    .toLowerCase()
    .trim()

// Search
.indexOf("search")
.includes("sub")
.startsWith("prefix")
.endsWith("suffix")

// Transform
.replace("old", "new")
.replaceAll("pattern", "replacement")
.split(",")
.repeat(3)
.padStart(5, "0")
.padEnd(10, " ")

Object Methods

// Get properties
variable("obj").keys()      // Object.keys(obj)
variable("obj").values()    // Object.values(obj)
variable("obj").entries()   // Object.entries(obj)

// Check property
variable("obj").hasOwnProperty("key")

// Static methods
objectAssign(variable("target"), variable("source"))
objectFreeze(variable("config"))
objectFromEntries(variable("entries"))

Operators

// Comparison
variable("a").eq(variable("b"))    // a === b
variable("a").neq(variable("b"))   // a !== b
variable("a").gt(5)                // a > 5
variable("a").gte(5)               // a >= 5
variable("a").lt(10)               // a < 10
variable("a").lte(10)              // a <= 10

// Logical
variable("a").and(variable("b"))   // a && b
variable("a").or(variable("b"))    // a || b
not(variable("flag"))              // !flag

// Arithmetic
variable("a").plus(variable("b"))  // a + b
variable("a").minus(5)             // a - 5
variable("a").times(2)             // a * 2
variable("a").divide(10)           // a / 10
variable("a").mod(2)               // a % 2

// Optional chaining
optionalChain(variable("user"), "address", "city")  // user?.address?.city

// Nullish coalescing
nullishCoalesce(variable("name"), str("Anonymous"))  // name ?? 'Anonymous'

Actions DSL

High-level builders for common UI interactions.

Form Submission

// Basic form submit
onSubmit("contact-form")
    .post("/api/contact").withFormData()
    .ok(showMessage("status").text("Sent!"))
    .fail(showMessage("status").text("Error"))

// With loading state
onSubmit("login-form")
    .loading("Signing in...")          // Disable form, show text
    .post("/api/login").withFormData()
    .ok(navigateTo("/dashboard"))
    .fail(showMessage("error").text("Invalid credentials"))

// With validation
onSubmit("register-form")
    .validate(v -> v
        .field("email").required().email()
        .field("password").required().minLength(8)
    )
    .loading("Creating account...")
    .post("/api/register").withFormData()
    .ok(all(
        resetForm("register-form"),
        showMessage("success").text("Account created!")
    ))

Click Handlers

// Simple click
onClick("save-btn")
    .post("/api/save")
    .ok(showMessage("status").text("Saved!"))

// With confirmation
onClick("delete-btn")
    .confirm("Are you sure you want to delete this?")
    .post("/api/delete/" + id)
    .ok(reload())

// Chain actions
onClick("logout-btn")
    .then(all(
        clearStorage(),
        navigateTo("/login")
    ))

UI Manipulation

// Show/hide elements
show("panel")
hide("loader")
toggle("dropdown")

// Set content
setText("label", "Updated text")
setHtml("container", variable("html"))

// CSS classes
addClass("card", "highlighted")
removeClass("card", "disabled")
toggleClass("menu", "open")

// Multiple actions
all(
    hide("loading"),
    show("content"),
    addClass("card", "loaded")
)
// Navigate to URL
navigateTo("/dashboard")

// Reload page
reload()

// Open in new tab
openInNewTab("https://example.com")

// Scroll to element
scrollTo("section-id")

// Smooth scroll
scrollTo("section-id", "smooth")

Fetch Requests

// GET request
fetch("/api/users")
    .get()
    .ok(setHtml("user-list"))
    .fail(showMessage("error").text("Failed to load"))

// POST with JSON
fetch("/api/users")
    .post()
    .json("name", "John", "email", "john@example.com")
    .ok(callback("user").call("addUserToList", variable("user")))

// POST with form data
fetch("/api/upload")
    .post()
    .withFormData("upload-form")
    .ok(showMessage("status").text("Uploaded!"))

// With headers
fetch("/api/protected")
    .get()
    .header("Authorization", "Bearer " + token)
    .ok(setHtml("data"))

Modals & Dialogs

// Show modal
showModal("confirm-dialog")
hideModal("confirm-dialog")

// Confirmation dialog
confirmDialog("modal")
    .message("Delete this item?")
    .danger()
    .onConfirm(fetch("/api/delete/" + id).post().ok(reload()))
    .onCancel(log("Cancelled"))

// Alert modal
alertModal("modal")
    .success("Operation completed!")

alertModal("modal")
    .error("Something went wrong")

Messages & Toasts

// Show message in element
showMessage("status-div")
    .text("Success!")

// From response
showMessage("result")
    .fromResponse("message")

// Clear after delay
showMessage("notification")
    .text("Saved!")
    .clearAfter(3000)  // 3 seconds

Conditional Actions

// Based on condition
when("isLoggedIn")
    .then(navigateTo("/dashboard"))
    .otherwise(navigateTo("/login"))

// Based on response
whenResponse("success")
    .then(showMessage("status").text("Done!"))
    .otherwise(showMessage("error").text("Failed"))

// Based on variable
whenVar("status")
    .equals("approved").thenUrl("/success")
    .equals("pending").thenUrl("/pending")
    .otherwise(showMessage("error").text("Unknown status"))

Event Handling

Advanced event patterns for interactive UIs.

Event Delegation

Efficient handling for dynamic lists.

// Delegate clicks within a container
delegate("todo-list", "click", "li")
    .handler(callback("e", "target")
        .call("toggleTodo", variable("target").getData("id"))
    )

// Works for dynamically added items
// Single listener on parent, not one per child

Debouncing

Delay execution until user stops typing/scrolling.

// Search input - wait 300ms after typing stops
onChange("search-input")
    .then(debounce("searchTimer", 300).wrap(
        fetch("/api/search?q=" + variable("this").dot("value"))
            .get()
            .ok(setHtml("results"))
    ))

// Resize handler - wait for resize to stop
onResize(debounce("resizeTimer", 200).wrap(
    callback().call("recalculateLayout")
))

Throttling

Limit execution frequency.

// Scroll handler - run at most every 100ms
onScroll(throttle("scrollTimer", 100).wrap(
    callback().call("updateScrollPosition")
))

// Mouse move - limit to 60fps
onMouseMove("canvas", throttle("moveTimer", 16).wrap(
    callback("e").call("draw", variable("e").dot("clientX"), variable("e").dot("clientY"))
))

Keyboard Events

// Key combinations
onKeyCombo("ctrl+s", callback("e")
    .call("preventDefault", variable("e"))
    .call("save")
)

onKeyCombo("ctrl+shift+p", callback("e")
    .call("openCommandPalette")
)

// Single keys
onEscape(callback().call("closeModal"))
onEnter(callback().call("submit"))
onKey("Delete", callback().call("deleteSelected"))

// Arrow navigation
onArrowKeys(callback("direction")
    .call("navigate", variable("direction"))
)

Touch & Swipe

// Swipe gestures
swipe(variable("carousel"))
    .threshold(100)  // Minimum distance in pixels
    .onLeft(callback().call("nextSlide"))
    .onRight(callback().call("prevSlide"))
    .onUp(callback().call("openFullscreen"))
    .onDown(callback().call("closeFullscreen"))
    .build()

// Touch events
onTouchStart("element", callback("e")
    .let_("touch", variable("e").dot("touches").at(0))
    .call("startDrag", variable("touch"))
)

Server-Sent Events (SSE)

Real-time server push.

// Connect to SSE endpoint
sse("/api/notifications")
    .onMessage(callback("e")
        .let_("data", jsonParse(variable("e").dot("data")))
        .call("showNotification", variable("data"))
    )
    .onError(callback()
        .log("SSE connection error")
    )
    .build()

// With auto-reconnect
sse("/api/events")
    .reconnectDelay(3000)
    .onOpen(callback().log("Connected"))
    .onMessage(handler)
    .build()

Custom Events

// Create and dispatch custom event
dispatchCustomEvent(
    variable("element"),
    "item-selected",
    obj("id", itemId, "name", itemName)
)

// Listen for custom event
on("item-selected", callback("e")
    .call("handleSelection", variable("e").dot("detail"))
)

Event Utilities

// Prevent default behavior
preventDefault(variable("event"))

// Stop propagation
stopPropagation(variable("event"))

// Once - remove after first call
once("button", "click", callback()
    .call("initializeOnce")
)

// Remove listener
removeListener(variable("element"), "click", variable("handler"))

Async/Await

Build asynchronous JavaScript with type-safe async functions.

import static com.osmig.Jweb.framework.js.Actions.*;

// Simple await
await_(fetch("/api/data").ok(processData()))

// Async function
asyncFunc("loadDashboard")
    .does(
        assignVar("isLoading", "true"),
        await_(fetch("/api/user").ok(assignVar("user", "_data"))),
        await_(fetch("/api/stats").ok(assignVar("stats", "_data"))),
        assignVar("isLoading", "false"),
        call("renderDashboard")
    )

Try-Catch-Finally

Handle errors in async operations.

asyncTry(
    await_(fetch("/api/data").ok(processData()))
)
.catch_("error",
    logError("error"),
    showMessage("status").error("Failed to load")
)
.finally_(
    hide("loading"),
    assignVar("isLoading", "false")
)

Promise.all

Execute multiple async operations in parallel.

// Parallel requests
promiseAll(
    fetch("/api/users").ok(assignVar("users", "_data")),
    fetch("/api/posts").ok(assignVar("posts", "_data")),
    fetch("/api/comments").ok(assignVar("comments", "_data"))
)

// With error handling
asyncFunc("loadAll")
    .does(
        show("loading"),
        asyncTry(
            promiseAll(
                fetch("/api/a").ok(assignVar("a", "_data")),
                fetch("/api/b").ok(assignVar("b", "_data"))
            ),
            call("renderAll")
        )
        .catch_("e", showMessage("error").error("Load failed"))
        .finally_(hide("loading"))
    )

Sleep/Delay

Add delays for debouncing or animations.

// Simple delay
sleep(1000)  // Wait 1 second

// Delay in sequence
asyncFunc("showWithDelay")
    .does(
        addClass("element", "fade-in"),
        sleep(300),
        setText("status", "Ready!")
    )

// Debounced search
asyncFunc("search")
    .params("query")
    .does(
        assignVar("searchQuery", "query"),
        sleep(300),
        raw("if(searchQuery !== query) return"),
        await_(fetch("/api/search?q=").appendVar("query")
            .ok(call("showResults", "_data")))
    )
Use Promise.all for parallel requests - it's faster than sequential awaits.

Browser APIs

Type-safe access to browser APIs.

Storage

import static com.osmig.Jweb.framework.js.JSStorage.*;

// localStorage
local().set("token", "abc123")
local().get("token")
local().remove("token")
local().clear()

// JSON storage
local().setJson("user", obj("name", "John", "id", 123))
local().getJson("user")
local().getJsonOr("user", obj())  // With fallback

// sessionStorage
session().set("temp", "value")
session().get("temp")

// Cross-tab communication
onStorageChange(callback("e")
    .if_(variable("e").dot("key").eq("theme"))
    .then(call("updateTheme", variable("e").dot("newValue")))
)

WebSocket

import static com.osmig.Jweb.framework.js.JSWebSocket.*;

// Create connection
webSocket("/ws/chat")
    .onOpen(callback().log("Connected"))
    .onMessage(callback("e")
        .call("handleMessage", variable("e").dot("data"))
    )
    .onClose(callback().log("Disconnected"))
    .onError(callback("e").log(variable("e")))
    .autoReconnect(3000)  // Auto-reconnect every 3s
    .build("ws")

// Send messages
send(variable("ws"), variable("message"))
sendJson(variable("ws"), obj("type", "chat", "text", variable("msg")))

// Close
close(variable("ws"))

Clipboard

import static com.osmig.Jweb.framework.js.JSClipboard.*;

// Write to clipboard
clipboardWrite(str("Copied text"))

// Copy from element
clipboardWriteFromElement(variable("inputElem"))

// Read (returns promise)
clipboardRead().then(callback("text").log(variable("text")))

Notifications

import static com.osmig.Jweb.framework.js.JSNotification.*;

// Check permission
notificationPermission()

// Request permission
requestNotificationPermission()

// Show notification
showNotification("New Message", obj(
    "body", "You have a new message",
    "icon", "/icon.png"
))

Geolocation

import static com.osmig.Jweb.framework.js.JSGeolocation.*;

// Get current position
getCurrentPosition()
    .onSuccess(callback("pos")
        .let_("lat", variable("pos").dot("coords").dot("latitude"))
        .let_("lng", variable("pos").dot("coords").dot("longitude"))
        .call("showOnMap", variable("lat"), variable("lng"))
    )
    .onError(callback("err").log(variable("err")))
    .build()

// Watch position (continuous updates)
watchPosition(callback("pos")
    .call("updatePosition", variable("pos").dot("coords"))
)

Web Share

import static com.osmig.Jweb.framework.js.JSShare.*;

// Share content
share(obj(
    "title", "Check this out",
    "text", "Interesting article",
    "url", window.location.href
))

// Check if sharing is supported
if_(canShare())
    .then(showShareButton())

Fullscreen

import static com.osmig.Jweb.framework.js.JSFullscreen.*;

// Enter fullscreen
requestFullscreen(variable("videoElem"))

// Exit fullscreen
exitFullscreen()

// Check state
isFullscreen()

Page Visibility

import static com.osmig.Jweb.framework.js.JSVisibility.*;

// Check if visible
isPageVisible()

// Handle visibility change
onVisibilityChange(callback()
    .if_(isPageVisible())
        .then(call("resumeVideo"))
    .else_(call("pauseVideo"))
)

Observers

import static com.osmig.Jweb.framework.js.JSObservers.*;

// IntersectionObserver (lazy loading, infinite scroll)
intersectionObserver(callback("entries")
    .forEach(callback("entry")
        .if_(variable("entry").dot("isIntersecting"))
        .then(call("lazyLoad", variable("entry").dot("target")))
    )
).observe(queryAll("img[data-src]"))

// ResizeObserver
resizeObserver(callback("entries")
    .forEach(callback("entry")
        .call("handleResize", variable("entry").dot("contentRect"))
    )
).observe(variable("container"))

// MutationObserver
mutationObserver(callback("mutations")
    .call("handleDOMChanges", variable("mutations"))
).observe(variable("element"), obj(
    "childList", true,
    "subtree", true
))

Advanced JavaScript

Powerful APIs for complex applications.

Promise Utilities

import static com.osmig.Jweb.framework.js.JSPromise.*;

// Promise combinators
promiseAll(
    fetch("/api/users").get().toVal(),
    fetch("/api/posts").get().toVal()
).then(callback("results").call("renderAll", variable("results")))

promiseRace(promise1, promise2)  // First to finish
promiseAny(promise1, promise2)   // First successful
promiseAllSettled(promises)      // All, regardless of success

// Retry with exponential backoff
retry(variable("apiCall"), 3)    // Max 3 attempts
    .delay(1000)                 // 1s initial delay
    .exponentialBackoff()        // Double delay each retry
    .onRetry(callback("attempt").log("Retry:", variable("attempt")))
    .shouldRetry(callback("err").ret(variable("err").dot("status").eq(503)))
    .build()

// Timeout
timeout(fetch("/api/slow").get().toVal(), 3000)
    .errorMessage("Request timed out")
    .build()

// Cancellable promise
cancellable(fetch("/api/data").get().toVal())
    .controller("abortCtrl")
    .timeout(5000)
    .build("result")

Web Workers

import static com.osmig.Jweb.framework.js.JSWorker.*;

// Create dedicated worker
dedicatedWorker("/worker.js")
    .onMessage(callback("e").call("handleResult", variable("e").dot("data")))
    .onError(callback("err").log(variable("err")))
    .build("worker")

// Send data to worker
workerPostMessage(variable("worker"), obj("task", "compute", "data", bigData))

// Terminate worker
workerTerminate(variable("worker"))

// SharedWorker (multiple tabs)
sharedWorker("/shared-worker.js").build("sw")

Service Workers

import static com.osmig.Jweb.framework.js.JSServiceWorker.*;

// Register service worker
registerServiceWorker("/sw.js")
    .onSuccess(callback("reg").log("SW registered"))
    .onError(callback("err").log(variable("err")))

// Check for updates
checkForUpdates(variable("registration"))

// Unregister
unregisterServiceWorker()

Web Crypto

import static com.osmig.Jweb.framework.js.JSCrypto.*;

// Random values
cryptoRandomUUID()     // UUID v4
cryptoRandomBytes(16)  // Random bytes

// Hashing
sha256(variable("data"))  // Returns promise
sha512(variable("data"))

// Encryption (AES)
aesEncrypt(variable("key"), variable("data"), variable("iv"))
aesDecrypt(variable("key"), variable("encrypted"), variable("iv"))

// Generate key
generateAESKey().then(callback("key").call("storeKey", variable("key")))

Canvas 2D

import static com.osmig.Jweb.framework.js.JSCanvas.*;

// Get context
getContext2D(variable("canvas"))

// Drawing
fillRect(variable("ctx"), 0, 0, 100, 100)
strokeRect(variable("ctx"), 10, 10, 80, 80)
clearRect(variable("ctx"), 0, 0, width, height)

// Text
fillText(variable("ctx"), str("Hello"), 50, 50)
strokeText(variable("ctx"), str("World"), 50, 80)

// Path
beginPath(variable("ctx"))
moveTo(variable("ctx"), 0, 0)
lineTo(variable("ctx"), 100, 100)
arc(variable("ctx"), 50, 50, 30, 0, Math.PI * 2)
stroke(variable("ctx"))
fill(variable("ctx"))

// Image
drawImage(variable("ctx"), variable("img"), 0, 0)

Performance API

import static com.osmig.Jweb.framework.js.JSPerformance.*;

// High-resolution timing
performanceNow()

// User timing marks
performanceMark("start")
// ... operation ...
performanceMark("end")
performanceMeasure("operation", "start", "end")

// Observe performance entries
performanceObserver(callback("entries")
    .forEach(callback("entry")
        .log(variable("entry").dot("name"), variable("entry").dot("duration"))
    )
).observe(obj("entryTypes", array("measure")))

JSON & Data

import static com.osmig.Jweb.framework.js.JSJson.*;

// Parse/stringify
jsonParse(variable("jsonString"))
jsonStringify(variable("obj"))
jsonStringifyPretty(variable("obj"), 2)

// FormData
import static com.osmig.Jweb.framework.js.JSFormData.*;

formData(variable("formElement"))
formDataEmpty()
formDataAppend(variable("fd"), "key", "value")

// URL
import static com.osmig.Jweb.framework.js.JSUrl.*;

urlParse(str("/path?q=search"))
urlSearchParams(obj("q", "search", "page", 1))
urlSearchParamsGet(variable("params"), "q")

Internationalization

import static com.osmig.Jweb.framework.js.JSIntl.*;

// Number formatting
numberFormat("en-US", obj(
    "style", "currency",
    "currency", "USD"
)).format(variable("amount"))
// Output: $1,234.56

// Date formatting
dateTimeFormat("en-US", obj(
    "dateStyle", "long",
    "timeStyle", "short"
)).format(variable("date"))
// Output: January 21, 2026 at 3:30 PM

// Relative time
relativeTimeFormat("en", obj("numeric", "auto"))
    .format(-1, "day")  // "yesterday"
Advanced APIs may require feature detection. Check browser support before using.

New Browser APIs

Additional browser APIs for offline storage, navigation, drag-and-drop, pointer input, and speech.

IndexedDB

Client-side database for structured offline storage.

import static com.osmig.Jweb.framework.js.JSIndexedDB.*;

// Open a database (creates if not exists)
openDB("myApp", 1)
    .onUpgrade(createStore(variable("db"), "users")
        .keyPath("id").autoIncrement()
        .index("email", "email")
        .uniqueIndex("username", "username")
        .build())
    .onSuccess(callback("db").log(str("DB opened")))
    .build()

// Transaction: add and read data
transaction(variable("db"), "users", "readwrite")
    .put(obj("id", num(1), "name", str("John")))
    .getAll()
    .onComplete(callback("results").log(variable("results")))
    .build()

// Cursor iteration with key range
cursorQuery(variable("db"), "users")
    .index("email")
    .bound("a", "m")
    .onEach(callback("cursor")
        .log(variable("cursor").dot("value")))
    .build()

// Delete a database
deleteDB("myApp")

History API

Browser navigation control for SPA routing patterns.

import static com.osmig.Jweb.framework.js.JSHistory.*;

// Navigate without reload
pushState("/dashboard", obj("page", str("dashboard")))
pushState("/users/42")  // URL-only

// Replace current entry (no back button)
replaceState("/settings")

// Go back/forward
back()
forward()
go(-2)  // Go back 2 steps

// Listen for back/forward navigation
onPopState(callback("e")
    .log(variable("e").dot("state")))

// Navigation guard (prompt before leaving)
navigationGuard("You have unsaved changes. Leave?")

// Query parameter helpers
getQueryParam("page")          // Read ?page=...
setQueryParam("sort", "name")  // Update URL param
removeQueryParam("filter")     // Remove param
queryParamsObject()             // All params as object

Drag and Drop

Native HTML5 drag-and-drop with builder pattern.

import static com.osmig.Jweb.framework.js.JSDragDrop.*;

// Make an element draggable
draggable("card-1")
    .data("text/plain", "Card 1 data")
    .effectAllowed("move")
    .onDragStart(callback("e").log(str("dragging")))
    .onDragEnd(callback("e").log(str("done")))
    .build()

// Create a drop zone
dropZone("drop-area")
    .dropEffect("move")
    .onDrop(callback("e")
        .log(getData(variable("e"), "text/plain")))
    .onDragEnter(callback("e")
        .log(str("entered drop zone")))
    .build()

// DataTransfer helpers
getData(variable("e"), "text/plain")
getFiles(variable("e"))
getTypes(variable("e"))

Pointer Events

Unified mouse, touch, and pen input handling.

import static com.osmig.Jweb.framework.js.JSPointer.*;

// Listen for pointer events
onPointerDown("canvas", callback("e")
    .log(pointerId(variable("e"))))
onPointerMove("canvas", callback("e")
    .log(pressure(variable("e"))))
onPointerUp("canvas", callback("e")
    .log(str("released")))

// Capture pointer (receive events outside element)
setPointerCapture("slider", variable("e").dot("pointerId"))
releasePointerCapture("slider", variable("e").dot("pointerId"))

// Access pointer properties
pointerId(variable("e"))      // Unique pointer ID
pointerType(variable("e"))    // "mouse", "touch", "pen"
pressure(variable("e"))       // 0.0 to 1.0
tiltX(variable("e"))          // Pen tilt angle
isPrimary(variable("e"))      // Is primary pointer?

// Multi-pointer tracking (pinch, multi-touch)
multiPointer("canvas")
    .onUpdate(callback("pointers")
        .log(variable("pointers").dot("size")))
    .build()

Web Speech

Text-to-speech and speech recognition APIs.

import static com.osmig.Jweb.framework.js.JSSpeech.*;

// Text-to-Speech (simple)
speak("Hello, welcome to JWeb!")

// Text-to-Speech (with options)
speakBuilder("Hello, welcome to JWeb!")
    .lang("en-US")
    .rate(1.0).pitch(1.0).volume(0.8)
    .onEnd(callback("e").log(str("Done speaking")))
    .build()

// Control speech
pauseSpeech()
resumeSpeech()
cancelSpeech()

// Speech Recognition (speech-to-text)
recognizer()
    .lang("en-US")
    .continuous(true)
    .interimResults(true)
    .onResult(callback("e")
        .log(transcript(variable("e"))))
    .onError(callback("e")
        .log(variable("e").dot("error")))
    .build("recognizer")

// Control recognition
startRecognition(variable("recognizer"))
stopRecognition(variable("recognizer"))

// Result helpers
transcript(variable("e"))     // Get text result
confidence(variable("e"))     // Confidence score
isFinal(variable("e"))        // Is result final?
IndexedDB and Speech APIs require user permission or HTTPS. Always check for browser support with feature detection before using these APIs.