Design doc for web-world.



We want to take advantage of web development interfaces.

    * We should be able to design and prototype web interfaces without
      touching a programming environment.

    * It should be easy to inject behavior separately from the static
      representation of a view.

    * This demands that the primary way to get a view is to use HTML
      files directly.


Furthermore, we want to fix a particularly glaring issue with the
previous attempt of jsworld:

    * The DOM nodes in jsworld were treated as values with implicit
      state, making it very difficult to write UI's that asked what
      the value was at a particular node.

    * The DOM tree represents external state!

    * Therefore, each world -> world function should take in, not just
      the internal state of the world, but the external state of the
      DOM tree.



We want to take the design ideas of JQuery.

    * The view is a cursor into a DOM node.

    * Operations refocus the cursor onto particular elements of the
      dom.

    * Methods on the view apply functional update on those nodes.




----------------------------------------------------------------------

Example 0  "hello world"

If we have an index.html as:

    
    <html><head><title>Hello world</title></head>
          <body><h1>Hello world</h1></body>
    </html>
    

then it should be trivial to make a program that just shows
that page:


    #lang planet dyoo/whalesong
    (require (planet dyoo/whalesong/web-world))

    (define-resource index.html)

    (big-bang "don't care"
              (initial-view index.html))


No reactivity means no changes to the view.

Comments: the initial-view can be a static resource.



In these examples, the ids I'm using for the resource and the file
name are matching.  I will allow an abbreviated use of define-resource
to eliminate this kind of duplication.  I'm planning to allow:

    (define-resource index.html)

to macro-expand out to the more explicit:

    (define-resource index.html "index.html")

which we talked about earlier.  I will use the abbreviated forms in
the remainder of the examples.



----------------------------------------------------------------------

Example 1  "tick tock"


A student should be able to prototype a basic user interface in .html,
such as:

    <html>
       <head><title>My simple program</title></head>
       <body>
       <p>The current counter is: <span id="counter">fill-me-in</span></p>
       </body>
    </html>



