use rdom_core::NodeId;
use super::model::{option_disabled, options, selected_options};
use crate::{TuiDom, TuiEvent};
const HIGHLIGHT_ATTR: &str = "data-rdom-highlight";
const ANCHOR_ATTR: &str = "data-rdom-anchor";
pub(crate) fn note_default_selected(dom: &mut TuiDom, select: NodeId) {
for opt in options(dom, select) {
let selected = dom.node(opt).has_attribute("selected");
if let Some(ext) = dom.node_mut(opt).ext_mut()
&& ext.default_selected.is_none()
{
ext.default_selected = Some(selected);
}
}
}
pub(crate) fn reset_to_default(dom: &mut TuiDom, select: NodeId) {
for opt in options(dom, select) {
match dom.node(opt).ext().and_then(|e| e.default_selected) {
Some(true) => {
let _ = dom.set_attribute(opt, "selected", "");
}
Some(false) => {
let _ = dom.remove_attribute(opt, "selected");
}
None => {}
}
}
super::selectedness::run(dom, select);
}
pub(super) fn select_single(dom: &mut TuiDom, select: NodeId, option: NodeId) {
let current = selected_options(dom, select);
let already = current.len() == 1 && current[0] == option;
if already {
return;
}
note_default_selected(dom, select);
for opt in current {
let _ = dom.remove_attribute(opt, "selected");
}
let _ = dom.set_attribute(option, "selected", "");
}
pub(super) fn toggle_option(dom: &mut TuiDom, select: NodeId, option: NodeId) {
note_default_selected(dom, select);
if dom.node(option).has_attribute("selected") {
let _ = dom.remove_attribute(option, "selected");
} else {
let _ = dom.set_attribute(option, "selected", "");
}
}
pub(super) fn extend_selection_to(dom: &mut TuiDom, select: NodeId, target: NodeId) {
let anchor = anchor(dom, select).unwrap_or_else(|| {
let a = highlight(dom, select).unwrap_or(target);
set_anchor(dom, select, Some(a));
a
});
let all = options(dom, select);
let a_idx = all.iter().position(|&o| o == anchor);
let t_idx = all.iter().position(|&o| o == target);
let (Some(a_idx), Some(t_idx)) = (a_idx, t_idx) else {
return;
};
note_default_selected(dom, select);
let (lo, hi) = if a_idx <= t_idx {
(a_idx, t_idx)
} else {
(t_idx, a_idx)
};
for (i, &opt) in all.iter().enumerate() {
if option_disabled(dom, opt) {
continue;
}
if i >= lo && i <= hi {
let _ = dom.set_attribute(opt, "selected", "");
} else {
let _ = dom.remove_attribute(opt, "selected");
}
}
}
pub(super) fn fire_input_and_change(dom: &mut TuiDom, select: NodeId) {
let mut input_ev = TuiEvent::new("input");
crate::tui_event::dispatch_to_live(dom, select, &mut input_ev);
let mut change_ev = TuiEvent::new("change");
crate::tui_event::dispatch_to_live(dom, select, &mut change_ev);
}
pub(super) fn highlight(dom: &TuiDom, select: NodeId) -> Option<NodeId> {
options(dom, select)
.into_iter()
.find(|&o| dom.node(o).has_attribute(HIGHLIGHT_ATTR))
}
pub(super) fn set_highlight(dom: &mut TuiDom, select: NodeId, target: Option<NodeId>) {
for opt in options(dom, select) {
let want = target == Some(opt);
let has = dom.node(opt).has_attribute(HIGHLIGHT_ATTR);
if want && !has {
let _ = dom.set_attribute(opt, HIGHLIGHT_ATTR, "");
} else if !want && has {
let _ = dom.remove_attribute(opt, HIGHLIGHT_ATTR);
}
}
}
pub(super) fn anchor(dom: &TuiDom, select: NodeId) -> Option<NodeId> {
options(dom, select)
.into_iter()
.find(|&o| dom.node(o).has_attribute(ANCHOR_ATTR))
}
pub(super) fn set_anchor(dom: &mut TuiDom, select: NodeId, target: Option<NodeId>) {
for opt in options(dom, select) {
let want = target == Some(opt);
let has = dom.node(opt).has_attribute(ANCHOR_ATTR);
if want && !has {
let _ = dom.set_attribute(opt, ANCHOR_ATTR, "");
} else if !want && has {
let _ = dom.remove_attribute(opt, ANCHOR_ATTR);
}
}
}