use std::collections::HashMap;
use super::node::NodeId;
#[derive(Debug, Default, Clone)]
pub struct SemanticMap {
href: HashMap<NodeId, String>,
src: HashMap<NodeId, String>,
alt: HashMap<NodeId, String>,
id: HashMap<NodeId, String>,
title: HashMap<NodeId, String>,
lang: HashMap<NodeId, String>,
epub_type: HashMap<NodeId, String>,
aria_role: HashMap<NodeId, String>,
datetime: HashMap<NodeId, String>,
list_start: HashMap<NodeId, u32>,
row_span: HashMap<NodeId, u32>,
col_span: HashMap<NodeId, u32>,
is_header_cell: HashMap<NodeId, bool>,
language: HashMap<NodeId, String>,
}
impl SemanticMap {
pub fn new() -> Self {
Self::default()
}
pub fn set_href(&mut self, node: NodeId, href: String) {
if !href.is_empty() {
self.href.insert(node, href);
}
}
pub fn href(&self, node: NodeId) -> Option<&str> {
self.href.get(&node).map(|s| s.as_str())
}
pub fn set_src(&mut self, node: NodeId, src: String) {
if !src.is_empty() {
self.src.insert(node, src);
}
}
pub fn src(&self, node: NodeId) -> Option<&str> {
self.src.get(&node).map(|s| s.as_str())
}
pub fn set_alt(&mut self, node: NodeId, alt: String) {
if !alt.is_empty() {
self.alt.insert(node, alt);
}
}
pub fn alt(&self, node: NodeId) -> Option<&str> {
self.alt.get(&node).map(|s| s.as_str())
}
pub fn set_id(&mut self, node: NodeId, id: String) {
if !id.is_empty() {
self.id.insert(node, id);
}
}
pub fn id(&self, node: NodeId) -> Option<&str> {
self.id.get(&node).map(|s| s.as_str())
}
pub fn set_title(&mut self, node: NodeId, title: String) {
if !title.is_empty() {
self.title.insert(node, title);
}
}
pub fn title(&self, node: NodeId) -> Option<&str> {
self.title.get(&node).map(|s| s.as_str())
}
pub fn set_lang(&mut self, node: NodeId, lang: String) {
if !lang.is_empty() {
self.lang.insert(node, lang);
}
}
pub fn lang(&self, node: NodeId) -> Option<&str> {
self.lang.get(&node).map(|s| s.as_str())
}
pub fn set_epub_type(&mut self, node: NodeId, epub_type: String) {
if !epub_type.is_empty() {
self.epub_type.insert(node, epub_type);
}
}
pub fn epub_type(&self, node: NodeId) -> Option<&str> {
self.epub_type.get(&node).map(|s| s.as_str())
}
pub fn set_aria_role(&mut self, node: NodeId, role: String) {
if !role.is_empty() {
self.aria_role.insert(node, role);
}
}
pub fn aria_role(&self, node: NodeId) -> Option<&str> {
self.aria_role.get(&node).map(|s| s.as_str())
}
pub fn set_datetime(&mut self, node: NodeId, datetime: String) {
if !datetime.is_empty() {
self.datetime.insert(node, datetime);
}
}
pub fn datetime(&self, node: NodeId) -> Option<&str> {
self.datetime.get(&node).map(|s| s.as_str())
}
pub fn set_list_start(&mut self, node: NodeId, start: u32) {
if start != 1 {
self.list_start.insert(node, start);
}
}
pub fn list_start(&self, node: NodeId) -> Option<u32> {
self.list_start.get(&node).copied()
}
pub fn set_row_span(&mut self, node: NodeId, span: u32) {
if span > 1 {
self.row_span.insert(node, span);
}
}
pub fn row_span(&self, node: NodeId) -> Option<u32> {
self.row_span.get(&node).copied()
}
pub fn set_col_span(&mut self, node: NodeId, span: u32) {
if span > 1 {
self.col_span.insert(node, span);
}
}
pub fn col_span(&self, node: NodeId) -> Option<u32> {
self.col_span.get(&node).copied()
}
pub fn set_header_cell(&mut self, node: NodeId, is_header: bool) {
if is_header {
self.is_header_cell.insert(node, true);
}
}
pub fn is_header_cell(&self, node: NodeId) -> bool {
self.is_header_cell.get(&node).copied().unwrap_or(false)
}
pub fn set_language(&mut self, node: NodeId, language: String) {
if !language.is_empty() {
self.language.insert(node, language);
}
}
pub fn language(&self, node: NodeId) -> Option<&str> {
self.language.get(&node).map(|s| s.as_str())
}
pub fn get_attr(&self, node: NodeId, name: &str) -> Option<&str> {
match name {
"href" => self.href(node),
"src" => self.src(node),
"alt" => self.alt(node),
"id" => self.id(node),
"title" => self.title(node),
"lang" | "xml:lang" => self.lang(node),
"epub:type" => self.epub_type(node),
"role" => self.aria_role(node),
"datetime" => self.datetime(node),
_ => None,
}
}
pub fn set_attr(&mut self, node: NodeId, name: &str, value: impl Into<String>) -> bool {
let value = value.into();
match name {
"href" => {
self.set_href(node, value);
true
}
"src" => {
self.set_src(node, value);
true
}
"alt" => {
self.set_alt(node, value);
true
}
"id" => {
self.set_id(node, value);
true
}
"title" => {
self.set_title(node, value);
true
}
"lang" | "xml:lang" => {
self.set_lang(node, value);
true
}
"epub:type" => {
self.set_epub_type(node, value);
true
}
"role" => {
self.set_aria_role(node, value);
true
}
"datetime" => {
self.set_datetime(node, value);
true
}
_ => false,
}
}
pub fn len(&self) -> usize {
self.href.len()
+ self.src.len()
+ self.alt.len()
+ self.id.len()
+ self.title.len()
+ self.lang.len()
+ self.epub_type.len()
+ self.aria_role.len()
+ self.datetime.len()
+ self.list_start.len()
+ self.row_span.len()
+ self.col_span.len()
+ self.is_header_cell.len()
+ self.language.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn resolve_paths<F>(&mut self, resolver: F)
where
F: Fn(&str) -> String,
{
for value in self.src.values_mut() {
*value = resolver(value);
}
for value in self.href.values_mut() {
if !value.contains("://") && !value.starts_with("mailto:") {
*value = resolver(value);
}
}
}
}