JavaScript DHTML/Mochkit/InterpreterManager — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
Admin (обсуждение | вклад) м (1 версия) |
(нет различий)
|
Текущая версия на 07:25, 26 мая 2010
Interpreter - JavaScript Interactive Interpreter
<!--
MochiKit is dual-licensed software. It is available under the terms of the
MIT License, or the Academic Free License version 2.1. The full text of
each license is included below.
-->
<!-- Code revised from MochiKit demo code -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Interpreter - JavaScript Interactive Interpreter</title>
<style type="text/css">
h1 {
font-size: 2em;
color: #4B4545;
text-align: center;
}
textarea.textbox {
font-family: Monaco, "lucida console", Courier;
border: 1px solid #CCCCCC;
font-size: .60em;
padding: 2px 4px;
margin-top: .3em;
}
input.textbox {
font-family: Monaco, "lucida console", Courier;
border: 1px solid #CCCCCC;
font-size: .60em;
padding: 2px 4px;
margin-top: .3em;
}
#interpreter_area {
display: block;
border: 1px solid #CCCCCC;
padding: 2px 4px;
margin-top: .3em;
width: 600px;
height: 300px;
overflow: auto;
}
#interpreter_output {
display: inline;
font-family: Monaco, "lucida console", Courier;
font-size: .60em;
}
#interpreter_output span {
white-space: -moz-pre-wrap; /* Mozilla */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS 2.1 */
white-space: pre-line; /* CSS 3 (and 2.1 as well, actually) */
word-wrap: break-word; /* IE */
wrap-option: emergency; /* CSS 3 */
}
input.textbox:focus { background-color: #FFFEE3; }
.code { color: blue; }
.data { color: black; }
.error { color: red; }
.banner { color: green; }
.invisible { display: none; }
</style>
<script type="text/javascript" src="MochiKit-1.4.2/lib/MochiKit/MochiKit.js"></script>
<script type="text/javascript">
/*
Interpreter: JavaScript Interactive Interpreter
*/
InterpreterManager = function () {
bindMethods(this);
};
InterpreterManager.prototype.initialize = function () {
connect("interpreter_text", "onkeyup", this.keyUp);
connect("interpreter_textarea", "onkeydown", this.areaKeyDown);
connect("interpreter_form", "onsubmit", this.submit);
getElement("interpreter_text").focus();
this.banner();
this.lines = [];
this.history = [];
this.currentHistory = "";
this.historyPos = -1;
this.blockingOn = null;
if (typeof(this.doEval) == "undefined") {
// detect broken eval, warn at some point if a namespace ever gets used
this.doEval = function () {
return eval(arguments[0]);
}
}
window.help = this.help;
this.help.NAME = "type help(func) for help on a MochiKit function";
};
InterpreterManager.prototype.banner = function () {
var _ua = window.navigator.userAgent;
var ua = _ua.replace(/^Mozilla\/.*?\(.*?\)\s*/, "");
if (ua == "") {
// MSIE
ua = _ua.replace(/^Mozilla\/4\.0 \(compatible; MS(IE .*?);.*$/, "$1");
}
appendChildNodes("interpreter_output",
SPAN({"class": "banner"},
"MochiKit v" + MochiKit.Base.VERSION + " [" + ua + "]",
BR(),
"Type your expression in the input box below and press return, or see the notes below for more information.",
BR()
),
BR()
);
};
InterpreterManager.prototype.submit = function (event) {
if (this.blockingOn) {
try {
this.blockingOn.cancel();
} catch (e) {
this.showError(e);
}
this.blockingOn = null;
}
this.doSubmit();
this.doScroll();
event.stop();
};
InterpreterManager.prototype.help = function (fn) {
if (fn && fn.NAME) {
fn = fn.NAME;
}
if (typeof(fn) != "string" || fn.length == 0) {
writeln("help(func) on any MochiKit function for help");
return;
}
var comps = fn.split(".");
var base = comps.splice(0, 2);
var shortfn = comps.join(".");
var url = "../../doc/html/" + base.join("/") + ".html";
var d = doXHR(url, {mimeType: "text/xml"});
d.addCallback(function (req) {
var els = getElementsByTagAndClassName(
"a", "mochidef", req.responseXML);
var match = "#fn-" + shortfn.toLowerCase();
for (var i = 0; i < els.length; i++) {
var elem = els[i];
var href = elem.href;
var idx = href.indexOf("#");
if (idx != -1 && href.substring(idx) == match) {
writeln(A({href: url + match, target: "_blank"},
scrapeText(elem)));
return;
}
}
writeln("documentation for " + fn + " not found");
});
blockOn(d);
};
InterpreterManager.prototype.doScroll = function () {
var p = getElement("interpreter_output").lastChild;
if (typeof(p) == "undefined" || p == null) {
return;
}
var area = getElement("interpreter_area");
if (area.offsetHeight > area.scrollHeight) {
area.scrollTop = 0;
} else {
area.scrollTop = area.scrollHeight;
}
};
InterpreterManager.prototype.moveHistory = function (dir) {
// totally bogus value
if (dir == 0 || this.history.length == 0) {
return;
}
var elem = getElement("interpreter_text");
if (this.historyPos == -1) {
this.currentHistory = elem.value;
if (dir > 0) {
return;
}
this.historyPos = this.history.length - 1;
elem.value = this.history[this.historyPos];
return;
}
if (this.historyPos == 0 && dir < 0) {
return;
}
if (this.historyPos == this.history.length - 1 && dir > 0) {
this.historyPos = -1;
elem.value = this.currentHistory;
return;
}
this.historyPos += dir;
elem.value = this.history[this.historyPos];
}
InterpreterManager.prototype.runMultipleLines = function (text) {
var lines = rstrip(text).replace("\r\n", "\n").split(/\n/);
appendChildNodes("interpreter_output",
SPAN({"class": "code"}, ">>> ", izip(lines, imap(BR, cycle([null]))))
);
this.runCode(text);
}
InterpreterManager.prototype.areaKeyDown = function (e) {
var mod = e.modifier();
var hasMod = mod.alt || mod.ctrl || mod.meta;
if (e.key().string == "KEY_ENTER" && hasMod) {
var elem = getElement("interpreter_textarea");
var text = elem.value;
elem.value = "";
this.runMultipleLines(text);
e.stop();
}
};
InterpreterManager.prototype.keyUp = function (e) {
var key = e.key();
// if any meta key is pressed, don"t handle the signal
if (e.modifier().any) {
return;
}
switch (key.string) {
case "KEY_ARROW_UP": this.moveHistory(-1); break;
case "KEY_ARROW_DOWN": this.moveHistory(1); break;
default: return;
}
e.stop();
};
InterpreterManager.prototype.blockOn = function (d) {
var node = SPAN({"class": "banner"}, "blocking on " + repr(d) + "...");
this.blockingOn = d;
appendChildNodes("interpreter_output", node);
this.doScroll();
d.addBoth(function (res) {
swapDOM(node);
this.blockingOn = null;
if (res instanceof CancelledError) {
window.writeln(SPAN({"class": "error"}, repr(d) + " cancelled!"));
return undefined;
}
return res;
});
d.addCallbacks(this.showResult, this.showError);
};
InterpreterManager.prototype.showError = function (e) {
if (typeof(e) != "object") {
e = new Error(e);
}
appendChildNodes("interpreter_output",
SPAN({"class": "error"}, "Error:"),
TABLE({"class": "error"},
THEAD({"class": "invisible"}, TD({"colspan": 2})),
TFOOT({"class": "invisible"}, TD({"colspan": 2})),
TBODY(null,
map(function (kv) {
var v = kv[1];
if (typeof(v) == "function") {
return;
}
if (typeof(v) == "object") {
v = repr(v);
}
return TR(null,
TD({"class": "error"}, kv[0]),
TD({"class": "data"}, v)
);
}, sorted(items(e)))
)
)
);
window.last_exc = e;
this.doScroll();
};
EvalFunctions = {
evalWith: function () {
with (arguments[1] || window) { return eval(arguments[0]); };
},
evalCall: function () {
return eval.call(arguments[1] || window, arguments[0]);
},
choose: function () {
var ns = {__test__: this};
var e;
try {
if (this.evalWith("return __test__", ns) === this) {
return this.evalWith;
}
} catch (e) {
// pass
}
try {
if (this.evalCall("return __test__", ns) === this) {
return this.evalCall;
}
} catch (e) {
// pass
}
return undefined;
}
};
InterpreterManager.prototype.doEval = EvalFunctions.choose();
InterpreterManager.prototype.doSubmit = function () {
var elem = getElement("interpreter_text");
var code = elem.value;
elem.value = "";
var isContinuation = false;
if (code.length >= 2 && code.lastIndexOf("//") == code.length - 2) {
isContinuation = true;
code = code.substr(0, code.length - 2);
}
appendChildNodes("interpreter_output",
SPAN({"class": "code"}, ">>> ", code),
BR()
);
this.lines.push(code);
this.history.push(code);
this.historyPos = -1;
this.currentHistory = "";
if (isContinuation) {
return;
}
var allCode = this.lines.join("\n");
this.lines = [];
this.runCode(allCode);
return;
};
InterpreterManager.prototype.runCode = function (allCode) {
var res;
try {
res = this.doEval(allCode);
} catch (e) {
// mozilla shows some keys more than once!
this.showError(e);
return;
}
this.showResult(res);
};
InterpreterManager.prototype.showResult = function (res) {
if (typeof(res) != "undefined") {
window._ = res;
}
if (typeof(res) != "undefined") {
appendChildNodes("interpreter_output",
SPAN({"class": "data"}, repr(res)),
BR()
);
this.doScroll();
}
};
window.writeln = function () {
appendChildNodes("interpreter_output",
SPAN({"class": "data"}, arguments),
BR()
);
interpreterManager.doScroll();
};
window.clear = function () {
replaceChildNodes("interpreter_output");
getElement("interpreter_area").scrollTop = 0;
};
window.blockOn = function (d) {
if (!(d instanceof Deferred)) {
throw new TypeError(repr(d) + " is not a Deferred!");
}
interpreterManager.blockOn(d);
};
window.dir = function (o) {
// Python muscle memory!
return sorted(keys(o));
};
window.inspect = function (o) {
window._ = o;
if ((typeof(o) != "function" && typeof(o) != "object") || o == null) {
window.writeln(repr(o));
return;
}
var pairs = items(o);
if (pairs.length == 0) {
window.writeln(repr(o));
return;
}
window.writeln(TABLE({"border": "1"},
THEAD({"class": "invisible"}, TR(null, TD(), TD())),
TFOOT({"class": "invisible"}, TR(null, TD(), TD())),
TBODY(null,
map(
function (kv) {
var click = function () {
try {
window.inspect(kv[1]);
} catch (e) {
interpreterManager.showError(e);
}
return false;
}
return TR(null,
TD(null, A({href: "#", onclick: click}, kv[0])),
TD(null, repr(kv[1]))
);
},
pairs
)
)
));
};
interpreterManager = new InterpreterManager();
addLoadEvent(interpreterManager.initialize);
// rewrite the view-source links
addLoadEvent(function () {
var elems = getElementsByTagAndClassName("A", "view-source");
var page = "interpreter/";
for (var i = 0; i < elems.length; i++) {
var elem = elems[i];
var href = elem.href.split(/\//).pop();
elem.target = "_blank";
elem.href = "../view-source/view-source.html#" + page + href;
}
});
</script>
</head>
<body>
<h1>
Interpreter - JavaScript Interactive Interpreter
</h1>
<div>
<p>
This demo is a JavaScript interpreter. Type some code into
the text input and press enter to see the results. It uses
<a href="http://mochikit.ru">MochiKit</a>"s
<a href="../../doc/html/lib/MochiKit/DOM.html">MochiKit.DOM</a>
to manipulate the display. It also supports waiting for
<a href="../../doc/html/lib/MochiKit/Async.html">MochiKit.Async</a>
Deferreds via <tt>blockOn(aDeferred)</tt>.
</p>
</div>
<div>
View Source: [
<a href="index.html" class="view-source">index.html</a> |
<a href="interpreter.js" class="view-source">interpreter.js</a>
]
</div>
<form id="interpreter_form" autocomplete="off">
<div id="interpreter_area">
<div id="interpreter_output"></div>
</div>
<div id="oneline">
<input id="interpreter_text" name="input_text" type="text" class="textbox" size="100" />
</div>
<div id="multiline">
<textarea id="interpreter_textarea" name="input_textarea" type="text" class="textbox" cols="97" rows="10"></textarea>
<br />
</div>
</form>
<div>
Notes:
<ul>
<li>
To show the signature of a MochiKit function and link
to its documentation, type help(fn) on any MochiKit
function.
</li>
<li>
To write multi-line code snippets, use the lower text area
and press ctrl-enter or cmd-enter to submit.
</li>
<li>
<tt>function name() {}</tt> syntax might not end up in
window scope, so use <tt>name = function () {}</tt>
syntax instead
</li>
<li>
If you want to stuff something into the output window
other than the <tt>repr(...)</tt> of the expression
result, use the <tt>writeln(...)</tt> function.
It accepts anything that MochiKit.DOM does, so you can
even put styled stuff in there!
</li>
<li>
Use <tt>clear()</tt> to clear the interpreter window.
</li>
<li>
You can use <tt>blockOn(aDeferred)</tt> to wait on a
Deferred. This expression must be used by itself, so
the value must be obtained from <tt>_</tt> or
<tt>last_exc</tt>. Typing any expression will
cancel the Deferred.
</li>
<li>
Up and down arrow keys work as a rudimentary history
</li>
<li>
<tt>_</tt> is the value of the last expression
that was not <tt>undefined</tt>, <tt>last_exc</tt> is
the value of the last unhandled exception.
</li>
</ul>
</div>
</body>
</html>