Skip to content

Commit d9f62c0

Browse files
author
Mark Pilgrim
committed
filled out list of acceptable and required attributes per tag
--HG-- extra : convert_revision : svn%3Aacbfec75-9323-0410-a652-858a13e371e0/trunk%40965
1 parent 8d18c09 commit d9f62c0

File tree

1 file changed

+82
-5
lines changed

1 file changed

+82
-5
lines changed

src/html5lib/filters/validator.py

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,73 @@
2121
E.update({
2222
"unrecognized-attribute":
2323
_(u"Unrecognized attribute '%(attributeName)s' in <%(tagName)s>"),
24+
"missing-required-attribute":
25+
_(u"Missing required attribute '%(attributeName)s' in <%(tagName)s>"),
2426
})
2527

26-
globalAttributes = ['id', 'title', 'lang', 'dir', 'class', 'irrelevant']
28+
globalAttributes = ['class', 'contenteditable', 'contextmenu', 'dir',
29+
'draggable', 'id', 'irrelevant', 'lang', 'ref', 'tabindex', 'template',
30+
'title', 'onabort', 'onbeforeunload', 'onblur', 'onchange', 'onclick',
31+
'oncontextmenu', 'ondblclick', 'ondrag', 'ondragend', 'ondragenter',
32+
'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror',
33+
'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onmessage',
34+
'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup',
35+
'onmousewheel', 'onresize', 'onscroll', 'onselect', 'onsubmit', 'onunload']
36+
# XXX lang in HTML only, xml:lang in XHTML only
37+
38+
modAttributes = ['cite', 'datetime']
39+
mediaAttributes = ['src', 'autoplay', 'start', 'loopstart', 'loopend', 'end',
40+
'loopcount', 'controls'],
2741
allowedAttributeMap = {
28-
'html': globalAttributes + ['xmlns']
42+
'html': ['xmlns'],
43+
'base': ['href', 'target'],
44+
'link': ['href', 'rel', 'media', 'hreflang', 'type'],
45+
'meta': ['name', 'http-equiv', 'content', 'charset'], # XXX charset in HTML only
46+
'style': ['media', 'type', 'scoped'],
47+
'blockquote': ['cite'],
48+
'ol': ['start'],
49+
'li': ['value'], # XXX depends on parent
50+
'a': ['href', 'target', 'ping', 'rel', 'media', 'hreflang', 'type'],
51+
'q': ['cite'],
52+
'time': ['datetime'],
53+
'meter': ['value', 'min', 'low', 'high', 'max', 'optimum'],
54+
'progress': ['value', 'max'],
55+
'ins': modAttributes,
56+
'del': modAttributes,
57+
'img': ['alt', 'src', 'usemap', 'ismap', 'height', 'width'], # XXX ismap depends on parent
58+
'iframe': ['src'],
59+
'object': ['data', 'type', 'usemap', 'height', 'width'],
60+
'param': ['name', 'value'],
61+
'video': mediaAttributes,
62+
'audio': mediaAttributes,
63+
'source': ['src', 'type', 'media'],
64+
'canvas': ['height', 'width'],
65+
'area': ['alt', 'coords', 'shape', 'href', 'target', 'ping', 'rel',
66+
'media', 'hreflang', 'type'],
67+
'colgroup': ['span'], # XXX only if element contains no <col> elements
68+
'col': ['span'],
69+
'td': ['colspan', 'rowspan'],
70+
'th': ['colspan', 'rowspan', 'scope'],
71+
# XXX form elements
72+
'script': ['src', 'defer', 'async', 'type'],
73+
'event-source': ['src'],
74+
'details': ['open'],
75+
'datagrid': ['multiple', 'disabled'],
76+
'command': ['type', 'label', 'icon', 'hidden', 'disabled', 'checked',
77+
'radiogroup', 'default'],
78+
'menu': ['type', 'label', 'autosubmit'],
79+
'font': ['style']
80+
}
81+
82+
requiredAttributeMap = {
83+
'link': ['href', 'rel'],
84+
'bdo': ['dir'],
85+
'img': ['src'],
86+
'embed': ['src'],
87+
'object': [], # XXX one of 'data' or 'type' is required
88+
'param': ['name', 'value'],
89+
'source': ['src'],
90+
'map': ['id'],
2991
}
3092

3193
class HTMLConformanceChecker(_base.Filter):
@@ -38,13 +100,28 @@ def __iter__(self):
38100
type = token["type"]
39101
if type == "StartTag":
40102
name = token["name"].lower()
41-
if name in allowedAttributeMap.keys():
42-
allowedAttributes = allowedAttributeMap[name]
103+
if name == 'embed':
104+
# XXX spec says "any attributes w/o namespace"
105+
pass
106+
else:
107+
if name in allowedAttributeMap.keys():
108+
allowedAttributes = globalAttributes + \
109+
allowedAttributeMap[name]
110+
else:
111+
allowedAttributes = globalAttributes
43112
for attrName, attrValue in token["data"]:
44113
if attrName.lower() not in allowedAttributes:
45114
yield {"type": "ParseError",
46115
"data": "unrecognized-attribute",
47116
"datavars": {"tagName": name,
48117
"attributeName": attrName}}
49-
118+
if name in requiredAttributeMap.keys():
119+
attrsPresent = [attrName for attrName, attrValue
120+
in token["data"]]
121+
for attrName in requiredAttributeMap[name]:
122+
if attrName not in attrsPresent:
123+
yield {"type": "ParseError",
124+
"data": "missing-required-attribute",
125+
"datavars": {"tagName": name,
126+
"attributeName": attrName}}
50127
yield token

0 commit comments

Comments
 (0)