Skip to content

Commit

Permalink
Use relative links and translate internal references (#603)
Browse files Browse the repository at this point in the history
* Relative links for 0.1.8

* Compat for IE11 search
  • Loading branch information
cetra3 authored and Michael-F-Bryan committed Jul 11, 2018
1 parent 01656b6 commit bdb37ec
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 93 deletions.
2 changes: 1 addition & 1 deletion book-example/src/cli/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ configuration files, etc.
- The `book` directory is where your book is rendered. All the output is ready to be uploaded
to a server to be seen by your audience.

- The `SUMMARY.md` file is the most important file, it's the skeleton of your book and is discussed in more detail in another [chapter](format/summary.html).
- The `SUMMARY.md` file is the most important file, it's the skeleton of your book and is discussed in more detail in another [chapter](../format/summary.md)

#### Tip & Trick: Hidden Feature
When a `SUMMARY.md` file already exists, the `init` command will first parse it and generate the missing files according to the paths used in the `SUMMARY.md`. This allows you to think and create the whole structure of your book and then let mdBook generate it for you.
Expand Down
4 changes: 2 additions & 2 deletions book-example/src/for_developers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ The *For Developers* chapters are here to show you the more advanced usage of

The two main ways a developer can hook into the book's build process is via,

- [Preprocessors](for_developers/preprocessors.html)
- [Alternate Backends](for_developers/backends.html)
- [Preprocessors](preprocessors.md)
- [Alternate Backends](backends.md)


## The Build Process
Expand Down
67 changes: 17 additions & 50 deletions src/renderer/html_handlebars/hbs_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ impl HtmlHandlebars {
.to_str()
.chain_err(|| "Could not convert path to str")?;
let filepath = Path::new(&ch.path).with_extension("html");
let filepathstr = filepath
.to_str()
.chain_err(|| "Could not convert HTML path to str")?;
let filepathstr = utils::fs::normalize_path(filepathstr);

// "print.html" is used for the print page.
if ch.path == Path::new("print.md") {
Expand Down Expand Up @@ -75,10 +71,10 @@ impl HtmlHandlebars {
debug!("Render template");
let rendered = ctx.handlebars.render("index", &ctx.data)?;

let rendered = self.post_process(rendered, &filepathstr, &ctx.html_config.playpen);
let rendered = self.post_process(rendered, &ctx.html_config.playpen);

// Write to file
debug!("Creating {} ✓", filepathstr);
debug!("Creating {} ✓", filepath.display());
utils::fs::write_file(&ctx.destination, &filepath, &rendered.into_bytes())?;

if ctx.is_index {
Expand Down Expand Up @@ -120,9 +116,8 @@ impl HtmlHandlebars {
}

#[cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
fn post_process(&self, rendered: String, filepath: &str, playpen_config: &Playpen) -> String {
let rendered = build_header_links(&rendered, filepath);
let rendered = fix_anchor_links(&rendered, filepath);
fn post_process(&self, rendered: String, playpen_config: &Playpen) -> String {
let rendered = build_header_links(&rendered);
let rendered = fix_code_blocks(&rendered);
let rendered = add_playpen_pre(&rendered, playpen_config);

Expand Down Expand Up @@ -360,7 +355,7 @@ impl Renderer for HtmlHandlebars {
debug!("Render template");
let rendered = handlebars.render("index", &data)?;

let rendered = self.post_process(rendered, "print.html", &html_config.playpen);
let rendered = self.post_process(rendered, &html_config.playpen);

utils::fs::write_file(&destination, "print.html", &rendered.into_bytes())?;
debug!("Creating print.html ✓");
Expand Down Expand Up @@ -497,7 +492,7 @@ fn make_data(

/// Goes through the rendered HTML, making sure all header tags are wrapped in
/// an anchor so people can link to sections directly.
fn build_header_links(html: &str, filepath: &str) -> String {
fn build_header_links(html: &str) -> String {
let regex = Regex::new(r"<h(\d)>(.*?)</h\d>").unwrap();
let mut id_counter = HashMap::new();

Expand All @@ -507,7 +502,7 @@ fn build_header_links(html: &str, filepath: &str) -> String {
.parse()
.expect("Regex should ensure we only ever get numbers here");

wrap_header_with_link(level, &caps[2], &mut id_counter, filepath)
wrap_header_with_link(level, &caps[2], &mut id_counter)
})
.into_owned()
}
Expand All @@ -517,8 +512,7 @@ fn build_header_links(html: &str, filepath: &str) -> String {
fn wrap_header_with_link(
level: usize,
content: &str,
id_counter: &mut HashMap<String, usize>,
filepath: &str,
id_counter: &mut HashMap<String, usize>
) -> String {
let raw_id = utils::id_from_content(content);

Expand All @@ -532,35 +526,13 @@ fn wrap_header_with_link(
*id_count += 1;

format!(
r##"<a class="header" href="{filepath}#{id}" id="{id}"><h{level}>{text}</h{level}></a>"##,
r##"<a class="header" href="#{id}" id="{id}"><h{level}>{text}</h{level}></a>"##,
level = level,
id = id,
text = content,
filepath = filepath
text = content
)
}

// anchors to the same page (href="#anchor") do not work because of
// <base href="../"> pointing to the root folder. This function *fixes*
// that in a very inelegant way
fn fix_anchor_links(html: &str, filepath: &str) -> String {
let regex = Regex::new(r##"<a([^>]+)href="#([^"]+)"([^>]*)>"##).unwrap();
regex
.replace_all(html, |caps: &Captures| {
let before = &caps[1];
let anchor = &caps[2];
let after = &caps[3];

format!(
"<a{before}href=\"{filepath}#{anchor}\"{after}>",
before = before,
filepath = filepath,
anchor = anchor,
after = after
)
})
.into_owned()
}

// The rust book uses annotations for rustdoc to test code snippets,
// like the following:
Expand Down Expand Up @@ -660,37 +632,32 @@ mod tests {
let inputs = vec![
(
"blah blah <h1>Foo</h1>",
r##"blah blah <a class="header" href="./some_chapter/some_section.html#foo" id="foo"><h1>Foo</h1></a>"##,
r##"blah blah <a class="header" href="#foo" id="foo"><h1>Foo</h1></a>"##,
),
(
"<h1>Foo</h1>",
r##"<a class="header" href="./some_chapter/some_section.html#foo" id="foo"><h1>Foo</h1></a>"##,
r##"<a class="header" href="#foo" id="foo"><h1>Foo</h1></a>"##,
),
(
"<h3>Foo^bar</h3>",
r##"<a class="header" href="./some_chapter/some_section.html#foobar" id="foobar"><h3>Foo^bar</h3></a>"##,
r##"<a class="header" href="#foobar" id="foobar"><h3>Foo^bar</h3></a>"##,
),
(
"<h4></h4>",
r##"<a class="header" href="./some_chapter/some_section.html#" id=""><h4></h4></a>"##,
r##"<a class="header" href="#" id=""><h4></h4></a>"##,
),
(
"<h4><em>Hï</em></h4>",
r##"<a class="header" href="./some_chapter/some_section.html#hï" id="hï"><h4><em>Hï</em></h4></a>"##,
r##"<a class="header" href="#hï" id="hï"><h4><em>Hï</em></h4></a>"##,
),
(
"<h1>Foo</h1><h3>Foo</h3>",
r##"<a class="header" href="./some_chapter/some_section.html#foo" id="foo"><h1>Foo</h1></a><a class="header" href="./some_chapter/some_section.html#foo-1" id="foo-1"><h3>Foo</h3></a>"##,
r##"<a class="header" href="#foo" id="foo"><h1>Foo</h1></a><a class="header" href="#foo-1" id="foo-1"><h3>Foo</h3></a>"##,
),
];

for (src, should_be) in inputs {
let filepath = "./some_chapter/some_section.html";
let got = build_header_links(&src, filepath);
assert_eq!(got, should_be);

// This is redundant for most cases
let got = fix_anchor_links(&got, filepath);
let got = build_header_links(&src);
assert_eq!(got, should_be);
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/renderer/html_handlebars/helpers/navigation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::collections::BTreeMap;
use serde_json;
use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError, Renderable};

use utils;

type StringMap = BTreeMap<String, String>;

/// Target for `find_chapter`.
Expand Down Expand Up @@ -87,6 +89,13 @@ fn render(
trace!("Creating BTreeMap to inject in context");

let mut context = BTreeMap::new();
let base_path = rc.evaluate_absolute("path", false)?
.as_str()
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.replace("\"", "");

context.insert("path_to_root".to_owned(),
json!(utils::fs::path_to_root(&base_path)));

chapter
.get("name")
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/html_handlebars/helpers/toc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::path::Path;
use std::collections::BTreeMap;

use utils;

use serde_json;
use handlebars::{Handlebars, Helper, HelperDef, RenderContext, RenderError};
use pulldown_cmark::{html, Event, Parser, Tag};
Expand Down Expand Up @@ -77,6 +79,7 @@ impl HelperDef for RenderToc {
.replace("\\", "/");

// Add link
rc.writer.write_all(&utils::fs::path_to_root(&current).as_bytes())?;
rc.writer.write_all(tmp.as_bytes())?;
rc.writer.write_all(b"\"")?;

Expand Down
6 changes: 3 additions & 3 deletions src/theme/book.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,9 @@ function playpen_text(playpen) {
var themePopup = document.getElementById('theme-list');
var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
var stylesheets = {
ayuHighlight: document.querySelector("[href='ayu-highlight.css']"),
tomorrowNight: document.querySelector("[href='tomorrow-night.css']"),
highlight: document.querySelector("[href='highlight.css']"),
ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"),
tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"),
highlight: document.querySelector("[href$='highlight.css']"),
};

function showThemes() {
Expand Down
51 changes: 26 additions & 25 deletions src/theme/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,18 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />

<base href="{{ path_to_root }}">

<link rel="stylesheet" href="book.css">
<link rel="stylesheet" href="{{ path_to_root }}book.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">

<link rel="shortcut icon" href="{{ favicon }}">

<!-- Font Awesome -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">

<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<link rel="stylesheet" href="{{ path_to_root }}highlight.css">
<link rel="stylesheet" href="{{ path_to_root }}tomorrow-night.css">
<link rel="stylesheet" href="{{ path_to_root }}ayu-highlight.css">

<!-- Custom theme stylesheets -->
{{#each additional_css}}
Expand Down Expand Up @@ -107,7 +105,7 @@
<h1 class="menu-title">{{ book_title }}</h1>

<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
Expand Down Expand Up @@ -144,13 +142,13 @@
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
{{#previous}}
<a rel="prev" href="{{link}}" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
{{/previous}}

{{#next}}
<a rel="next" href="{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}
Expand All @@ -162,13 +160,13 @@

<nav class="nav-wide-wrapper" aria-label="Page navigation">
{{#previous}}
<a href="{{link}}" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a href="{{ path_to_root }}{{link}}" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
{{/previous}}

{{#next}}
<a href="{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}
Expand Down Expand Up @@ -213,29 +211,32 @@
{{/if}}

{{#if playpen_js}}
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}ace.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}editor.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
{{/if}}

{{#if search_enabled}}
<script src="searchindex.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}searchindex.js" type="text/javascript" charset="utf-8"></script>
<script>
var path_to_root = "{{path_to_root}}";
</script>
{{/if}}
{{#if search_js}}
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}searcher.js" type="text/javascript" charset="utf-8"></script>
{{/if}}

<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ path_to_root }}book.js" type="text/javascript" charset="utf-8"></script>

<!-- Custom JS scripts -->
{{#each additional_js}}
<script type="text/javascript" src="{{this}}"></script>
<script type="text/javascript" src="{{ path_to_root }}{{this}}"></script>
{{/each}}

{{#if is_print}}
Expand Down
11 changes: 9 additions & 2 deletions src/theme/searcher/searcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ window.search = window.search || {};
if (!Mark || !elasticlunr) {
return;
}


//IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(search, pos) {
return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
};
}

var search_wrap = document.getElementById('search-wrapper'),
searchbar = document.getElementById('searchbar'),
searchbar_outer = document.getElementById('searchbar-outer'),
Expand Down Expand Up @@ -137,7 +144,7 @@ window.search = window.search || {};
url.push("");
}

return '<a href="' + url[0] + '?' + URL_MARK_PARAM + '=' + searchterms + '#' + url[1]
return '<a href="' + path_to_root + url[0] + '?' + URL_MARK_PARAM + '=' + searchterms + '#' + url[1]
+ '" aria-details="teaser_' + teaser_count + '">' + result.doc.breadcrumbs + '</a>'
+ '<span class="teaser" id="teaser_' + teaser_count + '" aria-label="Search Result Teaser">'
+ teaser + '</span>';
Expand Down
Loading

0 comments on commit bdb37ec

Please sign in to comment.