index links and translation links separately

This commit is contained in:
Gambhiro 2017-01-16 13:10:12 +00:00
parent 6492faa1bc
commit ca40e71d1b
7 changed files with 168 additions and 45 deletions

View File

@ -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>

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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();
// 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(_) => {},
None => {
newcontent.chapter.translation_links = Some(default_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
}

View File

@ -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));

View File

@ -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();