Merge branch 'web-world'

Conflicts:

	scribblings/cs19.scrbl
This commit is contained in:
Danny Yoo 2011-08-29 09:39:32 -04:00
commit efc8dcdf9f
12 changed files with 752 additions and 106 deletions

View File

@ -170,11 +170,11 @@
(source-name (first sources))))
(hash-set! visited (first sources) #t)
(let*-values ([(this-source)
((current-module-source-compiling-hook)
(first sources))]
((current-module-source-compiling-hook)
(first sources))]
[(ast stmts)
(get-ast-and-statements this-source)])
(log-debug "visiting")
(log-debug (format "visiting ~a\n" (source-name this-source)))
(on-module-statements this-source ast stmts)
(loop (append (map wrap-source (collect-new-dependencies this-source ast))
(rest sources)))

View File

@ -216,3 +216,4 @@ For example,
}

View File

@ -213,7 +213,7 @@ will be:
----------------------------------------------------------------------
Example 3
Example 3 "field"
We want to make it easy to query from the view. That's why each

View File

@ -1,8 +1,107 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta name="viewport" content="initial-scale=1.0, width=device-width, height=device-height, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta charset="utf-8"/>
<title></title>
</head>
<script>
<html>
<head><title>Animation</title>
<link rel="stylesheet" href="style.css"/>
</head>
<body>
<p>
This should be animating:
<hr/>
<div>
<div class="selectedBlock" id="0"></div>
<div class="block" id="1"></div>
<div class="block" id="2"></div>
<div class="block" id="3"></div>
<div class="block" id="4"></div>
<div class="block" id="5"></div>
<div class="block" id="6"></div>
<div class="block" id="7"></div>
<div class="block" id="8"></div>
<div class="block" id="9"></div>
</div>
<hr/>
The program for this is:
<blockquote>
<pre>
#lang planet dyoo/whalesong
(require (planet dyoo/whalesong/resource)
(planet dyoo/whalesong/web-world))
(define-resource index.html)
(define-resource style.css)
(define (tick w v)
(modulo (add1 w) 10))
;; pick-block: world view -> view
;; Focus the view on block i.
(define (pick-block v i)
(view-focus v (format "#~a" i)))
(define (draw w v)
(define v1 (update-view-attr
(pick-block v w)
"class"
"selectedBlock"))
(define v2 (update-view-attr
(pick-block v1 (modulo (sub1 w) 10))
"class"
"offsetBlock"))
(define v3 (update-view-attr
(pick-block v2 (modulo (add1 w) 10))
"class"
"offsetBlock"))
(define v4 (update-view-attr
(pick-block v3 (modulo (- w 2) 10))
"class"
"block"))
(define v5 (update-view-attr
(pick-block v4 (modulo (+ w 2) 10))
"class"
"block"))
v5)
(big-bang 0
(initial-view index.html)
(on-tick tick)
(to-draw draw))
</pre>
</blockquote>
with <tt>style.css</tt>:
<blockquote>
<pre>
.block {
width : 80px;
height : 10px;
background-color : blue;
display: inline-block;
}
.selectedBlock {
width : 80px;
height : 10px;
background-color: navy;
display: inline-block;
}
.offsetBlock {
width : 80px;
height : 10px;
background-color: teal;
display: inline-block;
}
</pre>
</blockquote>
</p>
</body>
</html>

View File