and then, in the programming language, add behavior:

    #lang planet dyoo/whalesong
    (require (planet dyoo/whalesong/web-world))

    (define-resource index.html)

    ;; draw: world view -> view
    (define (draw w v)
      (view-text (view-focus v "#counter")
                 w))

    ;; tick: world view -> world
    (define (tick w v)
      (add1 w)


    (big-bang 0
              (initial-view index.html)
              (to-draw draw)
              (on-tick tick))


to get a simple clock ticking application.



Comments: 

view-text, when given a view and a string, is a functional update that
replaces the text at the focus.  We're trying deliberately to match
JQuery.  These should be functional updates, though.


In contrast to plain vanilla world programs, the tick function of a
web-world consumes both the world and the view.  The draw function,
too, takes both the world and the currently-displayed view.  Event
handlers, like on-tick, should be allowed to look at the state of the
view, because they may want to do things like look up an element's
value.  The draw function does not reconstruct the entire DOM tree:
rather, it is responsible to producing functional updates of the
currently displayed view.



----------------------------------------------------------------------

Example 2  "the ticker"



We should be able to attach event handlers in the expected way to
elements of the DOM.  For example, let's count the number of times a
user clicks on a particular DIV.

Here, we need to adjust the view and attach a click event.

If index.html contains:

    <html>
       <head>
       <title>My simple program</title>
       <link rel="stylesheet" href="style.css">
       </head>

       <body>

       <div id="my-button">Click me!</div>

       <p>The current counter is: <span id="counter">fill-me-in</span></p>
       </body>
    </html>


with some appropriate CSS to make the DIV look good, then the program
will be:

    #lang planet dyoo/whalesong
    (require (planet dyoo/whalesong/web-world))

    (define-resource index.html)

    ;; Declare style.css as a resource so it gets bundled.
    (define-resource style.css)
    

    ;; draw: world view -> view
    (define (draw w v)
      (view-text (view-focus v "#counter")
                 w))

    ;; world view -> world
    (define (on-click w v)
      (add1 w))


    (define my-initial-view 
       (view-bind (view-focus (resource->view index.html)
                              "#my-button")
                  "click"
                  on-click))

    (big-bang 0
              (initial-view my-initial-view)
              (to-draw draw))


----------------------------------------------------------------------

Example 3 "field"


We want to make it easy to query from the view.  That's why each
handler takes, not only the world, but the current view.


    <html>
       <head>
       <title>My simple program</title>
       <link rel="stylesheet" href="style.css">
       </head>

       <body>
       <input type="text" id="text-field"/>
       <input type="button" id="button"/>

       <p>Hello <span id="template">fill-me-in</span>!</p>
       </body>
    </html>



    #lang planet dyoo/whalesong
    (require (planet dyoo/whalesong/web-world))

    (define-resource index.html)
    (define-resource style.css)

    ;; The world is a string which represents the name of the user.


    ;; on-click: world view -> world
    ;; When the user clicks on the button, grab at the text of the
    ;; text-field.
    (define (on-click w v)
      (view-text (view-focus v "#text-field")))


    ;; on-draw: world view -> view
    ;; Take the view, and replace the template with the world value.
    (define (on-draw w v)
      (view-text (view-focus v "#template")
                 w)) 
       

    (define my-view (view-bind (view-focus (resource->view index.html) 
                                           "#button")
                               "click"
                               on-click))

    (big-bang "Jane Doe"
              (initial-view my-view)
              (to-draw draw))


----------------------------------------------------------------------

Example 4   "dwarves!"


We need to be able to generate elements of views dynamically.  We
should also be able to attach event handlers dynamically, too.


The following should show an empty list, and on every clock tick, a
new dwarf will show up in the list.  If you click on a dwarf, it will
hide.

    <html>
    <head><title>Dwarves</title></head>
    <body>
    <ul></ul>
    </body>
    </html>


    #lang planet dyoo/whalesong
    (require (planet dyoo/whalesong/web-world))
    (define-resource index.html)

    ;; make-item: string -> view
    (define (make-item name)
       (view-bind (sexp->view `(li ,name))
                  "click"
                  hide-on-click))


    ;; When a dwarf clicks, it hides!
    (define (hide-on-click w v)
       (view-hide v))


    (define dwarf-names 
      '("Doc" "Grumpy" "Happy" "Sleepy" "Bashful" "Sneezy" "Dopey"))

 
    ;; Update the view so it shows the next dwarf on the scene,
    ;; until we're all done.
    (define (draw w v)
      (cond [(< w (length dwarf-names))
             (view-append (view-focus v "ul")
                          (make-item (list-ref dwarf-names w)))]
            [else
             v]))


    ;; tick: world view -> world
    (define (tick w v)
      (add1 w))


    (big-bang 0
              (initial-view index.html)
              (on-tick tick 1)
              (to-draw draw))
 


----------------------------------------------------------------------




Types


A view represents the DOM tree and its event handlers.


One way to create views is to take a resource and convert it to a view.

    resource->view: resource -> view

        Explicitly translate a resource into a view.


A more programmatic way to do this is with an s-expression representation.

    sexp->view: s-expression -> view

        Translate an s-expression into a view.

where the s-expression grammar is SXML.





A view is implicitly focused on a selection of its nodes.  You can
always refocus the view to the top:

   view-focus: view string -> view

       Refocus the view, using JQuery selector syntax.

   view-find: view string -> view

       Refocus the view, using JQuery selector syntax.  The search starts
       from the context of the currently focused nodes.

   view-top: view -> view

       Refocus the view to the toplevel node.

   view-up: view -> view

       Move the focus of the view over to the parents of the currently focused nodes.

   view-down: view -> view

       Move the focus of the view over to the parents of the currently focused nodes.

   view-next: view -> view

       Move the focus of the view over to the next siblings of the
       currently focused nodes.

   view-prev: view -> view

       Move the focus of the view over to the previous siblings of the
       currently focused nodes.






The content of a view may be functionally queried or updated:

   update-view-text: view string -> view

       Replace the text at the focus with the given string.

   view-text: view -> view

       Grab at the text of the currently focused nodes.
   

   update-view-css: view string string -> view
       Update the CSS style value of the currently focused node.

   view-css: view string -> view
       Get at the CSS style value of the currently focused node.




   update-view-attr: view string string -> view
       Update the attribute of the currently focused node.

   view-attr: view string -> view
       Get at the attribute value of the currently focused node.
        



   view-replace: view view -> view
   view-replace: view (listof view) -> view

       Replace the focused elements of the first view with the focused
       elements of the second view.


   view-delete: view -> view

       Remove the focused elements of the view.  The focus becomes empty.


   view-append: view view -> view
   view-append: view (listof view) -> view

       Append the focused elements of the second view after the
       focused elements of the first view.


   view-count: view -> number

       Count how many nodes are currently focused.



   view-clone: view -> view

       Do a deep clone of the currently focused elements.  Those fresh
       elements will focused.


   view-hide: view -> view

       Hide the selected focus.

   view-show: view -> view

       Show the selected focus.



We need to be able to bind events to elements of the view.

   view-bind: view string (world event -> world) -> view
   view-bind: view string (world -> world) -> view

      Given the view, the name of the event type, and its world
      handler, create a new view that binds that event to the focused
      nodes.

      The event will trigger the world-updating function, with the
      view focused on the originating node.

      If the bound function doesn't care about event-specific
      information, allow it to ignore the value.




Configuration of a web big-bang


    initial-view: resource | view -> handler
 
       Given a resource, assume it's a resource into a web page, and
       translate it directly into a view.


    into-dom: dom-node -> handler

       Use the given dom node as the toplevel parent.




Reactive handlers for a big bang:


    to-draw: (world view -> view) -> handler

        we need to be able to replace one view with another.


    on-tick: (world -> world) -> handler

             (world -> world) number -> handler