Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
Commit 27248073 authored by Pierre Jarriges's avatar Pierre Jarriges
Browse files

page build meta fields

parent e5702b36
No related branches found
No related tags found
No related merge requests found
......@@ -31,23 +31,6 @@
],
"sub_pages": []
},
"assets_index": {
"images": [
"/static/images/toto.jpg"
],
"sounds": [
"/static/sounds/toto.mp3"
],
"video": [
"/static/video/toto.mp4"
],
"docs": [
"/static/docs/toto.xcf"
],
"source_code": [
"/static/source_code/toto.js"
]
},
"templates": [
{
"name": "Pijar Custom template",
......@@ -79,5 +62,22 @@
}
]
}
]
],
"assets_index": {
"images": [
"/static/images/toto.jpg"
],
"sounds": [
"/static/sounds/toto.mp3"
],
"video": [
"/static/video/toto.mp4"
],
"docs": [
"/static/docs/toto.xcf"
],
"source_code": [
"/static/source_code/toto.js"
]
}
}
\ No newline at end of file
......@@ -24,7 +24,7 @@ impl StaticFilesManager {
if !static_dir.exists() {
match std::fs::create_dir_all(&static_dir) {
Ok(_) => {
if let Err(err) = Self::copy_default(&static_dir) {
if let Err(err) = Self::copy_default_files(&static_dir) {
return Err(format!("{}", err));
}
}
......@@ -35,19 +35,15 @@ impl StaticFilesManager {
Ok(static_dir)
}
fn copy_default(static_dir: &PathBuf) -> Result<(), String> {
fn copy_default_files(static_dir: &PathBuf) -> Result<(), String> {
let local_default_static = std::env::current_dir().unwrap().join("default_static");
let default_static = static_dir.join("default");
match std::fs::create_dir_all(&default_static) {
Err(err) => Err(format!("{}", err)),
Ok(_) => {
let mut copy_default_options = fs_extra::dir::CopyOptions::new();
copy_default_options.content_only = true;
match fs_extra::dir::copy(
local_default_static,
default_static,
&copy_default_options,
) {
let mut cpy_options = fs_extra::dir::CopyOptions::new();
cpy_options.content_only = true;
match fs_extra::dir::copy(local_default_static, default_static, &cpy_options) {
Err(err) => Err(format!("{}", err)),
Ok(_) => Ok(()),
}
......
......@@ -6,7 +6,7 @@ pub const TEST_JSON_WEBSITE: &'static str = "
\"metadata\": {
\"title\": \"TEST\",
\"description\": \"TEST DESCRIPTION\",
\"image\": \"https://test/static/images/test.png\",
\"image\": [\"https://test/static/images/test.png\"],
\"css\": [],
\"lang\":\"en\",
\"js\": [],
......@@ -24,7 +24,7 @@ pub const TEST_JSON_WEBSITE: &'static str = "
\"metadata\": {
\"title\": \"TEST SUBPAGE\",
\"description\": \"TEST DESCRIPTION SUBPAGE\",
\"image\": \"https://test/static/images/test.png\",
\"image\": [\"https://test/static/images/test.png\"],
\"css\": [],
\"lang\":\"en\",
\"js\": [],
......@@ -40,9 +40,9 @@ pub const TEST_JSON_WEBSITE: &'static str = "
{
\"template_name\": \"TEST TEMPLATE\",
\"metadata\": {
\"title\": \"TEST NESTTED\",
\"title\": \"TEST NESTED\",
\"description\": \"TEST DESCRIPTION NESTED\",
\"image\": \"https://test/static/images/test.png\",
\"image\": [\"https://test/static/images/test.png\"],
\"css\": [],
\"js\": [],
\"url_slug\": \"nested\",
......
......@@ -5,14 +5,23 @@ use std::collections::HashMap;
pub const CSS_LINK_FRAGMENT: &'static str = "<link rel='stylesheet' href='{url}'>";
pub const SCRIPT_FRAGMENT: &'static str = "<script src='{url}'></script>";
pub const FAVICON_LINK_FRAGMENT: &'static str = "<link rel='icon' type='image/*' href='{url}'/>";
pub const IMAGE_LINKS_FRAGMENT: &'static str = "<meta name='image' content='{url}'/>
<meta property='og:image' content='{url}'/>
<meta property='twitter:image' content='{url}'/>";
const HTML_DOC_TEMPLATE: &'static str = "
<html lang='{lang}'>
<html lang='{lang}' prefix='og: https://ogp.me/ns#'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<meta name='description' content='{description}'>
<meta name='author' content='{author}'>
<meta property='og:title' content='{title}'/>
<meta property='og:description' content='{description}'/>
{image}
<title>{title}</title>
{css}
</head>
......@@ -20,9 +29,7 @@ const HTML_DOC_TEMPLATE: &'static str = "
<body>
{body}
</body>
{js}
</html>
";
......
use super::css::StyleSheet;
use super::html::{replace_placeholders, HtmlDoc, HtmlElement, CSS_LINK_FRAGMENT, SCRIPT_FRAGMENT};
use super::html::{
replace_placeholders, HtmlDoc, HtmlElement, CSS_LINK_FRAGMENT, FAVICON_LINK_FRAGMENT,
IMAGE_LINKS_FRAGMENT, SCRIPT_FRAGMENT,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
......@@ -50,6 +53,35 @@ pub struct PageMetadata {
pub css: CSSLinks,
#[serde(default = "JSLinks::new")]
pub js: JSLinks,
#[serde(default = "FaviconLink::new")]
pub favicon: FaviconLink,
#[serde(default = "String::new")]
pub author: String,
#[serde(default = "ImageLinks::new")]
pub image: ImageLinks,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct FaviconLink(String);
impl FaviconLink {
pub fn new() -> Self {
FaviconLink(String::from("/static/default/favicon.ico"))
}
}
impl std::fmt::Display for FaviconLink {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
replace_placeholders(FAVICON_LINK_FRAGMENT, {
let mut map = HashMap::new();
map.insert("url".to_owned(), self.0.to_owned());
map
})
)
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
......@@ -75,7 +107,7 @@ impl std::fmt::Display for CSSLinks {
map
}))
.collect::<Vec<String>>()
.join("")
.join("\n")
)
}
}
......@@ -103,7 +135,35 @@ impl std::fmt::Display for JSLinks {
map
}))
.collect::<Vec<String>>()
.join("")
.join("\n")
)
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ImageLinks(Vec<String>);
impl ImageLinks {
pub fn new() -> Self {
ImageLinks(vec![])
}
}
impl std::fmt::Display for ImageLinks {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
&self
.0
.iter()
.map(|url| replace_placeholders(IMAGE_LINKS_FRAGMENT, {
let mut map = HashMap::new();
map.insert("url".to_string(), url.to_owned());
map
}))
.collect::<Vec<String>>()
.join("\n")
)
}
}
......@@ -113,20 +173,19 @@ impl Page {
self.html = HtmlDoc::from_page(self);
}
pub fn build_body_template(&mut self, template: PageTemplate) {
pub fn build_with_template(&mut self, template: PageTemplate) {
let mut complete_body = template.clone();
self.template = Some(template);
let err = "Couldn't find page-body placeholder";
// Insert page body inside the template page-body container.
// Then replace the page body by the complete template
complete_body
.contents
.iter_mut()
.find(|el| el.attrs.get("id").unwrap_or(&String::new()).eq("page-body"))
.expect(err)
.set_contents(self.body.0.clone());
// Then replace the page body by the complete template
self.body.0 = complete_body.contents;
}
......@@ -142,7 +201,160 @@ impl Page {
map.insert("body".to_string(), self.body.to_string());
map.insert("css".to_string(), self.metadata.css.to_string());
map.insert("js".to_string(), self.metadata.js.to_string());
map.insert("author".to_string(), self.metadata.author.to_string());
map.insert("image".to_string(), self.metadata.image.to_string());
map
}
}
#[cfg(test)]
mod test_pages {
use super::*;
use crate::website::html::{HtmlAttributes, HtmlElement};
fn test_page_metadata() -> PageMetadata {
PageMetadata {
title: String::from("Test"),
lang: String::from("en"),
description: String::from("test descr"),
url_slug: String::from("test-page"),
css: CSSLinks(vec![
"/static/source_code/mystyle.css".to_string(),
"/static/source_code/mystyle2.css".to_string(),
]),
js: JSLinks(vec![
"/static/source_code/myscript.js".to_string(),
"/static/source_code/myscript2.js".to_string(),
]),
favicon: FaviconLink(String::from("/static/images/testicon.ico")),
author: String::from("test author"),
image: ImageLinks(vec![
"/static/images/testimage.png".to_string(),
"/static/images/testimage2.png".to_string(),
]),
}
}
fn test_page_template() -> PageTemplate {
PageTemplate {
layout: StyleSheet(HashMap::new()),
name: String::from("test template"),
contents: vec![
HtmlElement {
tag: String::from("nav"),
attrs: HtmlAttributes::new(),
contents: None,
text: Some(String::from("NAV")),
},
HtmlElement {
tag: String::from("div"),
attrs: {
let mut attrs = HtmlAttributes::new();
attrs
.0
.insert(String::from("id"), String::from("page-body"));
attrs
},
contents: None,
text: None,
},
HtmlElement {
tag: String::from("footer"),
attrs: HtmlAttributes::new(),
contents: None,
text: Some(String::from("FOOTER")),
},
],
}
}
fn test_page() -> Page {
Page {
template_name: String::from("test template"),
body: PageBody(vec![HtmlElement {
tag: "span".to_string(),
text: Some("TEST".to_string()),
contents: None,
attrs: HtmlAttributes::new(),
}]),
metadata: test_page_metadata(),
sub_pages: Vec::new(),
html: HtmlDoc::new(),
template: None,
}
}
#[test]
fn page_body_to_string() {
let body = PageBody(vec![
HtmlElement {
tag: "span".to_string(),
text: Some("Hello ".to_string()),
contents: None,
attrs: HtmlAttributes::new(),
},
HtmlElement {
tag: "span".to_string(),
text: Some("World!".to_string()),
contents: None,
attrs: HtmlAttributes::new(),
},
]);
assert_eq!(body.to_string(), "<span>Hello </span><span>World!</span>");
}
#[test]
fn favicon_link_to_string() {
let pmd = test_page_metadata();
assert_eq!(
pmd.favicon.to_string(),
"<link rel='icon' type='image/*' href='/static/images/testicon.ico'/>"
)
}
#[test]
fn css_links_to_string() {
let pmd = test_page_metadata();
assert_eq!(
pmd.css.to_string(),
"<link rel='stylesheet' href='/static/source_code/mystyle.css'>
<link rel='stylesheet' href='/static/source_code/mystyle2.css'>"
)
}
#[test]
fn js_links_to_string() {
let pmd = test_page_metadata();
assert_eq!(
pmd.js.to_string(),
"<script src='/static/source_code/myscript.js'></script>
<script src='/static/source_code/myscript2.js'></script>"
)
}
#[test]
fn images_links_to_string() {
let pmd = test_page_metadata();
assert_eq!(
pmd.image.to_string(),
"<meta name='image' content='/static/images/testimage.png'/>
<meta property='og:image' content='/static/images/testimage.png'/>
<meta property='twitter:image' content='/static/images/testimage.png'/>
<meta name='image' content='/static/images/testimage2.png'/>
<meta property='og:image' content='/static/images/testimage2.png'/>
<meta property='twitter:image' content='/static/images/testimage2.png'/>"
)
}
#[test]
fn build_body_with_template() {
let mut page = test_page();
page.build_with_template(test_page_template());
assert_eq!(
page.body.to_string(),
"<nav>NAV</nav><div id=\"page-body\"><span>TEST</span></div><footer>FOOTER</footer>"
)
}
}
......@@ -39,7 +39,7 @@ impl WebSite {
pub fn from_json(json: &str) -> Self {
let mut obj: WebSite = serde_json::from_str(json).unwrap();
obj.root_page.build_body_template(
obj.root_page.build_with_template(
obj.templates
.iter()
.find(|t| t.name == obj.root_page.template_name)
......@@ -50,7 +50,7 @@ impl WebSite {
obj.root_page.build_html();
for p in obj.root_page.sub_pages.iter_mut() {
p.build_body_template(
p.build_with_template(
obj.templates
.iter()
.find(|t| t.name == p.template_name)
......@@ -107,17 +107,14 @@ mod test_website {
let website = WebSite::from_json(TEST_JSON_WEBSITE);
let root_page = website.get_page_by_url(&PathBuf::from("/"));
assert!(root_page.is_some());
let root_page = root_page.unwrap();
assert_eq!(format!("{}", root_page.body), "<h1>testing</h1>");
assert_eq!(root_page.unwrap().metadata.title, "TEST");
let sub_page = website.get_page_by_url(&PathBuf::from("subpage"));
assert!(sub_page.is_some());
let sub_page = sub_page.unwrap();
assert_eq!(format!("{}", sub_page.body), "<h1>testing subpage</h1>");
assert_eq!(sub_page.unwrap().metadata.title, "TEST SUBPAGE");
let nested_page = website.get_page_by_url(&PathBuf::from("subpage/nested"));
assert!(nested_page.is_some());
let nested_page = nested_page.unwrap();
assert_eq!(format!("{}", nested_page.body), "<h1>testing nested</h1>");
assert_eq!(nested_page.unwrap().metadata.title, "TEST NESTED");
}
}
......@@ -4,9 +4,11 @@
"metadata": {
"title": "New Website",
"description": "A new website",
"image": "",
"url_slug": "",
"lang": "en"
"lang": "en",
"image": [
"https://example.com/image.png"
]
},
"body": [
{
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment