Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export { default as idClassValue } from './id-class-value';
export { default as idUnique } from './id-unique';
export { default as inlineScriptDisabled } from './inline-script-disabled';
export { default as inlineStyleDisabled } from './inline-style-disabled';
export { default as inputRequiresLabel } from './input-requires-label';
export { default as scriptDisabled } from './script-disabled';
export { default as spaceTabMixedDisabled } from './space-tab-mixed-disabled';
export { default as specCharEscape } from './spec-char-escape';
Expand Down
46 changes: 46 additions & 0 deletions src/rules/input-requires-label.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export default {
id: 'input-requires-label',
description: 'All [ input ] tags must have a corresponding [ label ] tag. ',
init: function(parser, reporter){
var self = this,
labelTags = [],
inputTags = [];

parser.addListener('tagstart', function(event) {
var tagName = event.tagName.toLowerCase(),
mapAttrs = parser.getMapAttrs(event.attrs),
col = event.col + tagName.length + 1;

if (tagName === 'input') {
inputTags.push({event: event, col: col, id: mapAttrs['id']});
}

if (tagName === 'label') {
if (('for' in mapAttrs) && mapAttrs['for'] !== '') {
labelTags.push({event: event, col: col, forValue: mapAttrs['for']});
}
}

});

parser.addListener('end', function() {
inputTags.forEach(function(inputTag) {
if (!hasMatchingLabelTag(inputTag)) {
reporter.warn('No matching [ label ] tag found.', inputTag.event.line, inputTag.col, self, inputTag.event.raw);
}
});
});


function hasMatchingLabelTag(inputTag) {
var found = false;
labelTags.forEach(function(labelTag){
if (inputTag.id && (inputTag.id === labelTag.forValue)) {
found = true;
}
});
return found;

}
}
};
71 changes: 71 additions & 0 deletions test/rules/input-requires-label.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const expect = require("expect.js");

const HTMLHint = require('../../dist/htmlhint.js').HTMLHint;

const ruleId = 'input-requires-label';
const ruleOptions = {};

ruleOptions[ruleId] = true;

describe(`Rules: ${ruleId}`, function(){

describe('Successful cases', function() {

it('Input tag with a matching label before should result in no error', function () {
var code = '<label for="some-id"/><input id="some-id" type="password" />';
var messages = HTMLHint.verify(code, ruleOptions);
expect(messages.length).to.be(0);
});

it('Input tag with a matching label after should result in no error', function () {
var code = '<input id="some-id" type="password" /> <label for="some-id"/>';
var messages = HTMLHint.verify(code, ruleOptions);
expect(messages.length).to.be(0);
});
});


describe('Error cases', function() {

it('Input tag with no matching label should result in an error', function () {
var code = '<input type="password">';
var messages = HTMLHint.verify(code, ruleOptions);
expect(messages.length).to.be(1);
expect(messages[0].rule.id).to.be(ruleId);
expect(messages[0].line).to.be(1);
expect(messages[0].col).to.be(7);
expect(messages[0].type).to.be('warning');
});

it('Input tag with label that doesn\'t match id should result in error', function () {
var code = '<input id="some-id" type="password" /> <label for="some-other-id"/>';
var messages = HTMLHint.verify(code, ruleOptions);
expect(messages.length).to.be(1);
expect(messages[0].rule.id).to.be(ruleId);
expect(messages[0].line).to.be(1);
expect(messages[0].col).to.be(7);
expect(messages[0].type).to.be('warning');
});

it('Input tag with blank label:for should result in error', function () {
var code = '<input id="some-id" type="password" /> <label for=""/>';
var messages = HTMLHint.verify(code, ruleOptions);
expect(messages.length).to.be(1);
expect(messages[0].rule.id).to.be(ruleId);
expect(messages[0].line).to.be(1);
expect(messages[0].col).to.be(7);
expect(messages[0].type).to.be('warning');
});

it('Input tag with no id should result in error', function () {
var code = '<input type="password" /> <label for="something"/>';
var messages = HTMLHint.verify(code, ruleOptions);
expect(messages.length).to.be(1);
expect(messages[0].rule.id).to.be(ruleId);
expect(messages[0].line).to.be(1);
expect(messages[0].col).to.be(7);
expect(messages[0].type).to.be('warning');
});
});

});