Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use relative links and translate internal references #603

Merged
merged 2 commits into from
Jul 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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