rustyphoenixlecture 1.5.0

This project aims to provide a simple a powerfull lecture compilation to generate html web sites
/***************************************
	Auteur : Pierre Aubert
	Mail : pierre.aubert@lapp.in2p3.fr
	Licence : CeCILL-C
****************************************/

use std::path::PathBuf;

use crate::phighlighter::PLocation;
use crate::pcontent::{
	PAbstractContent,
	PAbstractLectureBackend,
	PLabelId,
	PLabeler,
	PContentTitle,
	PContentText,
	PContentType,
	PVecContent
};

///Menu of the full lecture
#[derive(Debug)]
pub struct PLectureMenu{
	///True if the current menu has to be expanded, false otherwise
	p_is_expanded: bool,
	///True if the current menu was the first which has to be expanded, false otherwise
	p_is_first_expanded: bool ,
	///Title of the current menu
	p_title: PLabeler<PContentTitle>,
	///Vector of sub menu of the current menu
	p_vec_child: Vec<PLectureMenu>,
}

impl PLectureMenu {
	///Constructor of a PLectureMenu
	/// # Parameters
	/// - `title` : title to put in the PLectureMenu
	/// # Returns
	/// Initialised PLectureMenu
	pub fn new(title: &PLabeler<PContentTitle>) -> Self {
		PLectureMenu {
			p_is_expanded: false,
			p_is_first_expanded: false,
			p_title: title.clone(),
			p_vec_child: vec![]
		}
	}
	///Create a PLectureMenu from a PVecContent
	/// # Parameters
	/// - `vec_content` : PVecContent to be used to build the PLectureMenu
	/// # Returns
	/// Initialised PLectureMenu
	pub fn from(vec_content: &PVecContent) -> Self {
		let mut main_title = PContentTitle::new(0, false, &PLocation::new(&PathBuf::from("index.md"), 1, 1));
		main_title.get_title_mut().add_child(&PContentType::Text(PLabeler::new(0, &PContentText::new(&String::from("Main Page")))));
		let mut other = PLectureMenu::new(&PLabeler::new(0, &main_title));
		for content in vec_content.get_vec_child().iter(){
			match content {
				PContentType::Title(title) => {
					if title.get_data().is_enumerated() {
						other.add_child(title);
					}
				},
				_ => {}	//We just skip everything which is not a Title
			}
		}
		return other;
	}
	///Add a children to the current PLectureMenu
	/// # Parameters
	/// - `title` : PContentTitle to be added to the current PLectureMenu
	fn add_child(&mut self, title: &PLabeler<PContentTitle>){
		let title_level: usize = title.get_data().get_level();
		//Let's get the level of the last child
		match self.p_vec_child.last_mut() {
			Some(child) => {
				//If the child has a lower level, we add the title in the child
				if child.p_title.get_data().get_level() < title_level {
					child.add_child(title);
				}else{
					//If the child has a level greater or equal, we add the title into the current PLectureMenu
					self.p_vec_child.push(PLectureMenu::new(title))
				}
			},
			None => self.p_vec_child.push(PLectureMenu::new(title)),	//The menu is empty, we add a child
		};
	}
	///Convert the current struct into html
	/// # Parameters
	/// - `backend` : backend which write a lecture in files
	/// - `current_link` : link of the current menu
	pub fn to_html<TLectureBackend>(&mut self, backend: &mut TLectureBackend, current_link: &String)
		where TLectureBackend: PAbstractLectureBackend
	{
		self.update_expanded(current_link);
		let indentation = String::from("\t\t");
		backend.write(&format!("{}<nav id=\"sidebar\" class=\"sidebar\" aria-label=\"Table of contents\">\n", indentation));
		backend.write(&format!("{}\t<div class=\"sidebar-scrollbox\">\n", indentation));
		backend.write(&format!("{}\t\t<ol class=\"chapter\">\n", indentation));
		backend.write(&format!("{}\t\t\t<li class=\"chapter-item \"><a href=\"index.html\">Main Page</a></li>\n", indentation));
		let child_indentation: String = String::from(format!("\t\t\t{}", indentation));
		for submenu in self.p_vec_child.iter() {
			submenu.to_html_sub_menu(backend, &child_indentation);
		}
		//TODO : if there is a bibliography
		// backend.write(&format!("{}\t\t\t<li class=\"chapter-item \"><a href=\"bibliography.html\">Bibliography</a></li>\n", indentation));
		backend.write(&format!("{}\t\t</ol>\n", indentation));
		backend.write(&format!("{}\t</div>\n", indentation));
		backend.write(&format!("{}\t<div id=\"sidebar-resize-handle\" class=\"sidebar-resize-handle\"></div>\n", indentation));
		backend.write(&format!("{}</nav>\n", indentation));
	}
	///Convert the current struct into html (only sub menu)
	/// # Parameters
	/// - `backend` : backend which write a lecture in files
	/// - `indentation` : display indentation
	fn to_html_sub_menu<TLectureBackend>(&self, backend: &mut TLectureBackend, indentation: &String)
		where TLectureBackend: PAbstractLectureBackend
	{
		//TODO : maybe we will have to take account separator later
		backend.write(&format!("{}<li class=\"chapter-item ", indentation));
		if self.p_is_expanded {
			backend.write(&String::from("expanded"));
			if self.p_is_first_expanded {
				backend.write(&String::from(" active"));
			}
		}
		//The output filename of the PContentTitle is relative and not absolute
		backend.write(&format!("\"><a href=\"{}\">", self.p_title.get_data().get_output_filename()));
		let mut str_title_number = self.p_title.get_data().get_str_title_number().clone();
		if !str_title_number.is_empty() {
			str_title_number += &String::from(" ");
		}
		backend.write(&str_title_number);
		self.p_title.get_data().get_title().to_html(backend, &PLabelId::new(0));
		backend.write(&String::from("</a>"));
		
		if self.p_vec_child.len() != 0 {	//Let's write the opening menu
			backend.write(&String::from("<a class=\"toggle\"><div>❱</div></a></li>\n"));
			//And now all children of the menu
			backend.write(&format!("{}<li>\n", indentation));
			backend.write(&format!("{}\t<ol class=\"section\">\n", indentation));
			let sub_indentation = String::from(format!("{}\t\t", indentation));
			for child in self.p_vec_child.iter() {
				child.to_html_sub_menu(backend, &sub_indentation);
			}
			backend.write(&format!("{}\t</ol>\n", indentation));
			backend.write(&format!("{}</li>\n", indentation));
		}else{
			backend.write(&String::from("</li>\n"));
		}
	}
	///Update the expanded menu attribute
	/// # Parameters
	/// - `current_link` : current link of the visited page
	fn update_expanded(&mut self, current_link: &String){
		self.p_is_first_expanded = current_link == self.p_title.get_data().get_output_filename();
		let mut is_extended = self.p_is_first_expanded;
		//TODO : update is_expanded stuff
		for child in self.p_vec_child.iter_mut(){
			if is_extended {	//If a previous menu is extended, no need to search for an other
				break;
			}
			child.update_expanded(current_link);
			is_extended = child.p_is_expanded;
		}
		self.p_is_expanded = is_extended;
	}
}