-
Notifications
You must be signed in to change notification settings - Fork 791
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix implicit attribute use in duplicate-id #374
Conversation
ok, I deleted the confusing comments and replies so I could clarify:
I am not sure whether this is documented browser behavior or a side-effect? Can you find a reference? If it is documented, we might be better off detecting it and having a rule that raises this as a violation rather than trying to fix this everywhere. |
lib/checks/aria/required-parent.js
Outdated
if (element.getAttribute('id')) { | ||
o = document.querySelector( | ||
'[aria-owns~=' + | ||
axe.commons.utils.escapeSelector(element.getAttribute('id')) + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The line breaks don't make this much easier to read. Perhaps the escapeSelector line should be indented to indicate a group?
@dylanb @marcysutton Any further comments? |
Looks good to me! |
Don't merge
…--Dylan
On Jun 30, 2017, at 11:40 AM, Wilco Fiers ***@***.***> wrote:
@dylanb @marcysutton Any further comments?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@dylanb Don't merge, because ... ? |
lib/checks/forms/labelledby.js
Outdated
@@ -4,7 +4,11 @@ this.data({ | |||
}); | |||
|
|||
var matchingNodes = document.querySelectorAll('input[type="' + | |||
axe.commons.utils.escapeSelector(node.type) + '"][name="' + axe.commons.utils.escapeSelector(node.name) + '"]'); | |||
axe.commons.utils.escapeSelector(node.getAttribute('type')) + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why these changes?
@@ -1,3 +1,5 @@ | |||
var title = axe.commons.text.sanitize(node.title).trim().toLowerCase(); | |||
var title = axe.commons.text.sanitize( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
lib/commons/dom/is-in-text-block.js
Outdated
@@ -75,7 +75,7 @@ dom.isInTextBlock = function isInTextBlock(node) { | |||
return false; | |||
|
|||
// Don't walk links, we're only interested in what's not in them. | |||
} else if ((nodeName === 'A' && currNode.href) || | |||
} else if ((nodeName === 'A' && currNode.hasAttribute('href')) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the same - don't change this
lib/commons/text/accessible-text.js
Outdated
@@ -32,21 +33,23 @@ function findLabel(element) { | |||
} | |||
|
|||
function isButton(element) { | |||
return ['button', 'reset', 'submit'].indexOf(element.type) !== -1; | |||
return ['button', 'reset', 'submit'].includes( | |||
(element.getAttribute('type') || '').toLowerCase() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't change this
lib/commons/text/accessible-text.js
Outdated
} | ||
|
||
function isInput(element) { | ||
var nodeName = element.nodeName.toUpperCase(); | ||
return (nodeName === 'TEXTAREA' || nodeName === 'SELECT') || | ||
(nodeName === 'INPUT' && element.type.toLowerCase() !== 'hidden'); | ||
(nodeName === 'INPUT' && (element.getAttribute('type') || '').toLowerCase() !== 'hidden'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change this
lib/commons/text/accessible-text.js
Outdated
default: | ||
return false; | ||
} | ||
} | ||
|
||
function shouldCheckAlt(element) { | ||
var nodeName = element.nodeName.toUpperCase(); | ||
return (nodeName === 'INPUT' && element.type.toLowerCase() === 'image') || | ||
['IMG', 'APPLET', 'AREA'].indexOf(nodeName) !== -1; | ||
return (nodeName === 'INPUT' && (element.getAttribute('type') || '').toLowerCase() === 'image') || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change this
lib/commons/text/accessible-text.js
Outdated
@@ -199,7 +202,12 @@ text.accessibleText = function(element, inLabelledByContext) { | |||
|
|||
if (isInput(element) && !inControlContext) { | |||
if (isButton(element)) { | |||
return element.value || element.title || defaultButtonValues[element.type] || ''; | |||
return ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change
lib/core/utils/get-selector.js
Outdated
@@ -81,15 +81,15 @@ const createSelector = { | |||
nodeName = escapeSelector(nodeName); | |||
// Add [type] if nodeName is an input element | |||
if (nodeName === 'input' && elm.hasAttribute('type')) { | |||
nodeName += '[type="' + elm.type + '"]'; | |||
nodeName += `[type="${ elm.getAttribute('type') }"]`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change
lib/core/utils/get-selector.js
Outdated
} | ||
return nodeName; | ||
} | ||
}, | ||
// Has a name property, but no ID (Think input fields) | ||
getElmNameProp (elm) { | ||
if (!elm.id && elm.name) { | ||
return '[name="' + escapeSelector(elm.name) + '"]'; | ||
if (!elm.getAttribute('id') && elm.getAttribute('name')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change
lib/rules/color-contrast-matches.js
Outdated
@@ -1,7 +1,7 @@ | |||
/* global document */ | |||
|
|||
var nodeName = node.nodeName.toUpperCase(), | |||
nodeType = node.type, | |||
nodeType = node.getAttribute('type'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change
lib/rules/color-contrast-matches.js
Outdated
@@ -13,7 +13,7 @@ if (nodeName === 'INPUT') { | |||
} | |||
|
|||
if (nodeName === 'SELECT') { | |||
return !!node.options.length && !node.disabled; | |||
return !!node.options.length && !node.hasAttribute('disabled'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change
lib/rules/color-contrast-matches.js
Outdated
@@ -24,11 +24,11 @@ if (nodeName === 'OPTION') { | |||
return false; | |||
} | |||
|
|||
if (nodeName === 'BUTTON' && node.disabled || axe.commons.dom.findUp(node, 'button[disabled]')) { | |||
if (nodeName === 'BUTTON' && node.hasAttribute('disabled') || axe.commons.dom.findUp(node, 'button[disabled]')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change
lib/rules/color-contrast-matches.js
Outdated
return false; | ||
} | ||
|
||
if (nodeName === 'FIELDSET' && node.disabled || axe.commons.dom.findUp(node, 'fieldset[disabled]')) { | ||
if (nodeName === 'FIELDSET' && node.hasAttribute('disabled') || axe.commons.dom.findUp(node, 'fieldset[disabled]')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change
lib/rules/color-contrast-matches.js
Outdated
@@ -40,23 +40,25 @@ if (nodeName === 'LABEL' || nodeParentLabel) { | |||
relevantNode = nodeParentLabel; | |||
} | |||
// explicit label of disabled input | |||
var candidate = relevantNode.htmlFor && doc.getElementById(relevantNode.htmlFor); | |||
if (candidate && candidate.disabled) { | |||
var candidate = relevantNode.hasAttribute('for') && doc.getElementById(relevantNode.getAttribute('for')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't change
@WilcoFiers because I had not had time to review it yet...now that I have, I am totally confused - I thought that this change was specifically about the |
@dylanb The problem isn't limited to IDs. From what I found, any property on html, body, and form elements can be replaced with an accessor to a different element. You can even overwrite things like It's fortunately limited to a few elements, but because we're often using role selectors, we can't ever be entirely sure that element properties aren't what we think. You could even replace things like Probably |
@WilcoFiers have we had complaints from users that this is occurring? I found 39 uses of simply That being said, I don't see the need to make these changes if we have not had complaints because that means that this bad use of HTML is not occurring frequently enough to warrant the required changes. Also, not all attributes return the same value as the call to Bottom line: I don't think this is worth it. |
428eea2
to
a2b73f2
Compare
@dylanb fair enough. I'll roll some stuff back. As for replacing all instances of |
* chore: convert spaces to tabs in Gruntfile Align the file with the EditorConfig setting * chore: ignore package-lock.json This file is produced by NPM 5, but this repo didn't use the old shrinkwrap version so this should be excluded
lib/checks/label/explicit.js
Outdated
var label = document.querySelector('label[for="' + axe.commons.utils.escapeSelector(node.id) + '"]'); | ||
if (node.getAttribute('id')) { | ||
const id = axe.commons.utils.escapeSelector(node.getAttribute('id')); | ||
const label = document.querySelector(`label[for="${id}"]`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some mixed indentation here.
axe.commons.utils.escapeSelector(node.id) + '"]')), | ||
parent = node.parentNode; | ||
const id = axe.commons.utils.escapeSelector(node.getAttribute('id')); | ||
let labels = Array.from(document.querySelectorAll(`label[for="${id}"]`)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Array.from
here is so slick. I love it!
@@ -30,7 +30,10 @@ var tableGrid = tableUtils.toGrid(node); | |||
|
|||
// Look for all the bad headers | |||
var out = headers.reduce(function (res, header) { | |||
if (header.id && reffedHeaders.indexOf(header.id) !== -1) { | |||
if ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this code fit on one line under 80 characters? It would be more consistent with our existing style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree - lets keep our coding style consistent
lib/commons/table/is-header.js
Outdated
if (cell.id) { | ||
return !!document.querySelector('[headers~="' + axe.utils.escapeSelector(cell.id) + '"]'); | ||
if (cell.getAttribute('id')) { | ||
const id = axe.utils.escapeSelector(cell.getAttribute('id')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation is mixed up here due to spaces/tabs, I'm guessing.
lib/core/utils/get-xpath.js
Outdated
if(node.getAttribute && node.getAttribute('id') && | ||
node.ownerDocument.querySelectorAll('#' + axe.utils.escapeSelector(node.id)).length === 1) { | ||
|
||
if( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we put the first part of the expression inline with the if(
for consistency's sake?
test/checks/shared/duplicate-id.js
Outdated
@@ -49,4 +49,11 @@ describe('duplicate-id', function () { | |||
assert.isTrue(checks['duplicate-id'].evaluate.call(checkContext, node)); | |||
}); | |||
|
|||
it('should allow overwrote ids', function () { | |||
fixture.innerHTML = '<form data-testelm="1" id="target"><input name="id"></form>'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be overkill for test code...but as stewards of accessibility it would be appropriate to have a label in the fixture.
I left a few style comments, but otherwise this PR looks good to me. |
@WilcoFiers only one remaining jshint problem, then we can merge |
The id property can be overloaded, so we should use getAttribute()