@@ -149,7 +149,7 @@ impl Default for FrontMatter { | |||||
order: None, | order: None, | ||||
template: None, | template: None, | ||||
paginate_by: None, | paginate_by: None, | ||||
paginate_path: None, | |||||
paginate_path: Some("page".to_string()), | |||||
render: Some(true), | render: Some(true), | ||||
extra: None, | extra: None, | ||||
} | } | ||||
@@ -23,10 +23,10 @@ pub struct Pager<'a> { | |||||
impl<'a> Pager<'a> { | impl<'a> Pager<'a> { | ||||
fn new(index: usize, pages: Vec<&'a Page>, permalink: String, path: String) -> Pager<'a> { | fn new(index: usize, pages: Vec<&'a Page>, permalink: String, path: String) -> Pager<'a> { | ||||
Pager { | Pager { | ||||
index: index, | |||||
permalink: permalink, | |||||
path: path, | |||||
pages: pages, | |||||
index, | |||||
permalink, | |||||
path, | |||||
pages, | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -44,6 +44,8 @@ pub struct Paginator<'a> { | |||||
} | } | ||||
impl<'a> Paginator<'a> { | impl<'a> Paginator<'a> { | ||||
/// Create a new paginator | |||||
/// It will always at least create one pager (the first) even if there are no pages to paginate | |||||
pub fn new(all_pages: &'a [Page], section: &'a Section) -> Paginator<'a> { | pub fn new(all_pages: &'a [Page], section: &'a Section) -> Paginator<'a> { | ||||
let paginate_by = section.meta.paginate_by.unwrap(); | let paginate_by = section.meta.paginate_by.unwrap(); | ||||
let paginate_path = match section.meta.paginate_path { | let paginate_path = match section.meta.paginate_path { | ||||
@@ -87,6 +89,11 @@ impl<'a> Paginator<'a> { | |||||
)); | )); | ||||
} | } | ||||
// We always have the index one at least | |||||
if pagers.is_empty() { | |||||
pagers.push(Pager::new(1, vec![], section.permalink.clone(), section.path.clone())); | |||||
} | |||||
Paginator { | Paginator { | ||||
all_pages: all_pages, | all_pages: all_pages, | ||||
pagers: pagers, | pagers: pagers, | ||||
@@ -149,7 +149,7 @@ impl ser::Serialize for Section { | |||||
} | } | ||||
impl Default for Section { | impl Default for Section { | ||||
/// Used to create a default index section if there is no _index.md | |||||
/// Used to create a default index section if there is no _index.md in the root content directory | |||||
fn default() -> Section { | fn default() -> Section { | ||||
Section { | Section { | ||||
file_path: PathBuf::new(), | file_path: PathBuf::new(), | ||||
@@ -173,9 +173,11 @@ impl Site { | |||||
} | } | ||||
// Insert a default index section so we don't need to create a _index.md to render | // Insert a default index section so we don't need to create a _index.md to render | ||||
// the index page | // the index page | ||||
let index_path = self.base_path.join("content"); | |||||
let index_path = self.base_path.join("content").join("_index.md"); | |||||
if !self.sections.contains_key(&index_path) { | if !self.sections.contains_key(&index_path) { | ||||
self.sections.insert(index_path, Section::default()); | |||||
let mut index_section = Section::default(); | |||||
index_section.permalink = self.config.make_permalink(""); | |||||
self.sections.insert(index_path, index_section); | |||||
} | } | ||||
// A map of all .md files (section and pages) and their permalink | // A map of all .md files (section and pages) and their permalink | ||||
@@ -217,7 +219,16 @@ impl Site { | |||||
/// Simple wrapper fn to avoid repeating that code in several places | /// Simple wrapper fn to avoid repeating that code in several places | ||||
fn add_section(&mut self, path: &Path) -> Result<()> { | fn add_section(&mut self, path: &Path) -> Result<()> { | ||||
let section = Section::from_file(path, &self.config)?; | let section = Section::from_file(path, &self.config)?; | ||||
self.sections.insert(section.parent_path.clone(), section); | |||||
self.sections.insert(section.file_path.clone(), section); | |||||
Ok(()) | |||||
} | |||||
/// Called in serve, add the section and render it | |||||
fn add_section_and_render(&mut self, path: &Path) -> Result<()> { | |||||
self.add_section(path)?; | |||||
let mut section = self.sections.get_mut(path).unwrap(); | |||||
self.permalinks.insert(section.relative_path.clone(), section.permalink.clone()); | |||||
section.render_markdown(&self.permalinks, &self.tera, &self.config)?; | |||||
Ok(()) | Ok(()) | ||||
} | } | ||||
@@ -239,10 +250,10 @@ impl Site { | |||||
/// Find out the direct subsections of each subsection if there are some | /// Find out the direct subsections of each subsection if there are some | ||||
/// as well as the pages for each section | /// as well as the pages for each section | ||||
fn populate_sections(&mut self) { | |||||
pub fn populate_sections(&mut self) { | |||||
for page in self.pages.values() { | for page in self.pages.values() { | ||||
if self.sections.contains_key(&page.parent_path) { | |||||
self.sections.get_mut(&page.parent_path).unwrap().pages.push(page.clone()); | |||||
if self.sections.contains_key(&page.parent_path.join("_index.md")) { | |||||
self.sections.get_mut(&page.parent_path.join("_index.md")).unwrap().pages.push(page.clone()); | |||||
} | } | ||||
} | } | ||||
@@ -253,14 +264,14 @@ impl Site { | |||||
} | } | ||||
} | } | ||||
for (parent_path, section) in &mut self.sections { | |||||
for section in self.sections.values_mut() { | |||||
// TODO: avoid this clone | // TODO: avoid this clone | ||||
let (mut sorted_pages, cannot_be_sorted_pages) = sort_pages(section.pages.clone(), section.meta.sort_by()); | let (mut sorted_pages, cannot_be_sorted_pages) = sort_pages(section.pages.clone(), section.meta.sort_by()); | ||||
sorted_pages = populate_previous_and_next_pages(&sorted_pages); | sorted_pages = populate_previous_and_next_pages(&sorted_pages); | ||||
section.pages = sorted_pages; | section.pages = sorted_pages; | ||||
section.ignored_pages = cannot_be_sorted_pages; | section.ignored_pages = cannot_be_sorted_pages; | ||||
match grandparent_paths.get(parent_path) { | |||||
match grandparent_paths.get(§ion.parent_path) { | |||||
Some(paths) => section.subsections.extend(paths.clone()), | Some(paths) => section.subsections.extend(paths.clone()), | ||||
None => continue, | None => continue, | ||||
}; | }; | ||||
@@ -353,7 +364,8 @@ impl Site { | |||||
if path.exists() { | if path.exists() { | ||||
// file exists, either a new one or updating content | // file exists, either a new one or updating content | ||||
if is_section { | if is_section { | ||||
self.add_section(path)?; | |||||
self.add_section_and_render(path)?; | |||||
self.render_sections()?; | |||||
} else { | } else { | ||||
// probably just an update so just re-parse that page | // probably just an update so just re-parse that page | ||||
let (frontmatter_changed, page) = self.add_page_and_render(path)?; | let (frontmatter_changed, page) = self.add_page_and_render(path)?; | ||||
@@ -661,7 +673,6 @@ impl Site { | |||||
}; | }; | ||||
let paginator = Paginator::new(§ion.pages, section); | let paginator = Paginator::new(§ion.pages, section); | ||||
for (i, pager) in paginator.pagers.iter().enumerate() { | for (i, pager) in paginator.pagers.iter().enumerate() { | ||||
let folder_path = output_path.join(&paginate_path); | let folder_path = output_path.join(&paginate_path); | ||||
let page_path = folder_path.join(&format!("{}", i + 1)); | let page_path = folder_path.join(&format!("{}", i + 1)); | ||||
@@ -0,0 +1,4 @@ | |||||
+++ | |||||
paginate_by = 10 | |||||
template = "section_paginated.html" | |||||
+++ |
@@ -1,4 +1,5 @@ | |||||
+++ | +++ | ||||
title = "Posts" | title = "Posts" | ||||
description = "" | |||||
paginate_by = 2 | |||||
template = "section_paginated.html" | |||||
+++ | +++ |
@@ -35,26 +35,26 @@ fn test_can_parse_site() { | |||||
assert_eq!(asset_folder_post.components, vec!["posts".to_string()]); | assert_eq!(asset_folder_post.components, vec!["posts".to_string()]); | ||||
// That we have the right number of sections | // That we have the right number of sections | ||||
assert_eq!(site.sections.len(), 5); | |||||
assert_eq!(site.sections.len(), 6); | |||||
// And that the sections are correct | // And that the sections are correct | ||||
let index_section = &site.sections[&path.join("content")]; | |||||
assert_eq!(index_section.subsections.len(), 1); | |||||
let index_section = &site.sections[&path.join("content").join("_index.md")]; | |||||
assert_eq!(index_section.subsections.len(), 2); | |||||
assert_eq!(index_section.pages.len(), 1); | assert_eq!(index_section.pages.len(), 1); | ||||
let posts_section = &site.sections[&posts_path]; | |||||
let posts_section = &site.sections[&posts_path.join("_index.md")]; | |||||
assert_eq!(posts_section.subsections.len(), 1); | assert_eq!(posts_section.subsections.len(), 1); | ||||
assert_eq!(posts_section.pages.len(), 5); | assert_eq!(posts_section.pages.len(), 5); | ||||
let tutorials_section = &site.sections[&posts_path.join("tutorials")]; | |||||
let tutorials_section = &site.sections[&posts_path.join("tutorials").join("_index.md")]; | |||||
assert_eq!(tutorials_section.subsections.len(), 2); | assert_eq!(tutorials_section.subsections.len(), 2); | ||||
assert_eq!(tutorials_section.pages.len(), 0); | assert_eq!(tutorials_section.pages.len(), 0); | ||||
let devops_section = &site.sections[&posts_path.join("tutorials").join("devops")]; | |||||
let devops_section = &site.sections[&posts_path.join("tutorials").join("devops").join("_index.md")]; | |||||
assert_eq!(devops_section.subsections.len(), 0); | assert_eq!(devops_section.subsections.len(), 0); | ||||
assert_eq!(devops_section.pages.len(), 2); | assert_eq!(devops_section.pages.len(), 2); | ||||
let prog_section = &site.sections[&posts_path.join("tutorials").join("programming")]; | |||||
let prog_section = &site.sections[&posts_path.join("tutorials").join("programming").join("_index.md")]; | |||||
assert_eq!(prog_section.subsections.len(), 0); | assert_eq!(prog_section.subsections.len(), 0); | ||||
assert_eq!(prog_section.pages.len(), 2); | assert_eq!(prog_section.pages.len(), 2); | ||||
} | } | ||||
@@ -294,6 +294,9 @@ fn test_can_build_site_with_pagination_for_section() { | |||||
let mut site = Site::new(&path, "config.toml").unwrap(); | let mut site = Site::new(&path, "config.toml").unwrap(); | ||||
site.load().unwrap(); | site.load().unwrap(); | ||||
for section in site.sections.values_mut(){ | for section in site.sections.values_mut(){ | ||||
if section.is_index() { | |||||
continue; | |||||
} | |||||
section.meta.paginate_by = Some(2); | section.meta.paginate_by = Some(2); | ||||
section.meta.template = Some("section_paginated.html".to_string()); | section.meta.template = Some("section_paginated.html".to_string()); | ||||
} | } | ||||
@@ -316,6 +319,9 @@ fn test_can_build_site_with_pagination_for_section() { | |||||
assert!(file_exists!(public, "posts/index.html")); | assert!(file_exists!(public, "posts/index.html")); | ||||
// And pagination! | // And pagination! | ||||
assert!(file_exists!(public, "posts/page/1/index.html")); | assert!(file_exists!(public, "posts/page/1/index.html")); | ||||
// even if there is no pages, only the section! | |||||
assert!(file_exists!(public, "paginated/page/1/index.html")); | |||||
assert!(file_exists!(public, "paginated/index.html")); | |||||
// should redirect to posts/ | // should redirect to posts/ | ||||
assert!(file_contains!( | assert!(file_contains!( | ||||
public, | public, | ||||
@@ -347,7 +353,7 @@ fn test_can_build_site_with_pagination_for_index() { | |||||
let mut site = Site::new(&path, "config.toml").unwrap(); | let mut site = Site::new(&path, "config.toml").unwrap(); | ||||
site.load().unwrap(); | site.load().unwrap(); | ||||
{ | { | ||||
let mut index = site.sections.get_mut(&path.join("content")).unwrap(); | |||||
let mut index = site.sections.get_mut(&path.join("content").join("_index.md")).unwrap(); | |||||
index.meta.paginate_by = Some(2); | index.meta.paginate_by = Some(2); | ||||
index.meta.template = Some("index_paginated.html".to_string()); | index.meta.template = Some("index_paginated.html".to_string()); | ||||
} | } | ||||
@@ -368,6 +374,9 @@ fn test_can_build_site_with_pagination_for_index() { | |||||
// And pagination! | // And pagination! | ||||
assert!(file_exists!(public, "page/1/index.html")); | assert!(file_exists!(public, "page/1/index.html")); | ||||
// even if there is no pages, only the section! | |||||
assert!(file_exists!(public, "paginated/page/1/index.html")); | |||||
assert!(file_exists!(public, "paginated/index.html")); | |||||
// should redirect to index | // should redirect to index | ||||
assert!(file_contains!( | assert!(file_contains!( | ||||
public, | public, | ||||