Skip to content
This repository has been archived by the owner on Feb 1, 2022. It is now read-only.

Added options to configure number of grid cols and screen names #391

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
31 changes: 25 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ $ bootlint << EOF
EOF
```

Customized Bootstrap grid support with options:
`--cols` (or `-c`) to set number of columns.
`--screens` (or `-s`) which takes a comma-separated list of screen sizes.
Here's an example:

```shell
$ bootlint -c 20 -s xxs,xs,sm,md,lg,xlg /path/to/some/webpage.html another_webpage.html [...]
```


### In the browser

Use the following [bookmarklet](https://en.wikipedia.org/wiki/Bookmarklet) that's powered by [BootstrapCDN](https://www.bootstrapcdn.com/bootlint/):
Expand Down Expand Up @@ -118,12 +128,18 @@ A ***reporter*** is a function that accepts exactly 1 argument of type `LintWarn
Bootlint exports a `bootlint` property on the global `window` object.
In a browser environment, the following public APIs are available:

* `bootlint.lintCurrentDocument(reporter, disabledIds)`: Lints the HTML of the current document and calls the `reporter()` function repeatedly with each lint problem as an argument.
* `bootlint.lintCurrentDocument(reporter, options)`: Lints the HTML of the current document and calls the `reporter()` function repeatedly with each lint problem as an argument.
* `reporter` is a *reporter* function (see above for a definition). It will be called repeatedly with each lint problem as an argument.
* `disabledIds` is an array of string linter IDs to disable
* `options` is an optional object of configuration options
* `cols` is number of bootstrap columns
* `disabledIds` is an array of string linter IDs to disable
* `screens` is an array of custom screen sizes (e.g. `['xxs', 'xs', 'sm', 'md', 'lg', 'xlg']`)
* Returns nothing (i.e. `undefined`)
* `bootlint.showLintReportForCurrentDocument(disabledIds, alertOpts)`: Lints the HTML of the current document and reports the linting results to the user. Each warning will be output individually using `console.warn()`.
* `disabledIds` is an array of string linter IDs to disable
* `options` is an optional object of configuration options
* `cols` is number of bootstrap columns
* `disabledIds` is an array of string linter IDs to disable
* `screens` is an array of custom screen sizes (e.g. `['xxs', 'xs', 'sm', 'md', 'lg', 'xlg']`)
* `alertOpts` is an optional options object with the following properties:
* `hasProblems` (type: `boolean`; default: `true`) - `window.alert()` a single general notification message to the user if there are any lint problems?
* `problemFree` (type: `boolean`; default: `true`) - `window.alert()` a notification message to the user if the document has no lint problems?
Expand All @@ -140,15 +156,18 @@ function reporter(lint) {
console.log(lint.id, lint.message);
}

