Class: Dommy::HTMLTableElement

Inherits:
HTMLElement show all
Defined in:
lib/dommy/html_elements.rb

Overview

<table> — top-level table element. rows returns rows from all sections (thead → tbody → tfoot); tBodies is a list of tbody elements. insertRow(-1) appends to the last tbody (or creates one); deleteRow works against the merged rows list.

Constant Summary collapse

HTML_NAMESPACE =
"http://www.w3.org/1999/xhtml"

Constants inherited from Element

Element::ADJACENT_POSITIONS, Element::APPROX_CHAR_PX, Element::APPROX_LINE_PX, Element::ATTRIBUTE_NODE, Element::CDATA_SECTION_NODE, Element::COMMENT_NODE, Element::DOCUMENT_FRAGMENT_NODE, Element::DOCUMENT_NODE, Element::DOCUMENT_POSITION_CONTAINED_BY, Element::DOCUMENT_POSITION_CONTAINS, Element::DOCUMENT_POSITION_DISCONNECTED, Element::DOCUMENT_POSITION_FOLLOWING, Element::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, Element::DOCUMENT_POSITION_PRECEDING, Element::DOCUMENT_TYPE_NODE, Element::ELEMENT_NODE, Element::INLINE_TAGS, Element::PROCESSING_INSTRUCTION_NODE, Element::REFLECTED_TOKEN_LIST_HOSTS, Element::SHADOW_HOST_TAGS, Element::SVG_NAMESPACE, Element::TEXT_NODE

Constants included from Node

Node::ATTRIBUTE_NODE, Node::CDATA_SECTION_NODE, Node::COMMENT_NODE, Node::DOCUMENT_FRAGMENT_NODE, Node::DOCUMENT_NODE, Node::DOCUMENT_POSITION_CONTAINED_BY, Node::DOCUMENT_POSITION_CONTAINS, Node::DOCUMENT_POSITION_DISCONNECTED, Node::DOCUMENT_POSITION_FOLLOWING, Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, Node::DOCUMENT_POSITION_PRECEDING, Node::DOCUMENT_TYPE_NODE, Node::ELEMENT_NODE, Node::PROCESSING_INSTRUCTION_NODE, Node::TEXT_NODE, Node::XMLNS_NAMESPACE, Node::XML_NAMESPACE

Instance Attribute Summary

Attributes inherited from Element

#document

Instance Method Summary collapse

Methods inherited from HTMLElement

#case_sensitive_attribute_names?, #disabled_by_ancestor_fieldset?, #labels_node_list, #parse_non_negative_reflected, #set_non_negative_reflected

Methods included from Internal::ReflectedAttributes

included

Methods inherited from Element

#[], #[]=, #__dommy_backend_node__, #__internal_approx_box, #__internal_case_sensitive_attribute_names__?, #__internal_created_namespace__, #__internal_normalize_attr_key__, #__internal_set_namespace__, #__internal_shadow_root__, #__js_attribute_snapshot__, #__run_click_activation_behavior__, #__test_scroll_log__, #access_key_label, #accessibility_tree, #activation_behavior, #activation_target, #activation_target?, #after, #anchor_href, #animate, #approximate_layout?, #aria_content_attr, #aria_element_attr, #aria_element_get, #aria_element_set, #aria_elements_attr, #aria_elements_current, #aria_elements_get, #aria_elements_set, #aria_find_in_root, #aria_get, #aria_ref_in_valid_scope?, #aria_set, #aria_snapshot, #assigned_slot, #at_xpath, #attach_shadow, #attributes, #base_uri, #before, #blur, #child_element_count, #child_nodes, #children, #class_list, #class_name, #class_name=, #clear_aria_element_ref_for, #click, #clone_node, #closest, #computed_description, #computed_label, #computed_role, #contains?, #dataset, #element_prefix, #equal_node?, #first_child, #first_element_child, #focus, #get_animations, #get_attribute, #get_attribute_names, #get_attribute_node, #get_attribute_node_ns, #get_attribute_ns, #get_bounding_client_rect, #get_client_rects, #get_elements_by_class_name, #get_elements_by_tag_name, #get_elements_by_tag_name_ns, #get_html, #get_inner_html, #has_attribute?, #has_attribute_ns?, #has_attributes?, #has_child_nodes?, #hide_popover, #id, #id=, #initialize, #inner_html, #inner_html=, #insert_adjacent_element, #insert_adjacent_html, #insert_adjacent_text, #insert_before, #insertion_parent!, #is_connected?, #last_child, #last_element_child, #live_child_nodes, #local_name, #mark_fragment_scripts_started, #matches?, #namespace_uri, #next_element_sibling, #next_sibling, #on, #outer_html, #outer_html=, #owner_document, #parent_element, #parent_node, #path, #pre_click_activation_state, #previous_element_sibling, #previous_sibling, #query_selector, #query_selector_all, #reflected_attr_name, #reflected_token_list, #remove, #remove_attribute, #remove_attribute_node, #remove_attribute_ns, #remove_child, #replace_child, #replace_with_nodes, #request_fullscreen, #restore_pre_click_activation, #role, #role=, #root_node, #run_post_click_activation, #same_node?, #set_attribute, #set_attribute_node, #set_attribute_ns, #shadow_root, #show_popover, #slot, #slot=, #style, #tag_name, #text_content, #text_content=, #to_s, #toggle_attribute, #toggle_popover, #translate_mode?, #validate_adjacent_document_insert!, #with_selector_errors, #xpath

