Class: Dommy::ClassList

Inherits:
Object
  • Object
show all
Includes:
Bridge::Methods, Enumerable
Defined in:
lib/dommy/element.rb

Overview

(LiveChildren removed — el.children now returns a Dommy::HTMLCollection initialized with a re-evaluating block.)

Instance Method Summary collapse

Methods included from Bridge::Methods

included

Constructor Details

#initialize(element, attribute = "class") ⇒ ClassList

attribute is the content attribute this token list reflects ("class" for classList, "rel" for relList, "sandbox", "sizes", "for", …).



757
758
759
760
# File 'lib/dommy/element.rb', line 757

def initialize(element, attribute = "class")
  @element = element
  @attribute = attribute
end

Instance Method Details

#[](index) ⇒ Object



830
831
832
# File 'lib/dommy/element.rb', line 830

def [](index)
  item(index)
end

#__js_call__(method, args) ⇒ Object



881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
# File 'lib/dommy/element.rb', line 881

def __js_call__(method, args)
  case method
  when "add"
    update_tokens { |tokens| tokens | normalize_tokens(args) }
    Bridge::UNDEFINED
  when "remove"
    update_tokens { |tokens| tokens - normalize_tokens(args) }
    Bridge::UNDEFINED
  when "contains"
    # contains() does not validate; null coerces to the string "null".
    class_tokens.include?(stringify_token(args[0]))
  when "toggle"
    toggle(args[0], args[1])
  when "replace"
    replace(args[0], args[1])
  when "item"
    item(args[0])
  when "toString"
    value
  else
    nil
  end
end

#__js_get__(key) ⇒ Object



846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
# File 'lib/dommy/element.rb', line 846

def __js_get__(key)
  case key
  when "length"
    length
  when "value"
    value
  else
    # Indexed getter: `classList[i]` is an undefined-returning indexed
    # property — out-of-range or negative indices yield JS `undefined`
    # (unlike `item(i)`, which returns null). Returning Ruby nil here would
    # marshal as JS null, so use the UNDEFINED sentinel.
    if key.is_a?(Integer) || key.to_s.match?(/\A-?\d+\z/)
      i = key.to_i
      token = i.negative? ? nil : class_tokens[i]
      token.nil? ? Bridge::UNDEFINED : token
    else
      Bridge::ABSENT # unknown non-index property
    end
  end
end

#__js_set__(key, val) ⇒ Object



867
868
869
870
871
872
873
874
# File 'lib/dommy/element.rb', line 867

def __js_set__(key, val)
  case key
  when "value"
    self.value = val
  end

  nil
end

#add(*tokens) ⇒ Object



796
797
798
799
# File 'lib/dommy/element.rb', line 796

def add(*tokens)
  update_tokens { |existing| existing | normalize_tokens(tokens) }
  nil
end

#contains?(token) ⇒ Boolean

Spec: contains() does NOT validate (no SyntaxError on empty).

Returns:

  • (Boolean)


784
785
786
# File 'lib/dommy/element.rb', line 784

def contains?(token)
  class_tokens.include?(token.to_s)
end

#each(&blk) ⇒ Object



834
835
836
# File 'lib/dommy/element.rb', line 834

def each(&blk)
  class_tokens.each(&blk)
end

#include?(token) ⇒ Boolean

DOMTokenList membership. Defined explicitly (rather than inheriting Enumerable#include?, which re-iterates via #each) so a class-selector match is a single Array#include? over the cached tokens — the hot path under a querySelector-heavy SPA.

Returns:

  • (Boolean)


792
793
794
# File 'lib/dommy/element.rb', line 792

def include?(token)
  class_tokens.include?(token.to_s)
end

#item(index) ⇒ Object



768
769
770
771
772
773
# File 'lib/dommy/element.rb', line 768

def item(index)
  i = index.to_i
  return nil if i.negative?

  class_tokens[i]
end

#lengthObject Also known as: size



762
763
764
# File 'lib/dommy/element.rb', line 762

def length
  class_tokens.length
end

#remove(*tokens) ⇒ Object



801
802
803
804
# File 'lib/dommy/element.rb', line 801

def remove(*tokens)
  update_tokens { |existing| existing - normalize_tokens(tokens) }
  nil
end

#replace(old_token, new_token) ⇒ Object



806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
# File 'lib/dommy/element.rb', line 806

def replace(old_token, new_token)
  # Spec order: both tokens' empty checks (SyntaxError) precede both
  # whitespace checks (InvalidCharacterError) — so replace(" ", "") is a
  # SyntaxError (the empty newToken), not an InvalidCharacterError.
  old_s = stringify_token(old_token)
  new_s = stringify_token(new_token)
  raise DOMException::SyntaxError, "token is empty" if old_s.empty? || new_s.empty?
  if old_s.match?(/[ \t\n\f\r]/) || new_s.match?(/[ \t\n\f\r]/)
    raise DOMException::InvalidCharacterError, "token contains whitespace"
  end

  tokens = class_tokens
  idx = tokens.index(old_s)
  return false unless idx

  # class_tokens returns the cached token array; dup before mutating so the
  # in-place assignment can't corrupt the cache (whose key is still the old
  # raw attribute string, which would then hand stale tokens to later reads).
  updated = tokens.dup
  updated[idx] = new_s
  @element.set_attribute(@attribute, updated.uniq.join(" "))
  true
end

#to_aObject



838
839
840
# File 'lib/dommy/element.rb', line 838

def to_a
  class_tokens.dup
end

#to_sObject



842
843
844
# File 'lib/dommy/element.rb', line 842

def to_s
  value
end

#valueObject



775
776
777
# File 'lib/dommy/element.rb', line 775

def value
  @element.__dommy_backend_node__[@attribute].to_s
end

#value=(new_value) ⇒ Object



779
780
781
# File 'lib/dommy/element.rb', line 779

def value=(new_value)
  @element.set_attribute(@attribute, new_value.to_s)
end