links-lang / links

Links: Linking Theory to Practice for the Web
http://www.links-lang.org
Other
333 stars 43 forks source link

Add Widget functionality (Address #1100) #1106

Closed SimonJF closed 2 years ago

SimonJF commented 2 years ago

This patch adds the notion of a 'widget' to the MVU library.

A widget is a virtual DOM node which is not affected by the render loop. You can therefore modify it using the usual (real) DOM functionality:

import MvuHTML;
import MvuAttrs;
open import Mvu;

typename Message = [| Incr | PopulateWidget |];
typename Model = (counter: Int);

sig view : (Model) ~> MvuHTML.HTML(Message)
fun view(model) {
    open MvuHTML;
    open MvuAttrs;
    var a0 = MvuAttrs.empty;
    var h0 = MvuHTML.empty;

    var widget =
        if (mod(model.counter, 2) == 0) {
                p(style("color:red"),
                    htmlWidget("div", [("id", "widget")]))
            } else {
                p(style("color:blue"),
                    htmlWidget("div", [("id", "widget")]))
            };

    div(a0,
        textNode(intToString(model.counter)) +*
        widget
    ) +*
    button(onClick(fun() { Incr }), textNode("Increment")) +*
    button(onClick(fun() { PopulateWidget }), textNode("Populate Widget"))
}

sig updt : (Message, Model) ~> Model
fun updt(msg, model) {
    switch (msg) {
        case Incr ->
            (counter = model.counter + 1)
        case PopulateWidget ->
            domReplaceChildren(<#>node content</#>, getNodeById("widget"));
            model
    }
}

fun mainPage() {
    var model = (counter = 0);
    runSimple("placeholder", model, view, updt);
    page
        <html><body><div id="placeholder"></div></body></html>
}

serveThis(mainPage)

This should address #1100 -- simply create a widget as a placeholder with a known ID, and then populate the widget from an FFI call.

SimonJF commented 2 years ago

Sorry, this one passed me by -- thanks for the review @dhil. Should be suitable for merging after the CI completes.