Methods included from Bridge::Methods

included

Methods included from Internal::ParentNode

#append, #append_child, #normalize, #prepend, #replace_children

Methods included from Internal::ChildNode

#child_node_after, #child_node_before, #child_node_replace_with, #nullable_dom_string, #validate_insert_before_ref!

Methods included from Node

#compare_document_position, #get_root_node, #is_default_namespace, #is_equal_node, #is_same_node, #lookup_namespace_uri, #lookup_prefix

Methods included from EventTarget

#__dommy_dump_event_failure__, #__internal_deliver_event__, #__internal_event_parent__, #__internal_process_event_handler_return__, #add_event_listener, capture_flag, #deliver_at, #dispatch_event, #event_name_from_on, #invoke_listener_isolated, js_truthy?, #on_handler, #remove_event_listener, #set_on_handler

Constructor Details

This class inherits a constructor from Dommy::Element

Instance Method Details

#__html_namespace_node__(node) ⇒ Object

Whether a raw backend node is in the HTML namespace.



3718
3719
3720
3721
# File 'lib/dommy/html_elements.rb', line 3718

def __html_namespace_node__(node)
  el = @document.wrap_node(node)
  !el.respond_to?(:namespace_uri) || el.namespace_uri == HTML_NAMESPACE
end

#__js_call__(method, args) ⇒ Object



3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
# File 'lib/dommy/html_elements.rb', line 3893

def __js_call__(method, args)
  case method
  when "insertRow"
    insert_row(args[0] || -1)
  when "deleteRow"
    delete_row(args[0])
    Bridge::UNDEFINED
  when "createCaption"
    create_caption
  when "deleteCaption"
    delete_caption
    Bridge::UNDEFINED
  when "createTHead"
    create_t_head
  when "deleteTHead"
    delete_t_head
    Bridge::UNDEFINED
  when "createTFoot"
    create_t_foot
  when "deleteTFoot"
    delete_t_foot
    Bridge::UNDEFINED
  when "createTBody"
    create_t_body
  else
    super
  end
end

#__js_get__(key) ⇒ Object



3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
# File 'lib/dommy/html_elements.rb', line 3859

def __js_get__(key)
  case key
  when "caption"
    caption
  when "tHead"
    t_head
  when "tFoot"
    t_foot
  when "tBodies"
    t_bodies
  when "rows"
    rows
  else
    super
  end
end

#__js_set__(key, value) ⇒ Object



3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
# File 'lib/dommy/html_elements.rb', line 3876

def __js_set__(key, value)
  case key
  when "caption"
    self.caption = value
  when "tHead"
    self.t_head = value
  when "tFoot"
    self.t_foot = value
  else
    super
  end
end

#__tr_children__(section) ⇒ Object

