merging in documentation from cs19 into the mainline docs

This commit is contained in:
Danny Yoo 2011-08-31 16:36:36 -04:00
parent bd5f0ba6f8
commit df51ff112d

View File

@ -16,7 +16,8 @@
@(require (for-label (this-package-in js))
(for-label (this-package-in lang/base))
(for-label (this-package-in resource)))
(for-label (this-package-in resource)
(for-label (this-package-in web-world))))
@ -412,7 +413,7 @@ Given the name of a program, this builds a standalone
executes the program in a web browser.
The @filepath{.xhtml} should be self-contained, with an exception: if
the file uses any external resources by using
the file uses any external @tech{resource}s by using
@racket[define-resource], those resources are written into the current
working directory, if they do not already exist there.
@ -451,7 +452,7 @@ get-javascript depend on.
@section{Including external resources}
@defmodule/this-package[resource]
Programs may need to use external file resources that aren't
Programs may need to use external file @deftech{resource}s that aren't
themselves Racket programs, but instead some other kind of data.
Graphical programs will often use @filepath{.png}s, and web-related
programs @filepath{.html}s, for example. Whalesong provides the
@ -461,7 +462,7 @@ these resources will be bundled alongside the JavaScript-compiled
output.
@defform[(define-resource id [path-string])]{
Defines a resource with the given path name.
Defines a @tech{resource} with the given path name.
For example,
@codeblock|{
@ -477,12 +478,12 @@ As a convenience, you can also write
(define-resource humpback.png)
}|
which defines a variable named @racket[humpback.png] whose
resource is @filepath{humpback.png}.
@tech{resource} is @filepath{humpback.png}.
@defproc[(resource->url [a-resource resource?]) string?]{
Given a resource, gets a URL.
Given a @tech{resource}, gets a URL.
For example,
@codeblock|{
@ -514,7 +515,363 @@ For example,
@section{The JavaScript API}
@section{The web-world API}
@defmodule/this-package[web-world]
The @tt{web-world} library allows you to write functional event-driven
@link["http://world.cs.brown.edu"]{World} programs for the web; the
user defines functional callbacks to handle events, and receive and
consume a world argument.
One difference introduced by the web is the web page itself: because
the page itself is a source of state, it too will be passed to
callbacks. This library presents a functional version of the DOM in
the form of a @tech{view}.
Let's demonstrate this by creating a basic ticker that counts on the
screen every second.
The first thing we can do is mock up a web page with a user interface, like this.
@filebox["index.html"]{
@verbatim|{
<html>
<head><title>My simple program</title></head>
<body>
<p>The current counter is: <span id="counter">fill-me-in</span></p>
</body>
</html>
}|
}
We can even look at this in a standard web browser.
Once we're happy with the statics of our program, we can inject dynamic behavior.
Write a file called @filepath{tick-tock.rkt} with the following content.
@filebox["tick-tock.rkt"]{
@codeblock|{
#lang planet dyoo/whalesong
(require (planet dyoo/whalesong/web-world)
(planet dyoo/whalesong/resource))
(define-resource index.html)
;; draw: world view -> view
(define (draw world dom)
(update-view-text (view-focus dom "#counter") world))
;; tick: world view -> world
(define (tick world dom)
(add1 world))
;; stop?: world view -> boolean
(define (stop? world dom)
(> world 10))
(big-bang 0
(initial-view index.html)
(to-draw draw)
(on-tick tick 1)
(stop-when stop?))
}|
}
Several things are happening here.
@itemize[
@item{We @racket[require] a few libraries to get us some additional
behavior; in particular, @racketmodname/this-package[web-world] to let
us write event-driven web-based programs, and @racketmodname/this-package[resource]
to give us access to external @tech{resource}s.}
@item{We use @racket[define-resource] to refer to external files, like @filepath{index.html} that
we'd like to include in our program.}
@item{We use @racket[big-bang] to start up a computation that
responses to events. In this example, that's clock ticks introduced
by @racket[on-tick], though because we're on the web, we can
bind to many other kinds of web events (by using @racket[view-bind]).}
]
@subsection{@racket[big-bang] and its options}
@declare-exporting/this-package[web-world]
@defproc[(big-bang [w world]
[h big-bang-handler] ...) world]{
Start a big bang computation. The @racket[big-bang] consumes an initial world,
as well as several handlers to configure it, described next:
}
@defproc[(initial-view [x any]) big-bang-handler]{
Provide an initial view for the big-bang. Normally, @racket[x] will be a @tech{resource}
to a web page.
@codeblock|{
...
(define-resource page1.html)
...
(big-bang ...
(initial-view page1.html))
}|
}
@defproc[(stop-when [stop? ([w world] [dom view] -> boolean)]) big-bang-handler]{
Tells @racket[big-bang] when to stop.
@codeblock|{
...
(define-struct world (given expected))
...
;; stop?: world view -> boolean
(define (stop? world dom)
(string=? (world-given world) (world-expected world)))
(big-bang ...
(stop-when stop?))
}|
}
@defproc*[(((on-tick [tick-f ([w world] [v view] [e event]? -> world)] [delay real]) big-bang-handler)
((on-tick [tick-f ([w world] [v view] [e event]? -> world)]) big-bang-handler))]{
Tells @racket[big-bang] to update the world during clock ticks.
By default, this will send a clock tick 28 times a second, but if
given @racket[delay], it will use that instead.
@codeblock|{
...
;; tick: world dom -> world
(define (tick world view)
(add1 world))
(big-bang ...
(on-tick tick 5)) ;; tick every five seconds
}|
}
@defproc[(on-mock-location-change [location-f ([w world] [v view] [e event]? -> world)]) big-bang-handler]{
Tells @racket[big-bang] to update the world during simulated movement.
During the extent of a big-bang, a form widget will appear in the
@tt{document.body} to allow us to manually send location-changing
events.
The optional @tech{event} argument will contain numbers for
@racket["latitude"] and @racket["longitude"].
@codeblock|{
...
;; move: world view event -> world
(define (move world dom event)
(list (event-ref event "latitude")
(event-ref event "longitude")))
...
(big-bang ...
(on-mock-location-change move))
}|
}
@defproc[(on-location-change [location-f ([w world] [v view] [e event]? -> world)]) big-bang-handler]{
Tells @racket[big-bang] to update when the location changes, as
received by the
@link["http://dev.w3.org/geo/api/spec-source.html"]{Geolocation API}.
The optional @tech{event} argument will contain numbers for
@racket["latitude"] and @racket["longitude"].
@codeblock|{
...
;; move: world view event -> world
(define (move world dom event)
(list (event-ref event "latitude")
(event-ref event "longitude")))
...
(big-bang ...
(on-location-change move))
}|
}
@defproc[(to-draw [draw-f ([w world] [v view] -> view)]) big-bang-handler]{
Tells @racket[big-bang] how to update the rendering of the world. The draw
function will be called every time an event occurs.
@codeblock|{
...
(define-struct world (name age))
;; draw: world view -> view
(define (draw world dom)
(update-view-text (view-focus dom "#name-span")
(world-name world)))
...
(big-bang ...
(to-draw draw))
}|
}
@subsection{Views}
@declare-exporting/this-package[web-world]
A @deftech{view} is a functional representation of the browser DOM
tree. A view is always focused on an element, and the functions in
this subsection show how to traverse and manipulate the view.
@defproc[(->view [x any]) view]{
Coerse a value into a view whose focus is on the topmost element.
Common values for @racket[x] include @tech{resource}s.
}
@defproc[(view-focus [v view] [selector String]) view]{
Focuses the view on an element, given the @racket[selector]. The view
will be searched starting from the toplevelmost node.
Selectors are currently restricted to @litchar{#id} selectors for the
moment.
}
@defproc[(view-left [v view]) view]{
Move the focus to the previous sibling.
}
@defproc[(view-right [v view]) view]{
Move the focus to the next sibling.}
@defproc[(view-up [v view]) view]{
Move the focus to the parent.}
@defproc[(view-down [v view]) view]{
Move the view to the first child.}
@defproc[(view-text [v view]) string]{
Get the textual content at the focus.
}
@defproc[(update-view-text [v view] [s string]) view]{
Update the textual content at the focus.}
@defproc[(view-bind [v view] [type string] [world-updater ([w world] [v view] [e event]? -> world)]) view]{
Attach a world-updating event to the focus.
Attach a world-updating event to the focus. When the world-updater is
called, the view will be focused on the element that triggered the
event.
Common event types include @racket["click"], @racket["mouseenter"], @racket["change"].}
@defproc[(view-show [v view]) view]{
Show the element at the focus.
}
@defproc[(view-hide [v view]) view]{
Hide the element at the focus.
}
@defproc[(view-attr [v view] [name String]) view]{
Get the attribute @racket[name] at the focus.
}
@defproc[(update-view-attr [v view] [name String] [value String]) view]{
Update the attribute @racket[n] with the value @racket[v] at the focus.
}
@defproc[(view-id [v view]) world]{
Get the unique identifier of the node at the focus.
}
@defproc[(view-form-value [v view]) view]{
Get the form value of the node at the focus.}
@defproc[(update-view-form-value [v view] [value String]) view]{
Update the form value of the node at the focus.}
@defproc[(view-append-child [d dom]) view]{
Add the dom node @racket[d] as the last child of the focused node.}
@subsection{Events}
@declare-exporting/this-package[web-world]
An @deftech{event} is a structure that holds name-value pairs.
Whenever an event occurs in web-world, it may include some auxiliary
information about the event. As a concrete example, location events
from @racket[on-location-change] and @racket[on-mock-location-change]
can send latitude and longitude values, as long as the world callback
can accept the event as an argument.
@defstruct[event ([kvpairs (listof (list symbol (or/c string number)))])]{}
@defproc[(event-ref [evt event?] [name (or/c symbol string)]) value]{
Get an value from the event, given its @racket[name].
}
@defproc[(event-keys [evt event?]) (listof symbol)]{
Get an list of the event's keys.
}
@subsection{Tips and tricks: Hiding standard output or directing it to an element}
@declare-exporting/this-package[web-world]
For a web-world program, output is normally done by using
@racket[to-draw]. However, side effecting functions, such as
@racket[printf] or @racket[display], are still available, and will
append to @tt{document.body}.
We may want to disable such printing or redirect it to a particular
element on the page. For such purposes, use a combination of
@racket[current-output-port] and @racket[open-output-element] to
redirect the output of these side effect functions to somewhere else.
For example:
@codeblock|{
...
;; Redirect standard output to a div called "stdout-div".
(current-output-port (open-output-element "stdout-div"))
...
(big-bang ...
(on-tick (lambda (world dom)
(printf "Tick!\n")
(add1 world)))
...)
}|
All subsequent I/O side effects after the call to
@racket[current-output-port] will be written out to the
@tt{stdout-div}, which can be easily styled with @tt{display: none} to
hide it from normal browser display.
@defproc[(open-output-element [id string]) output-port]{
Opens an output port that will be directed to write to the DOM element
whose id is @racket[id]. Note: writing to this port shouldn't fail,
even if the id does not currently exist on the page.
}
@section{The JavaScript Foreign Function Interface}
@defmodule/this-package[js]{
@ -596,7 +953,7 @@ Returns the height of the viewport.
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@section{World programming}
@section{Simple world programming}
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Whalesong provides a library to support writing functional I/O