define(function(require, exports, module) {
main.consumes = [
"immediate", "debugger", "Evaluator", "callstack", "ui"
];
main.provides = ["immediate.debugnode"];
return main;
function main(options, imports, register) {
var Evaluator = imports.Evaluator;
var debug = imports.debugger;
var immediate = imports.immediate;
var callstack = imports.callstack;
var ui = imports.ui;
var escapeHTML = require("ace/lib/lang").escapeHTML;
/***** Initialization *****/
var plugin = new Evaluator("Ajax.org", main.consumes, {
caption: "Debugger",
id: "debugger",
mode: "ace/mode/javascript", // @todo make this variable: repl.session.setMode
message: "Welcome to the debugger inspector. You can inspect "
+ "any process that the debugger is attached to. Code \nwill be "
+ "executed in the global context unless on "
+ "a breakpoint, then code is executed in the current frame."
});
// var emit = plugin.getEmitter();
var dbg, log, lastCell;
var loaded;
function load() {
if (loaded) return;
loaded = true;
// Set and clear the dbg variable
debug.on("attach", function(e) {
dbg = e.implementation;
if (dbg.attachLog)
initLog(dbg.attachLog());
immediate.defaultEvaluator = "debugger";
});
debug.on("detach", function(e) {
dbg = null;
immediate.defaultEvaluator = null;
});
debug.on("stateChange", function(e) {
plugin[e.action]();
});
}
/***** Log *****/
function writeLog() {
var cell;
var dist = 1;
var type = arguments[arguments.length - dist];
if (type && type.addWidget) {
dist++;
cell = type;
type = arguments[arguments.length - dist];
}
if (!cell)
cell = lastCell;
if (!cell.html)
createWidget(cell);
var html = cell.html.appendChild(document.createElement("div"));
html.className = type;
for (var i = 0; i < arguments.length - dist; i++) {
renderType(arguments[i], html, type != "return");
}
insert(html, "
");
html.updateWidget = updateWidget.bind(cell);
html.updateWidget();
scrollIntoView(cell);
}
function updateWidget() {
this.session.repl.onWidgetChanged(this);
}
function scrollIntoView(cell) {
if (!cell.session.repl.editor)
return;
// TODO add a better way to scroll ace cursor into view when rendered
var renderer = cell.session.repl.editor.renderer;
setTimeout(function() {
renderer.scrollCursorIntoView();
});
}
function initLog(proxy) {
log = proxy;
log.on("log", function(e) {
var args = Array.prototype.slice.apply(arguments);
args.push(e.type);
writeLog.apply(log, args);
}, plugin);
}
function createWidget(cell) {
cell.html = document.createElement("div");
cell.addWidget({ el: cell.html, coverLine: true, fixedWidth: true });
}
/***** Analyzer *****/
function insert(div, markup, name) {
if (name !== undefined)
insert(div, "" + escapeHTML(name) + ": ");
markup = markup.replace(/([a-z]\w{1,4}:\/\/[\w:_\-\?&\/\.\#]*)/gi, "$1");
div.insertAdjacentHTML("beforeend", markup);
if (div.lastChild && div.lastChild.nodeType == 1) {
var nodes = div.lastChild.querySelectorAll("a");
for (var i = 0; i < nodes.length; i++) {
nodes[i].addEventListener("click", function(e) {
//@todo
alert(this.firstChild.nodeValue);
e.stopPropagation();
});
}
}
}
function insertTree(div, caption, object, drawChildren) {
// caption can be a string or an html element
var treeitem = div.appendChild(document.createElement("span"));
var arrow = treeitem.appendChild(document.createElement("span"));
treeitem.className = "treeitem";
arrow.className = "arrow";
treeitem.appendChild(caption);
var container;
treeitem.addEventListener("click", function(e) {
if (container && ui.isChildOf(container, e.target, true))
return;
e.stopPropagation();
if (!container) {
container = treeitem.appendChild(document.createElement("div"));
container.className = "treecontainer";
container.style.display = "none";
drawChildren(object, container, function() {
findWidgetAndUpdate(target);
});
}
var collapsed = container.style.display == "none";
arrow.className = "arrow " + (collapsed ? "expanded" : "");
container.style.display = collapsed ? "block" : "none";
// hack!
var target = e.currentTarget;
findWidgetAndUpdate(target);
});
}
function findWidgetAndUpdate(target) {
while (target) {
if (target.updateWidget) {
target.updateWidget();
break;
}
target = target.parentNode;
}
}
function parseChildren(object, html, callback) {
if (object.value == "[Array]") {
if (object.length < 101) {
object.forEach(function(item, i) {
renderType(item, html, 2, false, i);
insert(html, "
");
});
}
else {
}
}
else if (object.$arrayWalker) {
}
else if (object instanceof Error) {
var stack = (object.stack || "").split("\n");
stack.shift();
stack = stack.join("
");
insert(html, "