Packages

Contains the W3C DOM specification.

Current section

Files

Jump to
dom lib dom dom_element.ex
Raw

lib/dom/dom_element.ex

defmodule DOM.DOMElement do
@moduledoc """
Defines interface Element
https://dom.spec.whatwg.org/#interface-element
"""
use DOM
defmacro __using__(_opts \\ []) do
quote do
use DOMNode
@dom_element_fields @dom_node_fields ++
[
:namespace_uri,
:prefix,
:local_name,
:tag_name,
:id,
:class_name,
:class_list,
:slot,
:shadow_root,
attributes: []
]
end
end
@type t ::
Map.merge(DOMNode.t(), %{
namespace_uri: binary(),
prefix: binary(),
local_name: binary(),
tag_name: binary(),
id: binary(),
class_name: binary(),
class_list: list(),
slot: binary(),
# using keyword list to preserve document order
attributes: keyword(),
shadow_root: map()
})
@doc """
https://dom.spec.whatwg.org/#dom-element-hasattributes
"""
@spec has_attributes(__MODULE__.t()) :: boolean()
def has_attributes(element)
def has_attributes(%{attributes: attrs} = _dom_element),
do: length(attrs) > 0
@doc """
https://dom.spec.whatwg.org/#dom-element-getattributenames
"""
@spec get_attribute_names(__MODULE__.t()) :: list(binary())
def get_attribute_names(element)
def get_attribute_names(%{attributes: attrs} = _dom_element),
do: Keystring.keys(attrs)
@doc """
https://dom.spec.whatwg.org/#dom-element-getattribute
"""
@spec get_attribute(__MODULE__.t(), binary()) :: binary()
def get_attribute(element, qualified_name)
def get_attribute(%{attributes: attrs} = _dom_element, qualified_name),
do: attrs |> Keystring.get(qualified_name, %DOMAttr{}) |> Map.get(:value)
@doc """
https://dom.spec.whatwg.org/#dom-element-setattribute
"""
@spec set_attribute(__MODULE__.t(), binary(), binary()) :: __MODULE__.t()
def set_attribute(element, qualified_name, value)
def set_attribute(dom_element, qualified_name, value) do
qualified_name = String.downcase(qualified_name)
attr = %DOMAttr{
node_name: qualified_name,
node_value: value,
text_content: value,
owner_document: dom_element.owner_document,
owner_element: dom_element,
local_name: qualified_name,
name: qualified_name,
value: value
}
set_attribute_node(dom_element, attr)
end
@doc """
https://dom.spec.whatwg.org/#dom-element-setattributenode
"""
@spec set_attribute_node(__MODULE__.t(), DOMAttr.t()) :: __MODULE__.t()
def set_attribute_node(element, attribute)
def set_attribute_node(dom_element, %DOMAttr{} = attribute),
do:
Map.update(
dom_element,
:attributes,
[],
&Keystring.put(&1, attribute.local_name, attribute)
)
@doc """
https://dom.spec.whatwg.org/#dom-element-hasattribute
"""
@spec has_attribute(__MODULE__.t(), binary()) :: boolean()
def has_attribute(element, qualified_name)
def has_attribute(%{attributes: attrs} = _dom_element, qualified_name),
do: Keystring.has_key?(attrs, String.downcase(qualified_name))
@doc """
https://dom.spec.whatwg.org/#dom-element-getattributenode
"""
@spec get_attribute_node(__MODULE__.t(), binary()) :: DOMAttr.t()
def get_attribute_node(element, qualified_name)
def get_attribute_node(%{attributes: attrs}, qualified_name),
do: Keystring.get(attrs, qualified_name)
@doc """
This function is not part of the official DOM Element interface
"""
@spec get_attribute_nodes(__MODULE__.t()) :: list(DOMAttr.t())
def get_attribute_nodes(element)
def get_attribute_nodes(%{attributes: attrs} = _dom_element),
do: attrs |> Enum.map(&elem(&1, 1))
@doc """
https://dom.spec.whatwg.org/#dom-element-attachshadow
"""
@spec attach_shadow(__MODULE__.t(), :open | :closed, boolean(), :manual | :named) ::
__MODULE__.t()
def attach_shadow(element, mode, delegate_focus \\ false, slot_assignment \\ :named)
def attach_shadow(dom_element, mode, delegate_focus, slot_assignment) do
shadow_root = %DOMShadowRoot{
host: dom_element,
mode: mode,
delegate_focus: delegate_focus,
slot_assignment: slot_assignment
}
%{dom_element | shadow_root: shadow_root}
end
@doc """
https://dom.spec.whatwg.org/#dom-element-getelementsbytagname
"""
@spec get_elements_by_tag_name(__MODULE__.t(), binary()) :: list(__MODULE__.t())
def get_elements_by_tag_name(element, qualified_name)
def get_elements_by_tag_name(%{child_nodes: child_nodes} = dom_element, qualified_name) do
elements =
child_nodes
|> Enum.filter(fn
%{tag_name: tag_name} ->
qualified_name == "*" or tag_name =~ qualified_name
_ ->
false
end)
|> Enum.reduce([], fn element, elements ->
elements = get_elements_by_tag_name(element, qualified_name) ++ elements
[element | elements]
end)
if qualified_name == "*" or dom_element.tag_name == qualified_name,
do: [dom_element | elements],
else: elements
end
def get_elements_by_id(%{child_nodes: child_nodes} = dom_element, element_id) do
elements =
child_nodes
|> Enum.filter(fn
%{id: id} ->
id == element_id
_ ->
false
end)
|> Enum.reduce([], fn element, elements ->
elements = get_elements_by_id(element, element_id) ++ elements
[element | elements]
end)
if dom_element.id == element_id,
do: [dom_element | elements],
else: elements
end
@doc """
https://dom.spec.whatwg.org/#dom-nonelementparentnode-getelementbyid
"""
@spec get_element_by_id(__MODULE__.t(), binary()) :: __MODULE__.t()
def get_element_by_id(element, element_id)
def get_element_by_id(%{id: id} = dom_element, element_id) when id == element_id,
do: dom_element
def get_element_by_id(dom_element, element_id) do
dom_element
|> get_elements_by_id(element_id)
|> List.first()
end
end