///////////////////////////////////////////////////////////////////
// An AJAX framework for connections back to the
// SAGE server (written by Tom Boothby).
///////////////////////////////////////////////////////////////////
//globals
var async_oblist = [null,null,null,null,null];
var async_idstack= [0,1,2,3,4];
function getAsyncObject(handler) {
var asyncObj;
try {
if (browser_ie) {
var s =browser_ie5?"Microsoft.XMLHTTP":"Msxml2.XMLHTTP";
asyncObj = new ActiveXObject(s);
asyncObj.onreadystatechange = handler;
return asyncObj;
} else {
asyncObj = new XMLHttpRequest();
asyncObj.onload = handler;
asyncObj.onerror = handler;
return asyncObj;
}
} catch(e) {
no_async = true;
return null;
}
}
function generic_callback(status, response_text) {
/* do nothing */
}
function asyncCallbackHandler(id) {
return eval("function() { async_callback("+id+"); }");
}
function async_callback(id) {
var asyncObj = async_oblist[id][0];
var callback = async_oblist[id][1];
try {
if( (asyncObj.readyState==4 || asyncObj.readyState=="complete")
&& asyncObj.status == 200 )
try {
callback('success', asyncObj.responseText);
async_release(id); //don't release the id until we've tried to capture output
} catch(e) {
async_release(id); //release immediately in case exception was in the callback
callback('success', "empty");
}
} catch(e) {
async_release(id); //release immediately
callback("failure", e);
}
}
function async_request(url, callback, postvars) {
var id = async_id();
var f = asyncCallbackHandler(id);
var asyncObj = getAsyncObject(f);
async_oblist[id] = [asyncObj,callback];
if(postvars != null) {
asyncObj.open('POST',url,true);
asyncObj.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
asyncObj.send(postvars);
} else {
asyncObj.open('GET',url,true);
asyncObj.setRequestHeader('Content-Type', "text/html");
asyncObj.send(null);
}
}
function async_id() {
if(async_idstack.length == 0) {
id = async_oblist.length;
async_oblist.push(null);
} else {
id = async_idstack.pop();
}
return id
}
function async_release(id) {
async_oblist[id] = null;
async_idstack.push(id);
if(async_idstack.length == async_oblist.length && async_oblist.length > 10) {
async_oblist = [null,null,null,null,null];
async_idstack= [0,1,2,3,4];
}
}
///////////////////////////////////////////////////////////////////
//
// GLOBAL VARIABLES
//
// PLEASE define all global variables up here, and if you want to
// set them with anything but simple assignment, 'var' them first,
// and set them later. Your code might work in your browser, but
// it might break initial setup for other critical pieces in other
// browsers. Thanks. (and for the record, I'm guilty of this more
// than anybody else here -- I figure a big block comment might
// help keep me in check)
//
// Exception: keyboard globals are defined at the end
//
///////////////////////////////////////////////////////////////////
// The active cell list.
var active_cell_list = [];
//Browser & OS identification
var browser_op, browser_saf, browser_konq, browser_moz, browser_ie, browser_ie5;
var os_mac, os_lin, os_win;
var update_error_count = 0;
var update_error_threshold = 30;
// in milliseconds
var update_error_delta = 1000;
var update_normal_delta = 256;
var cell_output_delta = update_normal_delta;
var SEP = '___S_A_G_E___'; // this had better be the same as in the server
var current_cell = -1; // gets set on focus / blur
var no_async = false; //this isn't really used -- should we think about dealing with this?
// introspection variables
var introspection_loaded = false;
var introspect_id;
var introspection_text = "";
var replacement_text = "";
var replacement_row = 0;
var replacement_col = 0;
var replacing_word = "";
var replacement_word = "";
var replacing = false;
var sub_introspecting = false;
// Info about the current worksheet. These get set in notebook.py
var worksheet_id=0;
var worksheet_filename='';
var worksheet_name='';
//regular expressions used to peek into the cell input for introspection
var non_word = "[^a-zA-Z0-9_]"; //finds any character that doesn't belong in a variable name
var command_pat = "([a-zA-Z_][a-zA-Z._0-9]*)$"; //identifies the command at the end of a string
var function_pat = "([a-zA-Z_][a-zA-Z._0-9]*)\\([^()]*$";
var one_word_pat = "([a-zA-Z_][a-zA-Z._0-9]*)";
try{
non_word = new RegExp(non_word);
command_pat = new RegExp(command_pat);
function_pat = new RegExp(function_pat);
one_word_pat = new RegExp(one_word_pat);
} catch(e){}
var after_cursor, before_cursor, before_replacing_word;
var update_timeout = -1;
var updating = false; var update_time = -1;
var jsmath_font_msg = 'jsMath temporarily disabled while we resolve a windows firefox hang bug '; /*var jsmath_font_msg = 'Click to download and install tex fonts. '; */
var cell_id_list; // this gets set in worksheet.py
var input_keypress; //this gets set to a function when we set up the keyboards
var in_slide_mode = false; //whether or not we're in slideshow mode
var slide_hidden = false; //whether the current slide has the hidden input class
var worksheet_locked;
///////////////////////////////////////////////////////////////////
//
// Cross-Browser Stuff
//
///////////////////////////////////////////////////////////////////
function true_function() {return true;}
input_keypress = true_function;
try{
var n=navigator;
var nav=n.appVersion;
var nan=n.appName;
var nua=n.userAgent;
browser_op=(nua.indexOf('Opera')!=-1);
browser_saf=(nua.indexOf('Safari')!=-1);
browser_konq=(!browser_saf && (nua.indexOf('Konqueror')!=-1) ) ? true : false;
browser_moz=( (!browser_saf && !browser_konq ) && ( nua.indexOf('Gecko')!=-1 ) ) ? true : false;
browser_ie=((nua.indexOf('MSIE')!=-1)&&!browser_op);
browser_ie5=(browser_ie&&(nua.indexOF('MSIE 5')!=-1));
os_mac=(nav.indexOf('Mac')!=-1);
os_win=( ( (nav.indexOf('Win')!=-1) || (nav.indexOf('NT')!=-1) ) && !os_mac)?true:false;
os_lin=(nua.indexOf('Linux')!=-1);
get_keyboard();
} catch(e){}
try{
[].indexOf || (Array.prototype.indexOf = function(v,n){
n = (n==null)?0:n; m = this.length;
for(var i = n; i < m; i++)
if(this[i] == v)
return i;
return -1;
});
} catch(e){}
function get_keyboard() {
var b,o,warn=false;
input_keypress = cell_input_key_event;
debug_keypress = debug_input_key_event;
if(browser_op) {
b = "o";
} else if(browser_ie) {
b = "i";
document.onkeydown = key_listen_ie;
input_keypress = true_function;
debug_keypress = true_function;
// warn = true;
} else if(browser_saf) {
b = "s";
} else if(browser_konq) {
b = "k";
// warn = true;
} else {
b = "m";
}
if(os_mac) {
o = "m";
} else if(os_lin) {
o = "l";
} else {
o = "w"
}
if(b == null || o == null || warn) {
alert("Your browser / OS combination is not supported. \nPlease use Firefox or Opera under linux, windows, or mac OSX, or Safari.")
}
async_request('__keyboard_'+b+o+'__.js', get_keyboard_callback, null);
}
function get_keyboard_callback(status, response_text) {
if(status == 'success') {
eval(response_text);
}
}
function get_element(id) {
if(document.getElementById)
return document.getElementById(id);
if(document.all)
return document.all[id];
if(document.layers)
return document.layers[id];
}
function set_class(id, cname) {
e = get_element(id);
if(e!=null) {
e.className = cname;
}
}
function get_class(id) {
e = get_element(id);
if(e!=null) {
return e.className;
}
return null
}
function set_html(id, html) {
e = get_element(id);
if(e!=null) {
e.innerHTML = html;
}
}
function get_event(e) {
return (e==null)?window.event:e;
}
function key_event(e) {
if(e==null) e = window.event;
if(e.modifiers) {
this.a = e.modifiers | 1;
this.c = e.modifiers | 2;
this.s = e.modifiers | 4;
} else {
this.a = e.altKey;
this.c = e.ctrlKey;
this.s = e.shiftKey;
}
this.k = e.keyCode + "," + e.which;
this.m = this.k + (this.s?'!':'');
return this;
}
function time_now() {
return (new Date()).getTime();
}
///////////////////////////////////////////////////////////////////
//
// Misc page functions -- for making the page work nicely
// (this is a crappy descriptor)
///////////////////////////////////////////////////////////////////
function trim(s) {
m = one_word_pat.exec(s);
if(m == null)
return s;
return m[1];
}
function body_load() {
// init_menus();
}
function init_menus() {
for( i = 1; i <= 3; i++) {
menu = get_element("menu"+i);
menu.style.display="none";
}
}
function toggle_menu(name) {
if(get_class(name) == "hidden") {
set_class(name, name);
set_html(name+'_hider', '[-]');
} else {
set_class(name, 'hidden');
set_html(name+'_hider', '[+]');
}
}
function toggle_left_pane() {
if(get_class('left_pane') == "hidden") {
set_class('left_pane', 'pane');
set_class('worksheet', 'worksheet');
// set_class('left_pane_bar', 'hidden');
// set_html('left_pane_hider', '««');
} else {
set_class('left_pane', 'hidden');
set_class('worksheet', 'slideshow');
// set_class('left_pane_bar', 'left_pane_bar');
// set_html('left_pane_hider', '» Control Bar »');
}
}
///////////////////////////////////////////////////////////////////
//
// Completions interface stuff
//
///////////////////////////////////////////////////////////////////
function handle_replacement_controls(cell_input, event) {
deselect_replacement_element();
if(key_menu_up(event)) {
if(replacement_row <= 0) {
halt_introspection();
} else {
replacement_row--;
}
} else if(key_menu_down(event)) {
replacement_row++;
if(!replacement_element_exists())
replacement_row = 0;
} else if(key_menu_right(event)) {
replacement_col++;
if(!replacement_element_exists())
replacement_col = 0;
} else if(key_menu_left(event)) {
replacement_col--;
if(!replacement_element_exists()) {
replacement_col = 1;
while(replacement_element_exists())
replacement_col++;
replacement_col--;
}
} else if(key_menu_pick(event)) {
do_replacement(introspect_id, replacement_word, true);
return false;
} else if(key_request_introspections(event)) {
if(sub_introspecting) {
introspection_text = replacement_text;
introspection_loaded = true;
sub_introspecting = false;
update_introspection_text();
} else {
replacement_text = introspection_text;
introspection_loaded = false;
sub_introspecting = true;
}
} else {
halt_introspection();
return true;
}
select_replacement_element();
if(sub_introspecting) {
active_cell_list = active_cell_list.concat([introspect_id]);
evaluate_cell_introspection(introspect_id, before_replacing_word+replacement_word+'?', after_cursor);
}
return false;
}
function do_replacement(id, word,do_trim) {
var cell_input = get_cell(id);
if(do_trim) //optimization 'cause Opera has a slow regexp engine
word = trim(word);
cell_input.value = before_replacing_word + word + after_cursor;
jump_to_cell(id,0); //reset the cursor (for explorer)
try{ //firefox, et al.
var pos = before_replacing_word.length + word.length;
cell_input.selectionStart = pos;
cell_input.selectionEnd = pos;
} catch(e) {}
try{ //explorer; anybody else?
var range = document.selection.createRange();
range.moveStart('character', -after_cursor.length);
range.moveEnd('character', -after_cursor.length);
} catch(e) {}
if(browser_op || browser_saf)
focus_delay(id);
halt_introspection();
}
function get_replacement_element() {
return get_element("completion"+introspect_id + "_" + replacement_row + "_" + replacement_col);
}
function replacement_element_exists() {
return get_replacement_element() != null;
}
function select_replacement(row, col) {
deselect_replacement_element();
replacement_row = row;
replacement_col = col;
select_replacement_element();
}
function deselect_replacement_element() {
e = get_replacement_element();
if(e==null) return;
e.className = 'completion_menu_two';
}
function select_replacement_element() {
var e = get_replacement_element();
if (e==null) return;
e.className = 'completion_menu_two completion_menu_selected';
var l = e.getElementsByTagName('a');
if(l.length && l[0]!=null) {
var h = l[0].innerHTML;
var i = h.indexOf(' ')
if (i != -1) {
h = h.substr(0,i);
}
replacement_word = h;
}
}
function update_introspection_text(preserve_cursor) {
close_introspection_text();
d = get_element("introspect_div_"+introspect_id);
if(!d) return;
if(introspection_loaded) {
if(introspection_text == "") {
halt_introspection();
return;
}
d.innerHTML = introspection_text;
if(replacing)
select_replacement_element();
} else {
d.innerHTML = "loading..."
}
}
function close_introspection_text() {
d = get_element("introspect_div_"+introspect_id);
if(d!=null)
d.innerHTML = "";
}
function halt_introspection() {
close_introspection_text();
introspect_id = null;
replacing = false;
sub_introspecting = false;
introspection_loaded = false;
replacement_row = replacement_col = 0;
}
///////////////////////////////////////////////////////////////////
//
// OBJECT functions -- for managing saved objects
//
///////////////////////////////////////////////////////////////////
function click_on_object(name) {
// o = document.open("/" + name + ".sobj");
}
///////////////////////////////////////////////////////////////////
//
// WORKSHEET functions -- for switching between and managing worksheets
//
///////////////////////////////////////////////////////////////////
function add_worksheet(name,pass) {
async_request('/add_worksheet', add_worksheet_callback, 'name='+name+'&passcode='+pass)
}
function add_worksheet_callback(status,response_text) {
if (status == "success") {
/* expect response_text to encode a pair consisting of
the HTML for the updated worksheet list and the
name of the new worksheet. */
var X = response_text.split(SEP);
if (X.length <= 1) {
alert("Unable to add worksheet.");
} else {
set_worksheet_list(X[0]);
switch_to_worksheet(X[1]);
}
} else {
alert("Possible failure adding worksheet.");
}
}
function delete_worksheet(name) {
async_request('/delete_worksheet', delete_worksheet_callback, 'name='+name)
}
function delete_worksheet_callback(status, response_text) {
if (status == "success") {
/* expect response_text to encode a pair consisting of
the HTML for the updated worksheet list and the
id of a worksheet to switch to in case we just
deleted the current worksheet. */
var X = response_text.split(SEP);
if (X.length <= 1) {
alert("Possible failure deleting worksheet. " + response_text);
} else {
set_worksheet_list(X[0]);
if (X[1] != -1)
switch_to_worksheet(X[1]);
}
} else {
alert("Possible failure deleting worksheet.");
}
}
function show_worksheet_menu(worksheet) {
// not implemented
}
function set_worksheet_list(worksheets) {
var wlist = get_element('worksheet_list');
wlist.innerHTML = worksheets;
}
function show_add_new_worksheet_menu() {
var add_worksheet_menu = get_element('add_worksheet_menu');
add_worksheet_menu.style.display = 'block';
get_element('new_worksheet_box').focus()
}
function hide_add_new_worksheet_menu() {
var add_worksheet_menu = get_element('add_worksheet_menu');
add_worksheet_menu.style.display = 'none';
}
function show_upload_worksheet_menu() {
w = window.open("__upload__.html", "upload", "width=500, height=200");
if(w.focus)
w.focus();
}
function hide_upload_worksheet_menu() {
var upload_worksheet_menu = get_element('upload_worksheet_menu');
upload_worksheet_menu.style.display = 'none';
}
function process_upload_worksheet_menu_submit() {
hide_upload_worksheet_menu();
var box = get_element('upload_worksheet_filename');
var filename = box.value;
box.value = '';
upload_worksheet(filename);
}
function upload_worksheet(filename) {
async_request('/upload_worksheet', upload_worksheet_callback, 'filename='+filename)
}
function upload_worksheet_callback(status, response_text) {
if (status == "success") {
if (response_text.slice(0,5) == "Error") {
alert("Error uploading worksheet.");
} else {
set_worksheet_list(response_text);
}
} else {
alert("Possible problem uploading file.");
}
}
function show_delete_worksheet_menu() {
var delete_worksheet_menu = get_element('delete_worksheet_menu');
delete_worksheet_menu.style.display = 'block';
get_element('delete_worksheet_box').focus();
}
function hide_delete_worksheet_menu() {
var delete_worksheet_menu = get_element('delete_worksheet_menu');
delete_worksheet_menu.style.display = 'none';
}
function process_new_worksheet_menu_submit() {
hide_add_new_worksheet_menu();
var add_worksheet_box = get_element('new_worksheet_box');
name = add_worksheet_box.value;
var add_worksheet_pass = get_element('new_worksheet_pass');
pass = add_worksheet_pass.value;
add_worksheet_box.value = '';
add_worksheet_pass.value = '';
add_worksheet(name,pass);
}
function process_delete_worksheet_menu_submit() {
hide_delete_worksheet_menu();
var delete_worksheet_box = get_element('delete_worksheet_box');
name = delete_worksheet_box.value;
delete_worksheet_box.value = '';
delete_worksheet(name);
}
// We decided not to implement the following, since normal user's
// tabbed browsing (or multiple windows, depending on user taste!)
// does the same thing much better and in a more flexible manner.
function switch_to_worksheet(id) {
/* 1. check to see if worksheet is already loaded into the DOM
2. If not, load it into the dom.
3. Move it to the front and everything else to the back by changing the css.
*/
/* alert('switch to worksheet ' + id); */
}
function unlock_worksheet() {
lock = get_element("worksheet_lock");
lock.innerHTML = 'Enter Passcode: ';
lock.innerHTML+= '';
lock_input = get_element("lock_input");
lock_input.focus();
}
function unlock_worksheet_submit(e,passcode) {
if(is_submit(e)) {
document.cookie = "ws_"+worksheet_filename+"_passcode="+passcode;
async_request('/unlock_worksheet', unlock_worksheet_callback, 'worksheet_id='+worksheet_id);
return false;
}
return true;
}
function unlock_worksheet_callback(status, response_text) {
if(status == 'success' && response_text == 'ok') {
lock = get_element("worksheet_lock");
lock.parentNode.removeChild(lock);
worksheet_locked = false;
} else {
lock_input = get_element("lock_input");
lock_input.value = "";
lock_input.focus();
txt = get_element('unlock_error');
if(txt)
txt.innerHTML = 'incorrect';
}
}
///////////////////////////////////////////////////////////////////
//
// CELL functions -- for the individual cells
//
///////////////////////////////////////////////////////////////////
function get_cell(id) {
return get_element('cell_input_'+ id);
}
function cell_focus(id) {
e = get_cell(id);
current_cell = id;
if(e == null) return;
e.className="cell_input_active";
cell_input_resize(e);
return true;
}
function cell_blur(id) {
/* if(!in_slide_mode)
current_cell = -1; */
e = get_cell(id);
if(e == null) return;
e.className="cell_input";
cell_input_minimize_size(e);
return true;
}
function debug_focus() {
in_debug_input = true;
w = get_element('debug_window');
if(w)
w.className = 'debug_window_active';
}
function debug_blur() {
in_debug_input = false;
w = get_element('debug_window');
if(w)
w.className = 'debug_window_inactive';
}
//set and_delay to true if you want to refocus the browser in a keyevent
//which expects a tab -- Opera apparently resists canceling the tab key
//event -- so we can subvert that by breaking out of the call stack with
//a little timeout.
function focus(id, bottom) {
// make_cell_input_active(id);
var cell = get_cell(id);
if (cell && cell.focus) {
cell.focus();
if (!bottom)
move_cursor_to_top_of_cell(cell);
}
}
function move_cursor_to_top_of_cell(cell) {
try{ //firefox, et al.
cell.selectionStart = 0;
cell.selectionEnd = 0;
} catch(e) {}
}
function focus_delay(id) {
setTimeout('focus('+id+')', 10);
}
function cell_input_resize(cell_input) {
var rows = 2;
//var rows = cell_input.value.split('\n').length - 1;
var rows = cell_input.value.split('\n').length + 1;
if (rows <= 1) {
rows = 2;
} else {
/* to avoid bottom chop off */
/* rows = rows + 1; */
}
try {
cell_input.style.height = rows + 'em'; // this sort of works in konqueror...
} catch(e) {}
try{
cell_input.rows = rows;
} catch(e) {}
if(slide_hidden) {
cell_input.className="cell_input_active";
slide_hidden = false;
}
}
function lstrip(s) {
var n = s.length;
var i = 0;
while (i < n && (s[i] == ' ' || s[i] == '\n' || s[i] == '\t')) {
i = i + 1;
}
return s.slice(i);
}
function cell_input_minimize_size(cell_input) {
var v = cell_input.value;
var w = lstrip(v);
var sl = w.slice(0,5);
if (sl == '%hide') {
cell_input.className = 'cell_input_hide';
cell_input.style.height = '1em';
return;
}
cell_input.className = 'cell_input';
var rows = v.split('\n').length ;
if (rows < 1) {
rows = 1;
}
cell_input.rows = rows;
if (rows == 1) {
// hack because of bug in firefox with 1-row textarea
cell_input.style.height = '1.5em';
}
}
function cell_input_minimize_all() {
var v = cell_id_list;
var n = v.length;
var i;
for(i=0; i= cell_id_list.length) {
i = cell_id_list.length - 1;
}
return(cell_id_list[i]);
}
}
function debug_clear() {
output = get_element("debug_output");
if(output == null) return;
output.value = "";
}
function debug_append(txt) {
output = get_element("debug_output");
if(output == null) return;
output.innerHTML = txt + "\n" + output.innerHTML;
}
/* old_id = -1;
function make_cell_input_active(id) {
if (old_id != -1) {
make_cell_input_inactive(old_id);
}
var txt = get_cell(id);
if (txt.style.display == "inline") {
return;
}
cell_input_resize(txt);
current_cell = id;
txt.style.display = "inline";
var pre = get_element('cell_input_pre_'+id);
pre.style.display = "none";
txt.value = pre.innerHTML;
pre.innerHTML = '';
}
function make_cell_input_inactive(id) {
var txt = get_cell(id);
if (txt.style.display != "inline") {
return;
}
txt.style.display = "none";
var pre = get_element('cell_input_pre_'+id);
pre.style.display = "inline";
pre.innerHTML = txt.value;
txt.value = '';
}
*/
function jump_to_cell(id, delta, bottom) {
if(delta != 0)
id = id_of_cell_delta(id, delta)
if(in_slide_mode) {
jump_to_slide(id);
} else {
focus(id, bottom);
}
}
function escape0(input) {
input = escape(input);
input = input.replace(/\+/g,"%2B");
return input;
}
function text_cursor_split(input) {
if(browser_ie) {
//for explorer, we call the
// document.selection.createRange().duplicate()
//to generate a selection range object which does not effect the
//original input box.
//Then, we rewind the start point of the range until we encounter
//a non-word character, or we've rewound past the beginning of
//the textarea).
var range = document.selection.createRange().duplicate();
var i = range.text.length;
while((input.value.match(range.text) || i==0)
&& range.text.length == i) {
range.moveStart('character', -1);
i = i + 1;
}
if(!input.value.match(range.text))
range.moveStart('character', 1);
b = range.text;
} else {
b = input.value.substr(0,input.selectionEnd);
}
a = input.value.substr(b.length);
return new Array(b,a);
}
function evaluate_cell(id, action) {
if(worksheet_locked) {
alert("This worksheet is locked. Click on the word [locked] next to the worksheet name to unlock it.")
return;
}
active_cell_list = active_cell_list.concat([id]);
if(action == 2) { // Introspection
evaluate_cell_introspection(id,null,null);
return;
}
if(!in_slide_mode) {
jump_to_cell(id,1);
}
cell_set_running(id);
var cell_input = get_cell(id);
var I = cell_input.value;
var input = escape0(I);
async_request('/eval' + action, evaluate_cell_callback,
'id=' + id + '&input='+input);
}
function evaluate_cell_introspection(id, before, after) {
var cell_input = get_cell(id);
replacing = false;
if(before == null) {
var in_text = text_cursor_split(cell_input);
before_cursor = before = in_text[0];
after_cursor = after = in_text[1];
before_replacing_word = before;
m = command_pat.exec(before);
f = function_pat.exec(before);
if(introspect_id != null)
halt_introspection();
introspect_id = id;
var last_char_before = before.charAt(before.length-1);
if(last_char_before == "?") {
} else if(m) {
replacing = true;
replacing_word = m[1];
before_replacing_word = before.substring(0, before.length-replacing_word.length);
} else if(f != null) { //we're in an open function paren -- give info on the function
before = f[1] + "?";
} else { //just a tab
do_replacement(id, ' ',false);
return;
}
} else {
sub_introspecting = true;
}
if(!replacing && (browser_op || browser_saf))
focus_delay(id);
update_introspection_text();
var before_cursor_e = escape0(before);
var after_cursor_e = escape0(after);
cell_set_running(id);
async_request('/introspect', evaluate_cell_callback,
'id=' + id + '&before_cursor='+before_cursor_e + '&after_cursor='+after_cursor_e);
}
function evaluate_cell_callback(status, response_text) {
/* update focus and possibly add a new cell to the end */
if (status == "failure") {
/* alert("Failure evaluating a cell."); */
return;
}
var X = response_text.split(SEP);
if (X[0] == '-1') {
/* something went wrong -- i.e., the requested cell doesn't exist. */
alert("You requested to evaluate a cell that, for some reason, the server is unaware of.");
return;
}
if (X[1] == 'append_new_cell') {
// add a new cell to the very end
append_new_cell(X[0],X[2]);
} else if (X[1] == 'insert_cell') {
// insert a new cell after the one with id X[3]
do_insert_new_cell_after(X[3], X[0], X[2]);
jump_to_cell(X[0],0);
}
start_update_check();
}
function cell_output_set_type(id, typ, do_async) {
set_class('cell_div_output_' + id, 'cell_output_' + typ)
set_class('cell_output_' + id, 'cell_output_' + typ)
set_class('cell_output_nowrap_' + id, 'cell_output_nowrap_' + typ)
set_class('cell_output_html_' + id, 'cell_output_html_' + typ)
/* Do async request back to the server */
if(do_async != false)
async_request('/cell_output_set', generic_callback, 'id='+id+'&type=' + typ)
}
function cycle_cell_output_type(id) {
var cell_div = get_element('cell_div_output_' + id);
if (cell_div.className == 'cell_output_hidden' || cell_div.className=='cell_output_running') {
cell_output_set_type(id, 'wrap');
return;
}
if (cell_div.className == 'cell_output_wrap') {
cell_output_set_type(id, 'nowrap');
} else {
cell_output_set_type(id, 'hidden');
}
}
function cell_set_evaluated(id) {
var D = get_element('cell_'+id);
D.className = "cell_evaluated";
}
function cell_set_not_evaluated(id) {
var D = get_element('cell_'+id);
D.className = "cell_not_evaluated";
cell_set_done(id);
}
function cell_set_running(id) {
set_output_text(id, '', '', '', '', '');
cell_output_set_type(id, 'wrap');
var cell_div = get_element('cell_div_output_' + id);
cell_div.className = 'cell_output_running';
var cell_number = get_element('cell_number_' + id);
cell_number.className = 'cell_number_running';
}
function cell_set_done(id) {
var cell_div = get_element('cell_div_output_' + id)
cell_div.className = 'cell_output_wrap';
var cell_number = get_element('cell_number_' + id);
cell_number.className = 'cell_number';
}
function check_for_cell_update() {
if (active_cell_list.length == 0) {
cancel_update_check();
return;
}
var cell_id = active_cell_list[0];
update_time = time_now();
async_request('/cell_update',
check_for_cell_update_callback,
'cell_id=' + cell_id + '&worksheet_id='+worksheet_id);
}
function start_update_check() {
if(updating) return;
updating = true;
check_for_cell_update();
set_class('interrupt', 'interrupt')
}
function cancel_update_check() {
updating = false;
clearTimeout(update_timeout);
set_class('interrupt', 'interrupt_grey')
}
function set_output_text(id, text, wrapped_text, output_html, status, introspect_html) {
/* fill in output text got so far */
var cell_output = get_element('cell_output_' + id);
var cell_output_nowrap = get_element('cell_output_nowrap_' + id);
var cell_output_html = get_element('cell_output_html_' + id);
cell_output.innerHTML = wrapped_text;
cell_output_nowrap.innerHTML = text;
cell_output_html.innerHTML = output_html;
if (status == 'd') {
cell_set_done(id);
// TODO: should make this not case sensitive!! how to .lower() in javascript?
if (text.indexOf('class="math"') != -1 || text.indexOf("class='math'") != -1) {
try {
/* jsMath.Process(cell_output); */
/* jsMath.ProcessBeforeShowing(cell_output_nowrap); */
jsMath.ProcessBeforeShowing(cell_output);
/* jsMath.ProcessBeforeShowing(cell_output_nowrap); */
} catch(e) {
cell_output.innerHTML = jsmath_font_msg + cell_output.innerHTML;
cell_output_nowrap.innerHTML = jsmath_font_msg + cell_output_nowrap.innerHTML;
}
}
} else {
}
if(introspect_id == id) {
if (status == 'd') {
introspection_loaded = true;
introspection_text = introspect_html;
}
update_introspection_text();
} else if(introspect_html != '') {
cell_output.innerHTML = '';
cell_output_nowrap.innerHTML = '';
cell_output_html.innerHTML = introspect_html;
}
}
function set_input_text(id, text) {
/* fill in input text */
var cell_input = get_cell(id);
cell_input.value = text;
jump_to_cell(id,0)
try {
pos = text.length - after_cursor.length;
cell_input.selectionStart = pos;
cell_input.selectionEnd = pos;
}catch(e){}
try{
var range = document.selection.createRange();
range.moveStart('character', -after_cursor.length);
range.moveEnd('character', -after_cursor.length);
}catch(e){}
return false;
}
function set_variable_list(variables) {
var varlist = get_element('variable_list');
varlist.innerHTML = variables;
}
function set_object_list(objects) {
var objlist = get_element('object_list');
objlist.innerHTML = objects;
}
function set_attached_files_list(objects) {
var objlist = get_element('attached_list');
objlist.innerHTML = objects;
}
function check_for_cell_update_callback(status, response_text) {
// make sure the update happens again in a few hundred milliseconds,
// unless a problem occurs below.
if (status != "success") {
if(update_error_count>update_error_threshold) {
cancel_update_check();
halt_active_cells();
var elapsed_time = update_error_count*update_error_delta/1000;
var msg = "Error updating cell output after " + elapsed_time + "s";
msg += "(canceling further update checks).";
alert(msg);
return;
}
cell_output_delta = update_error_delta;
update_error_count++;
continue_update_check();
return;
} else {
update_error_count = 0;
cell_output_delta = update_normal_delta;
}
var i = response_text.indexOf(' ');
var id = response_text.substring(1, i);
var stat = response_text.substring(0,1)
if(response_text == 'empty') {
cancel_update_check();
return;
}
if(stat == 'e') {
cancel_update_check();
halt_active_cells();
return;
}
/* compute output for a cell */
var D = response_text.slice(i+1).split(SEP);
var output_text = D[0] + ' ';
var output_text_wrapped = D[1] + ' ';
var output_html = D[2];
var new_cell_input = D[3];
var interrupted = D[4];
var variable_list = D[5];
var object_list = D[6];
var attached_files_list = D[7];
var introspect_html = D[8];
var j = id_of_cell_delta(id,1);
set_output_text(id, output_text, output_text_wrapped,
output_html, stat, introspect_html);
if (stat == 'd') {
active_cell_list = delete_from_array(active_cell_list, id);
if (interrupted == 'false') {
cell_set_evaluated(id);
} else {
halt_active_cells();
cancel_update_check();
}
if(active_cell_list.length == 0)
cancel_update_check();
if (new_cell_input != '') {
set_input_text(id, new_cell_input);
}
set_variable_list(variable_list);
set_object_list(object_list);
set_attached_files_list(attached_files_list);
}
continue_update_check();
}
function continue_update_check() {
var time_elapsed = time_now() - update_time;
if(time_elapsed < cell_output_delta) {
update_timeout = setTimeout('check_for_cell_update()', cell_output_delta-time_elapsed);
} else {
check_for_cell_update();
}
}
///////////////////////////////////////////////////////////////////
// Slideshow Functions
///////////////////////////////////////////////////////////////////
/* Switch into slide mode. */
function slide_mode() {
in_slide_mode = true;
set_class('left_pane', 'hidden');
set_class('cell_controls', 'hidden');
set_class('slide_controls', 'slide_control_commands');
set_class('worksheet', 'slideshow');
set_class('left_pane_bar', 'hidden');
for(i = 0; i < cell_id_list.length ; i++) {
set_class('cell_outer_'+cell_id_list[i], 'hidden');
}
slide_show();
}
function cell_mode() {
in_slide_mode = false;
set_class('left_pane', 'pane');
set_class('cell_controls', 'control_commands');
set_class('slide_controls', 'hidden');
set_class('worksheet', 'worksheet');
set_class('left_pane_bar', 'left_pane_bar');
for(i = 0; i < cell_id_list.length ; i++) {
set_class('cell_outer_'+cell_id_list[i], 'cell_visible');
}
}
function slide_hide() {
set_class('cell_outer_' + current_cell, 'hidden');
}
function slide_show() {
if(current_cell != -1) {
set_class('cell_outer_' + current_cell, 'cell_visible');
} else {
if(cell_id_list.length>0)
current_cell = cell_id_list[0];
set_class('cell_outer_' + current_cell, 'cell_visible');
}
if(current_cell != -1) {
input = get_cell(current_cell);
if(input != null) {
s = lstrip(input.value).slice(0,5)
focus(current_cell);
if (s == '%hide') {
slide_hidden = true;
input.className = 'cell_input_hide';
input.style.height = '1.5em';
}
}
}
update_slideshow_progress();
}
function slide_first() {
jump_to_slide(cell_id_list[0]);
}
function slide_last() {
jump_to_slide(cell_id_list[cell_id_list.length-1]);
}
function slide_next() {
jump_to_slide(id_of_cell_delta(current_cell, 1));
}
function slide_prev() {
jump_to_slide(id_of_cell_delta(current_cell, -1));
}
function jump_to_slide(id) {
slide_hide();
current_cell = id;
slide_show();
}
function update_slideshow_progress() {
var i = cell_id_list.indexOf(current_cell) + 1;
var n = cell_id_list.length;
var bar = get_element("slideshow_progress_bar")
if(bar != null)
bar.style.width = "" + 100*i/n + "%";
text = get_element("slideshow_progress_text")
if(text != null)
text.innerHTML = i + " / " + n;
}
///////////////////////////////////////////////////////////////////
// Insert and move cells
///////////////////////////////////////////////////////////////////
function insertAfter(parent, node, referenceNode) {
parent.insertBefore(node, referenceNode.nextSibling);
}
function insert_into_array(v, i, x) {
/* Return a new array with x inserted into position i of v. */
return (v.slice(0,i).concat([x]).concat(v.slice(i,v.length)));
}
function delete_from_array(v, x) {
/* Delete first occurrence of x in v.
Returns resulting array (creates a new array!).
No error if x is not in v.
*/
var i;
for (i=0; i 0) {
evaluate_cell(v[i],0);
}
}
}
function hide_all_callback() {
}
function hide_all() {
var v = cell_id_list;
var n = v.length;
var i;
for(i=0; i