Merge branch 'master' into dom
Conflicts: web-world/js-impl.js
This commit is contained in:
commit
d19e8562ac
|
@ -121,7 +121,7 @@
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p !== Empty.EMPTY) {
|
if (p !== EMPTY) {
|
||||||
texts.push('.');
|
texts.push('.');
|
||||||
texts.push(baselib.format.toDisplayedString(p, cache));
|
texts.push(baselib.format.toDisplayedString(p, cache));
|
||||||
}
|
}
|
||||||
|
@ -138,14 +138,14 @@
|
||||||
while (p instanceof Cons) {
|
while (p instanceof Cons) {
|
||||||
node.appendChild(baselib.format.toDomNode(p.first, cache));
|
node.appendChild(baselib.format.toDomNode(p.first, cache));
|
||||||
p = p.rest;
|
p = p.rest;
|
||||||
if (p !== Empty.EMPTY) {
|
if (p !== EMPTY) {
|
||||||
node.appendChild(document.createTextNode(" "));
|
node.appendChild(document.createTextNode(" "));
|
||||||
}
|
}
|
||||||
if (typeof (p) === 'object' && cache.containsKey(p)) {
|
if (typeof (p) === 'object' && cache.containsKey(p)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p !== Empty.EMPTY) {
|
if (p !== EMPTY) {
|
||||||
node.appendChild(document.createTextNode("."));
|
node.appendChild(document.createTextNode("."));
|
||||||
node.appendChild(document.createTextNode(" "));
|
node.appendChild(document.createTextNode(" "));
|
||||||
node.appendChild(baselib.format.toDomNode(p, cache));
|
node.appendChild(baselib.format.toDomNode(p, cache));
|
||||||
|
@ -157,13 +157,13 @@
|
||||||
|
|
||||||
|
|
||||||
var isPair = function (x) { return x instanceof Cons; };
|
var isPair = function (x) { return x instanceof Cons; };
|
||||||
var isEmpty = function (x) { return x === Empty.EMPTY; };
|
var isEmpty = function (x) { return x === EMPTY; };
|
||||||
|
|
||||||
|
|
||||||
var makePair = Cons.makeInstance;
|
var makePair = Cons.makeInstance;
|
||||||
|
|
||||||
var makeList = function () {
|
var makeList = function () {
|
||||||
var result = Empty.EMPTY, i;
|
var result = EMPTY, i;
|
||||||
for (i = arguments.length - 1; i >= 0; i--) {
|
for (i = arguments.length - 1; i >= 0; i--) {
|
||||||
result = Cons.makeInstance(arguments[i], result);
|
result = Cons.makeInstance(arguments[i], result);
|
||||||
}
|
}
|
||||||
|
@ -171,10 +171,21 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Coerse a list back into a JavaScript array.
|
||||||
|
var listToArray = function(lst) {
|
||||||
|
var result = [];
|
||||||
|
while (lst !== EMPTY) {
|
||||||
|
result.push(lst.first);
|
||||||
|
lst = lst.rest;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// isList: Any -> Boolean
|
// isList: Any -> Boolean
|
||||||
// Returns true if x is a list (a chain of pairs terminated by EMPTY).
|
// Returns true if x is a list (a chain of pairs terminated by EMPTY).
|
||||||
var isList = function (x) {
|
var isList = function (x) {
|
||||||
while (x !== Empty.EMPTY) {
|
while (x !== EMPTY) {
|
||||||
if (x instanceof Cons) {
|
if (x instanceof Cons) {
|
||||||
x = x.rest;
|
x = x.rest;
|
||||||
} else {
|
} else {
|
||||||
|
@ -229,6 +240,6 @@
|
||||||
exports.reverse = reverse;
|
exports.reverse = reverse;
|
||||||
exports.length = length;
|
exports.length = length;
|
||||||
exports.listRef = listRef;
|
exports.listRef = listRef;
|
||||||
|
exports.listToArray = listToArray;
|
||||||
|
|
||||||
}(this.plt.baselib));
|
}(this.plt.baselib));
|
|
@ -363,7 +363,7 @@
|
||||||
var marks = frame.marks;
|
var marks = frame.marks;
|
||||||
var i;
|
var i;
|
||||||
for (i = 0; i < marks.length; i++) {
|
for (i = 0; i < marks.length; i++) {
|
||||||
if (equals(key, marks[i][0])) {
|
if (key === marks[i][0]) {
|
||||||
marks[i][1] = value;
|
marks[i][1] = value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,6 +151,13 @@ $ planet link dyoo whalesong.plt 1 0 whalesong
|
||||||
than the latest version that's on PLaneT at the time.)
|
than the latest version that's on PLaneT at the time.)
|
||||||
|
|
||||||
|
|
||||||
|
Let's make the @filepath{whalesong} launcher somewhere appropriate. Run Racket with the following
|
||||||
|
@racket[require]:
|
||||||
|
@racketblock[
|
||||||
|
(require (planet dyoo/whalesong/make-launcher))
|
||||||
|
]
|
||||||
|
This will create a @filepath{whalesong} executable in the current working directory.
|
||||||
|
|
||||||
|
|
||||||
Finally, we need to set up Whalesong with @tt{raco setup}.
|
Finally, we need to set up Whalesong with @tt{raco setup}.
|
||||||
Here's how to do this at the command
|
Here's how to do this at the command
|
||||||
|
@ -158,24 +165,30 @@ line:
|
||||||
@verbatim|{
|
@verbatim|{
|
||||||
$ raco setup -P dyoo whalesong.plt 1 0
|
$ raco setup -P dyoo whalesong.plt 1 0
|
||||||
}|
|
}|
|
||||||
This should compile Whalesong, as well as set up the @filepath{whalesong} executable.
|
This should compile Whalesong. Any time the source code in
|
||||||
Any time the source code in @filepath{whalesong} changes, we should repeat
|
@filepath{whalesong} changes, we should repeat this @tt{raco setup}
|
||||||
this @tt{raco setup} step again.
|
step again.
|
||||||
|
|
||||||
|
|
||||||
At this point, you should be able to rung @filepath{whalesong} from the command line.
|
At this point, you should be able to run the @filepath{whalesong} executable from the command line.
|
||||||
@verbatim|{
|
@verbatim|{
|
||||||
$ ./whalesong
|
$ ./whalesong
|
||||||
Expected one of the following: [build, get-runtime, get-javascript].
|
Usage: whalesong <subcommand> [option ...] <arg ...>
|
||||||
|
where any unambiguous prefix can be used for a subcommand
|
||||||
|
|
||||||
|
The Whalesong command-line tool for compiling Racket to JavaScript
|
||||||
|
|
||||||
|
For help on a particular subcommand, use 'whalesong <subcommand> --help'
|
||||||
|
whalesong build build a standalone html and javascript package
|
||||||
|
whalesong get-runtime print the runtime library to standard output
|
||||||
|
whalesong get-javascript Gets just the JavaScript code and prints it to standard output
|
||||||
}|
|
}|
|
||||||
and if this does appear, then Whalesong should be installed successfully.
|
and if this does appear, then Whalesong should be installed successfully.
|
||||||
|
|
||||||
|
|
||||||
Note: whenever Whalesong's source code is updated from Github, please
|
To repeat: whenever Whalesong's source code is updated from Github,
|
||||||
re-run the @tt{raco setup}. Otherwise, Racket will try to recompile
|
please re-run the @tt{raco setup} step. Otherwise, Racket will try to
|
||||||
Whalesong on every single use of Whalesong, which can be very
|
recompile Whalesong on every single use, which can be very expensive.
|
||||||
expensive.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
3
tests/more-tests/view.expected
Normal file
3
tests/more-tests/view.expected
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
""
|
||||||
|
"some text"
|
||||||
|
(html (head) (body (p "hello world, this is a test") (div (@ (id "a div")) "some text")))
|
21
tests/more-tests/view.rkt
Normal file
21
tests/more-tests/view.rkt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#lang planet dyoo/whalesong
|
||||||
|
|
||||||
|
(require (planet dyoo/whalesong/web-world))
|
||||||
|
|
||||||
|
(define view (->view (xexp->dom `(html (head)
|
||||||
|
(body (p "hello world, this is a test")
|
||||||
|
(div (@ (id "a div"))))))))
|
||||||
|
(define new-view
|
||||||
|
(view-focus view "a div"))
|
||||||
|
|
||||||
|
(view-text new-view) ;; should be ""
|
||||||
|
|
||||||
|
(define updated-new-view
|
||||||
|
(update-view-text new-view "some text"))
|
||||||
|
|
||||||
|
(view-text updated-new-view) ;; should be "some text"
|
||||||
|
|
||||||
|
(view->xexp (view-up (view-up updated-new-view)))
|
||||||
|
;; should be:
|
||||||
|
; (html (head) (body (p "hello world, this is a test")
|
||||||
|
; (div (@ (id "a div")) "some text")))
|
|
@ -26,3 +26,4 @@
|
||||||
(test "more-tests/hello-bf.rkt")
|
(test "more-tests/hello-bf.rkt")
|
||||||
(test "more-tests/conform.rkt")
|
(test "more-tests/conform.rkt")
|
||||||
(test "more-tests/earley.rkt")
|
(test "more-tests/earley.rkt")
|
||||||
|
(test "more-tests/view.rkt")
|
||||||
|
|
|
@ -74,4 +74,6 @@
|
||||||
xexp?
|
xexp?
|
||||||
xexp->dom
|
xexp->dom
|
||||||
|
|
||||||
|
view->xexp
|
||||||
|
|
||||||
))
|
))
|
||||||
|
|
|
@ -124,6 +124,8 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var EMPTY_PENDING_ACTIONS = plt.baselib.lists.EMPTY;
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// A MockView provides a functional interface to the DOM. It
|
// A MockView provides a functional interface to the DOM. It
|
||||||
|
@ -132,17 +134,29 @@
|
||||||
// freshness of the MockView.
|
// freshness of the MockView.
|
||||||
var MockView = function(cursor, pendingActions, eventHandlers, nonce) {
|
var MockView = function(cursor, pendingActions, eventHandlers, nonce) {
|
||||||
this.cursor = cursor;
|
this.cursor = cursor;
|
||||||
|
|
||||||
|
// (listof (view -> void))
|
||||||
this.pendingActions = pendingActions;
|
this.pendingActions = pendingActions;
|
||||||
|
|
||||||
this.eventHandlers = eventHandlers;
|
this.eventHandlers = eventHandlers;
|
||||||
this.nonce = nonce;
|
this.nonce = nonce;
|
||||||
};
|
};
|
||||||
|
|
||||||
var isMockView = plt.baselib.makeClassPredicate(MockView);
|
var isMockView = plt.baselib.makeClassPredicate(MockView);
|
||||||
|
|
||||||
|
MockView.prototype.toString = function() {
|
||||||
|
return "<#view>";
|
||||||
|
};
|
||||||
|
|
||||||
|
MockView.prototype.getPendingActions = function() {
|
||||||
|
return plt.baselib.lists.listToArray(this.pendingActions).reverse();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
MockView.prototype.act = function(actionForCursor, actionForEventHandlers, actionForReal) {
|
MockView.prototype.act = function(actionForCursor, actionForEventHandlers, actionForReal) {
|
||||||
if (arguments.length !== 3) { throw new Error("act: insufficient arguments"); }
|
if (arguments.length !== 3) { throw new Error("act: insufficient arguments"); }
|
||||||
return new MockView(actionForCursor(this.cursor),
|
return new MockView(actionForCursor(this.cursor),
|
||||||
this.pendingActions.concat([actionForReal]),
|
plt.baselib.lists.makePair(actionForReal, this.pendingActions),
|
||||||
actionForEventHandlers(this.eventHandlers),
|
actionForEventHandlers(this.eventHandlers),
|
||||||
this.nonce);
|
this.nonce);
|
||||||
};
|
};
|
||||||
|
@ -488,8 +502,9 @@
|
||||||
|
|
||||||
View.prototype.getMockAndResetFocus = function(nonce) {
|
View.prototype.getMockAndResetFocus = function(nonce) {
|
||||||
this.focus = this.top;
|
this.focus = this.top;
|
||||||
|
|
||||||
return new MockView(domToArrayTreeCursor($(this.top).get(0)),
|
return new MockView(domToArrayTreeCursor($(this.top).get(0)),
|
||||||
[],
|
EMPTY_PENDING_ACTIONS,
|
||||||
this.eventHandlers.slice(0),
|
this.eventHandlers.slice(0),
|
||||||
nonce);
|
nonce);
|
||||||
};
|
};
|
||||||
|
@ -560,14 +575,14 @@
|
||||||
} catch (exn1) {
|
} catch (exn1) {
|
||||||
return onFail(exn1);
|
return onFail(exn1);
|
||||||
}
|
}
|
||||||
return onSuccess(new MockView(domToArrayTreeCursor(dom.get(0)), [], [], undefined));
|
return onSuccess(new MockView(domToArrayTreeCursor(dom.get(0)), EMPTY_PENDING_ACTIONS, [], undefined));
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
dom = $(plt.baselib.format.toDomNode(x));
|
dom = $(plt.baselib.format.toDomNode(x));
|
||||||
} catch (exn2) {
|
} catch (exn2) {
|
||||||
return onFail(exn2);
|
return onFail(exn2);
|
||||||
}
|
}
|
||||||
return onSuccess(new MockView(domToArrayTreeCursor(dom.get(0)), [], [], undefined));
|
return onSuccess(new MockView(domToArrayTreeCursor(dom.get(0)), EMPTY_PENDING_ACTIONS, [], undefined));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1123,7 +1138,7 @@
|
||||||
function(newMockView) {
|
function(newMockView) {
|
||||||
if (newMockView.nonce === nonce) {
|
if (newMockView.nonce === nonce) {
|
||||||
var i;
|
var i;
|
||||||
var actions = newMockView.pendingActions;
|
var actions = newMockView.getPendingActions();
|
||||||
for (i = 0; i < actions.length; i++) {
|
for (i = 0; i < actions.length; i++) {
|
||||||
actions[i](view);
|
actions[i](view);
|
||||||
}
|
}
|
||||||
|
@ -1309,6 +1324,61 @@
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var domToXexp = function(dom) {
|
||||||
|
var child, attrs, name, convertedChildren, i;
|
||||||
|
if (dom.nodeType === 1) {
|
||||||
|
attrs = plt.baselib.lists.EMPTY;
|
||||||
|
name = plt.baselib.symbols.makeSymbol(dom.nodeName.toLowerCase());
|
||||||
|
child = dom.firstChild;
|
||||||
|
convertedChildren = plt.baselib.lists.EMPTY;
|
||||||
|
|
||||||
|
for (i = 0; i < dom.attributes.length; i++) {
|
||||||
|
attrs = plt.baselib.lists.makePair(
|
||||||
|
plt.baselib.lists.makeList(plt.baselib.symbols.makeSymbol(dom.attributes[i].nodeName),
|
||||||
|
dom.attributes[i].nodeValue),
|
||||||
|
attrs);
|
||||||
|
}
|
||||||
|
while(child !== null) {
|
||||||
|
if (child.nodeType === 1) {
|
||||||
|
convertedChildren =
|
||||||
|
plt.baselib.lists.makePair(
|
||||||
|
domToXexp(child),
|
||||||
|
convertedChildren);
|
||||||
|
} else if (child.nodeType === 3) {
|
||||||
|
convertedChildren = plt.baselib.lists.makePair(
|
||||||
|
domToXexp(child),
|
||||||
|
convertedChildren);
|
||||||
|
}
|
||||||
|
// Ignore other types.
|
||||||
|
child = child.nextSibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs === plt.baselib.lists.EMPTY) {
|
||||||
|
return plt.baselib.lists.makePair(
|
||||||
|
name,
|
||||||
|
plt.baselib.lists.reverse(convertedChildren));
|
||||||
|
} else {
|
||||||
|
return plt.baselib.lists.makePair(
|
||||||
|
name,
|
||||||
|
plt.baselib.lists.makePair(
|
||||||
|
plt.baselib.lists.makePair(plt.baselib.symbols.makeSymbol("@"),
|
||||||
|
attrs),
|
||||||
|
plt.baselib.lists.reverse(convertedChildren)));
|
||||||
|
}
|
||||||
|
} else if (dom.nodeType === 3) {
|
||||||
|
return dom.nodeValue;
|
||||||
|
} else {
|
||||||
|
// If we can't convert it, return false.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1761,5 +1831,15 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
EXPORTS['view->xexp'] = makePrimitiveProcedure(
|
||||||
|
'view->xexp',
|
||||||
|
1,
|
||||||
|
function(MACHINE) {
|
||||||
|
var mockView = checkMockView(MACHINE, 'view-hide', 0);
|
||||||
|
var domNode = arrayTreeToDomNode(mockView.cursor.top().node);
|
||||||
|
return domToXexp(domNode);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
}());
|
}());
|
|
@ -28,7 +28,9 @@
|
||||||
open-output-element
|
open-output-element
|
||||||
|
|
||||||
xexp?
|
xexp?
|
||||||
xexp->dom)
|
xexp->dom
|
||||||
|
view->xexp
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
(define (big-bang world . handlers)
|
(define (big-bang world . handlers)
|
||||||
|
@ -169,3 +171,7 @@
|
||||||
|
|
||||||
(define (xexp->dom x)
|
(define (xexp->dom x)
|
||||||
(error 'xexp->dom "Please run in JavaScript context."))
|
(error 'xexp->dom "Please run in JavaScript context."))
|
||||||
|
|
||||||
|
|
||||||
|
(define (view->xexp x)
|
||||||
|
(error 'view->xexp "Please run in JavaScript context."))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user