index links and translation links separately
This commit is contained in:
parent
6492faa1bc
commit
ca40e71d1b
|
@ -43,6 +43,10 @@
|
|||
</script>
|
||||
|
||||
<div id="sidebar" class="sidebar">
|
||||
<div class="translation-indexes">
|
||||
{{#translation-indexes}}{{/translation-indexes}}
|
||||
</div>
|
||||
|
||||
{{#toc}}{{/toc}}
|
||||
</div>
|
||||
|
||||
|
@ -55,8 +59,8 @@
|
|||
<i id="theme-toggle" class="fa fa-paint-brush"></i>
|
||||
</div>
|
||||
|
||||
<div class="translations">
|
||||
{{#translations}}{{/translations}}
|
||||
<div class="translation-links">
|
||||
{{#translation-links}}{{/translation-links}}
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">{{ title }}</h1>
|
||||
|
|
|
@ -54,12 +54,30 @@
|
|||
img { max-width: 100%; }
|
||||
}
|
||||
|
||||
div.translations {
|
||||
float: left
|
||||
height: 50px
|
||||
div.translation-indexes {
|
||||
ul {
|
||||
margin: 10px 0 0 0
|
||||
display: inline-block
|
||||
padding: 0
|
||||
text-align: center
|
||||
list-style-type: none
|
||||
li {
|
||||
display: inline-block
|
||||
padding: 0.2em 0.5em
|
||||
a {
|
||||
text-decoration: none
|
||||
&:hover { text-decoration: underline; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.translation-links {
|
||||
float: left
|
||||
height: 50px
|
||||
ul {
|
||||
margin: 10px 0 0 0
|
||||
padding: 0 0 0 1em
|
||||
text-align: left
|
||||
list-style-type: none
|
||||
li {
|
||||
display: inline-block
|
||||
|
|
|
@ -151,23 +151,40 @@ table thead td {
|
|||
.content img {
|
||||
max-width: 100%;
|
||||
}
|
||||
div.translations {
|
||||
float: left;
|
||||
height: 50px;
|
||||
}
|
||||
div.translations ul {
|
||||
div.translation-indexes ul {
|
||||
margin: 10px 0 0 0;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
list-style-type: none;
|
||||
}
|
||||
div.translations ul li {
|
||||
div.translation-indexes ul li {
|
||||
display: inline-block;
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
div.translations ul li a {
|
||||
div.translation-indexes ul li a {
|
||||
text-decoration: none;
|
||||
}
|
||||
div.translations ul li a:hover {
|
||||
div.translation-indexes ul li a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
div.translation-links {
|
||||
float: left;
|
||||
height: 50px;
|
||||
}
|
||||
div.translation-links ul {
|
||||
margin: 10px 0 0 0;
|
||||
padding: 0 0 0 1em;
|
||||
text-align: left;
|
||||
list-style-type: none;
|
||||
}
|
||||
div.translation-links ul li {
|
||||
display: inline-block;
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
div.translation-links ul li a {
|
||||
text-decoration: none;
|
||||
}
|
||||
div.translation-links ul li a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.menu-bar {
|
||||
|
|
|
@ -69,6 +69,9 @@ pub struct Chapter {
|
|||
/// Links to the corresponding translations.
|
||||
pub translation_links: Option<Vec<TranslationLink>>,
|
||||
|
||||
/// An identifier string that can allow linking translations with different paths.
|
||||
pub translation_id: Option<String>,
|
||||
|
||||
/// The author of the chapter, or the book.
|
||||
pub authors: Option<Vec<Author>>,
|
||||
|
||||
|
@ -93,6 +96,7 @@ impl Default for Chapter {
|
|||
src_path: None,
|
||||
dest_path: None,
|
||||
translation_links: None,
|
||||
translation_id: None,
|
||||
authors: None,
|
||||
translators: None,
|
||||
description: None,
|
||||
|
@ -196,6 +200,10 @@ impl Chapter {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(a) = data.get("translation_id") {
|
||||
self.translation_id = Some(a.to_string().replace("\"", ""));
|
||||
}
|
||||
|
||||
// Author name as a hash key.
|
||||
if let Some(a) = data.get("author") {
|
||||
if let Some(b) = a.as_str() {
|
||||
|
@ -294,24 +302,35 @@ impl Chapter {
|
|||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TranslationLink {
|
||||
/// Language code, such as 'en' or 'fr'.
|
||||
pub code: String,
|
||||
pub link: String,
|
||||
/// The `<a href="">` link to the translation. `None` indicates that the
|
||||
/// language is part of the book, but there isn't a translation for this
|
||||
/// chapter.
|
||||
pub link: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for TranslationLink {
|
||||
fn default() -> TranslationLink {
|
||||
TranslationLink {
|
||||
code: "".to_string(),
|
||||
link: "".to_string(),
|
||||
code: "--".to_string(),
|
||||
link: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TranslationLink {
|
||||
pub fn new(code: String, link: String) -> TranslationLink {
|
||||
pub fn new(code: String) -> TranslationLink {
|
||||
TranslationLink {
|
||||
code: code,
|
||||
link: link,
|
||||
link: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_link(code: String, link: String) -> TranslationLink {
|
||||
TranslationLink {
|
||||
code: code,
|
||||
link: Some(link),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +342,9 @@ impl From<toml::Table> for TranslationLink {
|
|||
link.code = x.to_string().replace("\"", "");
|
||||
}
|
||||
if let Some(x) = data.get("link") {
|
||||
link.link = x.to_string().replace("\"", "");
|
||||
link.link = Some(x.to_string().replace("\"", ""));
|
||||
} else {
|
||||
link.link = None;
|
||||
}
|
||||
link
|
||||
}
|
||||
|
|
|
@ -448,7 +448,7 @@ impl MDBook {
|
|||
}
|
||||
|
||||
/// prepare a Vec of default links to point to the index.html of each translation
|
||||
fn translation_index_links(&mut self) -> Vec<TranslationLink> {
|
||||
pub fn translation_index_links(&self) -> Option<Vec<TranslationLink>> {
|
||||
let mut default_links: Vec<TranslationLink> = vec![];
|
||||
|
||||
let mut keys = self.translations.keys()
|
||||
|
@ -456,6 +456,11 @@ impl MDBook {
|
|||
.collect::<Vec<String>>();
|
||||
keys.sort();
|
||||
|
||||
if keys.len() < 2 {
|
||||
// There is only one language. No need to display translation links.
|
||||
return None;
|
||||
}
|
||||
|
||||
for key in keys {
|
||||
let book = self.translations.get(&key).unwrap();
|
||||
|
||||
|
@ -463,25 +468,37 @@ impl MDBook {
|
|||
let a = book.config.dest.strip_prefix(&z).unwrap();
|
||||
let b = a.join("index.html");
|
||||
let c = b.to_str().unwrap();
|
||||
let link = TranslationLink::new(key, c.to_string());
|
||||
let link = TranslationLink::new_with_link(key, c.to_string());
|
||||
default_links.push(link);
|
||||
}
|
||||
|
||||
default_links
|
||||
Some(default_links)
|
||||
}
|
||||
|
||||
fn set_translation_links(&mut self, content: &TocContent) -> TocContent {
|
||||
let default_links = self.translation_index_links();
|
||||
|
||||
let mut final_links: BTreeMap<String, TranslationLink> = BTreeMap::new();
|
||||
let mut newcontent: TocContent = content.clone();
|
||||
|
||||
match newcontent.chapter.translation_links {
|
||||
Some(_) => {},
|
||||
None => {
|
||||
newcontent.chapter.translation_links = Some(default_links);
|
||||
}
|
||||
// Start by adding the code of each language but no links. These will
|
||||
// render as gray <span> tags.
|
||||
for key in self.translations.keys() {
|
||||
final_links.insert(key.clone(), TranslationLink::new(key.clone()));
|
||||
}
|
||||
|
||||
// Take the links parsed from the chapter's TOML header
|
||||
|
||||
match newcontent.chapter.translation_links {
|
||||
Some(links) => {
|
||||
for i in links.iter() {
|
||||
final_links.insert(i.clone().code, i.clone());
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
|
||||
let a: Vec<TranslationLink> = final_links.values().map(|x| x.clone()).collect();
|
||||
newcontent.chapter.translation_links = Some(a);
|
||||
|
||||
newcontent
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use renderer::html_handlebars::helpers;
|
||||
use renderer::Renderer;
|
||||
use book::{MDBook, Book};
|
||||
use book::chapter::Chapter;
|
||||
use book::chapter::{Chapter, TranslationLink};
|
||||
use book::toc::{TocItem, TocContent};
|
||||
use utils;
|
||||
use FILES;
|
||||
|
@ -127,6 +127,8 @@ impl Renderer for HtmlHandlebars {
|
|||
debug!("[fn]: render");
|
||||
let mut handlebars = Handlebars::new();
|
||||
|
||||
let translation_indexes = book_project.translation_index_links();
|
||||
|
||||
// Render the chapters of each book
|
||||
for (key, book) in &book_project.translations {
|
||||
|
||||
|
@ -164,7 +166,8 @@ impl Renderer for HtmlHandlebars {
|
|||
handlebars.register_helper("toc", Box::new(helpers::toc::RenderToc));
|
||||
handlebars.register_helper("previous", Box::new(helpers::navigation::previous));
|
||||
handlebars.register_helper("next", Box::new(helpers::navigation::next));
|
||||
handlebars.register_helper("translations", Box::new(helpers::translations::TranslationsHelper));
|
||||
handlebars.register_helper("translation-links", Box::new(helpers::translations::TranslationLinksHelper));
|
||||
handlebars.register_helper("translation-indexes", Box::new(helpers::translations::TranslationIndexesHelper));
|
||||
|
||||
// Check if book's dest directory exists
|
||||
|
||||
|
@ -196,12 +199,12 @@ impl Renderer for HtmlHandlebars {
|
|||
// almost the same as process_chapter(), but we have to
|
||||
// manipulate path_to_root in data and rendered_path
|
||||
|
||||
let mut data = try!(make_data(&book, &chapter, &book_project.livereload_script));
|
||||
let mut data = try!(make_data(&book, &chapter, &translation_indexes, &book_project.livereload_script));
|
||||
|
||||
data.remove("path_to_root");
|
||||
data.insert("path_to_root".to_owned(), "".to_json());
|
||||
|
||||
// Rendere the handlebars template with the data
|
||||
// Render the handlebars template with the data
|
||||
debug!("[*]: Render template");
|
||||
let rendered_content = try!(handlebars.render("page", &data));
|
||||
|
||||
|
@ -221,7 +224,7 @@ impl Renderer for HtmlHandlebars {
|
|||
}
|
||||
|
||||
// Render a file for every entry in the book
|
||||
try!(self.process_items(&book.toc, &book, &book_project.livereload_script, &handlebars));
|
||||
try!(self.process_items(&book.toc, &book, &translation_indexes, &book_project.livereload_script, &handlebars));
|
||||
|
||||
// Write print.html
|
||||
if let Some(content) = self.collect_print_content_markdown(&book.toc, &book) {
|
||||
|
@ -231,7 +234,7 @@ impl Renderer for HtmlHandlebars {
|
|||
chapter.set_dest_path(PathBuf::from("print.html"));
|
||||
chapter.content = Some(content);
|
||||
|
||||
try!(self.process_chapter(&chapter, &book, &None, &handlebars));
|
||||
try!(self.process_chapter(&chapter, &book, &None, &None, &handlebars));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,6 +247,7 @@ impl HtmlHandlebars {
|
|||
fn process_items(&self,
|
||||
items: &Vec<TocItem>,
|
||||
book: &Book,
|
||||
translation_indexes: &Option<Vec<TranslationLink>>,
|
||||
livereload_script: &Option<String>,
|
||||
handlebars: &Handlebars)
|
||||
-> Result<(), Box<Error>> {
|
||||
|
@ -254,11 +258,11 @@ impl HtmlHandlebars {
|
|||
TocItem::Unnumbered(ref i) |
|
||||
TocItem::Unlisted(ref i) => {
|
||||
if let Some(_) = i.chapter.get_dest_path() {
|
||||
try!(self.process_chapter(&i.chapter, book, livereload_script, handlebars));
|
||||
try!(self.process_chapter(&i.chapter, book, translation_indexes, livereload_script, handlebars));
|
||||
}
|
||||
|
||||
if let Some(ref subs) = i.sub_items {
|
||||
try!(self.process_items(&subs, book, livereload_script, handlebars));
|
||||
try!(self.process_items(&subs, book, translation_indexes, livereload_script, handlebars));
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -303,11 +307,12 @@ impl HtmlHandlebars {
|
|||
fn process_chapter(&self,
|
||||
chapter: &Chapter,
|
||||
book: &Book,
|
||||
translation_indexes: &Option<Vec<TranslationLink>>,
|
||||
livereload_script: &Option<String>,
|
||||
handlebars: &Handlebars)
|
||||
-> Result<(), Box<Error>> {
|
||||
|
||||
let data = try!(make_data(book, chapter, livereload_script));
|
||||
let data = try!(make_data(book, chapter, translation_indexes, livereload_script));
|
||||
|
||||
// Render the handlebars template with the data
|
||||
debug!("[*]: Render template");
|
||||
|
@ -339,6 +344,7 @@ impl HtmlHandlebars {
|
|||
|
||||
fn make_data(book: &Book,
|
||||
chapter: &Chapter,
|
||||
translation_indexes: &Option<Vec<TranslationLink>>,
|
||||
livereload_script: &Option<String>)
|
||||
-> Result<serde_json::Map<String, serde_json::Value>, Box<Error>> {
|
||||
|
||||
|
@ -402,8 +408,12 @@ fn make_data(book: &Book,
|
|||
},
|
||||
}
|
||||
|
||||
if let Some(ref links) = *translation_indexes {
|
||||
data.insert("translation-indexes".to_owned(), links.to_json());
|
||||
}
|
||||
|
||||
if let Some(ref links) = chapter.translation_links {
|
||||
data.insert("translation_links".to_owned(), links.to_json());
|
||||
data.insert("translation-links".to_owned(), links.to_json());
|
||||
}
|
||||
|
||||
let chapters = try!(items_to_chapters(&book.toc, &book));
|
||||
|
|
|
@ -5,19 +5,55 @@ use serde_json;
|
|||
use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TranslationsHelper;
|
||||
pub struct TranslationLinksHelper;
|
||||
|
||||
impl HelperDef for TranslationsHelper {
|
||||
impl HelperDef for TranslationLinksHelper {
|
||||
fn call(&self, c: &Context, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
|
||||
|
||||
let translation_links = c.navigate(rc.get_path(), &VecDeque::new(), "translation_links");
|
||||
let translation_links = c.navigate(rc.get_path(), &VecDeque::new(), "translation-links");
|
||||
let decoded: Vec<BTreeMap<String, String>> = serde_json::from_str(&translation_links.to_string()).unwrap();
|
||||
|
||||
if decoded.len() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
try!(rc.writer.write("<ul class=\"translations\">".as_bytes()));
|
||||
try!(rc.writer.write("<ul class=\"translation-links\">".as_bytes()));
|
||||
|
||||
for item in decoded {
|
||||
let empty = "".to_string();
|
||||
let link = item.get("link").unwrap_or(&empty);
|
||||
let code = item.get("code").unwrap_or(&empty);
|
||||
|
||||
// None value in the link becomes an empty string
|
||||
let text = if link.len() == 0 {
|
||||
format!("<li><span>{}</span></li>", code)
|
||||
} else {
|
||||
format!("<li><a href=\"{}\">{}</a></li>", link, code)
|
||||
};
|
||||
|
||||
try!(rc.writer.write(text.as_bytes()));
|
||||
}
|
||||
|
||||
try!(rc.writer.write("</ul>".as_bytes()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TranslationIndexesHelper;
|
||||
|
||||
impl HelperDef for TranslationIndexesHelper {
|
||||
fn call(&self, c: &Context, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
|
||||
|
||||
let translation_indexes = c.navigate(rc.get_path(), &VecDeque::new(), "translation-indexes");
|
||||
let decoded: Vec<BTreeMap<String, String>> = serde_json::from_str(&translation_indexes.to_string()).unwrap();
|
||||
|
||||
if decoded.len() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
try!(rc.writer.write("<ul class=\"translation-indexes\">".as_bytes()));
|
||||
|
||||
for item in decoded {
|
||||
let empty = "".to_string();
|
||||
|
|
Loading…
Reference in New Issue