ghclive-0.1.0.1: static/ghclive.js
function wsLocation() {
return window.location.href.replace(/^([a-z]+)\:/i, "ws:");
}
var mainLayout;
var ignoreChange = false;
function handleChange(editor, change) {
if(ignoreChange) { return; }
var msgs = doc.replace(change.from, change.to, change.text);
if(msgs.length > 0) {
sock.send(JSON.stringify({ actions: msgs }));
}
}
function refreshEditor() {
ignoreChange = true;
// fixme: try to preserve cursor position and selection better if other users insert lines etc
var sel = cm.somethingSelected();
var selStart;
var selEnd;
var cursor = cm.getCursor();
if(sel) {
selStart = cm.getCursor(start);
selEnd = cm.getCursor(end);
}
cm.setValue(doc.currentVersion());
cm.setCursor(cursor);
if(sel) {
cm.setSelection(selStart,selEnd);
}
ignoreChange = false;
}
doc = new Document();
cm = CodeMirror.fromTextArea($('#editor')[0],
{ mode: 'text/x-haskell'
, lineWrapping: true
, lineNumbers: true
, fixedGutter: true
, onChange: handleChange
}
);
sock = new WebSocket(wsLocation());
sock.onmessage = function(evt) {
evtJson(evt,function(msg) {
if(msg.time) {
updateTimestamp(msg.time);
}
var refresh = false;
var r;
if(msg.actions) {
for(var i=0;i<msg.actions.length;i++) {
var a = msg.actions[i];
if(a.action === "doc") {
doc.setDocument(a.doc);
refresh = true;
} else if(a.action === "clientid") {
setClientId(a.clientId);
} else if(a.action === "insert") {
r = doc.applyOp(a);
if(r) { refresh = true; }
} else if(a.action === "remove") {
r = doc.applyOp(a);
if(r) { refresh = true; }
}
}
}
if(msg.refreshoutput) {
// refreshOutput();
// alert('need to refresh output');
outputit();
}
if(refresh) {
refreshEditor();
}
});
}
function makeResultSlot(expr) {
var slot = $('<div><span class="prompt">hint></span> <span class="expr">empty expr</span><div class="result">...</div></div>');
slot.find('.expr').text(expr);
return slot;
}
function fillInResultSlot(slot, res) {
var node = slot.find('.result');
if (res.error) {
formatErrors(node, res.error);
} else {
// node.text('');
// node.append(res.result.result);
node.empty();
for(var i=0; i<res.result.length; i++) {
node.append(convertRes(res.result[i]));
}
}
}
function convertRes (res) {
switch(res.t) {
case "svg":
return $(res.r); // fixme add clickable zoom function
case "html":
return $(res.r);
case "text":
var r = $("<span></span>");
r.text(res.r);
return r;
}
}
function formatResult (res) {
var slot = makeResultSlot(res.expr);
fillInResultSlot(slot, res);
return slot;
}
function formatErrors(node, message) {
node.empty();
var lines = message.split("\n");
for (var i = 0; i < lines.length; ++i) {
// console.log('line ' + i + ': ' + lines[i]);
node.append(spacify(lines[i]));
if (lines[i+1])
node.append($('<br>'));
}
}
// Change leading spaces into nbsp entities.
function spacify(line) {
var i;
var result = "";
for (i = 0; i < line.length && line[i] === " "; ++i)
result += " ";
return result + line.substring(i);
}
function scrollToBottom(elem) {
// var elem = document.getElementById(elem);
// elem.scrollTop = elem.scrollHeight;
$(elem).scrollTo('max')
}
function load(success) {
$.get('/loader', function(res) {
if ("" + res === "Main,Helper") {
$("#editormessages").text("");
// $("#editor-messages").hide()
} else if (typeof res === "string") {
formatErrors($("#editormessages"), res);
// $("#editor-messages").show()
} else { // just paranoia
$("#editormessages").text("" + res);
// $("#editor-messages").show()
}
mainLayout.sizeContent("center");
cm.refresh();
if (success) success();
});
}
function outputit(){
$.ajax({
type: "GET",
url: "/results",
success: function(results) {
// clear the output area
$("#output").empty();
// map formatResult over the results
for (var i = 0; i < results.length; i++) {
$("#output").append(formatResult(results[i]));
}
scrollToBottom('#output');
scrollToBottom('.ui-layout-center');
}
}); // end ajax call
return false;
}
$(function () {
// $("#tabs").tabs();
$( "input:submit, button").button();
$(document).ready(function () {
mainLayout = $('body').layout({
name: "main-layout"
, applyDefaultStyles: true
, west: { initHidden: true }
, east: { initHidden: true }
, north: { size: 300 }
, north__onresize: function() { cm.refresh(); }
});
});
function mentionit() {
var slot = $('<div><span class="prompt">hint></span> <span class="expr">:load</span><div class="result"></div></div>');
$("#output").append(slot)
scrollToBottom('#output');
scrollToBottom('.ui-layout-center');
}
$("#load").click(function() {
load();
$("#expr").select();
$("#expr").focus();
mentionit();
return false;
});
function evalit() {
var expr = $("#expr").val();
var slot = makeResultSlot(expr);
$("#output").append(slot);
load(function() {
$.ajax({
type: "GET",
url: "/eval",
data: {expr: expr},
success: function(res) {
// XXX This is probably pointless now that each evaluation
// causes the server to send out a refreshoutput message.
// But maybe it still gets you a result display with lower
// latency (one less round trip, and not rewriting the whole
// output history) so I'm not nuking this yet.
fillInResultSlot(slot, res);
scrollToBottom('#output');
scrollToBottom('.ui-layout-center');
}
});
});
$("#expr").select();
return false;
}
$("#evalform").submit(function(e) {
e.preventDefault();
evalit();
});
$("#evalit").click(evalit);
$("#outputit").click(outputit);
});