1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
//! This library is designed to provide a simple way to generate HTML documents from within Rust
//! code. To generate documents, this library uses the builder pattern; calls to add elements are
//! repeatedly chained together to dynamically build up an HTML document. The document is then
//! flushed to an HTML string which can be used elsewhere in your program with
//! [`to_html_string()`](Html::to_html_string)
//!
//! # Use
//! Everything you need to use this crate has been exported from the crate root. This means that
//! you can get easy access to every element using the import: `use build_html::*`.
//!
//! If compatibility is important, or you don't need access to every element, you can also import
//! elements piecemeal and prefix types with the package name. Note that the traits `HTML` and
//! `HtmlContainer` must be in scope for the library to be useful:
//! ```
//! use build_html::{self, Html, HtmlContainer};
//!
//! let page = build_html::HtmlPage::new()
//! .with_paragraph("Some Text")
//! .to_html_string();
//! ```
//!
//! Once the package is imported, the [`HtmlPage`] struct will provide the base for most use cases.
//! This struct provides the boilerplate for an HTML5 page, and allows content to be added to it
//! using chained methods.
//!
//! # Example
//!
//! ```rust
//! use build_html::*;
//!
//! let html: String = HtmlPage::new()
//! .with_title("My Page")
//! .with_header(1, "Main Content:")
//! .with_container(
//! Container::new(ContainerType::Article)
//! .with_attributes([("id", "article1")])
//! .with_header_attr(2, "Hello, World", [("id", "article-head")])
//! .with_paragraph("This is a simple HTML demo")
//! )
//! .to_html_string();
//! ```
//!
//! produces a string equivalent to:
//!
//! ```html
//! <!DOCTYPE html>
//! <html>
//! <head>
//! <title>My Page</title>
//! </head>
//! <body>
//! <h1>Main Content:</h1>
//! <article id="article1">
//! <h2 id="article-head">Hello World</h2>
//! <p>This is a simple HTML demo</p>
//! </article>
//! </body>
//! </html>
//! ```
//!
//! # Extensibility
//! The majority of the `add_x` methods specified in [`HtmlContainer`] are defined over generic
//! bounds. This means that they are quite flexibile, and you can pass in almost anything
//! implementing the [`ToString`] trait.
//!
//! In the event that you require additional tags or types not implemented in this library, you
//! can achieve this using one of two escape hatches. For a more structured approach, consider
//! seeing the documentation for [`HtmlContainer::add_html`]. For more one-off situations, consider
//! [`HtmlContainer::add_raw`].
mod attributes;
mod container;
mod content;
mod html_container;
mod html_page;
mod table;
// Exports for the `use build_html::*` syntax
pub use self::container::{Container, ContainerType};
pub use self::html_container::HtmlContainer;
pub use self::html_page::{HtmlPage, HtmlVersion};
pub use self::table::{Table, TableCell, TableCellType, TableRow};
/// An element that can be converted to an HTML string
///
/// This trait is the centerpiece of the entire library: after building up an
/// HTML structure, usually an [`HtmlPage`], [`to_html_string()`](crate::Html::to_html_string)
/// is used to flush the structure to a string.
pub trait Html: std::fmt::Debug {
/// Convert this element into an HTML string
///
/// This is the method that ultimately flushes each HTML object to a string.
///
/// # Example
/// ```
/// # use build_html::*;
/// let html = Container::default()
/// .with_paragraph("My p element")
/// .to_html_string();
///
/// assert_eq!(html, "<div><p>My p element</p></div>");
/// ```
fn to_html_string(&self) -> String;
}
impl std::fmt::Display for dyn Html {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.to_html_string())
}
}
impl Html for String {
fn to_html_string(&self) -> String {
self.clone()
}
}
impl Html for &str {
fn to_html_string(&self) -> String {
self.to_string()
}
}
/// Escape the provided string.
///
/// All HTML tags will be converted to their escaped versions. The output string should be safe to
/// insert into an HTML document. Any embedded HTML tags will be rendered as text. It is important
/// to *always* escape inputs from untrusted sources!
///
/// Implementation note: The list of escaped characters is pulled from [Svelte](https://github.com/sveltejs/svelte/blob/master/src/compiler/compile/utils/stringify.ts#L14).
///
/// # Example
/// ```
/// # use build_html::*;
/// let html = Container::default()
/// .with_paragraph(escape_html("My <p> element!"))
/// .to_html_string();
///
/// assert_eq!(html, "<div><p>My <p> element!</p></div>");
///
/// ```
pub fn escape_html(data: &str) -> String {
let mut escaped = String::with_capacity(data.len());
for c in data.chars() {
match c {
'"' => escaped.push_str("""),
'\'' => escaped.push_str("'"),
'&' => escaped.push_str("&"),
'<' => escaped.push_str("<"),
'>' => escaped.push_str(">"),
x => escaped.push(x),
}
}
escaped
}