The HTML-namespaced element children of a section node.



3706
3707
3708
# File 'lib/dommy/html_elements.rb', line 3706

def __tr_children__(section)
  section.element_children.select { |n| n.name == "tr" && __html_namespace_node__(n) }
end

#captionObject

Own js_call methods, on top of Element's.



3643
3644
3645
# File 'lib/dommy/html_elements.rb', line 3643

def caption
  first_html_child("caption")
end

#caption=(new_caption) ⇒ Object



3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
# File 'lib/dommy/html_elements.rb', line 3647

def caption=(new_caption)
  if !new_caption.nil? && !new_caption.is_a?(HTMLTableCaptionElement)
    raise Bridge::TypeError, "table.caption must be an HTMLTableCaptionElement or null"
  end

  delete_caption
  return if new_caption.nil?

  # Route through the validated insertion so a cycle (the caption already
  # containing this table) raises HierarchyRequestError and a caption from
  # another document is adopted, rather than corrupting the tree.
  insert_before(new_caption, first_child)
end

#create_captionObject



3723
3724
3725
3726
3727
3728
3729
3730
3731
# File 'lib/dommy/html_elements.rb', line 3723

def create_caption
  existing = caption
  return existing if existing

  cap = @document.create_element("caption")
  first = @__node__.children.first
  first ? first.add_previous_sibling(cap.__dommy_backend_node__) : @__node__.add_child(cap.__dommy_backend_node__)
  cap
end

#create_t_bodyObject



3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
# File 'lib/dommy/html_elements.rb', line 3774

def create_t_body
  tb = @document.create_element("tbody")
  last_tbody = t_bodies.last
  if last_tbody
    last_tbody.__dommy_backend_node__.add_next_sibling(tb.__dommy_backend_node__)
  else
    @__node__.add_child(tb.__dommy_backend_node__)
  end

  tb
end

#create_t_footObject



3760
3761
3762
3763
3764
3765
3766
3767
# File 'lib/dommy/html_elements.rb', line 3760

def create_t_foot
  existing = t_foot
  return existing if existing

  foot = @document.create_element("tfoot")
  @__node__.add_child(foot.__dommy_backend_node__)
  foot
end

#create_t_headObject



3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
# File 'lib/dommy/html_elements.rb', line 3739

def create_t_head
  existing = t_head
  return existing if existing

  head = @document.create_element("thead")
  cap = caption
  if cap
    cap.__dommy_backend_node__.add_next_sibling(head.__dommy_backend_node__)
  else
    first = @__node__.children.first
    first ? first.add_previous_sibling(head.__dommy_backend_node__) : @__node__.add_child(head.__dommy_backend_node__)
  end

  head
end

#delete_captionObject



3733
3734
3735
3736
3737
# File 'lib/dommy/html_elements.rb', line 3733

def delete_caption
  cap = caption
  cap&.remove
  nil
end

#delete_row(index) ⇒ Object



3813
3814
3815
3816
3817
3818
3819
3820
3821
# File 'lib/dommy/html_elements.rb', line 3813

def delete_row(index)
  list = rows.to_a
  i = index.to_i
  raise DOMException::IndexSizeError, "deleteRow index #{i} out of range" if i < -1 || i >= list.size

  target = i == -1 ? list.last : list[i]
  target&.remove
  nil
end

#delete_t_footObject



3769
3770
3771
3772
# File 'lib/dommy/html_elements.rb', line 3769

def delete_t_foot
  t_foot&.remove
  nil
end

#delete_t_headObject



3755
3756
3757
3758
# File 'lib/dommy/html_elements.rb', line 3755

def delete_t_head
  t_head&.remove
  nil
end

#first_html_child(local) ⇒ Object

