trying to get simple view stuff working.

This commit is contained in:
Danny Yoo 2011-08-24 16:56:58 -04:00
parent f488db734b
commit 84c6df5f90
5 changed files with 198 additions and 42 deletions

View File

@ -31,7 +31,7 @@ previous attempt of jsworld:
We want to take the design ideas of JQuery. We want to take the design ideas of JQuery.
* The view is a cursor into DOM nodes. * The view is a cursor into a DOM node.
* Operations refocus the cursor onto particular elements of the * Operations refocus the cursor onto particular elements of the
dom. dom.
@ -249,13 +249,13 @@ handler takes, not only the world, but the current view.
;; When the user clicks on the button, grab at the text of the ;; When the user clicks on the button, grab at the text of the
;; text-field. ;; text-field.
(define (on-click w v) (define (on-click w v)
(view-text (view-focus v "text-field"))) (view-text (view-focus v "#text-field")))
;; on-draw: world view -> view ;; on-draw: world view -> view
;; Take the view, and replace the template with the world value. ;; Take the view, and replace the template with the world value.
(define (on-draw w v) (define (on-draw w v)
(view-text (view-focus v "template") (view-text (view-focus v "#template")
w)) w))

View File

@ -4,18 +4,21 @@
(define-resource index.html) (define-resource index.html)
;; draw: world view -> view ;; draw: world view -> view
(define (draw w v) (define (draw w v)
v (update-view-text (view-focus v "#counter") w))
;(view-text (view-focus v "#counter") w)
)
;; tick: world view -> world ;; tick: world view -> world
(define (tick w v) (define (tick w v)
(printf "Tick\n") (printf "Tick ~s\n" w)
(+ add1 w)) (+ w 1))
(big-bang 0 (big-bang 0
(initial-view index.html) (initial-view index.html)
(to-draw draw) (to-draw draw)
(on-tick tick 1)) (on-tick tick 1)
(stop-when (lambda (w v)
(> w 10))))

View File

@ -23,4 +23,9 @@
to-draw to-draw
;; coerse to view ;; coerse to view
->view)) ->view
view-focus
view-text
update-view-text
))

View File

