Class: Dommy::HTMLInputElement

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

Overview

‘<input>` — covers the most-used form control surface.

Constant Summary collapse

JS_METHOD_NAMES =

Own js_call methods, on top of Element’s.

%w[
  select setSelectionRange setRangeText stepUp stepDown
  checkValidity reportValidity setCustomValidity
].freeze

Constants inherited from Element

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::PROCESSING_INSTRUCTION_NODE, Element::SHADOW_HOST_TAGS, 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

Instance Attribute Summary

Attributes inherited from Element

#document

Instance Method Summary collapse

Methods inherited from HTMLElement

#case_sensitive_attribute_names?

Methods inherited from Element

#[], #[]=, #__dommy_backend_node__, #__internal_shadow_root__, #__test_scroll_log__, #after, #anchor_href, #animate, #append, #append_child, #at_xpath, #attach_shadow, #attributes, #base_uri, #before, #blur, #child_element_count, #child_nodes, #children, #class_list, #class_name, #class_name=, #click, #clone_node, #closest, #compare_document_position, #contains?, #dataset, #equal_node?, #first_child, #first_element_child, #focus, #get_animations, #get_attribute, #get_attribute_node, #get_elements_by_class_name, #get_elements_by_tag_name, #get_html, #get_inner_html, #has_attribute?, #has_attributes?, #has_child_nodes?, #id, #id=, #initialize, #inner_html, #inner_html=, #insert_adjacent_element, #insert_adjacent_html, #insert_adjacent_text, #insert_before, #is_connected?, #last_child, #last_element_child, #live_child_nodes, #local_name, #matches?, #namespace_uri, #next_element_sibling, #next_sibling, #normalize, #on, #outer_html, #outer_html=, #owner_document, #parent_element, #parent_node, #path, #prepend, #previous_element_sibling, #previous_sibling, #query_selector, #query_selector_all, #reflected_attr_name, #remove, #remove_attribute, #remove_attribute_node, #remove_child, #replace_child, #replace_children, #replace_with_nodes, #role, #role=, #root_node, #same_node?, #set_attribute, #set_attribute_node, #shadow_root, #slot, #slot=, #style, #tag_name, #text_content, #text_content=, #to_s, #toggle_attribute, #xpath

Methods included from EventTarget

#__internal_deliver_event__, #add_event_listener, #dispatch_event, #invoke_listener, #remove_event_listener

Constructor Details

This class inherits a constructor from Dommy::Element

Instance Method Details

#__driver_set_files__(files_input) ⇒ Object

Test-only seam: set the input’s file list directly. Accepts an array (wrapped in a FileList) or a FileList itself.



447
448
449
# File 'lib/dommy/html_elements.rb', line 447

def __driver_set_files__(files_input)
  @__files = files_input.is_a?(FileList) ? files_input : FileList.new(Array(files_input))
end

#__js_call__(method, args) ⇒ Object



675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
# File 'lib/dommy/html_elements.rb', line 675

def __js_call__(method, args)
  case method
  when "select"
    select
  when "setSelectionRange"
    set_selection_range(args[0], args[1], args[2])
  when "setRangeText"
    set_range_text(args[0])
  when "stepUp"
    step_up(args[0])
  when "stepDown"
    step_down(args[0])
  when "checkValidity"
    check_validity
  when "reportValidity"
    report_validity
  when "setCustomValidity"
    set_custom_validity(args[0])
  else
    super
  end
end

#__js_get__(key) ⇒ Object



597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
# File 'lib/dommy/html_elements.rb', line 597

def __js_get__(key)
  case key
  when "type"
    type
  when "name"
    name
  when "placeholder"
    placeholder
  when "min"
    min
  when "max"
    max
  when "step"
    step
  when "pattern"
    pattern
  when "autocomplete"
    autocomplete
  when "autofocus"
    autofocus
  when "defaultValue"
    default_value
  when "defaultChecked"
    default_checked
  when "value"
    value
  when "checked"
    checked
  when "disabled"
    disabled
  when "required"
    required
  when "readonly", "readOnly"
    readonly
  when "labels"
    labels
  when "form"
    form
  when "validity"
    validity
  when "willValidate"
    will_validate
  when "validationMessage"
    validation_message
  when "files"
    files
  else
    super
  end
end

#__js_method_names__Object



360
361
362
# File 'lib/dommy/html_elements.rb', line 360

def __js_method_names__
  super + JS_METHOD_NAMES
end

#__js_set__(key, value) ⇒ Object



648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
# File 'lib/dommy/html_elements.rb', line 648

def __js_set__(key, value)
  case key
  when "type"
    set_reflected_string("type", value)
  when "name"
    set_reflected_string("name", value)
  when "placeholder"
    set_reflected_string("placeholder", value)
  when "min", "max", "step", "pattern", "autocomplete"
    set_reflected_string(key, value)
  when "autofocus"
    set_reflected_boolean("autofocus", value)
  when "value"
    self.value = value
  when "checked"
    self.checked = value
  when "disabled"
    self.disabled = value
  when "required"
    self.required = value
  when "readonly", "readOnly"
    self.readonly = value
  else
    super
  end
end

#autocompleteObject



405
406
407
# File 'lib/dommy/html_elements.rb', line 405

def autocomplete
  reflected_string("autocomplete")
end

#autofocusObject



409
410
411
# File 'lib/dommy/html_elements.rb', line 409

def autofocus
  reflected_boolean("autofocus")
end

#autofocus=(v) ⇒ Object



413
414
415
# File 'lib/dommy/html_elements.rb', line 413

def autofocus=(v)
  set_reflected_boolean("autofocus", v)
end

#check_validityObject



582
583
584
585
586
# File 'lib/dommy/html_elements.rb', line 582

def check_validity
  ok = !will_validate || validity.valid
  dispatch_event(Event.new("invalid", "bubbles" => false, "cancelable" => true)) unless ok
  ok
end

#checkedObject



491
492
493
# File 'lib/dommy/html_elements.rb', line 491

def checked
  @__checked.nil? ? default_checked : @__checked
end

#checked=(v) ⇒ Object



495
496
497
# File 'lib/dommy/html_elements.rb', line 495

def checked=(v)
  @__checked = !!v
end

#default_checkedObject



421
422
423
# File 'lib/dommy/html_elements.rb', line 421

def default_checked
  reflected_boolean("checked")
end

#default_valueObject



417
418
419
# File 'lib/dommy/html_elements.rb', line 417

def default_value
  reflected_string("value")
end

#disabledObject



499
500
501
# File 'lib/dommy/html_elements.rb', line 499

def disabled
  reflected_boolean("disabled")
end

#disabled=(v) ⇒ Object



503
504
505
# File 'lib/dommy/html_elements.rb', line 503

def disabled=(v)
  set_reflected_boolean("disabled", v)
end

#filesObject

‘files` — for `<input type=“file”>`. Browsers populate this via user interaction; in tests, code uses `driver_set_files` to seed it.



