Add a prefix to footnote IDs.
This avoids a conflict with multiple blog posts rendering in the same stream.
This commit is contained in:
		
							parent
							
								
									d4b290ebe6
								
							
						
					
					
						commit
						2e1c979127
					
				| @ -85,6 +85,7 @@ impl SiteRenderer { | ||||
|                     config, | ||||
|                     self.output_directory.as_path(), | ||||
|                     output_path.as_path(), | ||||
|                     None, | ||||
|                 )?; | ||||
|                 let render_context = RenderBlogPostPage::new(render_context, &convert_input)?; | ||||
|                 let rendered_output = renderer_integration.render(render_context)?; | ||||
| @ -165,6 +166,7 @@ impl SiteRenderer { | ||||
|                 config, | ||||
|                 self.output_directory.as_path(), | ||||
|                 output_file.as_path(), | ||||
|                 None, | ||||
|             )?; | ||||
|             let blog_stream = RenderBlogStream::new(render_context, &convert_input)?; | ||||
| 
 | ||||
|  | ||||
| @ -86,7 +86,13 @@ render!( | ||||
|         let children = original | ||||
|             .original | ||||
|             .into_iter() | ||||
|             .map(|blog_post| RenderBlogStreamEntry::new(render_context.clone(), blog_post)) | ||||
|             .enumerate() | ||||
|             .map(|(i, blog_post)| { | ||||
|                 RenderBlogStreamEntry::new( | ||||
|                     render_context.clone(), | ||||
|                     &RenderBlogStreamEntryInput::new(blog_post, i), | ||||
|                 ) | ||||
|             }) | ||||
|             .collect::<Result<Vec<_>, _>>()?; | ||||
| 
 | ||||
|         let stream_pagination = if original.older_link.is_some() || original.newer_link.is_some() { | ||||
| @ -107,6 +113,18 @@ render!( | ||||
|     } | ||||
| ); | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub(crate) struct RenderBlogStreamEntryInput<'a> { | ||||
|     original: &'a BlogPost, | ||||
|     offset: usize, | ||||
| } | ||||
| 
 | ||||