bootlint.lintHtml("<!DOCTYPE html><html>...", reporter, []); // calls reporter() repeatedly with each lint problem as an argument
bootlint.lintHtml("<!DOCTYPE html><html>...", reporter); // calls reporter() repeatedly with each lint problem as an argument
```

In a Node.js environment, Bootlint exposes the following public API:

* `bootlint.lintHtml(html, reporter, disabledIds)`: Lints the given HTML for a webpage and returns the linting results.
* `bootlint.lintHtml(html, reporter, options)`: Lints the given HTML for a webpage and returns the linting results.
* `html` is the HTML to lint, as a string
* `reporter` is a *reporter* function (see above for a definition). It will be called repeatedly with each lint problem as an argument.
* `disabledIds` is an array of string linter IDs to disable
* `options` is an optional object of configuration options
* `cols` is number of bootstrap columns
* `disabledIds` is an array of string linter IDs to disable
* `screens` is an array of custom screen sizes (e.g. `['xxs', 'xs', 'sm', 'md', 'lg', 'xlg']`)
* Returns nothing (i.e. `undefined`)

### HTTP API
Expand Down
85 changes: 72 additions & 13 deletions src/bootlint.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,43 @@ var LocationIndex = _location.LocationIndex;
].join(',');
var WIKI_URL = 'https://github.com/twbs/bootlint/wiki/';

exports.configure = function (options) {
var changed = false;

if (options.cols) {
NUM_COLS = options.cols || NUM_COLS;
changed = true;
}

if (options.screens) {
if (typeof options.screens === 'string') {
options.screens = options.screens.split(',');
}

SCREENS = options.screens;
changed = true;
}

if (changed) {
SCREEN2NUM = {};
NUM2SCREEN = [];
COL_CLASSES = [];

SCREENS.forEach(function (screen, index) {
SCREEN2NUM[screen] = index;
NUM2SCREEN[index] = screen;

for (var n = 1; n <= NUM_COLS; n++) {
COL_CLASSES.push('.col-' + screen + '-' + n);
}
});

var colPattern = '\\bcol-(' + SCREENS.join('|') + ')-(\\d{1,2})\\b';
COL_REGEX = new RegExp(colPattern);
COL_REGEX_G = new RegExp(colPattern, 'g');
}
};

function compareNums(a, b) {
return a - b;
}
Expand Down Expand Up @@ -1099,7 +1136,8 @@ var LocationIndex = _location.LocationIndex;
reporter('`.modal-dialog` must have a `role="document"` attribute.', modalDialogs);
}
});
exports._lint = function ($, reporter, disabledIdList, html) {
exports._lint = function ($, reporter, options, html) {
options = options || {};
var locationIndex = IN_NODE_JS ? new LocationIndex(html) : null;
var reporterWrapper = IN_NODE_JS ? function (problem) {
if (problem.elements) {
Expand All @@ -1115,10 +1153,21 @@ var LocationIndex = _location.LocationIndex;
reporter(problem);
} : reporter;

// Backward compatibility with previous param disabledIdList
if (options instanceof Array) {
options = {
disabledIds: options
};
}

this.configure(options);

var disabledIdSet = {};
disabledIdList.forEach(function (disabledId) {
disabledIdSet[disabledId] = true;
});
if (options.disabledIds instanceof Array) {
options.disabledIds.forEach(function (disabledId) {
disabledIdSet[disabledId] = true;
});
}
Object.keys(allLinters).sort().forEach(function (linterId) {
if (!disabledIdSet[linterId]) {
allLinters[linterId]($, reporterWrapper);
Expand All @@ -1137,12 +1186,15 @@ var LocationIndex = _location.LocationIndex;
* Lints the given HTML.
* @param {string} html The HTML to lint
* @param {reporter} reporter Function to call with each lint problem
* @param {string[]} disabledIds Array of string IDs of linters to disable
* @param {object} [options] Options object to configure linting
* @param {integer} [options.cols] Number of bootstrap columns
* @param {string[]} [options.disabledIds=[]] Array of string IDs of linters to disable
* @param {string[]} [options.screens=[]] Array of custom screen sizes
* @returns {undefined} Nothing
*/
exports.lintHtml = function (html, reporter, disabledIds) {
exports.lintHtml = function (html, reporter, options) {
var $ = cheerio.load(html, {withStartIndices: true});
this._lint($, reporter, disabledIds, html);
this._lint($, reporter, options, html);
};
} else {
// jQuery; in-browser
Expand All @@ -1152,23 +1204,30 @@ var LocationIndex = _location.LocationIndex;
/**
* Lints the HTML of the current document.
* @param {reporter} reporter Function to call with each lint problem
* @param {string[]} disabledIds Array of string IDs of linters to disable
* @param {object} [options] Options object to configure linting
* @param {integer} [options.cols] Number of bootstrap columns
* @param {string[]} [options.disabledIds=[]] Array of string IDs of linters to disable
* @param {string[]} [options.screens=[]] Array of custom screen sizes
* @returns {undefined} Nothing
*/
exports.lintCurrentDocument = function (reporter, disabledIds) {
this._lint($, reporter, disabledIds);
exports.lintCurrentDocument = function (reporter, options) {
this._lint($, reporter, options);
};
/**
* Lints the HTML of the current document.
* If there are any lint warnings, one general notification message will be window.alert()-ed to the user.
* Each warning will be output individually using console.warn().
* @param {string[]} disabledIds Array of string IDs of linters to disable
* @param {object} [options] Options object to configure linting
* @param {integer} [options.cols] Number of bootstrap columns
* @param {string[]} [options.disabledIds=[]] Array of string IDs of linters to disable
* @param {string[]} [options.screens=[]] Array of custom screen sizes
* @param {object} [alertOpts] Options object to configure alert()ing
* @param {boolean} [alertOpts.hasProblems=true] Show one alert() when the first lint problem is found?
* @param {boolean} [alertOpts.problemFree=true] Show one alert() at the end of linting if the page has no lint problems?
* @returns {undefined} Nothing
*/
exports.showLintReportForCurrentDocument = function (disabledIds, alertOpts) {
exports.showLintReportForCurrentDocument = function (options, alertOpts) {
options = options || {};
alertOpts = alertOpts || {};
var alertOnFirstProblem = alertOpts.hasProblems || alertOpts.hasProblems === undefined;
var alertIfNoProblems = alertOpts.problemFree || alertOpts.problemFree === undefined;
Expand All @@ -1193,7 +1252,7 @@ var LocationIndex = _location.LocationIndex;
}
errorCount++;
};
this.lintCurrentDocument(reporter, disabledIds);
this.lintCurrentDocument(reporter, options);

if (errorCount > 0) {
console.info('bootlint: For details, look up the lint problem IDs in the Bootlint wiki: https://github.com/twbs/bootlint/wiki');
Expand Down
16 changes: 13 additions & 3 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,19 @@ module.exports = function () {
.option('-d, --disable <IDs>', 'Comma-separated list of disabled lint problem IDs', function (val) {
return val.split(',');
})
.option('-c, --cols <num>', 'Number of grid columns', function (val) {
return parseInt(val, 10);
})
.option('-s, --screens <sizes>', 'Comma-separated list of custom screen sizes', function (val) {
return val.split(',');
})
.parse(process.argv);

var disabledIds = program.disable === undefined ? [] : program.disable;
var options = {
cols: program.cols,
disabledIds: program.disable === undefined ? [] : program.disable,
screens: program.screens === undefined ? [] : program.screens
};
var totalErrCount = 0;
var totalFileCount = 0;
var lintedFiles = [];
Expand Down Expand Up @@ -58,7 +68,7 @@ module.exports = function () {
});

process.stdin.on('end', function () {
bootlint.lintHtml(stdInput.join(''), buildReporter('<stdin>'), disabledIds);
bootlint.lintHtml(stdInput.join(''), buildReporter('<stdin>'), options);
totalFileCount++;
resolve();
});
Expand All @@ -74,7 +84,7 @@ module.exports = function () {
});
})
.each(function (file) {
bootlint.lintHtml(file.contents, buildReporter(file.name), disabledIds);
bootlint.lintHtml(file.contents, buildReporter(file.name), options);
totalFileCount++;
return Deferred.resolve();
});
Expand Down
16 changes: 12 additions & 4 deletions test/bootlint_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ function utf8Fixture(name) {
function utf16Fixture(name) {
return fs.readFileSync(_fixtureNameToFilepath(name), {encoding: 'utf16le'});
}
function lintHtml(html, disabledIds) {
function lintHtml(html, options) {
var lints = [];
var reporter = function (lint) {
lints.push(lint.message);
};
bootlint.lintHtml(html, reporter, disabledIds || []);
bootlint.lintHtml(html, reporter, options || {});
return lints;
}
/*
Expand Down Expand Up @@ -427,12 +427,20 @@ exports.bootlint = {
},

'columns outside of rows and form groups': function (test) {
test.expect(3);
test.expect(5);
test.deepEqual(lintHtml(utf8Fixture('grid/cols-within-row.html')),
[],
'should not complain when columns are within a row.'
);
test.deepEqual(lintHtml(utf8Fixture('grid/cols-within-form-group.html')),
test.deepEqual(lintHtml(utf8Fixture('grid/col-lg-20.html'), {cols: 20}),
[],
'should not complain when there is own number of grid columns and proper options.'
);
test.deepEqual(lintHtml(utf8Fixture('grid/col-xlg-10.html'), {screens: ['xxs', 'xlg']}),
[],
'should not complain when columns have custom screen sizes and proper options.'
);
test.deepEqual(lintHtml(utf8Fixture('grid/cols-within-form-group.html'), {cols: 12, screens: ['xs', 'sm', 'md', 'lg']}),
[],
'should not complain when columns are within a form group.'
);
Expand Down
7 changes: 4 additions & 3 deletions test/fixtures/generic-qunit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
(function () {
'use strict';

function lintCurrentDoc() {
function lintCurrentDoc(options) {
var lints = [];
var reporter = function (lint) {
lints.push(lint.message);
};
bootlint.lintCurrentDocument(reporter, []);
bootlint.lintCurrentDocument(reporter, options);
return lints;
}

Expand All @@ -23,7 +23,8 @@
var expectedLintMsgs = lints.map(function (item) {
return item.dataset.lint;
});
var actualLintMsgs = lintCurrentDoc();
var bootlintOptions = $('#bootlint').data('bootlint-options');
var actualLintMsgs = lintCurrentDoc(bootlintOptions);
assert.deepEqual(actualLintMsgs, expectedLintMsgs);
});
})();
29 changes: 29 additions & 0 deletions test/fixtures/grid/col-lg-20.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Test</title>
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script src="../../lib/jquery.min.js"></script>

<link rel="stylesheet" href="../../lib/qunit.css">
<script src="../../lib/qunit.js"></script>
<script src="../../../dist/browser/bootlint.js"></script>
<script src="../generic-qunit.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-20">Content</div>
</div>
</div>

<div id="qunit"></div>
<ol id="bootlint" data-bootlint-options='{"cols":20}'></ol>
</body>
</html>
29 changes: 29 additions & 0 deletions test/fixtures/grid/col-xlg-10.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Test</title>
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script src="../../lib/jquery.min.js"></script>

<link rel="stylesheet" href="../../lib/qunit.css">
<script src="../../lib/qunit.js"></script>
<script src="../../../dist/browser/bootlint.js"></script>
<script src="../generic-qunit.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xlg-10">Content</div>
</div>
</div>

<div id="qunit"></div>
<ol id="bootlint" data-bootlint-options='{"cols":12,"screens":["xxs", "xs", "sm", "md", "lg", "xlg"]}'></ol>
</body>
</html>