#[cfg(not(feature = "std"))]
use alloc::string::ToString;
use alloc::{boxed::Box, collections::btree_map::BTreeMap, string::String, vec::Vec};
use core::{
fmt,
hash::{Hash, Hasher},
iter::FromIterator,
mem,
sync::atomic::{AtomicUsize, Ordering},
};
use azul_css::{
css::{Css, NodeTypeTag},
format_rust_code::GetHash,
props::{
basic::{FloatValue, FontRef},
layout::{LayoutDisplay, LayoutFloat, LayoutPosition},
property::CssProperty,
},
AzString, OptionString,
};
pub use crate::events::{
ApplicationEventFilter, ComponentEventFilter, EventFilter, FocusEventFilter, HoverEventFilter,
NotEventFilter, WindowEventFilter,
};
pub use crate::id::{Node, NodeHierarchy, NodeId};
use crate::{
callbacks::{
CoreCallback, CoreCallbackData, CoreCallbackDataVec, CoreCallbackType, IFrameCallback,
IFrameCallbackType,
},
geom::LogicalPosition,
id::{NodeDataContainer, NodeDataContainerRef, NodeDataContainerRefMut},
menu::Menu,
prop_cache::{CssPropertyCache, CssPropertyCachePtr},
refany::{OptionRefAny, RefAny},
resources::{
image_ref_get_hash, CoreImageCallback, ImageMask, ImageRef, ImageRefHash, RendererResources,
},
styled_dom::{
CompactDom, NodeHierarchyItemId, StyleFontFamilyHash, StyledDom, StyledNode,
StyledNodeState,
},
window::OptionVirtualKeyCodeCombo,
};
pub use azul_css::dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec};
static TAG_ID: AtomicUsize = AtomicUsize::new(1);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub enum InputType {
Text,
Button,
Checkbox,
Color,
Date,
Datetime,
DatetimeLocal,
Email,
File,
Hidden,
Image,
Month,
Number,
Password,
Radio,
Range,
Reset,
Search,
Submit,
Tel,
Time,
Url,
Week,
}
impl InputType {
pub const fn as_str(&self) -> &'static str {
match self {
InputType::Text => "text",
InputType::Button => "button",
InputType::Checkbox => "checkbox",
InputType::Color => "color",
InputType::Date => "date",
InputType::Datetime => "datetime",
InputType::DatetimeLocal => "datetime-local",
InputType::Email => "email",
InputType::File => "file",
InputType::Hidden => "hidden",
InputType::Image => "image",
InputType::Month => "month",
InputType::Number => "number",
InputType::Password => "password",
InputType::Radio => "radio",
InputType::Range => "range",
InputType::Reset => "reset",
InputType::Search => "search",
InputType::Submit => "submit",
InputType::Tel => "tel",
InputType::Time => "time",
InputType::Url => "url",
InputType::Week => "week",
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[repr(C)]
pub struct TagId {
pub inner: u64,
}
impl ::core::fmt::Display for TagId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("TagId").field("inner", &self.inner).finish()
}
}
impl_option!(
TagId,
OptionTagId,
[Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash]
);
impl TagId {
pub const fn into_crate_internal(&self) -> TagId {
TagId { inner: self.inner }
}
pub const fn from_crate_internal(t: TagId) -> Self {
TagId { inner: t.inner }
}
pub fn unique() -> Self {
loop {
let current = TAG_ID.load(Ordering::SeqCst);
let next = if current == usize::MAX { 1 } else { current + 1 };
if TAG_ID.compare_exchange(current, next, Ordering::SeqCst, Ordering::SeqCst).is_ok() {
return TagId { inner: current as u64 };
}
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[repr(C)]
pub struct ScrollTagId {
pub inner: TagId,
}
impl ::core::fmt::Display for ScrollTagId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ScrollTagId")
.field("inner", &self.inner)
.finish()
}
}
impl ::core::fmt::Debug for ScrollTagId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl ScrollTagId {
pub fn unique() -> ScrollTagId {
ScrollTagId {
inner: TagId::unique(),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub enum ScrollbarOrientation {
Horizontal,
Vertical,
}
#[derive(Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
#[repr(C)]
pub struct DomNodeHash {
pub inner: u64,
}
impl ::core::fmt::Debug for DomNodeHash {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "DomNodeHash({})", self.inner)
}
}
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
#[repr(C, u8)]
pub enum NodeType {
Html,
Head,
Body,
Div,
P,
Article,
Section,
Nav,
Aside,
Header,
Footer,
Main,
Figure,
FigCaption,
H1,
H2,
H3,
H4,
H5,
H6,
Br,
Hr,
Pre,
BlockQuote,
Address,
Details,
Summary,
Dialog,
Ul,
Ol,
Li,
Dl,
Dt,
Dd,
Menu,
MenuItem,
Dir,
Table,
Caption,
THead,
TBody,
TFoot,
Tr,
Th,
Td,
ColGroup,
Col,
Form,
FieldSet,
Legend,
Label,
Input,
Button,
Select,
OptGroup,
SelectOption,
TextArea,
Output,
Progress,
Meter,
DataList,
Span,
A,
Em,
Strong,
B,
I,
U,
S,
Mark,
Del,
Ins,
Code,
Samp,
Kbd,
Var,
Cite,
Dfn,
Abbr,
Acronym,
Q,
Time,
Sub,
Sup,
Small,
Big,
Bdo,
Bdi,
Wbr,
Ruby,
Rt,
Rtc,
Rp,
Data,
Canvas,
Object,
Param,
Embed,
Audio,
Video,
Source,
Track,
Map,
Area,
Svg,
Title,
Meta,
Link,
Script,
Style,
Base,
Before,
After,
Marker,
Placeholder,
Text(AzString),
Image(ImageRef),
IFrame(IFrameNode),
Icon(AzString),
}
impl NodeType {
fn into_library_owned_nodetype(&self) -> Self {
use self::NodeType::*;
match self {
Html => Html,
Head => Head,
Body => Body,
Div => Div,
P => P,
Article => Article,
Section => Section,
Nav => Nav,
Aside => Aside,
Header => Header,
Footer => Footer,
Main => Main,
Figure => Figure,
FigCaption => FigCaption,
H1 => H1,
H2 => H2,
H3 => H3,
H4 => H4,
H5 => H5,
H6 => H6,
Br => Br,
Hr => Hr,
Pre => Pre,
BlockQuote => BlockQuote,
Address => Address,
Details => Details,
Summary => Summary,
Dialog => Dialog,
Ul => Ul,
Ol => Ol,
Li => Li,
Dl => Dl,
Dt => Dt,
Dd => Dd,
Menu => Menu,
MenuItem => MenuItem,
Dir => Dir,
Table => Table,
Caption => Caption,
THead => THead,
TBody => TBody,
TFoot => TFoot,
Tr => Tr,
Th => Th,
Td => Td,
ColGroup => ColGroup,
Col => Col,
Form => Form,
FieldSet => FieldSet,
Legend => Legend,
Label => Label,
Input => Input,
Button => Button,
Select => Select,
OptGroup => OptGroup,
SelectOption => SelectOption,
TextArea => TextArea,
Output => Output,
Progress => Progress,
Meter => Meter,
DataList => DataList,
Span => Span,
A => A,
Em => Em,
Strong => Strong,
B => B,
I => I,
U => U,
S => S,
Mark => Mark,
Del => Del,
Ins => Ins,
Code => Code,
Samp => Samp,
Kbd => Kbd,
Var => Var,
Cite => Cite,
Dfn => Dfn,
Abbr => Abbr,
Acronym => Acronym,
Q => Q,
Time => Time,
Sub => Sub,
Sup => Sup,
Small => Small,
Big => Big,
Bdo => Bdo,
Bdi => Bdi,
Wbr => Wbr,
Ruby => Ruby,
Rt => Rt,
Rtc => Rtc,
Rp => Rp,
Data => Data,
Canvas => Canvas,
Object => Object,
Param => Param,
Embed => Embed,
Audio => Audio,
Video => Video,
Source => Source,
Track => Track,
Map => Map,
Area => Area,
Svg => Svg,
Title => Title,
Meta => Meta,
Link => Link,
Script => Script,
Style => Style,
Base => Base,
Before => Before,
After => After,
Marker => Marker,
Placeholder => Placeholder,
Text(s) => Text(s.clone_self()),
Image(i) => Image(i.clone()), IFrame(i) => IFrame(IFrameNode {
callback: i.callback.clone(),
refany: i.refany.clone(),
}),
Icon(s) => Icon(s.clone_self()),
}
}
pub fn format(&self) -> Option<String> {
use self::NodeType::*;
match self {
Text(s) => Some(format!("{}", s)),
Image(id) => Some(format!("image({:?})", id)),
IFrame(i) => Some(format!("iframe({:?})", i)),
Icon(s) => Some(format!("icon({})", s)),
_ => None,
}
}
pub fn get_path(&self) -> NodeTypeTag {
match self {
Self::Html => NodeTypeTag::Html,
Self::Head => NodeTypeTag::Head,
Self::Body => NodeTypeTag::Body,
Self::Div => NodeTypeTag::Div,
Self::P => NodeTypeTag::P,
Self::Article => NodeTypeTag::Article,
Self::Section => NodeTypeTag::Section,
Self::Nav => NodeTypeTag::Nav,
Self::Aside => NodeTypeTag::Aside,
Self::Header => NodeTypeTag::Header,
Self::Footer => NodeTypeTag::Footer,
Self::Main => NodeTypeTag::Main,
Self::Figure => NodeTypeTag::Figure,
Self::FigCaption => NodeTypeTag::FigCaption,
Self::H1 => NodeTypeTag::H1,
Self::H2 => NodeTypeTag::H2,
Self::H3 => NodeTypeTag::H3,
Self::H4 => NodeTypeTag::H4,
Self::H5 => NodeTypeTag::H5,
Self::H6 => NodeTypeTag::H6,
Self::Br => NodeTypeTag::Br,
Self::Hr => NodeTypeTag::Hr,
Self::Pre => NodeTypeTag::Pre,
Self::BlockQuote => NodeTypeTag::BlockQuote,
Self::Address => NodeTypeTag::Address,
Self::Details => NodeTypeTag::Details,
Self::Summary => NodeTypeTag::Summary,
Self::Dialog => NodeTypeTag::Dialog,
Self::Ul => NodeTypeTag::Ul,
Self::Ol => NodeTypeTag::Ol,
Self::Li => NodeTypeTag::Li,
Self::Dl => NodeTypeTag::Dl,
Self::Dt => NodeTypeTag::Dt,
Self::Dd => NodeTypeTag::Dd,
Self::Menu => NodeTypeTag::Menu,
Self::MenuItem => NodeTypeTag::MenuItem,
Self::Dir => NodeTypeTag::Dir,
Self::Table => NodeTypeTag::Table,
Self::Caption => NodeTypeTag::Caption,
Self::THead => NodeTypeTag::THead,
Self::TBody => NodeTypeTag::TBody,
Self::TFoot => NodeTypeTag::TFoot,
Self::Tr => NodeTypeTag::Tr,
Self::Th => NodeTypeTag::Th,
Self::Td => NodeTypeTag::Td,
Self::ColGroup => NodeTypeTag::ColGroup,
Self::Col => NodeTypeTag::Col,
Self::Form => NodeTypeTag::Form,
Self::FieldSet => NodeTypeTag::FieldSet,
Self::Legend => NodeTypeTag::Legend,
Self::Label => NodeTypeTag::Label,
Self::Input => NodeTypeTag::Input,
Self::Button => NodeTypeTag::Button,
Self::Select => NodeTypeTag::Select,
Self::OptGroup => NodeTypeTag::OptGroup,
Self::SelectOption => NodeTypeTag::SelectOption,
Self::TextArea => NodeTypeTag::TextArea,
Self::Output => NodeTypeTag::Output,
Self::Progress => NodeTypeTag::Progress,
Self::Meter => NodeTypeTag::Meter,
Self::DataList => NodeTypeTag::DataList,
Self::Span => NodeTypeTag::Span,
Self::A => NodeTypeTag::A,
Self::Em => NodeTypeTag::Em,
Self::Strong => NodeTypeTag::Strong,
Self::B => NodeTypeTag::B,
Self::I => NodeTypeTag::I,
Self::U => NodeTypeTag::U,
Self::S => NodeTypeTag::S,
Self::Mark => NodeTypeTag::Mark,
Self::Del => NodeTypeTag::Del,
Self::Ins => NodeTypeTag::Ins,
Self::Code => NodeTypeTag::Code,
Self::Samp => NodeTypeTag::Samp,
Self::Kbd => NodeTypeTag::Kbd,
Self::Var => NodeTypeTag::Var,
Self::Cite => NodeTypeTag::Cite,
Self::Dfn => NodeTypeTag::Dfn,
Self::Abbr => NodeTypeTag::Abbr,
Self::Acronym => NodeTypeTag::Acronym,
Self::Q => NodeTypeTag::Q,
Self::Time => NodeTypeTag::Time,
Self::Sub => NodeTypeTag::Sub,
Self::Sup => NodeTypeTag::Sup,
Self::Small => NodeTypeTag::Small,
Self::Big => NodeTypeTag::Big,
Self::Bdo => NodeTypeTag::Bdo,
Self::Bdi => NodeTypeTag::Bdi,
Self::Wbr => NodeTypeTag::Wbr,
Self::Ruby => NodeTypeTag::Ruby,
Self::Rt => NodeTypeTag::Rt,
Self::Rtc => NodeTypeTag::Rtc,
Self::Rp => NodeTypeTag::Rp,
Self::Data => NodeTypeTag::Data,
Self::Canvas => NodeTypeTag::Canvas,
Self::Object => NodeTypeTag::Object,
Self::Param => NodeTypeTag::Param,
Self::Embed => NodeTypeTag::Embed,
Self::Audio => NodeTypeTag::Audio,
Self::Video => NodeTypeTag::Video,
Self::Source => NodeTypeTag::Source,
Self::Track => NodeTypeTag::Track,
Self::Map => NodeTypeTag::Map,
Self::Area => NodeTypeTag::Area,
Self::Svg => NodeTypeTag::Svg,
Self::Title => NodeTypeTag::Title,
Self::Meta => NodeTypeTag::Meta,
Self::Link => NodeTypeTag::Link,
Self::Script => NodeTypeTag::Script,
Self::Style => NodeTypeTag::Style,
Self::Base => NodeTypeTag::Base,
Self::Text(_) => NodeTypeTag::Text,
Self::Image(_) => NodeTypeTag::Img,
Self::IFrame(_) => NodeTypeTag::IFrame,
Self::Icon(_) => NodeTypeTag::Icon,
Self::Before => NodeTypeTag::Before,
Self::After => NodeTypeTag::After,
Self::Marker => NodeTypeTag::Marker,
Self::Placeholder => NodeTypeTag::Placeholder,
}
}
pub const fn is_semantic_for_accessibility(&self) -> bool {
matches!(
self,
Self::Button
| Self::Input
| Self::TextArea
| Self::Select
| Self::A
| Self::H1
| Self::H2
| Self::H3
| Self::H4
| Self::H5
| Self::H6
| Self::Article
| Self::Section
| Self::Nav
| Self::Main
| Self::Header
| Self::Footer
| Self::Aside
)
}
}
#[derive(Clone, PartialEq)]
pub enum FormattingContext {
Block {
establishes_new_context: bool,
},
Inline,
InlineBlock,
Flex,
Float(LayoutFloat),
OutOfFlow(LayoutPosition),
Table,
TableRowGroup,
TableRow,
TableCell,
TableColumnGroup,
TableCaption,
Grid,
None,
}
impl fmt::Debug for FormattingContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FormattingContext::Block {
establishes_new_context,
} => write!(
f,
"Block {{ establishes_new_context: {establishes_new_context:?} }}"
),
FormattingContext::Inline => write!(f, "Inline"),
FormattingContext::InlineBlock => write!(f, "InlineBlock"),
FormattingContext::Flex => write!(f, "Flex"),
FormattingContext::Float(layout_float) => write!(f, "Float({layout_float:?})"),
FormattingContext::OutOfFlow(layout_position) => {
write!(f, "OutOfFlow({layout_position:?})")
}
FormattingContext::Grid => write!(f, "Grid"),
FormattingContext::None => write!(f, "None"),
FormattingContext::Table => write!(f, "Table"),
FormattingContext::TableRowGroup => write!(f, "TableRowGroup"),
FormattingContext::TableRow => write!(f, "TableRow"),
FormattingContext::TableCell => write!(f, "TableCell"),
FormattingContext::TableColumnGroup => write!(f, "TableColumnGroup"),
FormattingContext::TableCaption => write!(f, "TableCaption"),
}
}
}
impl Default for FormattingContext {
fn default() -> Self {
FormattingContext::Block {
establishes_new_context: false,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub enum On {
MouseOver,
MouseDown,
LeftMouseDown,
MiddleMouseDown,
RightMouseDown,
MouseUp,
LeftMouseUp,
MiddleMouseUp,
RightMouseUp,
MouseEnter,
MouseLeave,
Scroll,
TextInput,
VirtualKeyDown,
VirtualKeyUp,
HoveredFile,
DroppedFile,
HoveredFileCancelled,
FocusReceived,
FocusLost,
Default,
Collapse,
Expand,
Increment,
Decrement,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct IFrameNode {
pub callback: IFrameCallback,
pub refany: RefAny,
}
#[repr(C, u8)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum IdOrClass {
Id(AzString),
Class(AzString),
}
impl_option!(
IdOrClass,
OptionIdOrClass,
copy = false,
[Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord]
);
impl_vec!(IdOrClass, IdOrClassVec, IdOrClassVecDestructor, IdOrClassVecDestructorType, IdOrClassVecSlice, OptionIdOrClass);
impl_vec_debug!(IdOrClass, IdOrClassVec);
impl_vec_partialord!(IdOrClass, IdOrClassVec);
impl_vec_ord!(IdOrClass, IdOrClassVec);
impl_vec_clone!(IdOrClass, IdOrClassVec, IdOrClassVecDestructor);
impl_vec_partialeq!(IdOrClass, IdOrClassVec);
impl_vec_eq!(IdOrClass, IdOrClassVec);
impl_vec_hash!(IdOrClass, IdOrClassVec);
impl IdOrClass {
pub fn as_id(&self) -> Option<&str> {
match self {
IdOrClass::Id(s) => Some(s.as_str()),
IdOrClass::Class(_) => None,
}
}
pub fn as_class(&self) -> Option<&str> {
match self {
IdOrClass::Class(s) => Some(s.as_str()),
IdOrClass::Id(_) => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct AttributeNameValue {
pub attr_name: AzString,
pub value: AzString,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, u8)]
pub enum AttributeType {
Id(AzString),
Class(AzString),
AriaLabel(AzString),
AriaLabelledBy(AzString),
AriaDescribedBy(AzString),
AriaRole(AzString),
AriaState(AttributeNameValue),
AriaProperty(AttributeNameValue),
Href(AzString),
Rel(AzString),
Target(AzString),
Src(AzString),
Alt(AzString),
Title(AzString),
Name(AzString),
Value(AzString),
InputType(AzString),
Placeholder(AzString),
Required,
Disabled,
Readonly,
Checked,
Selected,
Max(AzString),
Min(AzString),
Step(AzString),
Pattern(AzString),
MinLength(i32),
MaxLength(i32),
Autocomplete(AzString),
Scope(AzString),
ColSpan(i32),
RowSpan(i32),
TabIndex(i32),
Focusable,
Lang(AzString),
Dir(AzString),
ContentEditable(bool),
Draggable(bool),
Hidden,
Data(AttributeNameValue),
Custom(AttributeNameValue),
}
impl_option!(
AttributeType,
OptionAttributeType,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_vec!(AttributeType, AttributeTypeVec, AttributeTypeVecDestructor, AttributeTypeVecDestructorType, AttributeTypeVecSlice, OptionAttributeType);
impl_vec_debug!(AttributeType, AttributeTypeVec);
impl_vec_partialord!(AttributeType, AttributeTypeVec);
impl_vec_ord!(AttributeType, AttributeTypeVec);
impl_vec_clone!(AttributeType, AttributeTypeVec, AttributeTypeVecDestructor);
impl_vec_partialeq!(AttributeType, AttributeTypeVec);
impl_vec_eq!(AttributeType, AttributeTypeVec);
impl_vec_hash!(AttributeType, AttributeTypeVec);
impl AttributeType {
pub fn name(&self) -> &str {
match self {
AttributeType::Id(_) => "id",
AttributeType::Class(_) => "class",
AttributeType::AriaLabel(_) => "aria-label",
AttributeType::AriaLabelledBy(_) => "aria-labelledby",
AttributeType::AriaDescribedBy(_) => "aria-describedby",
AttributeType::AriaRole(_) => "role",
AttributeType::AriaState(nv) => nv.attr_name.as_str(),
AttributeType::AriaProperty(nv) => nv.attr_name.as_str(),
AttributeType::Href(_) => "href",
AttributeType::Rel(_) => "rel",
AttributeType::Target(_) => "target",
AttributeType::Src(_) => "src",
AttributeType::Alt(_) => "alt",
AttributeType::Title(_) => "title",
AttributeType::Name(_) => "name",
AttributeType::Value(_) => "value",
AttributeType::InputType(_) => "type",
AttributeType::Placeholder(_) => "placeholder",
AttributeType::Required => "required",
AttributeType::Disabled => "disabled",
AttributeType::Readonly => "readonly",
AttributeType::Checked => "checked",
AttributeType::Selected => "selected",
AttributeType::Max(_) => "max",
AttributeType::Min(_) => "min",
AttributeType::Step(_) => "step",
AttributeType::Pattern(_) => "pattern",
AttributeType::MinLength(_) => "minlength",
AttributeType::MaxLength(_) => "maxlength",
AttributeType::Autocomplete(_) => "autocomplete",
AttributeType::Scope(_) => "scope",
AttributeType::ColSpan(_) => "colspan",
AttributeType::RowSpan(_) => "rowspan",
AttributeType::TabIndex(_) => "tabindex",
AttributeType::Focusable => "tabindex",
AttributeType::Lang(_) => "lang",
AttributeType::Dir(_) => "dir",
AttributeType::ContentEditable(_) => "contenteditable",
AttributeType::Draggable(_) => "draggable",
AttributeType::Hidden => "hidden",
AttributeType::Data(nv) => nv.attr_name.as_str(),
AttributeType::Custom(nv) => nv.attr_name.as_str(),
}
}
pub fn value(&self) -> AzString {
match self {
AttributeType::Id(v)
| AttributeType::Class(v)
| AttributeType::AriaLabel(v)
| AttributeType::AriaLabelledBy(v)
| AttributeType::AriaDescribedBy(v)
| AttributeType::AriaRole(v)
| AttributeType::Href(v)
| AttributeType::Rel(v)
| AttributeType::Target(v)
| AttributeType::Src(v)
| AttributeType::Alt(v)
| AttributeType::Title(v)
| AttributeType::Name(v)
| AttributeType::Value(v)
| AttributeType::InputType(v)
| AttributeType::Placeholder(v)
| AttributeType::Max(v)
| AttributeType::Min(v)
| AttributeType::Step(v)
| AttributeType::Pattern(v)
| AttributeType::Autocomplete(v)
| AttributeType::Scope(v)
| AttributeType::Lang(v)
| AttributeType::Dir(v) => v.clone(),
AttributeType::AriaState(nv)
| AttributeType::AriaProperty(nv)
| AttributeType::Data(nv)
| AttributeType::Custom(nv) => nv.value.clone(),
AttributeType::MinLength(n)
| AttributeType::MaxLength(n)
| AttributeType::ColSpan(n)
| AttributeType::RowSpan(n)
| AttributeType::TabIndex(n) => n.to_string().into(),
AttributeType::Focusable => "0".into(),
AttributeType::ContentEditable(b) | AttributeType::Draggable(b) => {
if *b {
"true".into()
} else {
"false".into()
}
}
AttributeType::Required
| AttributeType::Disabled
| AttributeType::Readonly
| AttributeType::Checked
| AttributeType::Selected
| AttributeType::Hidden => "".into(), }
}
pub fn is_boolean(&self) -> bool {
matches!(
self,
AttributeType::Required
| AttributeType::Disabled
| AttributeType::Readonly
| AttributeType::Checked
| AttributeType::Selected
| AttributeType::Hidden
)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct SmallAriaInfo {
pub label: OptionString,
pub role: OptionAccessibilityRole,
pub description: OptionString,
}
impl_option!(
SmallAriaInfo,
OptionSmallAriaInfo,
copy = false,
[Debug, Clone, PartialEq, Eq, Hash]
);
impl SmallAriaInfo {
pub fn label<S: Into<AzString>>(text: S) -> Self {
Self {
label: OptionString::Some(text.into()),
role: OptionAccessibilityRole::None,
description: OptionString::None,
}
}
pub fn with_role(mut self, role: AccessibilityRole) -> Self {
self.role = OptionAccessibilityRole::Some(role);
self
}
pub fn with_description<S: Into<AzString>>(mut self, desc: S) -> Self {
self.description = OptionString::Some(desc.into());
self
}
pub fn to_full_info(&self) -> AccessibilityInfo {
AccessibilityInfo {
accessibility_name: self.label.clone(),
accessibility_value: OptionString::None,
role: match self.role {
OptionAccessibilityRole::Some(r) => r,
OptionAccessibilityRole::None => AccessibilityRole::Unknown,
},
states: Vec::new().into(),
accelerator: OptionVirtualKeyCodeCombo::None,
default_action: OptionString::None,
supported_actions: Vec::new().into(),
is_live_region: false,
labelled_by: OptionDomNodeId::None,
described_by: OptionDomNodeId::None,
}
}
}
#[repr(C)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct NodeData {
pub node_type: NodeType,
pub dataset: OptionRefAny,
pub ids_and_classes: IdOrClassVec,
pub attributes: AttributeTypeVec,
pub callbacks: CoreCallbackDataVec,
pub css_props: CssPropertyWithConditionsVec,
pub tab_index: OptionTabIndex,
pub contenteditable: bool,
extra: Option<Box<NodeDataExt>>,
}
impl_option!(
NodeData,
OptionNodeData,
copy = false,
[Debug, PartialEq, Eq, PartialOrd, Ord]
);
impl Hash for NodeData {
fn hash<H: Hasher>(&self, state: &mut H) {
self.node_type.hash(state);
self.dataset.hash(state);
self.ids_and_classes.as_ref().hash(state);
self.attributes.as_ref().hash(state);
self.contenteditable.hash(state);
for callback in self.callbacks.as_ref().iter() {
callback.event.hash(state);
callback.callback.hash(state);
callback.refany.get_type_id().hash(state);
}
for prop in self.css_props.as_ref().iter() {
core::mem::discriminant(&prop.property).hash(state);
}
if let Some(ext) = self.extra.as_ref() {
if let Some(c) = ext.clip_mask.as_ref() {
c.hash(state);
}
if let Some(c) = ext.menu_bar.as_ref() {
c.hash(state);
}
if let Some(c) = ext.context_menu.as_ref() {
c.hash(state);
}
}
}
}
#[repr(C)]
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct NodeDataExt {
pub clip_mask: Option<ImageMask>,
pub accessibility: Option<Box<AccessibilityInfo>>,
pub menu_bar: Option<Box<Menu>>,
pub context_menu: Option<Box<Menu>>,
pub is_anonymous: bool,
pub key: Option<u64>,
pub dataset_merge_callback: Option<DatasetMergeCallback>,
}
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub struct DatasetMergeCallback {
pub cb: DatasetMergeCallbackType,
pub callable: OptionRefAny,
}
impl core::fmt::Debug for DatasetMergeCallback {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DatasetMergeCallback")
.field("cb", &(self.cb as usize))
.field("callable", &self.callable)
.finish()
}
}
impl From<DatasetMergeCallbackType> for DatasetMergeCallback {
fn from(cb: DatasetMergeCallbackType) -> Self {
DatasetMergeCallback {
cb,
callable: OptionRefAny::None,
}
}
}
impl_option!(
DatasetMergeCallback,
OptionDatasetMergeCallback,
copy = false,
[Debug, Clone]
);
pub type DatasetMergeCallbackType = extern "C" fn(RefAny, RefAny) -> RefAny;
#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[repr(C)]
pub struct AccessibilityInfo {
pub accessibility_name: OptionString,
pub accessibility_value: OptionString,
pub role: AccessibilityRole,
pub states: AccessibilityStateVec,
pub accelerator: OptionVirtualKeyCodeCombo,
pub default_action: OptionString,
pub supported_actions: AccessibilityActionVec,
pub is_live_region: bool,
pub labelled_by: OptionDomNodeId,
pub described_by: OptionDomNodeId,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, u8)]
pub enum AccessibilityAction {
Default,
Focus,
Blur,
Collapse,
Expand,
ScrollIntoView,
Increment,
Decrement,
ShowContextMenu,
HideTooltip,
ShowTooltip,
ScrollUp,
ScrollDown,
ScrollLeft,
ScrollRight,
ReplaceSelectedText(AzString),
ScrollToPoint(LogicalPosition),
SetScrollOffset(LogicalPosition),
SetTextSelection(TextSelectionStartEnd),
SetSequentialFocusNavigationStartingPoint,
SetValue(AzString),
SetNumericValue(FloatValue),
CustomAction(i32),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct TextSelectionStartEnd {
pub selection_start: usize,
pub selection_end: usize,
}
impl_vec!(AccessibilityAction, AccessibilityActionVec, AccessibilityActionVecDestructor, AccessibilityActionVecDestructorType, AccessibilityActionVecSlice, OptionAccessibilityAction);
impl_vec_debug!(AccessibilityAction, AccessibilityActionVec);
impl_vec_clone!(
AccessibilityAction,
AccessibilityActionVec,
AccessibilityActionVecDestructor
);
impl_vec_partialeq!(AccessibilityAction, AccessibilityActionVec);
impl_vec_eq!(AccessibilityAction, AccessibilityActionVec);
impl_vec_partialord!(AccessibilityAction, AccessibilityActionVec);
impl_vec_ord!(AccessibilityAction, AccessibilityActionVec);
impl_vec_hash!(AccessibilityAction, AccessibilityActionVec);
impl_option![
AccessibilityAction,
OptionAccessibilityAction,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
];
impl_option!(
AccessibilityInfo,
OptionAccessibilityInfo,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum AccessibilityRole {
TitleBar,
MenuBar,
ScrollBar,
Grip,
Sound,
Cursor,
Caret,
Alert,
Window,
Client,
MenuPopup,
MenuItem,
Tooltip,
Application,
Document,
Pane,
Chart,
Dialog,
Border,
Grouping,
Separator,
Toolbar,
StatusBar,
Table,
ColumnHeader,
RowHeader,
Column,
Row,
Cell,
Link,
HelpBalloon,
Character,
List,
ListItem,
Outline,
OutlineItem,
PageTab,
PropertyPage,
Indicator,
Graphic,
StaticText,
Text,
PushButton,
CheckButton,
RadioButton,
ComboBox,
DropList,
ProgressBar,
Dial,
HotkeyField,
Slider,
SpinButton,
Diagram,
Animation,
Equation,
ButtonDropdown,
ButtonMenu,
ButtonDropdownGrid,
Whitespace,
PageTabList,
Clock,
SplitButton,
IpAddress,
Nothing,
Unknown,
}
impl_option!(
AccessibilityRole,
OptionAccessibilityRole,
[Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[repr(C)]
pub enum AccessibilityState {
Unavailable,
Selected,
Focused,
Checked,
Readonly,
Default,
Expanded,
Collapsed,
Busy,
Offscreen,
Focusable,
Selectable,
Linked,
Traversed,
Multiselectable,
Protected,
}
impl_option!(
AccessibilityState,
OptionAccessibilityState,
[Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
);
impl_vec!(AccessibilityState, AccessibilityStateVec, AccessibilityStateVecDestructor, AccessibilityStateVecDestructorType, AccessibilityStateVecSlice, OptionAccessibilityState);
impl_vec_clone!(
AccessibilityState,
AccessibilityStateVec,
AccessibilityStateVecDestructor
);
impl_vec_debug!(AccessibilityState, AccessibilityStateVec);
impl_vec_partialeq!(AccessibilityState, AccessibilityStateVec);
impl_vec_partialord!(AccessibilityState, AccessibilityStateVec);
impl_vec_eq!(AccessibilityState, AccessibilityStateVec);
impl_vec_ord!(AccessibilityState, AccessibilityStateVec);
impl_vec_hash!(AccessibilityState, AccessibilityStateVec);
impl Clone for NodeData {
#[inline]
fn clone(&self) -> Self {
Self {
node_type: self.node_type.into_library_owned_nodetype(),
dataset: match &self.dataset {
OptionRefAny::None => OptionRefAny::None,
OptionRefAny::Some(s) => OptionRefAny::Some(s.clone()),
},
ids_and_classes: self.ids_and_classes.clone(),
attributes: self.attributes.clone(),
css_props: self.css_props.clone(),
callbacks: self.callbacks.clone(),
tab_index: self.tab_index,
contenteditable: self.contenteditable,
extra: self.extra.clone(),
}
}
}
impl_vec!(NodeData, NodeDataVec, NodeDataVecDestructor, NodeDataVecDestructorType, NodeDataVecSlice, OptionNodeData);
impl_vec_clone!(NodeData, NodeDataVec, NodeDataVecDestructor);
impl_vec_mut!(NodeData, NodeDataVec);
impl_vec_debug!(NodeData, NodeDataVec);
impl_vec_partialord!(NodeData, NodeDataVec);
impl_vec_ord!(NodeData, NodeDataVec);
impl_vec_partialeq!(NodeData, NodeDataVec);
impl_vec_eq!(NodeData, NodeDataVec);
impl_vec_hash!(NodeData, NodeDataVec);
impl NodeDataVec {
#[inline]
pub fn as_container<'a>(&'a self) -> NodeDataContainerRef<'a, NodeData> {
NodeDataContainerRef {
internal: self.as_ref(),
}
}
#[inline]
pub fn as_container_mut<'a>(&'a mut self) -> NodeDataContainerRefMut<'a, NodeData> {
NodeDataContainerRefMut {
internal: self.as_mut(),
}
}
}
unsafe impl Send for NodeData {}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[repr(C, u8)]
pub enum TabIndex {
Auto,
OverrideInParent(u32),
NoKeyboardFocus,
}
impl_option!(
TabIndex,
OptionTabIndex,
[Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl TabIndex {
pub fn get_index(&self) -> isize {
use self::TabIndex::*;
match self {
Auto => 0,
OverrideInParent(x) => *x as isize,
NoKeyboardFocus => -1,
}
}
}
impl Default for TabIndex {
fn default() -> Self {
TabIndex::Auto
}
}
impl Default for NodeData {
fn default() -> Self {
NodeData::create_node(NodeType::Div)
}
}
impl fmt::Display for NodeData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let html_type = self.node_type.get_path();
let attributes_string = node_data_to_string(&self);
match self.node_type.format() {
Some(content) => write!(
f,
"<{}{}>{}</{}>",
html_type, attributes_string, content, html_type
),
None => write!(f, "<{}{}/>", html_type, attributes_string),
}
}
}
fn node_data_to_string(node_data: &NodeData) -> String {
let mut id_string = String::new();
let ids = node_data
.ids_and_classes
.as_ref()
.iter()
.filter_map(|s| s.as_id())
.collect::<Vec<_>>()
.join(" ");
if !ids.is_empty() {
id_string = format!(" id=\"{}\" ", ids);
}
let mut class_string = String::new();
let classes = node_data
.ids_and_classes
.as_ref()
.iter()
.filter_map(|s| s.as_class())
.collect::<Vec<_>>()
.join(" ");
if !classes.is_empty() {
class_string = format!(" class=\"{}\" ", classes);
}
let mut tabindex_string = String::new();
if let Some(tab_index) = node_data.get_tab_index() {
tabindex_string = format!(" tabindex=\"{}\" ", tab_index.get_index());
};
format!("{}{}{}", id_string, class_string, tabindex_string)
}
impl NodeData {
#[inline]
pub const fn create_node(node_type: NodeType) -> Self {
Self {
node_type,
dataset: OptionRefAny::None,
ids_and_classes: IdOrClassVec::from_const_slice(&[]),
attributes: AttributeTypeVec::from_const_slice(&[]),
callbacks: CoreCallbackDataVec::from_const_slice(&[]),
css_props: CssPropertyWithConditionsVec::from_const_slice(&[]),
tab_index: OptionTabIndex::None,
contenteditable: false,
extra: None,
}
}
#[inline(always)]
pub const fn create_body() -> Self {
Self::create_node(NodeType::Body)
}
#[inline(always)]
pub const fn create_div() -> Self {
Self::create_node(NodeType::Div)
}
#[inline(always)]
pub const fn create_br() -> Self {
Self::create_node(NodeType::Br)
}
#[inline(always)]
pub fn create_text<S: Into<AzString>>(value: S) -> Self {
Self::create_node(NodeType::Text(value.into()))
}
#[inline(always)]
pub fn create_image(image: ImageRef) -> Self {
Self::create_node(NodeType::Image(image))
}
#[inline(always)]
pub fn create_iframe(data: RefAny, callback: impl Into<IFrameCallback>) -> Self {
Self::create_node(NodeType::IFrame(IFrameNode {
callback: callback.into(),
refany: data,
}))
}
#[inline]
pub fn is_node_type(&self, searched_type: NodeType) -> bool {
self.node_type == searched_type
}
pub fn has_id(&self, id: &str) -> bool {
self.ids_and_classes
.iter()
.any(|id_or_class| id_or_class.as_id() == Some(id))
}
pub fn has_class(&self, class: &str) -> bool {
self.ids_and_classes
.iter()
.any(|id_or_class| id_or_class.as_class() == Some(class))
}
pub fn has_context_menu(&self) -> bool {
self.extra
.as_ref()
.map(|m| m.context_menu.is_some())
.unwrap_or(false)
}
pub fn is_text_node(&self) -> bool {
match self.node_type {
NodeType::Text(_) => true,
_ => false,
}
}
pub fn is_iframe_node(&self) -> bool {
match self.node_type {
NodeType::IFrame(_) => true,
_ => false,
}
}
#[inline(always)]
pub const fn get_node_type(&self) -> &NodeType {
&self.node_type
}
#[inline(always)]
pub fn get_dataset_mut(&mut self) -> &mut OptionRefAny {
&mut self.dataset
}
#[inline(always)]
pub const fn get_dataset(&self) -> &OptionRefAny {
&self.dataset
}
#[inline(always)]
pub const fn get_ids_and_classes(&self) -> &IdOrClassVec {
&self.ids_and_classes
}
#[inline(always)]
pub const fn get_callbacks(&self) -> &CoreCallbackDataVec {
&self.callbacks
}
#[inline(always)]
pub const fn get_css_props(&self) -> &CssPropertyWithConditionsVec {
&self.css_props
}
#[inline]
pub fn get_clip_mask(&self) -> Option<&ImageMask> {
self.extra.as_ref().and_then(|e| e.clip_mask.as_ref())
}
#[inline]
pub fn get_tab_index(&self) -> Option<&TabIndex> {
self.tab_index.as_ref()
}
#[inline]
pub fn get_accessibility_info(&self) -> Option<&Box<AccessibilityInfo>> {
self.extra.as_ref().and_then(|e| e.accessibility.as_ref())
}
#[inline]
pub fn get_menu_bar(&self) -> Option<&Box<Menu>> {
self.extra.as_ref().and_then(|e| e.menu_bar.as_ref())
}
#[inline]
pub fn get_context_menu(&self) -> Option<&Box<Menu>> {
self.extra.as_ref().and_then(|e| e.context_menu.as_ref())
}
#[inline]
pub fn is_anonymous(&self) -> bool {
self.extra.as_ref().map(|e| e.is_anonymous).unwrap_or(false)
}
#[inline(always)]
pub fn set_node_type(&mut self, node_type: NodeType) {
self.node_type = node_type;
}
#[inline(always)]
pub fn set_dataset(&mut self, data: OptionRefAny) {
self.dataset = data;
}
#[inline(always)]
pub fn set_ids_and_classes(&mut self, ids_and_classes: IdOrClassVec) {
self.ids_and_classes = ids_and_classes;
}
#[inline(always)]
pub fn set_callbacks(&mut self, callbacks: CoreCallbackDataVec) {
self.callbacks = callbacks;
}
#[inline(always)]
pub fn set_css_props(&mut self, css_props: CssPropertyWithConditionsVec) {
self.css_props = css_props;
}
#[inline]
pub fn set_clip_mask(&mut self, clip_mask: ImageMask) {
self.extra
.get_or_insert_with(|| Box::new(NodeDataExt::default()))
.clip_mask = Some(clip_mask);
}
#[inline]
pub fn set_tab_index(&mut self, tab_index: TabIndex) {
self.tab_index = Some(tab_index).into();
}
#[inline]
pub fn set_contenteditable(&mut self, contenteditable: bool) {
self.contenteditable = contenteditable;
}
#[inline]
pub fn is_contenteditable(&self) -> bool {
self.contenteditable
}
#[inline]
pub fn set_accessibility_info(&mut self, accessibility_info: AccessibilityInfo) {
self.extra
.get_or_insert_with(|| Box::new(NodeDataExt::default()))
.accessibility = Some(Box::new(accessibility_info));
}
#[inline]
pub fn set_anonymous(&mut self, is_anonymous: bool) {
self.extra
.get_or_insert_with(|| Box::new(NodeDataExt::default()))
.is_anonymous = is_anonymous;
}
#[inline]
pub fn set_menu_bar(&mut self, menu_bar: Menu) {
self.extra
.get_or_insert_with(|| Box::new(NodeDataExt::default()))
.menu_bar = Some(Box::new(menu_bar));
}
#[inline]
pub fn set_context_menu(&mut self, context_menu: Menu) {
self.extra
.get_or_insert_with(|| Box::new(NodeDataExt::default()))
.context_menu = Some(Box::new(context_menu));
}
#[inline]
pub fn set_key<K: core::hash::Hash>(&mut self, key: K) {
use highway::{HighwayHash, HighwayHasher, Key};
let mut hasher = HighwayHasher::new(Key([0; 4]));
key.hash(&mut hasher);
self.extra
.get_or_insert_with(|| Box::new(NodeDataExt::default()))
.key = Some(hasher.finalize64());
}
#[inline]
pub fn get_key(&self) -> Option<u64> {
self.extra.as_ref().and_then(|ext| ext.key)
}
#[inline]
pub fn set_merge_callback<C: Into<DatasetMergeCallback>>(&mut self, callback: C) {
self.extra
.get_or_insert_with(|| Box::new(NodeDataExt::default()))
.dataset_merge_callback = Some(callback.into());
}
#[inline]
pub fn get_merge_callback(&self) -> Option<DatasetMergeCallback> {
self.extra.as_ref().and_then(|ext| ext.dataset_merge_callback.clone())
}
#[inline]
pub fn with_menu_bar(mut self, menu_bar: Menu) -> Self {
self.set_menu_bar(menu_bar);
self
}
#[inline]
pub fn with_context_menu(mut self, context_menu: Menu) -> Self {
self.set_context_menu(context_menu);
self
}
#[inline]
pub fn add_callback<C: Into<CoreCallback>>(
&mut self,
event: EventFilter,
data: RefAny,
callback: C,
) {
let callback = callback.into();
let mut v: CoreCallbackDataVec = Vec::new().into();
mem::swap(&mut v, &mut self.callbacks);
let mut v = v.into_library_owned_vec();
v.push(CoreCallbackData {
event,
refany: data,
callback,
});
self.callbacks = v.into();
}
#[inline]
pub fn add_id(&mut self, s: AzString) {
let mut v: IdOrClassVec = Vec::new().into();
mem::swap(&mut v, &mut self.ids_and_classes);
let mut v = v.into_library_owned_vec();
v.push(IdOrClass::Id(s));
self.ids_and_classes = v.into();
}
#[inline]
pub fn add_class(&mut self, s: AzString) {
let mut v: IdOrClassVec = Vec::new().into();
mem::swap(&mut v, &mut self.ids_and_classes);
let mut v = v.into_library_owned_vec();
v.push(IdOrClass::Class(s));
self.ids_and_classes = v.into();
}
#[inline]
pub fn add_css_property(&mut self, p: CssPropertyWithConditions) {
let mut v: CssPropertyWithConditionsVec = Vec::new().into();
mem::swap(&mut v, &mut self.css_props);
let mut v = v.into_library_owned_vec();
v.push(p);
self.css_props = v.into();
}
pub fn calculate_node_data_hash(&self) -> DomNodeHash {
use highway::{HighwayHash, HighwayHasher, Key};
let mut hasher = HighwayHasher::new(Key([0; 4]));
self.hash(&mut hasher);
let h = hasher.finalize64();
DomNodeHash { inner: h }
}
pub fn calculate_structural_hash(&self) -> DomNodeHash {
use highway::{HighwayHash, HighwayHasher, Key};
use core::hash::Hasher as StdHasher;
let mut hasher = HighwayHasher::new(Key([0; 4]));
core::mem::discriminant(&self.node_type).hash(&mut hasher);
if let NodeType::IFrame(ref iframe) = self.node_type {
iframe.hash(&mut hasher);
}
if let NodeType::Image(ref img_ref) = self.node_type {
img_ref.hash(&mut hasher);
}
self.ids_and_classes.as_ref().hash(&mut hasher);
for attr in self.attributes.as_ref().iter() {
if !matches!(attr, AttributeType::ContentEditable(_)) {
attr.hash(&mut hasher);
}
}
for callback in self.callbacks.as_ref().iter() {
callback.event.hash(&mut hasher);
}
let h = hasher.finalize64();
DomNodeHash { inner: h }
}
#[inline(always)]
pub fn with_tab_index(mut self, tab_index: TabIndex) -> Self {
self.set_tab_index(tab_index);
self
}
#[inline(always)]
pub fn with_contenteditable(mut self, contenteditable: bool) -> Self {
self.set_contenteditable(contenteditable);
self
}
#[inline(always)]
pub fn with_node_type(mut self, node_type: NodeType) -> Self {
self.set_node_type(node_type);
self
}
#[inline(always)]
pub fn with_callback<C: Into<CoreCallback>>(
mut self,
event: EventFilter,
data: RefAny,
callback: C,
) -> Self {
self.add_callback(event, data, callback);
self
}
#[inline(always)]
pub fn with_dataset(mut self, data: OptionRefAny) -> Self {
self.dataset = data;
self
}
#[inline(always)]
pub fn with_ids_and_classes(mut self, ids_and_classes: IdOrClassVec) -> Self {
self.ids_and_classes = ids_and_classes;
self
}
#[inline(always)]
pub fn with_callbacks(mut self, callbacks: CoreCallbackDataVec) -> Self {
self.callbacks = callbacks;
self
}
#[inline(always)]
pub fn with_css_props(mut self, css_props: CssPropertyWithConditionsVec) -> Self {
self.css_props = css_props;
self
}
#[inline]
pub fn with_key<K: core::hash::Hash>(mut self, key: K) -> Self {
self.set_key(key);
self
}
#[inline]
pub fn with_merge_callback<C: Into<DatasetMergeCallback>>(mut self, callback: C) -> Self {
self.set_merge_callback(callback);
self
}
pub fn set_inline_style(&mut self, style: &str) {
let parsed = CssPropertyWithConditionsVec::parse(style);
let parsed_vec = parsed.into_library_owned_vec();
let mut current = Vec::new().into();
mem::swap(&mut current, &mut self.css_props);
let mut v = current.into_library_owned_vec();
v.extend(parsed_vec);
self.css_props = v.into();
}
pub fn with_inline_style(mut self, style: &str) -> Self {
self.set_inline_style(style);
self
}
pub fn set_css(&mut self, style: &str) {
let parsed = CssPropertyWithConditionsVec::parse(style);
let mut current = Vec::new().into();
mem::swap(&mut current, &mut self.css_props);
let mut v = current.into_library_owned_vec();
v.extend(parsed.into_library_owned_vec());
self.css_props = v.into();
}
pub fn with_css(mut self, style: &str) -> Self {
self.set_css(style);
self
}
pub fn set_inline_hover_style(&mut self, style: &str) {
let parsed = CssPropertyWithConditionsVec::parse_hover(style);
let mut current = Vec::new().into();
mem::swap(&mut current, &mut self.css_props);
let mut v = current.into_library_owned_vec();
v.extend(parsed.into_library_owned_vec());
self.css_props = v.into();
}
pub fn with_inline_hover_style(mut self, style: &str) -> Self {
self.set_inline_hover_style(style);
self
}
pub fn set_inline_active_style(&mut self, style: &str) {
let parsed = CssPropertyWithConditionsVec::parse_active(style);
let mut current = Vec::new().into();
mem::swap(&mut current, &mut self.css_props);
let mut v = current.into_library_owned_vec();
v.extend(parsed.into_library_owned_vec());
self.css_props = v.into();
}
pub fn with_inline_active_style(mut self, style: &str) -> Self {
self.set_inline_active_style(style);
self
}
pub fn set_inline_focus_style(&mut self, style: &str) {
let parsed = CssPropertyWithConditionsVec::parse_focus(style);
let mut current = Vec::new().into();
mem::swap(&mut current, &mut self.css_props);
let mut v = current.into_library_owned_vec();
v.extend(parsed.into_library_owned_vec());
self.css_props = v.into();
}
pub fn with_inline_focus_style(mut self, style: &str) -> Self {
self.set_inline_focus_style(style);
self
}
#[inline(always)]
pub fn swap_with_default(&mut self) -> Self {
let mut s = NodeData::create_div();
mem::swap(&mut s, self);
s
}
#[inline]
pub fn copy_special(&self) -> Self {
Self {
node_type: self.node_type.into_library_owned_nodetype(),
dataset: match &self.dataset {
OptionRefAny::None => OptionRefAny::None,
OptionRefAny::Some(s) => OptionRefAny::Some(s.clone()),
},
ids_and_classes: self.ids_and_classes.clone(),
attributes: self.attributes.clone(),
css_props: self.css_props.clone(),
callbacks: self.callbacks.clone(),
tab_index: self.tab_index,
contenteditable: self.contenteditable,
extra: self.extra.clone(),
}
}
pub fn is_focusable(&self) -> bool {
self.get_tab_index().is_some()
|| self
.get_callbacks()
.iter()
.any(|cb| cb.event.is_focus_callback())
}
pub fn has_activation_behavior(&self) -> bool {
use crate::events::{EventFilter, HoverEventFilter};
let has_click_callback = self
.get_callbacks()
.iter()
.any(|cb| matches!(
cb.event,
EventFilter::Hover(HoverEventFilter::MouseUp)
| EventFilter::Hover(HoverEventFilter::LeftMouseUp)
));
if has_click_callback {
return true;
}
if let Some(ref ext) = self.extra {
if let Some(ref accessibility) = ext.accessibility {
use crate::dom::AccessibilityRole;
match accessibility.role {
AccessibilityRole::PushButton | AccessibilityRole::Link
| AccessibilityRole::CheckButton | AccessibilityRole::RadioButton | AccessibilityRole::MenuItem
| AccessibilityRole::PageTab => return true,
_ => {}
}
}
}
false
}
pub fn is_activatable(&self) -> bool {
if !self.has_activation_behavior() {
return false;
}
if let Some(ref ext) = self.extra {
if let Some(ref accessibility) = ext.accessibility {
if accessibility
.states
.as_ref()
.iter()
.any(|s| matches!(s, AccessibilityState::Unavailable))
{
return false;
}
}
}
true
}
pub fn get_effective_tabindex(&self) -> Option<i32> {
match self.tab_index {
OptionTabIndex::None => {
if self.get_callbacks().iter().any(|cb| cb.event.is_focus_callback()) {
Some(0)
} else {
None
}
}
OptionTabIndex::Some(tab_idx) => {
match tab_idx {
TabIndex::Auto => Some(0),
TabIndex::OverrideInParent(n) => Some(n as i32),
TabIndex::NoKeyboardFocus => Some(-1),
}
}
}
}
pub fn get_iframe_node(&mut self) -> Option<&mut IFrameNode> {
match &mut self.node_type {
NodeType::IFrame(i) => Some(i),
_ => None,
}
}
pub fn get_render_image_callback_node<'a>(
&'a mut self,
) -> Option<(&'a mut CoreImageCallback, ImageRefHash)> {
match &mut self.node_type {
NodeType::Image(img) => {
let hash = image_ref_get_hash(&img);
img.get_image_callback_mut().map(|r| (r, hash))
}
_ => None,
}
}
pub fn debug_print_start(
&self,
css_cache: &CssPropertyCache,
node_id: &NodeId,
node_state: &StyledNodeState,
) -> String {
let html_type = self.node_type.get_path();
let attributes_string = node_data_to_string(&self);
let style = css_cache.get_computed_css_style_string(&self, node_id, node_state);
format!(
"<{} data-az-node-id=\"{}\" {} {style}>",
html_type,
node_id.index(),
attributes_string,
style = if style.trim().is_empty() {
String::new()
} else {
format!("style=\"{style}\"")
}
)
}
pub fn debug_print_end(&self) -> String {
let html_type = self.node_type.get_path();
format!("</{}>", html_type)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[repr(C)]
pub struct DomId {
pub inner: usize,
}
impl fmt::Display for DomId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.inner)
}
}
impl DomId {
pub const ROOT_ID: DomId = DomId { inner: 0 };
}
impl Default for DomId {
fn default() -> DomId {
DomId::ROOT_ID
}
}
impl_option!(
DomId,
OptionDomId,
[Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_vec!(DomId, DomIdVec, DomIdVecDestructor, DomIdVecDestructorType, DomIdVecSlice, OptionDomId);
impl_vec_debug!(DomId, DomIdVec);
impl_vec_clone!(DomId, DomIdVec, DomIdVecDestructor);
impl_vec_partialeq!(DomId, DomIdVec);
impl_vec_partialord!(DomId, DomIdVec);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct DomNodeId {
pub dom: DomId,
pub node: NodeHierarchyItemId,
}
impl_option!(
DomNodeId,
OptionDomNodeId,
[Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl DomNodeId {
pub const ROOT: DomNodeId = DomNodeId {
dom: DomId::ROOT_ID,
node: NodeHierarchyItemId::NONE,
};
}
#[repr(C)]
#[derive(PartialEq, Clone, Eq, Hash, PartialOrd, Ord)]
pub struct Dom {
pub root: NodeData,
pub children: DomVec,
pub estimated_total_children: usize,
}
impl_option!(
Dom,
OptionDom,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_vec!(Dom, DomVec, DomVecDestructor, DomVecDestructorType, DomVecSlice, OptionDom);
impl_vec_clone!(Dom, DomVec, DomVecDestructor);
impl_vec_mut!(Dom, DomVec);
impl_vec_debug!(Dom, DomVec);
impl_vec_partialord!(Dom, DomVec);
impl_vec_ord!(Dom, DomVec);
impl_vec_partialeq!(Dom, DomVec);
impl_vec_eq!(Dom, DomVec);
impl_vec_hash!(Dom, DomVec);
impl Dom {
#[inline(always)]
pub fn create_node(node_type: NodeType) -> Self {
Self {
root: NodeData::create_node(node_type),
children: Vec::new().into(),
estimated_total_children: 0,
}
}
#[inline(always)]
pub fn from_data(node_data: NodeData) -> Self {
Self {
root: node_data,
children: Vec::new().into(),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_html() -> Self {
Self {
root: NodeData::create_node(NodeType::Html),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_head() -> Self {
Self {
root: NodeData::create_node(NodeType::Head),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_body() -> Self {
Self {
root: NodeData::create_node(NodeType::Body),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_div() -> Self {
Self {
root: NodeData::create_node(NodeType::Div),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_article() -> Self {
Self {
root: NodeData::create_node(NodeType::Article),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_section() -> Self {
Self {
root: NodeData::create_node(NodeType::Section),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_nav() -> Self {
Self {
root: NodeData::create_node(NodeType::Nav),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_aside() -> Self {
Self {
root: NodeData::create_node(NodeType::Aside),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_header() -> Self {
Self {
root: NodeData::create_node(NodeType::Header),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_footer() -> Self {
Self {
root: NodeData::create_node(NodeType::Footer),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_main() -> Self {
Self {
root: NodeData::create_node(NodeType::Main),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_figure() -> Self {
Self {
root: NodeData::create_node(NodeType::Figure),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_figcaption() -> Self {
Self {
root: NodeData::create_node(NodeType::FigCaption),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_details() -> Self {
Self {
root: NodeData::create_node(NodeType::Details),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline]
pub fn summary<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::Summary),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline(always)]
pub const fn create_dialog() -> Self {
Self {
root: NodeData::create_node(NodeType::Dialog),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_br() -> Self {
Self {
root: NodeData::create_node(NodeType::Br),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub fn create_text<S: Into<AzString>>(value: S) -> Self {
Self::create_node(NodeType::Text(value.into()))
}
#[inline(always)]
pub fn create_image(image: ImageRef) -> Self {
Self::create_node(NodeType::Image(image))
}
#[inline(always)]
pub fn create_icon<S: Into<AzString>>(icon_name: S) -> Self {
Self::create_node(NodeType::Icon(icon_name.into()))
}
#[inline(always)]
pub fn create_iframe(data: RefAny, callback: impl Into<IFrameCallback>) -> Self {
Self::create_node(NodeType::IFrame(IFrameNode {
callback: callback.into(),
refany: data,
}))
}
#[inline(always)]
pub const fn create_p() -> Self {
Self {
root: NodeData::create_node(NodeType::P),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline]
pub fn h1<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::H1),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline]
pub fn h2<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::H2),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline]
pub fn h3<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::H3),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline]
pub fn h4<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::H4),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline]
pub fn h5<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::H5),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline]
pub fn h6<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::H6),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline]
pub fn span<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::Span),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline]
pub fn strong<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::Strong),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline]
pub fn em<S: Into<AzString>>(text: S) -> Self {
Self {
root: NodeData::create_node(NodeType::Em),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
.with_child(Self::create_text(text))
}
#[inline]
pub fn code<S: Into<AzString>>(code: S) -> Self {
Self::create_node(NodeType::Code).with_child(Self::create_text(code))
}
#[inline]
pub fn pre<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Pre).with_child(Self::create_text(text))
}
#[inline]
pub fn blockquote<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::BlockQuote).with_child(Self::create_text(text))
}
#[inline]
pub fn cite<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Cite).with_child(Self::create_text(text))
}
#[inline]
pub fn create_abbr(abbr_text: AzString, title: AzString) -> Self {
Self::create_node(NodeType::Abbr)
.with_attribute(AttributeType::Title(title))
.with_child(Self::create_text(abbr_text))
}
#[inline]
pub fn kbd<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Kbd).with_child(Self::create_text(text))
}
#[inline]
pub fn samp<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Samp).with_child(Self::create_text(text))
}
#[inline]
pub fn var<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Var).with_child(Self::create_text(text))
}
#[inline]
pub fn sub<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Sub).with_child(Self::create_text(text))
}
#[inline]
pub fn sup<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Sup).with_child(Self::create_text(text))
}
#[inline]
pub fn u<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::U).with_child(Self::create_text(text))
}
#[inline]
pub fn s<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::S).with_child(Self::create_text(text))
}
#[inline]
pub fn mark<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Mark).with_child(Self::create_text(text))
}
#[inline]
pub fn del<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Del).with_child(Self::create_text(text))
}
#[inline]
pub fn ins<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Ins).with_child(Self::create_text(text))
}
#[inline]
pub fn dfn<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Dfn).with_child(Self::create_text(text))
}
#[inline]
pub fn create_time(text: AzString, datetime: OptionString) -> Self {
let mut element = Self::create_node(NodeType::Time).with_child(Self::create_text(text));
if let OptionString::Some(dt) = datetime {
element = element.with_attribute(AttributeType::Custom(AttributeNameValue {
attr_name: "datetime".into(),
value: dt,
}));
}
element
}
#[inline]
pub fn bdo<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Bdo).with_child(Self::create_text(text))
}
#[inline]
pub fn create_a(href: AzString, label: OptionString) -> Self {
let mut link = Self::create_node(NodeType::A).with_attribute(AttributeType::Href(href));
if let OptionString::Some(text) = label {
link = link.with_child(Self::create_text(text));
}
link
}
#[inline]
pub fn create_button(text: AzString) -> Self {
Self::create_node(NodeType::Button).with_child(Self::create_text(text))
}
#[inline]
pub fn create_label(for_id: AzString, text: AzString) -> Self {
Self::create_node(NodeType::Label)
.with_attribute(AttributeType::Custom(AttributeNameValue {
attr_name: "for".into(),
value: for_id,
}))
.with_child(Self::create_text(text))
}
#[inline]
pub fn create_input(input_type: AzString, name: AzString, label: AzString) -> Self {
Self::create_node(NodeType::Input)
.with_attribute(AttributeType::InputType(input_type))
.with_attribute(AttributeType::Name(name))
.with_attribute(AttributeType::AriaLabel(label))
}
#[inline]
pub fn create_textarea(name: AzString, label: AzString) -> Self {
Self::create_node(NodeType::TextArea)
.with_attribute(AttributeType::Name(name))
.with_attribute(AttributeType::AriaLabel(label))
}
#[inline]
pub fn create_select(name: AzString, label: AzString) -> Self {
Self::create_node(NodeType::Select)
.with_attribute(AttributeType::Name(name))
.with_attribute(AttributeType::AriaLabel(label))
}
#[inline]
pub fn create_option(value: AzString, text: AzString) -> Self {
Self::create_node(NodeType::SelectOption)
.with_attribute(AttributeType::Value(value))
.with_child(Self::create_text(text))
}
#[inline(always)]
pub fn create_ul() -> Self {
Self::create_node(NodeType::Ul)
}
#[inline(always)]
pub fn create_ol() -> Self {
Self::create_node(NodeType::Ol)
}
#[inline(always)]
pub fn create_li() -> Self {
Self::create_node(NodeType::Li)
}
#[inline(always)]
pub fn create_table() -> Self {
Self::create_node(NodeType::Table)
}
#[inline(always)]
pub fn create_caption() -> Self {
Self::create_node(NodeType::Caption)
}
#[inline(always)]
pub fn create_thead() -> Self {
Self::create_node(NodeType::THead)
}
#[inline(always)]
pub fn create_tbody() -> Self {
Self::create_node(NodeType::TBody)
}
#[inline(always)]
pub fn create_tfoot() -> Self {
Self::create_node(NodeType::TFoot)
}
#[inline(always)]
pub fn create_tr() -> Self {
Self::create_node(NodeType::Tr)
}
#[inline(always)]
pub fn create_th() -> Self {
Self::create_node(NodeType::Th)
}
#[inline(always)]
pub fn create_td() -> Self {
Self::create_node(NodeType::Td)
}
#[inline(always)]
pub fn create_form() -> Self {
Self::create_node(NodeType::Form)
}
#[inline(always)]
pub fn create_fieldset() -> Self {
Self::create_node(NodeType::FieldSet)
}
#[inline(always)]
pub fn create_legend() -> Self {
Self::create_node(NodeType::Legend)
}
#[inline(always)]
pub fn create_hr() -> Self {
Self::create_node(NodeType::Hr)
}
#[inline(always)]
pub const fn create_address() -> Self {
Self {
root: NodeData::create_node(NodeType::Address),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_dl() -> Self {
Self {
root: NodeData::create_node(NodeType::Dl),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_dt() -> Self {
Self {
root: NodeData::create_node(NodeType::Dt),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_dd() -> Self {
Self {
root: NodeData::create_node(NodeType::Dd),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_colgroup() -> Self {
Self {
root: NodeData::create_node(NodeType::ColGroup),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline]
pub fn create_col(span: i32) -> Self {
Self::create_node(NodeType::Col).with_attribute(AttributeType::ColSpan(span))
}
#[inline]
pub fn create_optgroup(label: AzString) -> Self {
Self::create_node(NodeType::OptGroup).with_attribute(AttributeType::AriaLabel(label))
}
#[inline(always)]
pub const fn create_q() -> Self {
Self {
root: NodeData::create_node(NodeType::Q),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn acronym() -> Self {
Self {
root: NodeData::create_node(NodeType::Acronym),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_menu() -> Self {
Self {
root: NodeData::create_node(NodeType::Menu),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn menuitem() -> Self {
Self {
root: NodeData::create_node(NodeType::MenuItem),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_output() -> Self {
Self {
root: NodeData::create_node(NodeType::Output),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline]
pub fn create_progress(value: f32, max: f32) -> Self {
Self::create_node(NodeType::Progress)
.with_attribute(AttributeType::Custom(AttributeNameValue {
attr_name: "value".into(),
value: value.to_string().into(),
}))
.with_attribute(AttributeType::Custom(AttributeNameValue {
attr_name: "max".into(),
value: max.to_string().into(),
}))
}
#[inline]
pub fn create_meter(value: f32, min: f32, max: f32) -> Self {
Self::create_node(NodeType::Meter)
.with_attribute(AttributeType::Custom(AttributeNameValue {
attr_name: "value".into(),
value: value.to_string().into(),
}))
.with_attribute(AttributeType::Custom(AttributeNameValue {
attr_name: "min".into(),
value: min.to_string().into(),
}))
.with_attribute(AttributeType::Custom(AttributeNameValue {
attr_name: "max".into(),
value: max.to_string().into(),
}))
}
#[inline(always)]
pub const fn create_datalist() -> Self {
Self {
root: NodeData::create_node(NodeType::DataList),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_canvas() -> Self {
Self {
root: NodeData::create_node(NodeType::Canvas),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_object() -> Self {
Self {
root: NodeData::create_node(NodeType::Object),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline]
pub fn create_param(name: AzString, value: AzString) -> Self {
Self::create_node(NodeType::Param)
.with_attribute(AttributeType::Name(name))
.with_attribute(AttributeType::Value(value))
}
#[inline(always)]
pub const fn create_embed() -> Self {
Self {
root: NodeData::create_node(NodeType::Embed),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_audio() -> Self {
Self {
root: NodeData::create_node(NodeType::Audio),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_video() -> Self {
Self {
root: NodeData::create_node(NodeType::Video),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline]
pub fn create_source(src: AzString, media_type: AzString) -> Self {
Self::create_node(NodeType::Source)
.with_attribute(AttributeType::Src(src))
.with_attribute(AttributeType::Custom(AttributeNameValue {
attr_name: "type".into(),
value: media_type,
}))
}
#[inline]
pub fn create_track(src: AzString, kind: AzString) -> Self {
Self::create_node(NodeType::Track)
.with_attribute(AttributeType::Src(src))
.with_attribute(AttributeType::Custom(AttributeNameValue {
attr_name: "kind".into(),
value: kind,
}))
}
#[inline(always)]
pub const fn create_map() -> Self {
Self {
root: NodeData::create_node(NodeType::Map),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_area() -> Self {
Self {
root: NodeData::create_node(NodeType::Area),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline]
pub fn title<S: Into<AzString>>(text: S) -> Self {
Self::create_node(NodeType::Title).with_child(Self::create_text(text))
}
#[inline(always)]
pub const fn meta() -> Self {
Self {
root: NodeData::create_node(NodeType::Meta),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_link() -> Self {
Self {
root: NodeData::create_node(NodeType::Link),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn create_script() -> Self {
Self {
root: NodeData::create_node(NodeType::Script),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline(always)]
pub const fn style_element() -> Self {
Self {
root: NodeData::create_node(NodeType::Style),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
}
}
#[inline]
pub fn base(href: AzString) -> Self {
Self::create_node(NodeType::Base).with_attribute(AttributeType::Href(href))
}
#[inline]
pub fn th_with_scope(scope: AzString, text: AzString) -> Self {
Self::create_node(NodeType::Th)
.with_attribute(AttributeType::Scope(scope))
.with_child(Self::create_text(text))
}
#[inline]
pub fn td_with_text<S: Into<AzString>>(text: S) -> Self {
Self::create_td().with_child(Self::create_text(text))
}
#[inline]
pub fn th_with_text<S: Into<AzString>>(text: S) -> Self {
Self::create_th().with_child(Self::create_text(text))
}
#[inline]
pub fn li_with_text<S: Into<AzString>>(text: S) -> Self {
Self::create_li().with_child(Self::create_text(text))
}
#[inline]
pub fn p_with_text<S: Into<AzString>>(text: S) -> Self {
Self::create_p().with_child(Self::create_text(text))
}
#[inline]
pub fn button_with_aria<S: Into<AzString>>(text: S, aria: SmallAriaInfo) -> Self {
let mut btn = Self::create_button(text.into());
btn.root.set_accessibility_info(aria.to_full_info());
btn
}
#[inline]
pub fn link_with_aria<S1: Into<AzString>, S2: Into<AzString>>(
href: S1,
text: S2,
aria: SmallAriaInfo,
) -> Self {
let mut link = Self::create_a(href.into(), OptionString::Some(text.into()));
link.root.set_accessibility_info(aria.to_full_info());
link
}
#[inline]
pub fn input_with_aria<S1: Into<AzString>, S2: Into<AzString>, S3: Into<AzString>>(
input_type: S1,
name: S2,
label: S3,
aria: SmallAriaInfo,
) -> Self {
let mut input = Self::create_input(input_type.into(), name.into(), label.into());
input.root.set_accessibility_info(aria.to_full_info());
input
}
#[inline]
pub fn textarea_with_aria<S1: Into<AzString>, S2: Into<AzString>>(
name: S1,
label: S2,
aria: SmallAriaInfo,
) -> Self {
let mut textarea = Self::create_textarea(name.into(), label.into());
textarea.root.set_accessibility_info(aria.to_full_info());
textarea
}
#[inline]
pub fn select_with_aria<S1: Into<AzString>, S2: Into<AzString>>(
name: S1,
label: S2,
aria: SmallAriaInfo,
) -> Self {
let mut select = Self::create_select(name.into(), label.into());
select.root.set_accessibility_info(aria.to_full_info());
select
}
#[inline]
pub fn table_with_aria<S: Into<AzString>>(caption: S, aria: SmallAriaInfo) -> Self {
let mut table = Self::create_table()
.with_child(Self::create_caption().with_child(Self::create_text(caption)));
table.root.set_accessibility_info(aria.to_full_info());
table
}
#[inline]
pub fn label_with_aria<S1: Into<AzString>, S2: Into<AzString>>(
for_id: S1,
text: S2,
aria: SmallAriaInfo,
) -> Self {
let mut label = Self::create_label(for_id.into(), text.into());
label.root.set_accessibility_info(aria.to_full_info());
label
}
#[cfg(feature = "xml")]
pub fn from_xml<S: AsRef<str>>(xml_str: S) -> Self {
Self::create_text(format!(
"XML content loaded ({} bytes)",
xml_str.as_ref().len()
))
}
#[cfg(not(feature = "xml"))]
pub fn from_xml<S: AsRef<str>>(xml_str: S) -> Self {
Self::create_text(format!(
"XML parsing requires 'xml' feature ({} bytes)",
xml_str.as_ref().len()
))
}
#[inline(always)]
pub fn swap_with_default(&mut self) -> Self {
let mut s = Self {
root: NodeData::create_div(),
children: DomVec::from_const_slice(&[]),
estimated_total_children: 0,
};
mem::swap(&mut s, self);
s
}
#[inline]
pub fn add_child(&mut self, child: Dom) {
let estimated = child.estimated_total_children;
let mut v: DomVec = Vec::new().into();
mem::swap(&mut v, &mut self.children);
let mut v = v.into_library_owned_vec();
v.push(child);
self.children = v.into();
self.estimated_total_children += estimated + 1;
}
#[inline(always)]
pub fn set_children(&mut self, children: DomVec) {
let children_estimated = children
.iter()
.map(|s| s.estimated_total_children + 1)
.sum();
self.children = children;
self.estimated_total_children = children_estimated;
}
pub fn copy_except_for_root(&mut self) -> Self {
Self {
root: self.root.copy_special(),
children: self.children.clone(),
estimated_total_children: self.estimated_total_children,
}
}
pub fn node_count(&self) -> usize {
self.estimated_total_children + 1
}
pub fn style(&mut self, css: azul_css::css::Css) -> StyledDom {
StyledDom::create(self, css)
}
#[inline(always)]
pub fn with_children(mut self, children: DomVec) -> Self {
self.set_children(children);
self
}
#[inline(always)]
pub fn with_child(mut self, child: Self) -> Self {
self.add_child(child);
self
}
#[inline(always)]
pub fn with_node_type(mut self, node_type: NodeType) -> Self {
self.root.set_node_type(node_type);
self
}
#[inline(always)]
pub fn with_id(mut self, id: AzString) -> Self {
self.root.add_id(id);
self
}
#[inline(always)]
pub fn with_class(mut self, class: AzString) -> Self {
self.root.add_class(class);
self
}
#[inline(always)]
pub fn with_callback<C: Into<CoreCallback>>(
mut self,
event: EventFilter,
data: RefAny,
callback: C,
) -> Self {
self.root.add_callback(event, data, callback);
self
}
#[inline(always)]
pub fn with_css_property(mut self, prop: CssPropertyWithConditions) -> Self {
self.root.add_css_property(prop);
self
}
#[inline(always)]
pub fn add_css_property(&mut self, prop: CssPropertyWithConditions) {
self.root.add_css_property(prop);
}
#[inline(always)]
pub fn add_class(&mut self, class: AzString) {
self.root.add_class(class);
}
#[inline(always)]
pub fn add_callback<C: Into<CoreCallback>>(
&mut self,
event: EventFilter,
data: RefAny,
callback: C,
) {
self.root.add_callback(event, data, callback);
}
#[inline(always)]
pub fn set_tab_index(&mut self, tab_index: TabIndex) {
self.root.set_tab_index(tab_index);
}
#[inline(always)]
pub fn set_contenteditable(&mut self, contenteditable: bool) {
self.root.set_contenteditable(contenteditable);
}
#[inline(always)]
pub fn with_tab_index(mut self, tab_index: TabIndex) -> Self {
self.root.set_tab_index(tab_index);
self
}
#[inline(always)]
pub fn with_contenteditable(mut self, contenteditable: bool) -> Self {
self.root.set_contenteditable(contenteditable);
self
}
#[inline(always)]
pub fn with_dataset(mut self, data: OptionRefAny) -> Self {
self.root.dataset = data;
self
}
#[inline(always)]
pub fn with_ids_and_classes(mut self, ids_and_classes: IdOrClassVec) -> Self {
self.root.ids_and_classes = ids_and_classes;
self
}
#[inline(always)]
pub fn with_attribute(mut self, attr: AttributeType) -> Self {
let mut attrs = self.root.attributes.clone();
let mut v = attrs.into_library_owned_vec();
v.push(attr);
self.root.attributes = v.into();
self
}
#[inline(always)]
pub fn with_attributes(mut self, attributes: AttributeTypeVec) -> Self {
self.root.attributes = attributes;
self
}
#[inline(always)]
pub fn with_callbacks(mut self, callbacks: CoreCallbackDataVec) -> Self {
self.root.callbacks = callbacks;
self
}
#[inline(always)]
pub fn with_css_props(mut self, css_props: CssPropertyWithConditionsVec) -> Self {
self.root.css_props = css_props;
self
}
#[inline]
pub fn with_key<K: core::hash::Hash>(mut self, key: K) -> Self {
self.root.set_key(key);
self
}
#[inline]
pub fn with_merge_callback<C: Into<DatasetMergeCallback>>(mut self, callback: C) -> Self {
self.root.set_merge_callback(callback);
self
}
pub fn set_inline_style(&mut self, style: &str) {
self.root.set_inline_style(style);
}
pub fn with_inline_style(mut self, style: &str) -> Self {
self.set_inline_style(style);
self
}
pub fn set_css(&mut self, style: &str) {
let parsed = CssPropertyWithConditionsVec::parse(style);
let mut current = Vec::new().into();
mem::swap(&mut current, &mut self.root.css_props);
let mut v = current.into_library_owned_vec();
v.extend(parsed.into_library_owned_vec());
self.root.css_props = v.into();
}
pub fn with_css(mut self, style: &str) -> Self {
self.set_css(style);
self
}
pub fn set_inline_hover_style(&mut self, style: &str) {
self.root.set_inline_hover_style(style);
}
pub fn with_inline_hover_style(mut self, style: &str) -> Self {
self.set_inline_hover_style(style);
self
}
pub fn set_inline_active_style(&mut self, style: &str) {
self.root.set_inline_active_style(style);
}
pub fn with_inline_active_style(mut self, style: &str) -> Self {
self.set_inline_active_style(style);
self
}
pub fn set_inline_focus_style(&mut self, style: &str) {
self.root.set_inline_focus_style(style);
}
pub fn with_inline_focus_style(mut self, style: &str) -> Self {
self.set_inline_focus_style(style);
self
}
#[inline]
pub fn set_context_menu(&mut self, context_menu: Menu) {
self.root.set_context_menu(context_menu);
}
#[inline]
pub fn with_context_menu(mut self, context_menu: Menu) -> Self {
self.set_context_menu(context_menu);
self
}
#[inline]
pub fn set_menu_bar(&mut self, menu_bar: Menu) {
self.root.set_menu_bar(menu_bar);
}
#[inline]
pub fn with_menu_bar(mut self, menu_bar: Menu) -> Self {
self.set_menu_bar(menu_bar);
self
}
#[inline]
pub fn with_clip_mask(mut self, clip_mask: ImageMask) -> Self {
self.root.set_clip_mask(clip_mask);
self
}
#[inline]
pub fn with_accessibility_info(mut self, accessibility_info: AccessibilityInfo) -> Self {
self.root.set_accessibility_info(accessibility_info);
self
}
pub fn fixup_children_estimated(&mut self) -> usize {
if self.children.is_empty() {
self.estimated_total_children = 0;
} else {
self.estimated_total_children = self
.children
.iter_mut()
.map(|s| s.fixup_children_estimated() + 1)
.sum();
}
return self.estimated_total_children;
}
}
impl core::iter::FromIterator<Dom> for Dom {
fn from_iter<I: IntoIterator<Item = Dom>>(iter: I) -> Self {
let mut estimated_total_children = 0;
let children = iter
.into_iter()
.map(|c| {
estimated_total_children += c.estimated_total_children + 1;
c
})
.collect::<Vec<Dom>>();
Dom {
root: NodeData::create_div(),
children: children.into(),
estimated_total_children,
}
}
}
impl fmt::Debug for Dom {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn print_dom(d: &Dom, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Dom {{\r\n")?;
write!(f, "\troot: {:#?}\r\n", d.root)?;
write!(
f,
"\testimated_total_children: {:#?}\r\n",
d.estimated_total_children
)?;
write!(f, "\tchildren: [\r\n")?;
for c in d.children.iter() {
print_dom(c, f)?;
}
write!(f, "\t]\r\n")?;
write!(f, "}}\r\n")?;
Ok(())
}
print_dom(self, f)
}
}