|
41 | 41 | _(u"Duplicate value '%(attributeValue)s' in token list in '%(attributeName)s' attribute on <%(tagName)s>."),
|
42 | 42 | "invalid-attribute-value":
|
43 | 43 | _(u"Invalid value for '%(attributeName)s' attribute on <%(tagName)s>."),
|
| 44 | +"space-in-id": |
| 45 | +_(u"Illegal space character in ID attribute on <%(tagName)s>."), |
| 46 | +"duplicate-id": |
| 47 | +_(u"Duplicate ID on <%(tagName)s>."), |
| 48 | +"attribute-value-can-not-be-blank": |
| 49 | +_(u"Value can not be blank: '%(attributeName)s' attribute on <%(tagName)s>."), |
44 | 50 | })
|
45 | 51 |
|
46 | 52 | globalAttributes=frozenset(('class','contenteditable','contextmenu','dir',
|
@@ -215,6 +221,9 @@ class HTMLConformanceChecker(_base.Filter):
|
215 | 221 | def__init__(self,stream,encoding,parseMeta,**kwargs):
|
216 | 222 | _base.Filter.__init__(self,tokenizer.HTMLTokenizer(
|
217 | 223 | stream,encoding,parseMeta,**kwargs))
|
| 224 | +self.thingsThatDefineAnID= [] |
| 225 | +self.thingsThatPointToAnID= [] |
| 226 | +self.IDsWeHaveKnownAndLoved= [] |
218 | 227 |
|
219 | 228 | def__iter__(self):
|
220 | 229 | fortokenin_base.Filter.__iter__(self):
|
@@ -329,6 +338,36 @@ def validateAttributeValueContenteditable(self, token, tagName, attrName, attrVa
|
329 | 338 | "datavars": {"tagName":tagName,
|
330 | 339 | "attributeName":attrName}}
|
331 | 340 |
|
| 341 | +defvalidateAttributeValueId(self,token,tagName,attrName,attrValue): |
| 342 | +# This method has side effects. It adds 'token' to the list of |
| 343 | +# things that define an ID (self.thingsThatDefineAnID) so that we can |
| 344 | +# later check 1) whether an ID is duplicated, and 2) whether all the |
| 345 | +# things that point to something else by ID (like <label for> or |
| 346 | +# <span contextmenu>) point to an ID that actually exists somewhere. |
| 347 | +ifnotattrValue: |
| 348 | +yield {"type":"ParseError", |
| 349 | +"data":"attribute-value-can-not-be-blank", |
| 350 | +"datavars": {"tagName":tagName, |
| 351 | +"attributeName":attrName}} |
| 352 | +return |
| 353 | + |
| 354 | +ifattrValueinself.IDsWeHaveKnownAndLoved: |
| 355 | +yield {"type":"ParseError", |
| 356 | +"data":"duplicate-id", |
| 357 | +"datavars": {"tagName":tagName}} |
| 358 | +self.IDsWeHaveKnownAndLoved.append(attrValue) |
| 359 | +self.thingsThatDefineAnID.append(token) |
| 360 | +forcinattrValue: |
| 361 | +ifcinspaceCharacters: |
| 362 | +yield {"type":"ParseError", |
| 363 | +"data":"space-in-id", |
| 364 | +"datavars": {"tagName":tagName}} |
| 365 | +yield {"type":"ParseError", |
| 366 | +"data":"invalid-attribute-value", |
| 367 | +"datavars": {"tagName":tagName, |
| 368 | +"attributeName":attrName}} |
| 369 | +break |
| 370 | + |
332 | 371 | defcheckTokenList(self,tagName,attrName,attrValue):
|
333 | 372 | # The "token" in the method name refers to tokens in an attribute value
|
334 | 373 | # i.e. http://www.whatwg.org/specs/web-apps/current-work/#set-of
|
|