Class: HTMLConformanceChecker

Inherits:
HTML5::Filters::Base show all
Defined in:
lib/html5/filters/validator.rb

Constant Summary collapse

@@global_attributes =
%w[class contenteditable contextmenu dir
draggable id irrelevant lang ref tabindex template
title onabort onbeforeunload onblur onchange onclick
oncontextmenu ondblclick ondrag ondragend ondragenter
ondragleave ondragover ondragstart ondrop onerror
onfocus onkeydown onkeypress onkeyup onload onmessage
onmousedown onmousemove onmouseout onmouseover onmouseup
onmousewheel onresize onscroll onselect onsubmit onunload]
@@allowed_attribute_map =

XXX lang in HTML only, xml:lang in XHTML only XXX validate ref, template

{
  'html'         => %w[xmlns],
  'head'         => [],
  'title'        => [],
  'base'         => %w[href target],
  'link'         => %w[href rel media hreflang type],
  'meta'         => %w[name http-equiv content charset], # XXX charset in HTML only
  'style'        => %w[media type scoped],
  'body'         => [],
  'section'      => [],
  'nav'          => [],
  'article'      => [],
  'blockquote'   => %w[cite],
  'aside'        => [],
  'h1'           => [],
  'h2'           => [],
  'h3'           => [],
  'h4'           => [],
  'h5'           => [],
  'h6'           => [],
  'header'       => [],
  'footer'       => [],
  'address'      => [],
  'p'            => [],
  'hr'           => [],
  'br'           => [],
  'dialog'       => [],
  'pre'          => [],
  'ol'           => %w[start],
  'ul'           => [],
  'li'           => %w[value], # XXX depends on parent
  'dl'           => [],
  'dt'           => [],
  'dd'           => [],
  'a'            => %w[href target ping rel media hreflang type],
  'q'            => %w[cite],
  'cite'         => [],
  'em'           => [],
  'strong'       => [],
  'small'        => [],
  'm'            => [],
  'dfn'          => [],
  'abbr'         => [],
  'time'         => %w[datetime],
  'meter'        => %w[value min low high max optimum],
  'progress'     => %w[value max],
  'code'         => [],
  'var'          => [],
  'samp'         => [],
  'kbd'          => [],
  'sup'          => [],
  'sub'          => [],
  'span'         => [],
  'i'            => [],
  'b'            => [],
  'bdo'          => [],
  'ins'          => %w[cite datetime],
  'del'          => %w[cite datetime],
  'figure'       => [],
  'img'          => %w[alt src usemap ismap height width], # XXX ismap depends on parent
  'iframe'       => %w[src],
  # <embed> handled separately
  'object'       => %w[data type usemap height width],
  'param'        => %w[name value],
  'video'        => %w[src autoplay start loopstart loopend end loopcount controls],
  'audio'        => %w[src autoplay start loopstart loopend end loopcount controls],
  'source'       => %w[src type media],
  'canvas'       => %w[height width],
  'map'          => [],
  'area'         => %w[alt coords shape href target ping rel media hreflang type],
  'table'        => [],
  'caption'      => [],
  'colgroup'     => %w[span], # XXX only if element contains no <col> elements
  'col'          => %w[span],
  'tbody'        => [],
  'thead'        => [],
  'tfoot'        => [],
  'tr'           => [],
  'td'           => %w[colspan rowspan],
  'th'           => %w[colspan rowspan scope],
  # all possible <input> attributes are listed here but <input> is really handled separately
  'input'        => %w[accept accesskey action alt autocomplete autofocus checked
                       disabled enctype form inputmode list maxlength method min 
                       max name pattern step readonly replace required size src
                       tabindex target template value
  ],
  'form'         => %w[action method enctype accept name onsubmit onreset accept-charset
                       data replace
  ],
  'button'       => %w[action enctype method replace template name value type disabled form autofocus], # XXX may need matrix of acceptable attributes based on value of type attribute (like input)
  'select'       => %w[name size multiple disabled data accesskey form autofocus],
  'optgroup'     => %w[disabled label],
  'option'       => %w[selected disabled label value],
  'textarea'     => %w[maxlength name rows cols disabled readonly required form autofocus wrap accept],
  'label'        => %w[for accesskey form],
  'fieldset'     => %w[disabled form],
  'output'       => %w[form name for onforminput onformchange],
  'datalist'     => %w[data],
   # XXX repetition model for repeating form controls
  'script'       => %w[src defer async type],
  'noscript'     => [],
  'noembed'      => [],
  'event-source' => %w[src],
  'details'      => %w[open],
  'datagrid'     => %w[multiple disabled],
  'command'      => %w[type label icon hidden disabled checked radiogroup default],
  'menu'         => %w[type label autosubmit],
  'datatemplate' => [],
  'rule'         => [],
  'nest'         => [],
  'legend'       => [],
  'div'          => [],
  'font'         => %w[style]
}
@@required_attribute_map =
{
  'link'   => %w[href rel],
  'bdo'    => %w[dir],
  'img'    => %w[src],
  'embed'  => %w[src],
  'object' => [], # XXX one of 'data' or 'type' is required
  'param'  => %w[name value],
  'source' => %w[src],
  'map'    => %w[id]
}
@@input_type_allowed_attribute_map =
{
  'text'           => %w[accesskey autocomplete autofocus disabled form inputmode list maxlength name pattern readonly required size tabindex value],
  'password'       => %w[accesskey autocomplete autofocus disabled form inputmode maxlength name pattern readonly required size tabindex value],
  'checkbox'       => %w[accesskey autofocus checked disabled form name required tabindex value],
  'radio'          => %w[accesskey autofocus checked disabled form name required tabindex value],
  'button'         => %w[accesskey autofocus disabled form name tabindex value],
  'submit'         => %w[accesskey action autofocus disabled enctype form method name replace tabindex target value],
  'reset'          => %w[accesskey autofocus disabled form name tabindex value],
  'add'            => %w[accesskey autofocus disabled form name tabindex template value],
  'remove'         => %w[accesskey autofocus disabled form name tabindex value],
  'move-up'        => %w[accesskey autofocus disabled form name tabindex value],
  'move-down'      => %w[accesskey autofocus disabled form name tabindex value],
  'file'           => %w[accept accesskey autofocus disabled form min max name required tabindex],
  'hidden'         => %w[disabled form name value],
  'image'          => %w[accesskey action alt autofocus disabled enctype form method name replace src tabindex target],
  'datetime'       => %w[accesskey autocomplete autofocus disabled form list min max name step readonly required tabindex value],
  'datetime-local' => %w[accesskey autocomplete autofocus disabled form list min max name step readonly required tabindex value],
  'date'           => %w[accesskey autocomplete autofocus disabled form list min max name step readonly required tabindex value],
  'month'          => %w[accesskey autocomplete autofocus disabled form list min max name step readonly required tabindex value],
  'week'           => %w[accesskey autocomplete autofocus disabled form list min max name step readonly required tabindex value],
  'time'           => %w[accesskey autocomplete autofocus disabled form list min max name step readonly required tabindex value],
  'number'         => %w[accesskey autocomplete autofocus disabled form list min max name step readonly required tabindex value],
  'range'          => %w[accesskey autocomplete autofocus disabled form list min max name step readonly required tabindex value],
  'email'          => %w[accesskey autocomplete autofocus disabled form inputmode list maxlength name pattern readonly required tabindex value],
  'url'            => %w[accesskey autocomplete autofocus disabled form inputmode list maxlength name pattern readonly required tabindex value],
}
@@input_type_deprecated_attribute_map =
{
  'text'     => ['size'],
  'password' => ['size']
}
%w[alternate archive archives author contact feed first begin start help icon index top contents toc last end license copyright next pingback prefetch prev previous search stylesheet sidebar tag up]
@@a_rel_values =
%w[alternate archive archives author contact feed first begin start help index top contents toc last end license copyright next prev previous search sidebar tag up bookmark external nofollow]

