diff --git a/.jshintignore b/.jshintignore
index edaa3402..08a5239d 100644
--- a/.jshintignore
+++ b/.jshintignore
@@ -1,4 +1,4 @@
-lib/vendor
+lib/assets/vendor
test/cli/sample-project
test/cli/sample-project-link
test/browser/support/vendor
diff --git a/lib/vendor/base.css b/lib/assets/base.css
similarity index 89%
rename from lib/vendor/base.css
rename to lib/assets/base.css
index 75b0eb72..7fb88272 100644
--- a/lib/vendor/base.css
+++ b/lib/assets/base.css
@@ -138,19 +138,17 @@ div.coverage-summary a:visited { text-decoration: none; color: #333; }
div.coverage-summary a:hover { text-decoration: underline; }
div.coverage-summary tfoot td { border-top: 1px solid #666; }
-div.coverage-summary .yui3-datatable-sort-indicator, div.coverage-summary .dummy-sort-indicator {
+div.coverage-summary .sorter {
height: 10px;
width: 7px;
display: inline-block;
margin-left: 0.5em;
+ background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
}
-div.coverage-summary .yui3-datatable-sort-indicator {
- background: url("https://yui-s.yahooapis.com/3.6.0/build/datatable-sort/assets/skins/sam/sort-arrow-sprite.png") no-repeat scroll 0 0 transparent;
-}
-div.coverage-summary .yui3-datatable-sorted .yui3-datatable-sort-indicator {
+div.coverage-summary .sorted .sorter {
background-position: 0 -20px;
}
-div.coverage-summary .yui3-datatable-sorted-desc .yui3-datatable-sort-indicator {
+div.coverage-summary .sorted-desc .sorter {
background-position: 0 -10px;
}
diff --git a/lib/assets/sort-arrow-sprite.png b/lib/assets/sort-arrow-sprite.png
new file mode 100644
index 00000000..03f704a6
Binary files /dev/null and b/lib/assets/sort-arrow-sprite.png differ
diff --git a/lib/assets/sorter.js b/lib/assets/sorter.js
new file mode 100644
index 00000000..6afb736c
--- /dev/null
+++ b/lib/assets/sorter.js
@@ -0,0 +1,156 @@
+var addSorting = (function () {
+ "use strict";
+ var cols,
+ currentSort = {
+ index: 0,
+ desc: false
+ };
+
+ // returns the summary table element
+ function getTable() { return document.querySelector('.coverage-summary table'); }
+ // returns the thead element of the summary table
+ function getTableHeader() { return getTable().querySelector('thead tr'); }
+ // returns the tbody element of the summary table
+ function getTableBody() { return getTable().querySelector('tbody'); }
+ // returns the th element for nth column
+ function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
+
+ // loads all columns
+ function loadColumns() {
+ var colNodes = getTableHeader().querySelectorAll('th'),
+ colNode,
+ cols = [],
+ col,
+ i;
+
+ for (i = 0; i < colNodes.length; i += 1) {
+ colNode = colNodes[i];
+ col = {
+ key: colNode.getAttribute('data-col'),
+ sortable: !colNode.getAttribute('data-nosort'),
+ type: colNode.getAttribute('data-type') || 'string'
+ };
+ cols.push(col);
+ if (col.sortable) {
+ col.defaultDescSort = col.type === 'number';
+ colNode.innerHTML = colNode.innerHTML + '';
+ }
+ }
+ return cols;
+ }
+ // attaches a data attribute to every tr element with an object
+ // of data values keyed by column name
+ function loadRowData(tableRow) {
+ var tableCols = tableRow.querySelectorAll('td'),
+ colNode,
+ col,
+ data = {},
+ i,
+ val;
+ for (i = 0; i < tableCols.length; i += 1) {
+ colNode = tableCols[i];
+ col = cols[i];
+ val = colNode.getAttribute('data-value');
+ if (col.type === 'number') {
+ val = Number(val);
+ }
+ data[col.key] = val;
+ }
+ return data;
+ }
+ // loads all row data
+ function loadData() {
+ var rows = getTableBody().querySelectorAll('tr'),
+ i;
+
+ for (i = 0; i < rows.length; i += 1) {
+ rows[i].data = loadRowData(rows[i]);
+ }
+ }
+ // sorts the table using the data for the ith column
+ function sortByIndex(index, desc) {
+ var key = cols[index].key,
+ sorter = function (a, b) {
+ a = a.data[key];
+ b = b.data[key];
+ return a < b ? -1 : a > b ? 1 : 0;
+ },
+ finalSorter = sorter,
+ tableBody = document.querySelector('.coverage-summary tbody'),
+ rowNodes = tableBody.querySelectorAll('tr'),
+ rows = [],
+ i;
+
+ if (desc) {
+ finalSorter = function (a, b) {
+ return -1 * sorter(a, b);
+ };
+ }
+
+ for (i = 0; i < rowNodes.length; i += 1) {
+ rows.push(rowNodes[i]);
+ tableBody.removeChild(rowNodes[i]);
+ }
+
+ rows.sort(finalSorter);
+
+ for (i = 0; i < rows.length; i += 1) {
+ tableBody.appendChild(rows[i]);
+ }
+ }
+ // removes sort indicators for current column being sorted
+ function removeSortIndicators() {
+ var col = getNthColumn(currentSort.index),
+ cls = col.className;
+
+ cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
+ col.className = cls;
+ }
+ // adds sort indicators for current column being sorted
+ function addSortIndicators() {
+ getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
+ }
+ // adds event listeners for all sorter widgets
+ function enableUI() {
+ var i,
+ el,
+ ithSorter = function ithSorter(i) {
+ var col = cols[i];
+
+ return function () {
+ var desc = col.defaultDescSort;
+
+ if (currentSort.index === i) {
+ desc = !currentSort.desc;
+ }
+ sortByIndex(i, desc);
+ removeSortIndicators();
+ currentSort.index = i;
+ currentSort.desc = desc;
+ addSortIndicators();
+ };
+ };
+ for (i =0 ; i < cols.length; i += 1) {
+ if (cols[i].sortable) {
+ el = getNthColumn(i).querySelector('.sorter');
+ if (el.addEventListener) {
+ el.addEventListener('click', ithSorter(i));
+ } else {
+ el.attachEvent('onclick', ithSorter(i));
+ }
+ }
+ }
+ }
+ // adds sorting functionality to the UI
+ return function () {
+ if (!getTable()) {
+ return;
+ }
+ cols = loadColumns();
+ loadData(cols);
+ addSortIndicators();
+ enableUI();
+ };
+})();
+
+window.addEventListener('load', addSorting);
diff --git a/lib/vendor/prettify.css b/lib/assets/vendor/prettify.css
similarity index 100%
rename from lib/vendor/prettify.css
rename to lib/assets/vendor/prettify.css
diff --git a/lib/vendor/prettify.js b/lib/assets/vendor/prettify.js
similarity index 100%
rename from lib/vendor/prettify.js
rename to lib/assets/vendor/prettify.js
diff --git a/lib/report/html.js b/lib/report/html.js
index 8c446be6..fd71e8af 100644
--- a/lib/report/html.js
+++ b/lib/report/html.js
@@ -371,9 +371,12 @@ Report.mix(HtmlReport, {
templateData.reportClass = getReportClass(node.metrics.statements, opts.watermarks.statements);
templateData.pathHtml = pathTemplate({ html: this.getPathHtml(node, linkMapper) });
templateData.base = {
- js: linkMapper.asset(node, 'base.js'),
css: linkMapper.asset(node, 'base.css')
};
+ templateData.sorter = {
+ js: linkMapper.asset(node, 'sorter.js'),
+ image: linkMapper.asset(node, 'sort-arrow-sprite.png')
+ };
templateData.prettify = {
js: linkMapper.asset(node, 'prettify.js'),
css: linkMapper.asset(node, 'prettify.css')
@@ -521,23 +524,29 @@ Report.mix(HtmlReport, {
summarizer = new TreeSummarizer(),
writer = opts.writer || new FileWriter(sync),
that = this,
- tree;
+ tree,
+ copyAssets = function (subdir) {
+ var srcDir = path.resolve(__dirname, '..', 'assets', subdir);
+ fs.readdirSync(srcDir).forEach(function (f) {
+ var resolvedSource = path.resolve(srcDir, f),
+ resolvedDestination = path.resolve(dir, f),
+ stat = fs.statSync(resolvedSource);
+
+ if (stat.isFile()) {
+ if (opts.verbose) {
+ console.log('Write asset: ' + resolvedDestination);
+ }
+ writer.copyFile(resolvedSource, resolvedDestination);
+ }
+ });
+ };
collector.files().forEach(function (key) {
summarizer.addFileCoverageSummary(key, utils.summarizeFileCoverage(collector.fileCoverageFor(key)));
});
tree = summarizer.getTreeSummary();
- fs.readdirSync(path.resolve(__dirname, '..', 'vendor')).forEach(function (f) {
- var resolvedSource = path.resolve(__dirname, '..', 'vendor', f),
- resolvedDestination = path.resolve(dir, f),
- stat = fs.statSync(resolvedSource);
-
- if (stat.isFile()) {
- if (opts.verbose) {
- console.log('Write asset: ' + resolvedDestination);
- }
- writer.copyFile(resolvedSource, resolvedDestination);
- }
+ [ '.', 'vendor'].forEach(function (subdir) {
+ copyAssets(subdir);
});
writer.on('done', function () { that.emit('done'); });
//console.log(JSON.stringify(tree.root, undefined, 4));
diff --git a/lib/report/templates/foot.txt b/lib/report/templates/foot.txt
index 36fe4011..5fdaa5ab 100644
--- a/lib/report/templates/foot.txt
+++ b/lib/report/templates/foot.txt
@@ -5,8 +5,14 @@
{{#if prettify}}
+
{{/if}}
-
-
+