Compare commits

..

35 Commits

Author SHA1 Message Date
Michael Bryan
b765023da3 (cargo-release) version 0.1.3 2018-02-16 07:45:52 +08:00
Sorin Davidoi
d306aed587 Accessibility improvements (#611)
* fix(theme/book/themes): Check for control keys in event listener

* fix(theme/index): Menu role for theme selector

* fix(theme/book/themes): Handle focus when toggling theme list

* feat(theme/book/themes): Handle ArrowUp, ArrowDown, Home and End
2018-02-15 07:37:19 +08:00
Sorin Davidoi
89a5dbaf9a fix(theme/stylus/sidebar): Contain scrolling to the sidebar (#612)
> A position fixed left navigation bar does not want to hand off scrolling to the document because a scroll gesture performed on the navigation bar is almost never meant to scroll the document. In this case, the author can use contain on the sidebar to prevent scrolling from being chained to the parent document element.

https://wicg.github.io/overscroll-behavior/#motivating-examples
2018-02-15 07:24:39 +08:00
Ryan Scheel
6961247f56 Include Cargo.lock (#620) 2018-02-15 07:03:10 +08:00
Sorin Davidoi
07551760c9 feat(theme/stylus/sidebar): Reduce padding on non-touch devices (#615)
Closes #594.
2018-02-15 06:59:55 +08:00
Sorin Davidoi
990daceed5 feat(theme/book): Scroll to top when clicking the page title (#613)
Common pattern, especially on mobile devices where the page can be quite long.
2018-02-09 18:34:18 +08:00
Mathieu David
2989096188 Merge pull request #609 from bchatard/typo
Fix typo in format configuration
2018-02-05 15:17:24 +01:00
bchatard
03c6c44e5b Fix typo in format configuration 2018-02-05 13:01:17 +01:00
Ofek Lev
31a370d149 fix readme (#606) 2018-02-05 07:11:55 +08:00
Bulat Musin
0bc1030a02 implement clean subcommand (#583) 2018-02-04 21:00:29 +08:00
boxdot
43fcd00cd5 Inline footnotes. (#600) 2018-02-02 20:15:48 +08:00
Mathieu David
3d83b784b3 Merge pull request #601 from tshepang/patch-1
doc: small fixes
2018-02-01 11:31:55 +01:00
Tshepang Lekhonkhobe
5d42738a79 doc: small fixes 2018-02-01 03:29:39 +02:00
Michael Bryan
1f4dab3e5c (cargo-release) start next development iteration 0.1.3-alpha.0 2018-01-31 19:19:50 +08:00
Michael Bryan
7181993b43 (cargo-release) version 0.1.2 2018-01-31 19:18:02 +08:00
boxdot
bf9f58e11b Add docs for mdBook specific include feature (#593)
* Add docs for mdBook specific include feature.

Also:
* Fix bug in take_lines taking `end`-many lines instead of
  `end-start` many.
* Handle special case `include:number` as including a single line.
* Start counting lines at 1 and not 0.

* Merge mdBook and rust specific features into one chapter.
2018-01-31 18:57:47 +08:00
Steve Klabnik
3ba71c570c Handle input path with regards to custom css (#598)
* Handle input path with regards to custom css

Before, when someone like the Reference set their extra css as
"theme/reference.css" in their book.toml, this path would be treated as
relative to the invocation of mdbook, and not respect the input path. This
PR modifies these relative paths to do so.

Fixes the build of https://github.com/rust-lang/rust/pull/47753 which
blocks updating rustc to mdbook 0.1

* don't use file-name

the style name is theme/reference.css, this results in a Err(StripPrefixError(())), which means that we push only the file_name, losing the theme bit
2018-01-30 12:29:09 +08:00
Sorin Davidoi
674e58e747 fix(theme): Use aria-label alonside title (#568)
Tested this on macOS with VoiceOver, and it does not pick up the title as the text of the button. Kind of makes sense, since title and aria-label are not the same. This will make sure that the buttons and links are labeled properly.
2018-01-27 18:52:47 +08:00
Michael Bryan
348c5d07c5 (cargo-release) start next development iteration 0.1.2-alpha.0 2018-01-27 11:56:22 +08:00
Michael Bryan
1790b04e03 (cargo-release) version 0.1.1 2018-01-27 11:54:27 +08:00
Michael Bryan
50ee15472b Updated the light theme to have a lighter scrollbar (#590) 2018-01-27 11:52:43 +08:00
Michael Bryan
ffb90bb9e2 Made sure we create the themes directory (#586) 2018-01-26 14:38:53 +08:00
Sorin Davidoi
186e649530 feat(src/theme): Scrollbar theme (#563) 2018-01-26 01:17:02 +08:00
Michael Bryan
adc1f4ade7 Reverted #549 (#565) 2018-01-26 01:12:10 +08:00
Michael Bryan
b777a318f7 Expose functionality for creating core types (#578)
* You can now add chapters to a Book

* Made the RenderContext::new() constructor public
2018-01-26 01:11:48 +08:00
Michael Bryan
30e3b83167 Updated Cargo.toml metadata to make releases easier (#584) 2018-01-26 01:11:32 +08:00
Sorin Davidoi
f082187844 fix(theme/book): Use passive listeners for touchstart, touchmove (#575) 2018-01-25 18:44:22 +08:00
Michael Bryan
6119972fa7 Merge pull request #581 from bmusin/patch-3
fix typo
2018-01-25 17:49:40 +08:00
Michael Bryan
a910435fd9 Merge pull request #577 from Michael-F-Bryan/missing-backends-arent-fatal
Missing backends shouldn't be fatal
2018-01-25 07:33:54 +08:00
Bulat Musin
53b902b479 remove dot for consistency (#580) 2018-01-25 07:32:52 +08:00
Bulat Musin
2e9d8671a0 fix typo (insert dash) (#582) 2018-01-25 07:32:33 +08:00
Bulat Musin
50cdfc9623 fix typo (#579) 2018-01-25 07:25:56 +08:00
Bulat Musin
d47f4dce7f fix typo 2018-01-24 21:52:51 +03:00
Michael Bryan
bda23f0183 Missing backends are no longer fatal 2018-01-25 01:15:29 +08:00
Michael Bryan
1fbad982d8 (cargo-release) start next development iteration 0.1.1-alpha.0 2018-01-23 22:06:55 +08:00
33 changed files with 1795 additions and 117 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,3 @@
Cargo.lock
target
# MacOS temp file

View File

@@ -28,10 +28,10 @@ matrix:
- env: TARGET=x86_64-unknown-linux-musl
# Mac
# - env: TARGET=i686-apple-darwin
# os: osx
# - env: TARGET=x86_64-apple-darwin
# os: osx
- env: TARGET=i686-apple-darwin
os: osx
- env: TARGET=x86_64-apple-darwin
os: osx
# BSD
- env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1
@@ -41,14 +41,14 @@ matrix:
# Other channels
- env: TARGET=x86_64-unknown-linux-gnu
rust: beta
# - env: TARGET=x86_64-apple-darwin
# os: osx
# rust: beta
- env: TARGET=x86_64-apple-darwin
os: osx
rust: beta
- env: TARGET=x86_64-unknown-linux-gnu
rust: nightly
# - env: TARGET=x86_64-apple-darwin
# os: osx
# rust: nightly
- env: TARGET=x86_64-apple-darwin
os: osx
rust: nightly
before_install:
- set -e

1380
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "mdbook"
version = "0.1.0"
version = "0.1.3"
authors = ["Mathieu David <mathieudavid@mathieudavid.org>", "Michael-F-Bryan <michaelfbryan@gmail.com>"]
description = "create books from markdown files (like Gitbook)"
documentation = "http://rust-lang-nursery.github.io/mdBook/index.html"
@@ -14,6 +14,11 @@ exclude = [
"src/theme/stylus/**",
]
[package.metadata.release]
sign-commit = true
push-remote = "upstream"
tag-prefix = "v"
[dependencies]
clap = "2.24"
chrono = "0.4"
@@ -65,6 +70,3 @@ serve = ["iron", "staticfile", "ws"]
doc = false
name = "mdbook"
path = "src/bin/mdbook.rs"
[workspace]
members = ["book-example/src/for_developers/mdbook-wordcount"]

View File

@@ -40,7 +40,7 @@ There are multiple ways to install mdBook.
path to the binary into your `PATH`.
2. **From Crates.io**
j
This requires [Rust] and Cargo to be installed. Once you have installed
Rust, type the following in the terminal:

View File

@@ -15,7 +15,7 @@
- [Syntax highlighting](format/theme/syntax-highlighting.md)
- [Editor](format/theme/editor.md)
- [MathJax Support](format/mathjax.md)
- [Rust code specific features](format/rust.md)
- [mdBook specific features](format/mdbook.md)
- [For Developers](for_developers/index.md)
- [Preprocessors](for_developers/preprocessors.md)
- [Alternate Backends](for_developers/backends.md)

View File

@@ -21,7 +21,7 @@ mdbook serve path/to/book
For example: suppose you had an nginx server for SSL termination which has a public address of 192.168.1.100 on port 80 and proxied that to 127.0.0.1 on port 8000. To run use the nginx proxy do:
```bash
mdbook server path/to/book -p 8000 -i 127.0.0.1 -a 192.168.1.100
mdbook serve path/to/book -p 8000 -i 127.0.0.1 -a 192.168.1.100
```
If you were to want live reloading for this you would need to proxy the websocket calls through nginx as well from `192.168.1.100:<WS_PORT>` to `127.0.0.1:<WS_PORT>`. The `-w` flag allows for the websocket port to be configured.

View File

@@ -116,7 +116,7 @@ tables. If none are provided it'll fall back to using the default HTML
renderer.
Notably, this means if you want to add your own custom backend you'll also
need to make sure to add the HTML backend, even if its tabke just stays empty.
need to make sure to add the HTML backend, even if its table just stays empty.
Now you just need to build your book like normal, and everything should *Just
Work*.
@@ -149,7 +149,7 @@ The reason we didn't need to specify the full name/path of our `wordcount`
backend is because `mdbook` will try to *infer* the program's name via
convention. The executable for the `foo` backend is typically called
`mdbook-foo`, with an associated `[output.foo]` entry in the `book.toml`. To
explicitly tell `mdbook` what command to invoke (it may require command line
explicitly tell `mdbook` what command to invoke (it may require command-line
arguments or be an interpreted script), you can use the `command` field.
```diff
@@ -349,4 +349,4 @@ the source code or ask questions.
[`Book`]: http://rust-lang-nursery.github.io/mdBook/mdbook/book/struct.Book.html
[`Book::iter()`]: http://rust-lang-nursery.github.io/mdBook/mdbook/book/struct.Book.html#method.iter
[`Config`]: http://rust-lang-nursery.github.io/mdBook/mdbook/config/struct.Config.html
[issue tracker]: https://github.com/rust-lang-nursery/mdBook/issues
[issue tracker]: https://github.com/rust-lang-nursery/mdBook/issues

View File

@@ -21,7 +21,7 @@ The process of rendering a book project goes through several steps.
1. Load the book
- Parse the `book.toml`, falling back to the default `Config` if it doesn't
exist.
exist
- Load the book chapters into memory
- Discover which preprocessors/backends should be used
2. Run the preprocessors
@@ -43,4 +43,4 @@ explanation on the configuration system.
[`MDBook`]: http://rust-lang-nursery.github.io/mdBook/mdbook/book/struct.MDBook.html
[API Docs]: http://rust-lang-nursery.github.io/mdBook/mdbook/
[config]: file:///home/michael/Documents/forks/mdBook/target/doc/mdbook/config/index.html
[config]: file:///home/michael/Documents/forks/mdBook/target/doc/mdbook/config/index.html

View File

@@ -2,9 +2,8 @@
name = "mdbook-wordcount"
version = "0.1.0"
authors = ["Michael Bryan <michaelfbryan@gmail.com>"]
workspace = "../../../.."
[dependencies]
mdbook = { path = "../../../.." }
mdbook = { path = "../../../..", version = "*" }
serde = "1.0"
serde_derive = "1.0"

View File

@@ -110,7 +110,7 @@ editable = false
## Environment Variables
All configuration values van be overridden from the command line by setting the
All configuration values can be overridden from the command line by setting the
corresponding environment variable. Because many operating systems restrict
environment variables to be alphanumeric characters or `_`, the configuration
key needs to be formatted slightly differently to the normal `foo.bar.baz` form.

View File

@@ -0,0 +1,64 @@
# mdBook-specific markdown
## Hiding code lines
There is a feature in mdBook that lets you hide code lines by prepending them with a `#`.
```bash
# fn main() {
let x = 5;
let y = 6;
println!("{}", x + y);
# }
```
Will render as
```rust
# fn main() {
let x = 5;
let y = 7;
println!("{}", x + y);
# }
```
## Including files
With the following syntax, you can include files into your book:
```hbs
\{{#include file.rs}}
```
The path to the file has to be relative from the current source file.
Usually, this command is used for including code snippets and examples. In this case, oftens one would include a specific part of the file e.g. which only contains the relevant lines for the example. We support four different modes of partial includes:
```hbs
\{{#include file.rs:2}}
\{{#include file.rs::10}}
\{{#include file.rs:2:}}
\{{#include file.rs:2:10}}
```
The first command only includes the second line from file `file.rs`. The second command includes all lines up to line 10, i.e. the lines from 11 till the end of the file are omitted. The third command includes all lines from line 2, i.e. the first line is omitted. The last command includes the excerpt of `file.rs` consisting of lines 2 to 10.
## Inserting runnable Rust files
With the following syntax, you can insert runnable Rust files into your book:
```hbs
\{{#playpen file.rs}}
```
The path to the Rust file has to be relative from the current source file.
When play is clicked, the code snippet will be sent to the [Rust Playpen] to be compiled and run. The result is sent back and displayed directly underneath the code.
Here is what a rendered code snippet looks like:
{{#playpen example.rs}}
[Rust Playpen]: https://play.rust-lang.org/

View File

@@ -1,44 +0,0 @@
# Rust code specific features
## Hiding code lines
There is a feature in mdBook that let's you hide code lines by prepending them with a `#`.
```bash
# fn main() {
let x = 5;
let y = 6;
println!("{}", x + y);
# }
```
Will render as
```rust
# fn main() {
let x = 5;
let y = 7;
println!("{}", x + y);
# }
```
## Inserting runnable Rust files
With the following syntax, you can insert runnable Rust files into your book:
```hbs
\{{#playpen file.rs}}
```
The path to the Rust file has to be relative from the current source file.
When play is clicked, the code snippet will be send to the [Rust Playpen] to be compiled and run. The result is send back and displayed directly underneath the code.
Here is what a rendered code snippet looks like:
{{#playpen example.rs}}
[Rust Playpen]: https://play.rust-lang.org/

30
src/bin/clean.rs Normal file
View File

@@ -0,0 +1,30 @@
use std::fs;
use std::path::PathBuf;
use clap::{App, ArgMatches, SubCommand};
use mdbook::MDBook;
use mdbook::errors::*;
use get_book_dir;
// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("clean")
.about("Delete built book")
.arg_from_usage(
"-d, --dest-dir=[dest-dir] 'The directory of built book{n}(Defaults to ./book when \
omitted)'",
)
}
// Clean command implementation
pub fn execute(args: &ArgMatches) -> ::mdbook::errors::Result<()> {
let book_dir = get_book_dir(args);
let book = MDBook::load(&book_dir)?;
let dir_to_remove = match args.value_of("dest-dir") {
Some(dest_dir) => PathBuf::from(dest_dir),
None => book.root.join(&book.config.build.build_dir),
};
fs::remove_dir_all(&dir_to_remove).chain_err(|| "Unable to remove the build directory")?;
Ok(())
}

View File

@@ -19,6 +19,7 @@ use env_logger::Builder;
use mdbook::utils;
pub mod build;
pub mod clean;
pub mod init;
pub mod test;
#[cfg(feature = "serve")]
@@ -44,7 +45,8 @@ fn main() {
at: https://github.com/rust-lang-nursery/mdBook")
.subcommand(init::make_subcommand())
.subcommand(build::make_subcommand())
.subcommand(test::make_subcommand());
.subcommand(test::make_subcommand())
.subcommand(clean::make_subcommand());
#[cfg(feature = "watch")]
let app = app.subcommand(watch::make_subcommand());
@@ -55,6 +57,7 @@ fn main() {
let res = match app.get_matches().subcommand() {
("init", Some(sub_matches)) => init::execute(sub_matches),
("build", Some(sub_matches)) => build::execute(sub_matches),
("clean", Some(sub_matches)) => clean::execute(sub_matches),
#[cfg(feature = "watch")]
("watch", Some(sub_matches)) => watch::execute(sub_matches),
#[cfg(feature = "serve")]

View File

@@ -101,6 +101,12 @@ impl Book {
{
for_each_mut(&mut func, &mut self.sections);
}
/// Append a `BookItem` to the `Book`.
pub fn push_item<I: Into<BookItem>>(&mut self, item: I) -> &mut Self {
self.sections.push(item.into());
self
}
}
pub fn for_each_mut<'a, F, I>(func: &mut F, items: I)
@@ -126,6 +132,12 @@ pub enum BookItem {
Separator,
}
impl From<Chapter> for BookItem {
fn from(other: Chapter) -> BookItem {
BookItem::Chapter(other)
}
}
/// The representation of a "chapter", usually mapping to a single file on
/// disk however it may contain multiple sub-chapters.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]

View File

@@ -10,7 +10,7 @@ use book::{Book, BookItem};
const ESCAPE_CHAR: char = '\\';
/// A preprocessor for expanding the `{{# playpen}}` and `{{# include}}`
/// A preprocessor for expanding the `{{# playpen}}` and `{{# include}}`
/// helpers in a chapter.
pub struct LinkPreprocessor;
@@ -87,8 +87,14 @@ enum LinkType<'a> {
fn parse_include_path(path: &str) -> LinkType<'static> {
let mut parts = path.split(':');
let path = parts.next().unwrap().into();
let start = parts.next().and_then(|s| s.parse::<usize>().ok());
let end = parts.next().and_then(|s| s.parse::<usize>().ok());
// subtract 1 since line numbers usually begin with 1
let start = parts
.next()
.and_then(|s| s.parse::<usize>().ok())
.map(|val| val.checked_sub(1).unwrap_or(0));
let end = parts.next();
let has_end = end.is_some();
let end = end.and_then(|s| s.parse::<usize>().ok());
match start {
Some(start) => match end {
Some(end) => LinkType::IncludeRange(
@@ -98,7 +104,17 @@ fn parse_include_path(path: &str) -> LinkType<'static> {
end: end,
},
),
None => LinkType::IncludeRangeFrom(path, RangeFrom { start: start }),
None => if has_end {
LinkType::IncludeRangeFrom(path, RangeFrom { start: start })
} else {
LinkType::IncludeRange(
path,
Range {
start: start,
end: start + 1,
},
)
},
},
None => match end {
Some(end) => LinkType::IncludeRangeTo(path, RangeTo { end: end }),
@@ -276,13 +292,31 @@ mod tests {
Link {
start_index: 22,
end_index: 48,
link: LinkType::IncludeRange(PathBuf::from("file.rs"), 10..20),
link: LinkType::IncludeRange(PathBuf::from("file.rs"), 9..20),
link_text: "{{#include file.rs:10:20}}",
},
]
);
}
#[test]
fn test_find_links_with_line_number() {
let s = "Some random text with {{#include file.rs:10}}...";
let res = find_links(s).collect::<Vec<_>>();
println!("\nOUTPUT: {:?}\n", res);
assert_eq!(
res,
vec![
Link {
start_index: 22,
end_index: 45,
link: LinkType::IncludeRange(PathBuf::from("file.rs"), 9..10),
link_text: "{{#include file.rs:10}}",
},
]
);
}
#[test]
fn test_find_links_with_from_range() {
let s = "Some random text with {{#include file.rs:10:}}...";
@@ -294,7 +328,7 @@ mod tests {
Link {
start_index: 22,
end_index: 46,
link: LinkType::IncludeRangeFrom(PathBuf::from("file.rs"), 10..),
link: LinkType::IncludeRangeFrom(PathBuf::from("file.rs"), 9..),
link_text: "{{#include file.rs:10:}}",
},
]

View File

@@ -238,23 +238,28 @@ impl HtmlHandlebars {
/// Copy across any additional CSS and JavaScript files which the book
/// has been configured to use.
fn copy_additional_css_and_js(&self, html: &HtmlConfig, destination: &Path) -> Result<()> {
fn copy_additional_css_and_js(&self, html: &HtmlConfig, root: &Path, destination: &Path) -> Result<()> {
let custom_files = html.additional_css.iter().chain(html.additional_js.iter());
debug!("Copying additional CSS and JS");
for custom_file in custom_files {
let input_location = root.join(custom_file);
let output_location = destination.join(custom_file);
if let Some(parent) = output_location.parent() {
fs::create_dir_all(parent)
.chain_err(|| format!("Unable to create {}", parent.display()))?;
}
debug!(
"Copying {} -> {}",
custom_file.display(),
input_location.display(),
output_location.display()
);
fs::copy(custom_file, &output_location).chain_err(|| {
fs::copy(&input_location, &output_location).chain_err(|| {
format!(
"Unable to copy {} to {}",
custom_file.display(),
input_location.display(),
output_location.display()
)
})?;
@@ -334,7 +339,7 @@ impl Renderer for HtmlHandlebars {
debug!("Copy static files");
self.copy_static_files(&destination, &theme, &html_config)
.chain_err(|| "Unable to copy across static files")?;
self.copy_additional_css_and_js(&html_config, &destination)
self.copy_additional_css_and_js(&html_config, &ctx.root, &destination)
.chain_err(|| "Unable to copy across additional CSS and JS")?;
// Copy all remaining files
@@ -371,11 +376,11 @@ fn make_data(root: &Path, book: &Book, config: &Config, html_config: &HtmlConfig
let mut css = Vec::new();
for style in &html.additional_css {
match style.strip_prefix(root) {
Ok(p) => css.push(p.to_str().expect("Could not convert to str")),
Ok(p) => {
css.push(p.to_str().expect("Could not convert to str"))
},
Err(_) => {
css.push(style.file_name()
.expect("File has a file name")
.to_str()
css.push(style.to_str()
.expect("Could not convert to str"))
}
}

View File

@@ -16,7 +16,7 @@ pub use self::html_handlebars::HtmlHandlebars;
mod html_handlebars;
use std::fs;
use std::io::Read;
use std::io::{self, Read};
use std::path::PathBuf;
use std::process::{Command, Stdio};
use serde_json;
@@ -26,6 +26,8 @@ use errors::*;
use config::Config;
use book::Book;
const MDBOOK_VERSION: &str = env!("CARGO_PKG_VERSION");
/// An arbitrary `mdbook` backend.
///
/// Although it's quite possible for you to import `mdbook` as a library and
@@ -68,7 +70,7 @@ pub struct RenderContext {
impl RenderContext {
/// Create a new `RenderContext`.
pub(crate) fn new<P, Q>(root: P, book: Book, config: Config, destination: Q) -> RenderContext
pub fn new<P, Q>(root: P, book: Book, config: Config, destination: Q) -> RenderContext
where
P: Into<PathBuf>,
Q: Into<PathBuf>,
@@ -76,7 +78,7 @@ impl RenderContext {
RenderContext {
book: book,
config: config,
version: env!("CARGO_PKG_VERSION").to_string(),
version: MDBOOK_VERSION.to_string(),
root: root.into(),
destination: destination.into(),
}
@@ -155,13 +157,22 @@ impl Renderer for CmdRenderer {
let _ = fs::create_dir_all(&ctx.destination);
let mut child = self.compose_command()?
let mut child = match self.compose_command()?
.stdin(Stdio::piped())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.current_dir(&ctx.destination)
.spawn()
.chain_err(|| "Unable to start the renderer")?;
.spawn() {
Ok(c) => c,
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
warn!("The command wasn't found, is the \"{}\" backend installed?", self.name);
warn!("\tCommand: {}", self.cmd);
return Ok(());
}
Err(e) => {
return Err(e).chain_err(|| "Unable to start the backend")?;
}
};
{
let mut stdin = child.stdin.take().expect("Child has stdin");

View File

@@ -47,6 +47,17 @@ table td {
table thead td {
font-weight: 700;
}
:not(.footnote-definition) + .footnote-definition,
.footnote-definition + :not(.footnote-definition) {
margin-top: 2em;
}
.footnote-definition {
font-size: 0.9em;
margin: 0.5em 0;
}
.footnote-definition p {
display: inline;
}
.sidebar {
position: fixed;
left: 0;
@@ -60,6 +71,7 @@ table thead td {
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
overscroll-behavior-y: contain;
-webkit-transition: -webkit-transform 0.5s;
-moz-transition: -moz-transform 0.5s;
-o-transition: -o-transform 0.5s;
@@ -83,16 +95,26 @@ table thead td {
}
.chapter li a {
display: block;
padding: 5px 0;
padding: 0;
text-decoration: none;
}
@media (-moz-touch-enabled: 1), (pointer: coarse) {
.chapter li a {
padding: 5px 0;
}
}
.chapter li a:hover {
text-decoration: none;
}
.chapter .spacer {
width: 100%;
height: 3px;
margin: 10px 0px;
margin: 5px 0px;
}
@media (-moz-touch-enabled: 1), (pointer: coarse) {
.chapter .spacer {
margin: 10px 0;
}
}
.section {
list-style: none outside none;
@@ -209,6 +231,7 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
cursor: pointer;
}
.nav-chapters {
font-size: 2.5em;
@@ -340,6 +363,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
background-color: #fafafa;
color: #364149;
}
.light .sidebar::-webkit-scrollbar {
background: #fafafa;
}
.light .sidebar::-webkit-scrollbar-thumb {
background: #ccc;
}
.light .chapter li {
color: #aaa;
}
@@ -464,6 +493,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
.light .icon-button i {
margin: 0;
}
.light ::-webkit-scrollbar {
background: #fff;
}
.light ::-webkit-scrollbar-thumb {
background: #ccc;
}
.coal {
color: #98a3ad;
background-color: #141617;
@@ -494,6 +529,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
background-color: #292c2f;
color: #a1adb8;
}
.coal .sidebar::-webkit-scrollbar {
background: #292c2f;
}
.coal .sidebar::-webkit-scrollbar-thumb {
background: #a1adb8;
}
.coal .chapter li {
color: #505254;
}
@@ -618,6 +659,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
.coal .icon-button i {
margin: 0;
}
.coal ::-webkit-scrollbar {
background: #141617;
}
.coal ::-webkit-scrollbar-thumb {
background: #a1adb8;
}
.navy {
color: #bcbdd0;
background-color: #161923;
@@ -648,6 +695,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
background-color: #282d3f;
color: #c8c9db;
}
.navy .sidebar::-webkit-scrollbar {
background: #282d3f;
}
.navy .sidebar::-webkit-scrollbar-thumb {
background: #c8c9db;
}
.navy .chapter li {
color: #505274;
}
@@ -772,6 +825,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
.navy .icon-button i {
margin: 0;
}
.navy ::-webkit-scrollbar {
background: #161923;
}
.navy ::-webkit-scrollbar-thumb {
background: #c8c9db;
}
.rust {
color: #262625;
background-color: #e1e1db;
@@ -802,6 +861,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
background-color: #3b2e2a;
color: #c8c9db;
}
.rust .sidebar::-webkit-scrollbar {
background: #3b2e2a;
}
.rust .sidebar::-webkit-scrollbar-thumb {
background: #c8c9db;
}
.rust .chapter li {
color: #505254;
}
@@ -926,6 +991,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
.rust .icon-button i {
margin: 0;
}
.rust ::-webkit-scrollbar {
background: #e1e1db;
}
.rust ::-webkit-scrollbar-thumb {
background: #c8c9db;
}
.ayu {
color: #c5c5c5;
background-color: #0f1419;
@@ -956,6 +1027,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
background-color: #14191f;
color: #c8c9db;
}
.ayu .sidebar::-webkit-scrollbar {
background: #14191f;
}
.ayu .sidebar::-webkit-scrollbar-thumb {
background: #c8c9db;
}
.ayu .chapter li {
color: #5c6773;
}
@@ -1080,6 +1157,12 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
.ayu .icon-button i {
margin: 0;
}
.ayu ::-webkit-scrollbar {
background: #0f1419;
}
.ayu ::-webkit-scrollbar-thumb {
background: #c8c9db;
}
@media only print {
#sidebar,
#menu-bar,

View File

@@ -172,7 +172,7 @@ function playpen_text(playpen) {
var buttons = document.createElement('div');
buttons.className = 'buttons';
buttons.innerHTML = "<i class=\"fa fa-expand\" title=\"Show hidden lines\"></i>";
buttons.innerHTML = "<button class=\"fa fa-expand\" title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>";
// add expand button
pre_block.prepend(buttons);
@@ -184,6 +184,7 @@ function playpen_text(playpen) {
e.target.classList.remove('fa-expand');
e.target.classList.add('fa-compress');
e.target.title = 'Hide lines';
e.target.setAttribute('aria-label', e.target.title);
Array.from(lines).forEach(function (line) {
line.classList.remove('hidden');
@@ -195,6 +196,7 @@ function playpen_text(playpen) {
e.target.classList.remove('fa-compress');
e.target.classList.add('fa-expand');
e.target.title = 'Show hidden lines';
e.target.setAttribute('aria-label', e.target.title);
Array.from(lines).forEach(function (line) {
line.classList.remove('unhidden');
@@ -217,6 +219,7 @@ function playpen_text(playpen) {
var clipButton = document.createElement('button');
clipButton.className = 'fa fa-copy clip-button';
clipButton.title = 'Copy to clipboard';
clipButton.setAttribute('aria-label', clipButton.title);
clipButton.innerHTML = '<i class=\"tooltiptext\"></i>';
buttons.prepend(clipButton);
@@ -237,11 +240,13 @@ function playpen_text(playpen) {
runCodeButton.className = 'fa fa-play play-button';
runCodeButton.hidden = true;
runCodeButton.title = 'Run this code';
runCodeButton.setAttribute('aria-label', runCodeButton.title);
var copyCodeClipboardButton = document.createElement('button');
copyCodeClipboardButton.className = 'fa fa-copy clip-button';
copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
copyCodeClipboardButton.title = 'Copy to clipboard';
copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
buttons.prepend(runCodeButton);
buttons.prepend(copyCodeClipboardButton);
@@ -255,6 +260,7 @@ function playpen_text(playpen) {
var undoChangesButton = document.createElement('button');
undoChangesButton.className = 'fa fa-history reset-button';
undoChangesButton.title = 'Undo changes';
undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
buttons.prepend(undoChangesButton);
@@ -279,6 +285,7 @@ function playpen_text(playpen) {
})();
(function themes() {
var html = document.querySelector('html');
var themeToggleButton = document.getElementById('theme-toggle');
var themePopup = document.getElementById('theme-list');
var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
@@ -291,11 +298,13 @@ function playpen_text(playpen) {
function showThemes() {
themePopup.style.display = 'block';
themeToggleButton.setAttribute('aria-expanded', true);
themePopup.querySelector("button#" + document.body.className).focus();
}
function hideThemes() {
themePopup.style.display = 'none';
themeToggleButton.setAttribute('aria-expanded', false);
themeToggleButton.focus();
}
function set_theme(theme) {
@@ -331,9 +340,15 @@ function playpen_text(playpen) {
});
}
var previousTheme;
try { previousTheme = localStorage.getItem('mdbook-theme'); } catch (e) { }
if (previousTheme === null || previousTheme === undefined) { previousTheme = 'light'; }
try { localStorage.setItem('mdbook-theme', theme); } catch (e) { }
document.body.className = theme;
html.classList.remove(previousTheme);
html.classList.add(theme);
}
// Set theme
@@ -356,19 +371,43 @@ function playpen_text(playpen) {
set_theme(theme);
});
// Hide theme selector popup when clicking outside of it
document.addEventListener('click', function (event) {
if (themePopup.style.display === 'block' && !themeToggleButton.contains(event.target) && !themePopup.contains(event.target)) {
themePopup.addEventListener('focusout', function(e) {
if (!themePopup.contains(e.relatedTarget)) {
hideThemes();
}
});
document.addEventListener('keydown', function (e) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
if (!themePopup.contains(e.target)) { return; }
switch (e.key) {
case 'Escape':
e.preventDefault();
hideThemes();
break;
case 'ArrowUp':
e.preventDefault();
var li = document.activeElement.parentElement;
if (li && li.previousElementSibling) {
li.previousElementSibling.querySelector('button').focus();
}
break;
case 'ArrowDown':
e.preventDefault();
var li = document.activeElement.parentElement;
if (li && li.nextElementSibling) {
li.nextElementSibling.querySelector('button').focus();
}
break;
case 'Home':
e.preventDefault();
themePopup.querySelector('li:first-child button').focus();
break;
case 'End':
e.preventDefault();
themePopup.querySelector('li:last-child button').focus();
break;
}
});
})();
@@ -422,7 +461,7 @@ function playpen_text(playpen) {
x: e.touches[0].clientX,
time: Date.now()
};
});
}, { passive: true });
document.addEventListener('touchmove', function (e) {
if (!firstContact)
@@ -440,7 +479,7 @@ function playpen_text(playpen) {
firstContact = null;
}
});
}, { passive: true });
// Scroll sidebar to current active section
var activeSection = sidebar.querySelector(".active");
@@ -509,6 +548,14 @@ function playpen_text(playpen) {
});
})();
(function scrollToTop () {
var menuTitle = document.querySelector('.menu-title');
menuTitle.addEventListener('click', function () {
document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
});
})();
(function autoHideMenu() {
var menu = document.getElementById('menu-bar');

View File

@@ -65,6 +65,7 @@
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = 'light'; }
document.body.className = theme;
document.querySelector('html').className = theme;
</script>
<!-- Hide / unhide sidebar before it is displayed -->
@@ -88,25 +89,25 @@
<div id="menu-bar" class="menu-bar">
<div id="menu-bar-sticky-container">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-controls="sidebar">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="submenu">
<li><button class="theme" id="light">Light <span class="default">(default)</span></button></li>
<li><button class="theme" id="rust">Rust</button></li>
<li><button class="theme" id="coal">Coal</button></li>
<li><button class="theme" id="navy">Navy</button></li>
<li><button class="theme" id="ayu">Ayu</button></li>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light <span class="default">(default)</span></button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
</div>
<h1 class="menu-title">{{ book_title }}</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
@@ -130,13 +131,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-keyshortcuts="Left">
<a rel="prev" href="{{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-keyshortcuts="Right">
<a rel="next" href="{{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}}
@@ -148,13 +149,13 @@
<nav class="nav-wide-wrapper" aria-label="Page navigation">
{{#previous}}
<a href="{{link}}" class="nav-chapters previous" title="Previous chapter" aria-keyshortcuts="Left">
<a href="{{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-keyshortcuts="Right">
<a href="{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}

View File

@@ -48,3 +48,15 @@ table {
td { font-weight: 700; }
}
}
:not(.footnote-definition) + .footnote-definition,
.footnote-definition + :not(.footnote-definition) {
margin-top: 2em;
}
.footnote-definition {
font-size: 0.9em;
margin: 0.5em 0;
p { display: inline; }
}

View File

@@ -38,4 +38,5 @@ html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-conta
white-space: nowrap
overflow: hidden
text-overflow: ellipsis
cursor: pointer;
}

View File

@@ -11,6 +11,7 @@
font-size: 0.875em
box-sizing: border-box
-webkit-overflow-scrolling: touch
overscroll-behavior-y: contain;
// Animation: slide away
transition: transform 0.5s
@@ -31,16 +32,18 @@
li a {
display: block;
padding: 5px 0
padding: 0
text-decoration: none
@media (-moz-touch-enabled: 1), (pointer: coarse) { padding: 5px 0; }
&:hover { text-decoration: none }
}
.spacer {
width: 100%
height: 3px
margin: 10px 0px
margin: 5px 0px
@media (-moz-touch-enabled: 1), (pointer: coarse) { margin: 10px 0; }
}
}

View File

@@ -9,6 +9,8 @@ $sidebar-non-existant = #5c6773
$sidebar-active = #ffb454
$sidebar-spacer = #2d334f
$scrollbar = $sidebar-fg
$icons = #737480
$icons-hover = #b7b9cc

View File

@@ -32,6 +32,14 @@
.sidebar {
background-color: $sidebar-bg
color: $sidebar-fg
&::-webkit-scrollbar {
background: $sidebar-bg;
}
&::-webkit-scrollbar-thumb {
background: $scrollbar;
}
}
.chapter li {
@@ -172,4 +180,12 @@
margin: 0;
}
}
::-webkit-scrollbar {
background: $bg;
}
::-webkit-scrollbar-thumb {
background: $scrollbar;
}
}

View File

@@ -9,6 +9,8 @@ $sidebar-non-existant = #505254
$sidebar-active = #3473ad
$sidebar-spacer = #393939
$scrollbar = $sidebar-fg
$icons = #43484d
$icons-hover = #b3c0cc

View File

@@ -9,6 +9,8 @@ $sidebar-non-existant = #aaaaaa
$sidebar-active = #008cff
$sidebar-spacer = #f4f4f4
$scrollbar = #cccccc
$icons = #cccccc
$icons-hover = #333333

View File

@@ -9,6 +9,8 @@ $sidebar-non-existant = #505274
$sidebar-active = #2b79a2
$sidebar-spacer = #2d334f
$scrollbar = $sidebar-fg
$icons = #737480
$icons-hover = #b7b9cc

View File

@@ -9,6 +9,8 @@ $sidebar-non-existant = #505254
$sidebar-active = #e69f67
$sidebar-spacer = #45373a
$scrollbar = $sidebar-fg
$icons = #737480
$icons-hover = #262625

View File

@@ -50,7 +50,7 @@ pub fn take_lines<R: RangeArgument<usize>>(s: &str, range: R) -> String {
let start = *range.start().unwrap_or(&0);
let mut lines = s.lines().skip(start);
match range.end() {
Some(&end) => lines.take(end).join("\n"),
Some(&end) => lines.take(end.checked_sub(start).unwrap_or(0)).join("\n"),
None => lines.join("\n"),
}
}
@@ -62,9 +62,12 @@ mod tests {
#[test]
fn take_lines_test() {
let s = "Lorem\nipsum\ndolor\nsit\namet";
assert_eq!(take_lines(s, 0..3), "Lorem\nipsum\ndolor");
assert_eq!(take_lines(s, 1..3), "ipsum\ndolor");
assert_eq!(take_lines(s, 3..), "sit\namet");
assert_eq!(take_lines(s, ..3), "Lorem\nipsum\ndolor");
assert_eq!(take_lines(s, ..), s);
// corner cases
assert_eq!(take_lines(s, 4..3), "");
assert_eq!(take_lines(s, ..100), s);
}
}

View File

@@ -24,6 +24,13 @@ fn failing_alternate_backend() {
md.build().unwrap_err();
}
#[test]
fn missing_backends_arent_fatal() {
let (md, _temp) = dummy_book_with_backend("missing", "trduyvbhijnorgevfuhn");
assert!(md.build().is_ok());
}
#[test]
fn alternate_backend_with_arguments() {
let (md, _temp) = dummy_book_with_backend("arguments", "echo Hello World!");