Skip to content

Commit

Permalink
Make the sidebar work without JS
Browse files Browse the repository at this point in the history
Uses an iframe instead. The downside of iframes comes from them
not necessarily being same-origin as the main page (particularly
with `file:///` URLs), which can cause themes to fall out of sync,
but that's not a problem here since themes don't work without JS
anyway.
  • Loading branch information
notriddle committed Jul 16, 2024
1 parent 2cb5b85 commit 34dc0a8
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 8 deletions.
10 changes: 7 additions & 3 deletions src/renderer/html_handlebars/hbs_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,8 @@ impl Renderer for HtmlHandlebars {
handlebars.register_partial("header", String::from_utf8(theme.header.clone())?)?;

debug!("Register the toc handlebars template");
handlebars.register_template_string("toc", String::from_utf8(theme.toc.clone())?)?;
handlebars.register_template_string("toc_js", String::from_utf8(theme.toc_js.clone())?)?;
handlebars.register_template_string("toc_html", String::from_utf8(theme.toc_html.clone())?)?;

debug!("Register handlebars helpers");
self.register_hbs_helpers(&mut handlebars, &html_config);
Expand Down Expand Up @@ -586,11 +587,14 @@ impl Renderer for HtmlHandlebars {
debug!("Creating print.html ✓");
}

debug!("Render toc.js");
debug!("Render toc");
{
let rendered_toc = handlebars.render("toc", &data)?;
let rendered_toc = handlebars.render("toc_js", &data)?;
utils::fs::write_file(destination, "toc.js", rendered_toc.as_bytes())?;
debug!("Creating toc.js ✓");
let rendered_toc = handlebars.render("toc_html", &data)?;
utils::fs::write_file(destination, "toc.html", rendered_toc.as_bytes())?;
debug!("Creating toc.html ✓");
}

debug!("Copy static files");
Expand Down
16 changes: 16 additions & 0 deletions src/theme/css/chrome.css
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,22 @@ ul#searchresults span.teaser em {
background-color: var(--sidebar-bg);
color: var(--sidebar-fg);
}
.sidebar-iframe-inner {
background-color: var(--sidebar-bg);
color: var(--sidebar-fg);
padding: 10px 10px;
margin: 0;
font-size: 1.4rem;
}
.sidebar-iframe-outer {
border: none;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
[dir=rtl] .sidebar { left: unset; right: 0; }
.sidebar-resizing {
-moz-user-select: none;
Expand Down
3 changes: 3 additions & 0 deletions src/theme/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<div class="sidebar-scrollbox"></div>
<noscript>
<iframe class="sidebar-iframe-outer" src="{{ path_to_root }}toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
Expand Down
16 changes: 11 additions & 5 deletions src/theme/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ pub static INDEX: &[u8] = include_bytes!("index.hbs");
pub static HEAD: &[u8] = include_bytes!("head.hbs");
pub static REDIRECT: &[u8] = include_bytes!("redirect.hbs");
pub static HEADER: &[u8] = include_bytes!("header.hbs");
pub static TOC: &[u8] = include_bytes!("toc.js.hbs");
pub static TOC_JS: &[u8] = include_bytes!("toc.js.hbs");
pub static TOC_HTML: &[u8] = include_bytes!("toc.html.hbs");
pub static CHROME_CSS: &[u8] = include_bytes!("css/chrome.css");
pub static GENERAL_CSS: &[u8] = include_bytes!("css/general.css");
pub static PRINT_CSS: &[u8] = include_bytes!("css/print.css");
Expand Down Expand Up @@ -51,7 +52,8 @@ pub struct Theme {
pub head: Vec<u8>,
pub redirect: Vec<u8>,
pub header: Vec<u8>,
pub toc: Vec<u8>,
pub toc_js: Vec<u8>,
pub toc_html: Vec<u8>,
pub chrome_css: Vec<u8>,
pub general_css: Vec<u8>,
pub print_css: Vec<u8>,
Expand Down Expand Up @@ -87,7 +89,8 @@ impl Theme {
(theme_dir.join("head.hbs"), &mut theme.head),
(theme_dir.join("redirect.hbs"), &mut theme.redirect),
(theme_dir.join("header.hbs"), &mut theme.header),
(theme_dir.join("toc.js.hbs"), &mut theme.toc),
(theme_dir.join("toc.js.hbs"), &mut theme.toc_js),
(theme_dir.join("toc.html.hbs"), &mut theme.toc_html),
(theme_dir.join("book.js"), &mut theme.js),
(theme_dir.join("css/chrome.css"), &mut theme.chrome_css),
(theme_dir.join("css/general.css"), &mut theme.general_css),
Expand Down Expand Up @@ -177,7 +180,8 @@ impl Default for Theme {
head: HEAD.to_owned(),
redirect: REDIRECT.to_owned(),
header: HEADER.to_owned(),
toc: TOC.to_owned(),
toc_js: TOC_JS.to_owned(),
toc_html: TOC_HTML.to_owned(),
chrome_css: CHROME_CSS.to_owned(),
general_css: GENERAL_CSS.to_owned(),
print_css: PRINT_CSS.to_owned(),
Expand Down Expand Up @@ -237,6 +241,7 @@ mod tests {
"redirect.hbs",
"header.hbs",
"toc.js.hbs",
"toc.html.hbs",
"favicon.png",
"favicon.svg",
"css/chrome.css",
Expand Down Expand Up @@ -268,7 +273,8 @@ mod tests {
head: Vec::new(),
redirect: Vec::new(),
header: Vec::new(),
toc: Vec::new(),
toc_js: Vec::new(),
toc_html: Vec::new(),
chrome_css: Vec::new(),
general_css: Vec::new(),
print_css: Vec::new(),
Expand Down
43 changes: 43 additions & 0 deletions src/theme/toc.html.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html lang="{{ language }}" class="{{ default_theme }}" dir="{{ text_direction }}">
<head>
<!-- sidebar iframe generated using mdBook
This is a frame, and not included directly in the page, to control the total size of the
book. The TOC contains an entry for each page, so if each page includes a copy of the TOC,
the total size of the page becomes O(n**2).
The frame is only used as a fallback when JS is turned off. When it's on, the sidebar is
instead added to the main page by `toc.js` instead. The JavaScript mode is better
because, when running in a `file:///` URL, the iframed page would not be Same-Origin as
the rest of the page, so the sidebar and the main page theme would fall out of sync.
-->
<meta charset="UTF-8">
<meta name="robots" content="noindex">
{{#if base_url}}
<base href="{{ base_url }}">
{{/if}}
<!-- Custom HTML head -->
{{> head}}
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="{{ path_to_root }}css/variables.css">
<link rel="stylesheet" href="{{ path_to_root }}css/general.css">
<link rel="stylesheet" href="{{ path_to_root }}css/chrome.css">
{{#if print_enable}}
<link rel="stylesheet" href="{{ path_to_root }}css/print.css" media="print">
{{/if}}
<!-- Fonts -->
<link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
{{#if copy_fonts}}
<link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
{{/if}}
<!-- Custom theme stylesheets -->
{{#each additional_css}}
<link rel="stylesheet" href="{{ ../path_to_root }}{{ this }}">
{{/each}}
</head>
<body class="sidebar-iframe-inner">
{{#toc}}{{/toc}}
</body>
</html>

0 comments on commit 34dc0a8

Please sign in to comment.