use crate::types::HTMLResult;
use crate::{RUMWebRedirect, RUMWebTemplate};
use pulldown_cmark::Options;
use rumtk_core::base::RUMResult;
use rumtk_core::search::rumtk_search::string_replace_all_matches;
use rumtk_core::strings::{
rumtk_format, AsStr, GraphemePatternPair, RUMString,
};
use std::sync::LazyLock;
pub static MARKDOWN_OPTIONS: LazyLock<Options> = LazyLock::new(|| -> Options {
let mut options = Options::empty();
options.insert(Options::ENABLE_STRIKETHROUGH);
options.insert(Options::ENABLE_TASKLISTS);
options.insert(Options::ENABLE_MATH);
options.insert(Options::ENABLE_TABLES);
options.insert(Options::ENABLE_WIKILINKS);
options
}
);
const TEMPLATE_NEWLINE_COMPONENT_PATTERN: GraphemePatternPair<'static> = (&["<"], &[">"]);
const TEMPLATE_NEWLINE_COMPONENT_INNER_PATTERN: GraphemePatternPair<'static> =
(&[">", "\n"], &["<"]);
const TEMPLATE_MIDDLE_REGEX: &str = ">\\s+<";
const TEMPLATE_MIDDLE_REPLACEMENT: &str = "><";
#[derive(RUMWebTemplate)]
#[template(
source = "
{% for element in elements %}
{{ element|safe }}
{% endfor %}
",
ext = "html"
)]
struct ContentBlock<'a> {
elements: &'a [RUMString],
}
#[inline]
pub fn rumtk_web_trim_rendered_html(html: String) -> RUMResult<String> {
let filtered = html.as_grapheme_str()
.trim(&TEMPLATE_NEWLINE_COMPONENT_PATTERN)
.trim(&TEMPLATE_NEWLINE_COMPONENT_PATTERN)
.to_string();
string_replace_all_matches(filtered.as_str(), TEMPLATE_MIDDLE_REGEX, TEMPLATE_MIDDLE_REPLACEMENT)
}
#[inline]
pub fn rumtk_web_post_process(html: String, url: RUMWebRedirect) -> HTMLResult {
let filtered = rumtk_web_trim_rendered_html(html)?;
Ok(url.into_web_response(Some(filtered)))
}
#[inline]
pub fn rumtk_web_render<T: RUMWebTemplate>(template: T, url: RUMWebRedirect) -> HTMLResult {
let result = template.render();
match result {
Ok(html) => {
rumtk_web_post_process(html, url)
}
Err(e) => {
let tn = std::any::type_name::<T>();
Err(rumtk_format!("Template {tn} render failed: {e:?}"))
}
}
}
#[inline]
pub fn rumtk_web_render_contents(elements: &[RUMString]) -> HTMLResult {
rumtk_web_render(ContentBlock { elements }, RUMWebRedirect::None)
}
#[inline]
pub fn rumtk_web_redirect(url: RUMWebRedirect) -> HTMLResult {
Ok(url.into_web_response(Some(String::default())))
}
#[macro_export]
macro_rules! rumtk_web_render_component {
( $component_fxn:expr ) => {{
use $crate::render::rumtk_web_trim_rendered_html;
use rumtk_core::strings::{RUMString, RUMStringConversions};
match $component_fxn() {
Ok(x) => match rumtk_web_trim_rendered_html(x.to_string()) {
Ok(r) => r,
_ => RUMString::default()
},
_ => RUMString::default(),
}
}};
( $component_fxn:expr, $app_state:expr ) => {{
use $crate::render::rumtk_web_trim_rendered_html;
use rumtk_core::strings::{RUMString, RUMStringConversions};
match $component_fxn($app_state.clone()) {
Ok(x) => match rumtk_web_trim_rendered_html(x.to_string()) {
Ok(r) => r,
_ => RUMString::default()
},
_ => RUMString::default(),
}
}};
( $component:expr, $params:expr, $app_state:expr ) => {{
rumtk_web_render_component!($component, &[""], $params, $app_state)
}};
( $component:expr, $path:expr, $params:expr, $app_state:expr ) => {{
use $crate::components::html::div;
use $crate::render::rumtk_web_trim_rendered_html;
use $crate::{rumtk_web_get_component, rumtk_web_params_map};
let params = rumtk_web_params_map!($params);
match rumtk_web_get_component!($component) {
Some(component) => match component($path, params.get_inner(), $app_state.clone()){
Ok(x) => match rumtk_web_trim_rendered_html(x.to_string()) {
Ok(r) => r,
_ => RUMString::default()
},
_ => RUMString::default(),
},
None => div($path, params.get_inner(), $app_state.clone()) {
Ok(x) => match rumtk_web_trim_rendered_html(x.to_string()) {
Ok(r) => r,
_ => RUMString::default()
},
_ => RUMString::default(),
}
}
}};
}
#[macro_export]
macro_rules! rumtk_web_render_template {
( $page:expr ) => {{
use $crate::utils::{rumtk_web_render, RUMWebRedirect};
rumtk_web_render($page, RUMWebRedirect::None)
}};
( $page:expr, $redirect_url:expr ) => {{
use $crate::utils::rumtk_web_render;
rumtk_web_render($page, $redirect_url)
}};
}
#[macro_export]
macro_rules! rumtk_web_post_process_html {
( $html:expr ) => {{
use rumtk_core::strings::{RUMStringConversions};
use $crate::utils::{rumtk_web_post_process, RUMWebRedirect};
rumtk_web_post_process($html.to_string(), RUMWebRedirect::None)
}};
( $html:expr, $redirect_url:expr ) => {{
use rumtk_core::strings::{RUMStringConversions};
use $crate::utils::rumtk_web_post_process;
rumtk_web_post_process($html.to_string(), $redirect_url)
}};
}
#[macro_export]
macro_rules! rumtk_web_render_page_contents {
( $page_elements:expr ) => {{
use $crate::utils::rumtk_web_render_contents;
rumtk_web_render_contents($page_elements)
}};
}
#[macro_export]
macro_rules! rumtk_web_render_redirect {
( $url:expr ) => {{
use $crate::utils::rumtk_web_redirect;
rumtk_web_redirect($url)
}};
}
#[macro_export]
macro_rules! rumtk_web_render_markdown {
( $md:expr ) => {{
use pulldown_cmark::{Options, Parser};
use rumtk_core::strings::RUMStringConversions;
use $crate::utils::render::{MARKDOWN_OPTIONS};
let input = String::from($md);
let parser = Parser::new_ext(&input, unsafe {(*MARKDOWN_OPTIONS).clone()});
let mut html_output = String::new();
pulldown_cmark::html::push_html(&mut html_output, parser);
html_output.to_string()
}};
}