Move hiding of boring lines into static content (#846)
This commit is contained in:
parent
859659f197
commit
4448f3fc4b
|
@ -6,6 +6,7 @@ use crate::renderer::{RenderContext, Renderer};
|
||||||
use crate::theme::{self, playpen_editor, Theme};
|
use crate::theme::{self, playpen_editor, Theme};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
@ -584,6 +585,7 @@ fn fix_code_blocks(html: &str) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_playpen_pre(html: &str, playpen_config: &Playpen) -> String {
|
fn add_playpen_pre(html: &str, playpen_config: &Playpen) -> String {
|
||||||
|
let boring_line_regex = Regex::new(r"^(\s*)#(#|.)(.*)$").unwrap();
|
||||||
let regex = Regex::new(r##"((?s)<code[^>]?class="([^"]+)".*?>(.*?)</code>)"##).unwrap();
|
let regex = Regex::new(r##"((?s)<code[^>]?class="([^"]+)".*?>(.*?)</code>)"##).unwrap();
|
||||||
regex
|
regex
|
||||||
.replace_all(html, |caps: &Captures<'_>| {
|
.replace_all(html, |caps: &Captures<'_>| {
|
||||||
|
@ -597,21 +599,45 @@ fn add_playpen_pre(html: &str, playpen_config: &Playpen) -> String {
|
||||||
|| classes.contains("mdbook-runnable")
|
|| classes.contains("mdbook-runnable")
|
||||||
{
|
{
|
||||||
// wrap the contents in an external pre block
|
// wrap the contents in an external pre block
|
||||||
if playpen_config.editable && classes.contains("editable")
|
format!("<pre class=\"playpen\"><code class=\"{}\">{}</code></pre>",
|
||||||
|
classes,
|
||||||
|
{
|
||||||
|
let content: Cow<str> = if playpen_config.editable && classes.contains("editable")
|
||||||
|| text.contains("fn main")
|
|| text.contains("fn main")
|
||||||
|| text.contains("quick_main!")
|
|| text.contains("quick_main!")
|
||||||
{
|
{
|
||||||
format!("<pre class=\"playpen\">{}</pre>", text)
|
code.into()
|
||||||
} else {
|
} else {
|
||||||
// we need to inject our own main
|
// we need to inject our own main
|
||||||
let (attrs, code) = partition_source(code);
|
let (attrs, code) = partition_source(code);
|
||||||
|
|
||||||
format!(
|
format!("\n# #![allow(unused_variables)]\n{}#fn main() {{\n{}#}}",
|
||||||
"<pre class=\"playpen\"><code class=\"{}\">\n# \
|
attrs, code
|
||||||
#![allow(unused_variables)]\n{}#fn main() {{\n{}#}}</code></pre>",
|
).into()
|
||||||
classes, attrs, code
|
};
|
||||||
)
|
let mut prev_line_hidden = false;
|
||||||
|
let mut result = String::with_capacity(content.len());
|
||||||
|
for line in content.lines() {
|
||||||
|
if let Some(caps) = boring_line_regex.captures(line) {
|
||||||
|
if !prev_line_hidden && &caps[2] != "#" {
|
||||||
|
result += "<span class=\"boring\">";
|
||||||
|
prev_line_hidden = true;
|
||||||
}
|
}
|
||||||
|
result += &caps[1];
|
||||||
|
if &caps[2] != " " { result += &caps[2]; }
|
||||||
|
result += &caps[3];
|
||||||
|
} else {
|
||||||
|
if prev_line_hidden {
|
||||||
|
result += "</span>";
|
||||||
|
prev_line_hidden = false;
|
||||||
|
}
|
||||||
|
result += line;
|
||||||
|
}
|
||||||
|
result += "\n";
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// not language-rust, so no-op
|
// not language-rust, so no-op
|
||||||
text.to_owned()
|
text.to_owned()
|
||||||
|
@ -687,4 +713,22 @@ mod tests {
|
||||||
assert_eq!(got, should_be);
|
assert_eq!(got, should_be);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_playpen() {
|
||||||
|
let inputs = [
|
||||||
|
("<code class=\"language-rust\">x()</code>",
|
||||||
|
"<pre class=\"playpen\"><code class=\"language-rust\">\n<span class=\"boring\">#![allow(unused_variables)]\nfn main() {\n</span>x()\n<span class=\"boring\">}\n</code></pre>"),
|
||||||
|
("<code class=\"language-rust\">fn main() {}</code>",
|
||||||
|
"<pre class=\"playpen\"><code class=\"language-rust\">fn main() {}\n</code></pre>"),
|
||||||
|
("<code class=\"language-rust editable\">let s = \"foo\n # bar\n\";</code>",
|
||||||
|
"<pre class=\"playpen\"><code class=\"language-rust editable\">let s = \"foo\n<span class=\"boring\"> bar\n</span>\";\n</code></pre>"),
|
||||||
|
("<code class=\"language-rust editable\">let s = \"foo\n ## bar\n\";</code>",
|
||||||
|
"<pre class=\"playpen\"><code class=\"language-rust editable\">let s = \"foo\n # bar\n\";\n</code></pre>"),
|
||||||
|
];
|
||||||
|
for (src, should_be) in &inputs {
|
||||||
|
let got = add_playpen_pre(src, &Playpen { editable: true, ..Playpen::default() });
|
||||||
|
assert_eq!(&*got, *should_be);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,72 +161,34 @@ function playpen_text(playpen) {
|
||||||
|
|
||||||
Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) {
|
Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) {
|
||||||
|
|
||||||
var code_block = block;
|
var lines = Array.from(block.querySelectorAll('.boring'));
|
||||||
var pre_block = block.parentNode;
|
|
||||||
// hide lines
|
|
||||||
var lines = code_block.innerHTML.split("\n");
|
|
||||||
var first_non_hidden_line = false;
|
|
||||||
var lines_hidden = false;
|
|
||||||
var trimmed_line = "";
|
|
||||||
|
|
||||||
for (var n = 0; n < lines.length; n++) {
|
|
||||||
trimmed_line = lines[n].trim();
|
|
||||||
if (trimmed_line[0] == hiding_character && trimmed_line[1] != hiding_character) {
|
|
||||||
if (first_non_hidden_line) {
|
|
||||||
lines[n] = "<span class=\"hidden\">" + "\n" + lines[n].replace(/(\s*)# ?/, "$1") + "</span>";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lines[n] = "<span class=\"hidden\">" + lines[n].replace(/(\s*)# ?/, "$1") + "\n" + "</span>";
|
|
||||||
}
|
|
||||||
lines_hidden = true;
|
|
||||||
}
|
|
||||||
else if (first_non_hidden_line) {
|
|
||||||
lines[n] = "\n" + lines[n];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
first_non_hidden_line = true;
|
|
||||||
}
|
|
||||||
if (trimmed_line[0] == hiding_character && trimmed_line[1] == hiding_character) {
|
|
||||||
lines[n] = lines[n].replace("##", "#")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
code_block.innerHTML = lines.join("");
|
|
||||||
|
|
||||||
// If no lines were hidden, return
|
// If no lines were hidden, return
|
||||||
if (!lines_hidden) { return; }
|
if (!lines.length) { return; }
|
||||||
|
block.classList.add("hide-boring");
|
||||||
|
|
||||||
var buttons = document.createElement('div');
|
var buttons = document.createElement('div');
|
||||||
buttons.className = 'buttons';
|
buttons.className = 'buttons';
|
||||||
buttons.innerHTML = "<button class=\"fa fa-expand\" title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>";
|
buttons.innerHTML = "<button class=\"fa fa-expand\" title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>";
|
||||||
|
|
||||||
// add expand button
|
// add expand button
|
||||||
|
var pre_block = block.parentNode;
|
||||||
pre_block.insertBefore(buttons, pre_block.firstChild);
|
pre_block.insertBefore(buttons, pre_block.firstChild);
|
||||||
|
|
||||||
pre_block.querySelector('.buttons').addEventListener('click', function (e) {
|
pre_block.querySelector('.buttons').addEventListener('click', function (e) {
|
||||||
if (e.target.classList.contains('fa-expand')) {
|
if (e.target.classList.contains('fa-expand')) {
|
||||||
var lines = pre_block.querySelectorAll('span.hidden');
|
|
||||||
|
|
||||||
e.target.classList.remove('fa-expand');
|
e.target.classList.remove('fa-expand');
|
||||||
e.target.classList.add('fa-compress');
|
e.target.classList.add('fa-compress');
|
||||||
e.target.title = 'Hide lines';
|
e.target.title = 'Hide lines';
|
||||||
e.target.setAttribute('aria-label', e.target.title);
|
e.target.setAttribute('aria-label', e.target.title);
|
||||||
|
|
||||||
Array.from(lines).forEach(function (line) {
|
block.classList.remove('hide-boring');
|
||||||
line.classList.remove('hidden');
|
|
||||||
line.classList.add('unhidden');
|
|
||||||
});
|
|
||||||
} else if (e.target.classList.contains('fa-compress')) {
|
} else if (e.target.classList.contains('fa-compress')) {
|
||||||
var lines = pre_block.querySelectorAll('span.unhidden');
|
|
||||||
|
|
||||||
e.target.classList.remove('fa-compress');
|
e.target.classList.remove('fa-compress');
|
||||||
e.target.classList.add('fa-expand');
|
e.target.classList.add('fa-expand');
|
||||||
e.target.title = 'Show hidden lines';
|
e.target.title = 'Show hidden lines';
|
||||||
e.target.setAttribute('aria-label', e.target.title);
|
e.target.setAttribute('aria-label', e.target.title);
|
||||||
|
|
||||||
Array.from(lines).forEach(function (line) {
|
block.classList.add('hide-boring');
|
||||||
line.classList.remove('unhidden');
|
|
||||||
line.classList.add('hidden');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -22,8 +22,9 @@ code {
|
||||||
|
|
||||||
.left { float: left; }
|
.left { float: left; }
|
||||||
.right { float: right; }
|
.right { float: right; }
|
||||||
|
.boring { opacity: 0.6; }
|
||||||
|
.hide-boring .boring { display: none; }
|
||||||
.hidden { display: none; }
|
.hidden { display: none; }
|
||||||
.play-button.hidden { display: none; }
|
|
||||||
|
|
||||||
h2, h3 { margin-top: 2.5em; }
|
h2, h3 { margin-top: 2.5em; }
|
||||||
h4, h5 { margin-top: 2em; }
|
h4, h5 { margin-top: 2em; }
|
||||||
|
|
Loading…
Reference in New Issue