go.tools/cmd/godoc: add godocs.js and playground.js from core repo
The originals will be removed. R=golang-dev, r CC=golang-dev https://golang.org/cl/12219043
This commit is contained in:
parent
a705311956
commit
0afeff2d4b
|
|
@ -85,9 +85,9 @@ and code is licensed under a <a href="/LICENSE">BSD license</a>.<br>
|
||||||
|
|
||||||
<script type="text/javascript" src="/doc/jquery.js"></script>
|
<script type="text/javascript" src="/doc/jquery.js"></script>
|
||||||
{{if .Playground}}
|
{{if .Playground}}
|
||||||
<script type="text/javascript" src="/doc/play/playground.js"></script>
|
<script type="text/javascript" src="/lib/godoc/playground.js"></script>
|
||||||
{{end}}
|
{{end}}
|
||||||
<script type="text/javascript" src="/doc/godocs.js"></script>
|
<script type="text/javascript" src="/lib/godoc/godocs.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,266 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/* A little code to ease navigation of these documents.
|
||||||
|
*
|
||||||
|
* On window load we:
|
||||||
|
* + Bind search box hint placeholder show/hide events (bindSearchEvents)
|
||||||
|
* + Generate a table of contents (generateTOC)
|
||||||
|
* + Bind foldable sections (bindToggles)
|
||||||
|
* + Bind links to foldable sections (bindToggleLinks)
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function bindSearchEvents() {
|
||||||
|
|
||||||
|
var search = $('#search');
|
||||||
|
if (search.length === 0) {
|
||||||
|
return; // no search box
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearInactive() {
|
||||||
|
if (search.is('.inactive')) {
|
||||||
|
search.val('');
|
||||||
|
search.removeClass('inactive');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreInactive() {
|
||||||
|
if (search.val() !== '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
search.val(search.attr('placeholder'));
|
||||||
|
search.addClass('inactive');
|
||||||
|
}
|
||||||
|
|
||||||
|
search.on('focus', clearInactive);
|
||||||
|
search.on('blur', restoreInactive);
|
||||||
|
|
||||||
|
restoreInactive();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generates a table of contents: looks for h2 and h3 elements and generates
|
||||||
|
* links. "Decorates" the element with id=="nav" with this table of contents.
|
||||||
|
*/
|
||||||
|
function generateTOC() {
|
||||||
|
if ($('#manual-nav').length > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nav = $('#nav');
|
||||||
|
if (nav.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var toc_items = [];
|
||||||
|
$(nav).nextAll('h2, h3').each(function() {
|
||||||
|
var node = this;
|
||||||
|
if (node.id == '')
|
||||||
|
node.id = 'tmp_' + toc_items.length;
|
||||||
|
var link = $('<a/>').attr('href', '#' + node.id).text($(node).text());
|
||||||
|
var item;
|
||||||
|
if ($(node).is('h2')) {
|
||||||
|
item = $('<dt/>');
|
||||||
|
} else { // h3
|
||||||
|
item = $('<dd/>');
|
||||||
|
}
|
||||||
|
item.append(link);
|
||||||
|
toc_items.push(item);
|
||||||
|
});
|
||||||
|
if (toc_items.length <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dl1 = $('<dl/>');
|
||||||
|
var dl2 = $('<dl/>');
|
||||||
|
|
||||||
|
var split_index = (toc_items.length / 2) + 1;
|
||||||
|
if (split_index < 8) {
|
||||||
|
split_index = toc_items.length;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < split_index; i++) {
|
||||||
|
dl1.append(toc_items[i]);
|
||||||
|
}
|
||||||
|
for (/* keep using i */; i < toc_items.length; i++) {
|
||||||
|
dl2.append(toc_items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tocTable = $('<table class="unruled"/>').appendTo(nav);
|
||||||
|
var tocBody = $('<tbody/>').appendTo(tocTable);
|
||||||
|
var tocRow = $('<tr/>').appendTo(tocBody);
|
||||||
|
|
||||||
|
// 1st column
|
||||||
|
$('<td class="first"/>').appendTo(tocRow).append(dl1);
|
||||||
|
// 2nd column
|
||||||
|
$('<td/>').appendTo(tocRow).append(dl2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindToggle(el) {
|
||||||
|
$('.toggleButton', el).click(function() {
|
||||||
|
if ($(el).is('.toggle')) {
|
||||||
|
$(el).addClass('toggleVisible').removeClass('toggle');
|
||||||
|
} else {
|
||||||
|
$(el).addClass('toggle').removeClass('toggleVisible');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function bindToggles(selector) {
|
||||||
|
$(selector).each(function(i, el) {
|
||||||
|
bindToggle(el);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindToggleLink(el, prefix) {
|
||||||
|
$(el).click(function() {
|
||||||
|
var href = $(el).attr('href');
|
||||||
|
var i = href.indexOf('#'+prefix);
|
||||||
|
if (i < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var id = '#' + prefix + href.slice(i+1+prefix.length);
|
||||||
|
if ($(id).is('.toggle')) {
|
||||||
|
$(id).find('.toggleButton').first().click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function bindToggleLinks(selector, prefix) {
|
||||||
|
$(selector).each(function(i, el) {
|
||||||
|
bindToggleLink(el, prefix);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupDropdownPlayground() {
|
||||||
|
if (!$('#page').is('.wide')) {
|
||||||
|
return; // don't show on front page
|
||||||
|
}
|
||||||
|
var button = $('#playgroundButton');
|
||||||
|
var div = $('#playground');
|
||||||
|
var setup = false;
|
||||||
|
button.toggle(function() {
|
||||||
|
button.addClass('active');
|
||||||
|
div.show();
|
||||||
|
if (setup) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setup = true;
|
||||||
|
playground({
|
||||||
|
'codeEl': $('.code', div),
|
||||||
|
'outputEl': $('.output', div),
|
||||||
|
'runEl': $('.run', div),
|
||||||
|
'fmtEl': $('.fmt', div),
|
||||||
|
'shareEl': $('.share', div),
|
||||||
|
'shareRedirect': 'http://play.golang.org/p/'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
button.removeClass('active');
|
||||||
|
div.hide();
|
||||||
|
});
|
||||||
|
button.show();
|
||||||
|
$('#menu').css('min-width', '+=60');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupInlinePlayground() {
|
||||||
|
'use strict';
|
||||||
|
// Set up playground when each element is toggled.
|
||||||
|
$('div.play').each(function (i, el) {
|
||||||
|
// Set up playground for this example.
|
||||||
|
var setup = function() {
|
||||||
|
var code = $('.code', el);
|
||||||
|
playground({
|
||||||
|
'codeEl': code,
|
||||||
|
'outputEl': $('.output', el),
|
||||||
|
'runEl': $('.run', el),
|
||||||
|
'fmtEl': $('.fmt', el),
|
||||||
|
'shareEl': $('.share', el),
|
||||||
|
'shareRedirect': 'http://play.golang.org/p/'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make the code textarea resize to fit content.
|
||||||
|
var resize = function() {
|
||||||
|
code.height(0);
|
||||||
|
var h = code[0].scrollHeight;
|
||||||
|
code.height(h+20); // minimize bouncing.
|
||||||
|
code.closest('.input').height(h);
|
||||||
|
};
|
||||||
|
code.on('keydown', resize);
|
||||||
|
code.on('keyup', resize);
|
||||||
|
code.keyup(); // resize now.
|
||||||
|
};
|
||||||
|
|
||||||
|
// If example already visible, set up playground now.
|
||||||
|
if ($(el).is(':visible')) {
|
||||||
|
setup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, set up playground when example is expanded.
|
||||||
|
var built = false;
|
||||||
|
$(el).closest('.toggle').click(function() {
|
||||||
|
// Only set up once.
|
||||||
|
if (!built) {
|
||||||
|
setup();
|
||||||
|
built = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixFocus tries to put focus to div#page so that keyboard navigation works.
|
||||||
|
function fixFocus() {
|
||||||
|
var page = $('div#page');
|
||||||
|
var topbar = $('div#topbar');
|
||||||
|
page.css('outline', 0); // disable outline when focused
|
||||||
|
page.attr('tabindex', -1); // and set tabindex so that it is focusable
|
||||||
|
$(window).resize(function (evt) {
|
||||||
|
// only focus page when the topbar is at fixed position (that is, it's in
|
||||||
|
// front of page, and keyboard event will go to the former by default.)
|
||||||
|
// by focusing page, keyboard event will go to page so that up/down arrow,
|
||||||
|
// space, etc. will work as expected.
|
||||||
|
if (topbar.css('position') == "fixed")
|
||||||
|
page.focus();
|
||||||
|
}).resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleHash() {
|
||||||
|
var hash = $(window.location.hash);
|
||||||
|
if (hash.is('.toggle')) {
|
||||||
|
hash.find('.toggleButton').first().click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPlusButtons() {
|
||||||
|
var po = document.createElement('script');
|
||||||
|
po.type = 'text/javascript';
|
||||||
|
po.async = true;
|
||||||
|
po.src = 'https://apis.google.com/js/plusone.js';
|
||||||
|
var s = document.getElementsByTagName('script')[0];
|
||||||
|
s.parentNode.insertBefore(po, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
bindSearchEvents();
|
||||||
|
generateTOC();
|
||||||
|
bindToggles(".toggle");
|
||||||
|
bindToggles(".toggleVisible");
|
||||||
|
bindToggleLinks(".exampleLink", "example_");
|
||||||
|
bindToggleLinks(".overviewLink", "");
|
||||||
|
bindToggleLinks(".examplesLink", "");
|
||||||
|
bindToggleLinks(".indexLink", "");
|
||||||
|
setupDropdownPlayground();
|
||||||
|
setupInlinePlayground();
|
||||||
|
fixFocus();
|
||||||
|
toggleHash();
|
||||||
|
addPlusButtons();
|
||||||
|
|
||||||
|
// godoc.html defines window.initFuncs in the <head> tag, and root.html and
|
||||||
|
// codewalk.js push their on-page-ready functions to the list.
|
||||||
|
// We execute those functions here, to avoid loading jQuery until the page
|
||||||
|
// content is loaded.
|
||||||
|
for (var i = 0; i < window.initFuncs.length; i++) window.initFuncs[i]();
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,428 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This is a copy of present/js/playground.js from the repository at
|
||||||
|
// https://code.google.com/p/go.talks
|
||||||
|
// Please make changes to that repository.
|
||||||
|
|
||||||
|
/*
|
||||||
|
In the absence of any formal way to specify interfaces in JavaScript,
|
||||||
|
here's a skeleton implementation of a playground transport.
|
||||||
|
|
||||||
|
function Transport() {
|
||||||
|
// Set up any transport state (eg, make a websocket connnection).
|
||||||
|
return {
|
||||||
|
Run: function(body, output, options) {
|
||||||
|
// Compile and run the program 'body' with 'options'.
|
||||||
|
// Call the 'output' callback to display program output.
|
||||||
|
return {
|
||||||
|
Kill: function() {
|
||||||
|
// Kill the running program.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// The output callback is called multiple times, and each time it is
|
||||||
|
// passed an object of this form.
|
||||||
|
var write = {
|
||||||
|
Kind: 'string', // 'start', 'stdout', 'stderr', 'end'
|
||||||
|
Body: 'string' // content of write or end status message
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first call must be of Kind 'start' with no body.
|
||||||
|
// Subsequent calls may be of Kind 'stdout' or 'stderr'
|
||||||
|
// and must have a non-null Body string.
|
||||||
|
// The final call should be of Kind 'end' with an optional
|
||||||
|
// Body string, signifying a failure ("killed", for example).
|
||||||
|
|
||||||
|
// The output callback must be of this form.
|
||||||
|
// See PlaygroundOutput (below) for an implementation.
|
||||||
|
function outputCallback(write) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function HTTPTransport() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// TODO(adg): support stderr
|
||||||
|
|
||||||
|
function playback(output, events) {
|
||||||
|
var timeout;
|
||||||
|
output({Kind: 'start'});
|
||||||
|
function next() {
|
||||||
|
if (events.length === 0) {
|
||||||
|
output({Kind: 'end'});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var e = events.shift();
|
||||||
|
if (e.Delay === 0) {
|
||||||
|
output({Kind: 'stdout', Body: e.Message});
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timeout = setTimeout(function() {
|
||||||
|
output({Kind: 'stdout', Body: e.Message});
|
||||||
|
next();
|
||||||
|
}, e.Delay / 1000000);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
return {
|
||||||
|
Stop: function() {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function error(output, msg) {
|
||||||
|
output({Kind: 'start'});
|
||||||
|
output({Kind: 'stderr', Body: msg});
|
||||||
|
output({Kind: 'end'});
|
||||||
|
}
|
||||||
|
|
||||||
|
var seq = 0;
|
||||||
|
return {
|
||||||
|
Run: function(body, output, options) {
|
||||||
|
seq++;
|
||||||
|
var cur = seq;
|
||||||
|
var playing;
|
||||||
|
$.ajax('/compile', {
|
||||||
|
type: 'POST',
|
||||||
|
data: {'version': 2, 'body': body},
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(data) {
|
||||||
|
if (seq != cur) return;
|
||||||
|
if (!data) return;
|
||||||
|
if (playing != null) playing.Stop();
|
||||||
|
if (data.Errors) {
|
||||||
|
error(output, data.Errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
playing = playback(output, data.Events);
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
error(output, 'Error communicating with remote server.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
Kill: function() {
|
||||||
|
if (playing != null) playing.Stop();
|
||||||
|
output({Kind: 'end', Body: 'killed'});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function SocketTransport() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var id = 0;
|
||||||
|
var outputs = {};
|
||||||
|
var started = {};
|
||||||
|
var websocket = new WebSocket('ws://' + window.location.host + '/socket');
|
||||||
|
|
||||||
|
websocket.onclose = function() {
|
||||||
|
console.log('websocket connection closed');
|
||||||
|
}
|
||||||
|
|
||||||
|
websocket.onmessage = function(e) {
|
||||||
|
var m = JSON.parse(e.data);
|
||||||
|
var output = outputs[m.Id];
|
||||||
|
if (output === null)
|
||||||
|
return;
|
||||||
|
if (!started[m.Id]) {
|
||||||
|
output({Kind: 'start'});
|
||||||
|
started[m.Id] = true;
|
||||||
|
}
|
||||||
|
output({Kind: m.Kind, Body: m.Body});
|
||||||
|
}
|
||||||
|
|
||||||
|
function send(m) {
|
||||||
|
websocket.send(JSON.stringify(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
Run: function(body, output, options) {
|
||||||
|
var thisID = id+'';
|
||||||
|
id++;
|
||||||
|
outputs[thisID] = output;
|
||||||
|
send({Id: thisID, Kind: 'run', Body: body, Options: options});
|
||||||
|
return {
|
||||||
|
Kill: function() {
|
||||||
|
send({Id: thisID, Kind: 'kill'});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function PlaygroundOutput(el) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return function(write) {
|
||||||
|
if (write.Kind == 'start') {
|
||||||
|
el.innerHTML = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cl = 'system';
|
||||||
|
if (write.Kind == 'stdout' || write.Kind == 'stderr')
|
||||||
|
cl = write.Kind;
|
||||||
|
|
||||||
|
var m = write.Body;
|
||||||
|
if (write.Kind == 'end')
|
||||||
|
m = '\nProgram exited' + (m?(': '+m):'.');
|
||||||
|
|
||||||
|
if (m.indexOf('IMAGE:') === 0) {
|
||||||
|
// TODO(adg): buffer all writes before creating image
|
||||||
|
var url = 'data:image/png;base64,' + m.substr(6);
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.src = url;
|
||||||
|
el.appendChild(img);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ^L clears the screen.
|
||||||
|
var s = m.split('\x0c');
|
||||||
|
if (s.length > 1) {
|
||||||
|
el.innerHTML = '';
|
||||||
|
m = s.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
m = m.replace(/&/g, '&');
|
||||||
|
m = m.replace(/</g, '<');
|
||||||
|
m = m.replace(/>/g, '>');
|
||||||
|
|
||||||
|
var needScroll = (el.scrollTop + el.offsetHeight) == el.scrollHeight;
|
||||||
|
|
||||||
|
var span = document.createElement('span');
|
||||||
|
span.className = cl;
|
||||||
|
span.innerHTML = m;
|
||||||
|
el.appendChild(span);
|
||||||
|
|
||||||
|
if (needScroll)
|
||||||
|
el.scrollTop = el.scrollHeight - el.offsetHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
function lineHighlight(error) {
|
||||||
|
var regex = /prog.go:([0-9]+)/g;
|
||||||
|
var r = regex.exec(error);
|
||||||
|
while (r) {
|
||||||
|
$(".lines div").eq(r[1]-1).addClass("lineerror");
|
||||||
|
r = regex.exec(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function highlightOutput(wrappedOutput) {
|
||||||
|
return function(write) {
|
||||||
|
if (write.Body) lineHighlight(write.Body);
|
||||||
|
wrappedOutput(write);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function lineClear() {
|
||||||
|
$(".lineerror").removeClass("lineerror");
|
||||||
|
}
|
||||||
|
|
||||||
|
// opts is an object with these keys
|
||||||
|
// codeEl - code editor element
|
||||||
|
// outputEl - program output element
|
||||||
|
// runEl - run button element
|
||||||
|
// fmtEl - fmt button element (optional)
|
||||||
|
// shareEl - share button element (optional)
|
||||||
|
// shareURLEl - share URL text input element (optional)
|
||||||
|
// shareRedirect - base URL to redirect to on share (optional)
|
||||||
|
// toysEl - toys select element (optional)
|
||||||
|
// enableHistory - enable using HTML5 history API (optional)
|
||||||
|
// transport - playground transport to use (default is HTTPTransport)
|
||||||
|
function playground(opts) {
|
||||||
|
var code = $(opts.codeEl);
|
||||||
|
var transport = opts['transport'] || new HTTPTransport();
|
||||||
|
var running;
|
||||||
|
|
||||||
|
// autoindent helpers.
|
||||||
|
function insertTabs(n) {
|
||||||
|
// find the selection start and end
|
||||||
|
var start = code[0].selectionStart;
|
||||||
|
var end = code[0].selectionEnd;
|
||||||
|
// split the textarea content into two, and insert n tabs
|
||||||
|
var v = code[0].value;
|
||||||
|
var u = v.substr(0, start);
|
||||||
|
for (var i=0; i<n; i++) {
|
||||||
|
u += "\t";
|
||||||
|
}
|
||||||
|
u += v.substr(end);
|
||||||
|
// set revised content
|
||||||
|
code[0].value = u;
|
||||||
|
// reset caret position after inserted tabs
|
||||||
|
code[0].selectionStart = start+n;
|
||||||
|
code[0].selectionEnd = start+n;
|
||||||
|
}
|
||||||
|
function autoindent(el) {
|
||||||
|
var curpos = el.selectionStart;
|
||||||
|
var tabs = 0;
|
||||||
|
while (curpos > 0) {
|
||||||
|
curpos--;
|
||||||
|
if (el.value[curpos] == "\t") {
|
||||||
|
tabs++;
|
||||||
|
} else if (tabs > 0 || el.value[curpos] == "\n") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(function() {
|
||||||
|
insertTabs(tabs);
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyHandler(e) {
|
||||||
|
if (e.keyCode == 9) { // tab
|
||||||
|
insertTabs(1);
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (e.keyCode == 13) { // enter
|
||||||
|
if (e.shiftKey) { // +shift
|
||||||
|
run();
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
autoindent(e.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
code.unbind('keydown').bind('keydown', keyHandler);
|
||||||
|
var outdiv = $(opts.outputEl).empty();
|
||||||
|
var output = $('<pre/>').appendTo(outdiv);
|
||||||
|
|
||||||
|
function body() {
|
||||||
|
return $(opts.codeEl).val();
|
||||||
|
}
|
||||||
|
function setBody(text) {
|
||||||
|
$(opts.codeEl).val(text);
|
||||||
|
}
|
||||||
|
function origin(href) {
|
||||||
|
return (""+href).split("/").slice(0, 3).join("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
var pushedEmpty = (window.location.pathname == "/");
|
||||||
|
function inputChanged() {
|
||||||
|
if (pushedEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pushedEmpty = true;
|
||||||
|
$(opts.shareURLEl).hide();
|
||||||
|
window.history.pushState(null, "", "/");
|
||||||
|
}
|
||||||
|
function popState(e) {
|
||||||
|
if (e === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e && e.state && e.state.code) {
|
||||||
|
setBody(e.state.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var rewriteHistory = false;
|
||||||
|
if (window.history && window.history.pushState && window.addEventListener && opts.enableHistory) {
|
||||||
|
rewriteHistory = true;
|
||||||
|
code[0].addEventListener('input', inputChanged);
|
||||||
|
window.addEventListener('popstate', popState);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setError(error) {
|
||||||
|
if (running) running.Kill();
|
||||||
|
lineClear();
|
||||||
|
lineHighlight(error);
|
||||||
|
output.empty().addClass("error").text(error);
|
||||||
|
}
|
||||||
|
function loading() {
|
||||||
|
lineClear();
|
||||||
|
if (running) running.Kill();
|
||||||
|
output.removeClass("error").text('Waiting for remote server...');
|
||||||
|
}
|
||||||
|
function run() {
|
||||||
|
loading();
|
||||||
|
running = transport.Run(body(), highlightOutput(PlaygroundOutput(output[0])));
|
||||||
|
}
|
||||||
|
function fmt() {
|
||||||
|
loading();
|
||||||
|
$.ajax("/fmt", {
|
||||||
|
data: {"body": body()},
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
success: function(data) {
|
||||||
|
if (data.Error) {
|
||||||
|
setError(data.Error);
|
||||||
|
} else {
|
||||||
|
setBody(data.Body);
|
||||||
|
setError("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(opts.runEl).click(run);
|
||||||
|
$(opts.fmtEl).click(fmt);
|
||||||
|
|
||||||
|
if (opts.shareEl !== null && (opts.shareURLEl !== null || opts.shareRedirect !== null)) {
|
||||||
|
var shareURL;
|
||||||
|
if (opts.shareURLEl) {
|
||||||
|
shareURL = $(opts.shareURLEl).hide();
|
||||||
|
}
|
||||||
|
var sharing = false;
|
||||||
|
$(opts.shareEl).click(function() {
|
||||||
|
if (sharing) return;
|
||||||
|
sharing = true;
|
||||||
|
var sharingData = body();
|
||||||
|
$.ajax("/share", {
|
||||||
|
processData: false,
|
||||||
|
data: sharingData,
|
||||||
|
type: "POST",
|
||||||
|
complete: function(xhr) {
|
||||||
|
sharing = false;
|
||||||
|
if (xhr.status != 200) {
|
||||||
|
alert("Server error; try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (opts.shareRedirect) {
|
||||||
|
window.location = opts.shareRedirect + xhr.responseText;
|
||||||
|
}
|
||||||
|
if (shareURL) {
|
||||||
|
var path = "/p/" + xhr.responseText;
|
||||||
|
var url = origin(window.location) + path;
|
||||||
|
shareURL.show().val(url).focus().select();
|
||||||
|
|
||||||
|
if (rewriteHistory) {
|
||||||
|
var historyData = {"code": sharingData};
|
||||||
|
window.history.pushState(historyData, "", path);
|
||||||
|
pushedEmpty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.toysEl !== null) {
|
||||||
|
$(opts.toysEl).bind('change', function() {
|
||||||
|
var toy = $(this).val();
|
||||||
|
$.ajax("/doc/play/"+toy, {
|
||||||
|
processData: false,
|
||||||
|
type: "GET",
|
||||||
|
complete: function(xhr) {
|
||||||
|
if (xhr.status != 200) {
|
||||||
|
alert("Server error; try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setBody(xhr.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.playground = playground;
|
||||||
|
})();
|
||||||
Loading…
Reference in New Issue