]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/third_party/duktape-1.8.0/debugger/static/webui.js
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / prometheus-cpp / 3rdparty / civetweb / src / third_party / duktape-1.8.0 / debugger / static / webui.js
1 /*
2 * Duktape debugger web client
3 *
4 * Talks to the NodeJS server using socket.io.
5 *
6 * http://unixpapa.com/js/key.html
7 */
8
9 // Update interval for custom source highlighting.
10 var SOURCE_UPDATE_INTERVAL = 350;
11
12 // Source view
13 var activeFileName = null; // file that we want to be loaded in source view
14 var activeLine = null; // scroll to line once file has been loaded
15 var activeHighlight = null; // line that we want to highlight (if any)
16 var loadedFileName = null; // currently loaded (shown) file
17 var loadedLineCount = 0; // currently loaded file line count
18 var loadedFileExecuting = false; // true if currFileName (loosely) matches loadedFileName
19 var loadedLinePending = null; // if set, scroll loaded file to requested line
20 var highlightLine = null; // highlight line
21 var sourceEditedLines = []; // line numbers which have been modified
22 // (added classes etc, tracked for removing)
23 var sourceUpdateInterval = null; // timer for updating source view
24 var sourceFetchXhr = null; // current AJAX request for fetching a source file (if any)
25 var forceButtonUpdate = false; // hack to reset button states
26 var bytecodeDialogOpen = false; // bytecode dialog active
27 var bytecodeIdxHighlight = null; // index of currently highlighted line (or null)
28 var bytecodeIdxInstr = 0; // index to first line of bytecode instructions
29
30 // Execution state
31 var prevState = null; // previous execution state ('paused', 'running', etc)
32 var prevAttached = null; // previous debugger attached state (true, false, null)
33 var currFileName = null; // current filename being executed
34 var currFuncName = null; // current function name being executed
35 var currLine = 0; // current line being executed
36 var currPc = 0; // current bytecode PC being executed
37 var currState = 0; // current execution state ('paused', 'running', 'detached', etc)
38 var currAttached = false; // current debugger attached state (true or false)
39 var currLocals = []; // current local variables
40 var currCallstack = []; // current callstack (from top to bottom)
41 var currBreakpoints = []; // current breakpoints
42 var startedRunning = 0; // timestamp when last started running (if running)
43 // (used to grey out the source file if running for long enough)
44
45 /*
46 * Helpers
47 */
48
49 function formatBytes(x) {
50 if (x < 1024) {
51 return String(x) + ' bytes';
52 } else if (x < 1024 * 1024) {
53 return (x / 1024).toPrecision(3) + ' kB';
54 } else {
55 return (x / (1024 * 1024)).toPrecision(3) + ' MB';
56 }
57 }
58
59 /*
60 * Source view periodic update handling
61 */
62
63 function doSourceUpdate() {
64 var elem;
65
66 // Remove previously added custom classes
67 sourceEditedLines.forEach(function (linenum) {
68 elem = $('#source-code div')[linenum - 1];
69 if (elem) {
70 elem.classList.remove('breakpoint');
71 elem.classList.remove('execution');
72 elem.classList.remove('highlight');
73 }
74 });
75 sourceEditedLines.length = 0;
76
77 // If we're executing the file shown, highlight current line
78 if (loadedFileExecuting) {
79 elem = $('#source-code div')[currLine - 1];
80 if (elem) {
81 sourceEditedLines.push(currLine);
82 elem.classList.add('execution');
83 }
84 }
85
86 // Add breakpoints
87 currBreakpoints.forEach(function (bp) {
88 if (bp.fileName === loadedFileName) {
89 elem = $('#source-code div')[bp.lineNumber - 1];
90 if (elem) {
91 sourceEditedLines.push(bp.lineNumber);
92 elem.classList.add('breakpoint');
93 }
94 }
95 });
96
97 if (highlightLine !== null) {
98 elem = $('#source-code div')[highlightLine - 1];
99 if (elem) {
100 sourceEditedLines.push(highlightLine);
101 elem.classList.add('highlight');
102 }
103 }
104
105 // Bytecode dialog highlight
106 if (loadedFileExecuting && bytecodeDialogOpen && bytecodeIdxHighlight !== bytecodeIdxInstr + currPc) {
107 if (typeof bytecodeIdxHighlight === 'number') {
108 $('#bytecode-preformatted div')[bytecodeIdxHighlight].classList.remove('highlight');
109 }
110 bytecodeIdxHighlight = bytecodeIdxInstr + currPc;
111 $('#bytecode-preformatted div')[bytecodeIdxHighlight].classList.add('highlight');
112 }
113
114 // If no-one requested us to scroll to a specific line, finish.
115 if (loadedLinePending == null) {
116 return;
117 }
118
119 var reqLine = loadedLinePending;
120 loadedLinePending = null;
121
122 // Scroll to requested line. This is not very clean, so a better solution
123 // should be found:
124 // https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollIntoView
125 // http://erraticdev.blogspot.fi/2011/02/jquery-scroll-into-view-plugin-with.html
126 // http://flesler.blogspot.fi/2007/10/jqueryscrollto.html
127 var tmpLine = Math.max(reqLine - 5, 0);
128 elem = $('#source-code div')[tmpLine];
129 if (elem) {
130 elem.scrollIntoView();
131 }
132 }
133
134 // Source is updated periodically. Other code can also call doSourceUpdate()
135 // directly if an immediate update is needed.
136 sourceUpdateInterval = setInterval(doSourceUpdate, SOURCE_UPDATE_INTERVAL);
137
138 /*
139 * UI update handling when exec-status update arrives
140 */
141
142 function doUiUpdate() {
143 var now = Date.now();
144
145 // Note: loadedFileName can be either from target or from server, but they
146 // must match exactly. We could do a loose match here, but exact matches
147 // are needed for proper breakpoint handling anyway.
148 loadedFileExecuting = (loadedFileName === currFileName);
149
150 // If we just started running, store a timestamp so we can grey out the
151 // source view only if we execute long enough (i.e. we're not just
152 // stepping).
153 if (currState !== prevState && currState === 'running') {
154 startedRunning = now;
155 }
156
157 // If we just became paused, check for eval watch
158 if (currState !== prevState && currState === 'paused') {
159 if ($('#eval-watch').is(':checked')) {
160 submitEval(); // don't clear eval input
161 }
162 }
163
164 // Update current execution state
165 if (currFileName === '' && currLine === 0) {
166 $('#current-fileline').text('');
167 } else {
168 $('#current-fileline').text(String(currFileName) + ':' + String(currLine));
169 }
170 if (currFuncName === '' && currPc === 0) {
171 $('#current-funcpc').text('');
172 } else {
173 $('#current-funcpc').text(String(currFuncName) + '() pc ' + String(currPc));
174 }
175 $('#current-state').text(String(currState));
176
177 // Update buttons
178 if (currState !== prevState || currAttached !== prevAttached || forceButtonUpdate) {
179 $('#stepinto-button').prop('disabled', !currAttached || currState !== 'paused');
180 $('#stepover-button').prop('disabled', !currAttached || currState !== 'paused');
181 $('#stepout-button').prop('disabled', !currAttached || currState !== 'paused');
182 $('#resume-button').prop('disabled', !currAttached || currState !== 'paused');
183 $('#pause-button').prop('disabled', !currAttached || currState !== 'running');
184 $('#attach-button').prop('disabled', currAttached);
185 if (currAttached) {
186 $('#attach-button').removeClass('enabled');
187 } else {
188 $('#attach-button').addClass('enabled');
189 }
190 $('#detach-button').prop('disabled', !currAttached);
191 $('#eval-button').prop('disabled', !currAttached);
192 $('#add-breakpoint-button').prop('disabled', !currAttached);
193 $('#delete-all-breakpoints-button').prop('disabled', !currAttached);
194 $('.delete-breakpoint-button').prop('disabled', !currAttached);
195 $('#putvar-button').prop('disabled', !currAttached);
196 $('#getvar-button').prop('disabled', !currAttached);
197 $('#heap-dump-download-button').prop('disabled', !currAttached);
198 }
199 if (currState !== 'running' || forceButtonUpdate) {
200 // Remove pending highlight once we're no longer running.
201 $('#pause-button').removeClass('pending');
202 $('#eval-button').removeClass('pending');
203 }
204 forceButtonUpdate = false;
205
206 // Make source window grey when running for a longer time, use a small
207 // delay to avoid flashing grey when stepping.
208 if (currState === 'running' && now - startedRunning >= 500) {
209 $('#source-pre').removeClass('notrunning');
210 $('#current-state').removeClass('notrunning');
211 } else {
212 $('#source-pre').addClass('notrunning');
213 $('#current-state').addClass('notrunning');
214 }
215
216 // Force source view to match currFileName only when running or when
217 // just became paused (from running or detached).
218 var fetchSource = false;
219 if (typeof currFileName === 'string') {
220 if (currState === 'running' ||
221 (prevState !== 'paused' && currState === 'paused') ||
222 (currAttached !== prevAttached)) {
223 if (activeFileName !== currFileName) {
224 fetchSource = true;
225 activeFileName = currFileName;
226 activeLine = currLine;
227 activeHighlight = null;
228 requestSourceRefetch();
229 }
230 }
231 }
232
233 // Force line update (scrollTop) only when running or just became paused.
234 // Otherwise let user browse and scroll source files freely.
235 if (!fetchSource) {
236 if ((prevState !== 'paused' && currState === 'paused') ||
237 currState === 'running') {
238 loadedLinePending = currLine || 0;
239 }
240 }
241 }
242
243 /*
244 * Init socket.io and add handlers
245 */
246
247 var socket = io(); // returns a Manager
248
249 setInterval(function () {
250 socket.emit('keepalive', {
251 userAgent: (navigator || {}).userAgent
252 });
253 }, 30000);
254
255 socket.on('connect', function () {
256 $('#socketio-info').text('connected');
257 currState = 'connected';
258
259 fetchSourceList();
260 });
261 socket.on('disconnect', function () {
262 $('#socketio-info').text('not connected');
263 currState = 'disconnected';
264 });
265 socket.on('reconnecting', function () {
266 $('#socketio-info').text('reconnecting');
267 currState = 'reconnecting';
268 });
269 socket.on('error', function (err) {
270 $('#socketio-info').text(err);
271 });
272
273 socket.on('replaced', function () {
274 // XXX: how to minimize the chance we'll further communciate with the
275 // server or reconnect to it? socket.reconnection()?
276
277 // We'd like to window.close() here but can't (not allowed from scripts).
278 // Alert is the next best thing.
279 alert('Debugger connection replaced by a new one, do you have multiple tabs open? If so, please close this tab.');
280 });
281
282 socket.on('keepalive', function (msg) {
283 // Not really interesting in the UI
284 // $('#server-info').text(new Date() + ': ' + JSON.stringify(msg));
285 });
286
287 socket.on('basic-info', function (msg) {
288 $('#duk-version').text(String(msg.duk_version));
289 $('#duk-git-describe').text(String(msg.duk_git_describe));
290 $('#target-info').text(String(msg.target_info));
291 $('#endianness').text(String(msg.endianness));
292 });
293
294 socket.on('exec-status', function (msg) {
295 // Not 100% reliable if callstack has several functions of the same name
296 if (bytecodeDialogOpen && (currFileName != msg.fileName || currFuncName != msg.funcName)) {
297 socket.emit('get-bytecode', {});
298 }
299
300 currFileName = msg.fileName;
301 currFuncName = msg.funcName;
302 currLine = msg.line;
303 currPc = msg.pc;
304 currState = msg.state;
305 currAttached = msg.attached;
306
307 // Duktape now restricts execution status updates quite effectively so
308 // there's no need to rate limit UI updates now.
309
310 doUiUpdate();
311
312 prevState = currState;
313 prevAttached = currAttached;
314 });
315
316 // Update the "console" output based on lines sent by the server. The server
317 // rate limits these updates to keep the browser load under control. Even
318 // better would be for the client to pull this (and other stuff) on its own.
319 socket.on('output-lines', function (msg) {
320 var elem = $('#output');
321 var i, n, ent;
322
323 elem.empty();
324 for (i = 0, n = msg.length; i < n; i++) {
325 ent = msg[i];
326 if (ent.type === 'print') {
327 elem.append($('<div></div>').text(ent.message));
328 } else if (ent.type === 'alert') {
329 elem.append($('<div class="alert"></div>').text(ent.message));
330 } else if (ent.type === 'log') {
331 elem.append($('<div class="log loglevel' + ent.level + '"></div>').text(ent.message));
332 } else if (ent.type === 'debugger-info') {
333 elem.append($('<div class="debugger-info"><div>').text(ent.message));
334 } else if (ent.type === 'debugger-debug') {
335 elem.append($('<div class="debugger-debug"><div>').text(ent.message));
336 } else {
337 elem.append($('<div></div>').text(ent.message));
338 }
339 }
340
341 // http://stackoverflow.com/questions/14918787/jquery-scroll-to-bottom-of-div-even-after-it-updates
342 // Stop queued animations so that we always scroll quickly to bottom
343 $('#output').stop(true);
344 $('#output').animate({ scrollTop: $('#output')[0].scrollHeight}, 1000);
345 });
346
347 socket.on('callstack', function (msg) {
348 var elem = $('#callstack');
349 var s1, s2, div;
350
351 currCallstack = msg.callstack;
352
353 elem.empty();
354 msg.callstack.forEach(function (e) {
355 s1 = $('<a class="rest"></a>').text(e.fileName + ':' + e.lineNumber + ' (pc ' + e.pc + ')'); // float
356 s1.on('click', function () {
357 activeFileName = e.fileName;
358 activeLine = e.lineNumber || 1;
359 activeHighlight = activeLine;
360 requestSourceRefetch();
361 });
362 s2 = $('<span class="func"></span>').text(e.funcName + '()');
363 div = $('<div></div>');
364 div.append(s1);
365 div.append(s2);
366 elem.append(div);
367 });
368 });
369
370 socket.on('locals', function (msg) {
371 var elem = $('#locals');
372 var s1, s2, div;
373 var i, n, e;
374
375 currLocals = msg.locals;
376
377 elem.empty();
378 for (i = 0, n = msg.locals.length; i < n; i++) {
379 e = msg.locals[i];
380 s1 = $('<span class="value"></span>').text(e.value); // float
381 s2 = $('<span class="key"></span>').text(e.key);
382 div = $('<div></div>');
383 div.append(s1);
384 div.append(s2);
385 elem.append(div);
386 }
387 });
388
389 socket.on('debug-stats', function (msg) {
390 $('#debug-rx-bytes').text(formatBytes(msg.rxBytes));
391 $('#debug-rx-dvalues').text(msg.rxDvalues);
392 $('#debug-rx-messages').text(msg.rxMessages);
393 $('#debug-rx-kbrate').text((msg.rxBytesPerSec / 1024).toFixed(2));
394 $('#debug-tx-bytes').text(formatBytes(msg.txBytes));
395 $('#debug-tx-dvalues').text(msg.txDvalues);
396 $('#debug-tx-messages').text(msg.txMessages);
397 $('#debug-tx-kbrate').text((msg.txBytesPerSec / 1024).toFixed(2));
398 });
399
400 socket.on('breakpoints', function (msg) {
401 var elem = $('#breakpoints');
402 var div;
403 var sub;
404
405 currBreakpoints = msg.breakpoints;
406
407 elem.empty();
408
409 // First line is special
410 div = $('<div></div>');
411 sub = $('<button id="delete-all-breakpoints-button"></button>').text('Delete all breakpoints');
412 sub.on('click', function () {
413 socket.emit('delete-all-breakpoints');
414 });
415 div.append(sub);
416 sub = $('<input id="add-breakpoint-file"></input>').val('file.js');
417 div.append(sub);
418 sub = $('<span></span>').text(':');
419 div.append(sub);
420 sub = $('<input id="add-breakpoint-line"></input>').val('123');
421 div.append(sub);
422 sub = $('<button id="add-breakpoint-button"></button>').text('Add breakpoint');
423 sub.on('click', function () {
424 socket.emit('add-breakpoint', {
425 fileName: $('#add-breakpoint-file').val(),
426 lineNumber: Number($('#add-breakpoint-line').val())
427 });
428 });
429 div.append(sub);
430 sub = $('<span id="breakpoint-hint"></span>').text('or dblclick source');
431 div.append(sub);
432 elem.append(div);
433
434 // Active breakpoints follow
435 msg.breakpoints.forEach(function (bp) {
436 var div;
437 var sub;
438
439 div = $('<div class="breakpoint-line"></div>');
440 sub = $('<button class="delete-breakpoint-button"></button>').text('Delete');
441 sub.on('click', function () {
442 socket.emit('delete-breakpoint', {
443 fileName: bp.fileName,
444 lineNumber: bp.lineNumber
445 });
446 });
447 div.append(sub);
448 sub = $('<a></a>').text((bp.fileName || '?') + ':' + (bp.lineNumber || 0));
449 sub.on('click', function () {
450 activeFileName = bp.fileName || '';
451 activeLine = bp.lineNumber || 1;
452 activeHighlight = activeLine;
453 requestSourceRefetch();
454 });
455 div.append(sub);
456 elem.append(div);
457 });
458
459 forceButtonUpdate = true;
460 doUiUpdate();
461 });
462
463 socket.on('eval-result', function (msg) {
464 $('#eval-output').text((msg.error ? 'ERROR: ' : '') + msg.result);
465
466 // Remove eval button "pulsating" glow when we get a result
467 $('#eval-button').removeClass('pending');
468 });
469
470 socket.on('getvar-result', function (msg) {
471 $('#var-output').text(msg.found ? msg.result : 'NOTFOUND');
472 });
473
474 socket.on('bytecode', function (msg) {
475 var elem, div;
476 var div;
477
478 elem = $('#bytecode-preformatted');
479 elem.empty();
480
481 msg.preformatted.split('\n').forEach(function (line, idx) {
482 div = $('<div></div>');
483 div.text(line);
484 elem.append(div);
485 });
486
487 bytecodeIdxHighlight = null;
488 bytecodeIdxInstr = msg.idxPreformattedInstructions;
489 });
490
491 $('#stepinto-button').click(function () {
492 socket.emit('stepinto', {});
493 });
494
495 $('#stepover-button').click(function () {
496 socket.emit('stepover', {});
497 });
498
499 $('#stepout-button').click(function () {
500 socket.emit('stepout', {});
501 });
502
503 $('#pause-button').click(function () {
504 socket.emit('pause', {});
505
506 // Pause may take seconds to complete so indicate it is pending.
507 $('#pause-button').addClass('pending');
508 });
509
510 $('#resume-button').click(function () {
511 socket.emit('resume', {});
512 });
513
514 $('#attach-button').click(function () {
515 socket.emit('attach', {});
516 });
517
518 $('#detach-button').click(function () {
519 socket.emit('detach', {});
520 });
521
522 $('#about-button').click(function () {
523 $('#about-dialog').dialog('open');
524 });
525
526 $('#show-bytecode-button').click(function () {
527 bytecodeDialogOpen = true;
528 $('#bytecode-dialog').dialog('open');
529
530 elem = $('#bytecode-preformatted');
531 elem.empty().text('Loading bytecode...');
532
533 socket.emit('get-bytecode', {});
534 });
535
536 function submitEval() {
537 socket.emit('eval', { input: $('#eval-input').val() });
538
539 // Eval may take seconds to complete so indicate it is pending.
540 $('#eval-button').addClass('pending');
541 }
542
543 $('#eval-button').click(function () {
544 submitEval();
545 $('#eval-input').val('');
546 });
547
548 $('#getvar-button').click(function () {
549 socket.emit('getvar', { varname: $('#varname-input').val() });
550 });
551
552 $('#putvar-button').click(function () {
553 // The variable value is parsed as JSON right now, but it'd be better to
554 // also be able to parse buffer values etc.
555 var val = JSON.parse($('#varvalue-input').val());
556 socket.emit('putvar', { varname: $('#varname-input').val(), varvalue: val });
557 });
558
559 $('#source-code').dblclick(function (event) {
560 var target = event.target;
561 var elems = $('#source-code div');
562 var i, n;
563 var line = 0;
564
565 // XXX: any faster way; elems doesn't have e.g. indexOf()
566 for (i = 0, n = elems.length; i < n; i++) {
567 if (target === elems[i]) {
568 line = i + 1;
569 }
570 }
571
572 socket.emit('toggle-breakpoint', {
573 fileName: loadedFileName,
574 lineNumber: line
575 });
576 });
577
578 function setSourceText(data) {
579 var elem, div;
580
581 elem = $('#source-code');
582 elem.empty();
583 data.split('\n').forEach(function (line) {
584 div = $('<div></div>');
585 div.text(line);
586 elem.append(div);
587 });
588
589 sourceEditedLines = [];
590 }
591
592 function setSourceSelect(fileName) {
593 var elem;
594 var i, n, t;
595
596 if (fileName == null) {
597 $('#source-select').val('__none__');
598 return;
599 }
600
601 elem = $('#source-select option');
602 for (i = 0, n = elem.length; i < n; i++) {
603 // Exact match is required.
604 t = $(elem[i]).val();
605 if (t === fileName) {
606 $('#source-select').val(t);
607 return;
608 }
609 }
610 }
611
612 /*
613 * AJAX request handling to fetch source files
614 */
615
616 function requestSourceRefetch() {
617 // If previous update is pending, abort and start a new one.
618 if (sourceFetchXhr) {
619 sourceFetchXhr.abort();
620 sourceFetchXhr = null;
621 }
622
623 // Make copies of the requested file/line so that we have the proper
624 // values in case they've changed.
625 var fileName = activeFileName;
626 var lineNumber = activeLine;
627
628 // AJAX request for the source.
629 sourceFetchXhr = $.ajax({
630 type: 'POST',
631 url: '/source',
632 data: JSON.stringify({ fileName: fileName }),
633 contentType: 'application/json',
634 success: function (data, status, jqxhr) {
635 var elem;
636
637 sourceFetchXhr = null;
638
639 loadedFileName = fileName;
640 loadedLineCount = data.split('\n').length; // XXX: ignore issue with last empty line for now
641 loadedFileExecuting = (loadedFileName === currFileName);
642 setSourceText(data);
643 setSourceSelect(fileName);
644 loadedLinePending = activeLine || 1;
645 highlightLine = activeHighlight; // may be null
646 activeLine = null;
647 activeHighlight = null;
648 doSourceUpdate();
649
650 // XXX: hacky transition, make source change visible
651 $('#source-pre').fadeTo('fast', 0.25, function () {
652 $('#source-pre').fadeTo('fast', 1.0);
653 });
654 },
655 error: function (jqxhr, status, err) {
656 // Not worth alerting about because source fetch errors happen
657 // all the time, e.g. for dynamically evaluated code.
658
659 sourceFetchXhr = null;
660
661 // XXX: prevent retry of no-such-file by negative caching?
662 loadedFileName = fileName;
663 loadedLineCount = 1;
664 loadedFileExecuting = false;
665 setSourceText('// Cannot load source file: ' + fileName);
666 setSourceSelect(null);
667 loadedLinePending = 1;
668 activeLine = null;
669 activeHighlight = null;
670 doSourceUpdate();
671
672 // XXX: error transition here
673 $('#source-pre').fadeTo('fast', 0.25, function () {
674 $('#source-pre').fadeTo('fast', 1.0);
675 });
676 },
677 dataType: 'text'
678 });
679 }
680
681 /*
682 * AJAX request for fetching the source list
683 */
684
685 function fetchSourceList() {
686 $.ajax({
687 type: 'POST',
688 url: '/sourceList',
689 data: JSON.stringify({}),
690 contentType: 'application/json',
691 success: function (data, status, jqxhr) {
692 var elem = $('#source-select');
693
694 data = JSON.parse(data);
695
696 elem.empty();
697 var opt = $('<option></option>').attr({ 'value': '__none__' }).text('No source file selected');
698 elem.append(opt);
699 data.forEach(function (ent) {
700 var opt = $('<option></option>').attr({ 'value': ent }).text(ent);
701 elem.append(opt);
702 });
703 elem.change(function () {
704 activeFileName = elem.val();
705 activeLine = 1;
706 requestSourceRefetch();
707 });
708 },
709 error: function (jqxhr, status, err) {
710 // This is worth alerting about as the UI is somewhat unusable
711 // if we don't get a source list.
712
713 alert('Failed to load source list: ' + err);
714 },
715 dataType: 'text'
716 });
717 }
718
719 /*
720 * Initialization
721 */
722
723 $(document).ready(function () {
724 var showAbout = true;
725
726 // About dialog, shown automatically on first startup.
727 $('#about-dialog').dialog({
728 autoOpen: false,
729 hide: 'fade', // puff
730 show: 'fade', // slide, puff
731 width: 500,
732 height: 300
733 });
734
735 // Bytecode dialog
736 $('#bytecode-dialog').dialog({
737 autoOpen: false,
738 hide: 'fade', // puff
739 show: 'fade', // slide, puff
740 width: 700,
741 height: 600,
742 close: function () {
743 bytecodeDialogOpen = false;
744 bytecodeIdxHighlight = null;
745 bytecodeIdxInstr = 0;
746 }
747 });
748
749 // http://diveintohtml5.info/storage.html
750 if (typeof localStorage !== 'undefined') {
751 if (localStorage.getItem('about-shown')) {
752 showAbout = false;
753 } else {
754 localStorage.setItem('about-shown', 'yes');
755 }
756 }
757 if (showAbout) {
758 $('#about-dialog').dialog('open');
759 }
760
761 // onclick handler for exec status text
762 function loadCurrFunc() {
763 activeFileName = currFileName;
764 activeLine = currLine;
765 requestSourceRefetch();
766 }
767 $('#exec-other').on('click', loadCurrFunc);
768
769 // Enter handling for eval input
770 // https://forum.jquery.com/topic/bind-html-input-to-enter-key-keypress
771 $('#eval-input').keypress(function (event) {
772 if (event.keyCode == 13) {
773 submitEval();
774 $('#eval-input').val('');
775 }
776 });
777
778 // Eval watch handling
779 $('#eval-watch').change(function () {
780 // nop
781 });
782
783 forceButtonUpdate = true;
784 doUiUpdate();
785 });