From b9296f7985aceb7d1be5dc12f5b7d3396c5fa901 Mon Sep 17 00:00:00 2001 From: yanghuidong Date: Thu, 30 Jul 2020 02:44:09 +0800 Subject: [PATCH] Make current_path always start with a slash (#1101) * Make {section, page}.path always start with a slash Change tests accordingly * Fix missing leading/trailing slash in current_path of Taxonomy ("tags") and TaxonomyItem ("some-tag") * Make {Paginator, Pager}.path always start with a slash Fix Paginator.path missing trailing slash in from_taxonomy() Change tests accordingly * Update documentation regarding current_path now always starting with a slash * Fix asymptomatic inverted logic in filter() for {section, page}.assets * Add to 3 integration tests several checks for current_path in different templates * Add a check for current_path in a paginated index section, "/page/2/" This requires adding two dummy pages in the content root. * Fix false passing of test on paginator.last due to URL prefix matching A string formatting such as {name: value} can help prevent this. --- components/library/src/content/page.rs | 30 ++++++++----- components/library/src/content/section.rs | 22 ++++----- components/library/src/pagination/mod.rs | 23 +++++----- components/library/src/taxonomies/mod.rs | 4 +- components/site/tests/site.rs | 45 +++++++++++++++---- .../documentation/templates/overview.md | 4 +- test_site/content/root-page-1.md | 2 + test_site/content/root-page-2.md | 2 + test_site/templates/index_paginated.html | 3 ++ test_site/templates/tags/list.html | 2 + test_site/templates/tags/single.html | 2 + .../themes/sample/templates/current_path.html | 1 + test_site/themes/sample/templates/index.html | 2 + 13 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 test_site/content/root-page-1.md create mode 100644 test_site/content/root-page-2.md create mode 100644 test_site/themes/sample/templates/current_path.html diff --git a/components/library/src/content/page.rs b/components/library/src/content/page.rs index dbea1bd9..5199c013 100644 --- a/components/library/src/content/page.rs +++ b/components/library/src/content/page.rs @@ -48,7 +48,7 @@ pub struct Page { /// The slug of that page. /// First tries to find the slug in the meta and defaults to filename otherwise pub slug: String, - /// The URL path of the page + /// The URL path of the page, always starting with a slash pub path: String, /// The components of the path of the page pub components: Vec, @@ -182,8 +182,14 @@ impl Page { } }; - if let Some(ref p) = page.meta.path { - page.path = p.trim().trim_start_matches('/').to_string(); + page.path = if let Some(ref p) = page.meta.path { + let path = p.trim(); + + if path.starts_with('/') { + path.into() + } else { + format!("/{}", path) + } } else { let mut path = if page.file.components.is_empty() { page.slug.clone() @@ -195,8 +201,8 @@ impl Page { path = format!("{}/{}", page.lang, path); } - page.path = path; - } + format!("/{}", path) + }; if !page.path.ends_with('/') { page.path = format!("{}/", page.path); @@ -238,7 +244,7 @@ impl Page { page.assets = assets .into_iter() .filter(|path| match path.file_name() { - None => true, + None => false, Some(file) => !globset.is_match(file), }) .collect(); @@ -420,7 +426,7 @@ Hello world"#; Page::parse(Path::new("content/posts/intro/start.md"), content, &conf, &PathBuf::new()); assert!(res.is_ok()); let page = res.unwrap(); - assert_eq!(page.path, "posts/intro/hello-world/"); + assert_eq!(page.path, "/posts/intro/hello-world/"); assert_eq!(page.components, vec!["posts", "intro", "hello-world"]); assert_eq!(page.permalink, "http://hello.com/posts/intro/hello-world/"); } @@ -436,7 +442,7 @@ Hello world"#; let res = Page::parse(Path::new("start.md"), content, &config, &PathBuf::new()); assert!(res.is_ok()); let page = res.unwrap(); - assert_eq!(page.path, "hello-world/"); + assert_eq!(page.path, "/hello-world/"); assert_eq!(page.components, vec!["hello-world"]); assert_eq!(page.permalink, config.make_permalink("hello-world")); } @@ -453,7 +459,7 @@ Hello world"#; let res = Page::parse(Path::new("start.md"), content, &config, &PathBuf::new()); assert!(res.is_ok()); let page = res.unwrap(); - assert_eq!(page.path, "hello-world/"); + assert_eq!(page.path, "/hello-world/"); assert_eq!(page.components, vec!["hello-world"]); assert_eq!(page.permalink, config.make_permalink("hello-world")); } @@ -470,7 +476,7 @@ Hello world"#; let res = Page::parse(Path::new("start.md"), content, &config, &PathBuf::new()); assert!(res.is_ok()); let page = res.unwrap(); - assert_eq!(page.path, "日本/"); + assert_eq!(page.path, "/日本/"); assert_eq!(page.components, vec!["日本"]); assert_eq!(page.permalink, config.make_permalink("日本")); } @@ -491,7 +497,7 @@ Hello world"#; ); assert!(res.is_ok()); let page = res.unwrap(); - assert_eq!(page.path, "hello-world/"); + assert_eq!(page.path, "/hello-world/"); assert_eq!(page.components, vec!["hello-world"]); assert_eq!(page.permalink, config.make_permalink("hello-world")); } @@ -512,7 +518,7 @@ Hello world"#; ); assert!(res.is_ok()); let page = res.unwrap(); - assert_eq!(page.path, "hello-world/"); + assert_eq!(page.path, "/hello-world/"); assert_eq!(page.permalink, config.make_permalink("hello-world")); } diff --git a/components/library/src/content/section.rs b/components/library/src/content/section.rs index 705b5a2a..0694969c 100644 --- a/components/library/src/content/section.rs +++ b/components/library/src/content/section.rs @@ -23,7 +23,7 @@ pub struct Section { pub file: FileInfo, /// The front matter meta-data pub meta: SectionFrontMatter, - /// The URL path of the page + /// The URL path of the page, always starting with a slash pub path: String, /// The components for the path of that page pub components: Vec, @@ -111,16 +111,18 @@ impl Section { let (word_count, reading_time) = get_reading_analytics(§ion.raw_content); section.word_count = Some(word_count); section.reading_time = Some(reading_time); + let path = section.file.components.join("/"); - if section.lang != config.default_language { - if path.is_empty() { - section.path = format!("{}/", section.lang); - } else { - section.path = format!("{}/{}/", section.lang, path); - } + let lang_path = if section.lang != config.default_language { + format!("/{}", section.lang) } else { - section.path = format!("{}/", path); - } + "".into() + }; + section.path = if path.is_empty() { + format!("{}/", lang_path) + } else { + format!("{}/{}/", lang_path, path) + }; section.components = section .path @@ -156,7 +158,7 @@ impl Section { section.assets = assets .into_iter() .filter(|path| match path.file_name() { - None => true, + None => false, Some(file) => !globset.is_match(file), }) .collect(); diff --git a/components/library/src/pagination/mod.rs b/components/library/src/pagination/mod.rs index c186406f..eda1ebce 100644 --- a/components/library/src/pagination/mod.rs +++ b/components/library/src/pagination/mod.rs @@ -96,7 +96,7 @@ impl<'a> Paginator<'a> { paginate_by, root: PaginationRoot::Taxonomy(taxonomy, item), permalink: item.permalink.clone(), - path: format!("{}/{}", taxonomy.kind.name, item.slug), + path: format!("/{}/{}/", taxonomy.kind.name, item.slug), paginate_path: taxonomy .kind .paginate_path @@ -146,7 +146,7 @@ impl<'a> Paginator<'a> { let permalink = format!("{}{}", self.permalink, page_path); let pager_path = if self.is_index { - page_path + format!("/{}", page_path) } else if self.path.ends_with('/') { format!("{}{}", self.path, page_path) } else { @@ -252,10 +252,11 @@ mod tests { f.paginate_path = "page".to_string(); let mut s = Section::new("content/_index.md", f, &PathBuf::new()); if !is_index { - s.path = "posts/".to_string(); + s.path = "/posts/".to_string(); s.permalink = "https://vincent.is/posts/".to_string(); s.file.components = vec!["posts".to_string()]; } else { + s.path = "/".into(); s.permalink = "https://vincent.is/".to_string(); } s @@ -285,12 +286,12 @@ mod tests { assert_eq!(paginator.pagers[0].index, 1); assert_eq!(paginator.pagers[0].pages.len(), 2); assert_eq!(paginator.pagers[0].permalink, "https://vincent.is/posts/"); - assert_eq!(paginator.pagers[0].path, "posts/"); + assert_eq!(paginator.pagers[0].path, "/posts/"); assert_eq!(paginator.pagers[1].index, 2); assert_eq!(paginator.pagers[1].pages.len(), 2); assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/posts/page/2/"); - assert_eq!(paginator.pagers[1].path, "posts/page/2/"); + assert_eq!(paginator.pagers[1].path, "/posts/page/2/"); } #[test] @@ -302,12 +303,12 @@ mod tests { assert_eq!(paginator.pagers[0].index, 1); assert_eq!(paginator.pagers[0].pages.len(), 2); assert_eq!(paginator.pagers[0].permalink, "https://vincent.is/"); - assert_eq!(paginator.pagers[0].path, ""); + assert_eq!(paginator.pagers[0].path, "/"); assert_eq!(paginator.pagers[1].index, 2); assert_eq!(paginator.pagers[1].pages.len(), 2); assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/page/2/"); - assert_eq!(paginator.pagers[1].path, "page/2/"); + assert_eq!(paginator.pagers[1].path, "/page/2/"); } #[test] @@ -355,12 +356,12 @@ mod tests { assert_eq!(paginator.pagers[0].index, 1); assert_eq!(paginator.pagers[0].pages.len(), 2); assert_eq!(paginator.pagers[0].permalink, "https://vincent.is/tags/something/"); - assert_eq!(paginator.pagers[0].path, "tags/something"); + assert_eq!(paginator.pagers[0].path, "/tags/something/"); assert_eq!(paginator.pagers[1].index, 2); assert_eq!(paginator.pagers[1].pages.len(), 2); assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/tags/something/page/2/"); - assert_eq!(paginator.pagers[1].path, "tags/something/page/2/"); + assert_eq!(paginator.pagers[1].path, "/tags/something/page/2/"); } // https://github.com/getzola/zola/issues/866 @@ -374,12 +375,12 @@ mod tests { assert_eq!(paginator.pagers[0].index, 1); assert_eq!(paginator.pagers[0].pages.len(), 2); assert_eq!(paginator.pagers[0].permalink, "https://vincent.is/posts/"); - assert_eq!(paginator.pagers[0].path, "posts/"); + assert_eq!(paginator.pagers[0].path, "/posts/"); assert_eq!(paginator.pagers[1].index, 2); assert_eq!(paginator.pagers[1].pages.len(), 2); assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/posts/2/"); - assert_eq!(paginator.pagers[1].path, "posts/2/"); + assert_eq!(paginator.pagers[1].path, "/posts/2/"); let context = paginator.build_paginator_context(&paginator.pagers[0]); assert_eq!(context["base_url"], to_value("https://vincent.is/posts/").unwrap()); diff --git a/components/library/src/taxonomies/mod.rs b/components/library/src/taxonomies/mod.rs index c2f700f1..4c9f1076 100644 --- a/components/library/src/taxonomies/mod.rs +++ b/components/library/src/taxonomies/mod.rs @@ -150,7 +150,7 @@ impl Taxonomy { "current_url", &config.make_permalink(&format!("{}/{}", self.kind.name, item.slug)), ); - context.insert("current_path", &format!("/{}/{}", self.kind.name, item.slug)); + context.insert("current_path", &format!("/{}/{}/", self.kind.name, item.slug)); render_template(&format!("{}/single.html", self.kind.name), tera, context, &config.theme) .map_err(|e| { @@ -172,7 +172,7 @@ impl Taxonomy { context.insert("lang", &self.kind.lang); context.insert("taxonomy", &self.kind); context.insert("current_url", &config.make_permalink(&self.kind.name)); - context.insert("current_path", &self.kind.name); + context.insert("current_path", &format!("/{}/", self.kind.name)); render_template(&format!("{}/list.html", self.kind.name), tera, context, &config.theme) .map_err(|e| { diff --git a/components/site/tests/site.rs b/components/site/tests/site.rs index bb0fe240..170db3f5 100644 --- a/components/site/tests/site.rs +++ b/components/site/tests/site.rs @@ -19,12 +19,12 @@ fn can_parse_site() { let library = site.library.read().unwrap(); // Correct number of pages (sections do not count as pages, draft are ignored) - assert_eq!(library.pages().len(), 21); + assert_eq!(library.pages().len(), 23); let posts_path = path.join("content").join("posts"); // Make sure the page with a url doesn't have any sections let url_post = library.get_page(&posts_path.join("fixed-url.md")).unwrap(); - assert_eq!(url_post.path, "a-fixed-url/"); + assert_eq!(url_post.path, "/a-fixed-url/"); // Make sure the article in a folder with only asset doesn't get counted as a section let asset_folder_post = @@ -37,7 +37,7 @@ fn can_parse_site() { // And that the sections are correct let index_section = library.get_section(&path.join("content").join("_index.md")).unwrap(); assert_eq!(index_section.subsections.len(), 4); - assert_eq!(index_section.pages.len(), 1); + assert_eq!(index_section.pages.len(), 3); assert!(index_section.ancestors.is_empty()); let posts_section = library.get_section(&posts_path.join("_index.md")).unwrap(); @@ -446,6 +446,16 @@ fn can_build_site_with_pagination_for_section() { "sitemap.xml", "https://replace-this-with-your-url.com/posts/page/4/" )); + + // current_path + assert!(file_contains!(public, "posts/index.html", ¤t_path("/posts/"))); + assert!(file_contains!(public, "posts/page/2/index.html", ¤t_path("/posts/page/2/"))); + assert!(file_contains!(public, "posts/python/index.html", ¤t_path("/posts/python/"))); + assert!(file_contains!( + public, + "posts/tutorials/index.html", + ¤t_path("/posts/tutorials/") + )); } #[test] @@ -492,19 +502,28 @@ fn can_build_site_with_pagination_for_index() { "page/1/index.html", "Click here" )); - assert!(file_contains!(public, "index.html", "Num pages: 1")); + assert!(file_contains!(public, "index.html", "Num pages: 2")); assert!(file_contains!(public, "index.html", "Current index: 1")); assert!(file_contains!(public, "index.html", "First: https://replace-this-with-your-url.com/")); - assert!(file_contains!(public, "index.html", "Last: https://replace-this-with-your-url.com/")); + assert!(file_contains!( + public, + "index.html", + "Last: https://replace-this-with-your-url.com/page/2/" + )); assert_eq!(file_contains!(public, "index.html", "has_prev"), false); - assert_eq!(file_contains!(public, "index.html", "has_next"), false); + assert_eq!(file_contains!(public, "index.html", "has_next"), true); // sitemap contains the pager pages assert!(file_contains!( public, "sitemap.xml", "https://replace-this-with-your-url.com/page/1/" - )) + )); + + // current_path + assert!(file_contains!(public, "index.html", ¤t_path("/"))); + assert!(file_contains!(public, "page/2/index.html", ¤t_path("/page/2/"))); + assert!(file_contains!(public, "paginated/index.html", ¤t_path("/paginated/"))); } #[test] @@ -585,7 +604,12 @@ fn can_build_site_with_pagination_for_taxonomy() { public, "sitemap.xml", "https://replace-this-with-your-url.com/tags/a/page/6/" - )) + )); + + // current_path + assert!(file_contains!(public, "tags/index.html", ¤t_path("/tags/"))); + assert!(file_contains!(public, "tags/a/index.html", ¤t_path("/tags/a/"))); + assert!(file_contains!(public, "tags/a/page/2/index.html", ¤t_path("/tags/a/page/2/"))); } #[test] @@ -718,3 +742,8 @@ fn check_site() { site.config.enable_check_mode(); site.load().expect("link check test_site"); } + +// Follows test_site/themes/sample/templates/current_path.html +fn current_path(path: &str) -> String { + format!("[current_path]({})", path) +} diff --git a/docs/content/documentation/templates/overview.md b/docs/content/documentation/templates/overview.md index 2f97a5ce..18a809c3 100644 --- a/docs/content/documentation/templates/overview.md +++ b/docs/content/documentation/templates/overview.md @@ -16,7 +16,7 @@ you can place `{{ __tera_context }}` in the template to print the whole context. A few variables are available on all templates except feeds and the sitemap: - `config`: the [configuration](@/documentation/getting-started/configuration.md) without any modifications -- `current_path`: the path (full URL without `base_url`) of the current page, never starting with a `/` +- `current_path`: the path (full URL without `base_url`) of the current page, always starting with a `/` - `current_url`: the full URL for the current page - `lang`: the language for the current page @@ -165,7 +165,7 @@ Whenever hashing files, whether using `get_file_hash` or `get_url(..., cachebust ### `get_image_metadata` -Gets metadata for an image. This supports common formats like JPEG, PNG, as well as SVG. +Gets metadata for an image. This supports common formats like JPEG, PNG, as well as SVG. Currently, the only supported keys are `width` and `height`. ```jinja2 diff --git a/test_site/content/root-page-1.md b/test_site/content/root-page-1.md new file mode 100644 index 00000000..ac36e062 --- /dev/null +++ b/test_site/content/root-page-1.md @@ -0,0 +1,2 @@ ++++ ++++ diff --git a/test_site/content/root-page-2.md b/test_site/content/root-page-2.md new file mode 100644 index 00000000..ac36e062 --- /dev/null +++ b/test_site/content/root-page-2.md @@ -0,0 +1,2 @@ ++++ ++++ diff --git a/test_site/templates/index_paginated.html b/test_site/templates/index_paginated.html index 851ddb38..fe66d79a 100644 --- a/test_site/templates/index_paginated.html +++ b/test_site/templates/index_paginated.html @@ -29,5 +29,8 @@ {% endblock content %} + + {% include "current_path.html" %} + diff --git a/test_site/templates/tags/list.html b/test_site/templates/tags/list.html index 946e6f10..c13f40fd 100644 --- a/test_site/templates/tags/list.html +++ b/test_site/templates/tags/list.html @@ -1,3 +1,5 @@ {% for tag in terms %} {{ tag.name }} {{ tag.slug }} {{ tag.pages | length }} {% endfor %} + +{% include "current_path.html" %} \ No newline at end of file diff --git a/test_site/templates/tags/single.html b/test_site/templates/tags/single.html index 0c3f8fb8..6e2ffd1b 100644 --- a/test_site/templates/tags/single.html +++ b/test_site/templates/tags/single.html @@ -19,3 +19,5 @@ {% if paginator.previous %}has_prev{% endif%} {% if paginator.next %}has_next{% endif%} {% endif %} + +{% include "current_path.html" %} \ No newline at end of file diff --git a/test_site/themes/sample/templates/current_path.html b/test_site/themes/sample/templates/current_path.html new file mode 100644 index 00000000..fc6c7653 --- /dev/null +++ b/test_site/themes/sample/templates/current_path.html @@ -0,0 +1 @@ +
[current_path]({{ current_path | safe }})
\ No newline at end of file diff --git a/test_site/themes/sample/templates/index.html b/test_site/themes/sample/templates/index.html index a6d721e8..e0a8d28d 100644 --- a/test_site/themes/sample/templates/index.html +++ b/test_site/themes/sample/templates/index.html @@ -16,6 +16,8 @@ {% block content %}Hello{% endblock content %} + {% include "current_path.html" %} + {% block script %} {% endblock script %}