rendering configuration from environment variables
This commit is contained in:
parent
f038dcb404
commit
14e2c0e6e4
|
@ -300,10 +300,6 @@ impl MDBook {
|
||||||
let mut highlight_css = File::create(&theme_dir.join("highlight.css"))?;
|
let mut highlight_css = File::create(&theme_dir.join("highlight.css"))?;
|
||||||
highlight_css.write_all(theme::HIGHLIGHT_CSS)?;
|
highlight_css.write_all(theme::HIGHLIGHT_CSS)?;
|
||||||
|
|
||||||
// highlight.js
|
|
||||||
let mut highlight_js = File::create(&theme_dir.join("highlight.js"))?;
|
|
||||||
highlight_js.write_all(theme::HIGHLIGHT_JS)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,7 @@ mod parse;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
pub mod theme;
|
pub mod theme;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod resources;
|
||||||
|
|
||||||
pub use book::MDBook;
|
pub use book::MDBook;
|
||||||
pub use book::BookItem;
|
pub use book::BookItem;
|
||||||
|
|
|
@ -3,6 +3,7 @@ use renderer::Renderer;
|
||||||
use book::MDBook;
|
use book::MDBook;
|
||||||
use book::bookitem::BookItem;
|
use book::bookitem::BookItem;
|
||||||
use {utils, theme};
|
use {utils, theme};
|
||||||
|
use resources::{Resources,Resource};
|
||||||
use regex::{Regex, Captures};
|
use regex::{Regex, Captures};
|
||||||
|
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
|
@ -30,6 +31,7 @@ impl HtmlHandlebars {
|
||||||
impl Renderer for HtmlHandlebars {
|
impl Renderer for HtmlHandlebars {
|
||||||
fn render(&self, book: &MDBook) -> Result<(), Box<Error>> {
|
fn render(&self, book: &MDBook) -> Result<(), Box<Error>> {
|
||||||
debug!("[fn]: render");
|
debug!("[fn]: render");
|
||||||
|
let res = Resources::new();
|
||||||
let mut handlebars = Handlebars::new();
|
let mut handlebars = Handlebars::new();
|
||||||
|
|
||||||
// Load theme
|
// Load theme
|
||||||
|
@ -95,6 +97,22 @@ impl Renderer for HtmlHandlebars {
|
||||||
data.insert("chapter_title".to_owned(), json!(ch.name));
|
data.insert("chapter_title".to_owned(), json!(ch.name));
|
||||||
data.insert("path_to_root".to_owned(), json!(utils::fs::path_to_root(&ch.path)));
|
data.insert("path_to_root".to_owned(), json!(utils::fs::path_to_root(&ch.path)));
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut insert_from_env = |name: &str, conf: &Resource| {
|
||||||
|
data.insert(name.to_owned() + "_render_url", json!(conf.must_render_url()));
|
||||||
|
data.insert(name.to_owned() + "_render_embed", json!(conf.must_embed()));
|
||||||
|
if conf.must_render_url() {
|
||||||
|
data.insert(name.to_owned() + "_url", json!(conf.url()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
insert_from_env("highlight", &res.conf.highlight);
|
||||||
|
insert_from_env("jquery", &res.conf.jquery);
|
||||||
|
insert_from_env("mathjax", &res.conf.mathjax);
|
||||||
|
insert_from_env("awesome", &res.conf.awesome);
|
||||||
|
insert_from_env("source_code_pro", &res.conf.source_code_pro);
|
||||||
|
insert_from_env("open_sans", &res.conf.open_sans);
|
||||||
|
}
|
||||||
|
|
||||||
// Render the handlebars template with the data
|
// Render the handlebars template with the data
|
||||||
debug!("[*]: Render template");
|
debug!("[*]: Render template");
|
||||||
let rendered = handlebars.render("index", &data)?;
|
let rendered = handlebars.render("index", &data)?;
|
||||||
|
@ -167,17 +185,26 @@ impl Renderer for HtmlHandlebars {
|
||||||
book.write_file("book.js", &theme.js)?;
|
book.write_file("book.js", &theme.js)?;
|
||||||
book.write_file("book.css", &theme.css)?;
|
book.write_file("book.css", &theme.css)?;
|
||||||
book.write_file("favicon.png", &theme.favicon)?;
|
book.write_file("favicon.png", &theme.favicon)?;
|
||||||
book.write_file("jquery.js", &theme.jquery)?;
|
|
||||||
book.write_file("highlight.css", &theme.highlight_css)?;
|
book.write_file("highlight.css", &theme.highlight_css)?;
|
||||||
book.write_file("tomorrow-night.css", &theme.tomorrow_night_css)?;
|
book.write_file("tomorrow-night.css", &theme.tomorrow_night_css)?;
|
||||||
book.write_file("highlight.js", &theme.highlight_js)?;
|
|
||||||
book.write_file("_FontAwesome/css/font-awesome.css", theme::FONT_AWESOME)?;
|
if res.conf.jquery.must_embed() {
|
||||||
book.write_file("_FontAwesome/fonts/fontawesome-webfont.eot", theme::FONT_AWESOME_EOT)?;
|
book.write_file("jquery.js", &res.jquery())?;
|
||||||
book.write_file("_FontAwesome/fonts/fontawesome-webfont.svg", theme::FONT_AWESOME_SVG)?;
|
}
|
||||||
book.write_file("_FontAwesome/fonts/fontawesome-webfont.ttf", theme::FONT_AWESOME_TTF)?;
|
|
||||||
book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff", theme::FONT_AWESOME_WOFF)?;
|
if res.conf.highlight.must_embed() {
|
||||||
book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff2", theme::FONT_AWESOME_WOFF2)?;
|
book.write_file("highlight.js", &res.highlight_js())?;
|
||||||
book.write_file("_FontAwesome/fonts/FontAwesome.ttf", theme::FONT_AWESOME_TTF)?;
|
}
|
||||||
|
|
||||||
|
if res.conf.awesome.must_embed() {
|
||||||
|
book.write_file("_FontAwesome/css/font-awesome.css", &res.awesome_css())?;
|
||||||
|
book.write_file("_FontAwesome/fonts/fontawesome-webfont.eot", &res.awesome_eot())?;
|
||||||
|
book.write_file("_FontAwesome/fonts/fontawesome-webfont.svg", &res.awesome_svg())?;
|
||||||
|
book.write_file("_FontAwesome/fonts/fontawesome-webfont.ttf", &res.awesome_ttf())?;
|
||||||
|
book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff", &res.awesome_woff())?;
|
||||||
|
book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff2", &res.awesome_woff2())?;
|
||||||
|
book.write_file("_FontAwesome/fonts/FontAwesome.ttf", &res.awesome_ttf())?;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy all remaining files
|
// Copy all remaining files
|
||||||
utils::fs::copy_files_except_ext(book.get_src(), book.get_dest(), true, &["md"])?;
|
utils::fs::copy_files_except_ext(book.get_src(), book.get_dest(), true, &["md"])?;
|
||||||
|
|
Before Width: | Height: | Size: 348 KiB After Width: | Height: | Size: 348 KiB |
|
@ -0,0 +1,233 @@
|
||||||
|
//! Configuration options that can be passed through environment variables.
|
||||||
|
//!
|
||||||
|
//! By default, mdBook will try to retrieve external resources through a content
|
||||||
|
//! delivery network. If that fails, it'll load an embedded version of the
|
||||||
|
//! resource. Using environment variables this behavior can be changed in
|
||||||
|
//! various ways.
|
||||||
|
//!
|
||||||
|
//! The variables are as follows. [name] can be one of JQUERY, MATHJAX,
|
||||||
|
//! HIGHLIGHT, AWESOME, OPEN_SANS, SOURCE_CODE_PRO:
|
||||||
|
//!
|
||||||
|
//! - MDBOOK_GLOBAL_STRATEGY: Strategy for finding external resources. One of
|
||||||
|
//! UrlWithFallback (the default), UrlOnly and Omit.
|
||||||
|
//! - MDBOOK_[name]_URL: The URL of the resource.
|
||||||
|
//! - MDBOOK_[name]_SOURCE: The source file for the embedded resource.
|
||||||
|
//! - MDBOOK_[name]_STRATEGY: Strategy for this particular resource. This
|
||||||
|
//! overrides the global strategy.
|
||||||
|
//!
|
||||||
|
//! All variables have sane defaults which were determined at compile time.
|
||||||
|
//! the SOURCE variables, when left empty, ensure that a version is used that
|
||||||
|
//! was embedded into mdBook itself at compile time.
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
pub static JQUERY_URL: &str = &"https://code.jquery.com/jquery-2.1.4.min.js";
|
||||||
|
pub static MATHJAX_URL: &str = &"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
|
||||||
|
pub static HIGHLIGHT_URL: &str = &"highlight.js";
|
||||||
|
pub static AWESOME_URL: &str = &"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css";
|
||||||
|
pub static OPEN_SANS_URL: &str = &"https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800";
|
||||||
|
pub static SOURCE_CODE_PRO_URL: &str = &"https://fonts.googleapis.com/css?family=Source+Code+Pro:500";
|
||||||
|
|
||||||
|
/// A third-party resource
|
||||||
|
pub trait Resource {
|
||||||
|
/// returns true if this resource has to be rendered as an url
|
||||||
|
fn must_render_url(&self) -> bool;
|
||||||
|
/// returns true if this resource has to be embedded in the book
|
||||||
|
fn must_embed(&self) -> bool;
|
||||||
|
/// returns the url for this resource. This panics if must_render_url returns false.
|
||||||
|
fn url(&self) -> String;
|
||||||
|
/// returns the source location for this resource, or None if none was configured.
|
||||||
|
/// This panics if must_embed returns false.
|
||||||
|
fn source(&self) -> Option<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A third-party resource with nothing special to it.
|
||||||
|
pub enum BasicResource {
|
||||||
|
UrlWithFallback {
|
||||||
|
url: String,
|
||||||
|
source: Option<String>
|
||||||
|
},
|
||||||
|
UrlOnly {
|
||||||
|
url: String
|
||||||
|
},
|
||||||
|
Omit
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resource for BasicResource {
|
||||||
|
fn must_render_url(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&BasicResource::UrlWithFallback{url: _, source: _} => true,
|
||||||
|
&BasicResource::UrlOnly{url: _} => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn must_embed(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&BasicResource::UrlWithFallback{url: _, source: _} => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn url(&self) -> String {
|
||||||
|
match self {
|
||||||
|
&BasicResource::UrlWithFallback{ref url, source: _} => url.clone(),
|
||||||
|
&BasicResource::UrlOnly{ref url} => url.clone(),
|
||||||
|
_ => panic!("no url available")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source(&self) -> Option<String> {
|
||||||
|
match self {
|
||||||
|
&BasicResource::UrlWithFallback{url: _, ref source} => source.clone(),
|
||||||
|
_ => panic!("no source available")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Special struct for font-awesome, as it consists of multiple embedded files
|
||||||
|
/// but is configured as a directory. Methods implemented for this struct
|
||||||
|
/// calculate the paths of all the files in this directory.
|
||||||
|
pub struct Awesome {
|
||||||
|
resource: BasicResource
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resource for Awesome {
|
||||||
|
fn must_render_url(&self) -> bool {
|
||||||
|
self.resource.must_render_url()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn must_embed(&self) -> bool {
|
||||||
|
self.resource.must_embed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn url(&self) -> String {
|
||||||
|
self.resource.url()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source(&self) -> Option<String> {
|
||||||
|
self.resource.source()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Awesome {
|
||||||
|
pub fn css_source(&self) -> Option<String> {
|
||||||
|
self.resource.source().map(|p| p + "/css/font-awesome.min.css")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eot_source(&self) -> Option<String> {
|
||||||
|
self.resource.source().map(|p| p + "/fonts/fontawesome-webfont.eot")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn svg_source(&self) -> Option<String> {
|
||||||
|
self.resource.source().map(|p| p + "/fonts/fontawesome-webfont.svg")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ttf_source(&self) -> Option<String> {
|
||||||
|
self.resource.source().map(|p| p + "/fonts/fontawesome-webfont.ttf")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn woff_source(&self) -> Option<String> {
|
||||||
|
self.resource.source().map(|p| p + "/fonts/fontawesome-webfont.woff")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn woff2_source(&self) -> Option<String> {
|
||||||
|
self.resource.source().map(|p| p + "/fonts/fontawesome-webfont.woff2")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn otf_source(&self) -> Option<String> {
|
||||||
|
self.resource.source().map(|p| p + "/fonts/FontAwesome.otf")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration information for all the third-party resources. This specifies
|
||||||
|
/// for every resource whether it should be included at all, and if so, just as
|
||||||
|
/// an URL or also as an embedded resource.
|
||||||
|
pub struct Configuration {
|
||||||
|
pub jquery: BasicResource,
|
||||||
|
pub mathjax: BasicResource,
|
||||||
|
pub highlight: BasicResource,
|
||||||
|
pub awesome: Awesome,
|
||||||
|
pub open_sans: BasicResource,
|
||||||
|
pub source_code_pro: BasicResource
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate an environment variable name of the format MDBOOK_[name]_[key]
|
||||||
|
fn varname(resource : &str, key: &str) -> String {
|
||||||
|
"MDBOOK_".to_string() + &resource.to_uppercase() + "_" + key
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the contents of the environment variable of the given resource with
|
||||||
|
/// the given key, or None if the environment variable was not set.
|
||||||
|
fn var(resource: &str, key: &str) -> Option<String> {
|
||||||
|
env::var(varname(resource, key)).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a variable as var would. If the variable could not be found, return
|
||||||
|
/// the given default.
|
||||||
|
fn var_default(resource: &str, key: &str, default: &str) -> String {
|
||||||
|
var(resource, key).unwrap_or(String::from(default))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The rendering strategy for a resource
|
||||||
|
enum Strategy {
|
||||||
|
/// Render both an inclusion through an URL, and a fallback if it exists.
|
||||||
|
UrlWithFallback,
|
||||||
|
/// Render only the inclusion through an URL
|
||||||
|
UrlOnly,
|
||||||
|
/// Omit the resource altogether
|
||||||
|
Omit
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a strategy from an environment variable, or the default
|
||||||
|
/// `UrlWithFallback` if it can't be found.
|
||||||
|
fn strategy(resource: &str) -> Strategy {
|
||||||
|
match var(resource, "STRATEGY")
|
||||||
|
.unwrap_or(var_default("DEFAULT", "STRATEGY", "UrlWithFallback")).as_ref() {
|
||||||
|
"UrlOnly" => Strategy::UrlOnly,
|
||||||
|
"Omit" => Strategy::Omit,
|
||||||
|
_ => Strategy::UrlWithFallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return an URL from an environment variable, or the given default if the URL
|
||||||
|
/// was not set.
|
||||||
|
fn url(resource: &str, default: &str) -> String {
|
||||||
|
var_default(resource, "URL", default)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return a source location from an environment variable, if it can't be found.
|
||||||
|
fn source(resource : &str) -> Option<String> {
|
||||||
|
var(resource, "EMBED_SOURCE")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return a resource from various environment variables.
|
||||||
|
fn resource(resource: &str, url_default: &str) -> BasicResource {
|
||||||
|
match strategy(resource) {
|
||||||
|
Strategy::UrlWithFallback => BasicResource::UrlWithFallback {
|
||||||
|
url: url(resource, url_default),
|
||||||
|
source: source(resource)
|
||||||
|
},
|
||||||
|
Strategy::UrlOnly => BasicResource::UrlOnly {
|
||||||
|
url: url(resource, url_default)
|
||||||
|
},
|
||||||
|
Strategy::Omit => BasicResource::Omit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// parse font_awesome configuration from environment variables.
|
||||||
|
fn awesome() -> Awesome {
|
||||||
|
Awesome { resource: resource("AWESOME", AWESOME_URL) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the configuration from the environment variables.
|
||||||
|
pub fn configuration_from_env() -> Configuration {
|
||||||
|
Configuration {
|
||||||
|
jquery: resource("JQUERY", JQUERY_URL),
|
||||||
|
mathjax: resource("MATHJAX", MATHJAX_URL),
|
||||||
|
highlight: resource("HIGHLIGHT", HIGHLIGHT_URL),
|
||||||
|
awesome: awesome(),
|
||||||
|
open_sans: resource("OPEN_SANS", OPEN_SANS_URL),
|
||||||
|
source_code_pro: resource("SOURCE_CODE_PRO", SOURCE_CODE_PRO_URL)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
//! Resource management
|
||||||
|
//!
|
||||||
|
//! mdBook uses various third-party javascript libraries and fonts. This module
|
||||||
|
//! manages their resolution, dependent on run-time configuration, allowing the
|
||||||
|
//! renderer to determine how to include the resource.
|
||||||
|
//!
|
||||||
|
//! By default, resources are retrieved with an URL, usually a CDN. If this is not
|
||||||
|
//! possible, an embedded fallback is used instead. This improves rendering
|
||||||
|
//! speed while still allowing the book to be readable without an internet
|
||||||
|
//! connection.
|
||||||
|
//!
|
||||||
|
//! In some cases, this default behavior is unwanted. One might want to load the
|
||||||
|
//! library from a different URL, or one might want to embed a different
|
||||||
|
//! fallback resource. For those cases, resource resolution can be overridden
|
||||||
|
//! through environment variables. See the env_config module for more details.
|
||||||
|
|
||||||
|
mod env_config;
|
||||||
|
use self::env_config::{Configuration,configuration_from_env};
|
||||||
|
pub use self::env_config::{Resource};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
static HIGHLIGHT_JS: &'static [u8] = include_bytes!("highlight.js");
|
||||||
|
static JQUERY: &'static [u8] = include_bytes!("jquery-2.1.4.min.js");
|
||||||
|
static FONT_AWESOME_CSS: &'static [u8] = include_bytes!("_FontAwesome/css/font-awesome.min.css");
|
||||||
|
static FONT_AWESOME_EOT: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.eot");
|
||||||
|
static FONT_AWESOME_SVG: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.svg");
|
||||||
|
static FONT_AWESOME_TTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.ttf");
|
||||||
|
static FONT_AWESOME_WOFF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff");
|
||||||
|
static FONT_AWESOME_WOFF2: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff2");
|
||||||
|
static FONT_AWESOME_OTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/FontAwesome.otf");
|
||||||
|
|
||||||
|
/// handle for loading resource contents, based on a configuration
|
||||||
|
pub struct Resources {
|
||||||
|
/// the configuration read from the environment variables
|
||||||
|
pub conf: Configuration
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resources {
|
||||||
|
/// create a new Resources object, based on the environment variables
|
||||||
|
pub fn new() -> Resources {
|
||||||
|
Resources {
|
||||||
|
conf: configuration_from_env()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the contents that should be embedded in a book.
|
||||||
|
/// This returns a version of the resource that was embedded at compile
|
||||||
|
/// time, passed as the default argument, unless an alternative was set
|
||||||
|
/// through an environment variable.
|
||||||
|
fn resource_content(&self, default : &[u8]) -> Vec<u8> {
|
||||||
|
if let Some(s) = self.conf.highlight.source() {
|
||||||
|
if let Ok(mut f) = File::open(s) {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
f.read_to_end(&mut vec).expect("read failed");
|
||||||
|
vec
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Vec::from(default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Vec::from(default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn highlight_js(&self) -> Vec<u8> {
|
||||||
|
assert!(self.conf.highlight.must_embed());
|
||||||
|
self.resource_content(HIGHLIGHT_JS)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jquery(&self) -> Vec<u8> {
|
||||||
|
assert!(self.conf.jquery.must_embed());
|
||||||
|
self.resource_content(JQUERY)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn awesome_css(&self) -> Vec<u8> {
|
||||||
|
assert!(self.conf.awesome.must_embed());
|
||||||
|
self.resource_content(FONT_AWESOME_CSS)
|
||||||
|
}
|
||||||
|
pub fn awesome_eot(&self) -> Vec<u8> {
|
||||||
|
assert!(self.conf.awesome.must_embed());
|
||||||
|
self.resource_content(FONT_AWESOME_EOT)
|
||||||
|
}
|
||||||
|
pub fn awesome_svg(&self) -> Vec<u8> {
|
||||||
|
assert!(self.conf.awesome.must_embed());
|
||||||
|
self.resource_content(FONT_AWESOME_SVG)
|
||||||
|
}
|
||||||
|
pub fn awesome_ttf(&self) -> Vec<u8> {
|
||||||
|
assert!(self.conf.awesome.must_embed());
|
||||||
|
self.resource_content(FONT_AWESOME_TTF)
|
||||||
|
}
|
||||||
|
pub fn awesome_woff(&self) -> Vec<u8> {
|
||||||
|
assert!(self.conf.awesome.must_embed());
|
||||||
|
self.resource_content(FONT_AWESOME_WOFF)
|
||||||
|
}
|
||||||
|
pub fn awesome_woff2(&self) -> Vec<u8> {
|
||||||
|
assert!(self.conf.awesome.must_embed());
|
||||||
|
self.resource_content(FONT_AWESOME_WOFF2)
|
||||||
|
}
|
||||||
|
pub fn awesome_otf(&self) -> Vec<u8> {
|
||||||
|
assert!(self.conf.awesome.must_embed());
|
||||||
|
self.resource_content(FONT_AWESOME_OTF)
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,27 +10,40 @@
|
||||||
<base href="{{ path_to_root }}">
|
<base href="{{ path_to_root }}">
|
||||||
|
|
||||||
<link rel="stylesheet" href="book.css">
|
<link rel="stylesheet" href="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">
|
{{#if open_sans_render_url}}
|
||||||
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
|
<link href="{{open_sans_url}}" rel="stylesheet" type="text/css">
|
||||||
|
{{/if}}
|
||||||
|
{{#if source_code_pro_render_url}}
|
||||||
|
<link href="{{source_code_pro_url}}" rel="stylesheet" type="text/css">
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<link rel="shortcut icon" href="{{ favicon }}">
|
<link rel="shortcut icon" href="{{ favicon }}">
|
||||||
|
|
||||||
|
{{#if awesome_render_url}}
|
||||||
<!-- Font Awesome -->
|
<!-- Font Awesome -->
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
|
<link rel="stylesheet" href="{{awesome_url}}">
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<link rel="stylesheet" href="highlight.css">
|
<link rel="stylesheet" href="highlight.css">
|
||||||
<link rel="stylesheet" href="tomorrow-night.css">
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
|
||||||
|
{{#if mathjax_render_url}}
|
||||||
<!-- MathJax -->
|
<!-- MathJax -->
|
||||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
<script type="text/javascript" src="{{mathjax_url}}"></script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<!-- Fetch JQuery from CDN but have a local fallback -->
|
{{#if jquery_render_url }}
|
||||||
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
|
<!-- Fetch JQuery -->
|
||||||
|
<script src="{{jquery_url}}"></script>
|
||||||
|
{{/if}}
|
||||||
|
{{#if jquery_render_embed }}
|
||||||
|
<!-- local fallback for jquery -->
|
||||||
<script>
|
<script>
|
||||||
if (typeof jQuery == 'undefined') {
|
if (typeof jQuery == 'undefined') {
|
||||||
document.write(unescape("%3Cscript src='jquery.js'%3E%3C/script%3E"));
|
document.write(unescape("%3Cscript src='jquery.js'%3E%3C/script%3E"));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
{{/if}}
|
||||||
</head>
|
</head>
|
||||||
<body class="light">
|
<body class="light">
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
@ -101,12 +114,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{{#if awesome_render_embed}}
|
||||||
<!-- Local fallback for Font Awesome -->
|
<!-- Local fallback for Font Awesome -->
|
||||||
<script>
|
<script>
|
||||||
if ($(".fa").css("font-family") !== "FontAwesome") {
|
if ($(".fa").css("font-family") !== "FontAwesome") {
|
||||||
$('<link rel="stylesheet" type="text/css" href="_FontAwesome/css/font-awesome.css">').prependTo('head');
|
$('<link rel="stylesheet" type="text/css" href="_FontAwesome/css/font-awesome.css">').prependTo('head');
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<!-- Livereload script (if served using the cli tool) -->
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
{{{livereload}}}
|
{{{livereload}}}
|
||||||
|
@ -124,7 +139,9 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|
||||||
<script src="highlight.js"></script>
|
{{#if highlight_render_url}}
|
||||||
|
<script src="{{highlight_url}}"></script>
|
||||||
|
{{/if}}
|
||||||
<script src="book.js"></script>
|
<script src="book.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -7,17 +7,8 @@ pub static INDEX: &'static [u8] = include_bytes!("index.hbs");
|
||||||
pub static CSS: &'static [u8] = include_bytes!("book.css");
|
pub static CSS: &'static [u8] = include_bytes!("book.css");
|
||||||
pub static FAVICON: &'static [u8] = include_bytes!("favicon.png");
|
pub static FAVICON: &'static [u8] = include_bytes!("favicon.png");
|
||||||
pub static JS: &'static [u8] = include_bytes!("book.js");
|
pub static JS: &'static [u8] = include_bytes!("book.js");
|
||||||
pub static HIGHLIGHT_JS: &'static [u8] = include_bytes!("highlight.js");
|
|
||||||
pub static TOMORROW_NIGHT_CSS: &'static [u8] = include_bytes!("tomorrow-night.css");
|
pub static TOMORROW_NIGHT_CSS: &'static [u8] = include_bytes!("tomorrow-night.css");
|
||||||
pub static HIGHLIGHT_CSS: &'static [u8] = include_bytes!("highlight.css");
|
pub static HIGHLIGHT_CSS: &'static [u8] = include_bytes!("highlight.css");
|
||||||
pub static JQUERY: &'static [u8] = include_bytes!("jquery-2.1.4.min.js");
|
|
||||||
pub static FONT_AWESOME: &'static [u8] = include_bytes!("_FontAwesome/css/font-awesome.min.css");
|
|
||||||
pub static FONT_AWESOME_EOT: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.eot");
|
|
||||||
pub static FONT_AWESOME_SVG: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.svg");
|
|
||||||
pub static FONT_AWESOME_TTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.ttf");
|
|
||||||
pub static FONT_AWESOME_WOFF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff");
|
|
||||||
pub static FONT_AWESOME_WOFF2: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff2");
|
|
||||||
pub static FONT_AWESOME_OTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/FontAwesome.otf");
|
|
||||||
|
|
||||||
/// The `Theme` struct should be used instead of the static variables because
|
/// The `Theme` struct should be used instead of the static variables because
|
||||||
/// the `new()` method
|
/// the `new()` method
|
||||||
|
@ -35,8 +26,6 @@ pub struct Theme {
|
||||||
pub js: Vec<u8>,
|
pub js: Vec<u8>,
|
||||||
pub highlight_css: Vec<u8>,
|
pub highlight_css: Vec<u8>,
|
||||||
pub tomorrow_night_css: Vec<u8>,
|
pub tomorrow_night_css: Vec<u8>,
|
||||||
pub highlight_js: Vec<u8>,
|
|
||||||
pub jquery: Vec<u8>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Theme {
|
impl Theme {
|
||||||
|
@ -50,8 +39,6 @@ impl Theme {
|
||||||
js: JS.to_owned(),
|
js: JS.to_owned(),
|
||||||
highlight_css: HIGHLIGHT_CSS.to_owned(),
|
highlight_css: HIGHLIGHT_CSS.to_owned(),
|
||||||
tomorrow_night_css: TOMORROW_NIGHT_CSS.to_owned(),
|
tomorrow_night_css: TOMORROW_NIGHT_CSS.to_owned(),
|
||||||
highlight_js: HIGHLIGHT_JS.to_owned(),
|
|
||||||
jquery: JQUERY.to_owned(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the given path exists
|
// Check if the given path exists
|
||||||
|
@ -85,12 +72,6 @@ impl Theme {
|
||||||
let _ = f.read_to_end(&mut theme.favicon);
|
let _ = f.read_to_end(&mut theme.favicon);
|
||||||
}
|
}
|
||||||
|
|
||||||
// highlight.js
|
|
||||||
if let Ok(mut f) = File::open(&src.join("highlight.js")) {
|
|
||||||
theme.highlight_js.clear();
|
|
||||||
let _ = f.read_to_end(&mut theme.highlight_js);
|
|
||||||
}
|
|
||||||
|
|
||||||
// highlight.css
|
// highlight.css
|
||||||
if let Ok(mut f) = File::open(&src.join("highlight.css")) {
|
if let Ok(mut f) = File::open(&src.join("highlight.css")) {
|
||||||
theme.highlight_css.clear();
|
theme.highlight_css.clear();
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
//! Configuration options that can be passed through environment variables.
|
||||||
|
//!
|
||||||
|
//! By default, mdBook will try to retrieve external resources through a content
|
||||||
|
//! delivery network. If that fails, it'll load an embedded version of the
|
||||||
|
//! resource. Using environment variables this behavior can be changed in
|
||||||
|
//! various ways.
|
||||||
|
//!
|
||||||
|
//! The variables are as follows. [name] can be one of JQUERY, MATHJAX,
|
||||||
|
//! HIGHLIGHT, AWESOME, OPEN_SANS or SOURCE_CODE_PRO:
|
||||||
|
//!
|
||||||
|
//! - MDBOOK_DEFAULT_STRATEGY: Strategy for finding external resources. One of
|
||||||
|
//! UrlWithFallback (the default), EmbeddedOnly, UrlOnly and Omit.
|
||||||
|
//! - MDBOOK_[name]_URL: The URL of the resource. When omitted, an URL embedded at compile time will be used.
|
||||||
|
//! - MDBOOK_[name]_SOURCE: The source file for the embedded resource. When omitted, a version embeded at compile time will be used.
|
||||||
|
//! - MDBOOK_[name]_STRATEGY: Strategy for this particular resource. This
|
||||||
|
//! overrides the global strategy.
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
pub static JQUERY_URL: &str = &"https://code.jquery.com/jquery-2.1.4.min.js";
|
||||||
|
pub static MATHJAX_URL: &str = &"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
|
||||||
|
pub static HIGHLIGHT_URL: &str = &"highlight.js";
|
||||||
|
pub static AWESOME_URL: &str = &"https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css";
|
||||||
|
pub static OPEN_SANS_URL: &str = &"https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800";
|
||||||
|
pub static SOURCE_CODE_PRO_URL: &str = &"https://fonts.googleapis.com/css?family=Source+Code+Pro:500";
|
||||||
|
|
||||||
|
pub enum Resource {
|
||||||
|
UrlWithFallback {
|
||||||
|
url: String,
|
||||||
|
source: Option<String>
|
||||||
|
},
|
||||||
|
EmbeddedOnly {
|
||||||
|
source: Option<String>
|
||||||
|
},
|
||||||
|
UrlOnly {
|
||||||
|
url: String
|
||||||
|
},
|
||||||
|
Omit
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resource {
|
||||||
|
pub fn must_render_url(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&Resource::UrlWithFallback{url: _, source: _} => true,
|
||||||
|
&Resource::UrlOnly{url: _} => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn must_embed(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&Resource::UrlWithFallback{url: _, source: _} => true,
|
||||||
|
&Resource::EmbeddedOnly{source: _} => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn url(&self) -> String {
|
||||||
|
match self {
|
||||||
|
&Resource::UrlWithFallback{url: ref url, source: _} => url.clone(),
|
||||||
|
&Resource::UrlOnly{url: ref url} => url.clone(),
|
||||||
|
_ => panic!("no url available")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source(&self) -> Option<String> {
|
||||||
|
match self {
|
||||||
|
&Resource::UrlWithFallback{url: _, source: ref source} => source.clone(),
|
||||||
|
&Resource::EmbeddedOnly{source: ref source} => source.clone(),
|
||||||
|
_ => panic!("no source available")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Configuration {
|
||||||
|
pub jquery: Resource,
|
||||||
|
pub mathjax: Resource,
|
||||||
|
pub highlight: Resource,
|
||||||
|
pub awesome: Resource,
|
||||||
|
pub open_sans: Resource,
|
||||||
|
pub source_code_pro: Resource
|
||||||
|
}
|
||||||
|
|
||||||
|
fn varname(resource : &str, suffix: &str) -> String {
|
||||||
|
"MDBOOK_".to_string() + &resource.to_uppercase() + "_" + suffix
|
||||||
|
}
|
||||||
|
|
||||||
|
fn var(resource: &str, key: &str) -> Option<String> {
|
||||||
|
env::var(varname(resource, key)).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn var_default(resource: &str, key: &str, default: &str) -> String {
|
||||||
|
var(resource, key).unwrap_or(String::from(default))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Strategy {
|
||||||
|
UrlWithFallback,
|
||||||
|
EmbeddedOnly,
|
||||||
|
UrlOnly,
|
||||||
|
Omit
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strategy(resource: &str) -> Strategy {
|
||||||
|
match var(resource, "STRATEGY")
|
||||||
|
.unwrap_or(var_default("DEFAULT", "STRATEGY", "UrlWithFallback")).as_ref() {
|
||||||
|
"EmbeddedOnly" => Strategy::EmbeddedOnly,
|
||||||
|
"UrlOnly" => Strategy::UrlOnly,
|
||||||
|
"Omit" => Strategy::Omit,
|
||||||
|
_ => Strategy::UrlWithFallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn url(resource: &str, default: &str) -> String {
|
||||||
|
var_default(resource, "URL", default)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source(resource : &str) -> Option<String> {
|
||||||
|
var(resource, "EMBED_SOURCE")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resource(resource: &str, url_default: &str) -> Resource {
|
||||||
|
match strategy(resource) {
|
||||||
|
Strategy::UrlWithFallback => Resource::UrlWithFallback {
|
||||||
|
url: url(resource, url_default),
|
||||||
|
source: source(resource)
|
||||||
|
},
|
||||||
|
Strategy::EmbeddedOnly => Resource::EmbeddedOnly {
|
||||||
|
source: source(resource)
|
||||||
|
},
|
||||||
|
Strategy::UrlOnly => Resource::UrlOnly {
|
||||||
|
url: url(resource, url_default)
|
||||||
|
},
|
||||||
|
Strategy::Omit => Resource::Omit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configuration_from_env() -> Configuration {
|
||||||
|
Configuration {
|
||||||
|
jquery: resource("JQUERY", JQUERY_URL),
|
||||||
|
mathjax: resource("MATHJAX", MATHJAX_URL),
|
||||||
|
highlight: resource("HIGHLIGHT", HIGHLIGHT_URL),
|
||||||
|
awesome: resource("AWESOME", AWESOME_URL),
|
||||||
|
open_sans: resource("OPEN_SANS", OPEN_SANS_URL),
|
||||||
|
source_code_pro: resource("SOURCE_CODE_PRO", SOURCE_CODE_PRO_URL)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue