Add download & print buttons to all PRE blocks. (#1680)

Also, replaced the text in the Copy button with an icon instead.
This commit is contained in:
Martin Taillefer 2018-07-06 05:30:35 -07:00 committed by GitHub
parent 26113b3b5b
commit 512fdb5b61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 242 additions and 128 deletions

View File

@ -321,6 +321,20 @@ $ kubectl -n istio-system logs $(kubectl -n istio-system get pods -l istio-mixer
{"level":"warn","ts":"2017-09-21T04:33:31.233Z","instance":"newlog.logentry.istio-system","destination":"ingress.istio-system.svc.cluster.local","latency":"74.47ms","responseCode":200,"responseSize":5599,"source":"unknown","user":"unknown"}
{{< /text >}}
You can specify an optional third value which controls the name that the browser
will use when the user chooses to download the file. For example:
{{< text markdown >}}
{{</* text go plain "hello.go" */>}}
func HelloWorld() {
fmt.Println("Hello World")
}
{{</* /text */>}}
{{< /text >}}
If you don't specify a third value, then the download name is derived automatically based on the
name of the current page.
### Links to GitHub files
If your code block references a file from Istio's GitHub repo, you can surround the relative path name of the file with a pair
@ -338,9 +352,9 @@ This will be rendered as:
$ istioctl create -f @samples/bookinfo/kube/route-rule-reviews-v3.yaml@
{{< /text >}}
### File snippets
### Files and snippets
It is often useful to display portions of a larger file. You can annotate a text file to create named snippets within the file by
It is often useful to display files or portions of a file. You can annotate a text file to create named snippets within the file by
using the `$snippet` and `$endsnippet` annotations. For example, you could have a text file that looks like this:
{{< text_file file="examples/snippet_example.txt" syntax="plain" >}}
@ -359,6 +373,18 @@ The above snippet produces this output:
{{< text_file file="examples/snippet_example.txt" syntax="plain" snippet="SNIP1" >}}
If you don't specify a snippet name, then the whole file will be inserted instead.
You can specify an optional `downloadas` attribute, which specifies the name that the browser
will use when the user chooses to download the file. For example:
{{< text markdown >}}
{{</* text_file file="examples/snippet_example.txt" syntax="plain" downloadas="foo.txt" */>}}
{{< /text >}}
If you don't specify the `downloadas` attribute, then the download name is taken from the `file`
attribute instead.
A common thing to is to copy an example script or yaml file from GitHub into the documentation
repo and then use snippets within the file to produce examples in the documentation. To pull
in annotated files from GitHub, add the needed entries at the end of the
@ -380,6 +406,16 @@ which produces the following result:
If the file is from a different origin site, CORS should be enabled on that site. Note that the
GitHub raw content site (raw.githubusercontent.com) may be used here.
You can specify an optional `downloadas` attribute, which specifies the name that the browser
will use when the user chooses to download the file. For example:
{{< text markdown >}}
{{</* text_dynamic url="https://raw.githubusercontent.com/istio/istio/master/samples/bookinfo/kube/mixer-rule-ratings-ratelimit.yaml" syntax="yaml" downloadas="foo.yaml" */>}}
{{< /text >}}
If you don't specify the `downloadas` attribute, then the download name is taken from the `url`
attribute instead.
## Renaming or moving pages
If you move pages around and would like to ensure existing links continue to work, you can add
@ -433,7 +469,3 @@ in the code block itself, making cut & paste not work right.
- Make sure all images have valid width and aspect ratios. Otherwise, they will render
in odd ways, depending on screen size.
- The special syntax to insert links in code blocks using `@@` annotations produces links
which are unchecked. So you can put bad links in there and tooling won't stop you. So be
careful.

View File

@ -1,7 +1,7 @@
{{ $toc := partial "toc.html" (dict "page" .) }}
{{ $needTOC := .Scratch.Get "needTOC" }}
{{ $related := .Site.RegularPages.Related . | first 5 }}
{{ $related := .Site.RegularPages.Related . | first 6 }}
{{ with $related }}
<h2 id="see-also">See also</h2>

View File

@ -1,19 +1,15 @@
{{/*
Purpose:
Inserts a preformatted code block into the HTML. You specify the syntax to use for
highlighting, which can be one of `plain`, `markdown`, `yaml`, `json`, `java`, `javascript`,
`c`, `cpp`, `csharp`, `go`, `html`, `protobuf`, `perl`, `docker`, and `bash`.
When the syntax is bash, the first line of the block is expected to start with a $.
An additional output syntax can be specified which uses different syntax coloring
for the output portion of the block. Otherwise, the output is colored using the
`plain` syntax.
{{/* Inserts a text block into the HTML. See https://preliminary.istio.io/about/contribute/writing-a-new-topic/#embedding-preformatted-blocks for details
NOTE: The stuff below cannot be indented. If it is, it can cause the markdown
parser to insert spurious paragraphs around the PRE blocks, which turns out to
be invalid HTML
*/}}
{{ $scratch := .Scratch }}
{{ $scratch := .Page.Scratch }}
{{ $scratch.Add "text_counter" 1 }}
{{ $scratch.Set "downloadas" (printf "%s-%v.%s" .Page.File.BaseFileName ($scratch.Get "text_counter") (.Get 0)) }}
{{ if .Get 2 }}
{{ $scratch.Set "downloadas" (.Get 2) }}
{{ end }}
{{ if .Get 0 }}
{{ $lines := split (strings.TrimRight " " (trim .Inner "\n")) "\n" }}
{{ $line0 := index $lines 0 }}
@ -49,4 +45,4 @@ be invalid HTML
{{ if ($scratch.Get "output") }}{{ $scratch.Set "syntax" (printf "command-output-as-%s" ($scratch.Get "output")) }}{{ end }}
{{ end }}
{{ end }}
<pre><code class='language-{{ $scratch.Get "syntax" }}'>{{ $scratch.Get "text" }}</code></pre>
<pre><code class='language-{{ $scratch.Get "syntax" }}' data-downloadas='{{ $scratch.Get "downloadas" }}'>{{ $scratch.Get "text" }}</code></pre>

View File

@ -1 +1,7 @@
<pre data-src='{{ .Get "url" }}'><code class='language-{{ .Get "syntax" }}'></code></pre>
{{ $scratch := .Page.Scratch }}
{{ $name := split (.Get "url") "/" | last 1 }}
{{ $scratch.Set "downloadas" (index $name 0) }}
{{ if .Get "downloadas" }}
{{ $scratch.Set "downloadas" (.Get "downloadas") }}
{{ end }}
<pre data-src='{{ .Get "url" }}'><code class='language-{{ .Get "syntax" }}' data-downloadas='{{ $scratch.Get "downloadas" }}'></code></pre>

View File

@ -1,9 +1,15 @@
{{/* Inserts a text file into the HTML. See https://preliminary.istio.io/about/contribute/writing-a-new-topic/#displaying-file-snippets for details */}}
{{/* Inserts a text file into the HTML. See https://preliminary.istio.io/about/contribute/writing-a-new-topic/#embedding-preformatted-blocks for details */}}
{{ $scratch := .Page.Scratch }}
{{ $name := split (.Get "file") "/" | last 1 }}
{{ $scratch.Set "downloadas" (index $name 0) }}
{{ if .Get "downloadas" }}
{{ $scratch.Set "downloadas" (.Get "downloadas") }}
{{ end }}
{{ $file := readFile (.Get "file") }}
{{ if (.Get "snippet") }}
{{ $pattern := printf "(?msU)(.*\\$snippet %s.*$\\n)(.*)(?-s)(\\n^.*\\$endsnippet.*$)(?s-U)(.*)" (.Get "snippet") }}
{{ $match := replaceRE $pattern "$2" $file }}
<pre><code class='language-{{ .Get "syntax" }}'>{{ $match }}</code></pre>
<pre><code class='language-{{ .Get "syntax" }}' data-downloadas='{{ $scratch.Get "downloadas" }}'>{{ $match }}</code></pre>
{{ else }}
<pre><code class='language-{{ .Get "syntax" }}'>{{ $file }}</code></pre>
<pre><code class='language-{{ .Get "syntax" }}' data-downloadas='{{ $scratch.Get "downloadas" }}'>{{ $file }}</code></pre>
{{ end }}

View File

@ -2,7 +2,7 @@
$(function ($) {
// Show the navbar links, hide the search box
function showLinks() {
function showNavBarLinks() {
var $form = $('#search_form');
var $textbox = $('#search_textbox');
var $links = $('#navbar-links');
@ -28,7 +28,7 @@ $(function ($) {
// Hide the search box when the user hits the ESC key
$('body').on('keyup', function(event) {
if (event.which === 27) {
showLinks();
showNavBarLinks();
}
});
@ -41,7 +41,7 @@ $(function ($) {
// Hide the search box
$('#search_close').on('click', function(event) {
event.preventDefault();
showLinks();
showNavBarLinks();
});
// When the user submits the search form, initiate a search
@ -50,7 +50,7 @@ $(function ($) {
var $textbox = $('#search_textbox');
var $search_page_url = $('#search_page_url');
var url = $search_page_url.val() + '?q=' + $textbox.val();
showLinks();
showNavBarLinks();
window.location.assign(url);
});
@ -68,28 +68,60 @@ $(function ($) {
$(this).parent().children('ul.tree').toggle(200);
});
// toggle copy button
// toggle toolbar buttons
$(document).on('mouseenter', 'pre', function () {
$(this).next().toggleClass("copy-show", true);
$(this).next().toggleClass("copy-hide", false)
$(this).next().toggleClass("toolbar-show", true);
$(this).next().toggleClass("toolbar-hide", false);
$(this).next().next().toggleClass("toolbar-show", true);
$(this).next().next().toggleClass("toolbar-hide", false);
$(this).next().next().next().toggleClass("toolbar-show", true);
$(this).next().next().next().toggleClass("toolbar-hide", false);
});
// toggle copy button
// toggle toolbar buttons
$(document).on('mouseleave', 'pre', function () {
$(this).next().toggleClass("copy-show", false);
$(this).next().toggleClass("copy-hide", true)
$(this).next().toggleClass("toolbar-show", false);
$(this).next().toggleClass("toolbar-hide", true);
$(this).next().next().toggleClass("toolbar-show", false);
$(this).next().next().toggleClass("toolbar-hide", true);
$(this).next().next().next().toggleClass("toolbar-show", false);
$(this).next().next().next().toggleClass("toolbar-hide", true);
});
// toggle copy button
$(document).on('mouseenter', 'button.copy', function () {
$(this).toggleClass("copy-show", true);
$(this).toggleClass("copy-hide", false)
$(this).toggleClass("toolbar-show", true);
$(this).toggleClass("toolbar-hide", false);
});
// toggle copy button
$(document).on('mouseleave', 'button.copy', function () {
$(this).toggleClass("copy-show", false);
$(this).toggleClass("copy-hide", true)
$(this).toggleClass("toolbar-show", false);
$(this).toggleClass("toolbar-hide", true);
});
// toggle download button
$(document).on('mouseenter', 'button.download', function () {
$(this).toggleClass("toolbar-show", true);
$(this).toggleClass("toolbar-hide", false);
});
// toggle download button
$(document).on('mouseleave', 'button.download', function () {
$(this).toggleClass("toolbar-show", false);
$(this).toggleClass("toolbar-hide", true);
});
// toggle print button
$(document).on('mouseenter', 'button.print', function () {
$(this).toggleClass("toolbar-show", true);
$(this).toggleClass("toolbar-hide", false);
});
// toggle print button
$(document).on('mouseleave', 'button.print', function () {
$(this).toggleClass("toolbar-show", false);
$(this).toggleClass("toolbar-hide", true);
});
});
}(jQuery));
@ -172,74 +204,88 @@ function handleDOMLoaded() {
}
}
// Add a Copy button to all PRE blocks
function attachCopyButtons() {
// Add a toolbar to all PRE blocks
function attachToolbarToPreBlocks() {
var pre = document.getElementsByTagName('PRE');
for (var i = 0; i < pre.length; i++) {
var button = document.createElement("BUTTON");
button.title = "Copy to clipboard";
button.className = "copy copy-hide";
button.innerText = "Copy";
button.setAttribute("aria-label", "Copy to clipboard");
var copyButton = document.createElement("BUTTON");
copyButton.title = "Copy to clipboard";
copyButton.className = "copy toolbar-hide";
copyButton.innerHTML = "<i class='fa fa-copy'></i>";
copyButton.setAttribute("aria-label", "Copy to clipboard");
var downloadButton = document.createElement("BUTTON");
downloadButton.title = "Download";
downloadButton.className = "download toolbar-hide";
downloadButton.innerHTML = "<i class='fa fa-download'></i>";
downloadButton.setAttribute("aria-label", downloadButton.title);
downloadButton.onclick = function(e) {
var div = e.currentTarget.parentElement;
var codes = div.getElementsByTagName("CODE");
if ((codes !== null) && (codes.length > 0)) {
var text = getToolbarDivText(div);
saveFile(codes[0].getAttribute("data-downloadas"), text);
}
return true;
};
var printButton = document.createElement("BUTTON");
printButton.title = "Print";
printButton.className = "print toolbar-hide";
printButton.innerHTML = "<i class='fa fa-print'></i>";
printButton.setAttribute("aria-label", printButton.title);
printButton.onclick = function(e) {
var div = e.currentTarget.parentElement;
var text = getToolbarDivText(div);
printText(text);
return true;
};
// wrap the PRE block in a DIV so we have a place to attach the copy button
var div = document.createElement("DIV");
div.className = "copy";
div.className = "toolbar";
pre[i].parentElement.insertBefore(div, pre[i]);
div.appendChild(pre[i]);
div.appendChild(button);
div.appendChild(printButton);
div.appendChild(downloadButton);
div.appendChild(copyButton);
}
var copyCode = new Clipboard('button.copy', {
text: function (trigger) {
var commands = trigger.previousElementSibling.getElementsByClassName("command");
if ((commands !== null) && (commands.length > 0)) {
var lines = commands[0].innerText.split("\n");
var cmd = "";
for (var i = 0; i < lines.length; i++) {
if (lines[i].startsWith("$ ")) {
lines[i] = lines[i].substring(2);
}
if (cmd !== "") {
cmd = cmd + "\n";
}
cmd += lines[i];
}
return cmd;
}
return trigger.previousElementSibling.innerText;
return getToolbarDivText(trigger.parentElement);
}
});
// On success:
// - Change the "Copy" text to "Done".
// - Swap it to "Copy" in 2s.
copyCode.on('success', function (event) {
event.clearSelection();
event.trigger.textContent = 'Done';
window.setTimeout(function () {
event.trigger.textContent = 'Copy';
}, 2000);
});
// On error (Safari):
// - Change to "Not supported"
// - Swap it to "Copy" in 2s.
copyCode.on('error', function (event) {
event.trigger.textContent = 'Not supported';
window.setTimeout(function () {
event.trigger.textContent = 'Copy';
}, 5000);
alert("Sorry, but copying is not supported by your browser");
});
}
function applySyntaxColoring() {
function getToolbarDivText(div) {
var commands = div.getElementsByClassName("command");
if ((commands !== null) && (commands.length > 0)) {
var lines = commands[0].innerText.split("\n");
var cmd = "";
for (var i = 0; i < lines.length; i++) {
if (lines[i].startsWith("$ ")) {
lines[i] = lines[i].substring(2);
}
if (cmd !== "") {
cmd = cmd + "\n";
}
cmd += lines[i];
}
return cmd;
}
return div.innerText;
}
function applySyntaxColoringToPreBlocks() {
var pre = document.getElementsByTagName('PRE');
for (var i = 0; i < pre.length; i++) {
var code = pre[i].firstChild;
@ -340,7 +386,7 @@ function handleDOMLoaded() {
// Add a link icon next to each header so people can easily get bookmarks to headers
function attachLinksToHeaders() {
for (var level = 2; level <= 6; level++) {
var headers = document.getElementsByTagName("h" + level);
var headers = document.getElementsByTagName("h" + level.toString());
for (var i = 0; i < headers.length; i++) {
var header = headers[i];
if (header.id !== "") {
@ -437,8 +483,8 @@ function handleDOMLoaded() {
}
compensateForHugoBug();
attachCopyButtons();
applySyntaxColoring();
attachToolbarToPreBlocks();
applySyntaxColoringToPreBlocks();
attachLinksToHeaders();
attachLinksToDefinedTerms();
makeOutsideLinksOpenInTabs();
@ -528,5 +574,24 @@ function handlePageScroll() {
controlTOCActivation();
}
function saveFile(filename, text) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/text;charset=utf-8,' + encodeURI(text));
element.setAttribute('download', filename);
element.click();
}
function printText(text) {
var html="<html><body><pre><code>" + text + "</code></pre></html>";
var printWin = window.open('','','left=0,top=0,width=100,height=100,toolbar=0,scrollbars=0,status=0,location=0,menubar=0', false);
printWin.document.write(html);
printWin.document.close();
printWin.focus();
printWin.print();
printWin.close();
}
document.addEventListener("DOMContentLoaded", handleDOMLoaded);
window.addEventListener("scroll", handlePageScroll);

View File

@ -190,35 +190,44 @@ pre {
}
}
// this is necessary in order for proper positioning of the Copy button
div.copy {
div.toolbar {
position: relative;
}
button.copy {
font-size: .8em;
padding: 0 .5em;
border-radius: .3em;
background-color: $secondBrandColor;
cursor: pointer;
color: $textBrandColor;
text-decoration: none;
border: 0;
button {
font-size: .8em;
padding: 0 .5em;
border-radius: .3em;
background-color: $secondBrandColor;
cursor: pointer;
color: $textBrandColor;
text-decoration: none;
border: 0;
position: absolute;
top: 3px;
z-index: 5;
}
position: absolute;
top: 3px;
right: 1.3em;
z-index: 5;
}
button.toolbar-hide {
transition: opacity .4s ease-in-out;
opacity: 0;
}
button.copy-hide {
transition: opacity .4s ease-in-out;
opacity: 0;
}
button.toolbar-show {
transition: opacity 1.1s ease-in-out;
opacity: 1;
}
button.copy-show {
transition: opacity 1.2s ease-in-out;
opacity: 1;
button.copy {
right: 1.3em;
}
button.download {
right: 3.3em;
}
button.print {
right: 5.5em;
}
}
p {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long