| impl<'a> RenderBlogStreamEntryInput<'a> { | ||||
|     fn new(original: &'a BlogPost, offset: usize) -> RenderBlogStreamEntryInput<'a> { | ||||
|         RenderBlogStreamEntryInput { original, offset } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Serialize)] | ||||
| pub(crate) struct RenderBlogStreamEntry { | ||||
|     /// The title that will be shown visibly on the page.
 | ||||
| @ -119,37 +137,62 @@ pub(crate) struct RenderBlogStreamEntry { | ||||
|     footnotes: Vec<RenderRealFootnoteDefinition>, | ||||
| } | ||||
| 
 | ||||
| render!(RenderBlogStreamEntry, BlogPost, original, render_context, { | ||||
|     let link_to_blog_post = get_web_path( | ||||
|         render_context.config, | ||||
|         render_context.output_directory, | ||||
|         render_context.output_file, | ||||
|         render_context | ||||
|             .config | ||||
|             .get_relative_path_to_post(&original.id), | ||||
|     )?; | ||||
| render!( | ||||
|     RenderBlogStreamEntry, | ||||
|     RenderBlogStreamEntryInput, | ||||
|     original, | ||||
|     render_context, | ||||
|     { | ||||
|         let offset_string = original.offset.to_string(); | ||||
|         let render_context = { | ||||
|             let mut render_context = render_context.clone(); | ||||
|             render_context.id_addition = Some(offset_string.as_str()); | ||||
|             render_context | ||||
|         }; | ||||
|         let link_to_blog_post = get_web_path( | ||||
|             render_context.config, | ||||
|             render_context.output_directory, | ||||
|             render_context.output_file, | ||||
|             render_context | ||||
|                 .config | ||||
|                 .get_relative_path_to_post(&original.original.id), | ||||
|         )?; | ||||
| 
 | ||||
|     // TODO: Should I guess an index page instead of erroring out?
 | ||||
|     let index_page = original | ||||
|         .get_index_page() | ||||
|         .ok_or_else(|| format!("Blog post {} needs an index page.", original.id))?; | ||||
|         // TODO: Should I guess an index page instead of erroring out?
 | ||||
|         let index_page = original | ||||
|             .original | ||||
|             .get_index_page() | ||||
|             .ok_or_else(|| format!("Blog post {} needs an index page.", original.original.id))?; | ||||
| 
 | ||||
|     let title = index_page.title.clone(); | ||||
|         let title = index_page.title.clone(); | ||||
| 
 | ||||
|     // TODO: Handle footnotes.
 | ||||
|     let children = index_page | ||||
|         .children | ||||
|         .iter() | ||||
|         .map(|child| RenderDocumentElement::new(render_context.clone(), child)) | ||||
|         .collect::<Result<Vec<_>, _>>()?; | ||||
|         let children = index_page | ||||
|             .children | ||||
|             .iter() | ||||
|             .map(|child| RenderDocumentElement::new(render_context.clone(), child)) | ||||
|             .collect::<Result<Vec<_>, _>>()?; | ||||
| 
 | ||||
|     Ok(RenderBlogStreamEntry { | ||||
|         title, | ||||
|         self_link: Some(link_to_blog_post), | ||||
|         children, | ||||
|         footnotes: Vec::new(), | ||||
|     }) | ||||
| }); | ||||
|         let footnotes = { | ||||
|             let mut ret = Vec::new(); | ||||
| 
 | ||||
|             for footnote in index_page.footnotes.iter() { | ||||
|                 ret.push(RenderRealFootnoteDefinition::new( | ||||
|                     render_context.clone(), | ||||
|                     footnote, | ||||
|                 )?); | ||||
|             } | ||||
| 
 | ||||
|             ret | ||||
|         }; | ||||
| 
 | ||||
|         Ok(RenderBlogStreamEntry { | ||||
|             title, | ||||
|             self_link: Some(link_to_blog_post), | ||||
|             children, | ||||
|             footnotes, | ||||
|         }) | ||||
|     } | ||||
| ); | ||||
| 
 | ||||
| #[derive(Debug, Serialize)] | ||||
| pub(crate) struct RenderBlogStreamPagination { | ||||
|  | ||||
| @ -42,8 +42,8 @@ render!( | ||||
|         }; | ||||
| 
 | ||||
|         Ok(RenderRealFootnoteDefinition { | ||||
|             definition_id: original.get_definition_id(), | ||||
|             reference_link: format!("#{}", original.get_reference_id()), | ||||
|             definition_id: original.get_definition_id(render_context.id_addition), | ||||
|             reference_link: format!("#{}", original.get_reference_id(render_context.id_addition)), | ||||
|             label: original.get_display_label(), | ||||
|             contents, | ||||
|         }) | ||||
|  | ||||
| @ -19,11 +19,14 @@ render!( | ||||
|     RenderFootnoteReference, | ||||
|     IFootnoteReference, | ||||
|     original, | ||||
|     _render_context, | ||||
|     render_context, | ||||
|     { | ||||
|         Ok(RenderFootnoteReference { | ||||
|             reference_id: original.get_reference_id(), | ||||
|             definition_link: format!("#{}", original.get_definition_id()), | ||||
|             reference_id: original.get_reference_id(render_context.id_addition), | ||||
|             definition_link: format!( | ||||
|                 "#{}", | ||||
|                 original.get_definition_id(render_context.id_addition) | ||||
|             ), | ||||
|             label: original.get_display_label(), | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @ -10,6 +10,13 @@ pub(crate) struct RenderContext<'intermediate> { | ||||
|     // TODO: Perhaps rename to output_root_directory.
 | ||||
|     pub(crate) output_directory: &'intermediate Path, | ||||
|     pub(crate) output_file: &'intermediate Path, | ||||
| 
 | ||||
|     /// An optional string that gets added to IDs in HTML.
 | ||||
|     ///
 | ||||
|     /// This is useful for cases where you may have conflicting HTML
 | ||||
|     /// IDs, for example, multiple blog posts with footnotes in a blog
 | ||||
|     /// stream.
 | ||||
|     pub(crate) id_addition: Option<&'intermediate str>, | ||||
| } | ||||
| 
 | ||||
| impl<'intermediate> RenderContext<'intermediate> { | ||||
| @ -17,11 +24,13 @@ impl<'intermediate> RenderContext<'intermediate> { | ||||
|         config: &'intermediate Config, | ||||
|         output_directory: &'intermediate Path, | ||||
|         output_file: &'intermediate Path, | ||||
|         id_addition: Option<&'intermediate str>, | ||||
|     ) -> Result<RenderContext<'intermediate>, CustomError> { | ||||
|         Ok(RenderContext { | ||||
|             config, | ||||
|             output_directory, | ||||
|             output_file, | ||||
|             id_addition, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -44,14 +44,22 @@ impl IRealFootnoteDefinition { | ||||
|     /// Get an ID to refer to the first reference to this footnote definition.
 | ||||
|     ///
 | ||||
|     /// This ID could, for example, be used for the id attribute in HTML for the reference anchor tag.
 | ||||
|     pub(crate) fn get_reference_id(&self) -> String { | ||||
|         format!("fnr.{}", self.get_display_label()) | ||||
|     pub(crate) fn get_reference_id(&self, id_addition: Option<&str>) -> String { | ||||
|         let id_addition = id_addition | ||||
|             .map(|id_addition| format!("sec{}.", id_addition)) | ||||
|             .unwrap_or(String::default()); | ||||
| 
 | ||||
|         format!("{}fnr.{}", id_addition, self.get_display_label()) | ||||
|     } | ||||
| 
 | ||||
|     /// Get an ID to refer to the footnote definition.
 | ||||
|     ///
 | ||||
|     /// This ID could, for example, be used for the id attribute in HTML for the definition anchor tag.
 | ||||
|     pub(crate) fn get_definition_id(&self) -> String { | ||||
|         format!("fn.{}", self.get_display_label()) | ||||
|     pub(crate) fn get_definition_id(&self, id_addition: Option<&str>) -> String { | ||||
|         let id_addition = id_addition | ||||
|             .map(|id_addition| format!("sec{}.", id_addition)) | ||||
|             .unwrap_or(String::default()); | ||||
| 
 | ||||
|         format!("{}fn.{}", id_addition, self.get_display_label()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -32,20 +32,28 @@ impl IFootnoteReference { | ||||
|     /// Get an ID to refer to this footnote reference.
 | ||||
|     ///
 | ||||
|     /// This ID could, for example, be used for the id attribute in HTML for the reference anchor tag.
 | ||||
|     pub(crate) fn get_reference_id(&self) -> String { | ||||
|     pub(crate) fn get_reference_id(&self, id_addition: Option<&str>) -> String { | ||||
|         let id_addition = id_addition | ||||
|             .map(|id_addition| format!("sec{}.", id_addition)) | ||||
|             .unwrap_or(String::default()); | ||||
| 
 | ||||
|         if self.duplicate_offset == 0 { | ||||
|             format!("fnr.{}", self.get_display_label()) | ||||
|             format!("{}fnr.{}", id_addition, self.get_display_label()) | ||||
|         } else { | ||||
|             // Org-mode makes all duplicates use "100" but I figure there is no harm in giving each a unique ID.
 | ||||
|             let append = 100 + self.duplicate_offset - 1; | ||||
|             format!("fnr.{}.{}", self.get_display_label(), append) | ||||
|             format!("{}fnr.{}.{}", id_addition, self.get_display_label(), append) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Get an ID to refer to the footnote definition this footnote reference references.
 | ||||
|     ///
 | ||||
|     /// This ID could, for example, be used for the id attribute in HTML for the definition anchor tag.
 | ||||
|     pub(crate) fn get_definition_id(&self) -> String { | ||||
|         format!("fn.{}", self.get_display_label()) | ||||
|     pub(crate) fn get_definition_id(&self, id_addition: Option<&str>) -> String { | ||||
|         let id_addition = id_addition | ||||
|             .map(|id_addition| format!("sec{}.", id_addition)) | ||||
|             .unwrap_or(String::default()); | ||||
| 
 | ||||
|         format!("{}fn.{}", id_addition, self.get_display_label()) | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Tom Alexander
						Tom Alexander