Skip to content

Commit 32227cb

Browse files
author
Mark Pilgrim
committed
added support for validating contextmenu attribute
--HG-- extra : convert_revision : svn%3Aacbfec75-9323-0410-a652-858a13e371e0/trunk%40978
1 parent f7ea692 commit 32227cb

File tree

1 file changed

+51
-17
lines changed

1 file changed

+51
-17
lines changed

src/html5lib/filters/validator.py

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,27 @@
3030
"unknown-attribute":
3131
_(u"Unknown '%(attributeName)s' attribute on <%(tagName)s>."),
3232
"missing-required-attribute":
33-
_(u"Missing required '%(attributeName)s' attribute on <%(tagName)s>."),
33+
_(u"The '%(attributeName)s' attribute is required on <%(tagName)s>."),
3434
"unknown-input-type":
35-
_(u"Illegal value for <input type> attribute: '%(inputType)s'."),
35+
_(u"Illegal value for attribute on <input type='%(inputType)s'>."),
3636
"attribute-not-allowed-on-this-input-type":
37-
_(u"'%(attributeName)s' attribute is not allowed on <input type=%(inputType)s>."),
37+
_(u"The '%(attributeName)s' attribute is not allowed on <input type=%(inputType)s>."),
3838
"deprecated-attribute":
39-
_(u"'%(attributeName)s' attribute is deprecated on <%(tagName)s>."),
39+
_(u"This attribute is deprecated: '%(attributeName)s' attribute on <%(tagName)s>."),
4040
"duplicate-value-in-token-list":
41-
_(u"Duplicate value '%(attributeValue)s' in token list in '%(attributeName)s' attribute on <%(tagName)s>."),
41+
_(u"Duplicate value in token list: '%(attributeValue)s' in '%(attributeName)s' attribute on <%(tagName)s>."),
4242
"invalid-attribute-value":
43-
_(u"Invalid value for '%(attributeName)s' attribute on <%(tagName)s>."),
43+
_(u"Invalid attribute value: '%(attributeName)s' attribute on <%(tagName)s>."),
4444
"space-in-id":
45-
_(u"Illegal space character in ID attribute on <%(tagName)s>."),
45+
_(u"Whitespace is not allowed here: '%(attributeName)s' attribute on <%(tagName)s>."),
4646
"duplicate-id":
47-
_(u"Duplicate ID on <%(tagName)s>."),
47+
_(u"This ID was already defined earlier: 'id' attribute on <%(tagName)s>."),
4848
"attribute-value-can-not-be-blank":
49-
_(u"Value can not be blank: '%(attributeName)s' attribute on <%(tagName)s>."),
49+
_(u"This value can not be blank: '%(attributeName)s' attribute on <%(tagName)s>."),
50+
"id-does-not-exist":
51+
_(u"This value refers to a non-existent ID: '%(attributeName)s' attribute on <%(tagName)s>."),
52+
"contextmenu-must-point-to-menu":
53+
_(u"The contextmenu attribute must point to an ID defined on a <menu> element."),
5054
})
5155

5256
globalAttributes = frozenset(('class', 'contenteditable', 'contextmenu', 'dir',
@@ -237,6 +241,7 @@ def __iter__(self):
237241
if method:
238242
for t in method(token) or []: yield t
239243
yield token
244+
for t in self.eof() or []: yield t
240245

241246
def checkAttributeValues(self, token):
242247
tagName = token.get("name", "")
@@ -252,6 +257,28 @@ def checkAttributeValues(self, token):
252257
if method:
253258
for t in method(token, tagName, attrName, attrValue) or []: yield t
254259

260+
def eof(self):
261+
for token in self.thingsThatPointToAnID:
262+
tagName = token.get("name", "").lower()
263+
attrsDict = token["data"] # by now html5parser has "normalized" the attrs list into a dict.
264+
# hooray for obscure side effects!
265+
attrValue = attrsDict.get("contextmenu", "")
266+
if attrValue and (attrValue not in self.IDsWeHaveKnownAndLoved):
267+
yield {"type": "ParseError",
268+
"data": "id-does-not-exist",
269+
"datavars": {"tagName": tagName,
270+
"attributeName": "contextmenu",
271+
"attributeValue": attrValue}}
272+
else:
273+
for refToken in self.thingsThatDefineAnID:
274+
id = refToken.get("data", {}).get("id", "")
275+
if not id: continue
276+
if id == attrValue:
277+
if refToken.get("name", "").lower() != "menu":
278+
yield {"type": "ParseError",
279+
"data": "contextmenu-must-point-to-menu"}
280+
break
281+
255282
def validateStartTag(self, token):
256283
for t in self.checkUnknownStartTag(token) or []: yield t
257284
for t in self.checkStartTagRequiredAttributes(token) or []: yield t
@@ -338,30 +365,37 @@ def validateAttributeValueContenteditable(self, token, tagName, attrName, attrVa
338365
"datavars": {"tagName": tagName,
339366
"attributeName": attrName}}
340367

368+
def validateAttributeValueContextmenu(self, token, tagName, attrName, attrValue):
369+
for t in self.checkIDValue(token, tagName, attrName, attrValue) or []: yield t
370+
self.thingsThatPointToAnID.append(token)
371+
341372
def validateAttributeValueId(self, token, tagName, attrName, attrValue):
342373
# This method has side effects. It adds 'token' to the list of
343374
# things that define an ID (self.thingsThatDefineAnID) so that we can
344375
# later check 1) whether an ID is duplicated, and 2) whether all the
345376
# things that point to something else by ID (like <label for> or
346377
# <span contextmenu>) point to an ID that actually exists somewhere.
347-
if not attrValue:
348-
yield {"type": "ParseError",
349-
"data": "attribute-value-can-not-be-blank",
350-
"datavars": {"tagName": tagName,
351-
"attributeName": attrName}}
352-
return
353-
378+
for t in self.checkIDValue(token, tagName, attrName, attrValue) or []: yield t
379+
if not attrValue: return
354380
if attrValue in self.IDsWeHaveKnownAndLoved:
355381
yield {"type": "ParseError",
356382
"data": "duplicate-id",
357383
"datavars": {"tagName": tagName}}
358384
self.IDsWeHaveKnownAndLoved.append(attrValue)
359385
self.thingsThatDefineAnID.append(token)
386+
387+
def checkIDValue(self, token, tagName, attrName, attrValue):
388+
if not attrValue:
389+
yield {"type": "ParseError",
390+
"data": "attribute-value-can-not-be-blank",
391+
"datavars": {"tagName": tagName,
392+
"attributeName": attrName}}
360393
for c in attrValue:
361394
if c in spaceCharacters:
362395
yield {"type": "ParseError",
363396
"data": "space-in-id",
364-
"datavars": {"tagName": tagName}}
397+
"datavars": {"tagName": tagName,
398+
"attributeName": attrName}}
365399
yield {"type": "ParseError",
366400
"data": "invalid-attribute-value",
367401
"datavars": {"tagName": tagName,

0 commit comments

Comments
 (0)