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

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

#__node__, #document

Instance Method Summary collapse

Methods inherited from HTMLElement

#case_sensitive_attribute_names?

Methods inherited from Element

#[], #[]=, #__scroll_log__, #__shadow_root__, #after, #anchor_href, #animate, #append, #append_child, #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, #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

Methods included from EventTarget

#__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

#__js_call__(method, args) ⇒ Object



660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
# File 'lib/dommy/html_elements.rb', line 660

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



582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
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
# File 'lib/dommy/html_elements.rb', line 582

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_set__(key, value) ⇒ Object



633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
# File 'lib/dommy/html_elements.rb', line 633

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

#__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.



432
433
434
# File 'lib/dommy/html_elements.rb', line 432

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

#autocompleteObject



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

def autocomplete
  reflected_string("autocomplete")
end

#autofocusObject



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

def autofocus
  reflected_boolean("autofocus")
end

#autofocus=(v) ⇒ Object



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

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

#check_validityObject



567
568
569
570
571
# File 'lib/dommy/html_elements.rb', line 567

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

#checkedObject



476
477
478
# File 'lib/dommy/html_elements.rb', line 476

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

#checked=(v) ⇒ Object



480
481
482
# File 'lib/dommy/html_elements.rb', line 480

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

#default_checkedObject



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

def default_checked
  reflected_boolean("checked")
end

#default_valueObject



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

def default_value
  reflected_string("value")
end

#disabledObject



484
485
486
# File 'lib/dommy/html_elements.rb', line 484

def disabled
  reflected_boolean("disabled")
end

#disabled=(v) ⇒ Object



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

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 `set_files` to seed it.



426
427
428
# File 'lib/dommy/html_elements.rb', line 426

def files
  @__files ||= FileList.new
end

#formObject

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



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

def form
  closest("form")
end

#labelsObject



508
509
510
511
512
# File 'lib/dommy/html_elements.rb', line 508

def labels
  return [] if id.empty?

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

#maxObject



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

def max
  reflected_string("max")
end

#minObject



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

def min
  reflected_string("min")
end

#nameObject



358
359
360
# File 'lib/dommy/html_elements.rb', line 358

def name
  reflected_string("name")
end

#name=(v) ⇒ Object



362
363
364
# File 'lib/dommy/html_elements.rb', line 362

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

#patternObject



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

def pattern
  reflected_string("pattern")
end

#placeholderObject



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

def placeholder
  reflected_string("placeholder")
end

#placeholder=(v) ⇒ Object



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

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.



472
473
474
# File 'lib/dommy/html_elements.rb', line 472

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

#readonlyObject



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

def readonly
  reflected_boolean("readonly")
end

#readonly=(v) ⇒ Object



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

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

#report_validityObject



573
574
575
# File 'lib/dommy/html_elements.rb', line 573

def report_validity
  check_validity
end

#requiredObject



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

def required
  reflected_boolean("required")
end

#required=(v) ⇒ Object



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

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

#sanitize_number(raw) ⇒ Object



461
462
463
464
465
466
467
# File 'lib/dommy/html_elements.rb', line 461

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).



440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
# File 'lib/dommy/html_elements.rb', line 440

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.



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

def select
  nil
end

#set_custom_validity(msg) ⇒ Object



577
578
579
580
# File 'lib/dommy/html_elements.rb', line 577

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

#set_range_text(_replacement, *_) ⇒ Object



528
529
530
# File 'lib/dommy/html_elements.rb', line 528

def set_range_text(_replacement, *_)
  nil
end

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



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

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

#stepObject



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

def step
  reflected_string("step")
end

#step_down(_n = 1) ⇒ Object



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

def step_down(_n = 1)
  nil
end

#step_up(_n = 1) ⇒ Object



532
533
534
# File 'lib/dommy/html_elements.rb', line 532

def step_up(_n = 1)
  nil
end

#typeObject



349
350
351
352
# File 'lib/dommy/html_elements.rb', line 349

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

#type=(v) ⇒ Object



354
355
356
# File 'lib/dommy/html_elements.rb', line 354

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

#validation_messageObject



554
555
556
557
558
559
560
561
562
563
564
565
# File 'lib/dommy/html_elements.rb', line 554

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



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

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.



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

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

#value=(v) ⇒ Object



418
419
420
421
422
# File 'lib/dommy/html_elements.rb', line 418

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.



546
547
548
549
550
551
552
# File 'lib/dommy/html_elements.rb', line 546

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