441
442
443
# File 'lib/dommy/html_elements.rb', line 441

def files
  @__files ||= FileList.new
end

#formObject

Closest enclosing form (or nil if detached / not in a form).



530
531
532
# File 'lib/dommy/html_elements.rb', line 530

def form
  closest("form")
end

#labelsObject



523
524
525
526
527
# File 'lib/dommy/html_elements.rb', line 523

def labels
  return [] if id.empty?

  @document.query_selector_all("label[for='#{id}']")
end

#maxObject



393
394
395
# File 'lib/dommy/html_elements.rb', line 393

def max
  reflected_string("max")
end

#minObject



389
390
391
# File 'lib/dommy/html_elements.rb', line 389

def min
  reflected_string("min")
end

#nameObject



373
374
375
# File 'lib/dommy/html_elements.rb', line 373

def name
  reflected_string("name")
end

#name=(v) ⇒ Object



377
378
379
# File 'lib/dommy/html_elements.rb', line 377

def name=(v)
  set_reflected_string("name", v)
end

#patternObject



401
402
403
# File 'lib/dommy/html_elements.rb', line 401

def pattern
  reflected_string("pattern")
end

#placeholderObject



381
382
383
# File 'lib/dommy/html_elements.rb', line 381

def placeholder
  reflected_string("placeholder")
end

#placeholder=(v) ⇒ Object



385
386
387
# File 'lib/dommy/html_elements.rb', line 385

def placeholder=(v)
  set_reflected_string("placeholder", v)
end

#raw_valueObject