@ -0,0 +1,53 @@
#lang planet dyoo/whalesong
(require (planet dyoo/whalesong/web-world)
(planet dyoo/whalesong/resource))
(define-resource index.html)
;; The world is the set of dwarfs.
;; make-item: string -> view
(define (make-item name)
(view-bind (->view `(li ,name))
"click"
hide-on-click))
;; When a dwarf clicks, it hides!
(define (hide-on-click w v)
(remove (view-id v) w))
(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 dom-view)
(foldl (lambda (name view)
(define focused (view-focus view (format "#~a" name)))
(cond
[(member name w)
(view-show focused)]
[else
(view-hide focused)]))
dom-view
dwarf-names))
;; The first view consists of index.html. We attach event handlers
;; to each name here.
(define my-view
(foldl (lambda (name view)
(view-bind (view-focus view (format "#~a" name))
"click"
hide-on-click))
(->view index.html)
dwarf-names))
(big-bang dwarf-names
(initial-view my-view)
(to-draw draw))

View File

@ -0,0 +1,16 @@
<html>
<head><title>Dwarves</title></head>
<body>
<h1>Dwarfs from Snow White</h1>
<p>Click on a dwarf to make them hide.</p>
<ul id="list">
<li id="Doc">Doc</li>
<li id="Grumpy">Grumpy</li>
<li id="Happy">Happy</li>
<li id="Sleepy">Sleepy</li>
<li id="Bashful">Bashful</li>
<li id="Sneezy">Sneezy</li>
<li id="Dopey">Dopey</li>
</ul>
</body>
</html>

View File

@ -0,0 +1,31 @@
#lang planet dyoo/whalesong
(require (planet dyoo/whalesong/web-world)
(planet dyoo/whalesong/resource))
(define-resource index.html)
;; 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 button-view)
(view-form-value (view-focus button-view "#text-field")))
;; draw: world view -> view
;; Take the view, and replace the template with the world value.
(define (draw w dom)
(update-view-text (view-focus dom "#template")
w))
(define my-view (view-bind (view-focus (->view index.html)
"#button")
"click"
on-click))
(big-bang "Jane Doe"
(initial-view my-view)
(to-draw draw))

View File

@ -0,0 +1,12 @@
<html>
<head>
<title>My simple program</title>
</head>
<body>
<input type="text" id="text-field"/>
<input type="button" id="button" value="Click me"/>
<p>Hello <span id="template">fill-me-in</span>!</p>
</body>
</html>

View File

@ -35,7 +35,17 @@
view-text
update-view-text
view-bind
view-show
view-hide
view-attr
update-view-attr
view-id
view-form-value
update-view-form-value
view-append-child
))

3
web-world/info.rkt Normal file
View File

@ -0,0 +1,3 @@
#lang setup/infotab
(define compile-omit-paths '("examples"))

View File

@ -11,10 +11,45 @@
var isString = plt.baselib.strings.isString;
// FIXME: as soon as we get real parameters, use parameters
// instead. Global: defines the currently running big bang.
// Parameterized around the call to bigBang.
var currentBigBangRecord = undefined;
var resourceStructType =
MACHINE.modules['whalesong/resource/structs.rkt'].namespace['struct:resource'];
var domToCursor = function(dom) {
var domOpenF =
// To go down, just take the children.
function(n) {
return [].slice.call(n.childNodes, 0);
};
var domCloseF =
// To go back up, take the node, do a shallow cloning, and replace the children.
function(node, children) {
var i;
var newNode = node.cloneNode(false);
for (i = 0; i < children.length; i++) {
newNode.appendChild(children[i].cloneNode(true));
}
return newNode;
};
var domAtomicF =
function(node) {
return node.nodeType !== 1;
};
return TreeCursor.adaptTreeCursor(dom.cloneNode(true),
domOpenF,
domCloseF,
domAtomicF);
};
@ -69,18 +104,24 @@
//////////////////////////////////////////////////////////////////////
var MockView = function(cursor, pendingActions, nonce) {
// A MockView provides a functional interface to the DOM. It
// includes a cursor to the currently focused dom, the pending
// actions to perform on the actual view, and a nonce to detect
// freshness of the MockView.
var MockView = function(cursor, pendingActions, eventHandlers, nonce) {
this.cursor = cursor;
this.pendingActions = pendingActions;
this.eventHandlers = eventHandlers;
this.nonce = nonce;
};
var isMockView = plt.baselib.makeClassPredicate(MockView);
MockView.prototype.act = function(actionForCursor, actionForReal) {
if (arguments.length !== 2) { throw new Error("act: insufficient arguments"); }
MockView.prototype.act = function(actionForCursor, actionForEventHandlers, actionForReal) {
if (arguments.length !== 3) { throw new Error("act: insufficient arguments"); }
return new MockView(actionForCursor(this.cursor),
this.pendingActions.concat([actionForReal]),
actionForEventHandlers(this.eventHandlers),
this.nonce);
};
@ -100,6 +141,7 @@
}
}
},
function(eventHandlers) { return eventHandlers; },
function(view) {
view.focus = view.top.find(selector);
}
@ -115,30 +157,59 @@
function(cursor) {
return cursor.replaceNode($(cursor.node).clone(true).text(text).get(0));
},
function(eventHandlers) { return eventHandlers; },
function(view) {
view.focus.text(text);
})
}
)
};
MockView.prototype.getAttr = function(name) {
return $(this.cursor.node).attr(name);
};
MockView.prototype.updateAttr = function(name, value) {
return this.act(
function(cursor) {
return cursor.replaceNode($(cursor.node).clone(true).attr(name, value).get(0));
},
function(eventHandlers) {
return eventHandlers;
},
function(view) {
view.focus.attr(name, value);
})
};
MockView.prototype.getFormValue = function() {
return $(this.cursor.node).val();
};
MockView.prototype.updateFormValue = function(value) {
return this.act(
function(cursor) {
return cursor.replaceNode($(cursor.node).clone(true).val(value).get(0));
},
function(eventHandlers) {
return eventHandlers;
},
function(view) {
view.focus.val(value);
})
};
MockView.prototype.left = function() {
return this.act(
function(cursor) {
return cursor.left();
},
function(eventHandlers) {
return eventHandlers;
},
function(view) {
view.focus = view.focus.prev();
});
@ -149,6 +220,9 @@
function(cursor) {
return cursor.right();
},
function(eventHandlers) {
return eventHandlers;
},
function(view) {
view.focus = view.focus.next();
});
@ -159,9 +233,12 @@
function(cursor) {
return cursor.up();
},
function(eventHandlers) {
return eventHandlers;
},
function(view) {
view.focus = view.focus.parent();
});
});
};
MockView.prototype.down = function() {
@ -169,10 +246,112 @@
function(cursor) {
return cursor.down();
},
function(eventHandlers) {
return eventHandlers;
},
function(view) {
view.focus = view.focus.children(':first');
});
});
};
var mockViewIdGensym = 0;
MockView.prototype.bind = function(name, worldF) {
var that = this;
// HACK: every node that is bound needs to have an id. We
// enforce this by mutating the node.
if (! this.cursor.node.id) {
this.cursor.node.id = ("__webWorldId_" + mockViewIdGensym++);
}
return this.act(
function(cursor) {
var newCursor = cursor.replaceNode($(cursor.node).clone(true).get(0));
var handler = new EventHandler(name,
new DomEventSource(name, newCursor.node),
worldF);
if (currentBigBangRecord !== undefined) {
currentBigBangRecord.startEventHandler(handler);
}
return newCursor;
},
function(eventHandlers) {
var handler = new EventHandler(name,
new DomEventSource(
name,
that.cursor.node.id),
worldF);
return eventHandlers.concat([handler]);
},
function(view) {
// HACK: every node that is bound needs to have an id. We
// enforce this by mutating the node.
if (! view.focus.get(0).id) {
view.focus.get(0).id = ("__webWorldId_" + mockViewIdGensym++);
}
var handler = new EventHandler(name,
new DomEventSource(
name,
view.focus.get(0).id),
worldF);
view.addEventHandler(handler);
currentBigBangRecord.startEventHandler(handler);
});
};
MockView.prototype.show = function() {
return this.act(
function(cursor) {
return cursor.replaceNode($(cursor.node).clone(true).show().get(0));
},
function(eventHandlers) { return eventHandlers; },
function(view) {
view.focus.show();
}
)
};
MockView.prototype.hide = function() {
return this.act(
function(cursor) {
return cursor.replaceNode($(cursor.node).clone(true).hide().get(0));
},
function(eventHandlers) { return eventHandlers; },
function(view) {
view.focus.hide();
}
)
};
MockView.prototype.appendChild = function(domNode) {
return this.act(
function(cursor) {
if (cursor.canDown()) {
cursor = cursor.down();
while (cursor.canRight()) {
cursor = cursor.right();
}
return cursor.insertRight(domNode.cloneNode(true));
} else {
return cursor.insertDown(domNode.cloneNode(true));
}
},
function(eventHandlers) { return eventHandlers; },
function(view) {
var clone = $(domNode).clone(true);
clone.appendTo(view.focus);
view.focus = clone;
}
)
};
MockView.prototype.id = function() {
return this.cursor.node.id;
};
//////////////////////////////////////////////////////////////////////
@ -205,6 +384,10 @@
}
};
View.prototype.addEventHandler = function(handler) {
this.eventHandlers.push(handler);
};
// Return a list of the event sources from the view.
// fixme: may need to apply the pending actions to get the real set.
View.prototype.getEventHandlers = function() {
@ -213,7 +396,8 @@
View.prototype.getMockAndResetFocus = function(nonce) {
this.focus = this.top;
return new MockView(TreeCursor.domToCursor($(this.top).get(0)),
return new MockView(domToCursor($(this.top).get(0)),
[],
[],
nonce);
};
@ -252,7 +436,9 @@
return onFail(exn);
}
return onSuccess(new View(dom, []));
} else if (isMockView(x)) {
return onSuccess(new View($(x.cursor.top().node),
x.eventHandlers));
} else {
try {
dom = $(plt.baselib.format.toDomNode(x))
@ -277,18 +463,52 @@
} catch (exn) {
return onFail(exn);
}
return onSuccess(new MockView(TreeCursor.domToCursor(dom.get(0)), [], undefined));
return onSuccess(new MockView(domToCursor(dom.get(0)), [], [], undefined));
} else {
try {
dom = $(plt.baselib.format.toDomNode(x))
} catch (exn) {
return onFail(exn);
}
return onSuccess(new MockView(TreeCursor.domToCursor(dom.get(0)), [], undefined));
return onSuccess(new MockView(domToCursor(dom.get(0)), [], [], undefined));
}
};
var coerseToDomNode = function(x, onSuccess, onFail) {
var dom;
if (isDomNode(x)) {
return onSuccess(x);
} else if (isResource(x)) {
try {
dom = $(resourceContent(x).toString())
.css("margin", "0px")
.css("padding", "0px")
.css("border", "0px");
} catch (exn) {
return onFail(exn);
}
return onSuccess(dom.get(0));
} else if (isMockView(x)) {
return onSuccess(x.cursor.top().node);
} else {
try {
dom = plt.baselib.format.toDomNode(x);
} catch (exn) {
return onFail(exn);
}
return onSuccess(dom);
}
};
var isDomNode = function(x) {
return (x.hasOwnProperty('nodeType') &&
x.nodeType === 1);
};
@ -339,6 +559,8 @@
// An EventHandler combines a EventSource with a racketWorldCallback.
var EventHandler = function(name, eventSource, racketWorldCallback) {
WorldHandler.call(this);
this.name = name;
@ -379,7 +601,9 @@
/* Event sources.
An event source are the inputs to a web world program.
An event source is a way to send input to a web-world program.
An event source may be started or stopped.
Pause and Unpause are semantically meant to be cheaper than start, stop, so
@ -405,7 +629,8 @@
// Clock ticks.
// TickEventSource sends tick events.
var TickEventSource = function(delay) {
this.delay = delay; // delay in milliseconds.
@ -419,7 +644,7 @@
TickEventSource.prototype.onStart = function(fireEvent) {
this.id = setInterval(
function() {
fireEvent();
fireEvent(undefined);
},
this.delay);
};
@ -432,27 +657,43 @@
};
var BindEventSource = function(type, element) {
// DomElementSource: string (U DOM string) -> EventSource
// A DomEventSource allows DOM elements to send events over to
// web-world.
var DomEventSource = function(type, elementOrId) {
this.type = type;
this.element = element;
this.elementOrId = elementOrId;
this.handler = undefined;
};
BindEventSource.prototype = plt.baselib.heir(EventSource.prototype);
DomEventSource.prototype = plt.baselib.heir(EventSource.prototype);
BindEventSource.prototype.onStart = function(fireEvent) {
this.handler =
function(evt) {
fireEvent(evt);
};
$(this.element).bind(this.type,
this.handler);
DomEventSource.prototype.onStart = function(fireEvent) {
var element = this.elementOrId;
if (typeof(this.elementOrId) === 'string') {
element = $('#' + this.elementOrId).get(0);
}
this.handler = function(evt) {
if (element !== undefined) {
fireEvent(element, evt);
}
};
if (element !== undefined) {
$(element).bind(this.type, this.handler);
}
};
BindEventSource.prototype.onStop = function() {
DomEventSource.prototype.onStop = function() {
var element = this.elementOrId;
if (typeof(this.elementOrId) === 'string') {
element = $('#' + this.elementOrId).get(0);
}
if (this.handler !== undefined) {
$(this.element).unbind(this.type, this.handler);
if (element !== undefined) {
$(element).unbind(this.type, this.handler);
}
this.handler = undefined;
}
};
@ -479,7 +720,8 @@
};
var EventQueueElement = function(handler, data) {
var EventQueueElement = function(who, handler, data) {
this.who = who;
this.handler = handler;
this.data = data;
};
@ -499,6 +741,7 @@
// bigBang.
var bigBang = function(MACHINE, world, handlers) {
var oldArgcount = MACHINE.argcount;
var oldCurrentBigBangRecord = currentBigBangRecord;
var running = true;
var dispatchingEvents = false;
@ -510,34 +753,74 @@
var eventQueue = new EventQueue();
var top = $("<div/>");
var eventHandlers = filter(handlers, isEventHandler).concat(view.getEventHandlers());
MACHINE.params.currentDisplayer(MACHINE, top);
PAUSE(function(restart) {
var i;
var onCleanRestart = function() {
running = false;
var i;
for (i = 0; i < eventHandlers.length; i++) {
stopEventHandler(eventHandlers[i]);
}
stopEventHandlers();
restart(function(MACHINE) {
MACHINE.argcount = oldArgcount;
currentBigBangRecord = oldCurrentBigBangRecord;
finalizeClosureCall(MACHINE, world);
});
};
var onMessyRestart = function(exn) {
running = false;
var i;
for (i = 0; i < eventHandlers.length; i++) {
stopEventHandler(eventHandlers[i]);
}
stopEventHandlers();
restart(function(MACHINE) {
currentBigBangRecord = oldCurrentBigBangRecord;
plt.baselib.exceptions.raise(MACHINE, exn);
});
};
var dispatchEventsInQueue = function() {
var startEventHandlers = function() {
var i;
for (i = 0; i < eventHandlers.length; i++) {
startEventHandler(eventHandlers[i]);
}
};
var stopEventHandlers = function() {
var i;
for (i = 0; i < eventHandlers.length; i++) {
stopEventHandler(eventHandlers[i]);
}
};
var startEventHandler = function(handler) {
var fireEvent = function(who) {
if (! running) { return; }
var args = [].slice.call(arguments, 1);
eventQueue.queue(new EventQueueElement(who, handler, args));
if (! dispatchingEvents) {
dispatchingEvents = true;
setTimeout(
function() {
dispatchEventsInQueue(
function() {
refreshView(function() {},
onMessyRestart);
},
onMessyRestart);
},
0);
}
};
handler.eventSource.onStart(fireEvent);
};
var stopEventHandler = function(handler) {
handler.eventSource.onStop();
};
var dispatchEventsInQueue = function(success, fail) {
// Apply all the events on the queue, call toDraw, and then stop.
// If the world ever satisfies stopWhen, stop immediately and quit.
var nextEvent;
@ -549,8 +832,11 @@
// Set up the proxy object so we can do what appear to be functional
// queries.
mockView = view.getMockAndResetFocus();
nextEvent = eventQueue.dequeue();
if (nextEvent.who !== undefined) {
mockView = mockView.updateFocus('#' + nextEvent.who.id);
}
// FIXME: deal with event data here
racketWorldCallback = nextEvent.handler.racketWorldCallback;
racketWorldCallback(MACHINE,
@ -564,24 +850,25 @@
mockView,
function(shouldStop) {
if (shouldStop) {
refreshViewAndStopDispatching(
refreshView(
function() {
onCleanRestart();
},
onMessyRestart);
fail);
} else {
dispatchEventsInQueue();
dispatchEventsInQueue(success, fail);
}
},
onMessyRestart);
fail);
},
onMessyRestart);
fail);
} else {
refreshViewAndStopDispatching(function() {}, onMessyRestart);
dispatchingEvents = false;
success();
}
};
var refreshViewAndStopDispatching = function(success, failure) {
var refreshView = function(success, failure) {
// Note: we create a random nonce, and watch to see if the MockView we get back
// from the user came from here. If not, we have no hope to do a nice, efficient
// update, and have to do it from scratch.
@ -600,47 +887,23 @@
} else {
view.top = $(newMockView.cursor.top().node);
view.initialRender(top);
// FIXME: how about events embedded in the dom?
eventHandlers = newMockView.eventHandlers;
startEventHandlers();
}
dispatchingEvents = false;
success();
},
function(err) {
dispatchingEvents = false;
failure(err);
})
};
var startEventHandler = function(handler) {
var fireEvent = function() {
if (! running) { return; }
var args = [].slice.call(arguments, 0);
eventQueue.queue(new EventQueueElement(handler, args));
if (! dispatchingEvents) {
setTimeout(dispatchEventsInQueue, 0);
}
//
// fixme: if we see too many events accumulating, throttle
// the ones that are marked as throttleable.
};
handler.eventSource.onStart(fireEvent);
};
var stopEventHandler = function(handler) {
handler.eventSource.onStop();
};
currentBigBangRecord = { stop : onCleanRestart,
stopWithExn : onMessyRestart,
startEventHandler : startEventHandler,
stopEventHandler : stopEventHandler };
view.initialRender(top);
var eventHandlers = filter(handlers, isEventHandler).concat(view.getEventHandlers());
var i;
for (i = 0; i < eventHandlers.length; i++) {
startEventHandler(eventHandlers[i]);
}
startEventHandlers();
refreshView(function() {}, onMessyRestart);
});
};
@ -659,6 +922,38 @@
// findDomNodeLocation: dom-node dom-node -> arrayof number
// Given a node, returns the child indices we need to follow to reach
// it from the top.
// Assumption: top must be an ancestor of the node. Otherwise, the
// result is partial.
var findDomNodeLocation = function(node, top) {
var locator = [];
var parent, i;
while(node !== top && node.parentNode !== null) {
parent = node.parentNode;
for (i = 0; i < parent.childNodes.length; i++) {
if (parent.childNodes[i] === node) {
locator.push(i);
break;
}
}
node = parent;
}
return locator.reverse();
};
var findNodeFromLocation = function(top, location) {
var i = 0;
var node = top;
for (i = 0; i < location.length; i++) {
node = node.childNodes[location[i]];
}
return node;
};
//////////////////////////////////////////////////////////////////////
var checkReal = plt.baselib.check.checkReal;
@ -730,27 +1025,28 @@
'->view',
1,
function(MACHINE) {
var viewable = MACHINE.env[MACHINE.env.length - 1];
var oldArgcount = MACHINE.argcount;
PAUSE(function(restart) {
coerseToView(viewable,
function(v) {
restart(function(MACHINE) {
MACHINE.argcount = oldArgcount;
finalizeClosureCall(MACHINE, v);
coerseToMockView(viewable,
function(v) {
restart(function(MACHINE) {
MACHINE.argcount = oldArgcount;
finalizeClosureCall(MACHINE, v);
});
},
function(exn) {
restart(function(MACHINE) {
plt.baselib.exceptions.raise(
MACHINE,
new Error(plt.baselib.format.format(
"unable to translate ~s to view: ~a",
[viewable, exn.message])));
});
});
},
function(exn) {
restart(function(MACHINE) {
plt.baselib.exceptions.raise(
MACHINE,
new Error(plt.baselib.format.format(
"unable to translate ~s to view: ~a",
[viewable, exn.message])));
});
});
});
});
EXPORTS['stop-when'] = makePrimitiveProcedure(
'stop-when',
1,
@ -888,5 +1184,94 @@
EXPORTS['view-bind'] = makePrimitiveProcedure(
'view-bind',
3,
function(MACHINE) {
var view = checkMockView(MACHINE, 'view-bind', 0);
var name = checkSymbolOrString(MACHINE, 'view-bind', 1);
var worldF = wrapFunction(checkProcedure(MACHINE, 'view-bind', 2));
return view.bind(name, worldF);
});
EXPORTS['view-form-value'] = makePrimitiveProcedure(
'view-form-value',
1,
function(MACHINE) {
var view = checkMockView(MACHINE, 'view-form-value', 0);
return view.getFormValue();
});
EXPORTS['update-view-form-value'] = makePrimitiveProcedure(
'update-view-form-value',
2,
function(MACHINE) {
var view = checkMockView(MACHINE, 'update-view-form-value', 0);
var value = checkSymbolOrString(MACHINE, 'update-view-form-value', 1).toString();
return view.updateFormValue(value);
});
EXPORTS['view-show'] = makePrimitiveProcedure(
'view-show',
1,
function(MACHINE) {
var view = checkMockView(MACHINE, 'view-show', 0);
return view.show();
});
EXPORTS['view-hide'] = makePrimitiveProcedure(
'view-hide',
1,
function(MACHINE) {
var view = checkMockView(MACHINE, 'view-hide', 0);
return view.hide();
});
EXPORTS['view-append-child'] = makeClosure(
'view-append-child',
2,
function(MACHINE) {
var view = checkMockView(MACHINE, 'view-append-child', 0);
var oldArgcount = MACHINE.argcount;
var x = MACHINE.env[MACHINE.env.length - 2];
PAUSE(function(restart) {
coerseToDomNode(x,
function(dom) {
restart(function(MACHINE) {
MACHINE.argcount = oldArgcount;
var updatedView = view.appendChild(dom);
finalizeClosureCall(MACHINE, updatedView);
});
},
function(err) {
restart(function(MACHINE) {
plt.baselib.exceptions.raise(
MACHINE,
new Error(plt.baselib.format.format(
"unable to translate ~s to dom node: ~a",
[x, exn.message])));
});
});
});
});
EXPORTS['view-id'] = makePrimitiveProcedure(
'view-id',
1,
function(MACHINE) {
var view = checkMockView(MACHINE, 'view-hide', 0);
return view.id();
});
//////////////////////////////////////////////////////////////////////
}());

View File

@ -5,7 +5,18 @@
view-focus
view-left view-right view-up view-down
view-text update-view-text
view-attr update-view-attr)
view-attr update-view-attr
view-id
view-bind
view-form-value
update-view-form-value
view-show
view-hide
view-append-child)
(define (big-bang world . handlers)
(error 'big-bang "Please run in JavaScript context."))
@ -59,4 +70,29 @@
(error 'view-attr "Please run in JavaScript context."))
(define (update-view-attr v attr-name value)
(error 'update-view-attr "Please run in JavaScript context."))
(error 'update-view-attr "Please run in JavaScript context."))
(define (view-id v)
(error 'view-id "Please run in JavaScript context."))
(define (view-bind v type worldF)
(error 'view-bind "Please run in JavaScript context."))
(define (view-form-value)
(error 'view-form-value "Please run in JavaScript context."))
(define (update-view-form-value val)
(error 'view-form-value "Please run in JavaScript context."))
(define (view-show)
(error 'view-show "Please run in JavaScript context."))
(define (view-hide)
(error 'view-hide "Please run in JavaScript context."))
(define (view-append-child dom)
(error 'view-append "Please run in JavaScript context."))