From aff6cfeb90c779bc9b65ef3efc3067b809649823 Mon Sep 17 00:00:00 2001 From: Michal Budzynski Date: Tue, 8 Aug 2017 00:05:33 +0200 Subject: [PATCH 1/2] first prototype of play-button enabling only if crate list supported also minor refactor of clipboard handling TODO: - `no_run` support - test with ACE - disable play button with tooltip instead of hiding --- src/theme/book.css | 3 ++ src/theme/book.js | 59 +++++++++++++++++++++++++++++------ src/theme/stylus/general.styl | 4 +++ 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/theme/book.css b/src/theme/book.css index f1d73dbd2c..abf7868556 100644 --- a/src/theme/book.css +++ b/src/theme/book.css @@ -19,6 +19,9 @@ code { .hidden { display: none; } +.play-button.hidden { + display: none; +} h2, h3 { margin-top: 2.5em; diff --git a/src/theme/book.js b/src/theme/book.js index 12e72019a5..5e4a37f9dc 100644 --- a/src/theme/book.js +++ b/src/theme/book.js @@ -1,3 +1,5 @@ +playground_crates = []; + $( document ).ready(function() { // url @@ -219,7 +221,7 @@ $( document ).ready(function() { pre_block.prepend("
"); buttons = pre_block.find(".buttons"); } - buttons.prepend(""); + buttons.prepend(""); buttons.prepend(""); let code_block = pre_block.find("code").first(); @@ -245,14 +247,7 @@ $( document ).ready(function() { text: function(trigger) { hideTooltip(trigger); let playpen = $(trigger).parents(".playpen"); - let code_block = playpen.find("code").first(); - - if (window.ace && code_block.hasClass("editable")) { - let editor = window.ace.edit(code_block.get(0)); - return editor.getValue(); - } else { - return code_block.get(0).textContent; - } + return playpen_text(playpen); } }); clipboardSnippets.on('success', function(e) { @@ -262,8 +257,54 @@ $( document ).ready(function() { clipboardSnippets.on('error', function(e) { showTooltip(e.trigger, "Clipboard error!"); }); + + $.ajax({ + url: "https://play.rust-lang.org/meta/crates", + method: "POST", + crossDomain: true, + dataType: "json", + contentType: "application/json", + success: function(response){ + playground_crates = response.crates.map(function(item) {return item["id"];} ); + $(".playpen").each(function(block){ + update_play_button(this, playground_crates); + }); + }, + }); + }); +function playpen_text(playpen) { + let code_block = playpen.find("code").first(); + + if (window.ace && code_block.hasClass("editable")) { + let editor = window.ace.edit(code_block.get(0)); + return editor.getValue(); + } else { + return code_block.get(0).textContent; + } +} + +function update_play_button(block, playground_crates) { + //TODO skip if `no_run` is set + var pre_block = $(block); + var play_button = pre_block.find(".play-button"); + + var txt = playpen_text(pre_block); + + var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; + var snippet_crates = []; + while (item = re.exec(txt)) + snippet_crates.push(item[1]); + + var all_available = snippet_crates.every(elem => playground_crates.indexOf(elem) > -1); + if (all_available) { + play_button.removeClass("hidden"); + } else { + play_button.addClass("hidden"); + } +} + function hideTooltip(elem) { elem.firstChild.innerText=""; elem.setAttribute('class', 'fa fa-copy clip-button'); diff --git a/src/theme/stylus/general.styl b/src/theme/stylus/general.styl index 7d3a583e2d..210c378832 100644 --- a/src/theme/stylus/general.styl +++ b/src/theme/stylus/general.styl @@ -24,6 +24,10 @@ code { display: none; } +.play-button.hidden { + display: none; +} + h2, h3 { margin-top: 2.5em } h4, h5 { margin-top: 2em } From 886f3b5ae0299a71876ab7f5092951fe1eeabb55 Mon Sep 17 00:00:00 2001 From: Michal Budzynski Date: Tue, 8 Aug 2017 00:36:38 +0200 Subject: [PATCH 2/2] Both static and ACE editable snippets have optional play button - list of available crates is dynamically loaded from play.rust-lang.org - play button is enabled only if crates used in snippet are available on playground - ACE editor's play button is dynamically updated on each text change - `no_run` is honored by always disabling the play button - minor cleanups --- src/theme/book.js | 73 +++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/src/theme/book.js b/src/theme/book.js index 5e4a37f9dc..4c5108b8cd 100644 --- a/src/theme/book.js +++ b/src/theme/book.js @@ -1,5 +1,3 @@ -playground_crates = []; - $( document ).ready(function() { // url @@ -19,7 +17,7 @@ $( document ).ready(function() { tabReplace: ' ', // 4 spaces languages: [], // Languages used for auto-detection }); - + if (window.ace) { // language-rust class needs to be removed for editable // blocks or highlightjs will capture events @@ -33,7 +31,7 @@ $( document ).ready(function() { hljs.highlightBlock(block); }); } - + // Adding the hljs class gives code blocks the color css // even if highlighting doesn't apply $('code').addClass('hljs'); @@ -130,27 +128,27 @@ $( document ).ready(function() { function set_theme(theme) { let ace_theme; - + if (theme == 'coal' || theme == 'navy') { $("[href='ayu-highlight.css']").prop('disabled', true); $("[href='tomorrow-night.css']").prop('disabled', false); $("[href='highlight.css']").prop('disabled', true); - + ace_theme = "ace/theme/tomorrow_night"; } else if (theme == 'ayu') { $("[href='ayu-highlight.css']").prop('disabled', false); $("[href='tomorrow-night.css']").prop('disabled', true); $("[href='highlight.css']").prop('disabled', true); - + ace_theme = "ace/theme/tomorrow_night"; } else { $("[href='ayu-highlight.css']").prop('disabled', true); $("[href='tomorrow-night.css']").prop('disabled', true); $("[href='highlight.css']").prop('disabled', false); - + ace_theme = "ace/theme/dawn"; } - + if (window.ace && window.editors) { window.editors.forEach(function(editor) { editor.setTheme(ace_theme); @@ -265,9 +263,10 @@ $( document ).ready(function() { dataType: "json", contentType: "application/json", success: function(response){ - playground_crates = response.crates.map(function(item) {return item["id"];} ); - $(".playpen").each(function(block){ - update_play_button(this, playground_crates); + // get list of crates available in the rust playground + let playground_crates = response.crates.map(function(item) {return item["id"];} ); + $(".playpen").each(function(block) { + handle_crate_list_update($(this), playground_crates); }); }, }); @@ -285,19 +284,47 @@ function playpen_text(playpen) { } } -function update_play_button(block, playground_crates) { - //TODO skip if `no_run` is set - var pre_block = $(block); +function handle_crate_list_update(playpen_block, playground_crates) { + // update the play buttons after receiving the response + update_play_button(playpen_block, playground_crates); + + // and install on change listener to dynamically update ACE editors + if (window.ace) { + let code_block = playpen_block.find("code").first(); + if (code_block.hasClass("editable")) { + let editor = window.ace.edit(code_block.get(0)); + editor.on("change", function(e){ + update_play_button(playpen_block, playground_crates); + }); + } + } +} + +// updates the visibility of play button based on `no_run` class and +// used crates vs ones available on http://play.rust-lang.org +function update_play_button(pre_block, playground_crates) { var play_button = pre_block.find(".play-button"); - var txt = playpen_text(pre_block); + var classes = pre_block.find("code").attr("class").split(" "); + // skip if code is `no_run` + if (classes.indexOf("no_run") > -1) { + play_button.addClass("hidden"); + return; + } + // get list of `extern crate`'s from snippet + var txt = playpen_text(pre_block); var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; var snippet_crates = []; - while (item = re.exec(txt)) + while (item = re.exec(txt)) { snippet_crates.push(item[1]); + } + + // check if all used crates are available on play.rust-lang.org + var all_available = snippet_crates.every(function(elem) { + return playground_crates.indexOf(elem) > -1; + }); - var all_available = snippet_crates.every(elem => playground_crates.indexOf(elem) > -1); if (all_available) { play_button.removeClass("hidden"); } else { @@ -341,15 +368,7 @@ function run_rust_code(code_block) { result_block = code_block.find(".result"); } - let text; - - let inner_code_block = code_block.find("code").first(); - if (window.ace && inner_code_block.hasClass("editable")) { - let editor = window.ace.edit(inner_code_block.get(0)); - text = editor.getValue(); - } else { - text = inner_code_block.text(); - } + let text = playpen_text(code_block);; var params = { version: "stable",