use derive_where::derive_where;
use topcoat::{context::Cx, view::*};
use super::{Column, ColumnBase, ColumnWidth};
use crate::{
Lens,
rich_text::{PROSE, clean, plain_text},
values::FormScalar,
};
#[derive_where(Clone, Debug)]
pub struct RichTextColumn<M, T> {
lens: Lens<M, T>,
base: ColumnBase,
excerpt: usize,
}
impl<M, T> RichTextColumn<M, T>
where
M: toasty::schema::Model,
{
pub fn new(lens: Lens<M, T>) -> Self
where
T: toasty::schema::Field<Inner = String>,
{
Self {
base: ColumnBase::new(lens.path(), ColumnWidth::Grow),
lens,
excerpt: 120,
}
}
pub fn excerpt(mut self, chars: usize) -> Self {
self.excerpt = chars;
self
}
base_builders!();
}
impl<M, T> RichTextColumn<M, T>
where
T: FormScalar,
{
fn html(&self, row: &M) -> String {
clean(&self.lens.read(row).to_form())
}
}
impl<M, T> Column<M> for RichTextColumn<M, T>
where
M: toasty::schema::Model + Send + Sync + 'static,
T: FormScalar + Send + Sync + 'static,
{
base_column_methods!();
fn text(&self, _cx: &Cx, row: &M) -> String {
plain_text(&self.html(row))
}
fn cell<'a>(&self, cx: &'a Cx, row: &M) -> BoxView<'a> {
excerpt_cell(cx, &self.text(cx, row), self.excerpt)
}
fn entry<'a>(&self, cx: &'a Cx, row: &M) -> BoxView<'a> {
entry(cx, &self.label(), self.html(row))
}
}
impl<M, T> crate::column::ColumnInternals<M> for RichTextColumn<M, T>
where
M: toasty::schema::Model + Send + Sync + 'static,
T: FormScalar + Send + Sync + 'static,
{
base_internals!(binding);
}
fn excerpt_cell<'a>(cx: &'a Cx, text: &str, chars: usize) -> BoxView<'a> {
let text = text.replace('\n', " ");
let cut = match text.char_indices().nth(chars) {
Some((at, _)) => format!("{}…", text[..at].trim_end()),
None => text,
};
crate::schema::value_cell(cx, &cut)
}
fn entry<'a>(cx: &'a Cx, label: &crate::Text, html: String) -> BoxView<'a> {
let value = if html.is_empty() {
crate::schema::value_cell(cx, "")
} else {
let html = Unescaped::new_unchecked(html);
view! { <div class=(PROSE) data-rich-text-value="">(html)</div> }.boxed()
};
crate::schema::read_only(cx, label, value)
}