@ -8,7 +8,7 @@
var makeClosure = plt.baselib.functions.makeClosure; var makeClosure = plt.baselib.functions.makeClosure;
var finalizeClosureCall = plt.baselib.functions.finalizeClosureCall; var finalizeClosureCall = plt.baselib.functions.finalizeClosureCall;
var PAUSE = plt.runtime.PAUSE; var PAUSE = plt.runtime.PAUSE;
var isString = plt.baselib.strings.isString;
var resourceStructType = var resourceStructType =
@ -16,21 +16,62 @@
// A View represents a functional representation of the DOM tree. // See Functional Pearl: The Zipper, by G\'erard Huet
var View = function(top, focused, eventHandlers, pendingActions) { // J. Functional Programming 7 (5): 549--554 Sepember 1997
var TreeCursor = function() {
this.parent;
this
};
//////////////////////////////////////////////////////////////////////
var MockView = function(focused, pendingActions) {
this.focused = focused;
this.pendingActions = pendingActions;
};
var isMockView = plt.baselib.makeClassPredicate(MockView);
MockView.prototype.act = function(actionForMock, actionForReal) {
if (arguments.length !== 2) { throw new Error("act: insufficient arguments"); }
// FIXME: this is not enough. We need a way to do the action
// on a copy of the mock. clone is insufficient: we need to
// copy the whole tree, no?
return new MockView(actionForMock(this.focused),
this.pendingActions.concat([actionForReal]));
};
MockView.prototype.updateFocus = function(selector) {
return this;
};
MockView.prototype.getText = function() {
return "fill me in";
};
MockView.prototype.updateText = function(text) {
return this;
};
//////////////////////////////////////////////////////////////////////
// A View represents a representation of the DOM tree.
var View = function(top, focused, eventHandlers, pendingActions, proxy) {
// top: dom node // top: dom node
this.top = top; this.top = top;
this.focused = focused; this.focused = focused;
this.eventHandlers = eventHandlers; this.eventHandlers = eventHandlers;
this.pendingActions = pendingActions;
}; };
View.prototype.toString = function() { return "#<View>"; }; View.prototype.toString = function() { return "#<View>"; };
View.prototype.updateFocused = function(focused) {
return new View(this.top, focused, this.eventHandlers, this.pendingActions);
};
View.prototype.initialRender = function(top) { View.prototype.initialRender = function(top) {
top.empty(); top.empty();
$(document.head).append(this.top.find("head").children()); $(document.head).append(this.top.find("head").children());
@ -50,6 +91,42 @@
return this.eventHandlers; return this.eventHandlers;
}; };
View.prototype.getMock = function() {
return new MockView(this.top.clone(true), []);
};
// View.prototype.updateFocus = function(selector) {
// if (this.proxy) {
// return new View(this.top, this.top.find(selector), this.eventHandlers, this.pendingActions, this.proxy);
// } else {
// return new View(this.top, this.top.find(selector), this.eventHandlers, this.pendingActions, this.proxy);
// }
// };
// View.prototype.text = function() {
// if (this.proxy) {
// return (this.proxy.text())
// } else {
// return (this.focused.text());
// }
// };
// View.prototype.updateText = function(s) {
// if (this.proxy) {
// this.proxy.text(s);
// return new View(this.top,
// this.focused,
// this.eventHandlers,
// this.pendingActions.concat([ function(v) { this.focused.text(s); }]),
// this.proxy);
// } else {
// return (this.focused.text());
// }
// };
@ -83,9 +160,10 @@
return onFail(exn); return onFail(exn);
} }
return onSuccess(new View(dom, return onSuccess(new View(dom,
dom,
[], [],
[], [],
[])); undefined));
} else { } else {
try { try {
dom = $(plt.baselib.format.toDomNode(x)) dom = $(plt.baselib.format.toDomNode(x))
@ -93,9 +171,10 @@
return onFail(exn); return onFail(exn);
} }
return onSuccess(new View(dom, return onSuccess(new View(dom,
dom,
[], [],
[], [],
[])); undefined));
} }
}; };
@ -271,14 +350,6 @@
var defaultToDraw = function(world, view, success, fail) {
return success(view);
};
var defaultStopWhen = function(world, success, fail) {
return success(false);
};
var EventQueue = function() { var EventQueue = function() {
@ -304,12 +375,23 @@
var defaultToDraw = function(MACHINE, world, view, success, fail) {
return success(view);
};
var defaultStopWhen = function(MACHINE, world, view, success, fail) {
return success(false);
};
// bigBang. // bigBang.
var bigBang = function(MACHINE, world, handlers) { var bigBang = function(MACHINE, world, handlers) {
var oldArgcount = MACHINE.argcount; var oldArgcount = MACHINE.argcount;
var running = true;
var view = (find(handlers, isInitialViewHandler) || { view : new View(plt.baselib.format.toDomNode(world), var top = $(plt.baselib.format.toDomNode(world));
[], var view = (find(handlers, isInitialViewHandler) || { view : new View(top,
top,
[], [],
[])}).view; [])}).view;
var stopWhen = (find(handlers, isStopWhenHandler) || { stopWhen: defaultStopWhen }).stopWhen; var stopWhen = (find(handlers, isStopWhenHandler) || { stopWhen: defaultStopWhen }).stopWhen;
@ -323,6 +405,7 @@
PAUSE(function(restart) { PAUSE(function(restart) {
var onCleanRestart = function() { var onCleanRestart = function() {
running = false;
var i; var i;
for (i = 0; i < eventHandlers.length; i++) { for (i = 0; i < eventHandlers.length; i++) {
stopEventHandler(eventHandlers[i]); stopEventHandler(eventHandlers[i]);
@ -334,6 +417,7 @@
}; };
var onMessyRestart = function(exn) { var onMessyRestart = function(exn) {
running = false;
var i; var i;
for (i = 0; i < eventHandlers.length; i++) { for (i = 0; i < eventHandlers.length; i++) {
stopEventHandler(eventHandlers[i]); stopEventHandler(eventHandlers[i]);
@ -343,28 +427,43 @@
}); });
}; };
var dispatchEventsInQueue = function() { var dispatchEventsInQueue = function() {
// Apply all the events on the queue, call toDraw, and then stop. // Apply all the events on the queue, call toDraw, and then stop.
// If the world ever satisfies stopWhen, stop immediately and quit. // If the world ever satisfies stopWhen, stop immediately and quit.
var nextEvent; var nextEvent;
var data; var data;
var racketWorldCallback; var racketWorldCallback;
var mockView;
if(! eventQueue.isEmpty() ) { if(! eventQueue.isEmpty() ) {
// Set up the proxy object so we can do what appear to be functional
// queries.
mockView = view.getMock();
nextEvent = eventQueue.dequeue(); nextEvent = eventQueue.dequeue();
// FIXME: deal with event data here // FIXME: deal with event data here
racketWorldCallback = nextEvent.handler.racketWorldCallback; racketWorldCallback = nextEvent.handler.racketWorldCallback;
racketWorldCallback(MACHINE, racketWorldCallback(MACHINE,
world, world,
view, view,
// data, // data,
function(newWorld) { function(newWorld) {
world = newWorld; world = newWorld;
dispatchEventsInQueue();
stopWhen(MACHINE,
world,
view,
function(shouldStop) {
if (shouldStop) {
onCleanRestart();
} else {
dispatchEventsInQueue();
}
},
function(err) {
onMessyRestart(err);
});
}, },
function(err) { function(err) {
onMessyRestart(err); onMessyRestart(err);
@ -377,6 +476,7 @@
var startEventHandler = function(handler) { var startEventHandler = function(handler) {
var fireEvent = function() { var fireEvent = function() {
if (! running) { return; }
var args = [].slice.call(arguments, 0); var args = [].slice.call(arguments, 0);
eventQueue.queue(new EventQueueElement(handler, args)); eventQueue.queue(new EventQueueElement(handler, args));
setTimeout(dispatchEventsInQueue, 0); setTimeout(dispatchEventsInQueue, 0);
@ -444,7 +544,12 @@
'world handler'); 'world handler');
var checkView = plt.baselib.check.makeCheckArgumentType( var checkView = plt.baselib.check.makeCheckArgumentType(
isView, 'view'); isMockView, 'view');
var checkSelector = plt.baselib.check.makeCheckArgumentType(
isString, 'selector');
EXPORTS['big-bang'] = makeClosure( EXPORTS['big-bang'] = makeClosure(
@ -545,9 +650,40 @@
}); });
EXPORTS['view-focus'] = makePrimitiveProcedure(
'view-focus',
2,
function(MACHINE) {
var view = checkView(MACHINE, 'view-focus', 0);
var selector = checkSelector(MACHINE, 'view-focus', 1);
try {
return view.updateFocus(selector);
} catch (e) {
plt.baselib.exceptions.raise(
MACHINE,
new Error(plt.baselib.format.format(
"unable to focus to ~s",
[selector])));
}
});
EXPORTS['view-text'] = makePrimitiveProcedure(
'view-focus',
1,
function(MACHINE) {
var view = checkView(MACHINE, 'view-focus', 0);
return view.getText();
});
EXPORTS['update-view-text'] = makePrimitiveProcedure(
'update-view-text',
2,
function(MACHINE) {
var view = checkView(MACHINE, 'update-view-text', 0);
var text = checkString(MACHINE, 'update-view-text', 1);
return view.updateText(text);
});
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
}()); }());

View File

@ -1,6 +1,7 @@
#lang racket/base #lang racket/base
(provide big-bang initial-view stop-when on-tick to-draw ->view) (provide big-bang initial-view stop-when on-tick to-draw
->view view-focus view-text update-view-text)
(define (big-bang world . handlers) (define (big-bang world . handlers)
(error 'big-bang "Please run in JavaScript context.")) (error 'big-bang "Please run in JavaScript context."))
@ -22,3 +23,14 @@
(define (->view x) (define (->view x)
(error '->view "Please run in JavaScript context.")) (error '->view "Please run in JavaScript context."))
(define (view-focus v selector)
(error 'view-focus "Please run in JavaScript context."))
(define (view-text v)
(error 'view-text "Please run in JavaScript context."))
(define (update-view-text v text)
(error 'update-view-text "Please run in JavaScript context."))