///|
fn html_escape(text : String) -> String {
let out = StringBuilder()
for c in text.iter() {
match c {
'&' => out.write_string("&")
'<' => out.write_string("<")
'>' => out.write_string(">")
'"' => out.write_string(""")
'\'' => out.write_string("'")
'\n' => out.write_string("
\n")
'\t' => out.write_string(" ")
_ => out.write_char(c)
}
}
out.to_string()
}
///|
fn css_color(color : Color) -> String {
"rgb(\{color.red.max(0).min(255)},\{color.green.max(0).min(255)},\{color.blue.max(0).min(255)})"
}
///|
fn Document::html_run(self : Document, run : Run) -> String {
let out = StringBuilder()
let css = StringBuilder()
let style = run.style
if style.foreground > 0 {
if self.colors.get(style.foreground) is Some(color) && !color.automatic {
css.write_string("color:\{css_color(color)};")
}
}
if style.background > 0 {
if self.colors.get(style.background) is Some(color) && !color.automatic {
css.write_string("background-color:\{css_color(color)};")
}
}
if style.size_half_points > 0 && style.size_half_points <= 32767 {
let whole = style.size_half_points / 2
let half = if style.size_half_points % 2 == 0 { "" } else { ".5" }
css.write_string("font-size:\{whole}\{half}pt;")
}
let linked = match run.link {
Some(target) => safe_link(target)
None => false
}
if linked {
out.write_string(
"",
)
}
if !css.is_empty() {
out.write_string("")
}
if style.bold {
out.write_string("")
}
if style.italic {
out.write_string("")
}
if style.underline {
out.write_string("")
}
if style.strike {
out.write_string("")
}
if style.superscript > 0 {
out.write_string("")
}
if style.superscript < 0 {
out.write_string("")
}
out.write_string(html_escape(run.text))
if style.superscript < 0 {
out.write_string("")
}
if style.superscript > 0 {
out.write_string("")
}
if style.strike {
out.write_string("")
}
if style.underline {
out.write_string("")
}
if style.italic {
out.write_string("")
}
if style.bold {
out.write_string("")
}
if !css.is_empty() {
out.write_string("")
}
if linked {
out.write_string("")
}
out.to_string()
}
///|
fn Document::html_paragraph(
self : Document,
paragraph : Paragraph,
hidden : Bool,
) -> String {
let out = StringBuilder()
let align = alignment_name(paragraph.style.alignment)
out.write_string("")
for run in paragraph.runs {
if hidden || !run.style.hidden {
out.write_string(self.html_run(run))
}
}
out.write_string("
")
out.to_string()
}
///|
/// Semantic HTML fragment. No scripts, embedded resources, or raw RTF HTML.
pub fn Document::to_html(
self : Document,
options? : TextOptions = TextOptions::default(),
) -> String {
let out = StringBuilder()
let mut table = false
let mut row : Int? = None
let mut cell : Int? = None
let mut region : Region? = None
for paragraph in self.paragraphs {
if !options.accepts(paragraph.region) {
continue
}
if region != Some(paragraph.region) {
if table {
out.write_string("\n")
table = false
row = None
cell = None
}
if region is Some(_) {
out.write_string("\n")
}
out.write_string(
"\n",
)
region = Some(paragraph.region)
}
if paragraph.table_row is Some(index) {
if !table {
out.write_string("")
table = true
row = Some(index)
cell = paragraph.table_cell
} else if row != Some(index) {
out.write_string(" ")
row = Some(index)
cell = paragraph.table_cell
} else if cell != paragraph.table_cell {
out.write_string(" ")
cell = paragraph.table_cell
}
} else if table {
out.write_string("
\n")
table = false
row = None
cell = None
}
out.write_string(self.html_paragraph(paragraph, options.include_hidden))
out.write_char('\n')
}
if table {
out.write_string("\n")
}
if region is Some(_) {
out.write_string(" \n")
}
out.to_string()
}