Underlying string the user supplied to ‘value=`, before any sanitization. Used by ValidityState.badInput so a non-parseable number still trips constraint validation.



487
488
489
# File 'lib/dommy/html_elements.rb', line 487

def raw_value
  @__raw_value || @__value || reflected_string("value")
end

#readonlyObject



515
516
517
# File 'lib/dommy/html_elements.rb', line 515

def readonly
  reflected_boolean("readonly")
end

#readonly=(v) ⇒ Object



519
520
521
# File 'lib/dommy/html_elements.rb', line 519

def readonly=(v)
  set_reflected_boolean("readonly", v)
end

#report_validityObject



588
589
590
# File 'lib/dommy/html_elements.rb', line 588

def report_validity
  check_validity
end

#requiredObject



507
508
509
# File 'lib/dommy/html_elements.rb', line 507

def required
  reflected_boolean("required")
end

#required=(v) ⇒ Object



511
512
513
# File 'lib/dommy/html_elements.rb', line 511

def required=(v)
  set_reflected_boolean("required", v)
end

#sanitize_number(raw) ⇒ Object



476
477
478
479
480
481
482
# File 'lib/dommy/html_elements.rb', line 476

def sanitize_number(raw)
  s = raw.to_s
  Float(s)
  s
rescue ArgumentError, TypeError
  ""
end

#sanitize_value(raw) ⇒ Object

Spec: the “value sanitization algorithm” runs lazily on read. type=email/url trim leading/trailing ASCII whitespace; type=number rejects non-finite floats by returning “” (badInput stays true so validity surfaces the original raw value).



455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
# File 'lib/dommy/html_elements.rb', line 455

def sanitize_value(raw)
  case type
  when "email"
    if @__node__.key?("multiple")
      raw.to_s.split(",").map(&:strip).join(",")
    else
      raw.to_s.strip
    end

  when "url"
    raw.to_s.strip
  when "number", "range"
    sanitize_number(raw)
  when "color"
    s = raw.to_s.strip.downcase
    s.match?(/\A#[0-9a-f]{6}\z/) ? s : "#000000"
  else
    raw.to_s
  end
end

#selectObject

No real text selection; method stubs let callers proceed.



535
536
537
# File 'lib/dommy/html_elements.rb', line 535

def select
  nil
end

#set_custom_validity(msg) ⇒ Object



592
593
594
595
# File 'lib/dommy/html_elements.rb', line 592

def set_custom_validity(msg)
  @custom_validity_message = msg.to_s
  nil
end

#set_range_text(_replacement, *_) ⇒ Object



543
544
545
# File 'lib/dommy/html_elements.rb', line 543

def set_range_text(_replacement, *_)
  nil
end

#set_selection_range(_start, _end, _direction = nil) ⇒ Object



539
540
541
# File 'lib/dommy/html_elements.rb', line 539

def set_selection_range(_start, _end, _direction = nil)
  nil
end

#stepObject



397
398
399
# File 'lib/dommy/html_elements.rb', line 397

def step
  reflected_string("step")
end

#step_down(_n = 1) ⇒ Object



551
552
553
# File 'lib/dommy/html_elements.rb', line 551

def step_down(_n = 1)
  nil
end

#step_up(_n = 1) ⇒ Object



547
548
549
# File 'lib/dommy/html_elements.rb', line 547

def step_up(_n = 1)
  nil
end

#typeObject



364
365
366
367
# File 'lib/dommy/html_elements.rb', line 364

def type
  raw = @__node__["type"].to_s
  raw.empty? ? "text" : raw.downcase
end

#type=(v) ⇒ Object



369
370
371
# File 'lib/dommy/html_elements.rb', line 369

def type=(v)
  set_reflected_string("type", v)
end

#validation_messageObject



569
570
571
572
573
574
575
576
577
578
579
580
# File 'lib/dommy/html_elements.rb', line 569

def validation_message
  return "" unless will_validate

  msg = (@custom_validity_message || "").to_s
  return msg unless msg.empty?
  return "Please fill out this field." if validity.value_missing
  return "Please match the requested format." if validity.pattern_mismatch
  return "Please enter a valid email address." if validity.type_mismatch && type == "email"
  return "Please enter a URL." if validity.type_mismatch && type == "url"

  ""
end

#validityObject



555
556
557
# File 'lib/dommy/html_elements.rb', line 555

def validity
  @__validity ||= ValidityState.new(self)
end

#valueObject

Runtime value/checked. Dommy has no UI, so the runtime state is initialized from the attribute on first access and tracked separately thereafter — matching browser semantics where the ‘value` IDL attribute can drift from the `value` content attr.



429
430
431
# File 'lib/dommy/html_elements.rb', line 429

def value
  sanitize_value(@__value.nil? ? reflected_string("value") : @__value)
end

#value=(v) ⇒ Object



433
434
435
436
437
# File 'lib/dommy/html_elements.rb', line 433

def value=(v)
  raw = v.to_s
  @__raw_value = raw
  @__value = raw
end

#will_validateObject

Whether this control participates in constraint validation. Disabled / hidden / button-type inputs return false.



561
562
563
564
565
566
567
# File 'lib/dommy/html_elements.rb', line 561

def will_validate
  return false if reflected_boolean("disabled")
  return false if reflected_boolean("readonly")
  return false if %w[hidden button submit reset image].include?(type)

  true
end