static: add optional save shortcut support to playground

If enabled (via the "enableShortcuts" option), Ctrl+S/Cmd+S now
saves/shares the playground snippet and initiates a download.

Credit to Alexander Kucherenko (see golang.org/cl/35950).

Updates golang/go#15378.

Change-Id: I8a2d733c25e4c95787fbe1f5ac00fa1befbb4693
Reviewed-on: https://go-review.googlesource.com/36486
Reviewed-by: Andrew Gerrand <adg@golang.org>
This commit is contained in:
Chris Broadfoot 2017-02-07 10:29:28 -08:00
Родитель 1977f1cf7d
Коммит 69cfa78961
2 изменённых файлов: 144 добавлений и 80 удалений

Просмотреть файл

@ -169,8 +169,9 @@ function PlaygroundOutput(el) {
cl = write.Kind;
var m = write.Body;
if (write.Kind == 'end')
if (write.Kind == 'end') {
m = '\nProgram exited' + (m?(': '+m):'.');
}
if (m.indexOf('IMAGE:') === 0) {
// TODO(adg): buffer all writes before creating image
@ -235,11 +236,12 @@ function PlaygroundOutput(el) {
// toysEl - toys select element (optional)
// enableHistory - enable using HTML5 history API (optional)
// transport - playground transport to use (default is HTTPTransport)
// enableShortcuts - whether to enable shortcuts (Ctrl+S/Cmd+S to save) (default is false)
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
@ -273,8 +275,26 @@ function PlaygroundOutput(el) {
insertTabs(tabs);
}, 1);
}
// NOTE(cbro): e is a jQuery event, not a DOM event.
function handleSaveShortcut(e) {
if (e.isDefaultPrevented()) return false;
if (!e.metaKey && !e.ctrlKey) return false;
if (e.key != "S" && e.key != "s") return false;
e.preventDefault();
// Share and save
share(function(url) {
window.location.href = url + ".go?download=true";
});
return true;
}
function keyHandler(e) {
if (opts.enableShortcuts && handleSaveShortcut(e)) return;
if (e.keyCode == 9 && !e.ctrlKey) { // tab (but not ctrl-tab)
insertTabs(1);
e.preventDefault();
@ -297,7 +317,7 @@ function PlaygroundOutput(el) {
code.unbind('keydown').bind('keydown', keyHandler);
var outdiv = $(opts.outputEl).empty();
var output = $('<pre/>').appendTo(outdiv);
function body() {
return $(opts.codeEl).val();
}
@ -307,7 +327,7 @@ function PlaygroundOutput(el) {
function origin(href) {
return (""+href).split("/").slice(0, 3).join("/");
}
var pushedEmpty = (window.location.pathname == "/");
function inputChanged() {
if (pushedEmpty) {
@ -350,7 +370,7 @@ function PlaygroundOutput(el) {
function fmt() {
loading();
var data = {"body": body()};
var data = {"body": body()};
if ($(opts.fmtImportEl).is(":checked")) {
data["imports"] = "true";
}
@ -369,48 +389,60 @@ function PlaygroundOutput(el) {
});
}
var shareURL; // jQuery element to show the shared URL.
var sharing = false; // true if there is a pending request.
var shareCallbacks = [];
function share(opt_callback) {
if (opt_callback) shareCallbacks.push(opt_callback);
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;
}
var path = "/p/" + xhr.responseText;
var url = origin(window.location) + path;
for (var i = 0; i < shareCallbacks.length; i++) {
shareCallbacks[i](url);
}
shareCallbacks = [];
if (shareURL) {
shareURL.show().val(url).focus().select();
if (rewriteHistory) {
var historyData = {"code": sharingData};
window.history.pushState(historyData, "", path);
pushedEmpty = false;
}
}
}
});
}
$(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;
}
}
}
});
});
$(opts.shareEl).click(share);
}
if (opts.toysEl !== null) {
$(opts.toysEl).bind('change', function() {
var toy = $(this).val();

Просмотреть файл

@ -2379,8 +2379,9 @@ function PlaygroundOutput(el) {
cl = write.Kind;
var m = write.Body;
if (write.Kind == 'end')
if (write.Kind == 'end') {
m = '\nProgram exited' + (m?(': '+m):'.');
}
if (m.indexOf('IMAGE:') === 0) {
// TODO(adg): buffer all writes before creating image
@ -2445,11 +2446,12 @@ function PlaygroundOutput(el) {
// toysEl - toys select element (optional)
// enableHistory - enable using HTML5 history API (optional)
// transport - playground transport to use (default is HTTPTransport)
// enableShortcuts - whether to enable shortcuts (Ctrl+S/Cmd+S to save) (default is false)
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
@ -2483,8 +2485,26 @@ function PlaygroundOutput(el) {
insertTabs(tabs);
}, 1);
}
// NOTE(cbro): e is a jQuery event, not a DOM event.
function handleSaveShortcut(e) {
if (e.isDefaultPrevented()) return false;
if (!e.metaKey && !e.ctrlKey) return false;
if (e.key != "S" && e.key != "s") return false;
e.preventDefault();
// Share and save
share(function(url) {
window.location.href = url + ".go?download=true";
});
return true;
}
function keyHandler(e) {
if (opts.enableShortcuts && handleSaveShortcut(e)) return;
if (e.keyCode == 9 && !e.ctrlKey) { // tab (but not ctrl-tab)
insertTabs(1);
e.preventDefault();
@ -2507,7 +2527,7 @@ function PlaygroundOutput(el) {
code.unbind('keydown').bind('keydown', keyHandler);
var outdiv = $(opts.outputEl).empty();
var output = $('<pre/>').appendTo(outdiv);
function body() {
return $(opts.codeEl).val();
}
@ -2517,7 +2537,7 @@ function PlaygroundOutput(el) {
function origin(href) {
return (""+href).split("/").slice(0, 3).join("/");
}
var pushedEmpty = (window.location.pathname == "/");
function inputChanged() {
if (pushedEmpty) {
@ -2560,7 +2580,7 @@ function PlaygroundOutput(el) {
function fmt() {
loading();
var data = {"body": body()};
var data = {"body": body()};
if ($(opts.fmtImportEl).is(":checked")) {
data["imports"] = "true";
}
@ -2579,48 +2599,60 @@ function PlaygroundOutput(el) {
});
}
var shareURL; // jQuery element to show the shared URL.
var sharing = false; // true if there is a pending request.
var shareCallbacks = [];
function share(opt_callback) {
if (opt_callback) shareCallbacks.push(opt_callback);
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;
}
var path = "/p/" + xhr.responseText;
var url = origin(window.location) + path;
for (var i = 0; i < shareCallbacks.length; i++) {
shareCallbacks[i](url);
}
shareCallbacks = [];
if (shareURL) {
shareURL.show().val(url).focus().select();
if (rewriteHistory) {
var historyData = {"code": sharingData};
window.history.pushState(historyData, "", path);
pushedEmpty = false;
}
}
}
});
}
$(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;
}
}
}
});
});
$(opts.shareEl).click(share);
}
if (opts.toysEl !== null) {
$(opts.toysEl).bind('change', function() {
var toy = $(this).val();