The first HTML-namespaced element child with the given local name (a same-name element in another namespace, e.g. SVG's , is skipped).



3712
3713
3714
3715
# File 'lib/dommy/html_elements.rb', line 3712

def first_html_child(local)
  node = @__node__.element_children.find { |n| n.name == local && __html_namespace_node__(n) }
  node && @document.wrap_node(node)
end

#insert_row(index = -1)) ⇒ Object

table.insertRow(index) — inserts a <tr> at the merged index. Per spec, if no <tbody> exists and the table is empty, the row is inserted directly; otherwise it goes into the last <tbody>.



3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
# File 'lib/dommy/html_elements.rb', line 3790

def insert_row(index = -1)
  list = rows.to_a
  raw = index.to_i
  raise DOMException::IndexSizeError, "row index #{raw} out of range" if raw < -1 || raw > list.size

  idx = raw == -1 ? list.size : raw

  tr = @document.create_element("tr")
  if idx == list.size
    target_section = t_bodies.last || create_t_body
    target_section.append_child(tr)
  else
    anchor = list[idx]
    section = anchor.__dommy_backend_node__.parent
    if section
      anchor.__dommy_backend_node__.add_previous_sibling(tr.__dommy_backend_node__)
      @document.notify_child_list_mutation(target_node: section, added_nodes: [tr.__dommy_backend_node__], removed_nodes: [])
    end
  end

  tr
end

#rowsObject



3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
# File 'lib/dommy/html_elements.rb', line 3678

def rows
  el = self
  HTMLCollection.new do
    # Per spec: thead rows first, then the tr children of the table and of
    # tbody sections IN TREE ORDER (a direct <tr> and a <tbody>'s rows
    # interleave by document position), then tfoot rows.
    head_rows = []
    body_rows = []
    foot_rows = []
    el.__dommy_backend_node__.element_children.each do |n|
      next unless el.__html_namespace_node__(n)

      case n.name
      when "thead"
        el.__tr_children__(n).each { |c| head_rows << c }
      when "tfoot"
        el.__tr_children__(n).each { |c| foot_rows << c }
      when "tbody"
        el.__tr_children__(n).each { |c| body_rows << c }
      when "tr"
        body_rows << n
      end
    end
    (head_rows + body_rows + foot_rows).map { |n| el.document.wrap_node(n) }.compact
  end
end

#set_table_section(local, value) ⇒ Object



3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
# File 'lib/dommy/html_elements.rb', line 3833

def set_table_section(local, value)
  if value.nil?
    first_html_child(local)&.remove
    return
  end
  # A non-section value fails the WebIDL type check (TypeError); a section of
  # the wrong local name fails the spec's algorithm (HierarchyRequestError).
  unless value.is_a?(HTMLTableSectionElement)
    raise Bridge::TypeError, "table.#{local} must be an HTMLTableSectionElement or null"
  end
  unless value.tag_name.to_s.casecmp?(local)
    raise DOMException::HierarchyRequestError, "table.#{local} must be a <#{local}> element"
  end

  first_html_child(local)&.remove
  # A validated insertion (cycle → HierarchyRequestError, cross-document →
  # adopt). thead goes just after any caption; tfoot is appended last.
  if local == "thead"
    cap = caption
    insert_before(value, cap ? cap.next_sibling : first_child)
  else
    append_child(value)
  end
  value
end

#t_bodiesObject



3669
3670
3671
3672
3673
3674
3675
3676
# File 'lib/dommy/html_elements.rb', line 3669

def t_bodies
  el = self
  HTMLCollection.new do
    el.__dommy_backend_node__.element_children
      .select { |n| n.name == "tbody" && el.__html_namespace_node__(n) }
      .map { |n| el.document.wrap_node(n) }.compact
  end
end

#t_footObject



3665
3666
3667
# File 'lib/dommy/html_elements.rb', line 3665

def t_foot
  first_html_child("tfoot")
end

#t_foot=(value) ⇒ Object



3829
3830
3831
# File 'lib/dommy/html_elements.rb', line 3829

def t_foot=(value)
  set_table_section("tfoot", value)
end

#t_headObject



3661
3662
3663
# File 'lib/dommy/html_elements.rb', line 3661

def t_head
  first_html_child("thead")
end

#t_head=(value) ⇒ Object

table.tHead = x / table.tFoot = x: x must be a matching section element (or null). It replaces the existing one at the spec position.



3825
3826
3827
# File 'lib/dommy/html_elements.rb', line 3825

def t_head=(value)
  set_table_section("thead", value)
end