Instance Method Summary collapse

Constructor Details

#initialize(stream, *args) ⇒ HTMLConformanceChecker

Returns a new instance of HTMLConformanceChecker.



267
268
269
270
271
272
# File 'lib/html5/filters/validator.rb', line 267

def initialize(stream, *args)
  super(HTML5::HTMLTokenizer.new(stream, *args))
  @things_that_define_an_id    = []
  @things_that_point_to_an_id  = []
  @ids_we_have_known_and_loved = []
end

Instance Method Details

#check_attribute_values(token) ⇒ Object

Attribute validation



655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
# File 'lib/html5/filters/validator.rb', line 655

def check_attribute_values(token)
  tag_name = token.fetch(:name, "")
  for attr_name, attr_value in token.fetch(:data, [])
    attr_name = attr_name.downcase
    method = "validate_attribute_value_#{tag_name.to_s.underscore}_#{attr_name.to_s.underscore}"
    if respond_to?(method)
      send(method, token, tag_name, attr_name, attr_value) do |t|
        yield t
      end
    else
      method = "validate_attribute_value_#{attr_name.to_s.underscore}"
      if respond_to?(method)
        send(method, token, tag_name, attr_name, attr_value) do |t|
          yield t
        end
      end
    end
  end
end

#check_boolean(token, tag_name, attr_name, attr_value) ⇒ Object Also known as: validate_attribute_value_irrelevant, validate_attribute_value_style_scoped



