use crate::{
assert_element, inner_data, node::Wikinode, set_inner_data, Result,
WikinodeIterator,
};
use kuchikikiki::NodeRef;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
pub struct Reference(pub(crate) NodeRef);
impl Reference {
pub(crate) fn new_from_node(element: &NodeRef) -> Self {
assert_element(element);
Self(element.clone())
}
pub fn contents(&self) -> Wikinode {
self.select_first(".mw-reference-text")
.expect("no .mw-reference-text found")
}
pub fn id(&self) -> String {
self.contents()
.as_element()
.unwrap()
.attributes
.borrow()
.get("id")
.unwrap()
.to_string()
}
pub fn referenced_by_ids(&self) -> Vec<String> {
self.select(".mw-cite-backlink > a")
.into_iter()
.map(|node| {
node.as_element()
.unwrap()
.attributes
.borrow()
.get("href")
.unwrap()
.split_once('#')
.unwrap()
.1
.to_string()
})
.collect()
}
}
#[derive(Debug, Clone)]
pub struct ReferenceLink(pub(crate) NodeRef);
impl ReferenceLink {
pub(crate) const TYPEOF: &'static str = "mw:Extension/ref";
pub(crate) const SELECTOR: &'static str = "[typeof=\"mw:Extension/ref\"]";
pub(crate) fn new_from_node(element: &NodeRef) -> Self {
assert_element(element);
Self(element.clone())
}
pub fn id(&self) -> String {
self.as_element()
.unwrap()
.attributes
.borrow()
.get("id")
.unwrap()
.to_string()
}
pub fn name(&self) -> Result<Option<String>> {
Ok(self.inner()?.attrs.name)
}
pub fn set_name(&self, name: String) -> Result<()> {
let mut inner = self.inner()?;
inner.attrs.name = Some(name);
self.set_inner(inner)?;
Ok(())
}
pub fn remove_name(&self) -> Result<()> {
let mut inner = self.inner()?;
inner.attrs.name = None;
self.set_inner(inner)?;
Ok(())
}
pub fn group(&self) -> Result<Option<String>> {
Ok(self.inner()?.attrs.group)
}
pub fn set_group(&self, group: String) -> Result<()> {
let mut inner = self.inner()?;
inner.attrs.group = Some(group);
self.set_inner(inner)?;
Ok(())
}
pub fn remove_group(&self) -> Result<()> {
let mut inner = self.inner()?;
inner.attrs.group = None;
self.set_inner(inner)?;
Ok(())
}
pub fn is_reused(&self) -> Result<bool> {
Ok(self.inner()?.body.is_none())
}
pub fn reference_id(&self) -> Result<String> {
let id = match self.inner()?.body {
Some(body) => body.id,
None => {
let part = self
.select_first("a[href]")
.unwrap()
.as_element()
.unwrap()
.attributes
.borrow()
.get("href")
.unwrap()
.split_once('#')
.unwrap()
.1
.to_string();
format!("mw-reference-text-{part}")
}
};
Ok(id)
}
fn inner(&self) -> Result<RefDataMw> {
inner_data(self)
}
fn set_inner(&self, data: RefDataMw) -> Result<()> {
set_inner_data(self, data)
}
}
#[derive(Deserialize, Serialize)]
struct RefDataMw {
name: String,
attrs: RefAttrs,
#[serde(skip_serializing_if = "Option::is_none")]
body: Option<RefBody>,
}
#[derive(Deserialize, Serialize)]
struct RefAttrs {
#[serde(skip_serializing_if = "Option::is_none")]
group: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
}
#[derive(Deserialize, Serialize)]
struct RefBody {
id: String,
}
#[derive(Debug, Clone)]
pub struct ReferenceList(pub(crate) NodeRef);
impl ReferenceList {
pub(crate) const TYPEOF: &'static str = "mw:Extension/references";
pub(crate) const SELECTOR: &'static str =
"[typeof=\"mw:Extension/references\"]";
pub(crate) fn new_from_node(element: &NodeRef) -> Self {
assert_element(element);
Self(element.clone())
}
pub fn references(&self) -> Vec<Reference> {
self.select("ol.mw-references > li")
.into_iter()
.map(|node| Reference::new_from_node(&node))
.collect()
}
pub fn find(&self, id: &str) -> Option<Reference> {
self.references().into_iter().find(|ref_| ref_.id() == id)
}
pub fn group(&self) -> Result<Option<String>> {
Ok(self.inner()?.attrs.group)
}
pub fn set_group(&self, group: String) -> Result<()> {
let mut inner = self.inner()?;
inner.attrs.group = Some(group);
self.set_inner(inner)?;
Ok(())
}
pub fn remove_group(&self) -> Result<()> {
let mut inner = self.inner()?;
inner.attrs.group = None;
self.set_inner(inner)?;
Ok(())
}
pub fn is_auto_generated(&self) -> Result<bool> {
Ok(self.inner()?.auto_generated)
}
fn inner(&self) -> Result<ReferencesListDataMw> {
inner_data(self)
}
fn set_inner(&self, data: ReferencesListDataMw) -> Result<()> {
set_inner_data(self, data)
}
}
#[derive(Deserialize, Serialize)]
pub(crate) struct ReferencesListDataMw {
pub(crate) name: String,
pub(crate) attrs: ReferencesListAttrs,
#[serde(rename = "autoGenerated")]
#[serde(default)]
pub(crate) auto_generated: bool,
}
#[derive(Deserialize, Serialize)]
pub(crate) struct ReferencesListAttrs {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) group: Option<String>,
}