summaryrefslogtreecommitdiffstats
path: root/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/webui.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/civetweb/src/third_party/duktape-1.5.2/debugger/static/webui.js785
1 files changed, 785 insertions, 0 deletions
diff --git a/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/webui.js b/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/webui.js
new file mode 100644
index 000000000..d400c6c35
--- /dev/null
+++ b/src/civetweb/src/third_party/duktape-1.5.2/debugger/static/webui.js
@@ -0,0 +1,785 @@
+/*
+ * Duktape debugger web client
+ *
+ * Talks to the NodeJS server using socket.io.
+ *
+ * http://unixpapa.com/js/key.html
+ */
+
+// Update interval for custom source highlighting.
+var SOURCE_UPDATE_INTERVAL = 350;
+
+// Source view
+var activeFileName = null; // file that we want to be loaded in source view
+var activeLine = null; // scroll to line once file has been loaded
+var activeHighlight = null; // line that we want to highlight (if any)
+var loadedFileName = null; // currently loaded (shown) file
+var loadedLineCount = 0; // currently loaded file line count
+var loadedFileExecuting = false; // true if currFileName (loosely) matches loadedFileName
+var loadedLinePending = null; // if set, scroll loaded file to requested line
+var highlightLine = null; // highlight line
+var sourceEditedLines = []; // line numbers which have been modified
+ // (added classes etc, tracked for removing)
+var sourceUpdateInterval = null; // timer for updating source view
+var sourceFetchXhr = null; // current AJAX request for fetching a source file (if any)
+var forceButtonUpdate = false; // hack to reset button states
+var bytecodeDialogOpen = false; // bytecode dialog active
+var bytecodeIdxHighlight = null; // index of currently highlighted line (or null)
+var bytecodeIdxInstr = 0; // index to first line of bytecode instructions
+
+// Execution state
+var prevState = null; // previous execution state ('paused', 'running', etc)
+var prevAttached = null; // previous debugger attached state (true, false, null)
+var currFileName = null; // current filename being executed
+var currFuncName = null; // current function name being executed
+var currLine = 0; // current line being executed
+var currPc = 0; // current bytecode PC being executed
+var currState = 0; // current execution state ('paused', 'running', 'detached', etc)
+var currAttached = false; // current debugger attached state (true or false)
+var currLocals = []; // current local variables
+var currCallstack = []; // current callstack (from top to bottom)
+var currBreakpoints = []; // current breakpoints
+var startedRunning = 0; // timestamp when last started running (if running)
+ // (used to grey out the source file if running for long enough)
+
+/*
+ * Helpers
+ */
+
+function formatBytes(x) {
+ if (x < 1024) {
+ return String(x) + ' bytes';
+ } else if (x < 1024 * 1024) {
+ return (x / 1024).toPrecision(3) + ' kB';
+ } else {
+ return (x / (1024 * 1024)).toPrecision(3) + ' MB';
+ }
+}
+
+/*
+ * Source view periodic update handling
+ */
+
+function doSourceUpdate() {
+ var elem;
+
+ // Remove previously added custom classes
+ sourceEditedLines.forEach(function (linenum) {
+ elem = $('#source-code div')[linenum - 1];
+ if (elem) {
+ elem.classList.remove('breakpoint');
+ elem.classList.remove('execution');
+ elem.classList.remove('highlight');
+ }
+ });
+ sourceEditedLines.length = 0;
+
+ // If we're executing the file shown, highlight current line
+ if (loadedFileExecuting) {
+ elem = $('#source-code div')[currLine - 1];
+ if (elem) {
+ sourceEditedLines.push(currLine);
+ elem.classList.add('execution');
+ }
+ }
+
+ // Add breakpoints
+ currBreakpoints.forEach(function (bp) {
+ if (bp.fileName === loadedFileName) {
+ elem = $('#source-code div')[bp.lineNumber - 1];
+ if (elem) {
+ sourceEditedLines.push(bp.lineNumber);
+ elem.classList.add('breakpoint');
+ }
+ }
+ });
+
+ if (highlightLine !== null) {
+ elem = $('#source-code div')[highlightLine - 1];
+ if (elem) {
+ sourceEditedLines.push(highlightLine);
+ elem.classList.add('highlight');
+ }
+ }
+
+ // Bytecode dialog highlight
+ if (loadedFileExecuting && bytecodeDialogOpen && bytecodeIdxHighlight !== bytecodeIdxInstr + currPc) {
+ if (typeof bytecodeIdxHighlight === 'number') {
+ $('#bytecode-preformatted div')[bytecodeIdxHighlight].classList.remove('highlight');
+ }
+ bytecodeIdxHighlight = bytecodeIdxInstr + currPc;
+ $('#bytecode-preformatted div')[bytecodeIdxHighlight].classList.add('highlight');
+ }
+
+ // If no-one requested us to scroll to a specific line, finish.
+ if (loadedLinePending == null) {
+ return;
+ }
+
+ var reqLine = loadedLinePending;
+ loadedLinePending = null;
+
+ // Scroll to requested line. This is not very clean, so a better solution
+ // should be found:
+ // https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollIntoView
+ // http://erraticdev.blogspot.fi/2011/02/jquery-scroll-into-view-plugin-with.html
+ // http://flesler.blogspot.fi/2007/10/jqueryscrollto.html
+ var tmpLine = Math.max(reqLine - 5, 0);
+ elem = $('#source-code div')[tmpLine];
+ if (elem) {
+ elem.scrollIntoView();
+ }
+}
+
+// Source is updated periodically. Other code can also call doSourceUpdate()
+// directly if an immediate update is needed.
+sourceUpdateInterval = setInterval(doSourceUpdate, SOURCE_UPDATE_INTERVAL);
+
+/*
+ * UI update handling when exec-status update arrives
+ */
+
+function doUiUpdate() {
+ var now = Date.now();
+
+ // Note: loadedFileName can be either from target or from server, but they
+ // must match exactly. We could do a loose match here, but exact matches
+ // are needed for proper breakpoint handling anyway.
+ loadedFileExecuting = (loadedFileName === currFileName);
+
+ // If we just started running, store a timestamp so we can grey out the
+ // source view only if we execute long enough (i.e. we're not just
+ // stepping).
+ if (currState !== prevState && currState === 'running') {
+ startedRunning = now;
+ }
+
+ // If we just became paused, check for eval watch
+ if (currState !== prevState && currState === 'paused') {
+ if ($('#eval-watch').is(':checked')) {
+ submitEval(); // don't clear eval input
+ }
+ }
+
+ // Update current execution state
+ if (currFileName === '' && currLine === 0) {
+ $('#current-fileline').text('');
+ } else {
+ $('#current-fileline').text(String(currFileName) + ':' + String(currLine));
+ }
+ if (currFuncName === '' && currPc === 0) {
+ $('#current-funcpc').text('');
+ } else {
+ $('#current-funcpc').text(String(currFuncName) + '() pc ' + String(currPc));
+ }
+ $('#current-state').text(String(currState));
+
+ // Update buttons
+ if (currState !== prevState || currAttached !== prevAttached || forceButtonUpdate) {
+ $('#stepinto-button').prop('disabled', !currAttached || currState !== 'paused');
+ $('#stepover-button').prop('disabled', !currAttached || currState !== 'paused');
+ $('#stepout-button').prop('disabled', !currAttached || currState !== 'paused');
+ $('#resume-button').prop('disabled', !currAttached || currState !== 'paused');
+ $('#pause-button').prop('disabled', !currAttached || currState !== 'running');
+ $('#attach-button').prop('disabled', currAttached);
+ if (currAttached) {
+ $('#attach-button').removeClass('enabled');
+ } else {
+ $('#attach-button').addClass('enabled');
+ }
+ $('#detach-button').prop('disabled', !currAttached);
+ $('#eval-button').prop('disabled', !currAttached);
+ $('#add-breakpoint-button').prop('disabled', !currAttached);
+ $('#delete-all-breakpoints-button').prop('disabled', !currAttached);
+ $('.delete-breakpoint-button').prop('disabled', !currAttached);
+ $('#putvar-button').prop('disabled', !currAttached);
+ $('#getvar-button').prop('disabled', !currAttached);
+ $('#heap-dump-download-button').prop('disabled', !currAttached);
+ }
+ if (currState !== 'running' || forceButtonUpdate) {
+ // Remove pending highlight once we're no longer running.
+ $('#pause-button').removeClass('pending');
+ $('#eval-button').removeClass('pending');
+ }
+ forceButtonUpdate = false;
+
+ // Make source window grey when running for a longer time, use a small
+ // delay to avoid flashing grey when stepping.
+ if (currState === 'running' && now - startedRunning >= 500) {
+ $('#source-pre').removeClass('notrunning');
+ $('#current-state').removeClass('notrunning');
+ } else {
+ $('#source-pre').addClass('notrunning');
+ $('#current-state').addClass('notrunning');
+ }
+
+ // Force source view to match currFileName only when running or when
+ // just became paused (from running or detached).
+ var fetchSource = false;
+ if (typeof currFileName === 'string') {
+ if (currState === 'running' ||
+ (prevState !== 'paused' && currState === 'paused') ||
+ (currAttached !== prevAttached)) {
+ if (activeFileName !== currFileName) {
+ fetchSource = true;
+ activeFileName = currFileName;
+ activeLine = currLine;
+ activeHighlight = null;
+ requestSourceRefetch();
+ }
+ }
+ }
+
+ // Force line update (scrollTop) only when running or just became paused.
+ // Otherwise let user browse and scroll source files freely.
+ if (!fetchSource) {
+ if ((prevState !== 'paused' && currState === 'paused') ||
+ currState === 'running') {
+ loadedLinePending = currLine || 0;
+ }
+ }
+}
+
+/*
+ * Init socket.io and add handlers
+ */
+
+var socket = io(); // returns a Manager
+
+setInterval(function () {
+ socket.emit('keepalive', {
+ userAgent: (navigator || {}).userAgent
+ });
+}, 30000);
+
+socket.on('connect', function () {
+ $('#socketio-info').text('connected');
+ currState = 'connected';
+
+ fetchSourceList();
+});
+socket.on('disconnect', function () {
+ $('#socketio-info').text('not connected');
+ currState = 'disconnected';
+});
+socket.on('reconnecting', function () {
+ $('#socketio-info').text('reconnecting');
+ currState = 'reconnecting';
+});
+socket.on('error', function (err) {
+ $('#socketio-info').text(err);
+});
+
+socket.on('replaced', function () {
+ // XXX: how to minimize the chance we'll further communciate with the
+ // server or reconnect to it? socket.reconnection()?
+
+ // We'd like to window.close() here but can't (not allowed from scripts).
+ // Alert is the next best thing.
+ alert('Debugger connection replaced by a new one, do you have multiple tabs open? If so, please close this tab.');
+});
+
+socket.on('keepalive', function (msg) {
+ // Not really interesting in the UI
+ // $('#server-info').text(new Date() + ': ' + JSON.stringify(msg));
+});
+
+socket.on('basic-info', function (msg) {
+ $('#duk-version').text(String(msg.duk_version));
+ $('#duk-git-describe').text(String(msg.duk_git_describe));
+ $('#target-info').text(String(msg.target_info));
+ $('#endianness').text(String(msg.endianness));
+});
+
+socket.on('exec-status', function (msg) {
+ // Not 100% reliable if callstack has several functions of the same name
+ if (bytecodeDialogOpen && (currFileName != msg.fileName || currFuncName != msg.funcName)) {
+ socket.emit('get-bytecode', {});
+ }
+
+ currFileName = msg.fileName;
+ currFuncName = msg.funcName;
+ currLine = msg.line;
+ currPc = msg.pc;
+ currState = msg.state;
+ currAttached = msg.attached;
+
+ // Duktape now restricts execution status updates quite effectively so
+ // there's no need to rate limit UI updates now.
+
+ doUiUpdate();
+
+ prevState = currState;
+ prevAttached = currAttached;
+});
+
+// Update the "console" output based on lines sent by the server. The server
+// rate limits these updates to keep the browser load under control. Even
+// better would be for the client to pull this (and other stuff) on its own.
+socket.on('output-lines', function (msg) {
+ var elem = $('#output');
+ var i, n, ent;
+
+ elem.empty();
+ for (i = 0, n = msg.length; i < n; i++) {
+ ent = msg[i];
+ if (ent.type === 'print') {
+ elem.append($('<div></div>').text(ent.message));
+ } else if (ent.type === 'alert') {
+ elem.append($('<div class="alert"></div>').text(ent.message));
+ } else if (ent.type === 'log') {
+ elem.append($('<div class="log loglevel' + ent.level + '"></div>').text(ent.message));
+ } else if (ent.type === 'debugger-info') {
+ elem.append($('<div class="debugger-info"><div>').text(ent.message));
+ } else if (ent.type === 'debugger-debug') {
+ elem.append($('<div class="debugger-debug"><div>').text(ent.message));
+ } else {
+ elem.append($('<div></div>').text(ent.message));
+ }
+ }
+
+ // http://stackoverflow.com/questions/14918787/jquery-scroll-to-bottom-of-div-even-after-it-updates
+ // Stop queued animations so that we always scroll quickly to bottom
+ $('#output').stop(true);
+ $('#output').animate({ scrollTop: $('#output')[0].scrollHeight}, 1000);
+});
+
+socket.on('callstack', function (msg) {
+ var elem = $('#callstack');
+ var s1, s2, div;
+
+ currCallstack = msg.callstack;
+
+ elem.empty();
+ msg.callstack.forEach(function (e) {
+ s1 = $('<a class="rest"></a>').text(e.fileName + ':' + e.lineNumber + ' (pc ' + e.pc + ')'); // float
+ s1.on('click', function () {
+ activeFileName = e.fileName;
+ activeLine = e.lineNumber || 1;
+ activeHighlight = activeLine;
+ requestSourceRefetch();
+ });
+ s2 = $('<span class="func"></span>').text(e.funcName + '()');
+ div = $('<div></div>');
+ div.append(s1);
+ div.append(s2);
+ elem.append(div);
+ });
+});
+
+socket.on('locals', function (msg) {
+ var elem = $('#locals');
+ var s1, s2, div;
+ var i, n, e;
+
+ currLocals = msg.locals;
+
+ elem.empty();
+ for (i = 0, n = msg.locals.length; i < n; i++) {
+ e = msg.locals[i];
+ s1 = $('<span class="value"></span>').text(e.value); // float
+ s2 = $('<span class="key"></span>').text(e.key);
+ div = $('<div></div>');
+ div.append(s1);
+ div.append(s2);
+ elem.append(div);
+ }
+});
+
+socket.on('debug-stats', function (msg) {
+ $('#debug-rx-bytes').text(formatBytes(msg.rxBytes));
+ $('#debug-rx-dvalues').text(msg.rxDvalues);
+ $('#debug-rx-messages').text(msg.rxMessages);
+ $('#debug-rx-kbrate').text((msg.rxBytesPerSec / 1024).toFixed(2));
+ $('#debug-tx-bytes').text(formatBytes(msg.txBytes));
+ $('#debug-tx-dvalues').text(msg.txDvalues);
+ $('#debug-tx-messages').text(msg.txMessages);
+ $('#debug-tx-kbrate').text((msg.txBytesPerSec / 1024).toFixed(2));
+});
+
+socket.on('breakpoints', function (msg) {
+ var elem = $('#breakpoints');
+ var div;
+ var sub;
+
+ currBreakpoints = msg.breakpoints;
+
+ elem.empty();
+
+ // First line is special
+ div = $('<div></div>');
+ sub = $('<button id="delete-all-breakpoints-button"></button>').text('Delete all breakpoints');
+ sub.on('click', function () {
+ socket.emit('delete-all-breakpoints');
+ });
+ div.append(sub);
+ sub = $('<input id="add-breakpoint-file"></input>').val('file.js');
+ div.append(sub);
+ sub = $('<span></span>').text(':');
+ div.append(sub);
+ sub = $('<input id="add-breakpoint-line"></input>').val('123');
+ div.append(sub);
+ sub = $('<button id="add-breakpoint-button"></button>').text('Add breakpoint');
+ sub.on('click', function () {
+ socket.emit('add-breakpoint', {
+ fileName: $('#add-breakpoint-file').val(),
+ lineNumber: Number($('#add-breakpoint-line').val())
+ });
+ });
+ div.append(sub);
+ sub = $('<span id="breakpoint-hint"></span>').text('or dblclick source');
+ div.append(sub);
+ elem.append(div);
+
+ // Active breakpoints follow
+ msg.breakpoints.forEach(function (bp) {
+ var div;
+ var sub;
+
+ div = $('<div class="breakpoint-line"></div>');
+ sub = $('<button class="delete-breakpoint-button"></button>').text('Delete');
+ sub.on('click', function () {
+ socket.emit('delete-breakpoint', {
+ fileName: bp.fileName,
+ lineNumber: bp.lineNumber
+ });
+ });
+ div.append(sub);
+ sub = $('<a></a>').text((bp.fileName || '?') + ':' + (bp.lineNumber || 0));
+ sub.on('click', function () {
+ activeFileName = bp.fileName || '';
+ activeLine = bp.lineNumber || 1;
+ activeHighlight = activeLine;
+ requestSourceRefetch();
+ });
+ div.append(sub);
+ elem.append(div);
+ });
+
+ forceButtonUpdate = true;
+ doUiUpdate();
+});
+
+socket.on('eval-result', function (msg) {
+ $('#eval-output').text((msg.error ? 'ERROR: ' : '') + msg.result);
+
+ // Remove eval button "pulsating" glow when we get a result
+ $('#eval-button').removeClass('pending');
+});
+
+socket.on('getvar-result', function (msg) {
+ $('#var-output').text(msg.found ? msg.result : 'NOTFOUND');
+});
+
+socket.on('bytecode', function (msg) {
+ var elem, div;
+ var div;
+
+ elem = $('#bytecode-preformatted');
+ elem.empty();
+
+ msg.preformatted.split('\n').forEach(function (line, idx) {
+ div = $('<div></div>');
+ div.text(line);
+ elem.append(div);
+ });
+
+ bytecodeIdxHighlight = null;
+ bytecodeIdxInstr = msg.idxPreformattedInstructions;
+});
+
+$('#stepinto-button').click(function () {
+ socket.emit('stepinto', {});
+});
+
+$('#stepover-button').click(function () {
+ socket.emit('stepover', {});
+});
+
+$('#stepout-button').click(function () {
+ socket.emit('stepout', {});
+});
+
+$('#pause-button').click(function () {
+ socket.emit('pause', {});
+
+ // Pause may take seconds to complete so indicate it is pending.
+ $('#pause-button').addClass('pending');
+});
+
+$('#resume-button').click(function () {
+ socket.emit('resume', {});
+});
+
+$('#attach-button').click(function () {
+ socket.emit('attach', {});
+});
+
+$('#detach-button').click(function () {
+ socket.emit('detach', {});
+});
+
+$('#about-button').click(function () {
+ $('#about-dialog').dialog('open');
+});
+
+$('#show-bytecode-button').click(function () {
+ bytecodeDialogOpen = true;
+ $('#bytecode-dialog').dialog('open');
+
+ elem = $('#bytecode-preformatted');
+ elem.empty().text('Loading bytecode...');
+
+ socket.emit('get-bytecode', {});
+});
+
+function submitEval() {
+ socket.emit('eval', { input: $('#eval-input').val() });
+
+ // Eval may take seconds to complete so indicate it is pending.
+ $('#eval-button').addClass('pending');
+}
+
+$('#eval-button').click(function () {
+ submitEval();
+ $('#eval-input').val('');
+});
+
+$('#getvar-button').click(function () {
+ socket.emit('getvar', { varname: $('#varname-input').val() });
+});
+
+$('#putvar-button').click(function () {
+ // The variable value is parsed as JSON right now, but it'd be better to
+ // also be able to parse buffer values etc.
+ var val = JSON.parse($('#varvalue-input').val());
+ socket.emit('putvar', { varname: $('#varname-input').val(), varvalue: val });
+});
+
+$('#source-code').dblclick(function (event) {
+ var target = event.target;
+ var elems = $('#source-code div');
+ var i, n;
+ var line = 0;
+
+ // XXX: any faster way; elems doesn't have e.g. indexOf()
+ for (i = 0, n = elems.length; i < n; i++) {
+ if (target === elems[i]) {
+ line = i + 1;
+ }
+ }
+
+ socket.emit('toggle-breakpoint', {
+ fileName: loadedFileName,
+ lineNumber: line
+ });
+});
+
+function setSourceText(data) {
+ var elem, div;
+
+ elem = $('#source-code');
+ elem.empty();
+ data.split('\n').forEach(function (line) {
+ div = $('<div></div>');
+ div.text(line);
+ elem.append(div);
+ });
+
+ sourceEditedLines = [];
+}
+
+function setSourceSelect(fileName) {
+ var elem;
+ var i, n, t;
+
+ if (fileName == null) {
+ $('#source-select').val('__none__');
+ return;
+ }
+
+ elem = $('#source-select option');
+ for (i = 0, n = elem.length; i < n; i++) {
+ // Exact match is required.
+ t = $(elem[i]).val();
+ if (t === fileName) {
+ $('#source-select').val(t);
+ return;
+ }
+ }
+}
+
+/*
+ * AJAX request handling to fetch source files
+ */
+
+function requestSourceRefetch() {
+ // If previous update is pending, abort and start a new one.
+ if (sourceFetchXhr) {
+ sourceFetchXhr.abort();
+ sourceFetchXhr = null;
+ }
+
+ // Make copies of the requested file/line so that we have the proper
+ // values in case they've changed.
+ var fileName = activeFileName;
+ var lineNumber = activeLine;
+
+ // AJAX request for the source.
+ sourceFetchXhr = $.ajax({
+ type: 'POST',
+ url: '/source',
+ data: JSON.stringify({ fileName: fileName }),
+ contentType: 'application/json',
+ success: function (data, status, jqxhr) {
+ var elem;
+
+ sourceFetchXhr = null;
+
+ loadedFileName = fileName;
+ loadedLineCount = data.split('\n').length; // XXX: ignore issue with last empty line for now
+ loadedFileExecuting = (loadedFileName === currFileName);
+ setSourceText(data);
+ setSourceSelect(fileName);
+ loadedLinePending = activeLine || 1;
+ highlightLine = activeHighlight; // may be null
+ activeLine = null;
+ activeHighlight = null;
+ doSourceUpdate();
+
+ // XXX: hacky transition, make source change visible
+ $('#source-pre').fadeTo('fast', 0.25, function () {
+ $('#source-pre').fadeTo('fast', 1.0);
+ });
+ },
+ error: function (jqxhr, status, err) {
+ // Not worth alerting about because source fetch errors happen
+ // all the time, e.g. for dynamically evaluated code.
+
+ sourceFetchXhr = null;
+
+ // XXX: prevent retry of no-such-file by negative caching?
+ loadedFileName = fileName;
+ loadedLineCount = 1;
+ loadedFileExecuting = false;
+ setSourceText('// Cannot load source file: ' + fileName);
+ setSourceSelect(null);
+ loadedLinePending = 1;
+ activeLine = null;
+ activeHighlight = null;
+ doSourceUpdate();
+
+ // XXX: error transition here
+ $('#source-pre').fadeTo('fast', 0.25, function () {
+ $('#source-pre').fadeTo('fast', 1.0);
+ });
+ },
+ dataType: 'text'
+ });
+}
+
+/*
+ * AJAX request for fetching the source list
+ */
+
+function fetchSourceList() {
+ $.ajax({
+ type: 'POST',
+ url: '/sourceList',
+ data: JSON.stringify({}),
+ contentType: 'application/json',
+ success: function (data, status, jqxhr) {
+ var elem = $('#source-select');
+
+ data = JSON.parse(data);
+
+ elem.empty();
+ var opt = $('<option></option>').attr({ 'value': '__none__' }).text('No source file selected');
+ elem.append(opt);
+ data.forEach(function (ent) {
+ var opt = $('<option></option>').attr({ 'value': ent }).text(ent);
+ elem.append(opt);
+ });
+ elem.change(function () {
+ activeFileName = elem.val();
+ activeLine = 1;
+ requestSourceRefetch();
+ });
+ },
+ error: function (jqxhr, status, err) {
+ // This is worth alerting about as the UI is somewhat unusable
+ // if we don't get a source list.
+
+ alert('Failed to load source list: ' + err);
+ },
+ dataType: 'text'
+ });
+}
+
+/*
+ * Initialization
+ */
+
+$(document).ready(function () {
+ var showAbout = true;
+
+ // About dialog, shown automatically on first startup.
+ $('#about-dialog').dialog({
+ autoOpen: false,
+ hide: 'fade', // puff
+ show: 'fade', // slide, puff
+ width: 500,
+ height: 300
+ });
+
+ // Bytecode dialog
+ $('#bytecode-dialog').dialog({
+ autoOpen: false,
+ hide: 'fade', // puff
+ show: 'fade', // slide, puff
+ width: 700,
+ height: 600,
+ close: function () {
+ bytecodeDialogOpen = false;
+ bytecodeIdxHighlight = null;
+ bytecodeIdxInstr = 0;
+ }
+ });
+
+ // http://diveintohtml5.info/storage.html
+ if (typeof localStorage !== 'undefined') {
+ if (localStorage.getItem('about-shown')) {
+ showAbout = false;
+ } else {
+ localStorage.setItem('about-shown', 'yes');
+ }
+ }
+ if (showAbout) {
+ $('#about-dialog').dialog('open');
+ }
+
+ // onclick handler for exec status text
+ function loadCurrFunc() {
+ activeFileName = currFileName;
+ activeLine = currLine;
+ requestSourceRefetch();
+ }
+ $('#exec-other').on('click', loadCurrFunc);
+
+ // Enter handling for eval input
+ // https://forum.jquery.com/topic/bind-html-input-to-enter-key-keypress
+ $('#eval-input').keypress(function (event) {
+ if (event.keyCode == 13) {
+ submitEval();
+ $('#eval-input').val('');
+ }
+ });
+
+ // Eval watch handling
+ $('#eval-watch').change(function () {
+ // nop
+ });
+
+ forceButtonUpdate = true;
+ doUiUpdate();
+});