Redirect to translation index page in serve command
This commit is contained in:
parent
8869c2cf06
commit
85ab4d39cd
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -789,6 +789,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"gitignore",
|
"gitignore",
|
||||||
"handlebars",
|
"handlebars",
|
||||||
|
"http",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -21,6 +21,7 @@ chrono = "0.4"
|
|||||||
clap = "2.24"
|
clap = "2.24"
|
||||||
env_logger = "0.7.1"
|
env_logger = "0.7.1"
|
||||||
handlebars = "4.0"
|
handlebars = "4.0"
|
||||||
|
http = "0.2.4"
|
||||||
lazy_static = "1.0"
|
lazy_static = "1.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
memchr = "2.0"
|
memchr = "2.0"
|
||||||
|
@ -4,6 +4,7 @@ use crate::{get_book_dir, get_build_opts, open};
|
|||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
use futures_util::sink::SinkExt;
|
use futures_util::sink::SinkExt;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
|
use http::Uri;
|
||||||
use mdbook::errors::*;
|
use mdbook::errors::*;
|
||||||
use mdbook::utils;
|
use mdbook::utils;
|
||||||
use mdbook::utils::fs::get_404_output_file;
|
use mdbook::utils::fs::get_404_output_file;
|
||||||
@ -60,7 +61,7 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
|||||||
pub fn execute(args: &ArgMatches) -> Result<()> {
|
pub fn execute(args: &ArgMatches) -> Result<()> {
|
||||||
let book_dir = get_book_dir(args);
|
let book_dir = get_book_dir(args);
|
||||||
let build_opts = get_build_opts(args);
|
let build_opts = get_build_opts(args);
|
||||||
let mut book = MDBook::load_with_build_opts(&book_dir, build_opts)?;
|
let mut book = MDBook::load_with_build_opts(&book_dir, build_opts.clone())?;
|
||||||
|
|
||||||
let port = args.value_of("port").unwrap();
|
let port = args.value_of("port").unwrap();
|
||||||
let hostname = args.value_of("hostname").unwrap();
|
let hostname = args.value_of("hostname").unwrap();
|
||||||
@ -82,6 +83,18 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
|||||||
update_config(&mut book);
|
update_config(&mut book);
|
||||||
book.build()?;
|
book.build()?;
|
||||||
|
|
||||||
|
let language: Option<String> = match build_opts.language_ident {
|
||||||
|
// index.html will be at the root directory.
|
||||||
|
Some(_) => None,
|
||||||
|
None => match book.config.language.default_language() {
|
||||||
|
// If book has translations, index.html will be under src/en/ or
|
||||||
|
// similar.
|
||||||
|
Some(lang_ident) => Some(lang_ident.clone()),
|
||||||
|
// If not, it will be at the root.
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let sockaddr: SocketAddr = address
|
let sockaddr: SocketAddr = address
|
||||||
.to_socket_addrs()?
|
.to_socket_addrs()?
|
||||||
.next()
|
.next()
|
||||||
@ -100,7 +113,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
|||||||
|
|
||||||
let reload_tx = tx.clone();
|
let reload_tx = tx.clone();
|
||||||
let thread_handle = std::thread::spawn(move || {
|
let thread_handle = std::thread::spawn(move || {
|
||||||
serve(build_dir, sockaddr, reload_tx, &file_404);
|
serve(build_dir, sockaddr, reload_tx, &file_404, language);
|
||||||
});
|
});
|
||||||
|
|
||||||
let serving_url = format!("http://{}", address);
|
let serving_url = format!("http://{}", address);
|
||||||
@ -140,6 +153,7 @@ async fn serve(
|
|||||||
address: SocketAddr,
|
address: SocketAddr,
|
||||||
reload_tx: broadcast::Sender<Message>,
|
reload_tx: broadcast::Sender<Message>,
|
||||||
file_404: &str,
|
file_404: &str,
|
||||||
|
language: Option<String>,
|
||||||
) {
|
) {
|
||||||
// A warp Filter which captures `reload_tx` and provides an `rx` copy to
|
// A warp Filter which captures `reload_tx` and provides an `rx` copy to
|
||||||
// receive reload messages.
|
// receive reload messages.
|
||||||
@ -166,7 +180,6 @@ async fn serve(
|
|||||||
// The fallback route for 404 errors
|
// The fallback route for 404 errors
|
||||||
let fallback_route = warp::fs::file(build_dir.join(file_404))
|
let fallback_route = warp::fs::file(build_dir.join(file_404))
|
||||||
.map(|reply| warp::reply::with_status(reply, warp::http::StatusCode::NOT_FOUND));
|
.map(|reply| warp::reply::with_status(reply, warp::http::StatusCode::NOT_FOUND));
|
||||||
let routes = livereload.or(book_route).or(fallback_route);
|
|
||||||
|
|
||||||
std::panic::set_hook(Box::new(move |panic_info| {
|
std::panic::set_hook(Box::new(move |panic_info| {
|
||||||
// exit if serve panics
|
// exit if serve panics
|
||||||
@ -174,5 +187,16 @@ async fn serve(
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
warp::serve(routes).run(address).await;
|
if let Some(lang_ident) = language {
|
||||||
|
// Redirect root to the default translation directory, if serving a localized book.
|
||||||
|
// BUG: This can't be `/{lang_ident}`, or the static assets won't get loaded.
|
||||||
|
let index_for_language = format!("/{}/index.html", lang_ident).parse::<Uri>().unwrap();
|
||||||
|
let redirect_to_index = warp::path::end().map(move || warp::redirect(index_for_language.clone()));
|
||||||
|
let routes = livereload.or(redirect_to_index).or(book_route).or(fallback_route);
|
||||||
|
warp::serve(routes).run(address).await;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let routes = livereload.or(book_route).or(fallback_route);
|
||||||
|
warp::serve(routes).run(address).await;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -428,81 +428,83 @@ function playground_text(playground) {
|
|||||||
var languageToggleButton = document.getElementById('language-toggle');
|
var languageToggleButton = document.getElementById('language-toggle');
|
||||||
var languagePopup = document.getElementById('language-list');
|
var languagePopup = document.getElementById('language-list');
|
||||||
|
|
||||||
function showLanguages() {
|
if (languageToggleButton !== null) {
|
||||||
languagePopup.style.display = 'block';
|
function showLanguages() {
|
||||||
languageToggleButton.setAttribute('aria-expanded', true);
|
languagePopup.style.display = 'block';
|
||||||
}
|
languageToggleButton.setAttribute('aria-expanded', true);
|
||||||
|
|
||||||
function hideLanguages() {
|
|
||||||
languagePopup.style.display = 'none';
|
|
||||||
languageToggleButton.setAttribute('aria-expanded', false);
|
|
||||||
languageToggleButton.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function set_language(language) {
|
|
||||||
console.log("Set language " + language)
|
|
||||||
}
|
|
||||||
|
|
||||||
languageToggleButton.addEventListener('click', function () {
|
|
||||||
if (languagePopup.style.display === 'block') {
|
|
||||||
hideLanguages();
|
|
||||||
} else {
|
|
||||||
showLanguages();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
languagePopup.addEventListener('click', function (e) {
|
function hideLanguages() {
|
||||||
var language = e.target.id || e.target.parentElement.id;
|
languagePopup.style.display = 'none';
|
||||||
set_language(language);
|
languageToggleButton.setAttribute('aria-expanded', false);
|
||||||
});
|
languageToggleButton.focus();
|
||||||
|
|
||||||
languagePopup.addEventListener('focusout', function(e) {
|
|
||||||
// e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
|
|
||||||
if (!!e.relatedTarget && !languageToggleButton.contains(e.relatedTarget) && !languagePopup.contains(e.relatedTarget)) {
|
|
||||||
hideLanguages();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
|
function set_language(language) {
|
||||||
document.addEventListener('click', function(e) {
|
console.log("Set language " + language)
|
||||||
if (languagePopup.style.display === 'block' && !languageToggleButton.contains(e.target) && !languagePopup.contains(e.target)) {
|
|
||||||
hideLanguages();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('keydown', function (e) {
|
languageToggleButton.addEventListener('click', function () {
|
||||||
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
|
if (languagePopup.style.display === 'block') {
|
||||||
if (!languagePopup.contains(e.target)) { return; }
|
|
||||||
|
|
||||||
switch (e.key) {
|
|
||||||
case 'Escape':
|
|
||||||
e.preventDefault();
|
|
||||||
hideLanguages();
|
hideLanguages();
|
||||||
break;
|
} else {
|
||||||
case 'ArrowUp':
|
showLanguages();
|
||||||
e.preventDefault();
|
}
|
||||||
var li = document.activeElement.parentElement;
|
});
|
||||||
if (li && li.previousElementSibling) {
|
|
||||||
li.previousElementSibling.querySelector('button').focus();
|
languagePopup.addEventListener('click', function (e) {
|
||||||
}
|
var language = e.target.id || e.target.parentElement.id;
|
||||||
break;
|
set_language(language);
|
||||||
case 'ArrowDown':
|
});
|
||||||
e.preventDefault();
|
|
||||||
var li = document.activeElement.parentElement;
|
languagePopup.addEventListener('focusout', function(e) {
|
||||||
if (li && li.nextElementSibling) {
|
// e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
|
||||||
li.nextElementSibling.querySelector('button').focus();
|
if (!!e.relatedTarget && !languageToggleButton.contains(e.relatedTarget) && !languagePopup.contains(e.relatedTarget)) {
|
||||||
}
|
hideLanguages();
|
||||||
break;
|
}
|
||||||
case 'Home':
|
});
|
||||||
e.preventDefault();
|
|
||||||
languagePopup.querySelector('li:first-child button').focus();
|
// Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
|
||||||
break;
|
document.addEventListener('click', function(e) {
|
||||||
case 'End':
|
if (languagePopup.style.display === 'block' && !languageToggleButton.contains(e.target) && !languagePopup.contains(e.target)) {
|
||||||
e.preventDefault();
|
hideLanguages();
|
||||||
languagePopup.querySelector('li:last-child button').focus();
|
}
|
||||||
break;
|
});
|
||||||
}
|
|
||||||
});
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
|
||||||
|
if (!languagePopup.contains(e.target)) { return; }
|
||||||
|
|
||||||
|
switch (e.key) {
|
||||||
|
case 'Escape':
|
||||||
|
e.preventDefault();
|
||||||
|
hideLanguages();
|
||||||
|
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();
|
||||||
|
languagePopup.querySelector('li:first-child button').focus();
|
||||||
|
break;
|
||||||
|
case 'End':
|
||||||
|
e.preventDefault();
|
||||||
|
languagePopup.querySelector('li:last-child button').focus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(function sidebar() {
|
(function sidebar() {
|
||||||
|
Loading…
Reference in New Issue
Block a user