514
515
516
517
518
519
520
521
522
523
524
525
526
527
# File 'lib/html5/filters/validator.rb', line 514

def check_boolean(token, tag_name, attr_name, attr_value)
  enumerated_values = [attr_name, '']
  if !enumerated_values.include?(attr_value)
    yield( {:type => "ParseError",
         :data => "invalid-boolean-value",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name,
              "enumeratedValues" => enumerated_values}})
    yield( {:type => "ParseError",
         :data => "invalid-attribute-value",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
  end
end

#check_browsing_context(token, tag_name, attr_name, attr_value) {|{:type => "ParseError", :data => "invalid-browsing-context", :datavars => {"tagName" => tag_name, "attributeName" => attr_name}}| ... } ⇒ Object Also known as: validate_attribute_value_base_target, validate_attribute_value_a_target

Yields:

  • ({:type => "ParseError", :data => "invalid-browsing-context", :datavars => {"tagName" => tag_name, "attributeName" => attr_name}})


581
582
583
584
585
586
587
588
589
590
# File 'lib/html5/filters/validator.rb', line 581

def check_browsing_context(token, tag_name, attr_name, attr_value)
  return if not attr_value
  return if attr_value[0] != ?_
  attr_value.downcase!
  return if ['_self', '_parent', '_top', '_blank'].include?(attr_value)
  yield({:type => "ParseError",
       :data => "invalid-browsing-context",
       :datavars => {"tagName" => tag_name,
            "attributeName" => attr_name}})
end

#check_date_time(token, tag_name, attr_name, attr_value) ⇒ Object Also known as: validate_attribute_value_time_datetime, validate_attribute_value_ins_datetime, validate_attribute_value_del_datetime



640
641
642
643
644
645
646
647
648
649
# File 'lib/html5/filters/validator.rb', line 640

def check_date_time(token, tag_name, attr_name, attr_value)
  # XXX
  state = 'begin' # ('begin', '...
#    for c in attr_value
#      if state == 'begin' =>
#        if SPACE_CHARACTERS.include?(c)
#          continue
#        elsif digits.include?(c)
#          state = ...
end

#check_enumerated_value(token, tag_name, attr_name, attr_value, enumerated_values) ⇒ Object



492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
# File 'lib/html5/filters/validator.rb', line 492

def check_enumerated_value(token, tag_name, attr_name, attr_value, enumerated_values)
  if !attr_value || attr_value.length == 0
    yield( {:type => "ParseError",
         :data => "attribute-value-can-not-be-blank",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
    return
  end
  attr_value.downcase!
  if !enumerated_values.include?(attr_value)
    yield( {:type => "ParseError",
         :data => "invalid-enumerated-value",
         :datavars => {"tagName" => tag_name,
              "attribute_name" => attr_name,
              "enumeratedValues" => enumerated_values}})
    yield( {:type => "ParseError",
         :data => "invalid-attribute-value",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
  end
end

#check_floating_point_number(token, tag_name, attr_name, attr_value) ⇒ Object Also known as: validate_attribute_value_meter_value, validate_attribute_value_meter_min, validate_attribute_value_meter_low, validate_attribute_value_meter_high, validate_attribute_value_meter_max, validate_attribute_value_meter_optimum, validate_attribute_value_progress_value, validate_attribute_value_progress_max



577
578
579
# File 'lib/html5/filters/validator.rb', line 577

def check_floating_point_number(token, tag_name, attr_name, attr_value)
  # XXX
end

#check_id(token, tag_name, attr_name, attr_value) ⇒ Object



429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# File 'lib/html5/filters/validator.rb', line 429

def check_id(token, tag_name, attr_name, attr_value)
  if !attr_value || attr_value.length == 0
    yield({:type => "ParseError",
            :data => "attribute-value-can-not-be-blank",
            :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
  end
  attr_value.each_byte do |b|
    c = [b].pack('c*')
    if HTML5::SPACE_CHARACTERS.include?(c)
      yield( {:type => "ParseError",
           :data => "space-in-id",
           :datavars => {"tagName" => tag_name,
                "attributeName" => attr_name}})
      yield( {:type => "ParseError",
           :data => "invalid-attribute-value",
           :datavars => {"tagName" => tag_name,
                "attributeName" => attr_name}})
      break
    end
  end
end

#check_integer(token, tag_name, attr_name, attr_value) ⇒ Object Also known as: validate_attribute_value_tabindex, validate_attribute_value_ol_start, validate_attribute_value_li_value



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
# File 'lib/html5/filters/validator.rb', line 529

def check_integer(token, tag_name, attr_name, attr_value)
  sign = 1
  number_string = ''
  state = 'begin' # ('begin', 'initial-number', 'number', 'trailing-junk')
  error = {:type => "ParseError",
       :data => "invalid-integer-value",
       :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name,
              "attributeValue" => attr_value}}
  attr_value.scan(/./) do |c|
    if state == 'begin'
      if HTML5::SPACE_CHARACTERS.include?(c)
        next
      elsif c == '-'
        sign  = -1
        state = 'initial-number'
      elsif HTML5::DIGITS.include?(c)
        number_string += c
        state = 'in-number'
      else
        yield error
        return
      end
    elsif state == 'initial-number'
      if !HTML5::DIGITS.include?(c)
        yield error
        return
      end
      number_string += c
      state = 'in-number'
    elsif state == 'in-number'
      if HTML5::DIGITS.include?(c)
        number_string += c
      else
        state = 'trailing-junk'
      end
    elsif state == 'trailing-junk'
      next
    end
  end
  if number_string.length == 0
    yield( {:type => "ParseError",
         :data => "attribute-value-can-not-be-blank",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
  end
end

#check_iri(token, tag_name, attr_name, attr_value) ⇒ Object Also known as: validate_attribute_value_base_href, validate_attribute_value_link_href, validate_attribute_value_blockquote_cite, validate_attribute_value_a_href, validate_attribute_value_q_cite, validate_attribute_value_ins_cite, validate_attribute_value_del_cite

def checkURI(token, tag_name, attr_name, attr_value)

is_valid, error_code = rfc3987.is_valid_uri(attr_value)
if not is_valid
  yield {:type => "ParseError",
       :data => error_code,
       :datavars => {"tagName" => tag_name,
            "attributeName" => attr_name}}
  yield {:type => "ParseError",
       :data => "invalid-attribute-value",
       :datavars => {"tagName" => tag_name,
            "attributeName" => attr_name}}


415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/html5/filters/validator.rb', line 415

def check_iri(token, tag_name, attr_name, attr_value)
  is_valid, error_code = is_valid_iri(attr_value)
  if !is_valid
    yield({:type => "ParseError",
           :data => error_code,
           :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
    yield({:type => "ParseError",
           :data => "invalid-attribute-value",
           :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
  end
end

#check_lang_code(token, tag_name, attr_name, attr_value) ⇒ Object Also known as: validate_attribute_value_lang, validate_attribute_value_link_hreflang, validate_attribute_value_a_hreflang



592
593
594
595
596
597
598
599
600
601
# File 'lib/html5/filters/validator.rb', line 592

def check_lang_code(token, tag_name, attr_name, attr_value)
  return if !attr_value || attr_value == '' # blank is OK
  if not is_valid_lang_code(attr_value)
    yield( {:type => "ParseError",
         :data => "invalid-lang-code",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name,
              "attributeValue" => attr_value}})
  end
end


624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
# File 'lib/html5/filters/validator.rb', line 624

def check_link_relation(token, tag_name, attr_name, attr_value)
  check_token_list(tag_name, attr_name, attr_value) do |t|
    yield t
  end
  value_list = parse_token_list(attr_value)
  allowed_values = tag_name == 'link' ? @@link_rel_values : @@a_rel_values
  for current_value in value_list
    if !allowed_values.include?(current_value)
      yield({:type => "ParseError",
           :data => "invalid-rel",
           :datavars => {"tagName" => tag_name,
                "attributeName" => attr_name}})
    end
  end
end

#check_media_query(token, tag_name, attr_name, attr_value) ⇒ Object Also known as: validate_attribute_value_link_media, validate_attribute_value_style_media, validate_attribute_value_a_media



620
621
622
# File 'lib/html5/filters/validator.rb', line 620

def check_media_query(token, tag_name, attr_name, attr_value)
  # XXX
end

#check_mime_type(token, tag_name, attr_name, attr_value) ⇒ Object Also known as: validate_attribute_value_link_type, validate_attribute_value_style_type, validate_attribute_value_a_type



603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
# File 'lib/html5/filters/validator.rb', line 603

def check_mime_type(token, tag_name, attr_name, attr_value)
  # XXX needs tests
  if not attr_value
    yield( {:type => "ParseError",
         :data => "attribute-value-can-not-be-blank",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
  end
  if not is_valid_mime_type(attr_value)
    yield( {:type => "ParseError",
         :data => "invalid-mime-type",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name,
              "attributeValue" => attr_value}})
  end
end

#check_start_tag_required_attributes(token) ⇒ Object



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/html5/filters/validator.rb', line 369

def check_start_tag_required_attributes(token)
  # check for presence of required attributes
  name = (token[:name] || "").downcase
  if @@required_attribute_map.keys().include?(name)
    attrs_present = (token[:data] || []).collect{|t| t[0]}
    for attr_name in @@required_attribute_map[name]
      if !attrs_present.include?(attr_name)
        yield( {:type => "ParseError",
             :data => "missing-required-attribute",
             :datavars => {"tagName" => name,
                  "attributeName" => attr_name}})
      end
    end
  end
end

#check_start_tag_unknown_attributes(token) ⇒ Object



385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/html5/filters/validator.rb', line 385

def check_start_tag_unknown_attributes(token)
  # check for recognized attribute names
  name = token[:name].downcase
  allowed_attributes = @@global_attributes | @@allowed_attribute_map.fetch(name, [])
  for attr_name, attr_value in token.fetch(:data, [])
    if !allowed_attributes.include?(attr_name.downcase())
      yield( {:type => "ParseError",
           :data => "unknown-attribute",
           :datavars => {"tagName" => name,
                "attributeName" => attr_name}})
    end
  end
end

#check_token_list(tag_name, attr_name, attr_value) ⇒ Object



472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
# File 'lib/html5/filters/validator.rb', line 472

def check_token_list(tag_name, attr_name, attr_value)
  # The "token" in the method name refers to tokens in an attribute value
  # i.e. http://www.whatwg.org/specs/web-apps/current-work/#set-of
  # but the "token" parameter refers to the token generated from
  # HTMLTokenizer.  Sorry for the confusion.
  value_list = parse_token_list(attr_value)
  value_dict = {}
  for current_value in value_list
    if value_dict.has_key?(current_value)
      yield({:type => "ParseError",
           :data => "duplicate-value-in-token-list",
           :datavars => {"tagName" => tag_name,
                "attributeName" => attr_name,
                "attributeValue" => current_value}})
      break
    end
    value_dict[current_value] = 1
  end
end

#check_unknown_start_tag(token) ⇒ Object

Start tag validation helpers



359
360
361
362
363
364
365
366
367
# File 'lib/html5/filters/validator.rb', line 359

def check_unknown_start_tag(token)
  # check for recognized tag name
  name = (token[:name] || "").downcase
  if !@@allowed_attribute_map.keys.include?(name)
    yield({:type => "ParseError",
           :data => "unknown-start-tag",
           :datavars => {"tagName" => name}})
  end
end

#eachObject



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/html5/filters/validator.rb', line 274

def each
  __getobj__.each do |token|
    method = "validate_#{token.fetch(:type, '-').to_s.underscore}_#{token.fetch(:name, '-').to_s.underscore}"
    if respond_to?(method)
      send(method, token){|t| yield t }
    else
      method = "validate_#{token.fetch(:type, '-').to_s.underscore}"
      if respond_to?(method)
        send(method, token) do |t|
          yield t
        end
      end
    end
    yield token
  end
  eof do |t|
    yield t
  end
end

#eofObject

Whole document validation (IDs, etc.)



801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
# File 'lib/html5/filters/validator.rb', line 801

def eof
  for token in @things_that_point_to_an_id
    tag_name = token.fetch(:name, "").downcase
    attrs_dict = token[:data] # by now html5parser has "normalized" the attrs list into a dict.
                  # hooray for obscure side effects!
    attr_value = attrs_dict.fetch("contextmenu", "")
    if attr_value and (!@ids_we_have_known_and_loved.include?(attr_value))
      yield( {:type => "ParseError",
           :data => "id-does-not-exist",
           :datavars => {"tagName" => tag_name,
                "attributeName" => "contextmenu",
                "attributeValue" => attr_value}})
    else
      for ref_token in @things_that_define_an_id
        id = ref_token.fetch(:data, {}).fetch("id", "")
        if not id
          continue
        end
        if id == attr_value
          if ref_token.fetch(:name, "").downcase != "men"
            yield( {:type => "ParseError",
                 :data => "contextmenu-must-point-to-menu"})
          end
          break
        end
      end
    end
  end
end

#parse_token_list(value) ⇒ Object



452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
# File 'lib/html5/filters/validator.rb', line 452

def parse_token_list(value)
  valueList = []
  currentValue = ''
  (value + ' ').each_byte do |b|
    c = [b].pack('c*')
    if HTML5::SPACE_CHARACTERS.include?(c)
      if currentValue.length > 0
        valueList << currentValue
        currentValue = ''
      end
    else
      currentValue += c
    end
  end
  if currentValue.length > 0
    valueList << currentValue
  end
  valueList
end

#validate_attribute_value_a_ping(token, tag_name, attr_name, attr_value) ⇒ Object



769
770
771
772
773
774
775
776
# File 'lib/html5/filters/validator.rb', line 769

def validate_attribute_value_a_ping(token, tag_name, attr_name, attr_value)
  value_list = parse_token_list(attr_value)
  for current_value in value_list
    checkIRI(token, tag_name, attr_name, attr_value) do |t|
      yield t
    end
  end
end

#validate_attribute_value_class(token, tag_name, attr_name, attr_value) ⇒ Object



675
676
677
678
679
680
681
682
683
# File 'lib/html5/filters/validator.rb', line 675

def validate_attribute_value_class(token, tag_name, attr_name, attr_value)
  check_token_list(tag_name, attr_name, attr_value) do |t|
    yield t
    yield( {:type => "ParseError",
         :data => "invalid-attribute-value",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
  end
end

#validate_attribute_value_contenteditable(token, tag_name, attr_name, attr_value) ⇒ Object



685
686
687
688
689
# File 'lib/html5/filters/validator.rb', line 685

def validate_attribute_value_contenteditable(token, tag_name, attr_name, attr_value)
  check_enumerated_value(token, tag_name, attr_name, attr_value, ['true', 'false', '']) do |t|
    yield t
  end
end

#validate_attribute_value_contextmenu(token, tag_name, attr_name, attr_value) ⇒ Object



706
707
708
709
710
711
# File 'lib/html5/filters/validator.rb', line 706

def validate_attribute_value_contextmenu(token, tag_name, attr_name, attr_value)
  check_id(token, tag_name, attr_name, attr_value) do |t|
    yield t
  end
  @things_that_point_to_an_id << token
end

#validate_attribute_value_dir(token, tag_name, attr_name, attr_value) ⇒ Object



691
692
693
694
695
# File 'lib/html5/filters/validator.rb', line 691

def validate_attribute_value_dir(token, tag_name, attr_name, attr_value)
  check_enumerated_value(token, tag_name, attr_name, attr_value, ['ltr', 'rtl']) do |t|
    yield t
  end
end

#validate_attribute_value_draggable(token, tag_name, attr_name, attr_value) ⇒ Object



697
698
699
700
701
# File 'lib/html5/filters/validator.rb', line 697

def validate_attribute_value_draggable(token, tag_name, attr_name, attr_value)
  check_enumerated_value(token, tag_name, attr_name, attr_value, ['true', 'false']) do |t|
    yield t
  end
end

#validate_attribute_value_html_xmlns(token, tag_name, attr_name, attr_value) ⇒ Object



742
743
744
745
746
747
748
749
# File 'lib/html5/filters/validator.rb', line 742

def validate_attribute_value_html_xmlns(token, tag_name, attr_name, attr_value)
  if attr_value != "http://www.w3.org/1999/xhtml"
    yield( {:type => "ParseError",
         :data => "invalid-root-namespace",
         :datavars => {"tagName" => tag_name,
              "attributeName" => attr_name}})
  end
end

#validate_attribute_value_id(token, tag_name, attr_name, attr_value) ⇒ Object



713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
# File 'lib/html5/filters/validator.rb', line 713

def validate_attribute_value_id(token, tag_name, attr_name, attr_value)
  # This method has side effects.  It adds 'token' to the list of
  # things that define an ID (@things_that_define_an_id) so that we can
  # later check 1) whether an ID is duplicated, and 2) whether all the
  # things that point to something else by ID (like <label for> or
  # <span contextmenu>) point to an ID that actually exists somewhere.
  check_id(token, tag_name, attr_name, attr_value) do |t|
    yield t
  end
  return if not attr_value
  if @ids_we_have_known_and_loved.include?(attr_value)
    yield( {:type => "ParseError",
         :data => "duplicate-id",
         :datavars => {"tagName" => tag_name}})
  end
  @ids_we_have_known_and_loved << attr_value
  @things_that_define_an_id << token
end

#validate_attribute_value_ref(token, tag_name, attr_name, attr_value) ⇒ Object



734
735
736
# File 'lib/html5/filters/validator.rb', line 734

def validate_attribute_value_ref(token, tag_name, attr_name, attr_value)
  # XXX
end

#validate_attribute_value_template(token, tag_name, attr_name, attr_value) ⇒ Object



738
739
740
# File 'lib/html5/filters/validator.rb', line 738

def validate_attribute_value_template(token, tag_name, attr_name, attr_value)
  # XXX
end

#validate_start_tag(token) ⇒ Object

Start tag validation



298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/html5/filters/validator.rb', line 298

def validate_start_tag(token)
  check_unknown_start_tag(token){|t| yield t}
  check_start_tag_required_attributes(token) do |t|
    yield t
  end
  check_start_tag_unknown_attributes(token) do |t|
    yield t
  end
  check_attribute_values(token) do |t|
    yield t
  end
end

#validate_start_tag_embed(token) ⇒ Object



311
312
313
314
315
316
317
318
319
320
# File 'lib/html5/filters/validator.rb', line 311

def validate_start_tag_embed(token)
  check_start_tag_required_attributes(token) do |t|
    yield t
  end
  check_attribute_values(token) do |t|
    yield t
  end
  # spec says "any attributes w/o namespace"
  # so don't call check_start_tag_unknown_attributes
end

#validate_start_tag_input(token) ⇒ Object



322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/html5/filters/validator.rb', line 322

def validate_start_tag_input(token)
  check_attribute_values(token) do |t|
    yield t
  end
  attr_dict = Hash[*token[:data].collect{|(name, value)| [name.downcase, value]}.flatten]
  input_type = attr_dict.fetch('type', "text")
  if !@@input_type_allowed_attribute_map.keys().include?(input_type)
    yield({:type => "ParseError",
         :data => "unknown-input-type",
         :datavars => {:attrValue => input_type}})
  end
  allowed_attributes = @@input_type_allowed_attribute_map.fetch(input_type, [])
  attr_dict.each do |attr_name, attr_value|
    if !@@allowed_attribute_map['input'].include?(attr_name)
      yield({:type => "ParseError",
           :data => "unknown-attribute",
           :datavars => {"tagName" => "input",
                "attributeName" => attr_name}})
    elsif !allowed_attributes.include?(attr_name)
      yield({:type => "ParseError",
           :data => "attribute-not-allowed-on-this-input-type",
           :datavars => {"attributeName" => attr_name,
                "inputType" => input_type}})
    end
    if @@input_type_deprecated_attribute_map.fetch(input_type, []).include?(attr_name)
      yield({:type => "ParseError",
           :data => "deprecated-attribute",
           :datavars => {"attributeName" => attr_name,
                "inputType" => input_type}})
    end
  end
end